TEAMFORREST

Asterisk, VoIP, and IT Consulting

Using AGI to get Caller ID Name CNAM

with 17 comments

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.

Written by Team Forrest

January 5th, 2009 at 3:13 pm

Posted in VoIP

Tagged with , , , , , , ,

17 Responses to 'Using AGI to get Caller ID Name CNAM'

Subscribe to comments with RSS or TrackBack to 'Using AGI to get Caller ID Name CNAM'.

  1. [...] 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 [...]

  2. 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……

  3. [...] out this Perl script I found on Team Forrest’s website that leverages AGI (Asterisk Gateway Interface), a powerful interface that lets your [...]

  4. 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

  5. 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

  6. [...] 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): [...]

  7. The Anywho query will not work anymore as their query structure has changed.

    Frank

    4 Apr 09 at 3:26 pm

  8. 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

  9. 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

  10. 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

  11. Thanks Robert!

    I’ve updated the code and fixed the others.

    –fred

    Team Forrest

    18 Nov 09 at 10:14 pm

  12. 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

  13. 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

  14. How long has this blog been around? I have been searching for this kind of information for the past week and a half.

  15. [...] Using AGI to get Caller ID Name CNAM | TEAM FORREST Blog [...]

  16. [...] 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 [...]

  17. [...] 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) … [...]

Leave a Reply