import telepathy
+import tp
import util.coroutines as coroutines
import gtk_toolbox
import handle
class AllContactsListChannel(
- telepathy.server.ChannelTypeContactList,
- telepathy.server.ChannelInterfaceGroup,
+ tp.ChannelTypeContactList,
+ tp.ChannelInterfaceGroup,
):
"""
The group of contacts for whom you receive presence
"""
- def __init__(self, connection, manager, props, h):
- try:
- # HACK Older python-telepathy way
- telepathy.server.ChannelTypeContactList.__init__(self, connection, h)
- self._requested = props[telepathy.interfaces.CHANNEL_INTERFACE + '.Requested']
- self._implement_property_get(
- telepathy.interfaces.CHANNEL_INTERFACE,
- {"Requested": lambda: self._requested}
- )
- except TypeError:
- # HACK Newer python-telepathy way
- telepathy.server.ChannelTypeContactList.__init__(self, connection, manager, props)
- telepathy.server.ChannelInterfaceGroup.__init__(self)
+ def __init__(self, connection, manager, props, listHandle):
+ tp.ChannelTypeContactList.__init__(self, connection, manager, props)
+ tp.ChannelInterfaceGroup.__init__(self)
self.__manager = manager
self.__props = props
self.__session = connection.session
-
- # HACK Older python-telepathy doesn't provide this
- self._immutable_properties = {
- 'ChannelType': telepathy.server.interfaces.CHANNEL_INTERFACE,
- 'TargetHandle': telepathy.server.interfaces.CHANNEL_INTERFACE,
- 'Interfaces': telepathy.server.interfaces.CHANNEL_INTERFACE,
- 'TargetHandleType': telepathy.server.interfaces.CHANNEL_INTERFACE,
- 'TargetID': telepathy.server.interfaces.CHANNEL_INTERFACE,
- 'Requested': telepathy.server.interfaces.CHANNEL_INTERFACE
- }
-
- self._callback = coroutines.func_sink(
- coroutines.expand_positional(
- self._on_contacts_refreshed
+ self.__listHandle = listHandle
+ self.__members = set()
+
+ if self._conn.options.useGVContacts:
+ self._callback = coroutines.func_sink(
+ coroutines.expand_positional(
+ self._on_contacts_refreshed
+ )
+ )
+ self.__session.addressbook.updateSignalHandler.register_sink(
+ self._callback
)
- )
- self.__session.addressbook.updateSignalHandler.register_sink(
- self._callback
- )
- self.GroupFlagsChanged(0, 0)
+ addressbook = connection.session.addressbook
+ contacts = addressbook.get_numbers()
+ self._process_refresh(addressbook, set(contacts), set(), set())
+ else:
+ self._callback = None
- addressbook = connection.session.addressbook
- contacts = addressbook.get_contacts()
- self._process_refresh(addressbook, contacts, [])
+ self.GroupFlagsChanged(0, 0)
- def get_props(self):
- # HACK Older python-telepathy doesn't provide this
- props = dict()
- for prop, iface in self._immutable_properties.items():
- props[iface + '.' + prop] = \
- self._prop_getters[iface][prop]()
- return props
@gtk_toolbox.log_exception(_moduleLogger)
def Close(self):
self.close()
def close(self):
- self.__session.addressbook.updateSignalHandler.unregister_sink(
- self._callback
- )
- self._callback = None
+ _moduleLogger.debug("Closing contact list")
+ if self._callback is not None:
+ self.__session.addressbook.updateSignalHandler.unregister_sink(
+ self._callback
+ )
+ self._callback = None
- telepathy.server.ChannelTypeContactList.Close(self)
- if self.__manager.channel_exists(self.__props):
- # HACK Older python-telepathy requires doing this manually
- self.__manager.remove_channel(self)
+ tp.ChannelTypeContactList.Close(self)
self.remove_from_connection()
@gtk_toolbox.log_exception(_moduleLogger)
+ def GetLocalPendingMembersWithInfo(self):
+ return []
+
+ @gtk_toolbox.log_exception(_moduleLogger)
def _on_contacts_refreshed(self, addressbook, added, removed, changed):
- self._process_refresh(addressbook, added, removed)
+ self._process_refresh(addressbook, added, removed, changed)
+
+ def _is_on_list(self, number):
+ return True
+
+ def _is_on_list_changed(self, number):
+ return (number in self.__members) ^ (self._is_on_list(number))
+
+ def _is_now_on_list(self, number):
+ return number not in self.__members and self._is_on_list(number)
+
+ def _was_on_list(self, number):
+ return number in self.__members and not self._is_on_list(number)
- def _process_refresh(self, addressbook, added, removed):
- _moduleLogger.info("Added: %r, Removed: %r" % (len(added), len(removed)))
+ def _process_refresh(self, addressbook, added, removed, changed):
+ _moduleLogger.info(
+ "%s Added: %r, Removed: %r" % (self.__listHandle.get_name(), len(added), len(removed))
+ )
connection = self._conn
+
+ # convert changed into added/removed
+ alsoAdded = set(
+ number
+ for number in changed
+ if self._is_now_on_list(number)
+ )
+ alsoRemoved = set(
+ number
+ for number in changed
+ if self._was_on_list(number)
+ )
+
+ # Merge the added/removed with changed
+ added = [
+ contactNumber
+ for contactNumber in added
+ if self._is_on_list(contactNumber)
+ ]
+ added.extend(alsoAdded)
+ added.sort()
handlesAdded = [
- handle.create_handle(connection, "contact", contactId, phoneNumber)
- for contactId in added
- for (phoneType, phoneNumber) in addressbook.get_contact_details(contactId)
+ handle.create_handle(connection, "contact", contactNumber)
+ for contactNumber in added
]
+ self.__members.union(added)
+
+ removed = list(removed)
+ removed.extend(alsoRemoved)
handlesRemoved = [
- handle.create_handle(connection, "contact", contactId, phoneNumber)
- for contactId in removed
- for (phoneType, phoneNumber) in addressbook.get_contact_details(contactId)
+ handle.create_handle(connection, "contact", contactNumber)
+ for contactNumber in removed
]
+ self.__members.difference(removed)
+
message = ""
actor = 0
reason = telepathy.CHANNEL_GROUP_CHANGE_REASON_NONE
)
+class DenyContactsListChannel(AllContactsListChannel):
+
+ def _is_on_list(self, number):
+ return self._conn.session.addressbook.is_blocked(number)
+
+
+_LIST_TO_FACTORY = {
+ # The group of contacts for whom you receive presence
+ 'subscribe': AllContactsListChannel,
+ # The group of contacts who may receive your presence
+ 'publish': AllContactsListChannel,
+ # A group of contacts who are on the publish list but are temporarily
+ # disallowed from receiving your presence
+ # This doesn't make sense to support
+ 'hide': None,
+ # A group of contacts who may send you messages
+ # Is this meant to serve as a definitive white list for all contact?
+ 'allow': None,
+ # A group of contacts who may not send you messages
+ 'deny': DenyContactsListChannel,
+ # On protocols where the user's contacts are stored, this contact list
+ # contains all stored contacts regardless of subscription status.
+ 'stored': AllContactsListChannel,
+}
+
+
+_SUPPORTED_LISTS = frozenset(
+ name
+ for name in _LIST_TO_FACTORY.iterkeys()
+ if name is not None
+)
+
+
def create_contact_list_channel(connection, manager, props, h):
- if h.get_name() == 'subscribe':
- # The group of contacts for whom you receive presence
- ChannelClass = AllContactsListChannel
- elif h.get_name() == 'publish':
- # The group of contacts who may receive your presence
- ChannelClass = AllContactsListChannel
- elif h.get_name() == 'hide':
- # A group of contacts who are on the publish list but are temporarily
- # disallowed from receiving your presence
- # This doesn't make sense to support
- _moduleLogger.warn("Unsuported type %s" % h.get_name())
- elif h.get_name() == 'allow':
- # A group of contacts who may send you messages
- # @todo Allow-List would be cool to support
- _moduleLogger.warn("Unsuported type %s" % h.get_name())
- elif h.get_name() == 'deny':
- # A group of contacts who may not send you messages
- # @todo Deny-List would be cool to support
- _moduleLogger.warn("Unsuported type %s" % h.get_name())
- elif h.get_name() == 'stored':
- # On protocols where the user's contacts are stored, this contact list
- # contains all stored contacts regardless of subscription status.
- ChannelClass = AllContactsListChannel
- else:
- raise TypeError("Unknown list type : " + h.get_name())
- return ChannelClass(connection, manager, props, h)
+ factory = _LIST_TO_FACTORY.get(h.get_name(), None)
+ if factory is None:
+ raise telepathy.errors.NotCapable("Unsuported type %s" % h.get_name())
+ return factory(connection, manager, props, h)
+def get_spported_lists():
+ return _SUPPORTED_LISTS