Für uns iPhone- und Mac-Jünger ist die Mac OS X Adressverwaltung wunderbar integriert. Leider fehlte mir bisher eine Möglichkeit zum abgleich des Adressbuchs mit der Fritzbox. Das folgende Python-Programm schrieb ich, um dem abhilfe zu verschaffen. Ich suche noch immer nach einer Möglichkeit, das Programm per automatischen job einzuplanen – Hilfe wäre mir hier sehr willkommen!?
Das Python-Script zum ausführen und
Download: iPyFritz
Der Aufruf erfolgt nach dem entpacken per Doppelklick oder im Terminal mithilfe folgenden Befehls:
Dies erzeugt die Datei: myfritz.adressbuch.xml – welche in der Fritzbox unter “Telefonbuch – Wiederherstellen” eingespielt werden kann. VORSICHT – ALLE ALTEN EINTRÄGE WERDEN GELÖSCHT!!!
Für alle die ein paar Euro ausgeben möchten und können, könnte das hier interessanter sein: fritz.mac Suite. Wobei es in meinen Tests nicht die gleichen Ziele wie mein Adressbuch-exporter hat und die Fax-Anbindung an der 7370 zu abbrüchen führte…
Und hier das Coding / Thx a lot to programmish ); for releasing his snippet under public domain.
Update 11.04.2010
Nur Nickname-Fehler korrigiert
Mazo-Kategorie Update 17.04.2010
Das Script setzt das “Wichtig”-Flag für Personen die einen Nickname gepflegt haben im Adressbuch.
Update 23.04.2010
weitere Alternativen: Fakes Blog
Update 12.05.2010
Suche immer noch nach einer Möglichkeit per launchd (cron alternative) das Adressbuch automatisch zu syncen… Über einen Tipp würde ich mich sehr freuen.
from AddressBook import *
import re
from xml.dom.minidom import *
def addressBookToList():
"""
Copyright (c) 2010, J.Rumpf, www.web-dreamer.de / BSD Licence
All rights reserved.
original found on: http://www.programmish.com/?p=26 released under public domain
Read the current user's AddressBook database, converting each person
in the address book into a Dictionary of values. Some values (addresses,
phone numbers, email, etc) can have multiple values, in which case a
list of all of those values is stored. The result of this method is
a List of Dictionaries, with each person represented by a single record
in the list.
Redistribution and use in source and binary forms, with or without modification
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, th
is list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
Neither the name of the owner nor the names of its contributors may be used
to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Read the current user's AddressBook database, converting each person
in the address book into a Dictionary of values. Some values (addresses,
phone numbers, email, etc) can have multiple values, in which case a
list of all of those values is stored. The result of this method is
a List of Dictionaries, with each person represented by a single recordq
in the list.
"""
# get the shared addressbook and the list of
# people from the book.
ab = ABAddressBook.sharedAddressBook()
people = ab.people()
peopleList = []
# convert the ABPerson to a hash
for person in people:
thisPerson = {}
props = person.allProperties()
for prop in props:
# skip some properties
if prop == "com.apple.ABPersonMeProperty":
continue
elif prop == "com.apple.ABImageData":
continue
# How we convert the value depends on the ObjC
# class used to represent it
val = person.valueForProperty_(prop)
if (type(val) == objc.pyobjc_unicode) and val != None:
if val.canBeConvertedToEncoding_(NSISOLatin1StringEncoding): #NSUTF8StringEncoding
thisPerson[prop.lower()] = val.cStringUsingEncoding_(NSISOLatin1StringEncoding)
else:
# Unicode String
thisPerson[prop.lower()] = '* '
thisPerson[prop.lower()] += val.cStringUsingEncoding_(NSUTF8StringEncoding)
# thisPerson[prop.lower()] = thisPerson[prop.lower()].encode('iso-8859-1', 'xmlcharrefreplace')
elif issubclass(val.__class__, NSDate):
# NSDate
thisPerson[prop.lower()] = val.description()
elif type(val) == ABMultiValueCoreDataWrapper:
# List -- convert each item in the list
# into the proper format
thisPerson[prop.lower()] = {} #[]
for valIndex in range(0, val.count()):
indexedValue = val.valueAtIndex_(valIndex)
indexedKey = val.labelAtIndex_(valIndex)
if indexedKey == val.primaryIdentifier:
indexedKey += '+'
if type(indexedValue) == objc.pyobjc_unicode:
# Unicode string
thisPerson[prop.lower()].update({indexedKey.cStringUsingEncoding_(4): indexedValue.cStringUsingEncoding_(4)})
elif issubclass(indexedValue.__class__, NSDate):
# Date
thisPerson[prop.lower()].update({prop.lower(): indexedValue.description()})
elif type(indexedValue) == NSCFDictionary:
# NSDictionary -- convert to a Python Dictionary
propDict = {}
for propKey in indexedValue.keys():
propValue = indexedValue[propKey]
propDict[propKey.lower()] = propValue
thisPerson[prop.lower()].update(propDict)
peopleList.append(thisPerson)
return peopleList
format = re.compile('[ -()-]')
m49 = re.compile('\+49')
mlist = addressBookToList()
#print kABPhoneHomeLabel
#print kABPhoneMobileLabel
#print kABPhoneWorkLabel
#print kABOtherLabel
#print mlist[25]
"""
<phonebooks>
<phonebook>
<contact>
<category>0</category>
<person><realName></realName></person>
<telephony>
<number type="home" vanity="" prio="1" quickdial="4"></number>
<number type="mobile" vanity="" prio="0"></number>
<number type="work" vanity="" prio="0"></number>
</telephony>
<services />
<setup />
</contact>
"""
# Create the minidom document
doc = Document()
phonebooks = doc.createElement("phonebooks")
doc.appendChild(phonebooks)
phonebook = doc.createElement("phonebook")
phonebooks.appendChild(phonebook)
for pers in mlist:
name = pers.get(kABLastNameProperty.lower(),'') + ', ' + pers.get(kABFirstNameProperty.lower(),'')
if name == ', ':
name = pers.get(kABOrganizationProperty.lower())
if name == None:
name = pers.get(kABNicknameProperty.lower())
# print name
if name == None:
name = "NoName?"
contact = doc.createElement("contact")
phonebook.appendChild(contact)
category = doc.createElement("category")
contact.appendChild(category)
# person with nik is important >:
nikname = pers.get(kABNicknameProperty.lower())
if nikname == None:
cat = "0"
else:
cat = "1"
cat_0 = doc.createTextNode(cat)
category.appendChild(cat_0)
person = doc.createElement("person")
contact.appendChild(person)
realname = doc.createElement("realName")
person.appendChild(realname)
p_inhalt = doc.createTextNode(name)
realname.appendChild(p_inhalt)
pers_phone = pers.get(kABPhoneProperty.lower())
if pers_phone != None:
telephony = doc.createElement("telephony")
contact.appendChild(telephony)
# quickdial = format.sub('' ,pers_phone.get( "Quickdial", '' ), 0)
prio = 1
home = format.sub('' ,pers_phone.get(kABPhoneHomeLabel,''), 0)
home = m49.sub('0', home)
if home != '':
number = None
number = doc.createElement("number")
telephony.appendChild(number)
number.setAttribute("type", "home")
number.setAttribute("vanity", "")
number.setAttribute("prio", '%d' % prio)
prio += 1
#number.setAttribute("quickdial", "")
num_home = doc.createTextNode(home)
number.appendChild(num_home)
mobile = format.sub('', pers_phone.get( kABPhoneMobileLabel, '' ), 0)
mobile = m49.sub('0', mobile )
if mobile != '':
number = None
number = doc.createElement("number")
telephony.appendChild(number)
number.setAttribute("type", "mobile")
number.setAttribute("vanity", "")
number.setAttribute("prio", '%d' % prio )
prio += 1
#number.setAttribute("quickdial", "")
num_home = doc.createTextNode(mobile)
number.appendChild(num_home)
work = format.sub('' ,pers_phone.get( kABPhoneWorkLabel, ''), 0)
work = m49.sub('0', work )
if work != '':
number = None
number = doc.createElement("number")
telephony.appendChild(number)
number.setAttribute("type", "work")
number.setAttribute("vanity", "")
number.setAttribute("prio", '%d' % prio)
prio += 1
#number.setAttribute("quickdial", "")
num_home = doc.createTextNode(work)
number.appendChild(num_home)
if ((home == '') and (mobile == '') and ( work == '')):
other = format.sub('' ,pers_phone.get( kABOtherLabel, '' ), 0)
other = m49.sub('0', other )
number = doc.createElement("number")
telephony.appendChild(number )
number.setAttribute("type", "home")
number.setAttribute("vanity", "")
number.setAttribute("prio", '%d' % prio)
prio += 1
#number.setAttribute("quickdial", "")
num_home = doc.createTextNode(other)
number.appendChild(num_home)
f = open('myfritz.adressbuch.xml', 'w')
doc.writexml(f, '', '', '' , 'iso-8859-1')