Hi,

Here are two basic pieces of python that will :
  • Extract the contacts from Zimbra address book, matching the 'PhoneSync' tag.
  • Erase phone address book, and upload the new contacts


Please ensure that you take a backup of your phone contacts, as they will be deleted by the second script.

The current limitation is that it only synchronize the first phone (in case you have multiple phones). The current directory must be writable, so the first script can create the list2phone.vcf file. The scripts are very basic, but might already be usefull.

C470-getZimbraContacts.py
Code:
#!/usr/bin/env python
# This script will delete all the content of the C470 phone 1, it will read the
# address book on zimbra and import it into the phone.
import urllib2
import sys
import re
import base64
import string
import mechanize
from urlparse import urlparse

# URL that gives access to the Address book 'Commun'
theurl = 'https://www.pivert.org/service/home/francoisd/Commun?fmt=vcf'
# Credentials
username = 'yourZimbrausername'
password = 'agoodpassword'
# The tag of the contacts to be synchronized. So, if you keep PhoneSync as
# category value, you must ensure that the contacts you want to synchronize are
# tagged with PhoneSync tag. (Case sensitive).
category = 'PhoneSync'

req = urllib2.Request(theurl)

try:
    handle = urllib2.urlopen(req)
except IOError, e:
    # here we *want* to fail
    pass
else:
    # If we don't fail then the page isn't protected
    print "This page isn't protected by authentication."
    sys.exit(1)

if not hasattr(e, 'code') or e.code != 401:
    # we got an error - but not a 401 error
    print "This page isn't protected by authentication."
    print 'But we failed for another reason.'
    sys.exit(1)

authline = e.headers['www-authenticate']
# this gets the www-authenticate line from the headers
# which has the authentication scheme and realm in it


authobj = re.compile(
    r'''(?:\s*www-authenticate\s*:)?\s*(\w*)\s+realm=['"]([^'"]+)['"]''',
    re.IGNORECASE)
# this regular expression is used to extract scheme and realm
matchobj = authobj.match(authline)

if not matchobj:
    # if the authline isn't matched by the regular expression
    # then something is wrong
    print 'The authentication header is badly formed.'
    print authline
    sys.exit(1)

scheme = matchobj.group(1)
realm = matchobj.group(2)
# here we've extracted the scheme
# and the realm from the header
if scheme.lower() != 'basic':
    print 'This example only works with BASIC authentication.'
    sys.exit(1)

base64string = base64.encodestring(
                '%s:%s' % (username, password))[:-1]
authheader =  "Basic %s" % base64string
req.add_header("Authorization", authheader)
try:
    handle = urllib2.urlopen(req)
except IOError, e:
    # here we shouldn't fail if the username/password is right
    print "It looks like the username or password is wrong."
    sys.exit(1)

vCardList = []
for row in handle:
    s = re.match('([\w;,=]+):(.*)\r\n', row)
    if s:
        a,b = s.group(1,2)
        if a == 'BEGIN' and b == 'VCARD':
            vCard = dict()
            toImport = False
        if a == 'FN':
            b = b.decode('utf-8')
            b = b.encode('latin-1')
            vCard['name'] = b
        s = re.search('TEL;TYPE=([^,]+)', a)
        if s :
            b = re.sub('^\+','00',b)
            b = re.sub(' ','',b)
            vCard[s.group(1)] = b
        if a == 'CATEGORIES' and string.find(b,category) != -1:
            toImport = True
        if a == 'END' and b == 'VCARD':
            if toImport == True:
                vCardList.append(vCard)

file = open('list2phone.vcf', 'w')
for row in vCardList:
    # home/cell/work
    s = re.search('(\w)\w+ (.*)',row['name'])
    if len(row['name']) > 14 and s:
        displayname = s.group(1) + '. ' + s.group(2)
    else:
        displayname = row['name'][:12]
    if row.has_key('home'):
        file.write('BEGIN:VCARD\r\n')
        file.write('VERSION:2.1\r\n')
        file.write('FN:' + displayname + ' (h)\r\n')
        file.write('N:' + displayname + ' (h)\r\n')
        file.write('TEL;HOME:' + row['home'] + '\r\n')
        file.write('END:VCARD\r\n')
        file.write('\r\n')

    if row.has_key('cell'):
        file.write('BEGIN:VCARD\r\n')
        file.write('VERSION:2.1\r\n')
        file.write('FN:' + displayname + ' (m)\r\n')
        file.write('N:' + displayname + ' (m)\r\n')
        file.write('TEL;CELL:' + row['cell'] + '\r\n')
        file.write('END:VCARD\r\n')
        file.write('\r\n')

    if row.has_key('work'):
        file.write('BEGIN:VCARD\r\n')
        file.write('VERSION:2.1\r\n')
        file.write('FN:' + displayname + ' (w)\r\n')
        file.write('N:' + displayname + ' (w)\r\n')
        file.write('TEL;WORK:' + row['work'] + '\r\n')
        file.write('END:VCARD\r\n')
        file.write('\r\n')
C470-phoneupload.py : you must change the ip address to match the ip of the C470 base.

Code:
#!/usr/bin/env python
import mechanize
import re
import time

br = mechanize.Browser()
br.open("http://192.168.xxx.xxx/")
try:
    br.select_form(name="gigaset")
    br["password"] = "0000"
    response1 = br.submit()
    response = br.open('/settings_telephony_tdt.html')

    br.select_form(name="gigaset")
    br.form.controls[0].readonly = False
    br["tdt_function"] = '3'
    response = br.submit()
    time.sleep(5)
    br.open('/stoptdt.html')
    response = br.open('/settings_telephony_tdt.html')
    br.select_form(name="gigaset")
    br.form.controls[0].readonly = False
    br["tdt_function"] = '2'
    br.form.add_file(open('./list2phone.vcf'), 'text/plain', 'tdt_file')
    response = br.submit()
    print('Starting to upload file to phone')
    time.sleep(50)
finally:
    time.sleep(5)
    print("Cleaning up !\n")
    br.open('/logout.html')