root/freepbx/trunk/amp_conf/agi-bin/directory

Revision 3939, 12.6 kB (checked in by diego_iastrubni, 6 years ago)

fix for ticket:1912

  • 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 /**
5 // AGI directory Copyright (C) 2005 Greg MacLellan (greg@mtechsolutions.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
18 */
19
20 define("AGIBIN_DIR", dirname(__FILE__));
21 define("DIRECTORY_FILE", "/etc/asterisk/voicemail.conf");
22
23 // where is voicemail stored?
24 define("VOICEMAIL_DIR", "/var/spool/asterisk/voicemail/%s/%d");
25
26 // where shold we store logs? (fixes #1912)
27 define("LOG_DIR", "/var/log/asterisk/");
28
29 // set to 1 to say "zed" instead of "zee"
30 define("SAY_ZED",0);
31
32 /******************************************************************************/
33
34 define("DEBUG", 0);
35
36 define("DIR_LAST", 0);
37 define("DIR_FIRST", 1);
38 define("DIR_BOTH", 2);
39
40 define("NUM_DIGITS", 3);
41 define("MAX_REPEAT", 2); // how many times can we repeat the menu before hanging up?
42
43 // ordinal values of digits
44 define("D_0",48);
45 define("D_1",49);
46 define("D_2",50);
47 define("D_3",51);
48 define("D_4",52);
49 define("D_5",53);
50 define("D_6",54);
51 define("D_7",55);
52 define("D_8",56);
53 define("D_9",57);
54 define("D_POUND",35);
55 define("D_STAR",42);
56
57 include(AGIBIN_DIR."/phpagi.php");
58
59 function output(&$var) {
60     if (DEBUG) {
61         global $logfile;
62         
63         if (!isset($logfile)) return false;
64         
65         ob_start();
66         var_dump($var);
67         $output = ob_get_contents();
68         ob_end_clean();
69         fwrite($logfile, $output);
70     }
71 }
72
73
74 function parse_voicemailconf($filename, &$vmconf, &$section) {
75     if (is_null($vmconf)) {
76         $vmconf = array();
77     }
78     if (is_null($section)) {
79         $section = "general";
80     }
81     
82     if (file_exists($filename)) {
83         $fd = fopen($filename, "r");
84         while ($line = fgets($fd, 1024)) {
85             if (preg_match("/^\s*(\d+)\s*=>\s*(\d+),(.*),(.*),(.*),(.*)\s*([;#].*)?/",$line,$matches)) {
86                 // "mailbox=>password,name,email,pager,options"
87                 // this is a voicemail line   
88                 $vmconf[$section][ $matches[1] ] = array("mailbox"=>$matches[1],
89                                     "pwd"=>$matches[2],
90                                     "name"=>$matches[3],
91                                     "email"=>$matches[4],
92                                     "pager"=>$matches[5],
93                                     );
94                                 
95                 // parse options
96                 foreach (explode("|",$matches[6]) as $opt) {
97                     $temp = explode("=",$opt);
98                     if (isset($temp[1])) {
99                         list($key,$value) = $temp;
100                         $vmconf[$section][ $matches[1] ]["options"][$key] = $value;
101                     }
102                 }
103             } else if (preg_match("/^\s*(\d+)\s*=>\s*dup,(.*)\s*([;#].*)?/",$line,$matches)) {
104                 // "mailbox=>dup,name"
105                 // duplace name line
106                 $vmconf[$section][ $matches[1] ]["dups"][] = $matches[2];
107             } else if (preg_match("/^\s*#include\s+(.*)\s*([;#].*)?/",$line,$matches)) {
108                 // include another file
109                 
110                 if ($matches[1][0] == "/") {
111                     // absolute path
112                     $filename = $matches[1];
113                 } else {
114                     // relative path
115                     $filename dirname($filename)."/".$matches[1];
116                 }
117                 
118                 parse_voicemailconf($filename, $vmconf, $section);
119                 
120             } else if (preg_match("/^\s*\[(.+)\]/",$line,$matches)) {
121                 // section name
122                 $section = strtolower($matches[1]);
123             } else if (preg_match("/^\s*([a-zA-Z0-9-_]+)\s*=\s*(.*?)\s*([;#].*)?$/",$line,$matches)) {
124                 // name = value
125                 // option line
126                 $vmconf[$section][ $matches[1] ] = $matches[2];
127             }
128         }
129     }
130 }
131
132
133 /** Play a bunch of files, optionally accepting input and looping
134  * @param $files        The file/files to play (for multiple files, pass array)
135  * @param $escape_digits    The DTMF tones that can be pressed & returned, ie, "123*"
136  * @param $timeout        The timeout waiting for a digit, or 0 to not wait at all.
137  * @param $max_digits        Maximum number of digits to get. **NOT IMPLEMENTED YET.. 1 only**
138  * @param $loop            False for no loop, or an integer >0 being the number of times to loop.
139  * @param $loopreturn        Value to return when the loop expires
140 */
141 function stream_multiple($files, $escape_digits = "", $timeout = 0, $max_digits = 1, $loop = false, $loopreturn = 0) {
142     global $agi;
143     
144     if (!is_array($files)) {
145         $files = array($files);
146     }
147     
148     $i = 0;
149     do {
150         foreach ($files as $file) {
151             $agi->verbose("-- Playing '".$file."' (language 'en')");
152             $r = $agi->stream_file($file, $escape_digits);
153             $agi->conlog("stream_multiple: $file returned ".$r["result"]);
154             switch ($r["result"]) {
155                 case 0: // they did nothing
156                 break;
157                 case -1: // they hungup
158                     $agi->verbose("remote user hungup");
159                     return -1;
160                 break;
161                 default: // they pressed a key
162                     return $r["result"];
163                 break;
164             }
165         }
166         
167         if ($timeout > 0) {
168             $r = $agi->wait_for_digit($timeout);
169             if (($r["result"] != 0) || (!$loop)) {
170                 // return only if the reult is not 0 (timeout)
171                 // or we're not doing a loop
172                 return $r["result"];
173             }
174         }
175         
176         if ($loop && (++$i > $loop)) {
177             return $loopreturn;
178         }
179     } while ($loop);
180     
181     return 0;
182 }
183
184 /** If $file.(wav|WAV|gsm|GSM) exists
185  */
186 function sound_file_exists($file) {
187     global $agi;
188     
189     foreach (array("gsm","GSM","wav","WAV") as $ext) {
190         if (file_exists($file.".".$ext)) {
191             $agi->verbose("Found ".$file.".".$ext, 2);
192             return true;
193         }
194     }
195     return false;
196 }
197
198 function string_to_digits($string) {
199     $out = "";
200     
201     for($i=0; $i<strlen($string); $i++) {
202         switch (strtoupper($string[$i])) {
203             case '1':
204                 $out .= '1';
205             break;
206             case '2': case 'A': case 'B': case 'C':
207                 $out .= '2';
208             break;
209             case '3': case 'D': case 'E': case 'F':
210                 $out .= '3';
211             break;
212             case '4': case 'G': case 'H': case 'I':
213                 $out .= '4';
214             break;
215             case '5': case 'J': case 'K': case 'L':
216                 $out .= '5';
217             break;
218             case '6': case 'M': case 'N': case 'O':
219                 $out .= '6';
220             break;
221             case '7': case 'P': case 'Q': case 'R': case 'S':
222                 $out .= '7';
223             break;
224             case '8': case 'T': case 'U': case 'V':
225                 $out .= '8';
226             break;
227             case '9': case 'W': case 'X': case 'Y': case 'Z':
228                 $out .= '9';
229             break;
230         }
231         
232         if ($i+1 == NUM_DIGITS) break;
233     }
234     
235     return $out;
236 }
237
238 function say_alpha($string,$escape_digits) {
239     $string = strtolower($string);
240     $files = array();
241     
242     for($i=0; $i<strlen($string); $i++) {
243         if (('a' <= $string[$i]) && ($string[$i] <= 'z')) {
244         
245             if (($string[$i] == 'z') && SAY_ZED) {
246                 $files[] = "letters/zed";
247             } else {
248                 $files[] = "letters/".$string[$i];
249             }
250             
251         } else if (('1' <= $string[$i]) && ($string[$i] <= '0')) {
252             $files[] = "digits/".$string[$i];
253             
254         } else {
255             switch ($string[$i]) {
256                 case "@": $files[] = "letters/at"; break;
257                 case "-": $files[] = "letters/dash"; break;
258                 case "$": $files[] = "letters/dollar"; break;
259                 case ".": $files[] = "letters/dot"; break;
260                 case "=": $files[] = "letters/equals"; break;
261                 case "!": $files[] = "letters/exclaimation-point"; break;
262                 case "+": $files[] = "letters/plus"; break;
263                 case "/": case "\\": $files[] = "letters/slash"; break;
264                 case " ": $files[] = "letters/space"; break;
265             }
266         }
267     }
268     
269     return stream_multiple($files,$escape_digits);
270 }
271
272 function do_directory($type, &$directory, $dial_context, $say_exten, $operator) {
273     global $agi;
274     
275     $escape_digits = "1*";
276     if ($operator) $escape_digits .= "0";
277     
278     switch ($type) {
279         case DIR_FIRST: $intro = ($operator ? "dir-intro-fn-oper" : "dir-intro-fn"); break;
280         case DIR_BOTH: $intro = ($operator ? "dir-intro-fnln-oper" : "dir-intro-fnln"); break;
281         case DIR_LAST: default: $intro = ($operator ? "dir-intro-oper" : "dir-intro"); break;
282     }
283     
284     $loop = 0;
285     while ($loop < MAX_REPEAT) {
286         $r = $agi->get_data($intro, 4000, NUM_DIGITS);
287         
288         if (($r["result"] == "0") && $operator) {
289             // operator
290             $agi->verbose("Dropping to operator");
291             // switch to o,1 in the current context
292             $agi->set_extension("o");
293             $agi->set_priority("1");
294             // exiting application immediately!
295             exit(0);
296         }
297         $digits = $r["result"];
298         
299         usleep(500); // pause a bit, so digit presses get cleared
300         
301         if ($digits !== "") {
302             // they entered SOMETHING, reset our loop
303             $loop = 0;
304         }
305         
306         $i = 0;
307         $digit = false;
308         if (isset($directory[$digits]) && isset($directory[$digits][$i])) {
309             $loop = 0; // reset loop counter
310             do {
311                 $match = & $directory[$digits][$i];
312                 
313                 $maindirname = sprintf(VOICEMAIL_DIR, $match["context"], $match["ext"]);
314
315                 if (sound_file_exists($maindirname."/greet")) {
316                     $r = $agi->stream_file($maindirname."/greet",$escape_digits);
317                     if ($r["result"] > 0) $digit = $r["result"];
318                 } else {
319                     $digit = say_alpha($match["name"],$escape_digits);
320                 }
321                 
322                 if (!$digit) {
323                     $digit = stream_multiple("dir-instr", $escape_digits, 3000);
324                 }
325                 
326                 switch ($digit) {
327                     case D_1: // dial this
328                         if ($say_exten) {
329                             $agi->stream_file("pls-hold-while-try");
330                             $agi->stream_file("to-extension");
331
332                             $agi->say_digits($match["ext"]);
333                         }
334                         $agi->conlog("Dial ".$match["ext"]);
335                         
336                         $agi->set_context($dial_context);
337                         $agi->set_extension($match["ext"]);
338                         $agi->set_priority("1");
339                         exit(0);
340                     break;
341                     case D_STAR: // not correct
342                         $i += 1;
343                     break;
344                     case D_0: // operator
345                         if ($operator) {
346                             $agi->verbose("Dropping to operator");
347                             // switch to o,1 in the current context
348                             $agi->set_extension("o");
349                             $agi->set_priority("1");
350                             // exiting application immediately!
351                             exit(0);
352                         }
353                     break;
354                     case -1: // hungup
355                         $agi->conlog("User hungup");
356                         exit(1);
357                     break;
358                     case 0: // no response
359                         $loop++;
360                     break;
361                     case -2: // loop timed out
362                         $agi->stream_file("goodbye");
363                         $agi->hangup();
364                         exit(0);
365                     break;
366                 }
367                 
368                 if ($digit !== 0) {
369                     $loop = 0;
370                 }
371                 $digit = false;
372             } while (isset($directory[$digits][$i]) && ($loop < MAX_REPEAT));
373             
374             if (!isset($directory[$digits][$i])) {
375                 $agi->stream_file("dir-nomore");
376                 $loop = 0; // reset our loop counter so it doesn't hangup
377             }
378         } else if (!empty($digits) || ($digits === "0")) {
379             // strict type checking as they may have entered "0" (string) which is empty()
380             $agi->stream_file("dir-nomatch");
381         } // else, we timed out
382         
383         $loop++;
384     }
385 }
386
387 /******************************************************************************/
388
389 $agi = new AGI;
390
391 if (DEBUG) $logfile = fopen( LOG_DIR . "directory.log","w");
392
393 $vmconf = array();
394 $null = null;
395 parse_voicemailconf(DIRECTORY_FILE, $vmconf, $null);
396
397
398 if (!$argv[1]) {
399     $agi->verbose("Notice: vm-context not specified.  Using 'default'");
400     $vm_context = "default";
401 } else {
402     $vm_context = trim($argv[1]);
403 }
404
405 if (!isset($vmconf[$vm_context]) && ($vm_context != "general")) {
406     // we make an exception for "general" context,as it just includes other contexts
407     $agi->verbose("Cannot find context ".$vm_context." in ".DIRECTORY_FILE);
408     exit(1);
409 }
410
411 if (isset($argv[2])) {
412     $dial_context = trim($argv[2]);
413 } else {
414     $dial_context = $vm_context;
415 }
416
417 $operator = false;
418 $dir_type = DIR_FIRST;
419 $say_exten = false;
420
421 if (isset($argv[3])) {
422     for($i=0; $i<strlen($argv[3]); $i++) {
423         switch ($argv[3][$i]) {
424             case "f": case "F":
425                 $dir_type = DIR_FIRST;
426             break;
427             case "l": case "L":
428                 $dir_type = DIR_LAST;
429             break;
430             case "b": case "B":
431                 $dir_type = DIR_BOTH;
432             break;
433             case "o": case "O":
434                 $operator = true;
435             break;
436             case "e": case "E":
437                 $say_exten = true;
438             break;
439         }
440     }
441 }
442
443 if ($vm_context == "general") {
444     $boxes = array();
445     foreach ($vmconf as $context=>$arr) {
446         // skip if it's general context -- this doesn't contain mailboxes
447         if ($context == "general") continue;
448         
449         foreach ($arr as $key=>$box) {
450             // we could do if !isset($boxes[$key]) to NOT override mailboxes
451             
452             // add in the context, otherwise we don't know what it is
453             $box["context"] = $context;
454             
455             $boxes[$key] = $box;
456         }
457     }
458 } else {
459     $boxes = &$vmconf[$vm_context];
460 }
461
462 $directory = array();
463 foreach ($boxes as $box) {
464     if (!empty($box["name"])) {
465         $name = explode(" ",$box["name"]);
466         
467         if (isset($box["context"])) {
468             $context = $box["context"];
469         } else {
470             $context = $vm_context;
471         }
472         
473         switch ($dir_type) {
474             case DIR_FIRST: // first name only
475                 $digits = string_to_digits($name[0]);
476                 $directory[$digits][] = array("ext"=>$box["mailbox"], "name"=>$box["name"], "context"=>$context);
477             break;
478             case DIR_BOTH: // all names
479                 foreach ($name as $temp) {
480                     $digits = string_to_digits($temp);
481                     $directory[$digits][] = array("ext"=>$box["mailbox"], "name"=>$box["name"], "context"=>$context);
482                 }
483             break;
484             case DIR_LAST: default: // last name only
485                 $digits = string_to_digits(end($name));
486                 $directory[$digits][] = array("ext"=>$box["mailbox"], "name"=>$box["name"], "context"=>$context);
487             break;
488         }
489     }
490 }
491
492 if (DEBUG) {
493     output($argv);
494     output($dir_type);
495     output($directory);
496 }
497
498 do_directory($dir_type, $directory, $dial_context, $say_exten, $operator);
499     
500 ?>
501
Note: See TracBrowser for help on using the browser.