diff --git a/src/sugar/activity/activity.py b/src/sugar/activity/activity.py index 0c1a2060..7c797e45 100644 --- a/src/sugar/activity/activity.py +++ b/src/sugar/activity/activity.py @@ -694,22 +694,23 @@ class Activity(Window, gtk.Container): def _send_invites(self): while self._invites_queue: - buddy_key = self._invites_queue.pop() - buddy = self._pservice.get_buddy(buddy_key) + account_path, contact_id = self._invites_queue.pop() + pservice = presenceservice.get_instance() + buddy = pservice.get_buddy(account_path, contact_id) if buddy: self.shared_activity.invite( buddy, '', self._invite_response_cb) else: logging.error('Cannot invite %s, no such buddy.', buddy_key) - def invite(self, buddy_key): + def invite(self, account_path, contact_id): """Invite a buddy to join this Activity. Side Effects: Calls self.share(True) to privately share the activity if it wasn't shared before. """ - self._invites_queue.append(buddy_key) + self._invites_queue.append((account_path, contact_id)) if (self.shared_activity is None or not self.shared_activity.props.joined): diff --git a/src/sugar/activity/activityservice.py b/src/sugar/activity/activityservice.py index 36f485c5..d7a31adb 100644 --- a/src/sugar/activity/activityservice.py +++ b/src/sugar/activity/activityservice.py @@ -67,8 +67,8 @@ class ActivityService(dbus.service.Object): self._activity.props.active = active @dbus.service.method(_ACTIVITY_INTERFACE) - def Invite(self, buddy_key): - self._activity.invite(buddy_key) + def Invite(self, account_path, contact_id): + self._activity.invite(account_path, contact_id) @dbus.service.method(_ACTIVITY_INTERFACE) def HandleViewSource(self): diff --git a/src/sugar/presence/activity.py b/src/sugar/presence/activity.py index 4d11a674..b4a3f5e9 100644 --- a/src/sugar/presence/activity.py +++ b/src/sugar/presence/activity.py @@ -288,14 +288,19 @@ class Activity(gobject.GObject): The callback will be called with one parameter: None on success, or an exception on failure. """ - op = buddy.object_path() - _logger.debug('%r: inviting %s', self, op) - self._activity.Invite(op, message, - reply_handler=lambda: response_cb(None), - error_handler=response_cb) + if not self._joined: + raise RuntimeError('Cannot invite a buddy to an activity that is' + 'not shared.') + self.telepathy_text_chan.AddMembers([buddy.contact_handle], message, + dbus_interface=CHANNEL_INTERFACE_GROUP, + reply_handler=partial(self.__invite_cb, response_cb), + error_handler=partial(self.__invite_cb, response_cb)) + + def __invite_cb(self, response_cb, error=None): + response_cb(error) def set_up_tubes(self, reply_handler, error_handler): - pass + raise NotImplementedError() def __joined_cb(self, join_command, error): _logger.debug('%r: Join finished %r', self, error) @@ -378,9 +383,9 @@ class Activity(gobject.GObject): properties = {} if self._color is not None: - properties['color'] = self._color + properties['color'] = str(self._color) if self._name is not None: - properties['name'] = self._name + properties['name'] = str(self._name) if self._type is not None: properties['type'] = self._type if self._tags is not None: diff --git a/src/sugar/presence/buddy.py b/src/sugar/presence/buddy.py index c83cdf96..d9f5fb35 100644 --- a/src/sugar/presence/buddy.py +++ b/src/sugar/presence/buddy.py @@ -21,14 +21,19 @@ STABLE. """ import logging +from functools import partial import gobject import gtk import dbus import gconf -from telepathy.interfaces import CONNECTION_INTERFACE_ALIASING, \ +from telepathy.interfaces import ACCOUNT, \ + CONNECTION, \ + CONNECTION_INTERFACE_ALIASING, \ CONNECTION_INTERFACE_CONTACTS +from telepathy.constants import HANDLE_TYPE_CONTACT +ACCOUNT_MANAGER_SERVICE = 'org.freedesktop.Telepathy.AccountManager' CONN_INTERFACE_BUDDY_INFO = 'org.laptop.Telepathy.BuddyInfo' _logger = logging.getLogger('sugar.presence.buddy') @@ -247,31 +252,45 @@ class BaseBuddy(gobject.GObject): class Buddy(BaseBuddy): __gtype_name__ = 'PresenceBuddy' - def __init__(self, connection, contact_handle): + def __init__(self, account_path, contact_id): + _logger.debug('Buddy.__init__') BaseBuddy.__init__(self) - self._contact_handle = contact_handle + self._account_path = account_path + self.contact_id = contact_id + self.contact_handle = None + + _logger.info('KILL_PS Handle the connection going away and coming back') + + bus = dbus.Bus() + obj = bus.get_object(ACCOUNT_MANAGER_SERVICE, account_path) + connection_path = obj.Get(ACCOUNT, 'Connection') + connection_name = connection_path.replace('/', '.')[1:] + + obj = bus.get_object(connection_name, connection_path) + handles = obj.RequestHandles(HANDLE_TYPE_CONTACT, [self.contact_id], + dbus_interface=CONNECTION) + self.contact_handle = handles[0] - bus = dbus.SessionBus() self._get_properties_call = bus.call_async( - connection.requested_bus_name, - connection.object_path, + connection_name, + connection_path, CONN_INTERFACE_BUDDY_INFO, 'GetProperties', 'u', - (self._contact_handle,), + (self.contact_handle,), reply_handler=self.__got_properties_cb, error_handler=self.__error_handler_cb, utf8_strings=True, byte_arrays=True) self._get_attributes_call = bus.call_async( - connection.requested_bus_name, - connection.object_path, + connection_name, + connection_path, CONNECTION_INTERFACE_CONTACTS, 'GetContactAttributes', 'auasb', - ([self._contact_handle], [CONNECTION_INTERFACE_ALIASING], False), + ([self.contact_handle], [CONNECTION_INTERFACE_ALIASING], False), reply_handler=self.__got_attributes_cb, error_handler=self.__error_handler_cb) @@ -283,7 +302,7 @@ class Buddy(BaseBuddy): def __got_attributes_cb(self, attributes): _logger.debug('__got_attributes_cb %r', attributes) self._get_attributes_call = None - self._update_attributes(attributes[self._contact_handle]) + self._update_attributes(attributes[self.contact_handle]) def __error_handler_cb(self, error): _logger.debug('__error_handler_cb %r', error) diff --git a/src/sugar/presence/presenceservice.py b/src/sugar/presence/presenceservice.py index b36f4698..d561d942 100644 --- a/src/sugar/presence/presenceservice.py +++ b/src/sugar/presence/presenceservice.py @@ -32,6 +32,7 @@ from sugar.presence.buddy import Buddy, Owner from sugar.presence.activity import Activity from sugar.presence.util import get_connection_manager +from telepathy.constants import HANDLE_TYPE_CONTACT _logger = logging.getLogger('sugar.presence.presenceservice') @@ -314,23 +315,16 @@ class PresenceService(gobject.GObject): error_handler=lambda e: \ self._get_buddies_error_cb(error_handler, e)) - def get_buddy(self, key): - """Retrieve single Buddy object for the given public key + def get_buddy(self, account_path, contact_id): + logging.info('KILL_PS decide how to invalidate this cache') + if (account_path, contact_id) in self._buddy_cache: + return self._buddy_cache[(account_path, contact_id)] - key -- buddy's public encryption key - - returns single Buddy object or None if the activity - is not found using GetBuddyByPublicKey on the - service - """ - try: - buddy_op = self._ps.GetBuddyByPublicKey(dbus.ByteArray(key)) - except dbus.exceptions.DBusException: - _logger.exception('Unable to retrieve buddy handle for %r from ' - 'presence service', key) - return None - return self._new_object(buddy_op) + buddy = Buddy(account_path, contact_id) + self._buddy_cache[(account_path, contact_id)] = buddy + return buddy + # DEPRECATED def get_buddy_by_telepathy_handle(self, tp_conn_name, tp_conn_path, handle): """Retrieve single Buddy object for the given public key @@ -346,15 +340,22 @@ class PresenceService(gobject.GObject): channel-specific handle. :Returns: the Buddy object, or None if the buddy is not found """ - logging.info('KILL_PS decide how to invalidate this cache') - if (tp_conn_path, handle) in self._buddy_cache: - return self._buddy_cache[(tp_conn_path, handle)] - else: - bus = dbus.SessionBus() - connection = bus.get_object(tp_conn_name, tp_conn_path) - buddy = Buddy(connection, handle) - self._buddy_cache[(tp_conn_path, handle)] = buddy - return buddy + + bus = dbus.Bus() + obj = bus.get_object(ACCOUNT_MANAGER_SERVICE, ACCOUNT_MANAGER_PATH) + account_manager = dbus.Interface(obj, ACCOUNT_MANAGER) + account_paths = account_manager.Get(ACCOUNT_MANAGER, 'ValidAccounts', + dbus_interface=PROPERTIES_IFACE) + for account_path in account_paths: + obj = bus.get_object(ACCOUNT_MANAGER_SERVICE, account_path) + connection_path = obj.Get(ACCOUNT, 'Connection') + if connection_path == tp_conn_path: + connection_name = connection_path.replace('/', '.')[1:] + connection = bus.get_object(connection_name, connection_path) + contact_ids = connection.InspectHandles(HANDLE_TYPE_CONTACT, [handle]) + return self.get_buddy(account_path, contact_ids[0]) + + raise ValueError('Unknown buddy in connection %s with handle %d', tp_conn_path, handle) def get_owner(self): """Retrieves the laptop Buddy object."""