ibp (uk) Ltd. [~lars/addressbook] [~lars] [home]

OS X Address Book Snom hack

I recently got a Snom 190, and wanted to be able to dial from the Mac OS X Address Book. For once, this turned out to be easy, thanks to PyObjC. Most of the code was taken from here.

If you want to use this for yourself, you need to adjust SNOM_URL and tel_normalize.

To install, download plugin.py and setup.py, edit your plugin.py, and run:

$ python setup.py py2app
$ sudo mv dist/PySnomDial.bundle "/Library/Address Book Plug-Ins/"

On systems with PyObjc 1.x (i.e. before Leopard), the install step was:

$ sudo mv dist/PySnomDial.plugin "/Library/Address Book Plug-Ins/"

plugin.py

import sys
import logging
import urllib
from AddressBook import *
from AppKit import *

SNOM_URL='http://192.168.11.60/'

def tel_normalize(tel):
    """Normalize a telephone number so the Snom can dial it.

    There are some assumptions in this code; some based upon my location
    and some based upon the data in my Address Book:

    - the international prefix is 00
    - numbers in the Address Book that don't start with a 0 are numbers in
    Hamburg, Germany.
    - numbers without an international prefix are dialled without an
    international prefix (so this would break should I be abroad)."""
    for c in ('-', ' ', '\t'):
        tel = tel.replace(c, '')

    # adjust this for your international prefix
    if tel[0] == '+':
        return '00' + tel[1:]

    # adjust (or remove) this for your local prefix
    if tel[0] != '0':
        return '040' + tel

    return tel

class PyAddressLabelDelegate (NSObject):
    def actionProperty(self):
        return kABPhoneProperty

    def titleForPerson_identifier_(self, person, identifier):
        return u"Dial with Snom"

    def shouldEnableActionForPerson_identifier_(self, person, identifier):
        return len(person.phone()) > 0

    def performActionForPerson_identifier_(self, person, identifier):
        phones = person.valueForProperty_(kABPhoneProperty)
        p = phones.valueAtIndex_(phones.indexForIdentifier_(identifier))

        d = urllib.urlencode({'NUMBER': tel_normalize(p), 'DIAL': 'Dial',
                              'active_line': '1'})

        f = urllib.urlopen(SNOM_URL, data = d)
        f.close()

        log.debug('sent: %s', d)

# With python 2.4, logging.basicConfig takes keyword arguments and could do
# all the work
log = logging.getLogger('')
log.setLevel(logging.DEBUG)
log_formatter = logging.Formatter(
        '%(asctime)s PyAddressLabel %(levelname)-5s %(message)s')
# stdout in a plugin goes to console.log
hdlr = logging.StreamHandler()
hdlr.setFormatter(log_formatter)
log.addHandler(hdlr)

log.debug('loaded')

setup.py

"""
Script for building the example.

Usage:
    python setup.py py2app

To use this copy dist/PySnomDial.plugin to the plugin directory:
   $ mv dist/PySnomDial.plugin \
           ~/Library/Address\ Book\ Plug-Ins/PyAddressLabel.plugin
"""
from distutils.core import setup
import py2app

infoPlist = dict(
    CFBundleName='PySnomDial',
    CFBundleGetInfoString='Snom PopUp for AddressBook',
    CFBundleVersion='0.1',
    CFBundleShortVersionString = '0.1',
    NSPrincipalClass='PyAddressLabelDelegate',
)

setup(
    name='PySnomDial',
    plugin=['plugin.py'],
    data_files=[],
    options=dict(py2app=dict(
        extension=".bundle",
        plist=infoPlist,
    )),
)