#!/usr/bin/php -q get_variable( $value ); if ($r['result'] == 1) { $result = $r['data']; return $result; } else return ''; } function output(&$var) { if (DEBUG) { global $logfile; if (!isset($logfile)) return false; ob_start(); var_dump($var); $output = ob_get_contents(); ob_end_clean(); fwrite($logfile, $output); } } function parse_voicemailconf($filename, &$vmconf, &$section) { if (is_null($vmconf)) { $vmconf = array(); } if (is_null($section)) { $section = "general"; } if (file_exists($filename)) { $fd = fopen($filename, "r"); while ($line = fgets($fd, 1024)) { if (preg_match("/^\s*(\d+)\s*=>\s*(\d+),(.*),(.*),(.*),(.*)\s*([;#].*)?/",$line,$matches)) { // "mailbox=>password,name,email,pager,options" // this is a voicemail line $vmconf[$section][ $matches[1] ] = array("mailbox"=>$matches[1], "pwd"=>$matches[2], "name"=>$matches[3], "email"=>$matches[4], "pager"=>$matches[5], ); // parse options foreach (explode("|",$matches[6]) as $opt) { $temp = explode("=",$opt); if (isset($temp[1])) { list($key,$value) = $temp; $vmconf[$section][ $matches[1] ]["options"][$key] = $value; } } } else if (preg_match("/^\s*(\d+)\s*=>\s*dup,(.*)\s*([;#].*)?/",$line,$matches)) { // "mailbox=>dup,name" // duplace name line $vmconf[$section][ $matches[1] ]["dups"][] = $matches[2]; } else if (preg_match("/^\s*#include\s+(.*)\s*([;#].*)?/",$line,$matches)) { // include another file if ($matches[1][0] == "/") { // absolute path $filename = $matches[1]; } else { // relative path $filename = dirname($filename)."/".$matches[1]; } parse_voicemailconf($filename, $vmconf, $section); } else if (preg_match("/^\s*\[(.+)\]/",$line,$matches)) { // section name $section = strtolower($matches[1]); } else if (preg_match("/^\s*([a-zA-Z0-9-_]+)\s*=\s*(.*?)\s*([;#].*)?$/",$line,$matches)) { // name = value // option line $vmconf[$section][ $matches[1] ] = $matches[2]; } } } } /** Play a bunch of files, optionally accepting input and looping * @param $files The file/files to play (for multiple files, pass array) * @param $escape_digits The DTMF tones that can be pressed & returned, ie, "123*" * @param $timeout The timeout waiting for a digit, or 0 to not wait at all. * @param $max_digits Maximum number of digits to get. **NOT IMPLEMENTED YET.. 1 only** * @param $loop False for no loop, or an integer >0 being the number of times to loop. * @param $loopreturn Value to return when the loop expires */ function stream_multiple($files, $escape_digits = "", $timeout = 0, $max_digits = 1, $loop = false, $loopreturn = 0) { global $agi; if (!is_array($files)) { $files = array($files); } $i = 0; do { foreach ($files as $file) { $agi->verbose("-- Playing '".$file."' (language 'en')"); $r = $agi->stream_file($file, $escape_digits); $agi->conlog("stream_multiple: $file returned ".$r["result"]); switch ($r["result"]) { case 0: // they did nothing break; case -1: // they hungup $agi->verbose("remote user hungup"); return -1; break; default: // they pressed a key return $r["result"]; break; } } if ($timeout > 0) { $r = $agi->wait_for_digit($timeout); if (($r["result"] != 0) || (!$loop)) { // return only if the reult is not 0 (timeout) // or we're not doing a loop return $r["result"]; } } if ($loop && (++$i > $loop)) { return $loopreturn; } } while ($loop); return 0; } /** If $file.(wav|WAV|gsm|GSM) exists */ function sound_file_exists($file) { global $agi; foreach (array("gsm","GSM","wav","WAV") as $ext) { if (file_exists($file.".".$ext)) { $agi->verbose("Found ".$file.".".$ext, 2); return true; } } return false; } function string_to_digits($string) { $out = ""; for($i=0; $iget_data($intro, 4000, NUM_DIGITS); if (($r["result"] == "0") && $operator) { // operator $agi->verbose("Dropping to operator"); // switch to o,1 in the current context $agi->set_extension("o"); $agi->set_priority("1"); // exiting application immediately! exit(0); } $digits = $r["result"]; usleep(500); // pause a bit, so digit presses get cleared if ($digits !== "") { // they entered SOMETHING, reset our loop $loop = 0; } $i = 0; $digit = false; if (isset($directory[$digits]) && isset($directory[$digits][$i])) { $loop = 0; // reset loop counter do { $match = & $directory[$digits][$i]; $maindirname = sprintf($voicemail_dir, $match["context"], $match["ext"]); if (sound_file_exists($maindirname."/greet")) { $r = $agi->stream_file($maindirname."/greet",$escape_digits); if ($r["result"] > 0) $digit = $r["result"]; } else { $digit = say_alpha($match["name"],$escape_digits); } if (!$digit) { $digit = stream_multiple("dir-instr", $escape_digits, 3000); } switch ($digit) { case D_1: // dial this if ($say_exten) { $agi->stream_file("pls-hold-while-try"); $agi->stream_file("to-extension"); $agi->say_digits($match["ext"]); } $agi->conlog("Dial ".$match["ext"]); $agi->set_context($dial_context); $agi->set_extension($match["ext"]); $agi->set_priority("1"); exit(0); break; case D_STAR: // not correct $i += 1; break; case D_0: // operator if ($operator) { $agi->verbose("Dropping to operator"); // switch to o,1 in the current context $agi->set_extension("o"); $agi->set_priority("1"); // exiting application immediately! exit(0); } break; case -1: // hungup $agi->conlog("User hungup"); exit(1); break; case 0: // no response $loop++; break; case -2: // loop timed out $agi->stream_file("goodbye"); $agi->hangup(); exit(0); break; } if ($digit !== 0) { $loop = 0; } $digit = false; } while (isset($directory[$digits][$i]) && ($loop < MAX_REPEAT)); if (!isset($directory[$digits][$i])) { $agi->stream_file("dir-nomore"); $loop = 0; // reset our loop counter so it doesn't hangup } } else if (!empty($digits) || ($digits === "0")) { // strict type checking as they may have entered "0" (string) which is empty() $agi->stream_file("dir-nomatch"); } // else, we timed out $loop++; } } /******************************************************************************/ $agi = new AGI; $directory_file = get_var($agi, "ASTETCDIR")."/voicemail.conf"; // where is voicemail stored? $voicemail_dir = get_var($agi, "ASTSPOOLDIR")."/voicemail/%s/%d"; // where should we store logs? (fixes #1912) $log_dir = get_var($agi, "ASTLOGDIR"); if (DEBUG) $logfile = fopen( $log_dir . "/directory.log","w"); $vmconf = array(); $null = null; parse_voicemailconf($directory_file, $vmconf, $null); if (!$argv[1]) { $agi->verbose("Notice: vm-context not specified. Using 'default'"); $vm_context = "default"; } else { $vm_context = trim($argv[1]); } if (!isset($vmconf[$vm_context]) && ($vm_context != "general")) { // we make an exception for "general" context,as it just includes other contexts $agi->verbose("Cannot find context ".$vm_context." in ".$directory_file); exit(1); } if (isset($argv[2])) { $dial_context = trim($argv[2]); } else { $dial_context = $vm_context; } $operator = false; $dir_type = DIR_FIRST; $say_exten = false; if (isset($argv[3])) { for($i=0; $i$arr) { // skip if it's general context -- this doesn't contain mailboxes if ($context == "general") continue; foreach ($arr as $key=>$box) { // we could do if !isset($boxes[$key]) to NOT override mailboxes // add in the context, otherwise we don't know what it is $box["context"] = $context; $boxes[$key] = $box; } } } else { $boxes = &$vmconf[$vm_context]; } $directory = array(); foreach ($boxes as $box) { if (!empty($box["name"])) { $name = explode(" ",$box["name"]); if (isset($box["context"])) { $context = $box["context"]; } else { $context = $vm_context; } switch ($dir_type) { case DIR_FIRST: // first name only $digits = string_to_digits($name[0]); $directory[$digits][] = array("ext"=>$box["mailbox"], "name"=>$box["name"], "context"=>$context); break; case DIR_BOTH: // all names foreach ($name as $temp) { $digits = string_to_digits($temp); $directory[$digits][] = array("ext"=>$box["mailbox"], "name"=>$box["name"], "context"=>$cont ext); } break; case DIR_LAST: default: // last name only $digits = string_to_digits(end($name)); $directory[$digits][] = array("ext"=>$box["mailbox"], "name"=>$box["name"], "context"=>$context); break; } } } if (DEBUG) { output($argv); output($dir_type); output($directory); } do_directory($dir_type, $directory, $dial_context, $say_exten, $operator); ?>