logo       

useful AGI for small business with no dedicated receptionist: msg#00253

Subject: useful AGI for small business with no dedicated receptionist
My work is not really a small business anymore but using a telephone isn't a major part of an employees life here.  That means we don't have a receptionist to answer calls and direct them to the correct person.  The Directory agi is quite good however in my experience a lot of people get confused when trying to dial in a name ( don't know why this is?  maybe because until sms came along nobody used the text on the phone keypads ).   What I have done is hacked at the Directory agi so that it will read out each extension and their recorded mailbox name ( if it doesn't exist it uses the deadbeat.gsm sound instead ).   It reads out like the following :
 
Press 110 for Mary
Press 111 for Frank
Press 112 for Deadbeat
Press 113 for Simon
 
All of our extensions are 3 digits which is hardcoded in as a limit.  In fact there's probably a few things hardcoded in there that are specific to my work but could easily be edited out.
 
Here's the contents of the AGI.  It's pretty messy as it's just a hack of Directory although I have done a *little* bit of cleaning up.
 
>> extensions_custom.conf
[ext-local-custom]
exten => *611,1,Answer
exten => *611,2,AGI(custom_dir.agi)
exten => *611,3,Hangup
 
>> custom_dir.agi
 
#!/usr/bin/php -q
<?php
 
/**
// AGI directory Copyright (C) 2005 Greg MacLellan (greg-/EcZB/KljS9CkLs28/y7APd9D2ou9A/h@xxxxxxxxxxxxxxxx)
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
 

*/
 
define("AGIBIN_DIR", dirname(__FILE__));
define("DIRECTORY_FILE", "/etc/asterisk/voicemail.conf");
 
// where is voicemail stored?
define("VOICEMAIL_DIR", "/var/spool/asterisk/voicemail/%s/%d");
 

// set to 1 to say "zed" instead of "zee"
define("SAY_ZED",1);
 
/******************************************************************************/
 
define("DEBUG", 1);
 
define("DIR_LAST", 0);
define("DIR_FIRST", 1);
define("DIR_BOTH", 2);
define("TIMEOUT",100);
define("NUM_DIGITS", 3);
define("MAX_REPEAT", 2); // how many times can we repeat the menu before hanging up?
 

include(AGIBIN_DIR."/phpagi.php");
 
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];
   }
  }
 }
}
 

/** 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 say_alpha($string,$escape_digits) {
 $string = strtolower($string);
 $files = array();
 
 for($i=0; $i<strlen($string); $i++) {
  if (('a' <= $string[$i]) && ($string[$i] <= 'z')) {
  
   if (($string[$i] == 'z') && SAY_ZED) {
    $files[] = "letters/zed";
   } else {
    $files[] = "letters/".$string[$i];
   }
   
  } else if (('1' <= $string[$i]) && ($string[$i] <= '0')) {
   $files[] = "digits/".$string[$i];
   
  } else {
   switch ($string[$i]) {
    case "@": $files[] = "letters/at"; break;
    case "-": $files[] = "letters/dash"; break;
    case "$": $files[] = "letters/dollar"; break;
    case ".": $files[] = "letters/dot"; break;
    case "=": $files[] = "letters/equals"; break;
    case "!": $files[] = "letters/exclaimation-point"; break;
    case "+": $files[] = "letters/plus"; break;
    case "/": case "\\": $files[] = "letters/slash"; break;
    case " ": $files[] = "letters/space"; break;
   }
  }
 }
 
 return stream_multiple($files,$escape_digits);
}
 
function DialExt($ext,$dial_context) {
 global $agi;
 if ( strlen($ext) > 2 ) {
  $blah = array();
  preg_match("/^(...).*$/",$ext,$blah);
  $ext = $blah[1];
  $agi->verbose("Dial $dial_context:$ext:1");
  $agi->set_context($dial_context);
  $agi->set_extension($ext);
  $agi->set_priority("1");
  exit(0);
 } else {
  return 0;
 }
}
 
$agi = new AGI;
 
if (DEBUG) $logfile = fopen("/tmp/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;
}
 

if ($vm_context == "general") {
 $boxes = array();
 foreach ($vmconf as $context=>$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;
  }
      $directory[$box["mailbox"]] = $box["name"];
 }
}
ksort($directory);
foreach ( $directory as $ext=>$name ) {
 $r = $agi->get_data("/var/lib/asterisk/sounds/press",TIMEOUT,NUM_DIGITS);
  if ($r["result"] > 0) $digit .= $r["result"];
 if ( $digit ) DialExt($digit,$dial_context);
  if (sound_file_exists("/var/lib/asterisk/sounds/digits/$ext")) {
  $r = $agi->get_data("/var/lib/asterisk/sounds/digits/$ext",TIMEOUT,NUM_DIGITS);
  if ($r["result"] > 0) $digit .= $r["result"];
  } else {
   $digit .= say_alpha($ext,"1*");
  }
 if ( $digit ) DialExt($digit,$dial_context);
  $r = $agi->get_data("/var/lib/asterisk/sounds/for",TIMEOUT,NUM_DIGITS);
  if ($r["result"] > 0) $digit .= $r["result"];
 if ( $digit ) DialExt($digit,$dial_context);
  if (sound_file_exists("/var/spool/asterisk/voicemail/default/$ext/greet")) {
    $r = $agi->get_data("/var/spool/asterisk/voicemail/default/$ext/greet",TIMEOUT,NUM_DIGITS);
  if ($r["result"] > 0) $digit .= $r["result"];
  if ( $digit ) DialExt($digit,$dial_context);
 } else {
  $r = $agi->get_data("/var/lib/asterisk/sounds/deadbeat",TIMEOUT,NUM_DIGITS);
    if ($r["result"] > 0) $digit .= $r["result"];
  if ( $digit ) DialExt($digit,$dial_context);
  }
 
}
 
if (DEBUG) {
 output($argv);
 output($dir_type);
 output($directory);
}
 
?>
<Prev in Thread] Current Thread [Next in Thread>
Google Custom Search

Recently Viewed:
qnx.openqnx.dev...    politics.lenini...    audio.emagic.ex...    tex.texinfo.gen...    handhelds.linux...    ietf.sipping/20...    lang.erlang.gen...    cygwin.talk/200...    yellowdog.gener...    mozilla.devel.l...    xfree86.newbie/...    openbsd.ports/2...    db.oracle.devel...    kde.kalyxo.deve...    user-groups.lin...    bbc.cvs/2003-04...    gnu.libtool.bug...    redhat.k12osn/2...    emulators.wine....    freebsd.devel.d...    search.xapian.g...    java.izpack.use...    network.mrtg.us...    windows.total-c...   
Home | blog view | USPTO Patent Archive | advertise | OSDir is an inevitable website. super tiny logo

Free Magazines

Cisco News
Receive a free quarterly e-newsletter with exclusive articles on how Cisco IT uses its own products and solutions to enable the business.
subscribe

Systems Management News, the newspaper for IT systems administration and data center managers! Each issue of Systems Management News is chock-full of news and analysis to help you understand what's happening in your field.
subscribe

The Enterprise Newsweekly eWeek is the essential technology information source for builders of e-business.
subscribe

Oracle Magazine Oracle Magazine contains technology strategy articles, sample code, tips, Oracle and partner news, how to articles for developers and DBAs, and more. Oracle (NASDAQ: ORCL) is the world's largest enterprise software company.
subscribe

Total Telecom Total Telecom is "The Economist of the communications industry".
subscribe