Sync Google Contacts with Asterisk

Recent comments

Who's new

  • rhpot1991

Sync Google Contacts with Asterisk

Submitted by rhpot1991 on Thu, 07/29/2010 - 14:54

I posted a few weeks back about a SIP project I had been working on, this is the first in (hopefully) a series of posts about neat things I am doing with this setup. Spoiled by my Android phone, the Caller ID on my "house phone" wasn't up to par, so I set out to fix this.

For those of you unfamiliar with my Asterisk setup, after Mario showed me his setup I set out to join in the fun. I picked up the following:

Now onto the actual point of this post, I created a Python script which can be run on your Asterisk box to sync up your Google contacts. The script will retrieve all of your Google contacts, normalize their numbers and store them into the Asterisk Databse. Then you can then perform a lookup on the database when incoming calls occur.

First you will need to get the gdata-python-client in order to access your Google contacts. The install directions should handle everything you need to know. On my OpenWrt router I had to install the packages by hand to /usr/lib/python2.6, and needed to install the python-expat and python-openssl packages.

Now that you have the python client installed, download my script to a location of your choice and make it executable (chmod +x). Edit the script and insert your Google email address and password into the proper locations. Now execute the script and you should see feedback indicating that your contacts are being added to the Asterisk Database.

All of your Google contacts should now be in the Asterisk Database, lets verify that by running the following:
root@moonbaseone:~# asterisk -r
Connected to Asterisk currently running on moonbaseone (pid = 1790)
moonbaseone*CLI> database show cidname

Once you have verified your contacts are appearing in the database, lets move on and have Asterisk use these as Caller ID Names on incoming calls. Add the following to the incoming call portion of your /etc/asterisk/extensions.conf file:
exten => s,n,Set(CALLERID(name)=${DB(cidname/${CALLERID(num)})})

Then reload the extensions:
root@moonbaseone:~# asterisk -r
Connected to Asterisk currently running on moonbaseone (pid = 1790)
moonbaseone*CLI> dialplan reload
Dialplan reloaded.

Your incoming calls should now display the name located in your Google contacts if the phone numbers match. At this point I would recommend adding the script to a daily cronjob, so your changes continue to sync. If you are on an OpenWrt system you may want to move your Asterisk Database to a permanent location so you don't lose it if you ever reboot. To do this simply modify /etc/init.d/asterisk and replace:
[ -h $DEST/usr/lib/asterisk/astdb ] || ln -sf /var/spool/asterisk/astdb $DEST/usr/lib/asterisk/astdb
[ -h $DEST/usr/lib/asterisk/astdb ] || rm /var/spool/asterisk/astdb

It should be noted that my phone number normalizing regex only handles numbers that I am familiar with, so US numbers. If it doesn't work with your numbers or you had to tweak something, leave a comment below.

UPDATE: If you recently upgraded to Asterisk 1.8 and started using the native Google Voice support then you will notice that this method no longer works with your calls. The Google Voice CallerID is passed in a different way, luckily it is an easy work around, head over to Mario Limonciello's blog and check out his solution.

Anonymous (not verified)

Thu, 07/29/2010 - 15:37

Awesome, I think I'll integrate this but with a small improvement, change the database table to be cidname_. That way I can use multiple gmail accounts, and also use it in conjunction with other cid lookup and caching scripts.

I've also been pondering using google documents to make a two way bridge between the asterisk database, and something that is easy to access from the web (blacklist, whitelist, distinctive ring, call logs, etc).

This worked great for me--thanks!

I made a couple tweaks to my setup because I'm using SIPGate and the caller ID isn't prefixed with a "+1", so I took the "+" out of the line that begins with "os.system(..." and changed the country_code variable to "".

I also set the Caller ID up by going into FreePBX and creating a lookup source called "Google Contacts" with Source Type internal and cache results on. Then I set up my inbound route to use that as a caller id lookup source.

David Merrick

"a small improvement, change the database table to be cidname_. "
Thanks for this hint! I tried to figure it by myself for 2 months! I see you know things about Drupal and I truly hope you will give more useful advice in comments or guest posts)

Anonymous (not verified)

Mon, 08/02/2010 - 11:55

Hello! Thanks for the script!
I was looking for something like this for ages.
I have a problem tough. Can you explain the formating options in your script?
I have both belgian (+32) and us (+1) numbers and I can't get it work.
I don't get the
phone.text = re.sub('^\+1|^1|\(|\)|\s|-', '', phone.text)
os.system("asterisk -rx \'database put cidname +1%s \"%s\"\'" % (phone.text,entry.title.text))
Could you develop a little bit? Thanks!


Tue, 08/03/2010 - 00:44

In reply to by Anonymous (not verified)

What I am doing there is stripping out the following characters: leading +1, leading 1, (, ), -, and any whitespace. Then in the next line I append a +1 to whatever number I am left with. This will result in numbers like: +15555555555, which match the phone numbers that my asterisk receives calls from.

