Adding fancier version checks to allow to the cache to be preserved longer
[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 misc_utils
8
9
10 _moduleLogger = logging.getLogger(__name__)
11
12
13 class Addressbook(object):
14
15         _RESPONSE_GOOD = 0
16         _RESPONSE_BLOCKED = 3
17
18         def __init__(self, backend):
19                 self._backend = backend
20                 self._numbers = {}
21
22                 self.updateSignalHandler = coroutines.CoTee()
23
24         def update(self, force=False):
25                 if not force and self._numbers:
26                         return
27                 oldContacts = self._numbers
28                 oldContactNumbers = set(self.get_numbers())
29
30                 self._numbers = {}
31                 self._populate_contacts()
32                 newContactNumbers = set(self.get_numbers())
33
34                 addedContacts = newContactNumbers - oldContactNumbers
35                 removedContacts = oldContactNumbers - newContactNumbers
36                 changedContacts = set(
37                         contactNumber
38                         for contactNumber in newContactNumbers.intersection(oldContactNumbers)
39                         if self._numbers[contactNumber] != oldContacts[contactNumber]
40                 )
41
42                 if addedContacts or removedContacts or changedContacts:
43                         message = self, addedContacts, removedContacts, changedContacts
44                         self.updateSignalHandler.stage.send(message)
45
46         def get_numbers(self):
47                 return self._numbers.iterkeys()
48
49         def get_contact_name(self, strippedNumber):
50                 """
51                 @throws KeyError if contact not in list (so client can choose what to display)
52                 """
53                 return self._numbers[strippedNumber][0]
54
55         def get_phone_type(self, strippedNumber):
56                 try:
57                         return self._numbers[strippedNumber][1]
58                 except KeyError:
59                         return "unknown"
60
61         def is_blocked(self, strippedNumber):
62                 try:
63                         return self._numbers[strippedNumber][2]["response"] == self._RESPONSE_BLOCKED
64                 except KeyError:
65                         return False
66
67         def _populate_contacts(self):
68                 if self._numbers:
69                         return
70                 contacts = self._backend.get_contacts()
71                 for contactId, contactDetails in contacts:
72                         contactName = contactDetails["name"]
73                         contactNumbers = (
74                                 (
75                                         misc_utils.normalize_number(numberDetails["phoneNumber"]),
76                                         numberDetails.get("phoneType", "Mobile"),
77                                 )
78                                 for numberDetails in contactDetails["numbers"]
79                         )
80                         self._numbers.update(
81                                 (number, (contactName, phoneType, contactDetails))
82                                 for (number, phoneType) in contactNumbers
83                         )