Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomeu Vizoso <tomeu@sugarlabs.org>2010-03-23 11:34:25 (GMT)
committer Tomeu Vizoso <tomeu.vizoso@collabora.co.uk>2010-08-20 13:02:26 (GMT)
commit40e5531bc210efca8dff0af388b8cbbbc78446ea (patch)
tree40f641efb774585f8634188d977f61df68fc253a
parentbd685374977856d9a78b6cfe8fcb190fcadc5ef5 (diff)
First implementation of invitations from non-Sugar clients
-rw-r--r--src/jarabe/frame/activitiestray.py227
-rw-r--r--src/jarabe/model/invites.py158
-rw-r--r--src/jarabe/model/owner.py39
-rw-r--r--src/jarabe/model/telepathyclient.py97
4 files changed, 259 insertions, 262 deletions
diff --git a/src/jarabe/frame/activitiestray.py b/src/jarabe/frame/activitiestray.py
index f594342..473036c 100644
--- a/src/jarabe/frame/activitiestray.py
+++ b/src/jarabe/frame/activitiestray.py
@@ -41,7 +41,7 @@ from sugar import env
from jarabe.model import shell
from jarabe.model import neighborhood
-from jarabe.model import owner
+from jarabe.model import invites
from jarabe.model import bundleregistry
from jarabe.model import filetransfer
from jarabe.view.palettes import JournalPalette, CurrentActivityPalette
@@ -49,7 +49,6 @@ from jarabe.view.pulsingicon import PulsingIcon
from jarabe.view import launcher
from jarabe.frame.frameinvoker import FrameWidgetInvoker
from jarabe.frame.notification import NotificationIcon
-from jarabe.journal import misc
import jarabe.frame
@@ -102,21 +101,54 @@ class ActivityButton(RadioToolButton):
self._icon.props.pulsing = False
-class BaseInviteButton(ToolButton):
+
+class InviteButton(ToolButton):
+ """Invite to shared activity"""
def __init__(self, invite):
ToolButton.__init__(self)
+
self._invite = invite
+ self.connect('clicked', self.__clicked_cb)
+ self.connect('destroy', self.__destroy_cb)
+
+ bundle_registry = bundleregistry.get_registry()
+ bundle = bundle_registry.get_bundle(invite.get_bundle_id())
+
self._icon = Icon()
+ logging.info('KILL_PS get the inviter''s colors')
+ #self._icon.props.xo_color = activity_model.get_color()
+ if bundle is not None:
+ self._icon.props.file = bundle.get_icon()
+ else:
+ self._icon.props.icon_name = 'image-missing'
self.set_icon_widget(self._icon)
self._icon.show()
- self.connect('clicked', self.__clicked_cb)
- self.connect('destroy', self.__destroy_cb)
+ palette = InvitePalette(invite)
+ palette.props.invoker = FrameWidgetInvoker(self)
+ palette.set_group_id('frame')
+ self.set_palette(palette)
+
self._notif_icon = NotificationIcon()
self._notif_icon.connect('button-release-event',
self.__button_release_event_cb)
+ logging.info('KILL_PS get the inviter''s colors')
+ #self._notif_icon.props.xo_color = activity_model.get_color()
+ if bundle is not None:
+ self._notif_icon.props.icon_filename = bundle.get_icon()
+ else:
+ self._notif_icon.props.icon_name = 'image-missing'
+
+ palette = InvitePalette(invite)
+ palette.props.invoker = WidgetInvoker(self._notif_icon)
+ palette.set_group_id('frame')
+ self._notif_icon.palette = palette
+
+ frame = jarabe.frame.get_view()
+ frame.add_notification(self._notif_icon, gtk.CORNER_TOP_LEFT)
+
def __button_release_event_cb(self, icon, event):
self.emit('clicked')
@@ -127,106 +159,38 @@ class BaseInviteButton(ToolButton):
self._notif_icon = None
self._launch()
- def _launch(self):
- """Launch the target of the invite"""
- raise NotImplementedError
-
def __destroy_cb(self, button):
frame = jarabe.frame.get_view()
frame.remove_notification(self._notif_icon)
-class ActivityInviteButton(BaseInviteButton):
- """Invite to shared activity"""
- def __init__(self, invite):
- BaseInviteButton.__init__(self, invite)
- mesh = neighborhood.get_model()
- activity_model = mesh.get_activity(invite.get_activity_id())
- self._activity_model = activity_model
- self._bundle_id = activity_model.get_bundle_id()
-
- self._icon.props.xo_color = activity_model.get_color()
- if activity_model.get_icon_name():
- self._icon.props.file = activity_model.get_icon_name()
- else:
- self._icon.props.icon_name = 'image-missing'
-
- palette = ActivityInvitePalette(invite)
- palette.props.invoker = FrameWidgetInvoker(self)
- palette.set_group_id('frame')
- self.set_palette(palette)
-
- self._notif_icon.props.xo_color = activity_model.get_color()
- if activity_model.get_icon_name():
- icon_name = activity_model.get_icon_name()
- self._notif_icon.props.icon_filename = icon_name
- else:
- self._notif_icon.props.icon_name = 'image-missing'
-
- palette = ActivityInvitePalette(invite)
- palette.props.invoker = WidgetInvoker(self._notif_icon)
- palette.set_group_id('frame')
- self._notif_icon.palette = palette
-
- frame = jarabe.frame.get_view()
- frame.add_notification(self._notif_icon,
- gtk.CORNER_TOP_LEFT)
-
def _launch(self):
"""Join the activity in the invite."""
- registry = bundleregistry.get_registry()
- bundle = registry.get_bundle(self._bundle_id)
-
- misc.launch(bundle, color=self._activity_model.get_color())
-
-class PrivateInviteButton(BaseInviteButton):
- """Invite to a private one to one channel"""
- def __init__(self, invite):
- BaseInviteButton.__init__(self, invite)
- self._private_channel = invite.get_private_channel()
- self._bundle_id = invite.get_bundle_id()
- client = gconf.client_get_default()
- color = XoColor(client.get_string('/desktop/sugar/user/color'))
+ shell_model = shell.get_model()
+ activity = shell_model.get_activity_by_id(self._activity_model.get_id())
+ if activity:
+ activity.get_window().activate(gtk.get_current_event_time())
+ return
- self._icon.props.xo_color = color
registry = bundleregistry.get_registry()
- self._bundle = registry.get_bundle(self._bundle_id)
-
- if self._bundle:
- self._icon.props.file = self._bundle.get_icon()
- else:
- self._icon.props.icon_name = 'image-missing'
-
- palette = PrivateInvitePalette(invite)
- palette.props.invoker = FrameWidgetInvoker(self)
- palette.set_group_id('frame')
- self.set_palette(palette)
-
- self._notif_icon.props.xo_color = color
-
- if self._bundle:
- self._notif_icon.props.icon_filename = self._bundle.get_icon()
- else:
- self._notif_icon.props.icon_name = 'image-missing'
+ bundle = registry.get_bundle(self._bundle_id)
- palette = PrivateInvitePalette(invite)
- palette.props.invoker = WidgetInvoker(self._notif_icon)
- palette.set_group_id('frame')
- self._notif_icon.palette = palette
+ launcher.add_launcher(self._activity_model.get_id(),
+ bundle.get_icon(),
+ self._activity_model.get_color())
- frame = jarabe.frame.get_view()
- frame.add_notification(self._notif_icon,
- gtk.CORNER_TOP_LEFT)
+ handle = ActivityHandle(self._activity_model.get_id())
+ activityfactory.create(bundle, handle)
- def _launch(self):
- """Start the activity with private channel."""
- misc.launch(self._bundle, uri=self._private_channel)
-class BaseInvitePalette(Palette):
+class InvitePalette(Palette):
"""Palette for frame or notification icon for invites."""
- def __init__(self):
+
+ def __init__(self, invite):
Palette.__init__(self, '')
+ self._invite = invite
+
menu_item = MenuItem(_('Join'), icon_name='dialog-ok')
menu_item.connect('activate', self.__join_activate_cb)
self.menu.append(menu_item)
@@ -237,73 +201,24 @@ class BaseInvitePalette(Palette):
self.menu.append(menu_item)
menu_item.show()
- def __join_activate_cb(self, menu_item):
- self._join()
-
- def __decline_activate_cb(self, menu_item):
- self._decline()
-
- def _join(self):
- raise NotImplementedError
-
- def _decline(self):
- raise NotImplementedError
-
-
-class ActivityInvitePalette(BaseInvitePalette):
- """Palette for shared activity invites."""
-
- def __init__(self, invite):
- BaseInvitePalette.__init__(self)
-
- mesh = neighborhood.get_model()
- activity_model = mesh.get_activity(invite.get_activity_id())
- self._activity_model = activity_model
- self._bundle_id = activity_model.get_bundle_id()
+ bundle_id = invite.get_bundle_id()
registry = bundleregistry.get_registry()
- self._bundle = registry.get_bundle(self._bundle_id)
+ self._bundle = registry.get_bundle(bundle_id)
if self._bundle:
self.set_primary_text(self._bundle.get_name())
else:
- self.set_primary_text(self._bundle_id)
+ self.set_primary_text(bundle_id)
- def _join(self):
- misc.launch(self._bundle, activity_id=self._activity_model.get_id())
+ def __join_activate_cb(self, menu_item):
+ self._invite.join()
- def _decline(self):
- invites = owner.get_model().get_invites()
+ def __decline_activate_cb(self, menu_item):
+ invites = invites.get_instance()
activity_id = self._activity_model.get_id()
invites.remove_activity(activity_id)
-class PrivateInvitePalette(BaseInvitePalette):
- """Palette for private channel invites."""
-
- def __init__(self, invite):
- BaseInvitePalette.__init__(self)
-
- self._private_channel = invite.get_private_channel()
- self._bundle_id = invite.get_bundle_id()
-
- registry = bundleregistry.get_registry()
- self._bundle = registry.get_bundle(self._bundle_id)
- if self._bundle:
- self.set_primary_text(self._bundle.get_name())
- else:
- self.set_primary_text(self._bundle_id)
-
- def _join(self):
- misc.launch(self._bundle, uri=self._private_channel)
-
- invites = owner.get_model().get_invites()
- invites.remove_private_channel(self._private_channel)
-
- def _decline(self):
- invites = owner.get_model().get_invites()
- invites.remove_private_channel(self._private_channel)
-
-
class ActivitiesTray(HTray):
def __init__(self):
HTray.__init__(self)
@@ -320,7 +235,7 @@ class ActivitiesTray(HTray):
self._home_model.connect('tabbing-activity-changed',
self.__tabbing_activity_changed_cb)
- self._invites = owner.get_model().get_invites()
+ self._invites = invites.get_instance()
for invite in self._invites:
self._add_invite(invite)
self._invites.connect('invite-added', self.__invite_added_cb)
@@ -396,20 +311,12 @@ class ActivitiesTray(HTray):
self._remove_invite(invite)
def _add_invite(self, invite):
- """Add an invite (SugarInvite or PrivateInvite)"""
- item = None
- if hasattr(invite, 'get_activity_id'):
- mesh = neighborhood.get_model()
- activity_model = mesh.get_activity(invite.get_activity_id())
- if activity_model is not None:
- item = ActivityInviteButton(invite)
- else:
- item = PrivateInviteButton(invite)
- if item is not None:
- item.connect('clicked', self.__invite_clicked_cb, invite)
- self.add_item(item)
- item.show()
- self._invite_to_item[invite] = item
+ """Add an invite"""
+ item = InviteButton(invite)
+ item.connect('clicked', self.__invite_clicked_cb, invite)
+ self.add_item(item)
+ item.show()
+ self._invite_to_item[invite] = item
def _remove_invite(self, invite):
self.remove_item(self._invite_to_item[invite])
diff --git a/src/jarabe/model/invites.py b/src/jarabe/model/invites.py
index f4c7d71..abe6d39 100644
--- a/src/jarabe/model/invites.py
+++ b/src/jarabe/model/invites.py
@@ -17,50 +17,43 @@
import logging
import gobject
-from sugar.presence import presenceservice
+import dbus
+from telepathy.interfaces import CHANNEL, \
+ CHANNEL_DISPATCHER, \
+ CHANNEL_DISPATCH_OPERATION, \
+ CHANNEL_TYPE_CONTACT_LIST, \
+ CHANNEL_TYPE_DBUS_TUBE, \
+ CHANNEL_TYPE_STREAMED_MEDIA, \
+ CHANNEL_TYPE_STREAM_TUBE, \
+ CHANNEL_TYPE_TEXT, \
+ CLIENT
+from jarabe.model import telepathyclient
-class BaseInvite:
- """Invitation to shared activity or private 1-1 Telepathy channel"""
- def __init__(self, bundle_id):
- """init for BaseInvite.
- bundle_id: string, e.g. 'org.laptop.Chat'
- """
- self._bundle_id = bundle_id
-
- def get_bundle_id(self):
- return self._bundle_id
-
-
-class ActivityInvite(BaseInvite):
+class ActivityInvite(object):
"""Invitation to a shared activity."""
- def __init__(self, bundle_id, activity_id):
- BaseInvite.__init__(self, bundle_id)
- self._activity_id = activity_id
-
- def get_activity_id(self):
- return self._activity_id
+ def __init__(self, dispatch_operation_path, channel, handler):
+ self._dispatch_operation_path = dispatch_operation_path
+ self._channel = channel
+ self._handler = handler
+ def get_bundle_id(self):
+ return self._handler[len(CLIENT + '.'):]
-class PrivateInvite(BaseInvite):
- """Invitation to a private 1-1 Telepathy channel.
-
- This includes text chat or streaming media.
- """
- def __init__(self, bundle_id, private_channel):
- """init for PrivateInvite.
-
- bundle_id: string, e.g. 'org.laptop.Chat'
- private_channel: string containing simplejson dump of Telepathy
- bus, connection and channel
- """
- BaseInvite.__init__(self, bundle_id)
- self._private_channel = private_channel
+ def join(self):
+ bus = dbus.Bus()
+ obj = bus.get_object(CHANNEL_DISPATCHER, self._dispatch_operation_path)
+ dispatch_operation = dbus.Interface(obj, CHANNEL_DISPATCH_OPERATION)
+ dispatch_operation.HandleWith(self._handler,
+ reply_handler=self.__handle_with_reply_cb,
+ error_handler=self.__handle_with_reply_cb)
- def get_private_channel(self):
- """Telepathy channel info from private invitation"""
- return self._private_channel
+ def __handle_with_reply_cb(self, error=None):
+ if error is not None:
+ logging.error('__handle_with_reply_cb %r', error)
+ else:
+ logging.debug('__handle_with_reply_cb')
class Invites(gobject.GObject):
@@ -74,48 +67,78 @@ class Invites(gobject.GObject):
def __init__(self):
gobject.GObject.__init__(self)
- self._dict = {}
+ self._dispatch_operations = {}
logging.info('KILL_PS listen for when the owner joins an activity')
#ps = presenceservice.get_instance()
#owner = ps.get_owner()
#owner.connect('joined-activity', self._owner_joined_cb)
- def add_invite(self, bundle_id, activity_id):
- if activity_id in self._dict:
- # there is no point to add more than one time
- # an invite for the same activity
+ client_handler = telepathyclient.get_instance()
+ client_handler.got_dispatch_operation.connect(
+ self.__got_dispatch_operation_cb)
+
+ def __got_dispatch_operation_cb(self, **kwargs):
+ logging.debug('__got_dispatch_operation_cb')
+ dispatch_operation_path = kwargs['dispatch_operation_path']
+ channel, channel_properties = kwargs['channels'][0]
+
+ channel_type = channel_properties[CHANNEL + '.ChannelType']
+ if channel_type == CHANNEL_TYPE_CONTACT_LIST:
+ handler = None
+ self._handle_with(dispatch_operation_path, CLIENT + '.Sugar')
+ elif channel_type == CHANNEL_TYPE_TEXT:
+ handler = CLIENT + '.org.laptop.Chat'
+ elif channel_type == CHANNEL_TYPE_STREAMED_MEDIA:
+ handler = CLIENT + '.org.laptop.VideoChat'
+ elif channel_type == CHANNEL_TYPE_DBUS_TUBE:
+ handler = channel_properties[CHANNEL_TYPE_DBUS_TUBE + '.ServiceName']
+ elif channel_type == CHANNEL_TYPE_STREAM_TUBE:
+ handler = channel_properties[CHANNEL_TYPE_STREAM_TUBE + '.Service']
+ else:
+ handler = None
+ self._handle_with(dispatch_operation_path, '')
+
+ if handler is not None:
+ self._add_invite(dispatch_operation_path, channel, handler)
+
+ def _handle_with(self, dispatch_operation_path, handler):
+ logging.debug('_handle_with %r %r', dispatch_operation_path, handler)
+ bus = dbus.Bus()
+ obj = bus.get_object(CHANNEL_DISPATCHER, dispatch_operation_path)
+ dispatch_operation = dbus.Interface(obj, CHANNEL_DISPATCH_OPERATION)
+ dispatch_operation.HandleWith(handler,
+ reply_handler=self.__handle_with_reply_cb,
+ error_handler=self.__handle_with_reply_cb)
+
+ def __handle_with_reply_cb(self, error=None):
+ if error is not None:
+ logging.error('__handle_with_reply_cb %r', error)
+ else:
+ logging.debug('__handle_with_reply_cb')
+
+ def _add_invite(self, dispatch_operation_path, channel, handler):
+ logging.debug('_add_invite %r %r %r', dispatch_operation_path, channel, handler)
+ if dispatch_operation_path in self._dispatch_operations:
+ # there is no point to have more than one invite for the same
+ # dispatch operation
return
- invite = ActivityInvite(bundle_id, activity_id)
- self._dict[activity_id] = invite
+ invite = ActivityInvite(dispatch_operation_path, channel, handler)
+ self._dispatch_operations[dispatch_operation_path] = invite
self.emit('invite-added', invite)
- def add_private_invite(self, private_channel, bundle_id):
- if private_channel in self._dict:
- # there is no point to add more than one invite for the
- # same incoming connection
- return
-
- invite = PrivateInvite(bundle_id, private_channel)
- self._dict[private_channel] = invite
- self.emit('invite-added', invite)
-
- def remove_invite(self, invite):
- del self._dict[invite.get_activity_id()]
- self.emit('invite-removed', invite)
-
- def remove_private_invite(self, invite):
- del self._dict[invite.get_private_channel()]
+ def _remove_invite(self, invite):
+ del self._dispatch_operations[invite.get_activity_id()]
self.emit('invite-removed', invite)
def remove_activity(self, activity_id):
- invite = self._dict.get(activity_id)
+ invite = self._dispatch_operations.get(activity_id)
if invite is not None:
self.remove_invite(invite)
def remove_private_channel(self, private_channel):
- invite = self._dict.get(private_channel)
+ invite = self._dispatch_operations.get(private_channel)
if invite is not None:
self.remove_private_invite(invite)
@@ -123,4 +146,13 @@ class Invites(gobject.GObject):
self.remove_activity(activity.props.id)
def __iter__(self):
- return self._dict.values().__iter__()
+ return self._dispatch_operations.values().__iter__()
+
+
+_instance = None
+
+def get_instance():
+ global _instance
+ if not _instance:
+ _instance = Invites()
+ return _instance
diff --git a/src/jarabe/model/owner.py b/src/jarabe/model/owner.py
index 17996e6..7d7e1f5 100644
--- a/src/jarabe/model/owner.py
+++ b/src/jarabe/model/owner.py
@@ -20,12 +20,8 @@ import os
import gconf
import simplejson
-from telepathy.interfaces import CHANNEL_TYPE_TEXT
-
from sugar import env
-from sugar.presence import presenceservice
from sugar import util
-from jarabe.model.invites import Invites
class Owner(gobject.GObject):
"""Class representing the owner of this machine/instance. This class
@@ -66,44 +62,9 @@ class Owner(gobject.GObject):
digest = hashlib.md5(self._icon).digest()
self._icon_hash = util.printable_hash(digest)
- self._pservice = presenceservice.get_instance()
- self._pservice.connect('activity-invitation',
- self._activity_invitation_cb)
- self._pservice.connect('private-invitation',
- self._private_invitation_cb)
- self._pservice.connect('activity-disappeared',
- self._activity_disappeared_cb)
-
- self._invites = Invites()
-
- def get_invites(self):
- return self._invites
-
def get_nick(self):
return self._nick
- def _activity_invitation_cb(self, pservice, activity, buddy, message):
- self._invites.add_invite(activity.props.type,
- activity.props.id)
-
- def _private_invitation_cb(self, pservice, bus_name, connection,
- channel, channel_type):
- """Handle a private-invitation from Presence Service.
-
- This is a connection by a non-Sugar XMPP client, so
- launch Chat or VideoChat with the Telepathy connection and
- channel.
- """
- if channel_type == CHANNEL_TYPE_TEXT:
- bundle_id = 'org.laptop.Chat'
- else:
- bundle_id = 'org.laptop.VideoChat'
- tp_channel = simplejson.dumps([bus_name, connection, channel])
- self._invites.add_private_invite(tp_channel, bundle_id)
-
- def _activity_disappeared_cb(self, pservice, activity):
- self._invites.remove_activity(activity.props.id)
-
_model = None
def get_model():
diff --git a/src/jarabe/model/telepathyclient.py b/src/jarabe/model/telepathyclient.py
new file mode 100644
index 0000000..5a483d8
--- /dev/null
+++ b/src/jarabe/model/telepathyclient.py
@@ -0,0 +1,97 @@
+# Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+
+import dbus
+from dbus import PROPERTIES_IFACE
+from telepathy.interfaces import CLIENT, \
+ CLIENT_APPROVER, \
+ CLIENT_HANDLER, \
+ CLIENT_INTERFACE_REQUESTS
+from telepathy.server import DBusProperties
+
+from sugar import dispatch
+
+SUGAR_CLIENT_SERVICE = 'org.freedesktop.Telepathy.Client.Sugar'
+SUGAR_CLIENT_PATH = '/org/freedesktop/Telepathy/Client/Sugar'
+
+class TelepathyClient(dbus.service.Object, DBusProperties):
+ def __init__(self):
+ self._interfaces = set([CLIENT, CLIENT_HANDLER,
+ CLIENT_INTERFACE_REQUESTS, PROPERTIES_IFACE,
+ CLIENT_APPROVER])
+
+ bus = dbus.Bus()
+ bus_name = dbus.service.BusName(SUGAR_CLIENT_SERVICE, bus=bus)
+
+ dbus.service.Object.__init__(self, bus_name, SUGAR_CLIENT_PATH)
+ DBusProperties.__init__(self)
+
+ self._implement_property_get(CLIENT, {
+ 'Interfaces': lambda: list(self._interfaces),
+ })
+ self._implement_property_get(CLIENT_HANDLER, {
+ 'HandlerChannelFilter': self.__get_filters_cb,
+ })
+ self._implement_property_get(CLIENT_APPROVER, {
+ 'ApproverChannelFilter': self.__get_filters_cb,
+ })
+
+ self.got_channel = dispatch.Signal()
+ self.got_dispatch_operation = dispatch.Signal()
+
+ def __get_filters_cb(self):
+ logging.debug('__get_filters_cb')
+ filter_dict = dbus.Dictionary({}, signature='sv')
+ return dbus.Array([filter_dict], signature='a{sv}')
+
+ @dbus.service.method(dbus_interface=CLIENT_HANDLER,
+ in_signature='ooa(oa{sv})aota{sv}', out_signature='')
+ def HandleChannels(self, account, connection, channels, requests_satisfied,
+ user_action_time, handler_info):
+ logging.debug('HandleChannels\n%r\n%r\n%r\n%r\n%r\n%r\n', account, connection,
+ channels, requests_satisfied, user_action_time, handler_info)
+ for channel in channels:
+ self.got_channel.send(self, account=account,
+ connection=connection, channel=channel)
+
+ @dbus.service.method(dbus_interface=CLIENT_INTERFACE_REQUESTS,
+ in_signature='oa{sv}', out_signature='')
+ def AddRequest(self, request, properties):
+ logging.debug('AddRequest\n%r\n%r', request, properties)
+
+ @dbus.service.method(dbus_interface=CLIENT_APPROVER,
+ in_signature='a(oa{sv})oa{sv}', out_signature='',
+ async_callbacks=('success_cb', 'error_cb_'))
+ def AddDispatchOperation(self, channels, dispatch_operation_path,
+ properties, success_cb, error_cb_):
+ success_cb()
+
+ logging.debug('AddDispatchOperation\n%r\n%r\n%r', channels, dispatch_operation_path, properties)
+
+ self.got_dispatch_operation.send(self, channels=channels,
+ dispatch_operation_path=dispatch_operation_path,
+ properties=properties)
+
+
+_instance = None
+
+def get_instance():
+ global _instance
+ if not _instance:
+ _instance = TelepathyClient()
+ return _instance