Perl Script To Provision Polycom Phones

Provisioning Polycom SIP phones can be tedious if done manually. Configuration can be done from XML formatted configuration files read on boot via tftp or ftp, configured directly on the phone or through a web browser. If you any number of phones, using ftp or tftp is really the only way to go. You can download the latest firmware for the phones from Polycom’s website and example XML files for the configuration. I created this basic perl script to create files unique for each phone. It has lots of room for improvement, but it will also add an entry into the sip.conf file if one isn’t already there based on a template called phone. See the Asterisk sample sip.conf file for more information on templates.

#!/usr/bin/perl -w

use strict;

if(@ARGV != 6){
print <<”EOS”;
Usage:
$0 sip-peer ‘secret’ callerid-name callerid-num mac-address extension

EOS

exit()

}

my $sip_conf=’/etc/asterisk/sip.conf’;
my $cfg_temp=’/tftpboot/sp550_template.cfg’;
my @sp550;
my $tftp_dir=’/tftpboot/’;
my $sip_peer=$ARGV[0];
my $secret=$ARGV[1];
my $callerid_name=$ARGV[2];
my $callerid_num=$ARGV[3];
my $mac=$ARGV[4];
my $exten=$ARGV[5];

$mac =~ s/\.//g;

if(length($mac) != 12){
print “mac-address invalid!\nPlease enter the MAC address in the 12 digit HEX format.\n”;
}

sub read_file {
my ( $f ) = @_;
open F, “< $f” or die “Can’t open $f : $!”;
my @f = ;
close F;
return wantarray ? @f : \@f;
}

#######################################
# Read in template for individual
# phone settings and customize it
# before writing it.
#
@sp550=read_file($cfg_temp);
open(my $FILE,’+>’,$tftp_dir . “sp550_” . $sip_peer . “.cfg”) or die “Couldn’t open file ” . $tftp_dir . “sp550_” . $sip_peer . “.cfg\n”;
foreach (@sp550){
$_ =~ s/USERNAME/$sip_peer/g;
$_ =~ s/SECRET/$secret/g;
$_ =~ s/FULLNAME/$callerid_name/g;
print $FILE $_;
}
close $FILE;

########################################
# Write the mac.cfg file for this phone
#
open($FILE,’+>’,$tftp_dir . $mac . “.cfg”) or die “Couldn’t open file ” . $tftp_dir . $mac . “.cfg\n”;
print $FILE “\n”;
print $FILE “\n”;
print $FILE ” print $FILE $sip_peer;
print $FILE “.cfg, sip.cfg\” MISC_FILES=\”polycom/overrides/\” LOG_FILE_DIRECTORY=\”polycom/logs/\” CONTACTS_DIRECTORY=\”polycom/contacts/\”/>\n”;
close $FILE;

#######################################
# Concatenate sip.conf with new phone
#
my @sip=read_file($sip_conf);
foreach (@sip){
if($_ =~ m/$sip_peer/){
print “SIP peer is already defined in sip.conf\n”;
exit();
}
}
open($FILE,’>>’, $sip_conf) or die “Couldn’t open sip.conf file”;
print $FILE “\n[" . $sip_peer . "](phone)\n”;
print $FILE “secret=” . $secret . “\n”;
print $FILE “calledid=\”" . $callerid_name . “\” <” . $callerid_num . “>\n”;
print $FILE “mailbox=” . $exten . “\n”;
print $FILE “setvar=USERID=” . $sip_peer . “\n\n”;
print $FILE “\n[" . $sip_peer . "-softphone](” . $sip_peer . “)\n\n”;
close $FILE;

Posted in sip phone | Tagged , , , , | Comments Off

On Call AGI From Google Calendar

Here’s a PHP AGI script I wrote so that when someone calls 799 they it will ring a group of desk phones if it’s business hours or retrieve the phone number(s) from the ‘Description’ field of the calendar entry and attempt to call them. If no one is reached it will then call the IT Manager. If that is not answered either it will send an email to the group.

The phpagi library is used as the interface to Asterisk, which is a little out of date and I had to make a tweak to; leave a comment if you’d like the details. There’s also a logger class I wrote which I can post if anyone is interested. The dialplan needs an entry like this:

exten => 799,1,AGI(oncall.php)

