who’s calling?

Caller ID is a wonderful feature. Don’t we love getting a call from someone we like, and perhaps more importantly, ignore those annoying callers who we really don’t want to talk to.

But this is yesterday’s news. We all have caller IDs. It just works. Well, yes. It does. But what if we get a call on our landline? We get the caller ID there too, but do we know who it is?? All our contacts are on our mobile phones. Standard phones don’t usually have the capacity to hold more than 10 names on average. And even if they did. Who’s got the energy to key in those numbers?

Enters Asterisk. Asterisk supports name as well as numbers for caller ID. But how do you get your asterisk to know the name of the caller? How can we inject the caller’s name into the caller ID string sent to our voip phones?

I’ve seen some online posts (like this one) about setting up look-up through online phone directories. I wanted something simpler. Why can’t I have my asterisk know who’s calling, based on my contacts on my iphone address book??

So here’s what I did. It can work on any address book format, as long as you can get it out as a csv (examples for iphone here and here). I created a simple CSV file, with two columns: Name and Number, which looks like this:

"Tony Blair",07392838482
"Gordon Brown",07893420393
"Kate Moss",07393837732
...

I then created a little python script to run on my asterisk box, and pull the name based on the number. It’s an AGI script, but it’s so basic it doesn’t actually need any AGI libraries:

#!/usr/bin/env python

import sys
import csv

if len(sys.argv) <= 1:    
    exit()
    
cid = sys.argv[1].replace("-","").replace(" ","").strip()

# accepting AGI input (but there's nothing to do with it)
while 1:
    line = sys.stdin.readline()
    if not line:
        break
    if line=="\n":
        break

fd = file("/usr/share/asterisk/agi-bin/my_iphone_address_book.csv")

print 'VERBOSE "STATUS: Looking up %s" 2' % cid
for line in csv.reader(fd):
    # note: comparing the number back-to-front, and only comparing 8 rightmost digits.
    #           This helps dealing with different prefix, e.g. +44, 00, 001 etc. and still getting 
    #           an accurate match.
    if line[1].replace("-","").replace(" ","").strip()[::-1][:8] == cid[::-1][:8]:
        print 'VERBOSE "STATUS: Found %s : %s" 2' % (cid, line[0].strip())
        print 'SET VARIABLE CALLERID(name) "%s"' % line[0].strip()
        exit()
print 'VERBOSE "STATUS: %s Not Found" 2' % cid

It 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)
...
[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.py,${CALLERID(NUM)})
exten => s,n,NoOp(Caller ID Name is now ${CALLERID(NAME)})
exten => s,n,Return

Note that it’s currently only working with full matches. The caller ID number must match the record on the address book precisely. Let me know if you have any simple ideas for partial matches (e.g. to avoid non matches of numbers, e.g. +447771110006 != 07771110006). I’ll do some more research when I get a chance.

Update: code now deals with partial matches rather effectively.

Another benefit is with voicemails. I started forwarding my voicemail straight to my asterisk box. My mobile provider doesn’t support visual voicemail yet, and I find it frustrating to use the old fashioned voicemail system. Now when I get an email with the voicemail message, I not only see the number of the caller, and can call them back with a click. I also see their name.

7 Responses to “who’s calling?”

  1. Andy Mueller

    Hi Yoav,

    I have just tried your Script who’s calling. Indeed it is wokring fine. If I do asterisk -r in CLI it shows me the following Errormessage:
    utils.c:1168 ast_carefulwrite: write() returned error: Broken pipe
    [Mar 14 07:45:51] ERROR[7848]: utils.c:1168 ast_carefulwrite: write() returned error: Broken pipe

    How Im going to resolve the issue, or at least ignore the Message. I’m not sure if it is critical as all is working fine so far.
    Thanks a lot for your Help.

    Best Regards

    Andy.

  2. Yoav Aner

    Hi Andy,

    It’s quite an old script now, but it’s still working for me. I noticed the same error as well. At least according to this blog post, this shouldn’t cause much concern and we can ignore those errors.

  3. Andy Mueller

    Hi Yoav,
    yes as already mentioned, for me it is working totally fine, except those two three pipe Errors I’m receiving all the Time. But my Question, do you have a newer Script based on Python that I could try.
    None of the Perl Scirpts are working with me. Maybe Im doing something wrong. I just installed the Perl Script for AGI as described and Perl is installed anyway on my Machine. Do you have an accurate HOWTO for agi isntall or another Python Script? Maybe that assist to analise the Errors.
    Best Regards

    Andy

  4. Andy Mueller

    Maybe the Fault is related to my way of usage. You mentioned it in your Script below, but is used my internal phonenumber for dialing:

    my way
    exten => s,n,Gosub(cidname-lookup,s,1)
    exten => s,n,dial(SIP/201,30,t)

    according to you
    exten => s,n,Gosub(cidname-lookup,s,1)
    exten => s,n,dial(${PHONE},30,t)

  5. Yoav Aner

    Sorry Andy, but it’s working for me for a couple of years now without a hitch. From what I read it’s working for you too. I don’t see much point worrying too much about an error message that seems to do no harm…

  6. John

    Really nice guide. I do need to create something in reverse of yours and I would appreciate some help if possible. I do need to send the incoming caller’s I’d to a php form.

Leave a Reply

css.php