On syncing with Google Contacts

Share

So, I started with a new company a few weeks ago, and one of the things I missed from my previous company was having the entire corporate directory synced onto my phone. Its really handy as an on caller to be able to give people a call when something goes wrong, without having to dig around and find their details.

Back in the good old days at Google the way you got this sort of data onto your phone was to run a script written by one of the guys on the gmail team. The script grabbed the LDAP directory, and pushed it into Google contacts, which you could then sync with your phone. Now I wanted something very similar — especially as the contacts sync stuff with Android is pretty reasonable.

However, I’d never coded with the Google public APIs before, and that turned out to be the hardest part of the problem.

First off I wrote a little script which dumped the corporate directory into a text file. I mostly did this because I wanted other people to be able to run the script in as light weight a manner as possible — for example, if we wanted to roll this out for hundreds of people, then you wouldn’t want to run the LDAP query hundreds of times. The format for my text file is kinda lame to be honest:

    Michael Still: {'telephoneNumber': ['+61 123 123 123'], 'ID': ['mikalstill'], 'mail': ['mikal@stillhq.com']}
    

So, you get the user’s name, then a python dictionary with three keys in it. There isn’t any particular reason for having just three keys, it was just the three fields I thought were most interesting at the time. Note that each field is an array. A simple human readable format like this means that I can also grep through the file if I ever quickly want a user’s details, which is a nice side effect.

The most important thing I learnt here is that the ID field is really important. If you don’t have something you feel you can use there, then you might need to synthesize something — perhaps an ascii representation of the user’s name or something. This is important because I discovered that Google rewrites Unicode characters you ask it to store, so if you do a simple text comparison against the user’s name, then you might get a false negative and end up creating more than one entry for that user. That was particularly a problem for me because there are a fair few people in the company with European accented characters in their names.

The docs for the Google contacts API are ok, although I did have to spend some time randomly searching for examples of some of the things I wanted to do. For example, the docs didn’t have an example of how to store a phone number that I could find. Also, I am a little shocked to discover there is no query interface in contacts for contact name. This seems like a pretty massive oversight to me, but here’s what the docs have to say on the issue:

For more information about query parameters, see the Contacts Data API Reference Guide and the Google Data APIs Reference Guide. In particular, there is no support for full-text queries or locating a contact by email address.

Whatever intern wrote the API should have his ball pit rights revoked until he fixes that. After that it was all gravy. Here’s the code: http://www.stillhq.com/svn/trunk/google-contacts/pushdirectory.py.

I note that there is an enterprise shared contacts API (see here), but you have to be a premiere customer for it to work.

Share

Getting Google Talk working with PyXMPP

Share