#!/usr/bin/php
<?php
//*******************
// Oncall.php
//
// Read an event from a Google Calendar
//  and redirect the phone call to that
//  number, or default to the IT Mgr.
//
// Based on perl script by Brian
// by Steve Schoeneman 07.27.2010
$debug=0;
require_once(‘lib/LogFile.php’);
require_once(‘phpagi/branches/phpagi_php5/phpagi.php’);
// Deskphones to ring during the day.
if($debug){
$deskphones_us = (‘SIP/steves’);
}else{
$deskphones_us = (‘SIP/joe&SIP/steves&SIP/pete&SIP/scott&SIP/mark&’.
‘IAX/london/517&IAX/london/589′);
}
if($debug){
$deskphones_uk = (‘IAX/london/635′);
}else{
$deskphones_uk = (‘IAX/london/517&IAX/london/589′);
}
$log = new LogFile(‘/var/log/asterisk/oncall.log’);
$answer = 0;
$cid = “IT Support/”;
$confirmed = ‘http://schemas.google.com/g/2005#event.confirmed’;
date_default_timezone_set(‘America/Chicago’);
$asm = new AGI;
$cid_array = $asm->get_variable(‘CALLERIDNAME’);
$callerid = $cid_array['data'];
$cid = $cid.$cid_array['data'];
$asm->exec(‘SetCIDName’,'”‘.$cid.’”‘);
$asm->Verbose(‘cid name: ‘.$cid);
if(is_workhours_uk() == TRUE){
$asm->stream_file(‘tts/ringing_it_support’);
$log->lwrite(“Calling “.$deskphones_uk.”;”);
$asm->exec(‘Dial’,$deskphones_uk.’|15′);
$call = $asm->get_variable(‘DIALSTATUS’);
$asm->Verbose(‘DIALSTATUS: ‘.print_r($call,true));
if($call['data'] == ‘ANSWER’){
$log->lwrite(“Answered;\n”);
$asm->hangup();
}else{
$log->lwrite(“Not answered;”);
}
}
if(is_workhours_us() == TRUE){
$asm->stream_file(‘tts/ringing_it_support’);
$log->lwrite(“Calling “.$deskphones_us.”;”);
$asm->exec(‘Dial’,$deskphones_us.’|15′);
$call = $asm->get_variable(‘DIALSTATUS’);
$asm->Verbose(‘DIALSTATUS: ‘.print_r($call,true));
if($call['data'] == ‘ANSWER’){
$log->lwrite(“Answered;\n”);
$asm->hangup();
}else{
$log->lwrite(“Not answered;”);
}
}
$offset=date(“P”);
$tz=preg_replace(‘/\+/’,'%2b’,$offset);
if($debug){
$feed = ‘https://www.google.com/calendar/feeds/mydomain.com_your_private_calendar_xml _address_calendar.google.com/private-(*&*HUH*&H*HU/full?’.
‘orderby=starttime&singleevents=true&start-min=’ . date(“Y-m-d\Th:i:s”, time()).$tz.
‘&start-max=’ . date(“Y-m-d\Th:i:s”, time()).$tz;
} else {
$feed = ‘https://www.google.com/calendar/feeds/mydomain.com__your_private_calendar_xml _address_group.calendar.google.com/private-98732428jHJH82903′.
‘/full?orderby=starttime&singleevents=true&start-min=’ . date(“Y-m-d\Th:i:s”, time()).$tz.
‘&start-max=’ . date(“Y-m-d\Th:i:s”, time()).$tz;
}
//if($debug) $log->lwrite($feed);
// This is the XML document object
$doc = new DOMDocument();
$log->lwrite(date(“F j, Y,g:i a”).”;”);
$doc->load( $feed );
if($debug) $log->lwrite(“Loaded feed;”);
$entries = $doc->getElementsByTagName( “entry” );
// length of 0 means no entries were fetched
if($entries->length != 0) {
$x = 0;
$asm->verbose(“Total entries: $entries->length”);
foreach ( $entries as $entry ) {
$asm->verbose(“x = $x”);
$status = $entry->getElementsByTagName( “eventStatus” );
$eventStatus = $status->item(0)->getAttributeNode(“value”)->value;
if($eventStatus == $confirmed && ($call['data'] != ‘ANSWER’ || is_workhours_us() == FALSE)){
$log->lwrite(“Ringing on call number(s);”);
$titles = $entry->getElementsByTagName( “title” );
$title = $titles->item(0)->nodeValue;
$content = $entry->getElementsByTagName( “content” );
$what = $content->item(0)->nodeValue;
$log->lwrite($title.”;”);
$log->lwrite($what.”;”);
if($what != “”){
//Strip misc crap and white space from phone number
$number[$x] = preg_replace(‘/[-\.\s\(\)]/’,”,$what);
if($debug) $asm->verbose(“After junk removal ” . $number[$x]);
$number[$x] = preg_replace(‘/^1512/’, ”, $number[$x]);
if($debug) $asm->verbose(“Remove 1 if 512 ” . $number[$x]);
if(preg_match(‘/^[2-46-9]/’, $number[$x]) > 0){
$number[$x] = “1″ . $number[$x];
}
if(strlen($number[$x] == 7)){
$number[$x] = “512″.$number[$x];
}
if($number_sum != “”) $number_sum = $number_sum . “&”;
$number_sum = $number_sum . “Zap/g1/” . $number[$x];
}
}
$x++;
}
if($number_sum == “”){
//IT Manager’s mobile number
$asm->stream_file(‘tts/ringing_it_manager’);
$log->lwrite(“Failed to fetch schedule, using 15555551313;”);
if($debug){
$number = ’15555551212′;
}else{
$number = ’15555551313′;
}
$asm->Verbose(“Failed to get number!\n”);
}
if($debug) $log->lwrite(“\nnumber_sum: $number_sum\n”);
$asm->verbose(“About to call $number_sum”);
//Have a number, now make a call
$channel=”Zap/g1/”;
$asm->stream_file(‘tts/ringing_it_oncall’);
$log->lwrite(“Calling “.$number_sum.”;”);
$asm->exec(‘Dial’,$number_sum.’|90′);
$call = $asm->get_variable(‘DIALSTATUS’);
$asm->Verbose(‘DIALSTATUS: ‘.$call);
if($call['data'] == ‘ANSWER’){
$log->lwrite(“Answered;\n”);
$asm->hangup();
}else{
$log->lwrite(“Not answered;”);
if($debug){
$number = ’15555551212′;
}else{
$number = ’15555551313′;
}
$asm->stream_file(‘tts/ringing_it_manager’);
$log->lwrite(“Calling “.$channel.$number.”;”);
$asm->exec(‘Dial’,$channel.$number.’|90′);
$call = $asm->get_variable(‘DIALSTATUS’);
$asm->Verbose(‘DIALSTATUS: ‘.$call);
if($call == ‘ANSWERED’){
$log->lwrite(“Answered;\n”);
$asm->hangup();
}else{
$log->lwrite(“No one was reached;\n”);
mail_admin($callerdid);
$asm->hangup();
}
}
}else{
$log->lwrite(“no on-call entries in calendar;”);
$channel=”Zap/g1/”;
if($debug){
$number = ’15555551212′;
}else{
$number = ’15555551313′;
}
$asm->stream_file(‘tts/ringing_it_manager’);
$log->lwrite(“Calling “.$channel.$number.”;”);
$asm->exec(‘Dial’,$channel.$number.’|90′);
$call = $asm->get_variable(‘DIALSTATUS’);
$asm->Verbose(‘DIALSTATUS: ‘.$call);
if($call == ‘ANSWERED’){
$log->lwrite(“Answered;\n”);
$asm->hangup();
}else{
$log->lwrite(“No one was reached;\n”);
mail_admin($callerdid);
$asm->hangup();
}
}
//***********************
// is_workhours_us()
function is_workhours_us(){
if($debug) return FALSE;
$workhours = array(’7′,’8′,’9′,’10′,’11′,’12′,’13′,’14′,’15′,’16′,’17′);
$workdays = array(‘Mon’,'Tue’,'Wed’,'Thu’,'Fri’);
$day=date(‘D’);
$hour=date(‘G’);
if(in_array($day,$workdays) && in_array($hour,$workhours)){
return TRUE;
}else{
return FALSE;
}
}
//***********************
// is_workhours_uk()
function is_workhours_uk(){
if($debug) return FALSE;
$workhours = array(’1′,’2′,’3′,’4′,’5′,’6′);
$workdays = array(‘Mon’,'Tue’,'Wed’,'Thu’,'Fri’);
$day=date(‘D’);
$hour=date(‘G’);
if(in_array($day,$workdays) && in_array($hour,$workhours)){
return TRUE;
}else{
return FALSE;
}
}
//**********************
// mail_admin($callerid)
function mail_admin($callerid){
$to = “admin@mydomain.com”;
$subject = “IT Hotline Missed Call”;
$message = “There was an unanswered call from $callerid to the IT Hotline.”;
$headers = “From: admin@mydomain.com”;
mail($to,$subject,$message,$headers);
}
?>
Posted in AGI, PHP | Tagged , , , | Comments Off

Installing Asterisk with Digium Cards and DAHDI Drivers

This article describes installing Asterisk on a CentOS Linux server along with Digium telephony cards and the DAHDI (Digium Asterisk Hardware Device Interface) drivers. I assume you already have Linux installed and running and have root access to the server.

I found instructions vague on this subject and ran into a few issues installing a Digium TDM410 card along with Asterisk so I thought I would document my experience here.

Obviously the first step is to install the hardware. Don’t forget to connect the power connector if you have FXS (Foriegn eXchange Station – used for end devices like analog telephones, faxes, etc.) modules on your PCI card. You can identify the modules by color, FXS modules are green and FXO (Foreign eXchange Office – receives analog signaling like a phone or a fax) are red. Be sure you never plug an FXO to FXO as both are supplying voltage and physical damage to the card will most likely result!

Next download libpri, the DAHDI Complete package, and the latest stable Asterisk tarball from the Asterisk website. I’m assuming you already have the gcc compiler installed, if not you’ll need to get that and install it. The prerequisites for installing Asterisk and DAHDI are OpenSSL, ncurses and ncurses-devel, Zlib, and newt along with gcc. Untar and unzip the tarball with tar -zxf tarball.tar.gz in whatever directory you downloaded it to; by convention, it should have been /usr/src.

The order you compile and install is important. First, comes libpri, cd into the directory created after unpacking and issue make, followed by make install. You’ll have to do the latter as root or with sudo. Then change into the DAHDI directory and issue ./configure, make, make install, and finally make config which installs configuration scripts so DAHDI will start on reboot. Finally, change into the Asterisk directory and issue the commands ./configure, make menuselect. Menuselect gives you a change to choose options like the extra sounds that are quite humorous. Next, make, make install and finally make samples if you want sample configuration files installed.

Before loading anything, we need to set a few basic parameters up in the configuration files. Load the kernel configuration file into your favorite editor; it’s full path is /etc/dahdi/system.conf. Also note that unlike all other Asterisk config files where a semicolon (;) denotes a comment, in system.conf a pound (#) is used.

There’s some generic stuff that you’ll need no matter what kind of card you have. Make sure you have this (adjust for your country):

# Global data

loadzone    = us
defaultzone    = us

If you have FXS port you’ll want to configure it for FXO signaling, just the opposite for FXO. In other words, if you have an FXO module, you’ll want FXS signaling.  Here’s what this would look like:

#FXS Modules with kewlstart signaling
fxoks=1-2
#FXO Modules with kewlstart signaling
fxsks=3-4
#Echo cancellation on all ports
echocanceller=mg2,1-4

Kewlstart signaling is appropriate in almost all cases these days, and the echo cancellation is standard as well. If you don’t have the echo cancellation module on your card, it will be done in software.

DAHDI is a Linux kernel driver, so it must be started and running before starting Asterisk. It’s a good idea to do some checking at this point. Issue the command lsmod | grep dahdi and you should see an entry for your Digium card. If not, you may want to back up a few steps and do some checking. I had to also issue the command modprobe wctdm24xxp to get the driver to initialize properly. If all looks well, issue dahdi_cfg -vvv to request a reload of the DAHDI system and show which channels are loaded. To make sure everything is seen properly, issue dahdi_tool and examine the channels to make sure they are operational. If not, you may want to go back to the system.conf file and make sure everything is correct.

Finally you’re ready to start Asterisk. You can do this several ways:

service asterisk start

/etc/init.d/asterisk start

Or if you’re having trouble you can start Asterisk in console mode so you can see what’s going with /usr/sbin/asterisk -c.

Next time I’ll go into ways you can configure your cards in the dialplan.

Posted in Uncategorized | Tagged , , , , | Comments Off