View Javadoc

1   package org.asteriskjava.config.dialplan;
2   
3   import java.io.IOException;
4   import java.util.ArrayList;
5   import java.util.List;
6   
7   import org.asteriskjava.config.ConfigElement;
8   import org.asteriskjava.config.ConfigFileReader;
9   import org.asteriskjava.config.ConfigParseException;
10  import org.asteriskjava.config.ConfigVariable;
11  
12  /*
13   *   Interprets extensions.conf as a special kind of config file, the dialplan.
14   *   - Line numbers correspond with pbx_config.c, tags/1.4.19 revision 96024
15   */
16  public class ExtensionsConfigFileReader extends ConfigFileReader
17  {
18      /*
19       * This method corresponds to an iteration of the loop at line 2212 Notes:
20       *      1. [general] and [globals] are allowed to be a context here if they contain only configvariables
21       *      2. switch and ignorepat are treated like regular ConfigVariable.
22       */
23      @Override
24      protected ConfigElement processTextLine(String configfile, int lineno, String line) throws ConfigParseException
25      {
26          ConfigElement configElement;
27          
28          if(
29                  (line.trim().startsWith("exten") || line.trim().startsWith("include")) &&
30                  currentCategory != null && 
31                  (currentCategory.getName().equals("general") || currentCategory.getName().equals("globals"))
32          )
33              throw new ConfigParseException(configfile, lineno, "cannot have 'exten' or 'include' in global or general sections");
34  
35          
36          /*
37           * Goal here is to break out anything unique that we might want to
38           * look at and parse separately. For now, only exten and include fit
39           * that criteria. Eventually, I could see parsing sections for things
40           * from macros, contexts to differentiate them from categories, switch
41           * for realtime, and more. 
42           */
43          if (line.trim().startsWith("exten"))
44          {
45              configElement = parseExtension(configfile, lineno, line);
46              currentCategory.addElement(configElement);
47              return configElement;
48          }
49          else if(line.trim().startsWith("include"))
50          {
51              // use parseVariable since we have access to it
52              ConfigVariable configvar = parseVariable(configfile, lineno, line);
53              configElement = new ConfigInclude(configfile, lineno, configvar.getValue());
54              currentCategory.addElement(configElement);
55              return configElement;
56          }
57          
58          // leave everything else the same
59          configElement = super.processTextLine(configfile, lineno, line);
60          
61          return configElement;
62      }
63      
64      /* Roughly corresponds to pbx_config.c:2222 */
65      protected ConfigExtension parseExtension(String configfile, int lineno, String line) throws ConfigParseException
66      {
67          ConfigVariable initialVariable = parseVariable(configfile, lineno, line);
68          
69          if(!initialVariable.getName().equals("exten"))
70              throw new ConfigParseException(configfile, lineno, "missing 'exten' near " + line);
71          line = initialVariable.getValue().trim();
72  
73          int nameIndex = line.indexOf(",", 0);
74          if(nameIndex == -1)
75              throw new ConfigParseException(configfile, lineno, "missing extension name near " + line);
76          String name = line.substring(0, nameIndex);
77          line = line.substring(name.length()+1, line.length()).trim();
78          
79          int priorityDelimiter = line.indexOf(",", 0);
80          if(priorityDelimiter == -1)
81              throw new ConfigParseException(configfile, lineno, "missing extension priority near " + line);
82          String priority = line.substring(0, priorityDelimiter);
83          line = line.substring(priority.length()+1, line.length()).trim();
84  
85          String [] application = harvestApplicationWithArguments(line);
86          
87          return new ConfigExtension(configfile,lineno,name,priority,application);
88      }
89      
90      /* Roughly corresponds to pbx_config.c:2276 */
91      private static String [] harvestApplicationWithArguments(String arg)
92      {
93          List<String> args = new ArrayList<String>();
94          
95          if(args != null && arg.trim().length() >= 0)
96          {
97              String appl = "", data = "";
98              
99              /* Find the first occurrence of either '(' or ',' */
100             int firstc = arg.indexOf(',');
101             int firstp = arg.indexOf('(');
102             
103             if (firstc != -1 && (firstp == -1 || firstc < firstp)) {
104                 /* comma found, no parenthesis */
105                 /* or both found, but comma found first */
106                 String [] split = arg.split(",");
107                 appl = split[0];
108                 for(int i = 1; i < split.length; i++)
109                     data += split[i] + (i+1<split.length?",":"");
110             } else if (firstc == -1 && firstp == -1) {
111                 /* Neither found */
112                 data = "";
113             } else {
114                 /* Final remaining case is parenthesis found first */
115                 String [] split = arg.split("\\(");
116                 appl = split[0];
117                 for(int i = 1; i < split.length; i++)
118                     data += split[i] + (i+1<split.length?"(":"");
119                 int end = data.lastIndexOf(')');
120                 if (end == -1) {
121                     //ast_log(LOG_WARNING, "No closing parenthesis found? '%s(%s'\n", appl, data);
122                 } else if(end == data.length()-1) {
123                     data = data.substring(0, end);
124                 }
125                 data = processQuotesAndSlashes(data, ',', '|');
126             }
127             
128             if(!appl.trim().equals(""))
129             {
130                 args.add(appl.trim());
131                 if(!data.trim().equals(""))
132                 {
133                     String [] dataSplit = data.split("\\|");
134                     for (String aDataSplit : dataSplit)
135                     {
136                         args.add(aDataSplit.trim());
137                     }
138                 }
139             }
140         }
141         
142         return args.toArray(new String[args.size()]);
143     }
144 
145     public ExtensionsConfigFile readExtensionsFile(String configfile) throws IOException, ConfigParseException
146     {
147         super.readFile(configfile);
148         /* at some point, we may want to resolve back references */
149         /* that include or goto from one context to another */
150         return new ExtensionsConfigFile(configfile, categories);
151     }
152     
153     /* ast_process_quotes_and_slashes rewritten to be java friendly */
154     private static String processQuotesAndSlashes(String start, char find, char replace_with)
155     {
156         String dataPut = "";
157         int inEscape = 0;
158         int inQuotes = 0;
159         
160         char [] startChars = start.toCharArray();
161         for (char startChar : startChars)
162         {
163             if (inEscape != 0)
164             {
165                 dataPut += startChar;       /* Always goes verbatim */
166                 inEscape = 0;
167             }
168             else
169             {
170                 if (startChar == '\\')
171                 {
172                     inEscape = 1;      /* Do not copy \ into the data */
173                 }
174                 else if (startChar == '\'')
175                 {
176                     inQuotes = 1 - inQuotes;   /* Do not copy ' into the data */
177                 }
178                 else
179                 {
180                     /* Replace , with |, unless in quotes */
181                     dataPut += inQuotes != 0 ? startChar : ((startChar == find) ? replace_with : startChar);
182                 }
183             }
184         }
185         return dataPut;
186     }
187 }