root/modules/branches/2.4/core/agi-bin/fixlocalprefix

Revision 5756, 7.5 kB (checked in by p_lindheimer, 4 years ago)

#2828: fix bug allowing fixlocalprefix to return 0 as valid dialstring

  • Property svn:mime-type set to text/plain
  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1 #!/usr/bin/php -q
2 <?php
3 /**
4 // fixlocalprefix Copyright (C) 2005 Greg MacLellan (greg@mtechsolutions.ca)
5 // Asterisk Management Portal Copyright (C) 2004 Coalescent Systems Inc. (info@coalescentsystems.ca)
6 //
7 //This program is free software; you can redistribute it and/or
8 //modify it under the terms of the GNU General Public License
9 //as published by the Free Software Foundation; either version 2
10 //of the License, or (at your option) any later version.
11 //
12 //This program is distributed in the hope that it will be useful,
13 //but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 //GNU General Public License for more details.
16
17 /* --------WARNING---------
18  *
19  * This script is auto-copied from an included module and will get overwritten.
20  * If you modify it, you must change it to write only, in the agi-bin directory,
21  * to keep it from getting changed.
22
23
24 This program takes a number, checks it against a list of patterns for a specific trunk, and modifies the number based
25 on the rules for that number.
26
27 Two variables are required:
28
29 DIAL_NUMBER - the number to be dialed (this will be modified, if necessary)
30 DIAL_TRUNK - the trunk number to use
31
32 The list of prefixes is contained in $localprefix_file (defined below, defaults to /etc/asterisk/localprefixes.conf). This
33 file has the format:
34
35   [trunk-1]
36   rule1=1613|NXXXXXX
37   rule2=1519|555XXXX
38   rule2=1519|54[0-9]XXXX
39  
40   [trunk-2]
41   rule1=1613+NXXXXXX
42   rule2=1519+12XXXXX
43
44
45 The section read depends on the value of DIAL_TRUNK.
46
47 A | means to drop the number before the |. In this example, if DIAL_NUMBER is "16135551234" and DIAL_TRUNK is "1",
48 DIAL_NUMBER will become "5551234" (rule1). If DIAL_NUMBER is "15195551234", it will become "5551234" (rule2).
49 "15195435555" will become "5435555" (rule3).
50
51 A + means to prefix the beginning digits to the following pattern. In this example, if DIAL_NUMBER is 5551234, and
52 DIAL_TRUNK is "2", DIAL_NUMBER will become "16135551234". If DIAL_NUMBER is "1235555", it will match rule2 and
53 become "15191235555".
54
55 If no number is matched, DIAL_NUMBER is left untouched, and the script will exit with return value 0. If any errors
56 occur, DIAL_NUMBER is left untouched and the script will exit with return value 1.
57
58 There is no limit to the number of rules that may be defined.
59
60 You can also use #include filename.conf to include other files. Sections are preserved when including, which may
61 cause undesired behaviour if not planned for. For example:
62
63 localprefixes.conf:
64   [trunk-1]
65   #include t1.conf
66   rule1=1613|453XXXX
67   rule2=1613|384XXXX
68  
69 t1.conf:
70   [trunk-2]
71   rule1=141|NXXXXXX
72  
73 rule1 and rule2 defined in localprefixes.conf will actually belong to [trunk-2], and additionally, rule1 in
74 localprefixes.conf will override the rule1 defined in t1.conf.
75
76 */
77
78 include("phpagi.php");
79
80 function get_var( $agi, $value)
81 {
82   $r = $agi->get_variable( $value );
83  
84   if ($r['result'] == 1)
85   {
86     $result = $r['data'];
87     return $result;
88   }
89   else
90     return '';
91 }
92
93 function parse_conf($filename, &$conf, &$section) {
94   if (is_null($conf)) {
95     $conf = array();
96   }
97   if (is_null($section)) {
98     $section = "general";
99   }
100  
101   if (file_exists($filename)) {
102     $fd = fopen($filename, "r");
103     while ($line = fgets($fd, 1024)) {
104       if (preg_match("/^\s*([a-zA-Z0-9-_]+)\s*=\s*(.*?)\s*([;#].*)?$/",$line,$matches)) {
105         // name = value
106         // option line
107         $conf[$section][ $matches[1] ] = $matches[2];
108       } else if (preg_match("/^\s*\[(.+)\]/",$line,$matches)) {
109         // section name
110         $section = strtolower($matches[1]);
111       } else if (preg_match("/^\s*#include\s+(.*)\s*([;#].*)?/",$line,$matches)) {
112         // include another file
113        
114         if ($matches[1][0] == "/") {
115           // absolute path
116           $filename = $matches[1];
117         } else {
118           // relative path
119           $filename =  dirname($filename)."/".$matches[1];
120         }
121        
122         parse_conf($filename, $conf, $section);
123       }
124     }
125   }
126 }
127
128 function sanitizeNumber($number) {
129   global $agi;
130   if (strpos($number,"-") !== false) {
131     $agi->verbose("Stripping hyphens");
132     $number = str_replace("-","",$number);
133   }
134   return $number;
135 }
136
137 function fixNumber($pattern, $number, &$agi) {
138   // valid chars in a pattern are 0-9XNZwW#*\.\[\]\-\+\|
139   $chars = '0-9XNZwW#*\.\[\]\-'; //escaped pcre-ready
140  
141   // convert x n and z to uppercase
142   $regex = str_replace(array('x','n','z'), array('X','N','Z'), $pattern);
143   // sanitize the pattern - remove any non-pattern chars
144   $regex = preg_replace("/[^0-9XNZwW#*\.\[\]\-\+\|]/", "", $regex);
145   // Also kill the '-' characters outside of groups
146   $regex = preg_replace("/((?:\[[^\]]*\])*)([^\[\]\-]*)-?/", "$1$2", $regex);
147
148   $agi->verbose('Using pattern '.$regex, 4);
149   // attempt to grab the pieces of the pattern
150   if (preg_match('/^(([0-9XNZwW#*\.\[\]\-]+)\|)?(([0-9XNZwW#*\.\[\]\-]+)\+)?([0-9XNZwW#*\.\[\]\-]*)$/', $regex, $matches)) {
151     // one of NXXXXXX, 613|NXXXXXX   1+NXXXXXX    613|1+NXXXXXX, 
152     // matches[2] = drop (eg 613),  matches[4] = prefix (eg 1),  matches[5] = rest of number (eg NXXXXX)
153    
154     $drop = $matches[2];
155     $prefix = $matches[4];
156     $static = $matches[5];
157   } else if (preg_match('/^(([0-9XNZwW#*\.\[\]\-]+)\+)?(([0-9XNZwW#*\.\[\]\-]+)\|)?([0-9XNZwW#*\.\[\]\-]*)$/', $regex, $matches)) {
158     // one of NXXXXXX,  613|NXXXXXX   1+NXXXXXX    1+613|NXXXXXX
159     // matches[2] = prefix (eg 1),  matches[4] = drop (eg 613),  matches[5] = rest of number (eg NXXXXX)
160    
161     $drop = $matches[4];
162     $prefix = $matches[2];
163     $static = $matches[5];
164   } else {
165     if (!is_null($agi)) {
166       $agi->verbose('Could not understand pattern "'.$pattern.'" ('.$regex.')', 1);
167     }
168     return false;
169   }
170  
171   // convert asterisk pattern matching into perl regular expression
172   $regex = str_replace(
173       array(
174         "X",
175         "Z",
176         "N",
177         ".",
178       ),
179       array(
180         "[0-9]",
181         "[1-9]",
182         "[2-9]",
183         "[0-9#*]+",
184       ),
185       // note, we're doing a subpattern match on the static portion so it can be extracted later
186       $drop.'('.$static.')');
187  
188   if (preg_match('/^'.$regex.'$/', $number, $matches)) {
189     return $prefix.$matches[1];
190   }
191   return false;
192 }
193
194 /**********************************************************************************************************************/
195
196 $agi = new AGI();
197
198 $localprefix_file = get_var($agi, "ASTETCDIR")."/localprefixes.conf";
199
200 if (file_exists($localprefix_file)) {
201   parse_conf($localprefix_file, $conf, $section);
202   if (count($conf) == 0) {
203 //    $agi->verbose("Could not parse ".$localprefix_file);
204     exit(1);
205   }
206 } else {
207   $agi->verbose("Could not open ".$localprefix_file);
208   exit(1);
209 }
210
211 $r = $agi->get_variable("DIAL_NUMBER");
212 if ($r["result"] == 0) {
213   $agi->verbose("DIAL_NUMBER not set -- nothing to do");
214   exit(1);
215 }
216 $number = $r["data"];
217
218 $number = sanitizeNumber($number);
219
220 $r = $agi->get_variable("DIAL_TRUNK");
221 if ($r["result"] == 0) {
222   $agi->verbose("DIAL_TRUNK not set -- nothing to do");
223   exit(1);
224 }
225 $trunk = $r["data"];
226
227
228 if (isset($conf["trunk-$trunk"])) {
229   foreach ($conf["trunk-$trunk"] as $key=>$rule) {
230     // extract all ruleXX keys
231     //$agi->conlog("$key = $rule");
232     if (preg_match("/^rule\d+$/",$key)) {
233       // $rule is a dial rule
234      
235       if (($newnum = fixNumber($rule, $number, $agi)) !== false) {
236         $agi->verbose('Dialpattern '.$rule.' matched. '.$number.' -> '.$newnum, 2);
237         $agi->set_variable("DIAL_NUMBER", $newnum);
238        
239         // reverted back form r2080 (r2081 on trac) so that any pattern match will end
240         // the loop. This needs to stay like this for backwards compatibility and often
241         // patterns are used to avoid matching substitution rules for exception cases.
242         exit(0);
243       } // else, it didn't match this rule
244     } // else, this isn't a rule
245   }
246 } // else, no config for this section
247
248 // we just exit with no changes to the variable.
249 exit(0);
250
251 ?>
Note: See TracBrowser for help on using the browser.