diff --git a/services/presence2/Makefile.am b/services/presence2/Makefile.am index 3ec8c68c..b0942db1 100644 --- a/services/presence2/Makefile.am +++ b/services/presence2/Makefile.am @@ -1,6 +1,8 @@ sugardir = $(pkgdatadir)/services/presence2 sugar_PYTHON = \ __init__.py \ + activity.py \ + buddy.py \ buddyiconcache.py \ presenceservice.py diff --git a/services/presence2/activity.py b/services/presence2/activity.py new file mode 100644 index 00000000..27e372bd --- /dev/null +++ b/services/presence2/activity.py @@ -0,0 +1,92 @@ +# Copyright (C) 2007, Red Hat, Inc. +# Copyright (C) 2007, Collabora Ltd. +# +# 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 dbus, dbus.service + +_ACTIVITY_PATH = "/org/laptop/Sugar/Presence/Activities/" +_ACTIVITY_INTERFACE = "org.laptop.Sugar.Presence.Activity" + +class Activity(dbus.service.Object): + def __init__(self, bus_name, object_id): + self._buddies = [] + self._color = None + self._valid = False + self._activity_id = None + + self._object_id = object_id + self._object_path = "/org/laptop/Presence/Activities/%d" % self._object_id + + dbus.service.Object.__init__(self, bus_name, self._object_path) + + + # dbus signals + @dbus.service.signal(_ACTIVITY_INTERFACE, + signature="o") + def BuddyJoined(self, buddy_path): + pass + + @dbus.service.signal(_ACTIVITY_INTERFACE, + signature="o") + def BuddyLeft(self, buddy_path): + pass + + @dbus.service.signal(_ACTIVITY_INTERFACE, + signature="o") + def NewChannel(self, channel_path): + pass + + # dbus methods + @dbus.service.method(_ACTIVITY_INTERFACE, + in_signature="", out_signature="s") + def GetId(self): + return self.get_id() + + @dbus.service.method(_ACTIVITY_INTERFACE, + in_signature="", out_signature="s") + def GetColor(self): + return self.get_color() + + @dbus.service.method(_ACTIVITY_INTERFACE, + in_signature="", out_signature="") + def Join(self): + raise NotImplementedError("not implemented yet") + + @dbus.service.method(_ACTIVITY_INTERFACE, + in_signature="", out_signature="ao") + def GetJoinedBuddies(self): + for buddy in self._buddies: + ret.append(buddy.object_path()) + return ret + + @dbus.service.method(_ACTIVITY_INTERFACE, + in_signature="", out_signature="soao") + def GetChannels(self): + raise NotImplementedError("not implemented yet") + + # methods + def object_path(self): + return dbus.ObjectPath(self._object_path) + + def is_valid(self): + """An activity is only valid when it's color is available.""" + return self._valid + + def get_id(self): + return self._activity_id + + def get_color(self): + return self._color diff --git a/services/presence2/buddy.py b/services/presence2/buddy.py new file mode 100644 index 00000000..984bf949 --- /dev/null +++ b/services/presence2/buddy.py @@ -0,0 +1,201 @@ +# Copyright (C) 2007, Red Hat, Inc. +# Copyright (C) 2007, Collabora Ltd. +# +# 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 gobject +import dbus, dbus.service +from sugar import profile +from sugar.graphics import iconcolor + +_BUDDY_PATH = "/org/laptop/Sugar/Presence/Buddies/" +_BUDDY_INTERFACE = "org.laptop.Sugar.Presence.Buddy" +_OWNER_INTERFACE = "org.laptop.Sugar.Presence.Buddy.Owner" + +class NotFoundError(dbus.DBusException): + def __init__(self): + dbus.DBusException.__init__(self) + self._dbus_error_name = _PRESENCE_INTERFACE + '.NotFound' + +class Buddy(dbus.service.Object): + """Represents another person on the network and keeps track of the + activities and resources they make available for sharing.""" + + def __init__(self, bus_name, object_id, icon_cache): + if not bus_name: + raise ValueError("DBus bus name must be valid") + if not object_id or not isinstance(object_id, int): + raise ValueError("object id must be a valid number") + + self._bus_name = bus_name + self._object_id = object_id + self._object_path = _BUDDY_PATH + str(self._object_id) + + dbus.service.Object.__init__(self, self._bus_name, self._object_path) + + self._activities = {} # Activity ID -> Activity + + self._icon_cache = icon_cache + + self._nick_name = None + self._color = None + self._key = None + self._current_activity = None + + # dbus signals + @dbus.service.signal(_BUDDY_INTERFACE, + signature="ay") + def IconChanged(self, icon_data): + pass + + @dbus.service.signal(_BUDDY_INTERFACE, + signature="o") + def JoinedActivity(self, activity_path): + pass + + @dbus.service.signal(_BUDDY_INTERFACE, + signature="o") + def LeftActivity(self, activity_path): + pass + + @dbus.service.signal(_BUDDY_INTERFACE, + signature="a{sv}") + def PropertyChanged(self, updated): + pass + + # dbus methods + @dbus.service.method(_BUDDY_INTERFACE, + in_signature="", out_signature="ay") + def GetIcon(self): + icon = self.get_icon() + if not icon: + return "" + return icon + + @dbus.service.method(_BUDDY_INTERFACE, + in_signature="", out_signature="ao") + def GetJoinedActivities(self): + acts = [] + for act in self.get_joined_activities(): + acts.append(act.object_path()) + return acts + + @dbus.service.method(_BUDDY_INTERFACE, + in_signature="", out_signature="a{sv}") + def GetProperties(self): + props = {} + props['name'] = self.get_name() + props['owner'] = self.is_owner() + props['key'] = self.get_key() + color = self.get_color() + if color: + props['color'] = color + return props + + # methods + def object_path(self): + return dbus.ObjectPath(self._object_path) + + def add_activity(self, activity): + actid = activity.get_id() + if self._activities.has_key(actid): + return + self._activities[actid] = activity + if activity.is_valid(): + self.JoinedActivity(activity.object_path()) + + def remove_activity(self, activity): + actid = activity.get_id() + if not self._activities.has_key(actid): + return + del self._activities[actid] + if activity.is_valid(): + self.LeftActivity(activity.object_path()) + + def get_joined_activities(self): + acts = [] + for act in self._activities.values(): + if act.is_valid(): + acts.append(act) + return acts + + def get_icon(self): + """Return the buddies icon, if any.""" + return self._icon + + def get_name(self): + return self._nick_name + + def get_color(self): + return self._color + + def get_current_activity(self): + if not self._current_activity: + return None + if not self._activities.has_key(self._current_activity): + return None + return self._activities[self._current_activity] + + def _set_icon(self, icon): + """Can only set icon for other buddies. The Owner + takes care of setting it's own icon.""" + if icon != self._icon: + self._icon = icon + self.IconChanged(icon) + + def is_owner(self): + return False + + def get_key(self): + return self._key + +class Owner(Buddy): + """Class representing the owner of the machine. This is the client + portion of the Owner, paired with the server portion in Owner.py.""" + def __init__(self, ps, bus_name, object_id, icon_cache): + Buddy.__init__(self, bus_name, object_id, icon_cache) + + self._ps = ps + self._nick_name = profile.get_nick_name() + self._color = profile.get_color().to_string() + self._key = profile.get_pubkey() + + # dbus methods + @dbus.service.method(_OWNER_INTERFACE, + in_signature="ay", out_signature="") + def SetIcon(self, icon_data): + self.set_icon(icon_data) + + @dbus.service.method(_OWNER_INTERFACE, + in_signature="a{sv}", out_signature="") + def SetProperties(self, properties): + if "name" in properties.keys(): + self.set_name(properties["name"]) + if "color" in properties.keys(): + self.set_color(properties["color"]) + self.PropertyChanged(properties) + + # methods + def is_owner(self): + return True + + def set_icon(self, icon): + self._icon = icon + + def set_name(self, name): + self._nick_name = name + + def set_color(self, color): + self._color = color diff --git a/services/presence2/presenceservice.py b/services/presence2/presenceservice.py index 957d14d6..659c389f 100644 --- a/services/presence2/presenceservice.py +++ b/services/presence2/presenceservice.py @@ -16,7 +16,14 @@ import gobject import dbus, dbus.service, dbus.glib +from telepathy.client import ManagerRegistry, Connection +from telepathy.interfaces import CONN_MGR_INTERFACE + +import telepathyclient +import buddy +import activity import buddyiconcache +from sugar import profile _PRESENCE_SERVICE = "org.laptop.Sugar.Presence" @@ -42,14 +49,19 @@ class PresenceService(dbus.service.Object): bus = dbus.SessionBus() self._bus_name = dbus.service.BusName(_PRESENCE_SERVICE, bus=bus) - # Our owner object - if profile.get_nick_name(): - objid = self._get_next_object_id() - self._owner = buddy.Owner(self, self._bus_name, - objid, self._icon_cache) - self._buddies[self._owner.get_key()] = self._owner - else: - self._owner = None + # Create the Owner object + objid = self._get_next_object_id() + self._owner = buddy.Owner(self, self._bus_name, objid, self._icon_cache) + self._buddies[self._owner.get_key()] = self._owner + + self._registry = ManagerRegistry() + self._registry.LoadManagers() + # Telepathy connection to the server + self._server_client = None + # Telepathy link local connection + self._ll_client = None + + self._connect_server () dbus.service.Object.__init__(self, self._bus_name, _PRESENCE_PATH) @@ -58,6 +70,19 @@ class PresenceService(dbus.service.Object): self._next_object_id = self._next_object_id + 1 return self._next_object_id + def _connect_server (self): + mgr = self._registry.GetManager('gabble') + protocol = 'jabber' + account = { + 'account': 'olpc@collabora.co.uk', + 'password': 'learn', + 'server': 'light.bluelinux.co.uk' + } + conn_bus_name, conn_object_path = \ + mgr[CONN_MGR_INTERFACE].RequestConnection(protocol, account) + conn = Connection(conn_bus_name, conn_object_path) + self._server_client = telepathyclient.TelepathyClient(conn) + @dbus.service.signal(_PRESENCE_INTERFACE, signature="o") def ActivityAppeared(self, activity): pass