rendered paste bodydiff --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
+