Forum Archive

Distinguish contacts between two accounts

tonytx05

Is there a way to determine if a contact exists in a specific account? For example, my iPad syncs with both an Exchange server and iCloud, and I am trying to clean up some of the duplicates between both accounts. However, when I look at the contacts returned by Python, I can’t find a way to distinguish which account a specific contact came from. Is there a way to do this that I am missing?

mikael

@tonytx05, for some reason (I am guessing historically poor API design that they are now a bit stuck with), Apple has made the link between contacts and accounts difficult to determine, even with the ObjectiveC API. See e.g. here.

cvp

@tonytx05 could you test this little quick and dirty script, and give me some feedback.
I can't really test because I only have iCloud contacts...

from objc_util import *
import contacts

# ObjectiveC contacts
objc_contacts = {}
CNContactStore = ObjCClass('CNContactStore').alloc().init()
CNContact = ObjCClass('CNContact')
Containers = CNContactStore.containersMatchingPredicate_error_(None,None)
for Container in Containers:
    id = Container.identifier()
    predicate = CNContact.predicateForContactsInContainerWithIdentifier_(id)
    # keys not exactly like in Apple doc
    # found a sample here https://github.com/tdamdouni/Pythonista/blob/master/contacts/Add%20Twitter%20Profile%20Picture%20to%20iOS%20Contacts.py
    predicate_contacts = CNContactStore.unifiedContactsMatchingPredicate_keysToFetch_error_(predicate, ['familyName','givenName','middleName'], None)
    for contact in predicate_contacts:
        # crash if attribute not in fetched contacts
        name = str(contact.givenName()) + '|' + str(contact.middleName()) + '|' + str(contact.familyName())
        objc_contacts[name] = id

# Pythonista contacts
all_contacts = contacts.get_all_people()
for person in all_contacts:
    key = person.first_name + '|' + person.middle_name + '|' + person.last_name
    id = '****'
    if key in objc_contacts:
        id = objc_contacts[key]
    print(key, id)
mikael

@cvp, works for me, thanks!

I can get a semi-legible name for the container with:

print(container.name(), '-', container.descriptionForContainerType_(container.type()))

... but from the contents I am still not sure which are from Gmail - ”Address Book - CardDav” or ”Personal Contacts - Exchange”...

cvp

@mikael I can't help. Perhaps by putting one contact only in one account?

mikael

Looks like Gmail is the ”Address Book”/”CardDAV” container. People being in more than one container was throwing me off.

@cvp, I adjusted your code a little to show repeated entries for people in more than one container:

from objc_util import *
import contacts

# ObjectiveC contacts
objc_contacts = {}
CNContactStore = ObjCClass('CNContactStore').alloc().init()
CNContact = ObjCClass('CNContact')
Containers = CNContactStore.containersMatchingPredicate_error_(None,None)
containers = {}
for Container in Containers:
    id = Container.identifier()
    containers[id] = Container
    #print(dir(Container))
    predicate = CNContact.predicateForContactsInContainerWithIdentifier_(id)
    # keys not exactly like in Apple doc
    # found a sample here https://github.com/tdamdouni/Pythonista/blob/master/contacts/Add%20Twitter%20Profile%20Picture%20to%20iOS%20Contacts.py
    predicate_contacts = CNContactStore.unifiedContactsMatchingPredicate_keysToFetch_error_(predicate, ['familyName','givenName','middleName'], None)
    for contact in predicate_contacts:
        # crash if attribute not in fetched contacts
        name = str(contact.givenName()) + '|' + str(contact.middleName()) + '|' + str(contact.familyName())
        cont_per_name = objc_contacts.setdefault(name, [])
        cont_per_name.append(id)

# Pythonista contacts
all_contacts = contacts.get_all_people()
for person in all_contacts:
    key = person.first_name + '|' + person.middle_name + '|' + person.last_name
    id = '****'
    if key in objc_contacts:
        for id in objc_contacts[key]:
          container = containers[id]
          print(key, '-', container.name(), '-', container.descriptionForContainerType_(container.type()))
cvp

@mikael 👍thanks

cvp

@mikael Could you edit your post to replace "adjusted" by "improved" 😀

mikael

@cvp, no, thank you - I would not have had the time for the ObjC gymnastics at this time.

cvp

@mikael I agree that, with my very small knowledge about ObjC, I spend sometimes a lot of hours to finally write a so little script, but I have this time as retired 👴🏻

osamu

Matching by the name...
Is this the only way to correlate Pythonista contacts person.id and CNContact identifier()? 😟