All pastes #794703 Raw Edit

Stuff

public text v1 · immutable
#794703 ·published 2007-11-23 10:57 UTC
rendered paste body
diff --git a/src/presenceservice.py b/src/presenceservice.py
index 30c6dab..1503dac 100644
--- a/src/presenceservice.py
+++ b/src/presenceservice.py
@@ -834,6 +834,11 @@ class PresenceService(ExportedGObject):
         else:
             activity.set_properties(props)
 
+    @dbus.service.method(PRESENCE_INTERFACE, in_signature="",
+            out_signature="")
+    def SyncFriends(self):
+        if self._server_plugin is not None:
+            self._server_plugin.sync_friends()
 
 def main(test_num=0, randomize=False):
     loop = gobject.MainLoop()
diff --git a/src/server_plugin.py b/src/server_plugin.py
index 834eedc..90a9ca2 100644
--- a/src/server_plugin.py
+++ b/src/server_plugin.py
@@ -17,7 +17,10 @@
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 # Standard library
+import base64
+import ConfigParser
 import logging
+import os
 from itertools import izip
 from string import hexdigits
 
@@ -31,6 +34,8 @@ from telepathy.constants import (HANDLE_TYPE_CONTACT,
     CONNECTION_STATUS_CONNECTED, CONNECTION_STATUS_DISCONNECTED,
     CHANNEL_GROUP_FLAG_CHANNEL_SPECIFIC_HANDLES,
     CONNECTION_STATUS_REASON_NAME_IN_USE)
+import sugar.env
+import sugar.profile
 
 # Presence Service local modules
 import psutils
@@ -287,11 +292,13 @@ class ServerPlugin(TelepathyPlugin):
                 local_pending, '')
 
         self._add_not_subscribed_to_subscribe_channel()
+        self.sync_friends()
 
     def _subscribe_channel_cb(self, channel):
         TelepathyPlugin._subscribe_channel_cb(self, channel)
 
         self._add_not_subscribed_to_subscribe_channel()
+        self.sync_friends()
 
     def _add_not_subscribed_to_subscribe_channel(self):
         if self._publish_channel is None or self._subscribe_channel is None:
@@ -306,3 +313,76 @@ class ServerPlugin(TelepathyPlugin):
         not_subscribed -= self._subscribe_members
         self._subscribe_channel[CHANNEL_INTERFACE_GROUP].AddMembers(
                 not_subscribed, '')
+
+    def sync_friends(self):
+        """Synchornise our local friends list with our roster on the
+        server."""
+
+        try:
+            return self._sync_friends_ignore_dbus_error()
+        except dbus.DBusException, exc:
+            # something bad happened while using the connection; give up on
+            # syncing friend list
+            _logger.debug('error syncing friends: %s' % exc)
+            return False
+
+    def _sync_friends_ignore_dbus_error(self):
+        if self._publish_channel is None or self._subscribe_channel is None:
+            # not ready yet; try again later
+            return True
+
+        profile_path = sugar.env.get_profile_path()
+        friends_path = os.path.join(profile_path, 'friends')
+        config_path = os.path.join(profile_path, 'config')
+        parser = ConfigParser.SafeConfigParser()
+
+        if parser.read([friends_path]) == []:
+            # friends list is invalid; try again later
+            _logger.debug('error reading friends list')
+            return True
+
+        profile = sugar.profile.Profile(config_path)
+
+        if not profile.is_valid():
+            # profile is invalid; try again later
+            return True
+
+        friends = set()
+
+        for section in parser.sections:
+            try:
+                key = base64.b64decode(section)
+            except TypeError:
+                # key is invalid; skip this friend
+                _logger.debug('skipping friend with invalid key')
+                continue
+
+            id = psutils.pubkey_to_keyid(key)
+            # this assumes that all our friends are on the same server as us
+            jid = '%s@%s' % (id, profile.jabber_server)
+            friends.add(jid)
+
+        handles = self._conn[CONN_INTERFACE].RequestHandles(
+            HANDLE_TYPE_CONTACT, friends)
+        handles = set(handles)
+
+        cur, local_p, remote_p = self._subscribe_channel[
+            CHANNEL_INTERFACE_GROUP].GetAllMembers()
+        subscribe_handles = set(cur) + set(remote_p)
+
+        # stop sending presence to people not on our friend list
+        _logger.debug('removing friends from roster: %r' % (
+            subscribe_handles - handles))
+        self._publish_channel[CHANNEL_INTERFACE_GROUP].RemoveMembers(
+            subscribe_handles - handles)
+
+        # do send presence to people on our friend list
+        _logger.debug('adding friends to roster: %r' % (
+            handles - subscribe_handles))
+        self._subscribe_channel[CHANNEL_INTERFACE_GROUP].AddMembers(
+            handles - subscribe_handles)
+
+        # do this again later
+        _logger.debug('friends list synced with server')
+        return True
+