I uploaded a new version of the script, with some changes that should make your multiple country code usage easier, and the regex modified to remove all non-digits. Hopefully it works on your non US numbers, I guessed on them. I added comments where applicable, let me know how it works.

Anonymous (not verified)

Thu, 10/21/2010 - 16:57

very nice program, it works perfectly but what if I have my local cardDAV server??

I want to have a global address book editable from my network users. I used carddav.

It is the same as googles but it is locally. Can I somehow change the address of the server???

I'm not sure if its possible, you will have to check the gdata documentation, I didn't see anything when I did a quick search. Another option is to use a modified copy of the gdata cleint which points at your servers instead.

Anonymous (not verified)

Tue, 10/26/2010 - 18:12

Good morning!

Nice, useful script, very comprehend HOWTO.

Everything worked fine for me, but one problem occured: As I'm working with a couple of russian clients, my gmail-adress-book stores names them in cyrillic letters. By importing these contacts to my *-DB cyrillic letters convert to "Ðлена Ðойнова", for example.

As I'm not familiar with python hope you can propose a workaround.

Best regards,
Sebastian, Germany

Anonymous (not verified)

Sun, 11/14/2010 - 17:55

I am still getting asterisks as the callerid for all the calls, can you please give me some pointers.

when i run the following command:
database show cidname

OpenWrt*CLI> database show cidname
/cidname/+17407075678 : Testing Tester

Appreciate your help.

That looks correct to me. Make sure you added the following to the correct incoming call section of your extensions.conf:
exten => s,n,Set(CALLERID(name)=${DB(cidname/${CALLERID(num)})})

Its also possible that you may need to use a different portion of the CALLERID for your phone, see the available options here:

Anonymous (not verified)

Sun, 12/04/2011 - 23:26

Amazing post regarding Sync Google Contacts with Asterisk. Never have I thought it could be implemented. Thanks

Anonymous (not verified)

Sun, 12/11/2011 - 21:06

Wow, I love this! Fantastic, elegant solution. Thank you!

Anonymous (not verified)

Fri, 01/27/2012 - 23:35

Everything worked fine for me, but one problem occured: As I'm working with a couple of russian clients, my gmail-adress-book stores names them in cyrillic letters. By importing these contacts to my *-DB cyrillic letters convert to "Ðлена Ðойнова",

Anonymous (not verified)

Sun, 03/04/2012 - 08:22

Thank you very much for sharing it... I was looking for something similar, and this one just did the job! :P

Anonymous (not verified)

Sat, 08/18/2012 - 22:02

Thanks a million for this. I just moved ported my mobile number to google voice. I use an Obi110 with asterisk and the callerid comes in without the + symbol. I removed the + from the database put cidname line so all my contacts go in without the plus and callerid matching was perfect.

Anonymous (not verified)

Tue, 12/04/2012 - 16:28

Great script. I made a little change because the incoming callerid format coming from my VOIP service is unpredictable (+XXY.., 00XXY.., 0Y..). Instead of trying to match the entire number, prefix and country code, I'm stripping the incoming number down to the last 8 digits and matching against that. It works very well.

In the script:
phone.text = phone.text[-8:]
phone.text = re.sub('\D', '', phone.text)
os.system("asterisk -rx \'database put cidname %s%s \"%s\"\'" % (country_code,phone.text,entry.title.text))

And on the Asterisk side:
exten => s,1,Set(CALLERID(name)=${DB(cidname/${CALLERID(num):-8,8})})

Anonymous (not verified)

Tue, 02/12/2013 - 09:42

Thanks for putting together a great script. This was a fantastic place to start in my quest to sync with Asteridex (for PBX in a Flash).

Here's my modified code (insert after line beginning with "feed = ", and reformat for Python). I don't pretend to be a programmer, but I enjoy learning new things, so this was a fun challenge for me.

# Create a connection to MySQL
# Change the parameters if you are not using PBX in a Flash
con = MySQLdb.connect(host='localhost', user='root', passwd='passw0rd', db='asteridex')
cur = con.cursor()

# delete all of our contacts before we refetch them, this will allow deletions to propogate
cur.execute("DELETE FROM user1")

# re-instantiate the cursor
cur = con.cursor()

# for each phone number in the contacts
for i, entry in enumerate(feed.entry):
for phone in entry.phone_number:
# Strip out any non numeric characters
phone.text = re.sub('\D', '', phone.text)

# Remove leading digit if it exists, we will add this again later for all numbers
# Only if a country code is defined.
if country_code != "":
phone.text = re.sub('^\+?%s' % country_code, '', phone.text)

# Insert the number into the cidname database, reinsert the country code if defined.
name = entry.title.text
num = phone.text
if str(name).strip() != "None":
cur.execute("INSERT INTO user1(`name`, `out`, `email`) VALUES (%s,%s,%s)",(name,num,"NULL"))
print str(name) + " was inserted into the database"


Anonymous (not verified)

Mon, 04/15/2013 - 05:23

Found these guys done it..... waiting for their launch though..