Fixing a connecting bug
[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, asyncPool):
19                 self._backend = backend
20                 self._numbers = {}
21                 self._asyncPool = asyncPool
22
23                 self.updateSignalHandler = coroutines.CoTee()
24
25         def update(self, force=False):
26                 if not force and self._numbers:
27                         return
28                 self._asyncPool.add_task(
29                         self._backend.get_contacts,
30                         (),
31                         {},
32                         self._on_get_contacts,
33                         self._on_get_contacts_failed,
34                 )
35
36         def _on_get_contacts(self, contacts):
37                 oldContacts = self._numbers
38                 oldContactNumbers = set(self.get_numbers())
39
40                 self._numbers = self._populate_contacts(contacts)
41                 newContactNumbers = set(self.get_numbers())
42
43                 addedContacts = newContactNumbers - oldContactNumbers
44                 removedContacts = oldContactNumbers - newContactNumbers
45                 changedContacts = set(
46                         contactNumber
47                         for contactNumber in newContactNumbers.intersection(oldContactNumbers)
48                         if self._numbers[contactNumber] != oldContacts[contactNumber]
49                 )
50
51                 if addedContacts or removedContacts or changedContacts:
52                         message = self, addedContacts, removedContacts, changedContacts
53                         self.updateSignalHandler.stage.send(message)
54
55         @misc_utils.log_exception(_moduleLogger)
56         def _on_get_contacts_failed(self, error):
57                 _moduleLogger.error(error)
58
59         def get_numbers(self):
60                 return self._numbers.iterkeys()
61
62         def get_contact_name(self, strippedNumber):
63                 """
64                 @throws KeyError if contact not in list (so client can choose what to display)
65                 """
66                 return self._numbers[strippedNumber][0]
67
68         def get_phone_type(self, strippedNumber):
69                 try:
70                         return self._numbers[strippedNumber][1]
71                 except KeyError:
72                         return "unknown"
73
74         def is_blocked(self, strippedNumber):
75                 try:
76                         return self._numbers[strippedNumber][2]["response"] == self._RESPONSE_BLOCKED
77                 except KeyError:
78                         return False
79
80         def _populate_contacts(self, contacts):
81                 numbers = {}
82                 for contactId, contactDetails in contacts:
83                         contactName = contactDetails["name"]
84                         contactNumbers = (
85                                 (
86                                         misc_utils.normalize_number(numberDetails["phoneNumber"]),
87                                         numberDetails.get("phoneType", "Mobile"),
88                                 )
89                                 for numberDetails in contactDetails["numbers"]
90                         )
91                         numbers.update(
92                                 (number, (contactName, phoneType, contactDetails))
93                                 for (number, phoneType) in contactNumbers
94                         )
95                 return numbers