6 import util.coroutines as coroutines
7 import util.misc as misc_utils
11 _moduleLogger = logging.getLogger(__name__)
14 class AllContactsListChannel(
15 tp.ChannelTypeContactList,
16 tp.ChannelInterfaceGroup,
19 The group of contacts for whom you receive presence
22 def __init__(self, connection, manager, props, listHandle):
23 tp.ChannelTypeContactList.__init__(self, connection, manager, props)
24 tp.ChannelInterfaceGroup.__init__(self)
26 self.__manager = manager
28 self.__session = connection.session
29 self.__listHandle = listHandle
30 self.__members = set()
32 if self._conn.options.useGVContacts:
33 self._callback = coroutines.func_sink(
34 coroutines.expand_positional(
35 self._on_contacts_refreshed
38 self.__session.addressbook.updateSignalHandler.register_sink(
42 addressbook = connection.session.addressbook
43 contacts = addressbook.get_numbers()
44 self._process_refresh(addressbook, set(contacts), set(), set())
48 self.GroupFlagsChanged(0, 0)
51 @misc_utils.log_exception(_moduleLogger)
56 _moduleLogger.debug("Closing contact list")
57 if self._callback is not None:
58 self.__session.addressbook.updateSignalHandler.unregister_sink(
63 tp.ChannelTypeContactList.Close(self)
64 self.remove_from_connection()
66 @misc_utils.log_exception(_moduleLogger)
67 def GetLocalPendingMembersWithInfo(self):
70 @misc_utils.log_exception(_moduleLogger)
71 def _on_contacts_refreshed(self, addressbook, added, removed, changed):
72 self._process_refresh(addressbook, added, removed, changed)
74 def _is_on_list(self, number):
77 def _is_on_list_changed(self, number):
78 return (number in self.__members) ^ (self._is_on_list(number))
80 def _is_now_on_list(self, number):
81 return number not in self.__members and self._is_on_list(number)
83 def _was_on_list(self, number):
84 return number in self.__members and not self._is_on_list(number)
86 def _process_refresh(self, addressbook, added, removed, changed):
88 "%s Added: %r, Removed: %r" % (self.__listHandle.get_name(), len(added), len(removed))
90 connection = self._conn
92 # convert changed into added/removed
96 if self._is_now_on_list(number)
100 for number in changed
101 if self._was_on_list(number)
104 # Merge the added/removed with changed
107 for contactNumber in added
108 if self._is_on_list(contactNumber)
110 added.extend(alsoAdded)
113 handle.create_handle(connection, "contact", contactNumber)
114 for contactNumber in added
116 self.__members.union(added)
118 removed = list(removed)
119 removed.extend(alsoRemoved)
121 handle.create_handle(connection, "contact", contactNumber)
122 for contactNumber in removed
124 self.__members.difference(removed)
128 reason = telepathy.CHANNEL_GROUP_CHANGE_REASON_NONE
131 handlesAdded, handlesRemoved,
138 class DenyContactsListChannel(AllContactsListChannel):
140 def _is_on_list(self, number):
141 return self._conn.session.addressbook.is_blocked(number)
145 # The group of contacts for whom you receive presence
146 'subscribe': AllContactsListChannel,
147 # The group of contacts who may receive your presence
148 'publish': AllContactsListChannel,
149 # A group of contacts who are on the publish list but are temporarily
150 # disallowed from receiving your presence
151 # This doesn't make sense to support
153 # A group of contacts who may send you messages
154 # Is this meant to serve as a definitive white list for all contact?
156 # A group of contacts who may not send you messages
157 'deny': DenyContactsListChannel,
158 # On protocols where the user's contacts are stored, this contact list
159 # contains all stored contacts regardless of subscription status.
160 'stored': AllContactsListChannel,
164 _SUPPORTED_LISTS = frozenset(
166 for name in _LIST_TO_FACTORY.iterkeys()
171 def create_contact_list_channel(connection, manager, props, h):
172 factory = _LIST_TO_FACTORY.get(h.get_name(), None)
174 raise telepathy.errors.NotCapable("Unsuported type %s" % h.get_name())
175 return factory(connection, manager, props, h)
178 def get_spported_lists():
179 return _SUPPORTED_LISTS