root/modules/branches/2.3/core/agi-bin/directory

Revision 4457, 13.0 kB (checked in by p_lindheimer, 5 years ago)

#2115: fix dial-by-name directory not using vm voice files

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