Switching to shipping parts of python-telepathy with The One Ring so random changes...
[theonering] / src / gvoice / addressbook.py
1 #!/usr/bin/python
2
3
4 import logging
5
6 import util.coroutines as coroutines
7 import util.misc as util_misc
8
9
10 _moduleLogger = logging.getLogger("gvoice.addressbook")
11
12
13 class Addressbook(object):
14
15         def __init__(self, backend):
16                 self._backend = backend
17                 self._contacts = {}
18
19                 self.updateSignalHandler = coroutines.CoTee()
20
21         def update(self, force=False):
22                 if not force and self._contacts:
23                         return
24                 oldContacts = self._contacts
25                 oldContactIds = set(self.get_contact_ids())
26
27                 self._contacts = {}
28                 self._populate_contacts()
29                 newContactIds = set(self.get_contact_ids())
30
31                 addedContacts = newContactIds - oldContactIds
32                 removedContacts = oldContactIds - newContactIds
33                 changedContacts = set(
34                         contactId
35                         for contactId in newContactIds.intersection(oldContactIds)
36                         if self._has_contact_changed(contactId, oldContacts)
37                 )
38
39                 if addedContacts or removedContacts or changedContacts:
40                         message = self, addedContacts, removedContacts, changedContacts
41                         self.updateSignalHandler.stage.send(message)
42
43         def get_contact_ids(self):
44                 return self._contacts.iterkeys()
45
46         def get_contact_name(self, contactId):
47                 return self._contacts[contactId][0]
48
49         def get_contact_details(self, contactId):
50                 return iter(self._contacts[contactId][1])
51
52         def find_contacts_with_number(self, queryNumber):
53                 strippedQueryNumber = util_misc.strip_number(queryNumber)
54                 for contactId, (contactName, contactDetails) in self.get_contact_ids():
55                         for phoneType, number in contactDetails:
56                                 if number == strippedQueryNumber:
57                                         yield contactId
58
59         def _populate_contacts(self):
60                 if self._contacts:
61                         return
62                 contacts = self._backend.get_contacts()
63                 for contactId, contactDetails in contacts:
64                         contactName = contactDetails["name"]
65                         contactNumbers = [
66                                 (
67                                         numberDetails.get("phoneType", "Mobile"),
68                                         util_misc.strip_number(numberDetails["phoneNumber"]),
69                                 )
70                                 for numberDetails in contactDetails["numbers"]
71                         ]
72                         self._contacts[contactId] = (contactName, contactNumbers)
73
74         def _has_contact_changed(self, contactId, oldContacts):
75                 oldContact = oldContacts[contactId]
76                 oldContactName = oldContact[0]
77                 oldContactDetails = oldContact[1]
78                 if oldContactName != self.get_contact_name(contactId):
79                         return True
80                 if not oldContactDetails:
81                         return False
82                 # if its already in the old cache, purposefully add it into the new cache
83                 return oldContactDetails != self.get_contact_details(contactId)