Background
I wanted a quick and simple solution to handling Caller ID lookups in Asterisk. I didn't want to use Google contacts integration because I'm using multiple Google accounts and I wanted to keep the contact list centralized. So what I did was whip up a quick Perl AGI script that could be called.
Notes and assumptions:
- I'm running Asterisk 1.8 on DD-WRT using Optware.
- Obviously, this is for a small home installation with a low call volume. It is not suitable for anything else.
The Perl Script (cidlookup.pl)
I placed this under /opt/var/lib/asterisk/agi-bin/cidlookup.pl. You'll need to have Asterisk::AGI package installed. The quickest way is to download from CPAN, and then unzip the asterisk directory into your Perl lib directory. The script does several things:
- Load existing address book and a list of unknown numbers into memory.
- Look up the caller number in the address book.
- If found, then return the caller's name.
- If not found, then look up the caller name using Open CNAM.
- If found, then use Open CNAM's result and update the address book
- If still not found, return the phone number as the name, and add the number to the list of unknown callers.
#!/opt/bin/perl -w
use strict;
use Asterisk::AGI;
# Globals
my $strCIDFile = '/opt/home/asterisk/callerid.csv';
my $strUnknownNums = '/opt/home/asterisk/unknownnums.txt';
my %hshCIDList = ();
my %hshUnknownList = ();
main();
sub main {
my $blnAddCID = 0;
# load lookup files into memory
load_datafiles();
# Extract Caller ID from AGI input
my $objAGI = new Asterisk::AGI;
my $strCallerID = $objAGI->get_variable("CALLERID(name)");
# Match phone number
if ($strCallerID =~ /\+(\d+)\@/) {
my $strNumber = $1;
my $strName = '';
# Set caller ID number
$objAGI->set_variable("CALLERID(number)",$strNumber);
# Lookup name and set caller ID name if available,
# otherwise set caller ID to the number
if ($strName = $hshCIDList{$strNumber}) { # addr book
$objAGI->set_variable("CALLERID(name)",$strName);
} elsif ($strName = opencnam_lookup($strNumber) ) { # open cnam
$objAGI->set_variable("CALLERID(name)",$strName);
$hshCIDList{$strNumber} = $strName;
$blnAddCID = 1;
} else {
# Add number to unknown caller id list
$hshUnknownList{$strNumber} = 1;
# set caller id to number
$objAGI->set_variable("CALLERID(name)",$strNumber);
}
} else {
# error catch
$objAGI->set_callerid('UNKNOWN');
}
update_datafiles($blnAddCID);
}
sub load_datafiles {
# Read callerid lookup table into memory
if (-e $strCIDFile) {
open CIDFILE, $strCIDFile or die $!;
while (my $strLine = ) {
chomp $strLine;
my ($intNumber, $strName) = split(',',$strLine);
$hshCIDList{$intNumber} = $strName;
}
close CIDFILE;
}
# Read unknown numbers into memory
if (-e $strUnknownNums) {
open UNKNOWNFILE, $strUnknownNums or die $!;
while (my $strNum = ) {
chomp $strNum;
$hshUnknownList{$strNum} = 1;
}
close UNKNOWNFILE;
}
}
sub update_datafiles {
my $blnAddCID = $_[0];
# Prune unknown numbers list
open UNKNOWNFILE, "> $strUnknownNums" or die $!;
foreach my $strNum (sort keys %hshUnknownList) {
if ($hshCIDList{$strNum}) {
delete $hshUnknownList{$strNum}
} else {
print UNKNOWNFILE "$strNum\n";
}
}
close UNKNOWNFILE;
# Update address book from open cnam
if ($blnAddCID == 1) {
open CIDFILE, "> $strCIDFile" or die $!;
foreach my $strNum (sort keys %hshCIDList) {
print CIDFILE $strNum . ',' . $hshCIDList{$strNum} . "\n";
}
close CIDFILE;
}
}
# lookup open cnam in case not in personal address book
sub opencnam_lookup {
my $strNum = $_[0];
my $strRes = `curl -sk https://api.opencnam.com/v2/phone/$strNum`;
if ($strRes !~ /no caller ID|throttle limit/i) {
return sanitize($strRes)
} else {
return 0
}
}
# sanitize caller id names from the Internet
sub sanitize {
my $strToSanitize = $_[0];
$strToSanitize =~ s/[^\w|^ ]//g; # keep alphanumeric and spaces
$strToSanitize =~ s/ {2,}/ /g; # shrink spaces
$strToSanitize =~ s/^\s+//; # ltrim
$strToSanitize =~ s/\s+$//; # rtrim
return $strToSanitize;
}
The extensions.conf file
Call the script by using the AGI function. Be sure you have res_agi.so loaded in modules.conf.
; From Google
[google-in]
; Set caller ID
exten => s,1,NoOp(${CALLERID(dnid)})
same => n,AGI(cidlookup.pl)
same => n,Wait(1)
same => n,Answer()
same => n,SendDTMF(1)
same => n,Dial(SIP/100,15)
same => n,Hangup()