Using AGI to get Caller ID Name CNAM
Everyone has them — and here’s Team Forrest’s version of a Caller ID to Name (CNAM, CIDNAME, etc.) lookup using AnyWho, Google, and 411.com. The first file is the calleridname.pl:
UPDATE April 4, 2009 — Frank (user comment) let us know that AnyWho had changed their website. As a result the code has been updated. Thanks Frank!
UPDATE November 18, 2009 — Robert (user comment) let us know of another change. As a result the code has been updated. Thanks Robert!
#!/usr/bin/perl -w
use strict;
use LWP::UserAgent;
$|=1;
my ($cidnum,$cidname,$npa,$nxx,$station,$name);
#----------------------------------------------------------------
# get asterisk initial info
#----------------------------------------------------------------
while(<STDIN>) {
chomp;
last unless length($_);
}
#----------------------------------------------------------------
# check if we have a caller id
#----------------------------------------------------------------
if ($ARGV[0]) {
$cidnum = $ARGV[0];
} else {
print qq(VERBOSE "ERROR: no callerid provided" 2\n);
exit(0);
}
#----------------------------------------------------------------
# check caller id and split into npa, nxx, and station
#----------------------------------------------------------------
if(substr($cidnum,0,1) eq '1'){
$cidnum=substr($cidnum,1);
}
if(substr($cidnum,0,2) eq '+1'){
$cidnum=substr($cidnum,2);
}
if ($cidnum =~ /^(\d{3})(\d{3})(\d{4})$/) {
$npa = $1;
$nxx = $2;
$station = $3;
} elsif ($cidnum =~/\<(\d{3})(\d{3})(\d{4})\>/) {
$npa = $1;
$nxx = $2;
$station = $3;
} else {
print qq(VERBOSE "ERROR: unable to parse caller id" 2\n);
exit(0);
}
print qq(VERBOSE "STATUS: CID is $npa-$nxx-$station" 2\n);
#----------------------------------------------------------------
# check npa, nxx, and station for cid name
# 1 = check. 0 = skip.
#----------------------------------------------------------------
my $AnyWho = '1' ;
my $Google = '1' ;
my $www411 = '1' ;
if ($AnyWho > '0') {
print qq(VERBOSE "STATUS: checking AnyWho for name lookup" 2\n);
if ($name = &anywho_lookup ($npa, $nxx, $station)) {
$cidname = $name;
print qq(SET VARIABLE CALLERID\(name\) "$cidname"\n);
print qq(VERBOSE "STATUS: AnyWho said name was $cidname " 2\n);
exit(0);
} else {
print qq(VERBOSE "STATUS: unable to find name with AnyWho" 2\n);
}
} else {
print qq(VERBOSE "STATUS: AnyWho lookup disabled" 2\n);
}
if ($Google > '0') {
print qq(VERBOSE "STATUS: checking Google for name lookup" 2\n);
if ($name = &google_lookup ($npa, $nxx, $station)) {
$cidname = $name;
print qq(SET VARIABLE CALLERID\(name\) "$cidname"\n);
print qq(VERBOSE "STATUS: Google said name was $cidname " 2\n);
exit(0);
} else {
print qq(VERBOSE "STATUS: unable to find name with Google" 2\n);
}
} else {
print qq(VERBOSE "STATUS: Google lookup disabled" 2\n);
}
if ($www411 > '0') {
print qq(VERBOSE "STATUS: checking www411 for name lookup" 2\n);
if ($name = &www411_lookup ($npa, $nxx, $station)) {
$cidname = $name;
print qq(SET VARIABLE CALLERID\(name\) "$cidname"\n);
print qq(VERBOSE "STATUS: www411 said name was $cidname " 2\n);
exit(0);
} else {
print qq(VERBOSE "STATUS: unable to find name with www411" 2\n);
}
} else {
print qq(VERBOSE "STATUS: www411 lookup disabled" 2\n);
}
#----------------------------------------------------------------
# return results and exit
#----------------------------------------------------------------
print qq(SET VARIABLE CALLERID\(name\) "$cidnum"\n);
print qq(VERBOSE "STATUS: Unknown name for $cidnum " 2\n);
exit(0);
#----------------------------------------------------------------
# parse anywho
# http://whitepages.anywho.com/results.php?qnpa=$npa&qnpanxx=$npa$nxx&qnxx=$nxx&qp=$nxx$station&qstation=$station
# Find More Information for First Last</a>
#----------------------------------------------------------------
sub anywho_lookup {
my ($npa, $nxx, $station) = @_;
my $ua = LWP::UserAgent->new( timeout => 45);
my $URL = 'http://whitepages.anywho.com/results.php';
$URL .= qq(?qnpa=$npa&qnpanxx=$npa$nxx&qnxx=$nxx&qp=$nxx$station&qstation=$station);
$ua->agent('AsteriskAGIQuery/1');
my $req = new HTTP::Request GET => $URL;
my $res = $ua->request($req);
if ($res->is_success()) {
if ($res->content =~ /Find More Information for (.*)<\/a>/) {
my $clidname = $1;
return $clidname;
}
}
return "";
}
#----------------------------------------------------------------
# parse google
# http://www.google.com/search?rls=en&q=phonebook:$npa$nxx$station
# <td>First Name<td>(<b>$npa
#----------------------------------------------------------------
sub google_lookup {
my ($npa, $nxx, $station) = @_;
my $ua = LWP::UserAgent->new( timeout => 45);
my $URL = qq(http://www.google.com/search?rls=en&q=phonebook:$npa$nxx$station&ie=UTF-8&oe=UTF-8);
$ua->agent('AsteriskAGIQuery/1');
my $req = new HTTP::Request GET => $URL;
my $res = $ua->request($req);
if ($res->is_success()) {
if ($res->content =~ /<td>(.+)<td>\(<b>$npa/) {
my $clidname = $1;
return $clidname;
}
}
return "";
}
#----------------------------------------------------------------
# parse 411
# http://www.411.com/search/Reverse_Phone?phone=$npa$nxx$station
# View map, driving directions, and more">Name</a>
#----------------------------------------------------------------
sub www411_lookup {
my ($npa, $nxx, $station) = @_;
my $ua = LWP::UserAgent->new( timeout => 45);
my $URL = qq(http://www.411.com/search/Reverse_Phone?phone=$npa$nxx$station);
$ua->agent('AsteriskAGIQuery/1');
my $req = new HTTP::Request GET => $URL;
my $res = $ua->request($req);
if ($res->is_success()) {
if ($res->content =~ /View map, driving directions, and more\">(.*)<\/a>/) {
my $clidname = $1;
if ($clidname eq "Listing Detail") {
if ($res->content =~ /Type: <strong>(.*)<\/strong>/) {
$clidname = $1;
if ($res->content =~ /Location: <strong>(.*)<\/strong>/) {
$clidname = $clidname . " $1";
}
}
}
return $clidname;
}
}
return "";
}
This perl script will work well as an AGI script — checking AnyWho, Google, and then 411 for a caller’s name or location. If all else fails, the callerid name is set as the callerid number.
The perl script was designed to only use the Internet with minimal installation; so it will work without a database, Perl Asterisk module, or locally hosted NPA / NXX (phone number to region) file.
Team Forrest recommends using a subroutine context to get the callerid when needed; calling the script with either a GoSub or GosubIf command, such as:
exten => s,n,Gosub(cidname-lookup,s,1)
exten => s,n,dial(${PHONE},30,t)
...
...
[cidname-lookup]
exten => s,1,NoOp(looking up callerid name)
exten => s,n,GotoIf($["foo${CALLERID(NAME)}" = "foo" ]?getname)
exten => s,n,GotoIf($["${CALLERID(NAME)}" = "${CALLERID(NUM)}" ]?getname)
exten => s,n,NoOp(caller id name exists as ${CALLERID(NAME)})
exten => s,n,Return
exten => s,n(getname),AGI(calleridname.pl,${CALLERID(NUM)})
exten => s,n,NoOp(Caller ID Name is now ${CALLERID(NAME)})
exten => s,n,Return
Enjoy the file (download here) and remember, Team Forrest is here to assist you will all of your Asterisk, VoIP, or technical needs.
[...] perl script can be downloaded here, or code viewed online from Team Forrest’s website. There are many, many types of these scripts available online, and using Google, a VoIP enabled [...]
Asterisk Script: Caller ID Name CNAM Lookup | VoIP Tech Chat
6 Jan 09 at 11:09 am
CNAM (CallerID with Name) on Asterisk using Reverse Phone number lookup…
CallerID is cool, but CallerID with Name (CNAM), — also known as Calling NAMe — is where it’s at. When you go with a traditional phone provider (non-VoIP) they’ll often offer you CallerID with Name for an additional fee. But……
VoIP & Gadgets Blog
7 Jan 09 at 11:08 am
[...] out this Perl script I found on Team Forrest’s website that leverages AGI (Asterisk Gateway Interface), a powerful interface that lets your [...]
CNAM (CallerID with Name) on Asterisk using Reverse Phone number lookup
7 Jan 09 at 11:56 am
the google phonebook and anywho never work. Google returns a 403 forbidden every time because using scripts to access its database are against its terms of service. 411.com returns a city and state only on anything it has a listing for, and I haven’t seen anywho return any results for me yet either. I know beggars can’t be choosers, but does anyone actually have this script working?
mulderlr
17 Mar 09 at 4:04 pm
Mulderlr,
This works for us consistently. Google will block it if you are hammering it, but I certainly assume that’s not the case here. Anywho also works for us. Why not give us a shout (use the contact page) and let’s see if we can’t help you with this.
Team Forrest
Team Forrest
17 Mar 09 at 4:11 pm
[...] Since I don’t like installing the module, don’t want to install a local lookup table, and don’t wish to cache CID names in a database, I’ve modified publicly available scripts as follows (also, check up the write up on Team Forrest, with a little more detail): [...]
Geeky Item of the Day - Free CNAM | Fred Posner dot com
27 Mar 09 at 2:10 pm
The Anywho query will not work anymore as their query structure has changed.
Frank
4 Apr 09 at 3:26 pm
Frank, you’re 100% correct. Anywho has changed… this is the hack:
sub anywho_lookup { my ($npa, $nxx, $station) = @_; my $ua = LWP::UserAgent->new( timeout => 45); my $URL = 'http://whitepages.anywho.com/results.php?ReportType=33'; $URL .= '&qnpa=' . $npa . '&qp=' . $nxx . $station; $ua->agent('AsteriskAGIQuery/1'); my $req = new HTTP::Request GET => $URL; my $res = $ua->request($req); if ($res->is_success()) { if ($res->content =~ /Find More Information for (.*)< \/a>/) { my $listing = $1; return $listing; } } return ""; }And I will update the post… Thanks!
Team Forrest
4 Apr 09 at 4:19 pm
Changed again This retrieves the info but I haven’t parsed it out yet.
sub anywho_lookup {
my ($npa, $nxx, $station) = @_;
my $ua = LWP::UserAgent->new( timeout => 45);
my $URL = ‘http://whitepages.anywho.com/results.php?ReportType=33&refer=2938&adword=ANYWHO.COM&qi=0&qk=10′;
#$URL .= ‘&qnpa=’ . $npa . ‘&qp=’ . $nxx . $station;
$URL .=
‘&qnpa=’. $npa .
‘&qnpanxx=’. $npa . $nxx .
‘&qnpanxx7=’. $npa . $nxx . substr($station,1,1) .
‘&qnxx=’ . $nxx .
‘&qp=’. $nxx . $station .
‘&qstation=’.$station .
‘&PHPSESSID=’ . ’626da7c88dfce19b235ce7088a96a336′;
$ua->agent(‘AsteriskAGIQuery/1′);
my $req = new HTTP::Request GET => $URL;
my $res = $ua->request($req);
if ($res->is_success()) {
print $res->content;
if ($res->content =~ /Find More Information for (.*)/) {
my $listing = $1;
return $listing;
}
}
return “”;
}
Have you used the whitepages api? Net::Whitepages
I’ve tried to get it working
my $White_Pages = Net::WhitePages->new( TOKEN => ’12345′, api_key => ‘mykey’ );
my $res = $White_Pages->reverse_phone( phone => “7990989890″ );
print $res;
What is this TOKEN for? Also where am I supposed to use my api_key?
What about WWW::WhoCallsMe
I put in my listed number and it never finds it.
use WWW::WhoCallsMe;
my $who = WWW::WhoCallsMe->new;
my $number = ’9870709989′;
my $calledme = $who->fetch($number);
if ($calledme->{listed})
{
my $name = $calledme->{name};
print “The number $number is listed. “;
print “It seems that $name was calling.” if $name;
print “I don’t know who was calling, though.” unless $name;
print “\n”;
}
else
{
print “This number is not listed.\n”;
}
Joseph Barnes
21 Apr 09 at 10:34 pm
Even using the updated code, lookups are still failing for anywho and google, with a fallback of www411 working only about 75% of the time (giving city/state rather than name).
Any new updates? I can use the URLs from the script in a browser and get a good lookup, but apparently the script won’t parse the info and return it to asterisk.
Robert Dailey
18 Nov 09 at 5:45 pm
Thanks Robert!
I’ve updated the code and fixed the others.
–fred
Team Forrest
18 Nov 09 at 10:14 pm
I don’t know about anybody else but this does not work period. At all.
The script is just fine. I had zero problems running the script.
It’s all the websites. I ran those directly against some test numbers:
http://www.google.com/search?rls=en&q=phonebook:$thenumber&ie=UTF-8&oe=UTF-8
That never works. Tried it with 20+ phone numbers and did not work. Tried with a 1, + etc, different formats.
http://phonenumbers.addresses.com/results.php?ReportType=33&qfilterpro=on&qi=0&qk=10&qnpa=$npa&qp=$qp
Does not work either. Tested with the same 20+ phone numbers and it did not work.
http://whocalled.us/do?action=getScore&name=$WhoCalled_name&pass=$WhoCalled_pass&phoneNumber=$thenumber
This only seems to work for telemarketers and debt collectors. I can see it being useful as a phone spam blocker, but not a CNAM lookup.
http://www.whitepages.com/search/ReversePhone?full_phone=$thenumber
1/20 success rate and it was a 10 year old business.
http://yellowpages.addresses.com/yellow-pages/phone:$thenumber/listings.html
2/20 and it was both old businesses again.
http://whitepages.anywho.com/results.php?&qnpa=$npa&qp=$telephone
Nothing. Again.
I guess my big question here is if this even worth the processing cycles? It seems as if there is no way to get even a 10% hit rate on the free lookup services available.
Ed
2 Jan 10 at 11:25 pm
Ed,
Google is good for primarily residential numbers. If we take an example of a Chicago area McDonald’s:
http://www.google.com/search?rls=en&q=phonebook:3128670455
(fail)
http://www.411.com/search/Reverse_Phone?phone=3128670455
(comes back with McDonald’s and more)
http://whitepages.anywho.com/results.php?qnpa=312&qnpanxx=312867&qnxx=867&qp=8670455&qstation=0455
(fail)
Lately, 411 is my favorite. If it fails on a identity it will at least tell you if it’s a land line, cellular, etc and the city / state.
Team Forrest
2 Jan 10 at 11:40 pm
How long has this blog been around? I have been searching for this kind of information for the past week and a half.
reverse cell phone lookup
22 Jan 10 at 10:17 pm
[...] Using AGI to get Caller ID Name CNAM | TEAM FORREST Blog [...]
Who’s Calling – Is there a Cell Phone Directory Out There? | Phone Lookup Reviews
22 Jan 10 at 11:34 pm
[...] da perfezionare, ma quest’oggi mi sono fatto prendere da questa cosa finendo per sbaglio suquesto link dove si parla del medesimo lookup in america tramite alcuni servizi locali. In pratica è possibile [...]
Asterisk: ID chiamante da elenco on-line Pagine Bianche « Free Support Notes
23 Jan 10 at 4:43 pm
[...] can be invoked in the same way as described here, i.e.: exten => s,n,Gosub(cidname-lookup,s,1) exten => s,n,dial(${PHONE},30,t) … [...]
Gingerlime » who’s calling?
27 Feb 10 at 12:43 am