Jacek Konieczny has written the wholly fantabulous PyXMPP, which implements Jabber clients and servers in Python. Now, Google Talk is a Jabber server, but it needs TLS support before it works. The code is all there, but the echobot example in the download (look in the examples directory) doesn’t show you how. It’s not that hard though — here’s the patch I needed to make it work:

    --- echobot.py  2005-12-26 07:25:55.000000000 -0800
    +++ echobot2.py 2006-10-25 04:25:02.000000000 -0700
    @@ -13,6 +13,7 @@
    
     from pyxmpp.all import JID,Iq,Presence,Message,StreamError
     from pyxmpp.jabber.client import JabberClient
    +from pyxmpp import streamtls
    
     class Client(JabberClient):
         """Simple bot (client) example. Uses `pyxmpp.jabber.client.JabberClient`
    @@ -28,8 +29,12 @@
    
             # setup client with provided connection information
             # and identity data
    +
    +        tls = streamtls.TLSSettings(require=True, verify_peer=False)
    +        auth = ['sasl:PLAIN']
             JabberClient.__init__(self, jid, password,
    -                disco_name="PyXMPP example: echo bot", disco_type="bot")
    +                disco_name="PyXMPP example: echo bot", disco_type="bot",
    +                tls_settings=tls, auth_methods=auth)
    
             # register features to be announced via Service Discovery
             self.disco_info.add_feature("jabber:iq:version")
    

That makes the __init__ method for the client:

    def __init__(self, jid, password):
    
        # if bare JID is provided add a resource -- it is required
        if not jid.resource:
            jid=JID(jid.node, jid.domain, "Echobot")
    
        # setup client with provided connection information
        # and identity data
    
        tls = streamtls.TLSSettings(require=True, verify_peer=False)
        auth = ['sasl:PLAIN']
        JabberClient.__init__(self, jid, password,
                disco_name="PyXMPP example: echo bot", disco_type="bot",
                tls_settings=tls, auth_methods=auth)
    
        # register features to be announced via Service Discovery
        self.disco_info.add_feature("jabber:iq:version")
    

Now the client works with a gtalk login:

    $ ./echobot2.py username@gmail.com supersecretthingie
    creating client...
    connecting...
    *** State changed: resolving srv (u'gmail.com', 'xmpp-client') ***
    *** State changed: resolving 'talk.l.google.com.' ***
    *** State changed: connecting ('72.14.253.125', 5222) ***
    *** State changed: connected ('72.14.253.125', 5222) ***
    looping...
    *** State changed: tls connecting  ***
    *** State changed: tls connected  ***
    *** State changed: fully connected  ***
    *** State changed: authenticated  ***
    *** State changed: binding u'Echobot' ***
    *** State changed: authorized  ***
    mikalstill@gmail.com/Gaim6734F991 has become available
    mikalstill@gmail.com/GaimD2ECF56B has become available(away): I'm not at my
    desk at work at the moment. This is probably because I'm at a meeting or
    racing electric scooters. If you IM me I will see the message when I get back.
    My roster:
    mikalstill@gmail.com "" subscription=both groups=
    Message from mikalstill@gmail.com/Gaim6734F991 received. Body: "Hello there". Type: "chat".
    disconnecting...
    exiting...
    $
    

Too easy.

Update: mbot is a Google Talk bot engine built on top of this.

Share

Looking for Women studying computing in Australia

Share

I was in an unrelated meeting at work today, and it came up that the first annual Anti Borg scholarship is closing it’s application window in a few days. I thought it was worth mentioning here, in case there are people who are interested in applying. The basic deal is:

Dr. Anita Borg (1949 – 2003) devoted her adult life to revolutionizing the way we think about technology and dismantling barriers that keep women and minorities from entering computing and technology fields. Her combination of technical expertise and fearless vision continues to inspire and motivate countless women to become active participants and leaders in creating technology.

As part of Google’s ongoing commitment to furthering Anita’s vision, we are pleased to announce the 2006 Google Australia Anita Borg Scholarship. Through the scholarship, we would like to encourage women to excel in computing and technology and become active role models and leaders.

Scholarships will be awarded based on the strength of candidates’ academic background and demonstrated leadership. A group of female undergraduate and postgraduate student finalists will be chosen from the applicant pool. The scholarship recipients, selected from the finalists, will each receive a $5,000 AUD scholarship for the 2007 academic year.

All finalists will be invited to visit Google Sydney in November 2006 for a networking retreat. It will include workshops with a series of speakers, breakout sessions and social activities. The visit is meant to be an opportunity for all finalists to meet and share their experiences.

If that sounds interesting to you and you’re a lady studying computing or a related field, then you should checkout the announcement page before it’s too late.

Share

Kinderplex

Share

The kids are the in the Kinderplex today (the Google-only child care center). It’s the first time I’ve dropped Matthew off for care and he hasn’t gone ape — I think it’s because he loved the center so much… There are computers in every room, and it’s probably the nicest laid out and supplied child care center I have ever seen. It makes me wonder if I should be sending Andrew there next year for pre-school.

Share

What’s happening with frozenchicken.com?

Share

Gordon at work asks me what is happening with www.frozenchicken.com. If you hit the site, then you get the Google search interface. This is because of the DNS configuration for the domain:

    challenger:~# host www.frozenchicken.com
    www.frozenchicken.com is an alias for www.google.com.
    www.google.com is an alias for www.l.google.com.
    www.l.google.com has address 66.102.7.147
    www.l.google.com has address 66.102.7.99
    www.l.google.com has address 66.102.7.104
    www.frozenchicken.com is an alias for www.google.com.
    www.google.com is an alias for www.l.google.com.
    www.frozenchicken.com is an alias for www.google.com.
    www.google.com is an alias for www.l.google.com.
    

You can see that www.frozenchicken.com is an alias for www.google.com, which in turn points to what is presumably my local cluster.

So why do all the links of the Google page then point via www.frozenchicken.com? Well, because they’re relative URLs, they use the hostname from the browser.

Share

A first taste of Google blog reader

Share

So, Google has released a beta of their bloglines equivalent service, and given that Liferea crashes about four times a day for me I thought I would give it a go. Login et cetera is easy, and the user interface is nice and AJAXy. It’s fairly intuitive as well, although when I was importing my OPML file from Liferea I missed the message at the top saying the import was in progress as first.

That said, it’s been 30 minutes and it still says it’s importing my 460 line OPML file. I just refreshed the page for the import, and the import stopped and said that I now had 54 subscriptions. So, I guess that means I should wait longer for the import. I’m now going to try importing over the top and see if it’s smart enough to squelch duplicates.

Share