summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2014-02-06 19:18:35 +0000
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2014-02-06 19:18:35 +0000
commitb81df5f0da5a86fe5bef05f3d8d627f6a01cee76 (patch)
tree540d8894da5b5d4f3a0513b68af1b59ec584f530
parentd8edca5135d6b9fdbec6d25441f61e1f01098f28 (diff)
downloadtelepathy-salut-b81df5f0da5a86fe5bef05f3d8d627f6a01cee76.tar.gz
Revert to commit 822ddd0
Some commits intended for 'next' appear to have ended up on master.
-rw-r--r--.gitignore4
-rw-r--r--configure.ac31
-rw-r--r--data/Makefile.am4
-rw-r--r--data/salut.service.in2
-rw-r--r--extensions/Connection_Future.xml12
-rw-r--r--extensions/Makefile.am2
-rw-r--r--extensions/OLPC_Activity_Properties.xml124
-rw-r--r--extensions/OLPC_Buddy_Info.xml285
-rw-r--r--extensions/Salut_Plugin_Test.xml2
-rw-r--r--extensions/connection.xml3
-rw-r--r--plugins/test.c2
-rw-r--r--salut/capabilities.h1
-rw-r--r--src/Makefile.am14
-rw-r--r--src/avahi-contact.c72
-rw-r--r--src/avahi-discovery-client.c32
-rw-r--r--src/avahi-olpc-activity-manager.c376
-rw-r--r--src/avahi-olpc-activity-manager.h68
-rw-r--r--src/avahi-olpc-activity.c546
-rw-r--r--src/avahi-olpc-activity.h70
-rw-r--r--src/avahi-self.c134
-rw-r--r--src/avahi-self.h3
-rw-r--r--src/bonjour-discovery-client.c6
-rw-r--r--src/bonjour-self.c12
-rw-r--r--src/bonjour-self.h3
-rw-r--r--src/capability-set.c23
-rw-r--r--src/connection-contact-info.c49
-rw-r--r--src/connection.c1702
-rw-r--r--src/connection.h10
-rw-r--r--src/contact-manager.c5
-rw-r--r--src/contact.c255
-rw-r--r--src/contact.h43
-rw-r--r--src/debug.c1
-rw-r--r--src/debug.h5
-rw-r--r--src/discovery-client.c21
-rw-r--r--src/discovery-client.h18
-rw-r--r--src/dummy-discovery-client.c7
-rw-r--r--src/file-transfer-channel.c4
-rw-r--r--src/im-channel.c23
-rw-r--r--src/muc-channel.c134
-rw-r--r--src/muc-manager.c9
-rw-r--r--src/muc-tube-dbus.c2
-rw-r--r--src/muc-tube-stream.c2
-rw-r--r--src/namespaces.h8
-rw-r--r--src/olpc-activity-manager.c349
-rw-r--r--src/olpc-activity-manager.h98
-rw-r--r--src/olpc-activity.c680
-rw-r--r--src/olpc-activity.h98
-rw-r--r--src/presence.h1
-rw-r--r--src/protocol.c3
-rw-r--r--src/protocol.h4
-rw-r--r--src/roomlist-channel.c8
-rw-r--r--src/self.c480
-rw-r--r--src/self.h44
-rw-r--r--src/text-helper.h2
-rw-r--r--src/tube-dbus.c7
-rw-r--r--src/tube-iface.c4
-rw-r--r--src/tube-stream.c14
-rw-r--r--src/tubes-manager.c34
-rw-r--r--src/util.h6
-rw-r--r--src/write-mgr-file.c12
-rw-r--r--tests/twisted/Makefile.am8
-rw-r--r--tests/twisted/avahi/aliases.py11
-rw-r--r--tests/twisted/avahi/caps-file-transfer.py8
-rw-r--r--tests/twisted/avahi/caps-self.py2
-rw-r--r--tests/twisted/avahi/close-local-pending-room.py10
-rw-r--r--tests/twisted/avahi/file-transfer/file_transfer_helper.py10
-rw-r--r--tests/twisted/avahi/file-transfer/ft-client-caps.py14
-rw-r--r--tests/twisted/avahi/ichat-composing.py8
-rw-r--r--tests/twisted/avahi/ichat-incoming-msg.py10
-rw-r--r--tests/twisted/avahi/muc-invite.py11
-rw-r--r--tests/twisted/avahi/olpc-activity-announcements.py115
-rw-r--r--tests/twisted/avahi/request-im.py8
-rw-r--r--tests/twisted/avahi/request-muc.py6
-rw-r--r--tests/twisted/avahi/roomlist.py11
-rw-r--r--tests/twisted/avahi/set-presence.py4
-rw-r--r--tests/twisted/avahi/text-channel.py15
-rw-r--r--tests/twisted/avahi/tubes/request-muc-tubes.py6
-rw-r--r--tests/twisted/avahi/tubes/tubetestutil.py10
-rw-r--r--tests/twisted/avahi/tubes/two-muc-dbus-tubes.py4
-rw-r--r--tests/twisted/cm/protocol.py6
-rw-r--r--tests/twisted/constants.py205
-rw-r--r--tests/twisted/ns.py10
-rw-r--r--tests/twisted/saluttest.py24
-rw-r--r--tests/twisted/servicetest.py249
-rw-r--r--tests/twisted/sidecars.py2
-rw-r--r--tests/twisted/tools/Makefile.am4
-rw-r--r--tests/twisted/tools/salut.service.in2
87 files changed, 6109 insertions, 637 deletions
diff --git a/.gitignore b/.gitignore
index ec554dd4..d87d4ead 100644
--- a/.gitignore
+++ b/.gitignore
@@ -81,7 +81,7 @@ m4/lt~obsolete.m4
/coverage/
-data/im.telepathy1.ConnectionManager.salut.service
+data/org.freedesktop.Telepathy.ConnectionManager.salut.service
data/*.service
data/salut.manager
@@ -118,7 +118,7 @@ tests/twisted/tools/core
tests/twisted/tools/exec-with-log.sh
tests/twisted/tools/salut-testing.log*
tests/twisted/tools/tmp-session-bus.conf
-tests/twisted/tools/im.telepathy1.ConnectionManager.salut.service
+tests/twisted/tools/org.freedesktop.Telepathy.ConnectionManager.salut.service
tests/twisted/tools/refdbg.log
/tests/twisted/with-session-bus*.address
/tests/twisted/with-session-bus*.pid
diff --git a/configure.ac b/configure.ac
index 3723b1ec..47699d50 100644
--- a/configure.ac
+++ b/configure.ac
@@ -8,8 +8,8 @@ AC_PREREQ([2.60])
# set salut_nano_version to 0.
m4_define([salut_major_version], [0])
-m4_define([salut_minor_version], [99])
-m4_define([salut_micro_version], [2])
+m4_define([salut_minor_version], [8])
+m4_define([salut_micro_version], [999])
m4_define([salut_nano_version], [1])
# Some magic
@@ -114,6 +114,17 @@ AC_MSG_RESULT([$TEST_PYTHON])
AC_SUBST(TEST_PYTHON)
AM_CONDITIONAL([WANT_TWISTED_TESTS], test false != "$TEST_PYTHON")
+dnl olpc specific code switch
+AC_ARG_ENABLE(olpc,
+ AC_HELP_STRING([--enable-olpc],[compile with olpc specific code]),
+ enable_olpc=$enableval, enable_olpc=no )
+
+AS_IF([test x$enable_olpc = xyes],
+ [AC_DEFINE(ENABLE_OLPC, [], [Enable olpc code])])
+AM_CONDITIONAL(ENABLE_OLPC, test "x$enable_olpc" = "xyes")
+
+AC_SUBST(ENABLE_OLPC)
+
AC_HEADER_STDC([])
AC_C_INLINE
@@ -184,16 +195,11 @@ PKG_CHECK_MODULES(LIBXML2, [libxml-2.0])
AC_SUBST(LIBXML2_CFLAGS)
AC_SUBST(LIBXML2_LIBS)
-TELEPATHY_GLIB_REQUIRED=0.99.2
AC_DEFINE([TP_SEAL_ENABLE], [], [Prevent to use sealed variables])
AC_DEFINE([TP_DISABLE_SINGLE_INCLUDE], [], [Disable single header include])
-AC_DEFINE([TP_VERSION_MIN_REQUIRED], [TP_VERSION_1_0], [Ignore post 1.0 deprecations])
-AC_DEFINE([TP_VERSION_MAX_ALLOWED], [TP_VERSION_1_0], [Prevent post 1.0 APIs])
-PKG_CHECK_MODULES([TELEPATHY_GLIB],
- [
- telepathy-glib-1 >= $TELEPATHY_GLIB_REQUIRED
- telepathy-glib-1-dbus >= $TELEPATHY_GLIB_REQUIRED
- ])
+AC_DEFINE([TP_VERSION_MIN_REQUIRED], [TP_VERSION_0_22], [Ignore post 0.22 deprecations])
+AC_DEFINE([TP_VERSION_MAX_ALLOWED], [TP_VERSION_0_22], [Prevent post 0.22 APIs])
+PKG_CHECK_MODULES([TELEPATHY_GLIB], [telepathy-glib >= 0.21.2])
AC_SUBST(TELEPATHY_GLIB_CFLAGS)
AC_SUBST(TELEPATHY_GLIB_LIBS)
@@ -385,4 +391,9 @@ Configure summary:
Enable debug................: ${enable_debug}
Python tests................: ${tests_enabled}
Plugins.....................: ${enable_plugins}
+
+Features:
+
+ OLPC support................: ${enable_olpc}
+
"
diff --git a/data/Makefile.am b/data/Makefile.am
index 049070c6..e0002ab6 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -4,12 +4,12 @@ managerdir = $(datadir)/telepathy/managers
manager_DATA = salut.manager
servicedir = $(datadir)/dbus-1/services
-service_DATA = im.telepathy1.ConnectionManager.salut.service
+service_DATA = org.freedesktop.Telepathy.ConnectionManager.salut.service
# We don't use the full filename for the .in because > 99 character filenames
# in tarballs are non-portable (and automake 1.8 doesn't let us build
# non-archaic tarballs)
-im.telepathy1.ConnectionManager.salut.service: salut.service.in \
+org.freedesktop.Telepathy.ConnectionManager.salut.service: salut.service.in \
Makefile
$(AM_V_GEN)sed -e "s|[@]libexecdir[@]|$(libexecdir)|" $< > $@
diff --git a/data/salut.service.in b/data/salut.service.in
index 60303685..322aea76 100644
--- a/data/salut.service.in
+++ b/data/salut.service.in
@@ -1,3 +1,3 @@
[D-BUS Service]
-Name=im.telepathy1.ConnectionManager.salut
+Name=org.freedesktop.Telepathy.ConnectionManager.salut
Exec=@libexecdir@/telepathy-salut
diff --git a/extensions/Connection_Future.xml b/extensions/Connection_Future.xml
index a578a888..11047983 100644
--- a/extensions/Connection_Future.xml
+++ b/extensions/Connection_Future.xml
@@ -20,9 +20,9 @@ License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
USA.</p>
</tp:license>
- <interface name="im.telepathy1.Connection.FUTURE"
+ <interface name="org.freedesktop.Telepathy.Connection.FUTURE"
tp:causes-havoc='experimental'>
- <tp:requires interface="im.telepathy1.Connection"/>
+ <tp:requires interface="org.freedesktop.Telepathy.Connection"/>
<method name="EnsureSidecar" tp:name-for-bindings="Ensure_Sidecar">
<tp:added version="0.19.UNRELEASED"/>
@@ -75,12 +75,12 @@ USA.</p>
in a dictionary, build a proxy object from the value). More
“plural” plugins are likely to want to implement new types of
<tp:dbus-ref
- namespace="im.telepathy1">Channel</tp:dbus-ref>
+ namespace="org.freedesktop.Telepathy">Channel</tp:dbus-ref>
instead.</p>
</tp:rationale>
</tp:docstring>
- <tp:error name="im.telepathy1.Error.NotImplemented">
+ <tp:error name="org.freedesktop.Telepathy.Error.NotImplemented">
<tp:docstring>
The requested sidecar is not implemented by this connection manager,
or a necessary server-side component does not exist. (FIXME: split
@@ -91,7 +91,7 @@ USA.</p>
</tp:docstring>
</tp:error>
- <tp:error name="im.telepathy1.Error.ServiceBusy">
+ <tp:error name="org.freedesktop.Telepathy.Error.ServiceBusy">
<tp:docstring>
A server-side component needed by the requested sidecar reported it
is currently too busy, or did not respond for some
@@ -99,7 +99,7 @@ USA.</p>
</tp:docstring>
</tp:error>
- <tp:error name="im.telepathy1.Error.Cancelled">
+ <tp:error name="org.freedesktop.Telepathy.Error.Cancelled">
<tp:docstring>
The connection was disconnected while the sidecar was being set up.
</tp:docstring>
diff --git a/extensions/Makefile.am b/extensions/Makefile.am
index 5edd07d0..39f94e96 100644
--- a/extensions/Makefile.am
+++ b/extensions/Makefile.am
@@ -1,6 +1,8 @@
tools_dir = $(top_srcdir)/tools
EXTRA_DIST = \
+ OLPC_Buddy_Info.xml \
+ OLPC_Activity_Properties.xml \
connection.xml \
Salut_Plugin_Test.xml \
Connection_Future.xml \
diff --git a/extensions/OLPC_Activity_Properties.xml b/extensions/OLPC_Activity_Properties.xml
new file mode 100644
index 00000000..d1ea2afa
--- /dev/null
+++ b/extensions/OLPC_Activity_Properties.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" ?>
+<node name="/OLPC_Activity_Properties" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
+ <tp:copyright> Copyright (C) 2007 Collabora Limited </tp:copyright>
+ <tp:license xmlns="http://www.w3.org/1999/xhtml">
+ <p>This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.</p>
+
+<p>This library 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
+Lesser General Public License for more details.</p>
+
+<p>You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA</p>
+ </tp:license>
+ <interface name="org.laptop.Telepathy.ActivityProperties">
+ <tp:requires interface="org.freedesktop.Telepathy.Connection"/>
+
+ <method name="SetProperties" tp:name-for-bindings="Set_Properties">
+ <arg direction="in" name="room" type="u">
+ <tp:docstring>
+ An integer handle representing the room of the activity
+ </tp:docstring>
+ </arg>
+ <arg direction="in" name="properties" type="a{sv}">
+ <tp:docstring>
+ A dictionary mapping properties names to the desired values
+ </tp:docstring>
+ </arg>
+ <tp:docstring>
+ Set the properties of the activity associated to the given room for this connection.
+ You have to be the owner of this activity.
+ </tp:docstring>
+ <tp:possible-errors>
+ <tp:error name="org.freedesktop.Telepathy.Error.Disconnected"/>
+ <tp:error name="org.freedesktop.Telepathy.Error.InvalidArgument"/>
+ <tp:error name="org.freedesktop.Telepathy.Error.PermissionDenied"/>
+ </tp:possible-errors>
+ </method>
+
+ <method name="GetProperties" tp:name-for-bindings="Get_Properties">
+ <arg direction="in" name="room" type="u">
+ <tp:docstring>
+ An integer handle for the activity's room to request his properties for
+ </tp:docstring>
+ </arg>
+ <arg direction="out" name="properties" type="a{sv}">
+ <tp:docstring>
+ A dictionary mapping properties names to their values
+ </tp:docstring>
+ </arg>
+ <tp:docstring>
+ Get the properties of a particular activity.
+ </tp:docstring>
+ <tp:possible-errors>
+ <tp:error name="org.freedesktop.Telepathy.Error.Disconnected"/>
+ <tp:error name="org.freedesktop.Telepathy.Error.InvalidArgument"/>
+ </tp:possible-errors>
+ </method>
+
+ <method name="GetActivity" tp:name-for-bindings="Get_Activity">
+ <arg direction="in" name="activity_id" type="s">
+ <tp:docstring>
+ An activity id
+ </tp:docstring>
+ </arg>
+ <arg direction="out" name="room" type="u">
+ <tp:docstring>
+ A room handle
+ </tp:docstring>
+ </arg>
+ <tp:docstring>
+ Returns the handle of the room associated with this activity
+ <tp:rationale>
+ <p>When an activity starts up, it knows its activity_id but doesn't
+ know yet if it's shared or not, much less the room.</p>
+ </tp:rationale>
+ </tp:docstring>
+ <tp:possible-errors>
+ <tp:error name="org.freedesktop.Telepathy.Error.Disconnected"/>
+ <tp:error name="org.freedesktop.Telepathy.Error.InvalidArgument"/>
+ </tp:possible-errors>
+ </method>
+
+ <signal name="ActivityPropertiesChanged"
+ tp:name-for-bindings="Activity_Properties_Changed">
+ <arg name="room" type="u">
+ <tp:docstring>
+ An integer handle representing the room of the activity
+ </tp:docstring>
+ </arg>
+ <arg name="properties" type="a{sv}">
+ <tp:docstring>
+ A dictionary mapping properties names to their new values
+ </tp:docstring>
+ </arg>
+ <tp:docstring>
+ Signal emitted when the properties of an activity are changed.
+ </tp:docstring>
+ </signal>
+
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ <p>An interface on connections to associate OLPC activity properties
+ with rooms.</p>
+
+ <p>The following types and names are used to request and set properties:</p>
+ <dl>
+ <dt>s:color</dt>
+ <dd>The color of the activity. Format used is #RRGGBB,#RRGGBB (stroke,fill).</dd>
+
+ <dt>s:name</dt>
+ <dd>The name of the activity.</dd>
+
+ <dt>s:type</dt>
+ <dd>The type of the activity.</dd>
+ </dl>
+
+ </tp:docstring>
+ </interface>
+</node>
+<!-- vim:set sw=2 sts=2 et ft=xml: -->
diff --git a/extensions/OLPC_Buddy_Info.xml b/extensions/OLPC_Buddy_Info.xml
new file mode 100644
index 00000000..7caf35c0
--- /dev/null
+++ b/extensions/OLPC_Buddy_Info.xml
@@ -0,0 +1,285 @@
+<?xml version="1.0" ?>
+<node name="/OLPC_Buddy_Info" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
+ <tp:copyright> Copyright (C) 2007 Collabora Limited </tp:copyright>
+ <tp:license xmlns="http://www.w3.org/1999/xhtml">
+ <p>This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.</p>
+
+<p>This library 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
+Lesser General Public License for more details.</p>
+
+<p>You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA</p>
+ </tp:license>
+ <interface name="org.laptop.Telepathy.BuddyInfo">
+ <tp:requires interface="org.freedesktop.Telepathy.Connection"/>
+
+ <method name="SetProperties" tp:name-for-bindings="Set_Properties">
+ <arg direction="in" name="properties" type="a{sv}">
+ <tp:docstring>
+ A dictionary mapping information names to the desired values.
+ This replaces any existing buddy properties completely: any keys
+ which were previously present, but are not present in this dictionary,
+ are deleted.
+ </tp:docstring>
+ </arg>
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ <p>Set the information of the local user for this connection.</p>
+ <p>This method may be called before Connect(), in which case the given
+ properties will be advertised as soon as possible after connection
+ (possibly immediately).</p>
+ </tp:docstring>
+ <tp:possible-errors>
+ <tp:error name="org.freedesktop.Telepathy.Error.InvalidArgument"/>
+ </tp:possible-errors>
+ </method>
+
+ <method name="GetProperties" tp:name-for-bindings="Get_Properties">
+ <arg direction="in" name="contact" type="u">
+ <tp:docstring>
+ An integer handle for the contact to request his properties for
+ </tp:docstring>
+ </arg>
+ <arg direction="out" name="properties" type="a{sv}">
+ <tp:docstring>
+ A dictionary mapping information names to their values
+ </tp:docstring>
+ </arg>
+ <tp:docstring>
+ Get the properties of a particular contact.
+ </tp:docstring>
+ <tp:possible-errors>
+ <tp:error name="org.freedesktop.Telepathy.Error.Disconnected"/>
+ <tp:error name="org.freedesktop.Telepathy.Error.InvalidArgument"/>
+ </tp:possible-errors>
+ </method>
+
+ <signal name="PropertiesChanged" tp:name-for-bindings="Properties_Changed">
+ <arg name="contact" type="u">
+ <tp:docstring>
+ An integer handle representing the contact
+ </tp:docstring>
+ </arg>
+ <arg name="properties" type="a{sv}">
+ <tp:docstring>
+ A dictionary mapping property names to their new values. All
+ properties are included, not just those that have changed.
+ </tp:docstring>
+ </arg>
+ <tp:docstring>
+ Signal emitted when the properties of a contact from your 'subscribe'
+ contact list are changed.
+ </tp:docstring>
+ </signal>
+
+
+ <tp:struct name="Activity" array-name="Activity_List">
+ <tp:docstring>A struct containing:
+ <ul>
+ <li>the identifier of the activity</li>
+ <li>the room handle of the activity channel</li>
+ </ul>
+ </tp:docstring>
+ <tp:member type="s" name="id"/>
+ <tp:member type="u" tp:type="Room_Handle" name="room"/>
+ </tp:struct>
+
+ <method name="SetActivities" tp:name-for-bindings="Set_Activities">
+ <arg direction="in" name="activities" type="a(su)" tp:type="Activity[]">
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ An array of structs containing:
+ <ul>
+ <li>the identifier of the activity</li>
+ <li>the room handle of the activity channel</li>
+ </ul>
+ </tp:docstring>
+ </arg>
+ <tp:docstring>
+ Set the activities of the local user for this connection.
+ </tp:docstring>
+ <tp:possible-errors>
+ <tp:error name="org.freedesktop.Telepathy.Error.Disconnected"/>
+ <tp:error name="org.freedesktop.Telepathy.Error.InvalidArgument"/>
+ </tp:possible-errors>
+ </method>
+
+ <method name="AddActivity" tp:name-for-bindings="Add_Activity">
+ <arg direction="in" name="id" type="s">
+ <tp:docstring>
+ An activity id
+ </tp:docstring>
+ </arg>
+ <arg direction="in" name="handle" type="u">
+ <tp:docstring>
+ A room handle
+ </tp:docstring>
+ </arg>
+ <tp:docstring>
+ Advertise an activity associated to a muc room
+ <tp:rationale>
+ <p>Once an activity shares itself, needs to be advertised if it's not
+ private. SetActivities could be used for this but it would mean that
+ the activity would need to call GetActivities then add itself.</p>
+ </tp:rationale>
+ </tp:docstring>
+ <tp:possible-errors>
+ <tp:error name="org.freedesktop.Telepathy.Error.Disconnected"/>
+ <tp:error name="org.freedesktop.Telepathy.Error.InvalidArgument"/>
+ </tp:possible-errors>
+ </method>
+
+ <method name="GetActivities" tp:name-for-bindings="Get_Activities">
+ <arg direction="in" name="contact" type="u">
+ <tp:docstring>
+ An integer handle for the contact whose activities are to be returned
+ </tp:docstring>
+ </arg>
+ <arg direction="out" name="activities" type="a(su)" tp:type="Activity[]">
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ An array of structs containing:
+ <ul>
+ <li>the identifier of the activity</li>
+ <li>the room handle of the activity channel</li>
+ </ul>
+ </tp:docstring>
+ </arg>
+ <tp:docstring>
+ Get the activities of a particular contact.
+ </tp:docstring>
+ <tp:possible-errors>
+ <tp:error name="org.freedesktop.Telepathy.Error.Disconnected"/>
+ <tp:error name="org.freedesktop.Telepathy.Error.InvalidArgument"/>
+ </tp:possible-errors>
+ </method>
+
+ <signal name="ActivitiesChanged" tp:name-for-bindings="Activities_Changed">
+ <arg name="contact" type="u">
+ <tp:docstring>
+ An integer handle representing the contact
+ </tp:docstring>
+ </arg>
+ <arg name="activities" type="a(su)" tp:type="Activity[]">
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ An array of structs containing:
+ <ul>
+ <li>the identifier of the activity</li>
+ <li>the handle of the activity channel</li>
+ </ul>
+ </tp:docstring>
+ </arg>
+ <tp:docstring>
+ Signal emitted when the activities of a contact from your 'subscribe'
+ contact list are changed.
+ </tp:docstring>
+ </signal>
+
+ <method name="SetCurrentActivity"
+ tp:name-for-bindings="Set_Current_Activity">
+ <arg direction="in" name="activity" type="s">
+ <tp:docstring>
+ The identifier of the activity, or the empty string if there is no
+ current activity
+ </tp:docstring>
+ </arg>
+ <arg direction="in" name="channel" type="u">
+ <tp:docstring>
+ The room handle of the activity channel, or 0 if there is no current
+ activity
+ </tp:docstring>
+ </arg>
+ <tp:docstring>
+ Set the current activity of the local user for this connection.
+ </tp:docstring>
+ <tp:possible-errors>
+ <tp:error name="org.freedesktop.Telepathy.Error.Disconnected"/>
+ <tp:error name="org.freedesktop.Telepathy.Error.InvalidArgument"/>
+ </tp:possible-errors>
+ </method>
+
+ <method name="GetCurrentActivity"
+ tp:name-for-bindings="Get_Current_Activity">
+ <arg direction="in" name="contact" type="u">
+ <tp:docstring>
+ An integer handle for the contact whose current activity is to be
+ returned
+ </tp:docstring>
+ </arg>
+ <arg direction="out" name="activity" type="s">
+ <tp:docstring>
+ The identifier of the activity, or "" if there is no current activity
+ </tp:docstring>
+ </arg>
+ <arg direction="out" name="channel" type="u">
+ <tp:docstring>
+ The room handle of the activity, or 0 if there is no current activity
+ </tp:docstring>
+ </arg>
+ <tp:docstring>
+ Get the current activity of a particular contact.
+ </tp:docstring>
+ <tp:possible-errors>
+ <tp:error name="org.freedesktop.Telepathy.Error.Disconnected"/>
+ <tp:error name="org.freedesktop.Telepathy.Error.InvalidArgument"/>
+ </tp:possible-errors>
+ </method>
+
+ <signal name="CurrentActivityChanged"
+ tp:name-for-bindings="Current_Activity_Changed">
+ <arg name="contact" type="u">
+ <tp:docstring>
+ An integer handle representing the contact
+ </tp:docstring>
+ </arg>
+ <arg name="activity" type="s">
+ <tp:docstring>
+ The identifier of the activity, or "" if there is no current activity
+ </tp:docstring>
+ </arg>
+ <arg name="channel" type="u">
+ <tp:docstring>
+ The room handle of the activity channel, or 0 if there is no current
+ activity
+ </tp:docstring>
+ </arg>
+ <tp:docstring>
+ Signal emitted when the current activity of a contact from your 'subscribe'
+ contact list is changed.
+ </tp:docstring>
+ </signal>
+
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ <p>An interface on connections to associate OLPC buddy information
+ with contacts, providing methods for the user to set their own
+ information and retrieve information of contacts.
+ The user is automatically notified when information of contacts that
+ are in his 'subscribe' contact list change.</p>
+
+ <p>The following types and names are used to request and set information
+ (except for activities):</p>
+ <dl>
+ <dt>s:color</dt>
+ <dd>The color name of the buddy. Format used is #RRGGBB,#RRGGBB
+ (stroke,fill).
+ </dd>
+
+ <dt>ay:key</dt>
+ <dd>The public key of the buddy.</dd>
+
+ <dt>s:jid</dt>
+ <dd>For link-local connections, the JID of the buddy's server account.</dd>
+ </dl>
+
+ <p>Activities are represented by a struct containing:</p>
+ <ul>
+ <li>the identifier of the activity</li>
+ <li>the handle of the activity channel</li>
+ </ul>
+ </tp:docstring>
+ </interface>
+</node>
+<!-- vim:set sw=2 sts=2 et ft=xml: -->
diff --git a/extensions/Salut_Plugin_Test.xml b/extensions/Salut_Plugin_Test.xml
index d62c26b9..265c2a84 100644
--- a/extensions/Salut_Plugin_Test.xml
+++ b/extensions/Salut_Plugin_Test.xml
@@ -17,7 +17,7 @@ Lesser General Public License for more details.</p>
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</p>
</tp:license>
- <interface name="im.telepathy1.Salut.Plugin.Test">
+ <interface name="org.freedesktop.Telepathy.Salut.Plugin.Test">
<tp:docstring xmlns="http://www.w3.org/1999/xhtml">
<p>A sidecar interface implemented by a plugin used by the test
suite.</p>
diff --git a/extensions/connection.xml b/extensions/connection.xml
index cfaafbbd..8e72821c 100644
--- a/extensions/connection.xml
+++ b/extensions/connection.xml
@@ -22,4 +22,7 @@ License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA</p>
</tp:license>
+<xi:include href="OLPC_Buddy_Info.xml"/>
+<xi:include href="OLPC_Activity_Properties.xml"/>
+
</tp:spec>
diff --git a/plugins/test.c b/plugins/test.c
index 6ab15135..70e231b8 100644
--- a/plugins/test.c
+++ b/plugins/test.c
@@ -14,7 +14,7 @@ static void plugin_iface_init (
gpointer g_iface,
gpointer data);
-#define IFACE_TEST "im.telepathy1.Salut.Plugin.Test"
+#define IFACE_TEST "org.freedesktop.Telepathy.Salut.Plugin.Test"
static const gchar * const sidecar_interfaces[] = {
IFACE_TEST,
diff --git a/salut/capabilities.h b/salut/capabilities.h
index 0dcbaee5..faecc64f 100644
--- a/salut/capabilities.h
+++ b/salut/capabilities.h
@@ -43,6 +43,7 @@ const GabbleCapabilitySet *gabble_capabilities_get_any_google_av (void);
const GabbleCapabilitySet *gabble_capabilities_get_any_jingle_av (void);
const GabbleCapabilitySet *gabble_capabilities_get_any_transport (void);
const GabbleCapabilitySet *gabble_capabilities_get_geoloc_notify (void);
+const GabbleCapabilitySet *gabble_capabilities_get_olpc_notify (void);
/* XEP-0115 version 1.3:
*
diff --git a/src/Makefile.am b/src/Makefile.am
index 52fabb1f..e1d10e0d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -106,6 +106,20 @@ BONJOUR_BACKEND_SOURCES = \
bonjour-discovery-client.h \
bonjour-discovery-client.c
+if ENABLE_OLPC
+ CORE_SOURCES += \
+ olpc-activity.h \
+ olpc-activity.c \
+ olpc-activity-manager.h \
+ olpc-activity-manager.c
+
+ AVAHI_BACKEND_SOURCES += \
+ avahi-olpc-activity-manager.h \
+ avahi-olpc-activity-manager.c \
+ avahi-olpc-activity.h \
+ avahi-olpc-activity.c
+endif
+
DUMMY_BACKEND_SOURCES = \
dummy-discovery-client.h \
dummy-discovery-client.c
diff --git a/src/avahi-contact.c b/src/avahi-contact.c
index 385b8516..dd15ed4e 100644
--- a/src/avahi-contact.c
+++ b/src/avahi-contact.c
@@ -649,6 +649,11 @@ contact_resolved_cb (GaServiceResolver *resolver,
char *nick, *first, *last;
/* node, hash and ver as defined by XEP-0115 */
char *node, *hash, *ver;
+#ifdef ENABLE_OLPC
+ char *activity_id, *room_id;
+ char *olpc_key_part;
+ gsize size;
+#endif
DEBUG_RESOLVER (self, resolver, "contact %s resolved", contact->name);
@@ -718,6 +723,73 @@ contact_resolved_cb (GaServiceResolver *resolver,
salut_contact_change_jid (contact, s);
avahi_free (s);
+#ifdef ENABLE_OLPC
+ /* OLPC color */
+ s = _avahi_txt_get_keyval (txt, "olpc-color");
+ salut_contact_change_olpc_color (contact, s);
+ avahi_free (s);
+
+ /* current activity */
+ activity_id = _avahi_txt_get_keyval (txt, "olpc-current-activity");
+ room_id = _avahi_txt_get_keyval (txt, "olpc-current-activity-room");
+
+ salut_contact_change_current_activity (contact, room_id, activity_id);
+ avahi_free (activity_id);
+ avahi_free (room_id);
+
+ /* OLPC key */
+ olpc_key_part = _avahi_txt_get_keyval_with_size (txt,
+ "olpc-key-part0", &size);
+
+ if (olpc_key_part != NULL)
+ {
+ guint i = 0;
+ gchar *olpc_key_part_name = NULL;
+ GArray *olpc_key;
+
+ /* FIXME: how big are OLPC keys anyway? */
+ olpc_key = g_array_sized_new (FALSE, FALSE, sizeof (guint8), 512);
+
+ do
+ {
+ g_array_append_vals (olpc_key, olpc_key_part, size);
+ avahi_free (olpc_key_part);
+
+ i++;
+ olpc_key_part_name = g_strdup_printf ("olpc-key-part%u", i);
+ olpc_key_part = _avahi_txt_get_keyval_with_size (txt,
+ olpc_key_part_name, &size);
+ g_free (olpc_key_part_name);
+ }
+ while (olpc_key_part != NULL);
+
+ salut_contact_change_olpc_key (contact, olpc_key);
+ g_array_unref (olpc_key);
+ }
+
+ /* address */
+ if (address != NULL)
+ {
+ gchar* saddr = g_malloc0 (AVAHI_ADDRESS_STR_MAX);
+
+ if (avahi_address_snprint (saddr, AVAHI_ADDRESS_STR_MAX, address))
+ {
+ switch (address->proto)
+ {
+ case AVAHI_PROTO_INET:
+ salut_contact_change_ipv4_addr (contact, saddr);
+ break;
+ case AVAHI_PROTO_INET6:
+ salut_contact_change_ipv6_addr (contact, saddr);
+ break;
+ default:
+ break;
+ }
+ }
+ g_free (saddr);
+ }
+#endif
+
salut_contact_found (contact);
salut_contact_thaw (contact);
}
diff --git a/src/avahi-discovery-client.c b/src/avahi-discovery-client.c
index b557d331..72cf9203 100644
--- a/src/avahi-discovery-client.c
+++ b/src/avahi-discovery-client.c
@@ -41,6 +41,9 @@
#include "avahi-contact-manager.h"
#include "avahi-roomlist-manager.h"
#include "avahi-self.h"
+#ifdef ENABLE_OLPC
+#include "avahi-olpc-activity-manager.h"
+#endif
#include "presence.h"
@@ -302,6 +305,25 @@ salut_avahi_discovery_client_create_contact_manager (
self));
}
+#ifdef ENABLE_OLPC
+/*
+ * salut_avahi_discovery_client_create_olpc_activity_manager
+ *
+ * Implements salut_discovery_client_create_olpc_activity_manager on
+ * SalutDiscoveryClient
+ */
+static SalutOlpcActivityManager *
+salut_avahi_discovery_client_create_olpc_activity_manager (
+ SalutDiscoveryClient *client,
+ SalutConnection *connection)
+{
+ SalutAvahiDiscoveryClient *self = SALUT_AVAHI_DISCOVERY_CLIENT (client);
+
+ return SALUT_OLPC_ACTIVITY_MANAGER (salut_avahi_olpc_activity_manager_new (
+ connection, self));
+}
+#endif
+
/*
* salut_avahi_discovery_client_create_self
*
@@ -315,12 +337,14 @@ salut_avahi_discovery_client_create_self (SalutDiscoveryClient *client,
const gchar *last_name,
const gchar *jid,
const gchar *email,
- const gchar *published_name)
+ const gchar *published_name,
+ const GArray *olpc_key,
+ const gchar *olpc_color)
{
SalutAvahiDiscoveryClient *self = SALUT_AVAHI_DISCOVERY_CLIENT (client);
return SALUT_SELF (salut_avahi_self_new (connection, self, nickname, first_name,
- last_name, jid, email, published_name));
+ last_name, jid, email, published_name, olpc_key, olpc_color));
}
static const gchar *
@@ -354,6 +378,10 @@ discovery_client_init (gpointer g_iface,
salut_avahi_discovery_client_create_roomlist_manager;
klass->create_contact_manager =
salut_avahi_discovery_client_create_contact_manager;
+#ifdef ENABLE_OLPC
+ klass->create_olpc_activity_manager =
+ salut_avahi_discovery_client_create_olpc_activity_manager;
+#endif
klass->create_self = salut_avahi_discovery_client_create_self;
klass->get_host_name_fqdn = salut_avahi_discovery_client_get_host_name_fqdn;
}
diff --git a/src/avahi-olpc-activity-manager.c b/src/avahi-olpc-activity-manager.c
new file mode 100644
index 00000000..f7ae90fd
--- /dev/null
+++ b/src/avahi-olpc-activity-manager.c
@@ -0,0 +1,376 @@
+/*
+ * avahi-avahi_olpc-activity-manager.c - Source for
+ * SalutAvahiOlpcActivityManager
+ * Copyright (C) 2008 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "avahi-olpc-activity-manager.h"
+
+#include <dbus/dbus-glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <avahi-gobject/ga-service-browser.h>
+
+#include "avahi-olpc-activity.h"
+#include "avahi-discovery-client.h"
+#include "olpc-activity.h"
+
+#define DEBUG_FLAG DEBUG_OLPC_ACTIVITY
+#include "debug.h"
+
+G_DEFINE_TYPE (SalutAvahiOlpcActivityManager, salut_avahi_olpc_activity_manager,
+ SALUT_TYPE_OLPC_ACTIVITY_MANAGER);
+
+/* properties */
+enum {
+ PROP_CLIENT = 1,
+ LAST_PROP
+};
+
+/* private structure */
+typedef struct _SalutAvahiOlpcActivityManagerPrivate SalutAvahiOlpcActivityManagerPrivate;
+
+struct _SalutAvahiOlpcActivityManagerPrivate
+{
+ SalutAvahiDiscoveryClient *discovery_client;
+ GaServiceBrowser *browser;
+
+ gboolean dispose_has_run;
+};
+
+#define SALUT_AVAHI_OLPC_ACTIVITY_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SALUT_TYPE_AVAHI_OLPC_ACTIVITY_MANAGER, SalutAvahiOlpcActivityManagerPrivate))
+
+static void
+salut_avahi_olpc_activity_manager_init (SalutAvahiOlpcActivityManager *self)
+{
+ SalutAvahiOlpcActivityManagerPrivate *priv =
+ SALUT_AVAHI_OLPC_ACTIVITY_MANAGER_GET_PRIVATE (self);
+
+ priv->browser = ga_service_browser_new (SALUT_DNSSD_OLPC_ACTIVITY);
+}
+
+static void
+salut_avahi_olpc_activity_manager_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ SalutAvahiOlpcActivityManager *self = SALUT_AVAHI_OLPC_ACTIVITY_MANAGER (object);
+ SalutAvahiOlpcActivityManagerPrivate *priv = SALUT_AVAHI_OLPC_ACTIVITY_MANAGER_GET_PRIVATE (self);
+
+ switch (property_id)
+ {
+ case PROP_CLIENT:
+ g_value_set_object (value, priv->discovery_client);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+salut_avahi_olpc_activity_manager_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ SalutAvahiOlpcActivityManager *self = SALUT_AVAHI_OLPC_ACTIVITY_MANAGER (object);
+ SalutAvahiOlpcActivityManagerPrivate *priv = SALUT_AVAHI_OLPC_ACTIVITY_MANAGER_GET_PRIVATE (self);
+
+ switch (property_id)
+ {
+ case PROP_CLIENT:
+ priv->discovery_client = g_value_get_object (value);
+ g_object_ref (priv->discovery_client);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+split_activity_name (const gchar *name,
+ gchar **room_name,
+ gchar **contact_name)
+{
+ gchar **tmp;
+
+ tmp = g_strsplit (name, ":", 2);
+ if (tmp[0] == NULL || tmp[1] == NULL)
+ {
+ DEBUG ("Ignoring invalid OLPC activity DNS-SD with no ':': %s", name);
+ return FALSE;
+ }
+
+ if (room_name != NULL)
+ *room_name = g_strdup (tmp[0]);
+ if (contact_name != NULL)
+ *contact_name = g_strdup (tmp[1]);
+
+ g_strfreev (tmp);
+ return TRUE;
+}
+
+static void
+browser_found (GaServiceBrowser *browser,
+ AvahiIfIndex interface,
+ AvahiProtocol protocol,
+ const char *name,
+ const char *type,
+ const char *domain,
+ GaLookupResultFlags flags,
+ SalutAvahiOlpcActivityManager *self)
+{
+ SalutOlpcActivityManager *mgr = SALUT_OLPC_ACTIVITY_MANAGER (self);
+ SalutOlpcActivity *activity;
+ gchar *room_name = NULL;
+ gchar *contact_name = NULL;
+ TpBaseConnection *base_conn = (TpBaseConnection *) mgr->connection;
+ TpHandleRepoIface *room_repo = tp_base_connection_get_handles (
+ base_conn, TP_HANDLE_TYPE_ROOM);
+ TpHandle room;
+ GError *error = NULL;
+ SalutContactManager *contact_manager;
+ SalutContact *contact;
+
+ if (flags & AVAHI_LOOKUP_RESULT_OUR_OWN)
+ return;
+
+ if (tp_base_connection_is_destroyed (base_conn))
+ return;
+
+ if (!split_activity_name (name, &room_name, &contact_name))
+ return;
+
+ room = tp_handle_ensure (room_repo, room_name, NULL, &error);
+ if (room == 0)
+ {
+ DEBUG ("invalid room name %s: %s", room_name, error->message);
+ g_free (room_name);
+ g_free (contact_name);
+ return;
+ }
+
+ activity = salut_olpc_activity_manager_ensure_activity_by_room (mgr,
+ room);
+
+ salut_avahi_olpc_activity_add_service (SALUT_AVAHI_OLPC_ACTIVITY (activity),
+ interface, protocol, name, type, domain);
+
+ g_object_get (mgr->connection,
+ "contact-manager", &contact_manager, NULL);
+ g_assert (contact_manager != NULL);
+
+ contact = salut_contact_manager_ensure_contact (contact_manager,
+ contact_name);
+ salut_olpc_activity_manager_contact_joined (mgr, contact, activity);
+
+ g_object_unref (activity);
+ g_free (contact_name);
+ g_free (room_name);
+ g_object_unref (contact);
+ g_object_unref (contact_manager);
+}
+
+static void
+browser_removed (GaServiceBrowser *browser,
+ AvahiIfIndex interface,
+ AvahiProtocol protocol,
+ const char *name,
+ const char *type,
+ const char *domain,
+ GaLookupResultFlags flags,
+ SalutAvahiOlpcActivityManager *self)
+{
+ SalutOlpcActivityManager *mgr = SALUT_OLPC_ACTIVITY_MANAGER (self);
+ SalutOlpcActivity *activity;
+ gchar *room_name = NULL;
+ gchar *contact_name = NULL;
+ TpHandleRepoIface *room_repo = tp_base_connection_get_handles
+ ((TpBaseConnection *) mgr->connection, TP_HANDLE_TYPE_ROOM);
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles
+ ((TpBaseConnection *) mgr->connection, TP_HANDLE_TYPE_CONTACT);
+ TpHandle room;
+ TpHandle contact_handle;
+ GError *error = NULL;
+ SalutContactManager *contact_manager;
+ SalutContact *contact;
+
+ if (!split_activity_name (name, &room_name, &contact_name))
+ return;
+
+ room = tp_handle_ensure (room_repo, room_name, NULL, &error);
+ g_free (room_name);
+ if (room == 0)
+ {
+ DEBUG ("invalid room name %s: %s", room_name, error->message);
+ g_free (contact_name);
+ g_error_free (error);
+ return;
+ }
+
+ contact_handle = tp_handle_ensure (contact_repo, contact_name, NULL, &error);
+ if (contact_handle == 0)
+ {
+ DEBUG ("Invalid contact name %s: %s", contact_name, error->message);
+ g_error_free (error);
+ g_free (contact_name);
+ return;
+ }
+ g_free (contact_name);
+
+ activity = salut_olpc_activity_manager_get_activity_by_room (mgr, room);
+ if (activity == NULL)
+ return;
+
+ salut_avahi_olpc_activity_remove_service (SALUT_AVAHI_OLPC_ACTIVITY (activity),
+ interface, protocol, name, type, domain);
+
+ g_object_get (mgr->connection,
+ "contact-manager", &contact_manager, NULL);
+ g_assert (contact_manager != NULL);
+
+ contact = salut_contact_manager_get_contact (contact_manager,
+ contact_handle);
+ g_object_unref (contact_manager);
+ if (contact == NULL)
+ return;
+
+ salut_olpc_activity_manager_contact_left (mgr, contact, activity);
+ g_object_unref (contact);
+}
+
+static void
+browser_failed (GaServiceBrowser *browser,
+ GError *error,
+ SalutAvahiOlpcActivityManager *self)
+{
+ g_warning ("browser failed -> %s", error->message);
+}
+
+static gboolean
+salut_avahi_olpc_activity_manager_start (SalutOlpcActivityManager *mgr,
+ GError **error)
+{
+ SalutAvahiOlpcActivityManager *self = SALUT_AVAHI_OLPC_ACTIVITY_MANAGER (mgr);
+ SalutAvahiOlpcActivityManagerPrivate *priv =
+ SALUT_AVAHI_OLPC_ACTIVITY_MANAGER_GET_PRIVATE (self);
+
+ g_signal_connect (priv->browser, "new-service",
+ G_CALLBACK (browser_found), self);
+ g_signal_connect (priv->browser, "removed-service",
+ G_CALLBACK (browser_removed), self);
+ g_signal_connect (priv->browser, "failure",
+ G_CALLBACK (browser_failed), self);
+
+ if (!ga_service_browser_attach (priv->browser,
+ priv->discovery_client->avahi_client, error))
+ {
+ DEBUG ("browser attach failed");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static SalutOlpcActivity *
+salut_avahi_olpc_activity_manager_create_activity (
+ SalutOlpcActivityManager *mgr)
+{
+ SalutAvahiOlpcActivityManager *self = SALUT_AVAHI_OLPC_ACTIVITY_MANAGER (mgr);
+ SalutAvahiOlpcActivityManagerPrivate *priv =
+ SALUT_AVAHI_OLPC_ACTIVITY_MANAGER_GET_PRIVATE (self);
+
+ return SALUT_OLPC_ACTIVITY (salut_avahi_olpc_activity_new (
+ mgr->connection, priv->discovery_client));
+}
+
+static void salut_avahi_olpc_activity_manager_dispose (GObject *object);
+
+static void
+salut_avahi_olpc_activity_manager_class_init (SalutAvahiOlpcActivityManagerClass *salut_avahi_olpc_activity_manager_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (salut_avahi_olpc_activity_manager_class);
+ SalutOlpcActivityManagerClass *activity_manager_class = SALUT_OLPC_ACTIVITY_MANAGER_CLASS (
+ salut_avahi_olpc_activity_manager_class);
+
+ GParamSpec *param_spec;
+
+ g_type_class_add_private (salut_avahi_olpc_activity_manager_class,
+ sizeof (SalutAvahiOlpcActivityManagerPrivate));
+
+ object_class->get_property = salut_avahi_olpc_activity_manager_get_property;
+ object_class->set_property = salut_avahi_olpc_activity_manager_set_property;
+
+ object_class->dispose = salut_avahi_olpc_activity_manager_dispose;
+
+ activity_manager_class->start = salut_avahi_olpc_activity_manager_start;
+ activity_manager_class->create_activity =
+ salut_avahi_olpc_activity_manager_create_activity;
+
+ param_spec = g_param_spec_object (
+ "discovery-client",
+ "SalutAvahiDiscoveryClient object",
+ "The Salut Avahi Discovery client associated with this manager",
+ SALUT_TYPE_AVAHI_DISCOVERY_CLIENT,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_CLIENT,
+ param_spec);
+}
+
+static void
+salut_avahi_olpc_activity_manager_dispose (GObject *object)
+{
+ SalutAvahiOlpcActivityManager *self = SALUT_AVAHI_OLPC_ACTIVITY_MANAGER (object);
+ SalutAvahiOlpcActivityManagerPrivate *priv = SALUT_AVAHI_OLPC_ACTIVITY_MANAGER_GET_PRIVATE (self);
+
+ if (priv->dispose_has_run)
+ return;
+
+ priv->dispose_has_run = TRUE;
+
+ if (priv->discovery_client != NULL)
+ {
+ g_object_unref (priv->discovery_client);
+ priv->discovery_client = NULL;
+ }
+
+ if (priv->browser != NULL)
+ {
+ g_object_unref (priv->browser);
+ priv->browser = NULL;
+ }
+
+ if (G_OBJECT_CLASS (salut_avahi_olpc_activity_manager_parent_class)->dispose)
+ G_OBJECT_CLASS (salut_avahi_olpc_activity_manager_parent_class)->dispose (object);
+}
+
+SalutAvahiOlpcActivityManager *
+salut_avahi_olpc_activity_manager_new (SalutConnection *connection,
+ SalutAvahiDiscoveryClient *discovery_client)
+{
+ return g_object_new (SALUT_TYPE_AVAHI_OLPC_ACTIVITY_MANAGER,
+ "connection", connection,
+ "discovery-client", discovery_client,
+ NULL);
+}
diff --git a/src/avahi-olpc-activity-manager.h b/src/avahi-olpc-activity-manager.h
new file mode 100644
index 00000000..88c94db3
--- /dev/null
+++ b/src/avahi-olpc-activity-manager.h
@@ -0,0 +1,68 @@
+/*
+ * avahi-olpc-activity-managere.h - Header for
+ * SalutAvahiOlpcActivityManager
+ * Copyright (C) 2008 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __SALUT_AVAHI_OLPC_ACTIVITY_MANAGER_H__
+#define __SALUT_AVAHI_OLPC_ACTIVITY_MANAGER_H__
+
+#include <glib-object.h>
+
+#include <telepathy-glib/telepathy-glib.h>
+
+#include "olpc-activity-manager.h"
+#include "connection.h"
+#include "avahi-discovery-client.h"
+
+G_BEGIN_DECLS
+
+typedef struct _SalutAvahiOlpcActivityManager SalutAvahiOlpcActivityManager;
+typedef struct _SalutAvahiOlpcActivityManagerClass SalutAvahiOlpcActivityManagerClass;
+
+struct _SalutAvahiOlpcActivityManagerClass {
+ SalutOlpcActivityManagerClass parent_class;
+};
+
+struct _SalutAvahiOlpcActivityManager {
+ SalutOlpcActivityManager parent;
+};
+
+GType salut_avahi_olpc_activity_manager_get_type (void);
+
+/* TYPE MACROS */
+#define SALUT_TYPE_AVAHI_OLPC_ACTIVITY_MANAGER \
+ (salut_avahi_olpc_activity_manager_get_type ())
+#define SALUT_AVAHI_OLPC_ACTIVITY_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), SALUT_TYPE_AVAHI_OLPC_ACTIVITY_MANAGER, \
+ SalutAvahiOlpcActivityManager))
+#define SALUT_AVAHI_OLPC_ACTIVITY_MANAGER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), SALUT_TYPE_AVAHI_OLPC_ACTIVITY_MANAGER, \
+ SalutAvahiOlpcActivityManagerClass))
+#define SALUT_IS_AVAHI_OLPC_ACTIVITY_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), SALUT_TYPE_AVAHI_OLPC_ACTIVITY_MANAGER))
+#define SALUT_IS_AVAHI_OLPC_ACTIVITY_MANAGER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), SALUT_TYPE_AVAHI_OLPC_ACTIVITY_MANAGER))
+#define SALUT_AVAHI_OLPC_ACTIVITY_MANAGER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), SALUT_TYPE_AVAHI_OLPC_ACTIVITY_MANAGER, SalutAvahiOlpcActivityManagerClass))
+
+SalutAvahiOlpcActivityManager * salut_avahi_olpc_activity_manager_new (
+ SalutConnection *connection, SalutAvahiDiscoveryClient *discovery_client);
+
+G_END_DECLS
+
+#endif /* #ifndef __SALUT_AVAHI_OLPC_ACTIVITY_MANAGER_H__*/
diff --git a/src/avahi-olpc-activity.c b/src/avahi-olpc-activity.c
new file mode 100644
index 00000000..8dba37af
--- /dev/null
+++ b/src/avahi-olpc-activity.c
@@ -0,0 +1,546 @@
+/*
+ * avahi-olpc-activity.c - Source for SalutAvahiOlpcActivity
+ * Copyright (C) 2008 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "avahi-olpc-activity.h"
+
+#include <dbus/dbus-glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <avahi-gobject/ga-entry-group.h>
+#include <avahi-gobject/ga-service-resolver.h>
+#include <avahi-common/malloc.h>
+
+#define DEBUG_FLAG DEBUG_OLPC_ACTIVITY
+#include "debug.h"
+
+G_DEFINE_TYPE (SalutAvahiOlpcActivity, salut_avahi_olpc_activity,
+ SALUT_TYPE_OLPC_ACTIVITY);
+
+/* properties */
+enum {
+ PROP_CLIENT = 1,
+ LAST_PROP
+};
+
+/* private structure */
+typedef struct _SalutAvahiOlpcActivityPrivate SalutAvahiOlpcActivityPrivate;
+
+struct _SalutAvahiOlpcActivityPrivate
+{
+ SalutAvahiDiscoveryClient *discovery_client;
+ GSList *resolvers;
+ /* group and service can be NULL if we are not announcing this activity */
+ GaEntryGroup *group;
+ GaEntryGroupService *service;
+
+ gboolean dispose_has_run;
+};
+
+#define SALUT_AVAHI_OLPC_ACTIVITY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SALUT_TYPE_AVAHI_OLPC_ACTIVITY, SalutAvahiOlpcActivityPrivate))
+
+static void
+salut_avahi_olpc_activity_init (SalutAvahiOlpcActivity *obj)
+{
+ SalutAvahiOlpcActivityPrivate *priv = SALUT_AVAHI_OLPC_ACTIVITY_GET_PRIVATE (
+ obj);
+
+ priv->resolvers = NULL;
+}
+
+static void
+salut_avahi_olpc_activity_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ SalutAvahiOlpcActivity *self = SALUT_AVAHI_OLPC_ACTIVITY (object);
+ SalutAvahiOlpcActivityPrivate *priv = SALUT_AVAHI_OLPC_ACTIVITY_GET_PRIVATE (
+ self);
+
+ switch (property_id)
+ {
+ case PROP_CLIENT:
+ g_value_set_object (value, priv->discovery_client);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+salut_avahi_olpc_activity_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ SalutAvahiOlpcActivity *self = SALUT_AVAHI_OLPC_ACTIVITY (object);
+ SalutAvahiOlpcActivityPrivate *priv = SALUT_AVAHI_OLPC_ACTIVITY_GET_PRIVATE (
+ self);
+
+ switch (property_id)
+ {
+ case PROP_CLIENT:
+ priv->discovery_client = g_value_get_object (value);
+ g_object_ref (priv->discovery_client);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+activity_is_announced (SalutAvahiOlpcActivity *self)
+{
+ SalutAvahiOlpcActivityPrivate *priv = SALUT_AVAHI_OLPC_ACTIVITY_GET_PRIVATE (
+ self);
+
+ return (priv->group != NULL && priv->service != NULL);
+}
+
+static gboolean
+update_activity_service (SalutAvahiOlpcActivity *self,
+ GError **error)
+{
+ SalutOlpcActivity *activity = SALUT_OLPC_ACTIVITY (self);
+ SalutAvahiOlpcActivityPrivate *priv = SALUT_AVAHI_OLPC_ACTIVITY_GET_PRIVATE (
+ self);
+ GError *err = NULL;
+
+ if (!activity_is_announced (self))
+ {
+ g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "Trying to update an activity that's not announced");
+ return FALSE;
+ }
+
+ ga_entry_group_service_freeze (priv->service);
+
+ if (activity->name != NULL)
+ ga_entry_group_service_set (priv->service, "name",
+ activity->name, NULL);
+
+ if (activity->color != NULL)
+ ga_entry_group_service_set (priv->service, "color",
+ activity->color, NULL);
+
+ if (activity->type != NULL)
+ ga_entry_group_service_set (priv->service, "type",
+ activity->type, NULL);
+
+ if (activity->tags != NULL)
+ ga_entry_group_service_set (priv->service, "tags",
+ activity->tags, NULL);
+
+ return ga_entry_group_service_thaw (priv->service, &err);
+}
+
+static gboolean
+salut_avahi_olpc_activity_announce (SalutOlpcActivity *activity,
+ GError **error)
+{
+ SalutAvahiOlpcActivity *self = SALUT_AVAHI_OLPC_ACTIVITY (activity);
+ SalutAvahiOlpcActivityPrivate *priv = SALUT_AVAHI_OLPC_ACTIVITY_GET_PRIVATE (
+ self);
+ const gchar *room_name;
+ gchar *name;
+ AvahiStringList *txt_record;
+ TpHandleRepoIface *room_repo;
+ gchar *published_name;
+
+ g_return_val_if_fail (!activity->is_private, FALSE);
+ g_return_val_if_fail (!activity_is_announced (self), FALSE);
+
+ room_repo = tp_base_connection_get_handles (
+ (TpBaseConnection *) activity->connection, TP_HANDLE_TYPE_ROOM);
+
+ room_name = tp_handle_inspect (room_repo, activity->room);
+ /* caller should already have validated this */
+ g_return_val_if_fail (room_name != NULL, FALSE);
+
+ priv->group = ga_entry_group_new ();
+ if (!ga_entry_group_attach (priv->group, priv->discovery_client->avahi_client,
+ error))
+ return FALSE;
+
+ g_object_get (activity->connection, "published-name", &published_name, NULL);
+
+ name = g_strdup_printf ("%s:%s@%s", room_name, published_name,
+ avahi_client_get_host_name (
+ priv->discovery_client->avahi_client->avahi_client));
+
+ g_free (published_name);
+
+ txt_record = avahi_string_list_new ("txtvers=0", NULL);
+ txt_record = avahi_string_list_add_printf (txt_record, "room=%s", room_name);
+ if (activity->id != NULL)
+ txt_record = avahi_string_list_add_printf (txt_record, "activity-id=%s",
+ activity->id);
+
+ priv->service = ga_entry_group_add_service_strlist (priv->group, name,
+ SALUT_DNSSD_OLPC_ACTIVITY, 0, error, txt_record);
+
+ if (priv->service == NULL)
+ return FALSE;
+
+ DEBUG ("announce activity %s", name);
+ g_free (name);
+ avahi_string_list_free (txt_record);
+
+ if (!ga_entry_group_commit (priv->group, error))
+ return FALSE;
+
+ /* announce activities properties */
+ if (!update_activity_service (self, error))
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+salut_avahi_olpc_activity_stop_announce (SalutOlpcActivity *activity)
+{
+ SalutAvahiOlpcActivity *self = SALUT_AVAHI_OLPC_ACTIVITY (activity);
+ SalutAvahiOlpcActivityPrivate *priv = SALUT_AVAHI_OLPC_ACTIVITY_GET_PRIVATE (
+ self);
+
+ /* Announcing the activity could have failed, so check if we're actually
+ * announcing it */
+ if (!activity_is_announced (self))
+ return;
+
+ g_object_unref (priv->group);
+ priv->group = NULL;
+ priv->service = NULL;
+
+ DEBUG ("stop announce activity %s", activity->id);
+}
+
+static gboolean
+salut_avahi_update (SalutOlpcActivity *activity,
+ GError **error)
+{
+ SalutAvahiOlpcActivity *self = SALUT_AVAHI_OLPC_ACTIVITY (activity);
+
+ return update_activity_service (self, error);
+}
+
+static void salut_avahi_olpc_activity_dispose (GObject *object);
+static void salut_avahi_olpc_activity_finalize (GObject *object);
+
+static void
+salut_avahi_olpc_activity_class_init (
+ SalutAvahiOlpcActivityClass *salut_avahi_olpc_activity_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (salut_avahi_olpc_activity_class);
+ SalutOlpcActivityClass *activity_class = SALUT_OLPC_ACTIVITY_CLASS (
+ salut_avahi_olpc_activity_class);
+ GParamSpec *param_spec;
+
+ g_type_class_add_private (salut_avahi_olpc_activity_class,
+ sizeof (SalutAvahiOlpcActivityPrivate));
+
+ object_class->get_property = salut_avahi_olpc_activity_get_property;
+ object_class->set_property = salut_avahi_olpc_activity_set_property;
+
+ object_class->dispose = salut_avahi_olpc_activity_dispose;
+ object_class->finalize = salut_avahi_olpc_activity_finalize;
+
+ activity_class->announce = salut_avahi_olpc_activity_announce;
+ activity_class->stop_announce = salut_avahi_olpc_activity_stop_announce;
+ activity_class->update = salut_avahi_update;
+
+ param_spec = g_param_spec_object (
+ "discovery-client",
+ "SalutAvahiDiscoveryClient object",
+ "The Salut Avahi Discovery client associated with this manager",
+ SALUT_TYPE_AVAHI_DISCOVERY_CLIENT,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_CLIENT,
+ param_spec);
+}
+
+void
+salut_avahi_olpc_activity_dispose (GObject *object)
+{
+ SalutAvahiOlpcActivity *self = SALUT_AVAHI_OLPC_ACTIVITY (object);
+ SalutAvahiOlpcActivityPrivate *priv = SALUT_AVAHI_OLPC_ACTIVITY_GET_PRIVATE (
+ self);
+
+ if (priv->dispose_has_run)
+ return;
+
+ priv->dispose_has_run = TRUE;
+
+ g_slist_foreach (priv->resolvers, (GFunc) g_object_unref, NULL);
+ g_slist_free (priv->resolvers);
+ priv->resolvers = NULL;
+
+ if (priv->group != NULL)
+ {
+ g_object_unref (priv->group);
+ priv->group = NULL;
+ }
+
+ if (priv->discovery_client != NULL)
+ {
+ g_object_unref (priv->discovery_client);
+ priv->discovery_client = NULL;
+ }
+
+ if (G_OBJECT_CLASS (salut_avahi_olpc_activity_parent_class)->dispose)
+ G_OBJECT_CLASS (salut_avahi_olpc_activity_parent_class)->dispose (object);
+}
+
+void
+salut_avahi_olpc_activity_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (salut_avahi_olpc_activity_parent_class)->finalize (object);
+}
+
+SalutAvahiOlpcActivity *
+salut_avahi_olpc_activity_new (SalutConnection *connection,
+ SalutAvahiDiscoveryClient *discovery_client)
+{
+ return g_object_new (SALUT_TYPE_AVAHI_OLPC_ACTIVITY,
+ "connection", connection,
+ "discovery-client", discovery_client,
+ NULL);
+}
+
+struct resolverinfo
+{
+ AvahiIfIndex interface;
+ AvahiProtocol protocol;
+ const gchar *name;
+ const gchar *type;
+ const gchar *domain;
+};
+
+static gint
+compare_resolver (GaServiceResolver *resolver,
+ struct resolverinfo *info)
+{
+ AvahiIfIndex interface;
+ AvahiProtocol protocol;
+ gchar *name;
+ gchar *type;
+ gchar *domain;
+ gint result;
+
+ g_object_get (resolver,
+ "interface", &interface,
+ "protocol", &protocol,
+ "name", &name,
+ "type", &type,
+ "domain", &domain,
+ NULL);
+
+ if (interface == info->interface
+ && protocol == info->protocol
+ && !tp_strdiff (name, info->name)
+ && !tp_strdiff (type, info->type)
+ && !tp_strdiff (domain, info->domain))
+ {
+ result = 0;
+ }
+ else
+ {
+ result = 1;
+ }
+
+ g_free (name);
+ g_free (type);
+ g_free (domain);
+ return result;
+}
+
+static GaServiceResolver *
+find_resolver (SalutAvahiOlpcActivity *self,
+ AvahiIfIndex interface,
+ AvahiProtocol protocol,
+ const gchar *name,
+ const gchar *type,
+ const gchar *domain)
+{
+ SalutAvahiOlpcActivityPrivate *priv = SALUT_AVAHI_OLPC_ACTIVITY_GET_PRIVATE (
+ self);
+ struct resolverinfo info;
+ GSList *ret;
+
+ info.interface = interface;
+ info.protocol = protocol;
+ info.name = name;
+ info.type = type;
+ info.domain = domain;
+ ret = g_slist_find_custom (priv->resolvers, &info,
+ (GCompareFunc) compare_resolver);
+
+ return ret ? GA_SERVICE_RESOLVER (ret->data) : NULL;
+}
+
+static void
+activity_resolved_cb (GaServiceResolver *resolver,
+ AvahiIfIndex interface,
+ AvahiProtocol protocol,
+ gchar *name,
+ gchar *type,
+ gchar *domain,
+ gchar *host_name,
+ AvahiAddress *a,
+ gint port,
+ AvahiStringList *txt,
+ AvahiLookupResultFlags flags,
+ SalutAvahiOlpcActivity *self)
+{
+ SalutOlpcActivity *act = SALUT_OLPC_ACTIVITY (self);
+ AvahiStringList *t;
+ char *activity_id = NULL;
+ char *color = NULL;
+ char *activity_name = NULL;
+ char *activity_type = NULL;
+ char *tags = NULL;
+ char *room_name = NULL;
+ TpHandle room = 0;
+ TpHandleRepoIface *room_repo = tp_base_connection_get_handles
+ ((TpBaseConnection *) act->connection, TP_HANDLE_TYPE_ROOM);
+
+ DEBUG ("called: \"%s\".%s. on %s port %u", name, domain, host_name, port);
+
+ if ((t = avahi_string_list_find (txt, "txtvers")) != NULL)
+ {
+ char *txtvers;
+
+ avahi_string_list_get_pair (t, NULL, &txtvers, NULL);
+ if (tp_strdiff (txtvers, "0"))
+ {
+ DEBUG ("Ignoring record with txtvers not 0: %s",
+ txtvers ? txtvers : "(no value)");
+ avahi_free (txtvers);
+ return;
+ }
+ avahi_free (txtvers);
+ }
+
+ if ((t = avahi_string_list_find (txt, "room")) != NULL)
+ {
+ avahi_string_list_get_pair (t, NULL, &room_name, NULL);
+
+ room = tp_handle_ensure (room_repo, room_name, NULL, NULL);
+ avahi_free (room_name);
+ if (room == 0)
+ {
+ DEBUG ("Ignoring record with invalid room name: %s", room_name);
+ return;
+ }
+ }
+
+ if ((t = avahi_string_list_find (txt, "activity-id")) != NULL)
+ {
+ avahi_string_list_get_pair (t, NULL, &activity_id, NULL);
+ }
+
+ if ((t = avahi_string_list_find (txt, "color")) != NULL)
+ {
+ avahi_string_list_get_pair (t, NULL, &color, NULL);
+ }
+
+ if ((t = avahi_string_list_find (txt, "name")) != NULL)
+ {
+ avahi_string_list_get_pair (t, NULL, &activity_name, NULL);
+ }
+
+ if ((t = avahi_string_list_find (txt, "type")) != NULL)
+ {
+ avahi_string_list_get_pair (t, NULL, &activity_type, NULL);
+ }
+
+ if ((t = avahi_string_list_find (txt, "tags")) != NULL)
+ {
+ avahi_string_list_get_pair (t, NULL, &tags, NULL);
+ }
+
+ salut_olpc_activity_update (SALUT_OLPC_ACTIVITY (self), room,
+ activity_id, activity_name, activity_type, color, tags, FALSE);
+
+ avahi_free (activity_id);
+ avahi_free (activity_type);
+ avahi_free (activity_name);
+ avahi_free (color);
+ avahi_free (tags);
+}
+
+void
+salut_avahi_olpc_activity_add_service (SalutAvahiOlpcActivity *self,
+ AvahiIfIndex interface,
+ AvahiProtocol protocol,
+ const char *name,
+ const char *type,
+ const char *domain)
+{
+ SalutAvahiOlpcActivityPrivate *priv = SALUT_AVAHI_OLPC_ACTIVITY_GET_PRIVATE (
+ self);
+ GaServiceResolver *resolver;
+ GError *error = NULL;
+
+ resolver = find_resolver (self, interface, protocol, name, type, domain);
+ if (resolver != NULL)
+ return;
+
+ resolver = ga_service_resolver_new (interface, protocol, name, type, domain,
+ protocol, 0);
+
+ g_signal_connect (resolver, "found", G_CALLBACK (activity_resolved_cb),
+ self);
+
+ if (!ga_service_resolver_attach (resolver,
+ priv->discovery_client->avahi_client, &error))
+ {
+ g_warning ("Failed to attach resolver: %s", error->message);
+ g_error_free (error);
+ }
+
+ /* DEBUG_RESOLVER (contact, resolver, "added"); */
+ priv->resolvers = g_slist_prepend (priv->resolvers, resolver);
+}
+
+void
+salut_avahi_olpc_activity_remove_service (SalutAvahiOlpcActivity *self,
+ AvahiIfIndex interface,
+ AvahiProtocol protocol,
+ const char *name,
+ const char *type,
+ const char *domain)
+{
+ SalutAvahiOlpcActivityPrivate *priv = SALUT_AVAHI_OLPC_ACTIVITY_GET_PRIVATE (
+ self);
+ GaServiceResolver *resolver;
+
+ resolver = find_resolver (self, interface, protocol, name, type, domain);
+
+ if (resolver == NULL)
+ return;
+
+ priv->resolvers = g_slist_remove (priv->resolvers, resolver);
+ g_object_unref (resolver);
+}
diff --git a/src/avahi-olpc-activity.h b/src/avahi-olpc-activity.h
new file mode 100644
index 00000000..6343261a
--- /dev/null
+++ b/src/avahi-olpc-activity.h
@@ -0,0 +1,70 @@
+/*
+ * avahi-olpc-activity.h - Header for SalutAvahiOlpcActivity
+ * Copyright (C) 2008 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __SALUT_AVAHI_OLPC_ACTIVITY_H__
+#define __SALUT_AVAHI_OLPC_ACTIVITY_H__
+
+#include <glib-object.h>
+
+#include "olpc-activity.h"
+#include "avahi-discovery-client.h"
+
+G_BEGIN_DECLS
+
+typedef struct _SalutAvahiOlpcActivity SalutAvahiOlpcActivity;
+typedef struct _SalutAvahiOlpcActivityClass SalutAvahiOlpcActivityClass;
+
+struct _SalutAvahiOlpcActivityClass {
+ SalutOlpcActivityClass parent_class;
+};
+
+struct _SalutAvahiOlpcActivity {
+ SalutOlpcActivity parent;
+};
+
+GType salut_avahi_olpc_activity_get_type (void);
+
+/* TYPE MACROS */
+#define SALUT_TYPE_AVAHI_OLPC_ACTIVITY \
+ (salut_avahi_olpc_activity_get_type ())
+#define SALUT_AVAHI_OLPC_ACTIVITY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), SALUT_TYPE_AVAHI_OLPC_ACTIVITY, SalutAvahiOlpcActivity))
+#define SALUT_AVAHI_OLPC_ACTIVITY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), SALUT_TYPE_AVAHI_OLPC_ACTIVITY, SalutAvahiOlpcActivityClass))
+#define SALUT_IS_AVAHI_OLPC_ACTIVITY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), SALUT_TYPE_AVAHI_OLPC_ACTIVITY))
+#define SALUT_IS_AVAHI_OLPC_ACTIVITY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), SALUT_TYPE_AVAHI_OLPC_ACTIVITY))
+#define SALUT_AVAHI_OLPC_ACTIVITY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), SALUT_TYPE_AVAHI_OLPC_ACTIVITY, SalutAvahiOlpcActivityClass))
+
+SalutAvahiOlpcActivity * salut_avahi_olpc_activity_new (
+ SalutConnection *connection, SalutAvahiDiscoveryClient *discovery_client);
+
+void salut_avahi_olpc_activity_add_service (SalutAvahiOlpcActivity *activity,
+ AvahiIfIndex interface, AvahiProtocol protocol,
+ const char *name, const char *type, const char *domain);
+
+void salut_avahi_olpc_activity_remove_service (SalutAvahiOlpcActivity *activity,
+ AvahiIfIndex interface, AvahiProtocol protocol,
+ const char *name, const char *type, const char *domain);
+
+G_END_DECLS
+
+#endif /* #ifndef __SALUT_AVAHI_OLPC_ACTIVITY_H__*/
diff --git a/src/avahi-self.c b/src/avahi-self.c
index 8c6c7495..0b752868 100644
--- a/src/avahi-self.c
+++ b/src/avahi-self.c
@@ -32,6 +32,10 @@
#include "sha1/sha1-util.h"
+#ifdef ENABLE_OLPC
+#define KEY_SEGMENT_SIZE 200
+#endif
+
G_DEFINE_TYPE (SalutAvahiSelf, salut_avahi_self, SALUT_TYPE_SELF);
/* properties */
@@ -140,6 +144,30 @@ create_txt_record (SalutAvahiSelf *self,
if (_self->jid != NULL)
ret = avahi_string_list_add_printf (ret, "jid=%s", _self->jid);
+#ifdef ENABLE_OLPC
+ if (_self->olpc_color)
+ ret = avahi_string_list_add_printf (ret, "olpc-color=%s",
+ _self->olpc_color);
+
+ if (_self->olpc_key != NULL)
+ {
+ uint8_t *key = (uint8_t *) _self->olpc_key->data;
+ size_t key_len = _self->olpc_key->len;
+ guint i = 0;
+
+ while (key_len > 0)
+ {
+ size_t step = MIN (key_len, KEY_SEGMENT_SIZE);
+ gchar *name = g_strdup_printf ("olpc-key-part%u", i);
+
+ ret = avahi_string_list_add_pair_arbitrary (ret, name, key, step);
+ key += step;
+ key_len -= step;
+ i++;
+ }
+ }
+#endif
+
ret = avahi_string_list_add_printf (ret, "status=%s",
salut_presence_status_txt_names[_self->status]);
@@ -334,6 +362,99 @@ salut_avahi_self_set_avatar (SalutSelf *_self,
_self->avatar_token, error);
}
+#ifdef ENABLE_OLPC
+static gboolean
+salut_avahi_self_update_current_activity (SalutSelf *_self,
+ const gchar *room_name,
+ GError **error)
+{
+ SalutAvahiSelf *self = SALUT_AVAHI_SELF (_self);
+ SalutAvahiSelfPrivate *priv = self->priv;
+
+ ga_entry_group_service_freeze (priv->presence);
+
+ ga_entry_group_service_set (priv->presence,
+ "olpc-current-activity", _self->olpc_cur_act, NULL);
+
+ ga_entry_group_service_set (priv->presence,
+ "olpc-current-activity-room", room_name, NULL);
+
+ return ga_entry_group_service_thaw (priv->presence, error);
+}
+
+static gboolean
+salut_avahi_self_set_olpc_properties (SalutSelf *_self,
+ const GArray *key,
+ const gchar *color,
+ const gchar *jid,
+ GError **error)
+{
+ SalutAvahiSelf *self = SALUT_AVAHI_SELF (_self);
+ SalutAvahiSelfPrivate *priv = self->priv;
+
+ ga_entry_group_service_freeze (priv->presence);
+
+ if (key != NULL)
+ {
+ size_t key_len = key->len;
+ const guint8 *key_data = (const guint8 *) key->data;
+ guint i;
+ guint to_remove;
+
+ if (_self->olpc_key == NULL)
+ {
+ to_remove = 0;
+ }
+ else
+ {
+ to_remove = (_self->olpc_key->len + KEY_SEGMENT_SIZE - 1) /
+ KEY_SEGMENT_SIZE;
+ }
+
+ i = 0;
+ while (key_len > 0)
+ {
+ size_t step = MIN (key_len, KEY_SEGMENT_SIZE);
+ gchar *name = g_strdup_printf ("olpc-key-part%u", i);
+
+ ga_entry_group_service_set_arbitrary (priv->presence, name,
+ key_data, step, NULL);
+ g_free (name);
+
+ key_data += step;
+ key_len -= step;
+ i++;
+ }
+
+ /* if the new key is shorter than the old, clean up any stray segments */
+ while (i < to_remove)
+ {
+ gchar *name = g_strdup_printf ("olpc-key-part%u", i);
+
+ ga_entry_group_service_remove_key (priv->presence, name,
+ NULL);
+ g_free (name);
+
+ i++;
+ }
+ }
+
+ if (color != NULL)
+ {
+ ga_entry_group_service_set (priv->presence, "olpc-color",
+ color, NULL);
+ }
+
+ if (jid != NULL)
+ {
+ ga_entry_group_service_set (priv->presence, "jid",
+ jid, NULL);
+ }
+
+ return ga_entry_group_service_thaw (priv->presence, error);
+}
+#endif
+
static void salut_avahi_self_dispose (GObject *object);
static void
@@ -358,6 +479,11 @@ salut_avahi_self_class_init (
self_class->set_alias = salut_avahi_self_set_alias;
self_class->remove_avatar = salut_avahi_self_remove_avatar;
self_class->set_avatar = salut_avahi_self_set_avatar;
+#ifdef ENABLE_OLPC
+ self_class->update_current_activity =
+ salut_avahi_self_update_current_activity;
+ self_class->set_olpc_properties = salut_avahi_self_set_olpc_properties;
+#endif
param_spec = g_param_spec_object (
"discovery-client",
@@ -411,7 +537,9 @@ salut_avahi_self_new (SalutConnection *connection,
const gchar *last_name,
const gchar *jid,
const gchar *email,
- const gchar *published_name)
+ const gchar *published_name,
+ const GArray *olpc_key,
+ const gchar *olpc_color)
{
return g_object_new (SALUT_TYPE_AVAHI_SELF,
"connection", connection,
@@ -422,5 +550,9 @@ salut_avahi_self_new (SalutConnection *connection,
"jid", jid,
"email", email,
"published-name", published_name,
+#ifdef ENABLE_OLPC
+ "olpc-key", olpc_key,
+ "olpc-color", olpc_color,
+#endif
NULL);
}
diff --git a/src/avahi-self.h b/src/avahi-self.h
index b6785e86..4ebe942c 100644
--- a/src/avahi-self.h
+++ b/src/avahi-self.h
@@ -63,6 +63,7 @@ GType salut_avahi_self_get_type (void);
SalutAvahiSelf * salut_avahi_self_new (SalutConnection *connection,
SalutAvahiDiscoveryClient *discovery_client, const gchar *nickname,
const gchar *first_name, const gchar *last_name, const gchar *jid,
- const gchar *email, const gchar *published_name);
+ const gchar *email, const gchar *published_name, const GArray *olpc_key,
+ const gchar *olpc_color);
#endif /* #ifndef __SALUT_AVAHI_SELF_H__*/
diff --git a/src/bonjour-discovery-client.c b/src/bonjour-discovery-client.c
index b6dfe1d6..66a69669 100644
--- a/src/bonjour-discovery-client.c
+++ b/src/bonjour-discovery-client.c
@@ -254,12 +254,14 @@ salut_bonjour_discovery_client_create_self (SalutDiscoveryClient *client,
const gchar *last_name,
const gchar *jid,
const gchar *email,
- const gchar *published_name)
+ const gchar *published_name,
+ const GArray *olpc_key,
+ const gchar *olpc_color)
{
SalutBonjourDiscoveryClient *self = SALUT_BONJOUR_DISCOVERY_CLIENT (client);
return SALUT_SELF (salut_bonjour_self_new (connection, self, nickname,
- first_name, last_name, jid, email, published_name);
+ first_name, last_name, jid, email, published_name, olpc_key, olpc_color));
}
static const gchar *
diff --git a/src/bonjour-self.c b/src/bonjour-self.c
index 08d22a71..330bcae4 100644
--- a/src/bonjour-self.c
+++ b/src/bonjour-self.c
@@ -30,6 +30,10 @@
#include "sha1/sha1-util.h"
+#ifdef ENABLE_OLPC
+#define KEY_SEGMENT_SIZE 200
+#endif
+
#define RETURN_FALSE_IF_FAIL(error_type) \
if (error_type != kDNSServiceErr_NoError) return FALSE;
@@ -563,7 +567,9 @@ salut_bonjour_self_new (SalutConnection *connection,
const gchar *last_name,
const gchar *jid,
const gchar *email,
- const gchar *published_name)
+ const gchar *published_name,
+ const GArray *olpc_key,
+ const gchar *olpc_color)
{
return g_object_new (SALUT_TYPE_BONJOUR_SELF,
"connection", connection,
@@ -574,5 +580,9 @@ salut_bonjour_self_new (SalutConnection *connection,
"jid", jid,
"email", email,
"published-name", published_name,
+#ifdef ENABLE_OLPC
+ "olpc-key", olpc_key,
+ "olpc-color", olpc_color,
+#endif
NULL);
}
diff --git a/src/bonjour-self.h b/src/bonjour-self.h
index 56b03b60..31010366 100644
--- a/src/bonjour-self.h
+++ b/src/bonjour-self.h
@@ -63,6 +63,7 @@ GType salut_bonjour_self_get_type (void);
SalutBonjourSelf * salut_bonjour_self_new (SalutConnection *connection,
SalutBonjourDiscoveryClient *discovery_client, const gchar *nickname,
const gchar *first_name, const gchar *last_name, const gchar *jid,
- const gchar *email, const gchar *published_name);
+ const gchar *email, const gchar *published_name, const GArray *olpc_key,
+ const gchar *olpc_color);
#endif /* #ifndef __SALUT_BONJOUR_SELF_H__*/
diff --git a/src/capability-set.c b/src/capability-set.c
index ffdb0f36..f8632691 100644
--- a/src/capability-set.c
+++ b/src/capability-set.c
@@ -38,6 +38,7 @@ struct _Feature
enum {
FEATURE_FIXED,
FEATURE_OPTIONAL,
+ FEATURE_OLPC
} feature_type;
gchar *ns;
};
@@ -69,6 +70,11 @@ static const Feature self_advertised_features[] =
{ FEATURE_OPTIONAL, NS_JINGLE_RTP_AUDIO },
{ FEATURE_OPTIONAL, NS_JINGLE_RTP_VIDEO },
+ { FEATURE_OLPC, NS_OLPC_BUDDY_PROPS "+notify" },
+ { FEATURE_OLPC, NS_OLPC_ACTIVITIES "+notify" },
+ { FEATURE_OLPC, NS_OLPC_CURRENT_ACTIVITY "+notify" },
+ { FEATURE_OLPC, NS_OLPC_ACTIVITY_PROPS "+notify" },
+
{ FEATURE_OPTIONAL, NS_GEOLOC "+notify" },
{ 0, NULL }
@@ -91,6 +97,7 @@ static GabbleCapabilitySet *any_jingle_av_caps = NULL;
static GabbleCapabilitySet *any_transport_caps = NULL;
static GabbleCapabilitySet *fixed_caps = NULL;
static GabbleCapabilitySet *geoloc_caps = NULL;
+static GabbleCapabilitySet *olpc_caps = NULL;
const GabbleCapabilitySet *
gabble_capabilities_get_legacy (void)
@@ -164,6 +171,12 @@ gabble_capabilities_get_geoloc_notify (void)
return geoloc_caps;
}
+const GabbleCapabilitySet *
+gabble_capabilities_get_olpc_notify (void)
+{
+ return olpc_caps;
+}
+
static gboolean
omits_content_creators (WockyNode *identity)
{
@@ -279,6 +292,14 @@ gabble_capabilities_init (gpointer conn)
geoloc_caps = gabble_capability_set_new ();
gabble_capability_set_add (geoloc_caps, NS_GEOLOC "+notify");
+
+ olpc_caps = gabble_capability_set_new ();
+
+ for (feat = self_advertised_features; feat->ns != NULL; feat++)
+ {
+ if (feat->feature_type == FEATURE_OLPC)
+ gabble_capability_set_add (olpc_caps, feat->ns);
+ }
}
g_assert (feature_handles != NULL);
@@ -305,6 +326,7 @@ gabble_capabilities_finalize (gpointer conn)
gabble_capability_set_free (any_transport_caps);
gabble_capability_set_free (fixed_caps);
gabble_capability_set_free (geoloc_caps);
+ gabble_capability_set_free (olpc_caps);
legacy_caps = NULL;
share_v1_caps = NULL;
@@ -318,6 +340,7 @@ gabble_capabilities_finalize (gpointer conn)
any_transport_caps = NULL;
fixed_caps = NULL;
geoloc_caps = NULL;
+ olpc_caps = NULL;
tp_clear_object (&feature_handles);
}
diff --git a/src/connection-contact-info.c b/src/connection-contact-info.c
index c49963fe..cf1f0cb6 100644
--- a/src/connection-contact-info.c
+++ b/src/connection-contact-info.c
@@ -253,6 +253,54 @@ salut_conn_contact_info_changed (
}
static void
+salut_conn_contact_info_get_contact_info (
+ TpSvcConnectionInterfaceContactInfo *iface,
+ const GArray *contacts,
+ DBusGMethodInvocation *context)
+{
+ SalutConnection *self = SALUT_CONNECTION (iface);
+ TpBaseConnection *base = (TpBaseConnection *) self;
+ TpHandleRepoIface *contacts_repo =
+ tp_base_connection_get_handles (base, TP_HANDLE_TYPE_CONTACT);
+ SalutContactManager *contact_manager;
+ guint i;
+ GHashTable *ret;
+ GError *error = NULL;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (TP_BASE_CONNECTION (iface),
+ context);
+
+ if (!tp_handles_are_valid (contacts_repo, contacts, FALSE, &error))
+ {
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ return;
+ }
+
+ g_object_get (self, "contact-manager", &contact_manager, NULL);
+ ret = dbus_g_type_specialized_construct (TP_HASH_TYPE_CONTACT_INFO_MAP);
+
+ for (i = 0; i < contacts->len; i++)
+ {
+ TpHandle handle = g_array_index (contacts, TpHandle, i);
+ SalutContact *contact = salut_contact_manager_get_contact (
+ contact_manager, handle);
+
+ if (contact != NULL)
+ {
+ g_hash_table_insert (ret, GUINT_TO_POINTER (handle),
+ build_contact_info_for_contact (contact));
+ g_object_unref (contact);
+ }
+ }
+
+ tp_svc_connection_interface_contact_info_return_from_get_contact_info (
+ context, ret);
+ g_boxed_free (TP_HASH_TYPE_CONTACT_INFO_MAP, ret);
+ g_object_unref (contact_manager);
+}
+
+static void
salut_conn_contact_info_request_contact_info (
TpSvcConnectionInterfaceContactInfo *iface,
guint handle,
@@ -319,6 +367,7 @@ salut_conn_contact_info_iface_init (
#define IMPLEMENT(x) tp_svc_connection_interface_contact_info_implement_##x \
(klass, salut_conn_contact_info_##x)
+ IMPLEMENT (get_contact_info);
IMPLEMENT (request_contact_info);
IMPLEMENT (refresh_contact_info);
#undef IMPLEMENT
diff --git a/src/connection.c b/src/connection.c
index 2ab791a0..a0e19e4d 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -61,11 +61,31 @@
#include "plugin-loader.h"
+#ifdef ENABLE_OLPC
+#include "olpc-activity-manager.h"
+#endif
+
#include <extensions/extensions.h>
#define DEBUG_FLAG DEBUG_CONNECTION
#include "debug.h"
+#ifdef ENABLE_OLPC
+
+#define ACTIVITY_PAIR_TYPE \
+ (dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_UINT, \
+ G_TYPE_INVALID))
+
+static void
+salut_connection_olpc_buddy_info_iface_init (gpointer g_iface,
+ gpointer iface_data);
+
+static void
+salut_connection_olpc_activity_properties_iface_init (gpointer g_iface,
+ gpointer iface_data);
+
+#endif
+
static void
salut_connection_aliasing_service_iface_init (gpointer g_iface,
gpointer iface_data);
@@ -96,8 +116,8 @@ G_DEFINE_TYPE_WITH_CODE(SalutConnection,
tp_contacts_mixin_iface_init);
G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_LIST,
tp_base_contact_list_mixin_list_iface_init);
- G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_PRESENCE,
- tp_presence_mixin_iface_init);
+ G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
+ tp_presence_mixin_simple_presence_iface_init);
G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_AVATARS,
salut_connection_avatar_service_iface_init);
G_IMPLEMENT_INTERFACE
@@ -109,8 +129,19 @@ G_DEFINE_TYPE_WITH_CODE(SalutConnection,
salut_conn_future_iface_init);
G_IMPLEMENT_INTERFACE (SALUT_TYPE_PLUGIN_CONNECTION,
salut_plugin_connection_iface_init);
+#ifdef ENABLE_OLPC
+ G_IMPLEMENT_INTERFACE (SALUT_TYPE_SVC_OLPC_BUDDY_INFO,
+ salut_connection_olpc_buddy_info_iface_init);
+ G_IMPLEMENT_INTERFACE (SALUT_TYPE_SVC_OLPC_ACTIVITY_PROPERTIES,
+ salut_connection_olpc_activity_properties_iface_init);
+#endif
)
+#ifdef ENABLE_OLPC
+static gboolean uninvite_stanza_callback (WockyPorter *porter,
+ WockyStanza *stanza, gpointer user_data);
+#endif
+
/* properties */
enum {
PROP_NICKNAME = 1,
@@ -127,6 +158,9 @@ enum {
PROP_SELF,
PROP_XCM,
PROP_SI_BYTESTREAM_MANAGER,
+#ifdef ENABLE_OLPC
+ PROP_OLPC_ACTIVITY_MANAGER,
+#endif
PROP_BACKEND,
PROP_DNSSD_NAME,
LAST_PROP
@@ -143,6 +177,10 @@ struct _SalutConnectionPrivate
gchar *last_name;
gchar *jid;
gchar *email;
+#ifdef ENABLE_OLPC
+ gchar *olpc_color;
+ GArray *olpc_key;
+#endif
/* Discovery client for browsing and resolving */
SalutDiscoveryClient *discovery_client;
@@ -185,6 +223,11 @@ struct _SalutConnectionPrivate
/* gchar *interface → GList<DBusGMethodInvocation> */
GHashTable *pending_sidecars;
+#ifdef ENABLE_OLPC
+ SalutOlpcActivityManager *olpc_activity_manager;
+ guint uninvite_handler_id;
+#endif
+
/* timer used when trying to properly disconnect */
guint disconnect_timer;
@@ -213,6 +256,9 @@ salut_connection_create_handle_repos (TpBaseConnection *self,
TpHandleRepoIface *repos[TP_NUM_HANDLE_TYPES]);
static GPtrArray *
+salut_connection_create_channel_factories (TpBaseConnection *self);
+
+static GPtrArray *
salut_connection_create_channel_managers (TpBaseConnection *self);
static gchar *
@@ -261,21 +307,6 @@ static TpDBusPropertiesMixinPropImpl conn_avatars_properties[] = {
{ NULL }
};
-static TpDBusPropertiesMixinPropImpl conn_aliasing_properties[] = {
- { "AliasFlags", GUINT_TO_POINTER (0), NULL },
- { NULL }
-};
-
-static void
-conn_aliasing_properties_getter (GObject *object,
- GQuark interface,
- GQuark name,
- GValue *value,
- gpointer getter_data)
-{
- g_value_set_uint (value, GPOINTER_TO_UINT (getter_data));
-}
-
static void
salut_connection_init (SalutConnection *obj)
{
@@ -303,6 +334,10 @@ salut_connection_init (SalutConnection *obj)
priv->last_name = NULL;
priv->jid = NULL;
priv->email = NULL;
+#ifdef ENABLE_OLPC
+ priv->olpc_color = NULL;
+ priv->olpc_key = NULL;
+#endif
priv->discovery_client = NULL;
priv->self = NULL;
@@ -319,9 +354,6 @@ static void
sidecars_conn_status_changed_cb (SalutConnection *conn,
guint status, guint reason, gpointer unused);
-static void _contact_manager_contact_change_cb (SalutContactManager *mgr,
- SalutContact *contact, int changes, gpointer data);
-
static void
salut_connection_constructed (GObject *obj)
{
@@ -337,9 +369,8 @@ salut_connection_constructed (GObject *obj)
G_STRUCT_OFFSET (SalutConnection, contacts_mixin));
tp_base_connection_register_with_contacts_mixin (base);
- tp_presence_mixin_register_with_contacts_mixin (obj);
- tp_base_contact_list_mixin_register_with_contacts_mixin (
- TP_BASE_CONTACT_LIST (self->priv->contact_manager), base);
+ tp_presence_mixin_simple_presence_register_with_contacts_mixin (obj);
+ tp_base_contact_list_mixin_register_with_contacts_mixin (base);
tp_contacts_mixin_add_contact_attributes_iface (obj,
TP_IFACE_CONNECTION_INTERFACE_AVATARS,
@@ -421,6 +452,11 @@ salut_connection_get_property (GObject *object,
g_value_set_object (value, priv->si_bytestream_manager);
break;
#endif
+#ifdef ENABLE_OLPC
+ case PROP_OLPC_ACTIVITY_MANAGER:
+ g_value_set_object (value, priv->olpc_activity_manager);
+ break;
+#endif
case PROP_BACKEND:
g_value_set_gtype (value, priv->backend_type);
break;
@@ -547,15 +583,23 @@ make_presence_opt_args (SalutPresenceId presence, const gchar *message)
static GHashTable *
get_contact_statuses (GObject *obj,
- const GArray *handles)
+ const GArray *handles,
+ GError **error)
{
SalutConnection *self = SALUT_CONNECTION (obj);
SalutConnectionPrivate *priv = self->priv;
TpBaseConnection *base = (TpBaseConnection *) self;
TpHandle self_handle = tp_base_connection_get_self_handle (base);
+ TpHandleRepoIface *handle_repo = tp_base_connection_get_handles (base,
+ TP_HANDLE_TYPE_CONTACT);
GHashTable *ret;
guint i;
+ if (!tp_handles_are_valid (handle_repo, handles, FALSE, error))
+ {
+ return NULL;
+ }
+
ret = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL, (GDestroyNotify) tp_presence_status_free);
@@ -672,12 +716,16 @@ static const gchar *interfaces [] = {
TP_IFACE_CONNECTION_INTERFACE_ALIASING,
TP_IFACE_CONNECTION_INTERFACE_AVATARS,
TP_IFACE_CONNECTION_INTERFACE_CONTACTS,
- TP_IFACE_CONNECTION_INTERFACE_PRESENCE,
+ TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
TP_IFACE_CONNECTION_INTERFACE_REQUESTS,
TP_IFACE_CONNECTION_INTERFACE_CONTACT_CAPABILITIES,
TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO,
TP_IFACE_CONNECTION_INTERFACE_CONTACT_LIST,
SALUT_IFACE_CONNECTION_FUTURE,
+#ifdef ENABLE_OLPC
+ SALUT_IFACE_OLPC_BUDDY_INFO,
+ SALUT_IFACE_OLPC_ACTIVITY_PROPERTIES,
+#endif
NULL };
static GPtrArray *
@@ -714,11 +762,6 @@ salut_connection_class_init (SalutConnectionClass *salut_connection_class)
NULL,
conn_avatars_properties,
},
- { TP_IFACE_CONNECTION_INTERFACE_ALIASING,
- conn_aliasing_properties_getter,
- NULL,
- conn_aliasing_properties,
- },
{ NULL }
};
@@ -735,6 +778,8 @@ salut_connection_class_init (SalutConnectionClass *salut_connection_class)
tp_connection_class->create_handle_repos =
salut_connection_create_handle_repos;
+ tp_connection_class->create_channel_factories =
+ salut_connection_create_channel_factories;
tp_connection_class->create_channel_managers =
salut_connection_create_channel_managers;
tp_connection_class->get_unique_connection_name =
@@ -754,7 +799,7 @@ salut_connection_class_init (SalutConnectionClass *salut_connection_class)
is_presence_status_available, get_contact_statuses, set_own_status,
presence_statuses);
- tp_presence_mixin_init_dbus_properties (object_class);
+ tp_presence_mixin_simple_presence_init_dbus_properties (object_class);
tp_contacts_mixin_class_init (object_class,
G_STRUCT_OFFSET (SalutConnectionClass, contacts_mixin));
@@ -857,6 +902,17 @@ salut_connection_class_init (SalutConnectionClass *salut_connection_class)
g_object_class_install_property (object_class, PROP_SI_BYTESTREAM_MANAGER,
param_spec);
+#ifdef ENABLE_OLPC
+ param_spec = g_param_spec_object (
+ "olpc-activity-manager",
+ "SalutOlpcActivityManager object",
+ "The OLPC activity Manager associated with this Salut Connection",
+ SALUT_TYPE_OLPC_ACTIVITY_MANAGER,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_OLPC_ACTIVITY_MANAGER,
+ param_spec);
+#endif
+
param_spec = g_param_spec_gtype (
"backend-type",
"backend type",
@@ -921,6 +977,19 @@ salut_connection_dispose (GObject *object)
priv->self = NULL;
}
+#ifdef ENABLE_OLPC
+ {
+ wocky_porter_unregister_handler (self->porter, priv->uninvite_handler_id);
+ priv->uninvite_handler_id = 0;
+ }
+
+ if (priv->olpc_activity_manager != NULL)
+ {
+ g_object_unref (priv->olpc_activity_manager);
+ priv->olpc_activity_manager = NULL;
+ }
+#endif
+
if (self->session != NULL)
{
g_object_unref (self->session);
@@ -969,6 +1038,11 @@ salut_connection_finalize (GObject *object)
g_free (priv->last_name);
g_free (priv->email);
g_free (priv->jid);
+#ifdef ENABLE_OLPC
+ if (priv->olpc_key != NULL)
+ g_array_unref (priv->olpc_key);
+ g_free (priv->olpc_color);
+#endif
g_free (priv->dnssd_name);
tp_contacts_mixin_finalize (G_OBJECT(self));
@@ -1074,6 +1148,19 @@ _self_established_cb (SalutSelf *s, gpointer data)
}
#endif
+#ifdef ENABLE_OLPC
+ if (!salut_olpc_activity_manager_start (priv->olpc_activity_manager, &error))
+ {
+ DEBUG ("failed to start olpc activity manager: %s", error->message);
+ g_clear_error (&error);
+
+ tp_base_connection_change_status ( TP_BASE_CONNECTION (base),
+ TP_CONNECTION_STATUS_DISCONNECTED,
+ TP_CONNECTION_STATUS_REASON_NETWORK_ERROR);
+ return;
+ }
+#endif
+
tp_base_connection_change_status (base, TP_CONNECTION_STATUS_CONNECTED,
TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED);
}
@@ -1099,7 +1186,13 @@ discovery_client_running (SalutConnection *self)
priv->self = salut_discovery_client_create_self (priv->discovery_client,
self, priv->nickname, priv->first_name, priv->last_name, priv->jid,
- priv->email, priv->published_name);
+ priv->email, priv->published_name,
+#ifdef ENABLE_OLPC
+ priv->olpc_key, priv->olpc_color
+#else
+ NULL, NULL
+#endif
+ );
if (priv->pre_connect_caps != NULL)
{
@@ -1196,6 +1289,23 @@ _salut_connection_disconnect (SalutConnection *self)
/* Aliasing interface */
+/**
+ * salut_connection_get_alias_flags
+ *
+ * Implements D-Bus method GetAliasFlags
+ * on interface org.freedesktop.Telepathy.Connection.Interface.Aliasing
+ *
+ */
+static void
+salut_connection_get_alias_flags (TpSvcConnectionInterfaceAliasing *self,
+ DBusGMethodInvocation *context)
+{
+ /* Aliases are set by the contacts
+ * Actually we concat the first and lastname property */
+
+ tp_svc_connection_interface_aliasing_return_from_get_alias_flags (context,
+ 0);
+}
static const gchar *
salut_connection_get_alias (SalutConnection *self, TpHandle handle)
@@ -1234,7 +1344,7 @@ salut_connection_get_alias (SalutConnection *self, TpHandle handle)
* salut_connection_request_aliases
*
* Implements D-Bus method RequestAliases
- * on interface im.telepathy1.Connection.Interface.Aliasing
+ * on interface org.freedesktop.Telepathy.Connection.Interface.Aliasing
*
*/
static void
@@ -1276,6 +1386,40 @@ salut_connection_request_aliases (TpSvcConnectionInterfaceAliasing *iface,
}
static void
+salut_connection_get_aliases (TpSvcConnectionInterfaceAliasing *iface,
+ const GArray *contacts, DBusGMethodInvocation *context)
+{
+ SalutConnection *self = SALUT_CONNECTION (iface);
+ TpBaseConnection *base = TP_BASE_CONNECTION (self);
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base,
+ TP_HANDLE_TYPE_CONTACT);
+ guint i;
+ GError *error = NULL;
+ GHashTable *result = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL, NULL);
+
+ if (!tp_handles_are_valid (contact_repo, contacts, FALSE, &error))
+ {
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ return;
+ }
+
+ for (i = 0; i < contacts->len; i++)
+ {
+ TpHandle handle = g_array_index (contacts, TpHandle, i);
+
+ g_hash_table_insert (result, GUINT_TO_POINTER (handle),
+ (gchar *) salut_connection_get_alias (self, handle));
+ }
+
+ tp_svc_connection_interface_aliasing_return_from_get_aliases (context,
+ result);
+
+ g_hash_table_unref (result);
+}
+
+static void
salut_connection_aliasing_fill_contact_attributes (GObject *obj,
const GArray *contacts, GHashTable *attributes_hash)
{
@@ -1415,18 +1559,24 @@ static void
_contact_manager_contact_alias_changed (SalutConnection *self,
SalutContact *contact, TpHandle handle)
{
- GHashTable *aliases;
+ GPtrArray *aliases;
+ GValue entry = {0, };
- DEBUG("Emitting AliasesChanged");
+ g_value_init (&entry, TP_STRUCT_TYPE_ALIAS_PAIR);
+ g_value_take_boxed (&entry,
+ dbus_g_type_specialized_construct (TP_STRUCT_TYPE_ALIAS_PAIR));
+
+ dbus_g_type_struct_set (&entry,
+ 0, handle, 1, salut_contact_get_alias (contact), G_MAXUINT);
+ aliases = g_ptr_array_sized_new (1);
+ g_ptr_array_add (aliases, g_value_get_boxed (&entry));
- aliases = g_hash_table_new (NULL, NULL);
- g_hash_table_insert (aliases,
- GUINT_TO_POINTER (handle),
- (gchar *) salut_contact_get_alias (contact));
+ DEBUG("Emitting AliasesChanged");
tp_svc_connection_interface_aliasing_emit_aliases_changed (self, aliases);
- g_hash_table_unref (aliases);
+ g_value_unset (&entry);
+ g_ptr_array_unref (aliases);
}
static void
@@ -1438,7 +1588,9 @@ salut_connection_aliasing_service_iface_init (gpointer g_iface,
#define IMPLEMENT(x) tp_svc_connection_interface_aliasing_implement_##x \
(klass, salut_connection_##x)
+ IMPLEMENT (get_alias_flags);
IMPLEMENT (request_aliases);
+ IMPLEMENT (get_aliases);
IMPLEMENT (set_aliases);
#undef IMPLEMENT
}
@@ -1501,6 +1653,62 @@ salut_connection_set_avatar (TpSvcConnectionInterfaceAvatars *iface,
static void
+salut_connection_get_avatar_tokens (TpSvcConnectionInterfaceAvatars *iface,
+ const GArray *contacts, DBusGMethodInvocation *context)
+{
+ guint i;
+ gchar **ret;
+ GError *err = NULL;
+ SalutConnection *self = SALUT_CONNECTION (iface);
+ SalutConnectionPrivate *priv = self->priv;
+ TpBaseConnection *base = TP_BASE_CONNECTION (self);
+ TpHandle self_handle = tp_base_connection_get_self_handle (base);
+ TpHandleRepoIface *handle_repo;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+
+ handle_repo = tp_base_connection_get_handles (base,
+ TP_HANDLE_TYPE_CONTACT);
+
+ if (!tp_handles_are_valid (handle_repo, contacts, FALSE, &err))
+ {
+ dbus_g_method_return_error (context, err);
+ g_error_free (err);
+ return;
+ }
+
+ ret = g_new0(gchar *, contacts->len + 1);
+
+ for (i = 0; i < contacts->len ; i++)
+ {
+ TpHandle handle = g_array_index (contacts, TpHandle, i);
+ if (self_handle == handle)
+ {
+ ret[i] = priv->self->avatar_token;
+ }
+ else
+ {
+ SalutContact *contact;
+
+ contact = salut_contact_manager_get_contact (priv->contact_manager,
+ handle);
+ if (contact != NULL)
+ {
+ ret[i] = contact->avatar_token;
+ g_object_unref (contact);
+ }
+ }
+ if (ret[i] == NULL)
+ ret[i] = "";
+ }
+
+ tp_svc_connection_interface_avatars_return_from_get_avatar_tokens (context,
+ (const gchar **)ret);
+
+ g_free (ret);
+}
+
+static void
salut_connection_get_known_avatar_tokens (
TpSvcConnectionInterfaceAvatars *iface, const GArray *contacts,
DBusGMethodInvocation *context)
@@ -1694,6 +1902,78 @@ salut_connection_request_avatars (
}
static void
+_request_avatar_cb (SalutContact *contact, guint8 *avatar, gsize size,
+ gpointer user_data)
+{
+ DBusGMethodInvocation *context = (DBusGMethodInvocation *) user_data;
+
+ GError *err = NULL;
+ GArray *arr;
+
+ if (size == 0)
+ {
+ err = g_error_new (TP_ERROR, TP_ERROR_NOT_AVAILABLE,
+ "Unable to get avatar");
+ dbus_g_method_return_error (context, err);
+ g_error_free (err);
+ return;
+ }
+
+ arr = g_array_sized_new (FALSE, FALSE, sizeof (guint8), size);
+ arr = g_array_append_vals (arr, avatar, size);
+ tp_svc_connection_interface_avatars_return_from_request_avatar (context,
+ arr, "");
+ g_array_unref (arr);
+}
+
+static void
+salut_connection_request_avatar (TpSvcConnectionInterfaceAvatars *iface,
+ guint handle, DBusGMethodInvocation *context)
+{
+ SalutConnection *self = SALUT_CONNECTION (iface);
+ SalutConnectionPrivate *priv = self->priv;
+ TpBaseConnection *base = TP_BASE_CONNECTION (self);
+ TpHandle self_handle = tp_base_connection_get_self_handle (base);
+ SalutContact *contact;
+ GError *err = NULL;
+ TpHandleRepoIface *handle_repo;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+
+ handle_repo = tp_base_connection_get_handles (base,
+ TP_HANDLE_TYPE_CONTACT);
+
+ if (!tp_handle_is_valid (handle_repo, handle, &err))
+ {
+ dbus_g_method_return_error (context, err);
+ g_error_free (err);
+ return;
+ }
+
+ if (handle == self_handle)
+ {
+ _request_avatar_cb (NULL, priv->self->avatar, priv->self->avatar_size,
+ context);
+ return;
+ }
+
+ contact = salut_contact_manager_get_contact (priv->contact_manager, handle);
+ if (contact == NULL || contact->avatar_token == NULL)
+ {
+ err = g_error_new (TP_ERROR, TP_ERROR_NOT_AVAILABLE, "No known avatar");
+ dbus_g_method_return_error (context, err);
+ g_error_free (err);
+ if (contact != NULL)
+ {
+ g_object_unref (contact);
+ }
+ return;
+ }
+ salut_contact_get_avatar (contact, _request_avatar_cb, context);
+ g_object_unref (contact);
+}
+
+static void
conn_avatars_properties_getter (GObject *object,
GQuark interface,
GQuark name,
@@ -1714,6 +1994,15 @@ conn_avatars_properties_getter (GObject *object,
}
static void
+salut_connection_get_avatar_requirements (
+ TpSvcConnectionInterfaceAvatars *iface, DBusGMethodInvocation *context)
+{
+ tp_svc_connection_interface_avatars_return_from_get_avatar_requirements (
+ context, mimetypes, AVATAR_MIN_PX, AVATAR_MIN_PX, AVATAR_MAX_PX,
+ AVATAR_MAX_PX, AVATAR_MAX_BYTES);
+}
+
+static void
salut_connection_avatar_service_iface_init (gpointer g_iface,
gpointer iface_data)
{
@@ -1722,7 +2011,10 @@ salut_connection_avatar_service_iface_init (gpointer g_iface,
#define IMPLEMENT(x) tp_svc_connection_interface_avatars_implement_##x \
(klass, salut_connection_##x)
+ IMPLEMENT (get_avatar_requirements);
+ IMPLEMENT (get_avatar_tokens);
IMPLEMENT (get_known_avatar_tokens);
+ IMPLEMENT (request_avatar);
IMPLEMENT (request_avatars);
IMPLEMENT (set_avatar);
IMPLEMENT (clear_avatar);
@@ -1746,6 +2038,56 @@ salut_free_enhanced_contact_capabilities (GPtrArray *caps)
g_ptr_array_unref (caps);
}
+/**
+ * salut_connection_get_contact_capabilities
+ *
+ * Implements D-Bus method GetContactCapabilities
+ * on interface
+ * org.freedesktop.Telepathy.Connection.Interface.ContactCapabilities
+ */
+static void
+salut_connection_get_contact_capabilities (
+ TpSvcConnectionInterfaceContactCapabilities *iface,
+ const GArray *handles,
+ DBusGMethodInvocation *context)
+{
+ SalutConnection *self = SALUT_CONNECTION (iface);
+ TpBaseConnection *base = (TpBaseConnection *) self;
+ TpHandleRepoIface *contact_handles = tp_base_connection_get_handles (base,
+ TP_HANDLE_TYPE_CONTACT);
+ guint i;
+ GHashTable *ret;
+ GError *error = NULL;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+
+ if (!tp_handles_are_valid (contact_handles, handles, FALSE, &error))
+ {
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ return;
+ }
+
+ ret = g_hash_table_new_full (NULL, NULL, NULL,
+ (GDestroyNotify) salut_free_enhanced_contact_capabilities);
+
+ for (i = 0; i < handles->len; i++)
+ {
+ GPtrArray *arr = g_ptr_array_new ();
+ TpHandle handle = g_array_index (handles, TpHandle, i);
+
+ salut_connection_get_handle_contact_capabilities (self, handle, arr);
+
+ g_hash_table_insert (ret, GINT_TO_POINTER (handle), arr);
+ }
+
+ tp_svc_connection_interface_contact_capabilities_return_from_get_contact_capabilities
+ (context, ret);
+
+ g_hash_table_unref (ret);
+}
+
+
static void
_emit_contact_capabilities_changed (SalutConnection *conn,
TpHandle handle)
@@ -1827,7 +2169,7 @@ data_forms_equal (GPtrArray *one,
*
* Implements D-Bus method UpdateCapabilities
* on interface
- * im.telepathy1.Connection.Interface.ContactCapabilities
+ * org.freedesktop.Telepathy.Connection.Interface.ContactCapabilities
*/
static void
salut_connection_update_capabilities (
@@ -1959,10 +2301,1041 @@ salut_conn_contact_caps_iface_init (gpointer g_iface, gpointer iface_data)
#define IMPLEMENT(x) \
tp_svc_connection_interface_contact_capabilities_implement_##x (\
klass, salut_connection_##x)
+ IMPLEMENT(get_contact_capabilities);
IMPLEMENT(update_capabilities);
#undef IMPLEMENT
}
+
+#ifdef ENABLE_OLPC
+static GValue *
+new_gvalue (GType type)
+{
+ GValue *result = g_slice_new0 (GValue);
+ g_value_init (result, type);
+ return result;
+}
+
+static GHashTable *
+get_properties_hash (const GArray *key, const gchar *color, const gchar *jid,
+ const gchar *ip4, const gchar *ip6)
+{
+ GHashTable *properties;
+ GValue *gvalue;
+
+ properties = g_hash_table_new_full (g_str_hash, g_str_equal,
+ NULL, (GDestroyNotify) tp_g_value_slice_free);
+ if (key != NULL)
+ {
+ gvalue = new_gvalue (DBUS_TYPE_G_UCHAR_ARRAY);
+ g_value_set_boxed (gvalue, key);
+ g_hash_table_insert (properties, "key", gvalue);
+ }
+
+ if (color != NULL)
+ {
+ gvalue = new_gvalue (G_TYPE_STRING);
+ g_value_set_string (gvalue, color);
+ g_hash_table_insert (properties, "color", gvalue);
+ }
+
+ if (jid != NULL)
+ {
+ gvalue = new_gvalue (G_TYPE_STRING);
+ g_value_set_string (gvalue, jid);
+ g_hash_table_insert (properties, "jid", gvalue);
+ }
+
+ if (ip4 != NULL)
+ {
+ gvalue = new_gvalue (G_TYPE_STRING);
+ g_value_set_string (gvalue, ip4);
+ g_hash_table_insert (properties, "ip4-address", gvalue);
+ }
+
+ if (ip6 != NULL)
+ {
+ gvalue = new_gvalue (G_TYPE_STRING);
+ g_value_set_string (gvalue, ip6);
+ g_hash_table_insert (properties, "ip6-address", gvalue);
+ }
+
+ return properties;
+}
+
+static void
+emit_properties_changed (SalutConnection *connection,
+ TpHandle handle,
+ const GArray *key,
+ const gchar *color,
+ const gchar *jid,
+ const gchar *ip4,
+ const gchar *ip6)
+{
+ GHashTable *properties;
+ properties = get_properties_hash (key, color, jid, ip4, ip6);
+
+ salut_svc_olpc_buddy_info_emit_properties_changed (connection,
+ handle, properties);
+
+ g_hash_table_unref (properties);
+}
+
+static void
+append_activity (SalutOlpcActivity *activity,
+ gpointer user_data)
+{
+ GPtrArray *arr = user_data;
+ GType type = ACTIVITY_PAIR_TYPE;
+ GValue gvalue = {0};
+
+ g_value_init (&gvalue, type);
+ g_value_take_boxed (&gvalue,
+ dbus_g_type_specialized_construct (type));
+
+ dbus_g_type_struct_set (&gvalue,
+ 0, activity->id,
+ 1, activity->room,
+ G_MAXUINT);
+ g_ptr_array_add (arr, g_value_get_boxed (&gvalue));
+}
+
+static void
+free_olpc_activities (GPtrArray *arr)
+{
+ GType type = ACTIVITY_PAIR_TYPE;
+ guint i;
+
+ for (i = 0; i < arr->len; i++)
+ g_boxed_free (type, arr->pdata[i]);
+
+ g_ptr_array_unref (arr);
+}
+
+static void
+_contact_manager_contact_olpc_activities_changed (SalutConnection *self,
+ SalutContact *contact,
+ TpHandle handle)
+{
+ GPtrArray *activities = g_ptr_array_new ();
+
+ DEBUG ("called for %u", handle);
+
+ salut_contact_foreach_olpc_activity (contact, append_activity, activities);
+ salut_svc_olpc_buddy_info_emit_activities_changed (self,
+ handle, activities);
+ free_olpc_activities (activities);
+}
+
+static void
+_contact_manager_contact_olpc_properties_changed (SalutConnection *self,
+ SalutContact *contact,
+ TpHandle handle)
+{
+ emit_properties_changed (self, handle, contact->olpc_key,
+ contact->olpc_color, contact->jid, contact->olpc_ip4, contact->olpc_ip6);
+}
+
+static gboolean
+check_handle (TpHandleRepoIface *handle_repo,
+ TpHandle handle,
+ DBusGMethodInvocation *context)
+{
+ GError *error = NULL;
+
+ if (!tp_handle_is_valid (handle_repo, handle, &error))
+ {
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+check_contact (TpBaseConnection *base,
+ TpHandle contact,
+ DBusGMethodInvocation *context)
+{
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
+ base, TP_HANDLE_TYPE_CONTACT);
+
+ return check_handle (contact_repo, contact, context);
+}
+
+static gboolean
+check_room (TpBaseConnection *base,
+ TpHandle contact,
+ DBusGMethodInvocation *context)
+{
+ TpHandleRepoIface *room_repo = tp_base_connection_get_handles (
+ base, TP_HANDLE_TYPE_ROOM);
+
+ return check_handle (room_repo, contact, context);
+}
+
+static void
+salut_connection_olpc_get_properties (SalutSvcOLPCBuddyInfo *iface,
+ TpHandle handle,
+ DBusGMethodInvocation *context)
+{
+ SalutConnection *self = SALUT_CONNECTION (iface);
+ SalutConnectionPrivate *priv = self->priv;
+ TpBaseConnection *base = TP_BASE_CONNECTION (self);
+ TpHandle self_handle = tp_base_connection_get_self_handle (base);
+ GHashTable *properties = NULL;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+
+ if (!check_contact (base, handle, context))
+ return;
+
+ if (handle == self_handle)
+ {
+ properties = get_properties_hash (priv->self->olpc_key,
+ priv->self->olpc_color, priv->self->jid, NULL, NULL);
+ }
+ else
+ {
+ SalutContact *contact;
+ contact = salut_contact_manager_get_contact (priv->contact_manager,
+ handle);
+ if (contact == NULL)
+ {
+ /* FIXME: should this be InvalidHandle? */
+ GError e = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Unknown contact" };
+ dbus_g_method_return_error (context, &e);
+ return;
+ }
+ properties = get_properties_hash (contact->olpc_key, contact->olpc_color,
+ contact->jid, contact->olpc_ip4, contact->olpc_ip6);
+ g_object_unref (contact);
+ }
+
+ salut_svc_olpc_buddy_info_return_from_get_properties (context, properties);
+ g_hash_table_unref (properties);
+}
+
+
+static gboolean
+find_unknown_properties (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ gchar **valid_props = (gchar **) user_data;
+ int i;
+ for (i = 0; valid_props[i] != NULL; i++)
+ {
+ if (!tp_strdiff (key, valid_props[i]))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+salut_connection_olpc_set_properties (SalutSvcOLPCBuddyInfo *iface,
+ GHashTable *properties,
+ DBusGMethodInvocation *context)
+{
+ SalutConnection *self = SALUT_CONNECTION (iface);
+ SalutConnectionPrivate *priv = self->priv;
+
+ GError *error = NULL;
+ /* Only a few known properties, so handle it quite naively */
+ const gchar *known_properties[] = { "color", "key", "jid", "ip4-address",
+ "ip6-address", NULL };
+ const gchar *color = NULL;
+ const GArray *key = NULL;
+ const gchar *jid = NULL;
+ const GValue *val;
+
+ /* this function explicitly supports being called when DISCONNECTED
+ * or CONNECTING */
+
+ if (g_hash_table_find (properties, find_unknown_properties, known_properties)
+ != NULL)
+ {
+ error = g_error_new (TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "Unknown property given");
+ goto error;
+ }
+
+ val = (const GValue *) g_hash_table_lookup (properties, "color");
+ if (val != NULL)
+ {
+ if (G_VALUE_TYPE (val) != G_TYPE_STRING)
+ {
+ error = g_error_new (TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "Color value should be of type s");
+ goto error;
+ }
+ else
+ {
+ int len;
+ gboolean correct = TRUE;
+
+ color = g_value_get_string (val);
+
+ /* be very anal about the color format */
+ len = strlen (color);
+ if (len != 15)
+ {
+ correct = FALSE;
+ }
+ else
+ {
+ int i;
+ for (i = 0 ; i < len ; i++)
+ {
+ switch (i)
+ {
+ case 0:
+ case 8:
+ correct = (color[i] == '#');
+ break;
+ case 7:
+ correct = (color[i] == ',');
+ break;
+ default:
+ correct = isxdigit (color[i]);
+ break;
+ }
+ }
+ }
+
+ if (!correct)
+ {
+ error = g_error_new (TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "Color value has an incorrect format");
+ goto error;
+ }
+ }
+ }
+
+ if ((val = (const GValue *) g_hash_table_lookup (properties, "key")) != NULL)
+ {
+ if (G_VALUE_TYPE (val) != DBUS_TYPE_G_UCHAR_ARRAY)
+ {
+ error = g_error_new (TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "Key value should be of type ay");
+ goto error;
+ }
+ else
+ {
+ key = g_value_get_boxed (val);
+ if (key->len == 0)
+ {
+ error = g_error_new (TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "Key value of length 0 not allowed");
+ goto error;
+ }
+ }
+ }
+
+ val = g_hash_table_lookup (properties, "jid");
+ if (val != NULL)
+ {
+ if (G_VALUE_TYPE (val) != G_TYPE_STRING)
+ {
+ error = g_error_new (TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "JID value should be of type s");
+ goto error;
+ }
+
+ jid = g_value_get_string (val);
+
+ if (strchr (jid, '@') == NULL)
+ {
+ error = g_error_new (TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "JID value has an incorrect format");
+ goto error;
+ }
+ }
+
+ if (priv->self)
+ {
+ if (!salut_self_set_olpc_properties (priv->self, key, color, jid,
+ &error))
+ goto error;
+ }
+ else
+ {
+ /* queue it up for later */
+ if (key)
+ {
+ if (priv->olpc_key == NULL)
+ {
+ priv->olpc_key = g_array_sized_new (FALSE, FALSE, sizeof (guint8),
+ key->len);
+ }
+ else
+ {
+ g_array_remove_range (priv->olpc_key, 0, priv->olpc_key->len);
+ }
+ g_array_append_vals (priv->olpc_key, key->data, key->len);
+ }
+ if (color)
+ {
+ g_free (priv->olpc_color);
+ priv->olpc_color = g_strdup (color);
+ }
+ if (jid)
+ {
+ g_free (priv->jid);
+ priv->jid = g_strdup (jid);
+ }
+ }
+
+ salut_svc_olpc_buddy_info_return_from_set_properties (context);
+ return;
+
+error:
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+}
+
+static void
+salut_connection_olpc_get_current_activity (SalutSvcOLPCBuddyInfo *iface,
+ TpHandle handle,
+ DBusGMethodInvocation *context)
+{
+ SalutConnection *self = SALUT_CONNECTION (iface);
+ TpBaseConnection *base = (TpBaseConnection *) self;
+ TpHandle self_handle = tp_base_connection_get_self_handle (base);
+ SalutConnectionPrivate *priv = self->priv;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+
+ DEBUG ("called for %u", handle);
+
+ if (!check_contact (base, handle, context))
+ return;
+
+ if (handle == self_handle)
+ {
+ DEBUG ("Returning my own cur.act.: %s -> %u",
+ priv->self->olpc_cur_act ? priv->self->olpc_cur_act : "",
+ priv->self->olpc_cur_act_room);
+ salut_svc_olpc_buddy_info_return_from_get_current_activity (context,
+ priv->self->olpc_cur_act ? priv->self->olpc_cur_act : "",
+ priv->self->olpc_cur_act_room);
+ }
+ else
+ {
+ SalutContact *contact = salut_contact_manager_get_contact
+ (priv->contact_manager, handle);
+
+ if (contact == NULL)
+ {
+ /* FIXME: should this be InvalidHandle? */
+ GError e = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Unknown contact" };
+ DEBUG ("Returning error: unknown contact");
+ dbus_g_method_return_error (context, &e);
+ return;
+ }
+
+ DEBUG ("Returning buddy %u cur.act.: %s -> %u", handle,
+ contact->olpc_cur_act ? contact->olpc_cur_act : "",
+ contact->olpc_cur_act_room);
+ salut_svc_olpc_buddy_info_return_from_get_current_activity (context,
+ contact->olpc_cur_act ? contact->olpc_cur_act : "",
+ contact->olpc_cur_act_room);
+ g_object_unref (contact);
+ }
+}
+
+static void
+salut_connection_olpc_set_current_activity (SalutSvcOLPCBuddyInfo *iface,
+ const gchar *activity_id,
+ TpHandle room_handle,
+ DBusGMethodInvocation *context)
+{
+ SalutConnection *self = SALUT_CONNECTION (iface);
+ SalutConnectionPrivate *priv = self->priv;
+ TpBaseConnection *base = (TpBaseConnection *) self;
+ GError *error = NULL;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+
+ DEBUG ("called");
+
+ if (activity_id[0] == '\0')
+ {
+ if (room_handle != 0)
+ {
+ GError e = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "If activity ID is empty, room handle must be 0" };
+
+ dbus_g_method_return_error (context, &e);
+ return;
+ }
+ }
+ else
+ {
+ if (!check_room (base, room_handle, context))
+ return;
+ }
+
+ if (!salut_self_set_olpc_current_activity (priv->self, activity_id,
+ room_handle, &error))
+ {
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ return;
+ }
+
+ salut_svc_olpc_buddy_info_return_from_set_current_activity (context);
+}
+
+static void
+salut_connection_olpc_get_activities (SalutSvcOLPCBuddyInfo *iface,
+ TpHandle handle,
+ DBusGMethodInvocation *context)
+{
+ SalutConnection *self = SALUT_CONNECTION (iface);
+ SalutConnectionPrivate *priv = self->priv;
+ TpBaseConnection *base = (TpBaseConnection *) self;
+ TpHandle self_handle = tp_base_connection_get_self_handle (base);
+ GPtrArray *arr;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+
+ DEBUG ("called for %u", handle);
+
+ if (!check_contact (base, handle, context))
+ return;
+
+ if (handle == self_handle)
+ {
+ arr = g_ptr_array_new ();
+ salut_self_foreach_olpc_activity (priv->self, append_activity, arr);
+ }
+ else
+ {
+ SalutContact *contact = salut_contact_manager_get_contact
+ (priv->contact_manager, handle);
+
+ if (contact == NULL)
+ {
+ /* FIXME: should this be InvalidHandle? */
+ GError e = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Unknown contact" };
+ DEBUG ("Returning error: unknown contact");
+ dbus_g_method_return_error (context, &e);
+ return;
+ }
+
+ arr = g_ptr_array_new ();
+ salut_contact_foreach_olpc_activity (contact, append_activity, arr);
+ g_object_unref (contact);
+ }
+
+ salut_svc_olpc_buddy_info_return_from_get_activities (context, arr);
+ free_olpc_activities (arr);
+}
+
+static void
+salut_connection_olpc_set_activities (SalutSvcOLPCBuddyInfo *iface,
+ const GPtrArray *activities,
+ DBusGMethodInvocation *context)
+{
+ SalutConnection *self = SALUT_CONNECTION (iface);
+ SalutConnectionPrivate *priv = self->priv;
+ TpBaseConnection *base = (TpBaseConnection *) self;
+ TpHandleRepoIface *room_repo = tp_base_connection_get_handles (base,
+ TP_HANDLE_TYPE_ROOM);
+ GHashTable *room_to_act_id = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal, NULL, (GDestroyNotify) g_free);
+ GError *error = NULL;
+ guint i;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+
+ for (i = 0; i < activities->len; i++)
+ {
+ GValue pair = {0};
+ gchar *activity;
+ guint room_handle;
+
+ g_value_init (&pair, ACTIVITY_PAIR_TYPE);
+ g_value_set_static_boxed (&pair, g_ptr_array_index (activities, i));
+ dbus_g_type_struct_get (&pair,
+ 0, &activity,
+ 1, &room_handle,
+ G_MAXUINT);
+
+ if (activity[0] == '\0')
+ {
+ GError e = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "Invalid empty activity ID" };
+
+ DEBUG ("%s", e.message);
+ dbus_g_method_return_error (context, &e);
+ g_free (activity);
+ goto finally;
+ }
+
+ if (!tp_handle_is_valid (room_repo, room_handle, &error))
+ {
+ DEBUG ("Invalid room handle %u: %s", room_handle, error->message);
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ g_free (activity);
+ goto finally;
+ }
+
+ g_hash_table_insert (room_to_act_id, GUINT_TO_POINTER (room_handle),
+ activity);
+ }
+
+ if (!salut_self_set_olpc_activities (priv->self, room_to_act_id, &error))
+ {
+ dbus_g_method_return_error (context, error);
+ }
+ else
+ {
+ salut_svc_olpc_buddy_info_return_from_set_activities (context);
+ }
+
+finally:
+ g_hash_table_unref (room_to_act_id);
+}
+
+static void
+salut_connection_olpc_add_activity (SalutSvcOLPCBuddyInfo *iface,
+ const gchar *id,
+ TpHandle handle,
+ DBusGMethodInvocation *context)
+{
+ SalutConnection *self = SALUT_CONNECTION (iface);
+ SalutConnectionPrivate *priv = self->priv;
+ TpBaseConnection *base = (TpBaseConnection *) self;
+ GError *error = NULL;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+
+ if (!salut_self_add_olpc_activity (priv->self, id, handle, &error))
+ {
+ dbus_g_method_return_error (context, error);
+ }
+ else
+ {
+ salut_svc_olpc_buddy_info_return_from_set_activities (context);
+ }
+}
+
+static void
+salut_connection_olpc_buddy_info_iface_init (gpointer g_iface,
+ gpointer iface_data)
+{
+ SalutSvcOLPCBuddyInfoClass *klass =
+ (SalutSvcOLPCBuddyInfoClass *) g_iface;
+#define IMPLEMENT(x) salut_svc_olpc_buddy_info_implement_##x (klass, \
+ salut_connection_olpc_##x)
+ IMPLEMENT(set_properties);
+ IMPLEMENT(get_properties);
+ IMPLEMENT(set_activities);
+ IMPLEMENT(add_activity);
+ IMPLEMENT(get_activities);
+ IMPLEMENT(set_current_activity);
+ IMPLEMENT(get_current_activity);
+#undef IMPLEMENT
+}
+
+static void
+salut_connection_act_get_properties (SalutSvcOLPCActivityProperties *iface,
+ TpHandle handle,
+ DBusGMethodInvocation *context)
+{
+ SalutConnection *self = SALUT_CONNECTION (iface);
+ SalutConnectionPrivate *priv = self->priv;
+ TpBaseConnection *base = (TpBaseConnection *) self;
+ TpHandleRepoIface *room_repo = tp_base_connection_get_handles (base,
+ TP_HANDLE_TYPE_ROOM);
+ GHashTable *properties = NULL;
+ GError *error = NULL;
+ SalutOlpcActivity *activity;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+
+ if (!tp_handle_is_valid (room_repo, handle, &error))
+ goto error;
+
+ activity = salut_olpc_activity_manager_get_activity_by_room (
+ priv->olpc_activity_manager, handle);
+ if (activity == NULL)
+ {
+ g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
+ "Activity unknown: %u", handle);
+ goto error;
+ }
+
+ properties = salut_olpc_activity_create_properties_table (activity);
+
+ salut_svc_olpc_buddy_info_return_from_get_properties (context, properties);
+ g_hash_table_unref (properties);
+
+ return;
+
+error:
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+}
+
+static gboolean
+check_color (const gchar *color)
+{
+ int len, i;
+
+ /* be very anal about the color format */
+ len = strlen (color);
+ if (len != 15)
+ return FALSE;
+
+ for (i = 0 ; i < len ; i++)
+ {
+ switch (i)
+ {
+ case 0:
+ case 8:
+ if (color[i] != '#')
+ return FALSE;
+ break;
+ case 7:
+ if (color[i] != ',')
+ return FALSE;
+ break;
+ default:
+ if (!isxdigit (color[i]))
+ return FALSE;
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+/* returned strings are only valid as long as the hash table isn't modified */
+static gboolean
+extract_properties_from_hash (GHashTable *properties,
+ const gchar **id,
+ const gchar **color,
+ const gchar **name,
+ const gchar **type,
+ const gchar **tags,
+ gboolean *is_private,
+ GError **error)
+{
+ GValue *activity_id_val, *color_val, *activity_name_val, *activity_type_val,
+ *tags_val, *is_private_val;
+
+ /* activity ID */
+ activity_id_val = g_hash_table_lookup (properties, "id");
+ if (activity_id_val != NULL)
+ {
+ if (G_VALUE_TYPE (activity_id_val) != G_TYPE_STRING)
+ {
+ g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "Activity ID value should be of type s");
+ return FALSE;
+ }
+
+ if (id != NULL)
+ *id = g_value_get_string (activity_id_val);
+ }
+
+ /* color */
+ color_val = g_hash_table_lookup (properties, "color");
+ if (color_val != NULL)
+ {
+ if (G_VALUE_TYPE (color_val) != G_TYPE_STRING)
+ {
+ g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "Color value should be of type s");
+ return FALSE;
+ }
+
+ if (color != NULL)
+ {
+ *color = g_value_get_string (color_val);
+
+ if (!check_color (*color))
+ {
+ g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "Color value has an incorrect format");
+ return FALSE;
+ }
+ }
+ }
+
+ /* name */
+ activity_name_val = g_hash_table_lookup (properties, "name");
+ if (activity_name_val != NULL)
+ {
+ if (G_VALUE_TYPE (activity_name_val) != G_TYPE_STRING)
+ {
+ g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "name value should be of type s");
+ return FALSE;
+ }
+
+ if (name != NULL)
+ *name = g_value_get_string (activity_name_val);
+ }
+
+ /* type */
+ activity_type_val = g_hash_table_lookup (properties, "type");
+ if (activity_type_val != NULL)
+ {
+ if (G_VALUE_TYPE (activity_type_val) != G_TYPE_STRING)
+ {
+ g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "type value should be of type s");
+ return FALSE;
+ }
+
+ if (type != NULL)
+ {
+ *type = g_value_get_string (activity_type_val);
+
+ if (*type[0] == '\0')
+ {
+ g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "type value must be non-empty");
+ return FALSE;
+ }
+ }
+ }
+
+ /* tags */
+ tags_val = g_hash_table_lookup (properties, "tags");
+ if (tags_val != NULL)
+ {
+ if (G_VALUE_TYPE (activity_type_val) != G_TYPE_STRING)
+ {
+ g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "tags value should be of type s");
+ return FALSE;
+ }
+
+ if (type != NULL)
+ *tags = g_value_get_string (tags_val);
+ }
+
+ /* is_private */
+ is_private_val = g_hash_table_lookup (properties, "private");
+ if (is_private_val != NULL)
+ {
+ if (G_VALUE_TYPE (is_private_val) != G_TYPE_BOOLEAN)
+ {
+ g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "private value should be of type b");
+ return FALSE;
+ }
+
+ if (is_private != NULL)
+ *is_private = g_value_get_boolean (is_private_val);
+ }
+
+ return TRUE;
+}
+
+static void
+salut_connection_act_set_properties (SalutSvcOLPCActivityProperties *iface,
+ TpHandle handle,
+ GHashTable *properties,
+ DBusGMethodInvocation *context)
+{
+ SalutConnection *self = SALUT_CONNECTION (iface);
+ SalutConnectionPrivate *priv = self->priv;
+ TpBaseConnection *base = (TpBaseConnection *) self;
+ GError *error = NULL;
+ const gchar *known_properties[] = { "color", "name", "type", "private",
+ "tags", NULL };
+ const gchar *color = NULL, *name = NULL, *type = NULL, *tags = NULL;
+ gboolean is_private = TRUE;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+
+ if (!check_room (base, handle, context))
+ return;
+
+ if (g_hash_table_find (properties, find_unknown_properties, known_properties)
+ != NULL)
+ {
+ error = g_error_new (TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "Unknown property given");
+ goto error;
+ }
+
+ if (!extract_properties_from_hash (properties, NULL, &color, &name, &type,
+ &tags, &is_private, &error))
+ goto error;
+
+ if (!salut_self_set_olpc_activity_properties (priv->self, handle, color,
+ name, type, tags, is_private, &error))
+ goto error;
+
+ salut_svc_olpc_activity_properties_return_from_set_properties (context);
+ return;
+
+error:
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+}
+
+typedef struct
+{
+ SalutContact *inviter;
+ SalutOlpcActivity *activity;
+} muc_ready_ctx;
+
+static muc_ready_ctx *
+muc_ready_ctx_new (SalutContact *inviter,
+ SalutOlpcActivity *activity)
+{
+ muc_ready_ctx *ctx = g_slice_new (muc_ready_ctx);
+ ctx->inviter = inviter;
+ g_object_ref (inviter);
+ ctx->activity = activity;
+ g_object_ref (activity);
+ return ctx;
+}
+
+static void
+muc_ready_ctx_free (muc_ready_ctx *ctx)
+{
+ if (ctx == NULL)
+ return;
+
+ g_object_unref (ctx->inviter);
+ g_object_unref (ctx->activity);
+ g_slice_free (muc_ready_ctx, ctx);
+}
+
+static void
+muc_ready_cb (SalutMucChannel *muc,
+ muc_ready_ctx *ctx)
+{
+ /* We joined the muc so have to forget about invites */
+ salut_contact_left_activity (ctx->inviter, ctx->activity);
+
+ DEBUG ("forget invite received from %s", ctx->inviter->name);
+ g_signal_handlers_disconnect_matched (muc, G_SIGNAL_MATCH_DATA, 0, 0, NULL,
+ NULL, ctx);
+ muc_ready_ctx_free (ctx);
+}
+
+static void
+muc_closed_cb (SalutMucChannel *muc,
+ muc_ready_ctx *ctx)
+{
+ /* FIXME: should we call left_private_activity here too ? */
+
+ g_signal_handlers_disconnect_matched (muc, G_SIGNAL_MATCH_DATA, 0, 0, NULL,
+ NULL, ctx);
+ muc_ready_ctx_free (ctx);
+}
+
+void
+salut_connection_olpc_observe_invitation (SalutConnection *self,
+ TpHandle room,
+ TpHandle inviter_handle,
+ WockyNode *invite_node)
+{
+ SalutConnectionPrivate *priv = self->priv;
+ WockyNode *props_node;
+ GHashTable *properties;
+ const gchar *activity_id, *color = NULL, *activity_name = NULL,
+ *activity_type = NULL, *tags = NULL;
+ SalutContact *inviter;
+ SalutOlpcActivity *activity;
+ SalutMucChannel *muc;
+ muc_ready_ctx *ctx;
+
+ props_node = wocky_node_get_child_ns (invite_node, "properties",
+ NS_OLPC_ACTIVITY_PROPS);
+
+ if (props_node == NULL)
+ return;
+
+ inviter = salut_contact_manager_get_contact (priv->contact_manager,
+ inviter_handle);
+ if (inviter == NULL)
+ return;
+
+ properties = salut_wocky_node_extract_properties (props_node,
+ "property");
+
+ if (!extract_properties_from_hash (properties, &activity_id, &color,
+ &activity_name, &activity_type, &tags, NULL, NULL))
+ return;
+
+ activity = salut_olpc_activity_manager_got_invitation (
+ priv->olpc_activity_manager,
+ room, inviter, activity_id, activity_name, activity_type,
+ color, tags);
+#ifndef USE_BACKEND_BONJOUR
+ muc = salut_muc_manager_get_text_channel (priv->muc_manager, room);
+ g_assert (muc != NULL);
+
+ ctx = muc_ready_ctx_new (inviter, activity);
+ g_signal_connect (muc, "ready", G_CALLBACK (muc_ready_cb), ctx);
+ g_signal_connect (muc, "closed", G_CALLBACK (muc_closed_cb), ctx);
+
+ g_object_unref (muc);
+#endif
+ g_hash_table_unref (properties);
+ g_object_unref (inviter);
+}
+
+static void
+salut_connection_act_get_activity (SalutSvcOLPCActivityProperties *iface,
+ const gchar *activity_id,
+ DBusGMethodInvocation *context)
+{
+ SalutConnection *self = SALUT_CONNECTION (iface);
+ SalutConnectionPrivate *priv = self->priv;
+ TpBaseConnection *base = (TpBaseConnection *) self;
+ GError *error = NULL;
+ SalutOlpcActivity *activity;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context);
+
+ activity = salut_olpc_activity_manager_get_activity_by_id (
+ priv->olpc_activity_manager, activity_id);
+ if (activity == NULL)
+ {
+ g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
+ "Activity unknown: %s", activity_id);
+ goto error;
+ }
+
+ salut_svc_olpc_activity_properties_return_from_get_activity (context,
+ activity->room);
+
+ return;
+
+error:
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+}
+
+static void
+salut_connection_olpc_activity_properties_iface_init (gpointer g_iface,
+ gpointer iface_data)
+{
+ SalutSvcOLPCActivityPropertiesClass *klass =
+ (SalutSvcOLPCActivityPropertiesClass *) g_iface;
+#define IMPLEMENT(x) salut_svc_olpc_activity_properties_implement_##x \
+ (klass, salut_connection_act_##x)
+ IMPLEMENT(set_properties);
+ IMPLEMENT(get_properties);
+ IMPLEMENT(get_activity);
+#undef IMPLEMENT
+}
+#endif
+
gchar *
salut_normalize_non_empty (const gchar *id,
GError **error)
@@ -2033,7 +3406,234 @@ _contact_manager_contact_change_cb (SalutContactManager *mgr,
{
salut_conn_contact_info_changed (self, contact, handle);
}
+
+#ifdef ENABLE_OLPC
+ if (changes & SALUT_CONTACT_OLPC_PROPERTIES)
+ _contact_manager_contact_olpc_properties_changed (self, contact, handle);
+
+ if (changes & SALUT_CONTACT_OLPC_CURRENT_ACTIVITY)
+ salut_svc_olpc_buddy_info_emit_current_activity_changed (self,
+ handle, contact->olpc_cur_act, contact->olpc_cur_act_room);
+
+ if (changes & SALUT_CONTACT_OLPC_ACTIVITIES)
+ _contact_manager_contact_olpc_activities_changed (self, contact, handle);
+#endif
+}
+
+#ifdef ENABLE_OLPC
+static void
+_olpc_activity_manager_activity_modified_cb (SalutOlpcActivityManager *mgr,
+ SalutOlpcActivity *activity, SalutConnection *self)
+{
+ GHashTable *properties;
+
+ properties = salut_olpc_activity_create_properties_table (activity);
+ salut_svc_olpc_activity_properties_emit_activity_properties_changed (
+ self, activity->room, properties);
+
+ g_hash_table_unref (properties);
+}
+
+gboolean
+salut_connection_olpc_observe_muc_stanza (SalutConnection *self,
+ TpHandle room, TpHandle sender, WockyStanza *stanza)
+{
+ WockyNode *node = wocky_stanza_get_top_node (stanza);
+ SalutConnectionPrivate *priv = self->priv;
+ WockyNode *props_node;
+ GHashTable *properties;
+ const gchar *activity_id, *color = NULL, *activity_name = NULL,
+ *activity_type = NULL, *tags = NULL;
+ gboolean is_private = FALSE;
+ SalutOlpcActivity *activity;
+
+ props_node = wocky_node_get_child_ns (node, "properties",
+ NS_OLPC_ACTIVITY_PROPS);
+
+ if (props_node == NULL)
+ return FALSE;
+
+ activity = salut_olpc_activity_manager_get_activity_by_room (
+ priv->olpc_activity_manager, room);
+
+ if (activity == NULL)
+ {
+ DEBUG ("no activity in room %d", room);
+ return FALSE;
+ }
+
+ properties = salut_wocky_node_extract_properties (props_node,
+ "property");
+
+ if (!extract_properties_from_hash (properties, &activity_id, &color,
+ &activity_name, &activity_type, &tags, &is_private, NULL))
+ return TRUE;
+
+ salut_olpc_activity_update (activity, room, activity_id, activity_name,
+ activity_type, color, tags, is_private);
+
+ g_hash_table_unref (properties);
+
+ return TRUE;
+}
+
+static gboolean
+uninvite_stanza_callback (WockyPorter *porter,
+ WockyStanza *stanza,
+ gpointer user_data)
+{
+ SalutConnection *self = SALUT_CONNECTION (user_data);
+ SalutConnectionPrivate *priv = self->priv;
+ TpHandleRepoIface *room_repo = tp_base_connection_get_handles (
+ (TpBaseConnection *) self, TP_HANDLE_TYPE_ROOM);
+ WockyNode *node;
+ TpHandle room_handle;
+ const gchar *room, *activity_id;
+ SalutOlpcActivity *activity;
+ WockyNode *top_node = wocky_stanza_get_top_node (stanza);
+ SalutContact *contact = SALUT_CONTACT (wocky_stanza_get_from_contact (stanza));
+
+ node = wocky_node_get_child_ns (top_node, "uninvite",
+ NS_OLPC_ACTIVITY_PROPS);
+ g_assert (node != NULL);
+
+ room = wocky_node_get_attribute (node, "room");
+ if (room == NULL)
+ {
+ DEBUG ("No room attribute");
+ return FALSE;
+ }
+
+ room_handle = tp_handle_lookup (room_repo, room, NULL, NULL);
+ if (room_handle == 0)
+ {
+ DEBUG ("room %s unknown", room);
+ return FALSE;
+ }
+
+ activity_id = wocky_node_get_attribute (node, "id");
+ if (activity_id == NULL)
+ {
+ DEBUG ("No id attribute");
+ return FALSE;
+ }
+
+ DEBUG ("received uninvite from %s", contact->name);
+
+ activity = salut_olpc_activity_manager_get_activity_by_room (
+ priv->olpc_activity_manager, room_handle);
+
+ if (activity == NULL)
+ return FALSE;
+
+ salut_contact_left_activity (contact, activity);
+
+ return TRUE;
+}
+
+#endif
+
+static GPtrArray *
+salut_connection_create_channel_factories (TpBaseConnection *base)
+{
+ SalutConnection *self = SALUT_CONNECTION (base);
+ SalutConnectionPrivate *priv = self->priv;
+ GPtrArray *factories = g_ptr_array_sized_new (4);
+
+ /* Create the contact manager */
+ priv->contact_manager = salut_discovery_client_create_contact_manager (
+ priv->discovery_client, self);
+ g_signal_connect (priv->contact_manager, "contact-change",
+ G_CALLBACK (_contact_manager_contact_change_cb), self);
+
+#ifdef ENABLE_OLPC
+ priv->uninvite_handler_id = wocky_porter_register_handler_from_anyone (
+ self->porter,
+ WOCKY_STANZA_TYPE_MESSAGE, WOCKY_STANZA_SUB_TYPE_NONE,
+ WOCKY_PORTER_HANDLER_PRIORITY_NORMAL,
+ uninvite_stanza_callback, self,
+ '(', "uninvite",
+ ':', NS_OLPC_ACTIVITY_PROPS,
+ ')', NULL);
+
+ /* create the OLPC activity manager */
+ priv->olpc_activity_manager =
+ salut_discovery_client_create_olpc_activity_manager (
+ priv->discovery_client, self);
+ g_signal_connect (priv->olpc_activity_manager, "activity-modified",
+ G_CALLBACK (_olpc_activity_manager_activity_modified_cb), self);
+#endif
+
+ return factories;
+}
+
+#ifdef ENABLE_OLPC
+static void
+muc_channel_closed_cb (SalutMucChannel *chan,
+ SalutOlpcActivity *activity)
+{
+ SalutConnection *conn;
+ SalutConnectionPrivate *priv;
+ TpBaseConnection *base;
+ TpHandle self_handle;
+ GPtrArray *activities = g_ptr_array_new ();
+
+ g_signal_handlers_disconnect_by_func (chan,
+ G_CALLBACK (muc_channel_closed_cb), activity);
+
+ g_object_get (activity,
+ "connection", &conn,
+ NULL);
+
+ priv = conn->priv;
+ base = (TpBaseConnection *) conn;
+ self_handle = tp_base_connection_get_self_handle (base);
+
+ salut_self_remove_olpc_activity (priv->self, activity);
+
+ salut_self_foreach_olpc_activity (priv->self, append_activity, activities);
+ salut_svc_olpc_buddy_info_emit_activities_changed (conn, self_handle,
+ activities);
+ free_olpc_activities (activities);
+
+ /* we were holding a ref since the channel was opened */
+ g_object_unref (activity);
+
+ g_object_unref (conn);
+}
+
+static void
+muc_manager_new_channels_cb (TpChannelManager *channel_manager,
+ GHashTable *channels,
+ SalutConnection *conn)
+{
+ SalutConnectionPrivate *priv = conn->priv;
+ GHashTableIter iter;
+ gpointer chan;
+
+ g_hash_table_iter_init (&iter, channels);
+ while (g_hash_table_iter_next (&iter, &chan, NULL))
+ {
+ SalutOlpcActivity *activity;
+ TpHandle room_handle;
+
+ if (!SALUT_IS_MUC_CHANNEL (chan))
+ return;
+
+ g_object_get (chan,
+ "handle", &room_handle,
+ NULL);
+
+ /* ref the activity as long as we have a channel open */
+ activity = salut_olpc_activity_manager_ensure_activity_by_room (
+ priv->olpc_activity_manager,
+ room_handle);
+
+ g_signal_connect (chan, "closed", G_CALLBACK (muc_channel_closed_cb),
+ activity);
+ }
}
+#endif
static void
add_to_array (gpointer data,
@@ -2052,16 +3652,12 @@ salut_connection_create_channel_managers (TpBaseConnection *base)
GPtrArray *tmp;
SalutPluginLoader *loader;
- /* Create the contact manager. This is not a channel manager anymore,
- * but still needs to be created from here because others channel managers use
- * it and TpBaseConnection calls ::create_channel_managers() before
- * ::constructed() */
- self->priv->contact_manager = salut_discovery_client_create_contact_manager (
- self->priv->discovery_client, self);
- g_signal_connect (self->priv->contact_manager, "contact-change",
- G_CALLBACK (_contact_manager_contact_change_cb), self);
-
+ /* FIXME: The second and third arguments depend on create_channel_factories
+ * being called before this; should telepathy-glib guarantee that or
+ * should we be defensive?
+ */
priv->im_manager = salut_im_manager_new (self, priv->contact_manager);
+
priv->ft_manager = salut_ft_manager_new (self, priv->contact_manager);
#ifndef USE_BACKEND_BONJOUR
@@ -2077,6 +3673,7 @@ salut_connection_create_channel_managers (TpBaseConnection *base)
#endif
g_ptr_array_add (managers, priv->im_manager);
+ g_ptr_array_add (managers, priv->contact_manager);
g_ptr_array_add (managers, priv->ft_manager);
#ifndef USE_BACKEND_BONJOUR
g_ptr_array_add (managers, priv->muc_manager);
@@ -2087,6 +3684,11 @@ salut_connection_create_channel_managers (TpBaseConnection *base)
g_ptr_array_add (managers, priv->tubes_manager);
#endif
+#ifdef ENABLE_OLPC
+ g_signal_connect (TP_CHANNEL_MANAGER (priv->muc_manager), "new-channels",
+ G_CALLBACK (muc_manager_new_channels_cb), self);
+#endif
+
/* plugin channel managers */
loader = salut_plugin_loader_dup ();
tmp = salut_plugin_loader_create_channel_managers (loader, plugin_connection);
diff --git a/src/connection.h b/src/connection.h
index d965587e..dcc0128d 100644
--- a/src/connection.h
+++ b/src/connection.h
@@ -91,6 +91,16 @@ typedef enum {
LIST_HANDLE_LAST = LIST_HANDLE_KNOWN
} SalutConnectionListHandle;
+#ifdef ENABLE_OLPC
+void
+salut_connection_olpc_observe_invitation (SalutConnection *connection,
+ TpHandle room, TpHandle invitor_handle, WockyNode *invite_node);
+
+gboolean
+salut_connection_olpc_observe_muc_stanza (SalutConnection *self, TpHandle room,
+ TpHandle sender, WockyStanza *stanza);
+#endif
+
const gchar * const *salut_connection_get_implemented_interfaces (void);
gchar *salut_normalize_non_empty (const gchar *id, GError **error);
diff --git a/src/contact-manager.c b/src/contact-manager.c
index 8efd6f83..f15eda01 100644
--- a/src/contact-manager.c
+++ b/src/contact-manager.c
@@ -40,8 +40,9 @@ static void salut_contact_manager_close_all (SalutContactManager *mgr);
static void
_contact_finalized_cb (gpointer data, GObject *old_object);
-G_DEFINE_TYPE(SalutContactManager, salut_contact_manager,
- TP_TYPE_BASE_CONTACT_LIST)
+G_DEFINE_TYPE_WITH_CODE(SalutContactManager, salut_contact_manager,
+ TP_TYPE_BASE_CONTACT_LIST,
+ G_IMPLEMENT_INTERFACE (GABBLE_TYPE_CAPS_CHANNEL_MANAGER, NULL))
/* signal enum */
enum
diff --git a/src/contact.c b/src/contact.c
index 558b6ff0..109c8db8 100644
--- a/src/contact.c
+++ b/src/contact.c
@@ -73,6 +73,10 @@ struct _SalutContactPrivate
gboolean dispose_has_run;
gchar *alias;
GList *avatar_requests;
+#ifdef ENABLE_OLPC
+ /* room handle owned by the SalutOlpcActivity -> SalutOlpcActivity */
+ GHashTable *olpc_activities;
+#endif
gboolean found;
gboolean frozen;
guint pending_changes;
@@ -142,6 +146,16 @@ salut_contact_init (SalutContact *obj)
obj->status_message = NULL;
obj->avatar_token = NULL;
obj->jid = NULL;
+#ifdef ENABLE_OLPC
+ obj->olpc_key = NULL;
+ obj->olpc_color = NULL;
+ obj->olpc_cur_act = NULL;
+ obj->olpc_cur_act_room = 0;
+ obj->olpc_ip4 = NULL;
+ obj->olpc_ip6 = NULL;
+ priv->olpc_activities = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify) g_object_unref);
+#endif
priv->found = FALSE;
priv->alias = NULL;
}
@@ -255,6 +269,17 @@ salut_contact_class_init (SalutContactClass *salut_contact_class)
param_spec);
}
+#ifdef ENABLE_OLPC
+static void
+disconnect_activity_signal_foreach (TpHandle room,
+ SalutOlpcActivity *activity,
+ SalutContact *self)
+{
+ g_signal_handlers_disconnect_matched (activity, G_SIGNAL_MATCH_DATA, 0, 0,
+ NULL, NULL, self);
+}
+#endif
+
void
salut_contact_dispose (GObject *object)
{
@@ -268,6 +293,12 @@ salut_contact_dispose (GObject *object)
priv->dispose_has_run = TRUE;
+#ifdef ENABLE_OLPC
+ g_hash_table_foreach (priv->olpc_activities,
+ (GHFunc) disconnect_activity_signal_foreach, self);
+ g_hash_table_unref (priv->olpc_activities);
+#endif
+
salut_contact_avatar_request_flush (self, NULL, 0);
/* release any references held by the object here */
@@ -299,6 +330,17 @@ salut_contact_finalize (GObject *object)
g_free (self->email);
g_free (self->jid);
+#ifdef ENABLE_OLPC
+ if (self->olpc_key != NULL)
+ {
+ g_array_unref (self->olpc_key);
+ }
+ g_free (self->olpc_color);
+ g_free (self->olpc_cur_act);
+ g_free (self->olpc_ip4);
+ g_free (self->olpc_ip6);
+#endif
+
G_OBJECT_CLASS (salut_contact_parent_class)->finalize (object);
}
@@ -317,6 +359,45 @@ purge_cached_avatar (SalutContact *self,
SALUT_CONTACT_GET_CLASS (self)->retrieve_avatar (self);
}
+#ifdef ENABLE_OLPC
+typedef struct
+{
+ SalutContactOLPCActivityFunc foreach;
+ gpointer user_data;
+} foreach_olpc_activity_ctx;
+
+static void
+foreach_olpc_activity (gpointer key, gpointer value, gpointer user_data)
+{
+ foreach_olpc_activity_ctx *ctx = user_data;
+ SalutOlpcActivity *activity = value;
+
+ /* ignore activity without ID */
+ if (activity->id == NULL)
+ return;
+
+ DEBUG ("%s => %u", activity->id, activity->room);
+ (ctx->foreach) (activity, ctx->user_data);
+}
+
+void
+salut_contact_foreach_olpc_activity (SalutContact *self,
+ SalutContactOLPCActivityFunc foreach,
+ gpointer user_data)
+{
+ SalutContactPrivate *priv = self->priv;
+ foreach_olpc_activity_ctx ctx = { foreach, user_data };
+
+ DEBUG ("called");
+
+ g_hash_table_foreach (priv->olpc_activities, foreach_olpc_activity,
+ &ctx);
+
+ DEBUG ("end");
+}
+
+#endif
+
GArray *
salut_contact_get_addresses (SalutContact *self)
{
@@ -535,6 +616,9 @@ salut_contact_change_jid (SalutContact *self, gchar *jid)
self->jid = g_strdup (jid);
salut_contact_change (self,
SALUT_CONTACT_JID_CHANGED
+#ifdef ENABLE_OLPC
+ | SALUT_CONTACT_OLPC_PROPERTIES
+#endif
);
}
}
@@ -551,6 +635,115 @@ void salut_contact_change_capabilities (SalutContact *self,
hash, node, ver);
}
+#ifdef ENABLE_OLPC
+void
+salut_contact_change_olpc_color (SalutContact *self, const gchar *olpc_color)
+{
+ if (tp_strdiff (self->olpc_color, olpc_color))
+ {
+ g_free (self->olpc_color);
+ self->olpc_color = g_strdup (olpc_color);
+ salut_contact_change (self, SALUT_CONTACT_OLPC_PROPERTIES);
+ }
+}
+
+void
+salut_contact_change_olpc_key (SalutContact *self, GArray *olpc_key)
+{
+ if (olpc_key != NULL)
+ {
+ if (self->olpc_key == NULL || self->olpc_key->len != olpc_key->len ||
+ memcmp (self->olpc_key->data, olpc_key->data, olpc_key->len) != 0)
+ {
+ if (self->olpc_key != NULL)
+ {
+ g_array_unref (self->olpc_key);
+ }
+ self->olpc_key = g_array_sized_new (FALSE, FALSE,
+ sizeof (guint8), olpc_key->len);
+ g_array_append_vals (self->olpc_key, olpc_key->data,
+ olpc_key->len);
+ salut_contact_change (self, SALUT_CONTACT_OLPC_PROPERTIES);
+ }
+ }
+}
+
+void
+salut_contact_change_ipv4_addr (SalutContact *self, const gchar *ipv4_addr)
+{
+ if (tp_strdiff (ipv4_addr, self->olpc_ip4))
+ {
+ g_free (self->olpc_ip4);
+ self->olpc_ip4 = g_strdup (ipv4_addr);
+ salut_contact_change (self, SALUT_CONTACT_OLPC_PROPERTIES);
+ }
+
+}
+
+void
+salut_contact_change_ipv6_addr (SalutContact *self, const gchar *ipv6_addr)
+{
+ if (tp_strdiff (ipv6_addr, self->olpc_ip6))
+ {
+ g_free (self->olpc_ip6);
+ self->olpc_ip6 = g_strdup (ipv6_addr);
+ salut_contact_change (self, SALUT_CONTACT_OLPC_PROPERTIES);
+ }
+}
+
+void
+salut_contact_change_current_activity (SalutContact *self,
+ const gchar *current_activity_id,
+ const gchar *current_activity_room)
+{
+ TpHandleRepoIface *room_repo;
+ TpHandle room_handle = 0;
+
+ if (self->connection == NULL)
+ return;
+
+ room_repo = tp_base_connection_get_handles
+ ((TpBaseConnection *) self->connection, TP_HANDLE_TYPE_ROOM);
+
+ if (current_activity_room != NULL && *current_activity_room != '\0')
+ {
+ room_handle = tp_handle_ensure (room_repo, current_activity_room,
+ NULL, NULL);
+ if (room_handle == 0)
+ {
+ DEBUG ("Invalid room \"%s\" for current activity \"%s\": "
+ "ignoring", current_activity_room, current_activity_id);
+ }
+ }
+
+ if (current_activity_id == NULL || room_handle == 0)
+ {
+ DEBUG ("Unsetting current activity");
+ if (self->olpc_cur_act != NULL || self->olpc_cur_act_room != 0)
+ {
+ g_free (self->olpc_cur_act);
+ self->olpc_cur_act = NULL;
+ self->olpc_cur_act_room = 0;
+ salut_contact_change (self, SALUT_CONTACT_OLPC_CURRENT_ACTIVITY);
+ }
+ }
+ else
+ {
+ DEBUG ("Current activity %s, room handle %d", current_activity_id,
+ room_handle);
+ if (tp_strdiff (self->olpc_cur_act, current_activity_id) ||
+ self->olpc_cur_act_room != room_handle)
+ {
+ g_free (self->olpc_cur_act);
+ self->olpc_cur_act_room = room_handle;
+ self->olpc_cur_act = g_strdup (current_activity_id);
+ salut_contact_change (self, SALUT_CONTACT_OLPC_CURRENT_ACTIVITY);
+ }
+ }
+}
+
+#endif
+
void
salut_contact_found (SalutContact *self)
{
@@ -606,6 +799,68 @@ salut_contact_thaw (SalutContact *self)
salut_contact_change (self, 0);
}
+#ifdef ENABLE_OLPC
+static void
+activity_valid_cb (SalutOlpcActivity *activity,
+ SalutContact *self)
+{
+ /* Now we can emit the ActivitiesChanged signal */
+ DEBUG ("activity in room %d (%s) is now valid", activity->room, activity->id);
+ g_signal_emit (self, signals[CONTACT_CHANGE], 0,
+ SALUT_CONTACT_OLPC_ACTIVITIES);
+}
+
+gboolean
+salut_contact_joined_activity (SalutContact *self,
+ SalutOlpcActivity *activity)
+{
+ SalutContactPrivate *priv = self->priv;
+
+ if (g_hash_table_lookup (priv->olpc_activities,
+ GUINT_TO_POINTER (activity->room)) != NULL)
+ return FALSE;
+
+ DEBUG_CONTACT (self, "joined activity %s", activity->id);
+ g_hash_table_insert (priv->olpc_activities, GUINT_TO_POINTER (activity->room),
+ activity);
+ g_object_ref (activity);
+
+ if (activity->id == NULL)
+ {
+ /* we can't emit the ActivitiesChanged signal right now as we don't have
+ * the activity ID. Thanks OLPC interface */
+ DEBUG ("activity in room %d isn't valid yet", activity->room);
+ g_signal_connect (activity, "valid", G_CALLBACK (activity_valid_cb),
+ self);
+ }
+ else
+ {
+ g_signal_emit (self, signals[CONTACT_CHANGE], 0,
+ SALUT_CONTACT_OLPC_ACTIVITIES);
+ }
+
+ return TRUE;
+}
+
+void
+salut_contact_left_activity (SalutContact *self,
+ SalutOlpcActivity *activity)
+{
+ SalutContactPrivate *priv = self->priv;
+
+ g_signal_handlers_disconnect_matched (activity, G_SIGNAL_MATCH_DATA, 0, 0,
+ NULL, NULL, self);
+
+ DEBUG_CONTACT (self, "left activity %s", activity->id);
+ if (!g_hash_table_remove (priv->olpc_activities,
+ GUINT_TO_POINTER (activity->room)))
+ return;
+
+ g_signal_emit (self, signals[CONTACT_CHANGE], 0,
+ SALUT_CONTACT_OLPC_ACTIVITIES);
+}
+#endif
+
static const GPtrArray *
salut_contact_get_data_forms (WockyXep0115Capabilities *caps)
{
diff --git a/src/contact.h b/src/contact.h
index 33244f2c..d301e293 100644
--- a/src/contact.h
+++ b/src/contact.h
@@ -28,6 +28,10 @@
#include "presence.h"
#include "connection.h"
+#ifdef ENABLE_OLPC
+#include "olpc-activity.h"
+#endif
+
#include <gibber/gibber-sockets.h>
#include <wocky/wocky.h>
@@ -38,6 +42,11 @@ enum {
SALUT_CONTACT_ALIAS_CHANGED = 0x1,
SALUT_CONTACT_STATUS_CHANGED = 0x2,
SALUT_CONTACT_AVATAR_CHANGED = 0x4,
+#ifdef ENABLE_OLPC
+ SALUT_CONTACT_OLPC_PROPERTIES = 0x8,
+ SALUT_CONTACT_OLPC_CURRENT_ACTIVITY = 0x10,
+ SALUT_CONTACT_OLPC_ACTIVITIES = 0x20,
+#endif /* ENABLE_OLPC */
SALUT_CONTACT_JID_CHANGED = 0x40,
SALUT_CONTACT_EMAIL_CHANGED = 0x80,
SALUT_CONTACT_REAL_NAME_CHANGED = 0x100,
@@ -80,6 +89,14 @@ struct _SalutContact {
GPtrArray *data_forms; /* of owned WockyDataForm*s */
TpHandle handle;
+#ifdef ENABLE_OLPC
+ GArray *olpc_key;
+ gchar *olpc_color;
+ gchar *olpc_cur_act;
+ TpHandle olpc_cur_act_room;
+ gchar *olpc_ip4;
+ gchar *olpc_ip6;
+#endif /* ENABLE_OLPC */
/* private */
SalutConnection *connection;
@@ -127,6 +144,20 @@ void salut_contact_set_capabilities (SalutContact *contact,
const GabbleCapabilitySet *caps,
const GPtrArray *data_forms);
+#ifdef ENABLE_OLPC
+typedef void (*SalutContactOLPCActivityFunc)
+ (SalutOlpcActivity *activity, gpointer user_data);
+
+void salut_contact_foreach_olpc_activity (SalutContact *self,
+ SalutContactOLPCActivityFunc foreach, gpointer user_data);
+
+gboolean salut_contact_joined_activity (SalutContact *self,
+ SalutOlpcActivity *activity);
+
+void salut_contact_left_activity (SalutContact *self,
+ SalutOlpcActivity *activity);
+#endif
+
/* restricted methods */
void salut_contact_change_real_name (SalutContact *self, const gchar *first,
const gchar *last);
@@ -141,6 +172,18 @@ void salut_contact_change_jid (SalutContact *self, gchar *jid);
void salut_contact_change_capabilities (SalutContact *self,
const gchar *hash, const gchar *node, const gchar *ver);
+#ifdef ENABLE_OLPC
+void salut_contact_change_olpc_color (SalutContact *self,
+ const gchar *olpc_color);
+void salut_contact_change_olpc_key (SalutContact *self, GArray *olpc_key);
+void salut_contact_change_ipv4_addr (SalutContact *self,
+ const gchar *ipv4_addr);
+void salut_contact_change_ipv6_addr (SalutContact *self,
+ const gchar *ipv4_addr);
+void salut_contact_change_current_activity (SalutContact *self,
+ const gchar *current_activity_id, const gchar *current_activity_room);
+#endif
+
void salut_contact_avatar_request_flush (SalutContact *self, guint8 *data,
gsize size);
diff --git a/src/debug.c b/src/debug.c
index 53a7c60e..365cb7d8 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -35,6 +35,7 @@ GDebugKey keys[] = {
{ "xmpp-connection-manager", DEBUG_XCM },
{ "si-bytestream-manager", DEBUG_SI_BYTESTREAM_MGR },
{ "discovery", DEBUG_DISCOVERY },
+ { "olpc-activity", DEBUG_OLPC_ACTIVITY },
{ "ft", DEBUG_FT },
{ "plugin", DEBUG_PLUGIN },
{ 0, },
diff --git a/src/debug.h b/src/debug.h
index 135ec385..9e97ed3d 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -31,8 +31,9 @@ typedef enum
DEBUG_TUBES = 1 << 16,
DEBUG_XCM = 1 << 17,
DEBUG_DISCOVERY = 1 << 18,
- DEBUG_FT = 1 << 19,
- DEBUG_PLUGIN = 1 << 20,
+ DEBUG_OLPC_ACTIVITY = 1 << 19,
+ DEBUG_FT = 1 << 20,
+ DEBUG_PLUGIN = 1 << 21,
} DebugFlags;
void debug_set_flags_from_env (void);
diff --git a/src/discovery-client.c b/src/discovery-client.c
index 75f48248..7add6fa8 100644
--- a/src/discovery-client.c
+++ b/src/discovery-client.c
@@ -65,6 +65,19 @@ salut_discovery_client_create_contact_manager (SalutDiscoveryClient *self,
return virtual_method (self, connection);
}
+#ifdef ENABLE_OLPC
+SalutOlpcActivityManager *
+salut_discovery_client_create_olpc_activity_manager (SalutDiscoveryClient *self,
+ SalutConnection *connection)
+{
+ SalutOlpcActivityManager * (*virtual_method)(SalutDiscoveryClient *,
+ SalutConnection *) =
+ SALUT_DISCOVERY_CLIENT_GET_CLASS (self)->create_olpc_activity_manager;
+ g_assert (virtual_method != NULL);
+ return virtual_method (self, connection);
+}
+#endif
+
SalutSelf *
salut_discovery_client_create_self (SalutDiscoveryClient *self,
SalutConnection *connection,
@@ -73,15 +86,17 @@ salut_discovery_client_create_self (SalutDiscoveryClient *self,
const gchar *last_name,
const gchar *jid,
const gchar *email,
- const gchar *published_name)
+ const gchar *published_name,
+ const GArray *olpc_key,
+ const gchar *olpc_color)
{
SalutSelf * (*virtual_method)(SalutDiscoveryClient *, SalutConnection *,
const gchar *, const gchar *, const gchar *, const gchar *,
- const gchar *, const gchar *) =
+ const gchar *, const gchar *, const GArray *, const gchar *) =
SALUT_DISCOVERY_CLIENT_GET_CLASS (self)->create_self;
g_assert (virtual_method != NULL);
return virtual_method (self, connection, nickname, first_name, last_name,
- jid, email, published_name);
+ jid, email, published_name, olpc_key, olpc_color);
}
const gchar *
diff --git a/src/discovery-client.h b/src/discovery-client.h
index 60bfd63d..e741a275 100644
--- a/src/discovery-client.h
+++ b/src/discovery-client.h
@@ -26,6 +26,9 @@
#include "contact-manager.h"
#include "roomlist-manager.h"
#include "self.h"
+#ifdef ENABLE_OLPC
+#include "olpc-activity-manager.h"
+#endif
G_BEGIN_DECLS
@@ -52,9 +55,14 @@ struct _SalutDiscoveryClientClass
SalutConnection *connection);
SalutContactManager * (*create_contact_manager) (SalutDiscoveryClient *clt,
SalutConnection *connection);
+#ifdef ENABLE_OLPC
+ SalutOlpcActivityManager * (*create_olpc_activity_manager) (
+ SalutDiscoveryClient *clt, SalutConnection *connection);
+#endif
SalutSelf * (*create_self) (SalutDiscoveryClient *clt, SalutConnection *conn,
const gchar *nickname, const gchar *first_name, const gchar *last_name,
- const gchar *jid, const gchar *email, const gchar *published_name);
+ const gchar *jid, const gchar *email, const gchar *published_name,
+ const GArray *olpc_key, const gchar *olpc_color);
const gchar * (*get_host_name_fqdn) (SalutDiscoveryClient *clt);
};
@@ -85,10 +93,16 @@ SalutRoomlistManager * salut_discovery_client_create_roomlist_manager (
SalutContactManager * salut_discovery_client_create_contact_manager (
SalutDiscoveryClient *clt, SalutConnection *connection);
+#ifdef ENABLE_OLPC
+SalutOlpcActivityManager * salut_discovery_client_create_olpc_activity_manager (
+ SalutDiscoveryClient *clt, SalutConnection *connection);
+#endif
+
SalutSelf * salut_discovery_client_create_self (
SalutDiscoveryClient *clt, SalutConnection *connection,
const gchar *nickname, const gchar *first_name, const gchar *last_name,
- const gchar *jid, const gchar *email, const gchar *published_name);
+ const gchar *jid, const gchar *email, const gchar *published_name,
+ const GArray *olpc_key, const gchar *olpc_color);
const gchar * salut_discovery_client_get_host_name_fqdn (
SalutDiscoveryClient *clt);
diff --git a/src/dummy-discovery-client.c b/src/dummy-discovery-client.c
index d7d279e2..5399f260 100644
--- a/src/dummy-discovery-client.c
+++ b/src/dummy-discovery-client.c
@@ -112,7 +112,9 @@ salut_dummy_discovery_client_create_self (SalutDiscoveryClient *client,
const gchar *last_name,
const gchar *jid,
const gchar *email,
- const gchar *published_name)
+ const gchar *published_name,
+ const GArray *olpc_key,
+ const gchar *olpc_color)
{
return NULL;
}
@@ -126,5 +128,8 @@ discovery_client_init (gpointer g_iface,
klass->start = NULL;
klass->create_muc_manager = NULL;
klass->create_contact_manager = NULL;
+#ifdef ENABLE_OLPC
+ klass->create_olpc_activity_manager = NULL;
+#endif
klass->create_self = salut_dummy_discovery_client_create_self;
}
diff --git a/src/file-transfer-channel.c b/src/file-transfer-channel.c
index efc28802..78271d63 100644
--- a/src/file-transfer-channel.c
+++ b/src/file-transfer-channel.c
@@ -1188,7 +1188,7 @@ salut_file_transfer_channel_offer_file (SalutFileTransferChannel *self,
* salut_file_transfer_channel_accept_file
*
* Implements D-Bus method AcceptFile
- * on interface im.telepathy1.Channel.Type.FileTransfer
+ * on interface org.freedesktop.Telepathy.Channel.Type.FileTransfer
*/
static void
salut_file_transfer_channel_accept_file (TpSvcChannelTypeFileTransfer *iface,
@@ -1264,7 +1264,7 @@ salut_file_transfer_channel_accept_file (TpSvcChannelTypeFileTransfer *iface,
* salut_file_transfer_channel_provide_file
*
* Implements D-Bus method ProvideFile
- * on interface im.telepathy1.Channel.Type.FileTransfer
+ * on interface org.freedesktop.Telepathy.Channel.Type.FileTransfer
*/
static void
salut_file_transfer_channel_provide_file (
diff --git a/src/im-channel.c b/src/im-channel.c
index 46ecc32f..d7a409be 100644
--- a/src/im-channel.c
+++ b/src/im-channel.c
@@ -47,7 +47,9 @@
G_DEFINE_TYPE_WITH_CODE (SalutImChannel, salut_im_channel, TP_TYPE_BASE_CHANNEL,
G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_TEXT,
- tp_message_mixin_iface_init)
+ tp_message_mixin_text_iface_init);
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_MESSAGES,
+ tp_message_mixin_messages_iface_init);
);
/* properties */
@@ -208,10 +210,10 @@ salut_im_channel_fill_immutable_properties (TpBaseChannel *chan,
tp_dbus_properties_mixin_fill_properties_hash (
G_OBJECT (chan), properties,
- TP_IFACE_CHANNEL_TYPE_TEXT, "MessagePartSupportFlags",
- TP_IFACE_CHANNEL_TYPE_TEXT, "DeliveryReportingSupport",
- TP_IFACE_CHANNEL_TYPE_TEXT, "SupportedContentTypes",
- TP_IFACE_CHANNEL_TYPE_TEXT, "MessageTypes",
+ TP_IFACE_CHANNEL_INTERFACE_MESSAGES, "MessagePartSupportFlags",
+ TP_IFACE_CHANNEL_INTERFACE_MESSAGES, "DeliveryReportingSupport",
+ TP_IFACE_CHANNEL_INTERFACE_MESSAGES, "SupportedContentTypes",
+ TP_IFACE_CHANNEL_INTERFACE_MESSAGES, "MessageTypes",
NULL);
}
@@ -222,6 +224,16 @@ salut_im_channel_get_object_path_suffix (TpBaseChannel *chan)
tp_base_channel_get_target_handle (chan));
}
+static GPtrArray *
+salut_im_channel_get_interfaces (TpBaseChannel *chan)
+{
+ GPtrArray *interfaces = TP_BASE_CHANNEL_CLASS (salut_im_channel_parent_class)
+ ->get_interfaces (chan);
+
+ g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_MESSAGES);
+ return interfaces;
+}
+
static void
salut_im_channel_class_init (SalutImChannelClass *salut_im_channel_class)
{
@@ -239,6 +251,7 @@ salut_im_channel_class_init (SalutImChannelClass *salut_im_channel_class)
object_class->set_property = salut_im_channel_set_property;
base_class->channel_type = TP_IFACE_CHANNEL_TYPE_TEXT;
+ base_class->get_interfaces = salut_im_channel_get_interfaces;
base_class->target_handle_type = TP_HANDLE_TYPE_CONTACT;
base_class->close = salut_im_channel_close;
base_class->fill_immutable_properties =
diff --git a/src/muc-channel.c b/src/muc-channel.c
index c0eb63e6..091e60a2 100644
--- a/src/muc-channel.c
+++ b/src/muc-channel.c
@@ -54,13 +54,14 @@
#include "text-helper.h"
#include "tube-stream.h"
#include "tube-dbus.h"
-#include "util.h"
G_DEFINE_TYPE_WITH_CODE(SalutMucChannel, salut_muc_channel, TP_TYPE_BASE_CHANNEL,
G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_GROUP,
tp_group_mixin_iface_init);
G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_TEXT,
- tp_message_mixin_iface_init);
+ tp_message_mixin_text_iface_init);
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_MESSAGES,
+ tp_message_mixin_messages_iface_init);
)
/* signal enum */
@@ -122,7 +123,7 @@ static void salut_muc_channel_close (TpBaseChannel *base);
static void update_tube_info (SalutMucChannel *self);
static SalutTubeIface * create_new_tube (SalutMucChannel *self,
- SalutTubeType type,
+ TpTubeType type,
TpHandle initiator,
const gchar *service,
GHashTable *parameters,
@@ -182,34 +183,6 @@ salut_muc_channel_set_property (GObject *object,
}
}
-/* This is helper function with the signature of tp_group_mixin_change_members()
- * from tp-glib 0.x */
-static void
-change_members (GObject *obj,
- const gchar *message,
- const TpIntset *add,
- const TpIntset *del,
- const TpIntset *add_local_pending,
- const TpIntset *add_remote_pending,
- TpHandle actor,
- TpChannelGroupChangeReason reason)
-{
- GHashTable *details;
-
- details = tp_asv_new (
- "actor", G_TYPE_UINT, actor,
- "change-reason", G_TYPE_UINT, reason,
- NULL);
-
- if (message != NULL)
- tp_asv_set_string (details, "message", message);
-
- tp_group_mixin_change_members (obj,
- add, del, add_local_pending, add_remote_pending, details);
-
- g_hash_table_unref (details);
-}
-
static void
salut_muc_channel_add_self_to_members (SalutMucChannel *self)
{
@@ -233,7 +206,7 @@ salut_muc_channel_add_self_to_members (SalutMucChannel *self)
add = tp_intset_new ();
tp_intset_add (add, tp_base_connection_get_self_handle (base_conn));
- change_members (G_OBJECT (self),
+ tp_group_mixin_change_members (G_OBJECT (self),
"", add, empty, empty, empty,
tp_base_connection_get_self_handle (base_conn),
TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
@@ -331,6 +304,7 @@ salut_muc_channel_constructed (GObject *obj)
contact_repo, tp_base_connection_get_self_handle (base_conn));
tp_group_mixin_change_flags (obj,
+ TP_CHANNEL_GROUP_FLAG_PROPERTIES |
TP_CHANNEL_GROUP_FLAG_CAN_ADD |
TP_CHANNEL_GROUP_FLAG_MESSAGE_ADD,
0);
@@ -405,6 +379,12 @@ create_invitation (SalutMucChannel *self,
priv->muc_connection),
invitation_append_parameter, invite_node);
+#ifdef ENABLE_OLPC
+ salut_self_olpc_augment_invitation (priv->self,
+ tp_base_channel_get_target_handle (base_chan), contact->handle,
+ invite_node);
+#endif
+
return msg;
}
@@ -450,7 +430,7 @@ send_invite_cb (GObject *source_object,
removed = tp_intset_new ();
tp_intset_add (removed, handle);
- change_members (G_OBJECT (data->self), "", empty, removed, empty,
+ tp_group_mixin_change_members (G_OBJECT (data->self), "", empty, removed, empty,
empty, tp_base_connection_get_self_handle (base_connection),
TP_CHANNEL_GROUP_CHANGE_REASON_ERROR);
@@ -542,7 +522,7 @@ salut_muc_channel_add_member (GObject *iface,
{
/* We are considered as remote-pending while the muc connection
* is not connected */
- change_members (G_OBJECT (self),
+ tp_group_mixin_change_members (G_OBJECT (self),
message, empty_, empty_, empty_, add,
tp_base_connection_get_self_handle (base_connection),
TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
@@ -571,7 +551,7 @@ salut_muc_channel_add_member (GObject *iface,
empty = tp_intset_new ();
remote_pending = tp_intset_new ();
tp_intset_add (remote_pending, handle);
- change_members (G_OBJECT(self), "", empty, empty, empty,
+ tp_group_mixin_change_members (G_OBJECT(self), "", empty, empty, empty,
remote_pending, tp_base_connection_get_self_handle (base_connection),
TP_CHANNEL_GROUP_CHANGE_REASON_INVITED);
tp_intset_destroy (empty);
@@ -638,10 +618,10 @@ salut_muc_channel_fill_immutable_properties (TpBaseChannel *chan,
tp_dbus_properties_mixin_fill_properties_hash (
G_OBJECT (chan), properties,
- TP_IFACE_CHANNEL_TYPE_TEXT, "MessagePartSupportFlags",
- TP_IFACE_CHANNEL_TYPE_TEXT, "DeliveryReportingSupport",
- TP_IFACE_CHANNEL_TYPE_TEXT, "SupportedContentTypes",
- TP_IFACE_CHANNEL_TYPE_TEXT, "MessageTypes",
+ TP_IFACE_CHANNEL_INTERFACE_MESSAGES, "MessagePartSupportFlags",
+ TP_IFACE_CHANNEL_INTERFACE_MESSAGES, "DeliveryReportingSupport",
+ TP_IFACE_CHANNEL_INTERFACE_MESSAGES, "SupportedContentTypes",
+ TP_IFACE_CHANNEL_INTERFACE_MESSAGES, "MessageTypes",
NULL);
}
@@ -652,7 +632,7 @@ salut_muc_channel_get_interfaces (TpBaseChannel *chan)
->get_interfaces (chan);
g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_GROUP);
-
+ g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_MESSAGES);
return interfaces;
}
@@ -848,9 +828,11 @@ salut_muc_channel_invited (SalutMucChannel *self, TpHandle inviter,
g_assert (stanza != NULL);
tp_intset_add (local_pending, self_handle);
- change_members (G_OBJECT(self), stanza,
- empty, empty, local_pending, empty,
- inviter, TP_CHANNEL_GROUP_CHANGE_REASON_INVITED);
+ tp_group_mixin_change_members (G_OBJECT(self), stanza,
+ empty, empty,
+ local_pending, empty,
+ inviter,
+ TP_CHANNEL_GROUP_CHANGE_REASON_INVITED);
tp_intset_destroy (local_pending);
tp_intset_destroy (empty);
}
@@ -907,8 +889,13 @@ salut_muc_channel_add_members (SalutMucChannel *self,
tp_intset_add (changes, contact->handle);
}
- change_members (G_OBJECT(self), "", changes, empty, empty, empty,
- 0, TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
+ tp_group_mixin_change_members (G_OBJECT(self),
+ "",
+ changes,
+ empty,
+ empty, empty,
+ 0,
+ TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
tp_intset_destroy (changes);
tp_intset_destroy (empty);
g_object_unref (contact_mgr);
@@ -947,8 +934,13 @@ salut_muc_channel_remove_members (SalutMucChannel *self,
tp_intset_add (changes, handle);
}
- change_members (G_OBJECT(self), "", empty, changes, empty, empty,
- 0, TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
+ tp_group_mixin_change_members (G_OBJECT(self),
+ "",
+ empty,
+ changes,
+ empty, empty,
+ 0,
+ TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
tp_intset_destroy (changes);
tp_intset_destroy (empty);
}
@@ -957,7 +949,7 @@ salut_muc_channel_remove_members (SalutMucChannel *self,
static gboolean
extract_tube_information (SalutMucChannel *self,
WockyNode *tube_node,
- SalutTubeType *type,
+ TpTubeType *type,
TpHandle *initiator_handle,
const gchar **service,
GHashTable **parameters,
@@ -977,11 +969,11 @@ extract_tube_information (SalutMucChannel *self,
if (!tp_strdiff (_type, "stream"))
{
- *type = SALUT_TUBE_TYPE_STREAM;
+ *type = TP_TUBE_TYPE_STREAM;
}
else if (!tp_strdiff (_type, "dbus"))
{
- *type = SALUT_TUBE_TYPE_DBUS;
+ *type = TP_TUBE_TYPE_DBUS;
}
else
{
@@ -1096,13 +1088,13 @@ muc_channel_handle_tubes (SalutMucChannel *self,
{
guint tube_id = GPOINTER_TO_UINT (key);
SalutTubeIface *tube = value;
- SalutTubeType type;
+ TpTubeType type;
g_object_get (tube,
"type", &type,
NULL);
- if (type != SALUT_TUBE_TYPE_DBUS)
+ if (type != TP_TUBE_TYPE_DBUS)
return;
if (salut_tube_dbus_handle_in_names (SALUT_TUBE_DBUS (tube),
@@ -1118,7 +1110,7 @@ muc_channel_handle_tubes (SalutMucChannel *self,
const gchar *stream_id;
SalutTubeIface *tube;
guint tube_id;
- SalutTubeType type;
+ TpTubeType type;
GibberBytestreamIface *bytestream;
stream_id = wocky_node_get_attribute (tube_node, "stream-id");
@@ -1142,7 +1134,7 @@ muc_channel_handle_tubes (SalutMucChannel *self,
{
switch (type)
{
- case SALUT_TUBE_TYPE_DBUS:
+ case TP_TUBE_TYPE_DBUS:
{
if (initiator_handle == 0)
{
@@ -1151,7 +1143,7 @@ muc_channel_handle_tubes (SalutMucChannel *self,
}
}
break;
- case SALUT_TUBE_TYPE_STREAM:
+ case TP_TUBE_TYPE_STREAM:
initiator_handle = contact;
break;
default:
@@ -1180,7 +1172,7 @@ muc_channel_handle_tubes (SalutMucChannel *self,
"type", &type,
NULL);
- if (type == SALUT_TUBE_TYPE_DBUS
+ if (type == TP_TUBE_TYPE_DBUS
&& !salut_tube_dbus_handle_in_names (SALUT_TUBE_DBUS (tube),
contact))
{
@@ -1283,6 +1275,14 @@ salut_muc_channel_received_stanza (GibberMucConnection *conn,
/* let's not autoclose now */
priv->autoclose = FALSE;
+#ifdef ENABLE_OLPC
+ if (salut_connection_olpc_observe_muc_stanza (
+ SALUT_CONNECTION (base_connection),
+ tp_base_channel_get_target_handle (base_chan),
+ from_handle, stanza))
+ return;
+#endif
+
tubes_node = wocky_node_get_child_ns (node, "tubes",
WOCKY_TELEPATHY_NS_TUBES);
if (tubes_node != NULL)
@@ -1479,7 +1479,7 @@ publish_tube_in_node (SalutMucChannel *self,
base_conn, TP_HANDLE_TYPE_CONTACT);
WockyNode *parameters_node;
GHashTable *parameters;
- SalutTubeType type;
+ TpTubeType type;
gchar *service, *id_str;
guint64 tube_id;
TpHandle initiator_handle;
@@ -1501,7 +1501,7 @@ publish_tube_in_node (SalutMucChannel *self,
switch (type)
{
- case SALUT_TUBE_TYPE_DBUS:
+ case TP_TUBE_TYPE_DBUS:
{
gchar *name, *stream_id;
@@ -1523,7 +1523,7 @@ publish_tube_in_node (SalutMucChannel *self,
}
break;
- case SALUT_TUBE_TYPE_STREAM:
+ case TP_TUBE_TYPE_STREAM:
wocky_node_set_attribute (node, "type", "stream");
break;
default:
@@ -1577,7 +1577,7 @@ update_tube_info (SalutMucChannel *self)
while (g_hash_table_iter_next (&iter, NULL, &value))
{
TpTubeChannelState state;
- SalutTubeType type;
+ TpTubeType type;
TpHandle initiator;
WockyNode *tube_node;
@@ -1590,7 +1590,7 @@ update_tube_info (SalutMucChannel *self)
if (state != TP_TUBE_CHANNEL_STATE_OPEN)
continue;
- if (type == SALUT_TUBE_TYPE_STREAM
+ if (type == TP_TUBE_TYPE_STREAM
&& initiator != TP_GROUP_MIXIN (self)->self_handle)
/* We only announce stream tubes we initiated */
return;
@@ -1674,7 +1674,7 @@ generate_tube_id (SalutMucChannel *self)
static SalutTubeIface *
create_new_tube (SalutMucChannel *self,
- SalutTubeType type,
+ TpTubeType type,
TpHandle initiator,
const gchar *service,
GHashTable *parameters,
@@ -1693,12 +1693,12 @@ create_new_tube (SalutMucChannel *self,
switch (type)
{
- case SALUT_TUBE_TYPE_DBUS:
+ case TP_TUBE_TYPE_DBUS:
tube = SALUT_TUBE_IFACE (salut_tube_dbus_new (conn,
handle, TP_HANDLE_TYPE_ROOM, self_handle, priv->muc_connection,
initiator, service, parameters, tube_id, requested));
break;
- case SALUT_TUBE_TYPE_STREAM:
+ case TP_TUBE_TYPE_STREAM:
tube = SALUT_TUBE_IFACE (salut_tube_stream_new (conn,
handle, TP_HANDLE_TYPE_ROOM,
self_handle, initiator, FALSE, service,
@@ -1729,7 +1729,7 @@ salut_muc_channel_tube_request (SalutMucChannel *self,
const gchar *service;
GHashTable *parameters = NULL;
guint64 tube_id;
- SalutTubeType type;
+ TpTubeType type;
tube_id = generate_tube_id (self);
@@ -1738,14 +1738,14 @@ salut_muc_channel_tube_request (SalutMucChannel *self,
if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE))
{
- type = SALUT_TUBE_TYPE_STREAM;
+ type = TP_TUBE_TYPE_STREAM;
service = tp_asv_get_string (request_properties,
TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SERVICE);
}
else if (! tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE))
{
- type = SALUT_TUBE_TYPE_DBUS;
+ type = TP_TUBE_TYPE_DBUS;
service = tp_asv_get_string (request_properties,
TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME);
}
diff --git a/src/muc-manager.c b/src/muc-manager.c
index db4978e1..41cd3438 100644
--- a/src/muc-manager.c
+++ b/src/muc-manager.c
@@ -360,12 +360,12 @@ salut_muc_manager_type_foreach_channel_class (GType type,
g_hash_table_insert (table, TP_IFACE_CHANNEL ".TargetHandleType",
handle_type_value);
- /* im.telepathy1.Channel.Type.Text */
+ /* org.freedesktop.Telepathy.Channel.Type.Text */
g_value_set_static_string (channel_type_value, TP_IFACE_CHANNEL_TYPE_TEXT);
func (type, table, muc_channel_allowed_properties,
user_data);
- /* im.telepathy1.Channel.Type.StreamTube */
+ /* org.freedesktop.Telepathy.Channel.Type.StreamTube */
g_value_set_static_string (channel_type_value,
TP_IFACE_CHANNEL_TYPE_STREAM_TUBE);
func (type, table, salut_tube_stream_channel_get_allowed_properties (),
@@ -1108,6 +1108,11 @@ invite_stanza_callback (WockyPorter *porter,
/* FIXME handle properly */
g_assert (chan != NULL);
+#ifdef ENABLE_OLPC
+ salut_connection_olpc_observe_invitation (priv->connection, room_handle,
+ inviter_handle, invite);
+#endif
+
salut_muc_channel_invited (chan, inviter_handle, reason, NULL);
return TRUE;
diff --git a/src/muc-tube-dbus.c b/src/muc-tube-dbus.c
index 3054885e..5d639f40 100644
--- a/src/muc-tube-dbus.c
+++ b/src/muc-tube-dbus.c
@@ -21,8 +21,6 @@
#include "muc-tube-dbus.h"
-#include <telepathy-glib/telepathy-glib-dbus.h>
-
G_DEFINE_TYPE (SalutMucTubeDBus, salut_muc_tube_dbus,
SALUT_TYPE_TUBE_DBUS)
diff --git a/src/muc-tube-stream.c b/src/muc-tube-stream.c
index f66a96fe..8155b9c2 100644
--- a/src/muc-tube-stream.c
+++ b/src/muc-tube-stream.c
@@ -21,8 +21,6 @@
#include "muc-tube-stream.h"
-#include <telepathy-glib/telepathy-glib-dbus.h>
-
G_DEFINE_TYPE (SalutMucTubeStream, salut_muc_tube_stream,
SALUT_TYPE_TUBE_STREAM)
diff --git a/src/namespaces.h b/src/namespaces.h
index fdc1bdd4..dd634185 100644
--- a/src/namespaces.h
+++ b/src/namespaces.h
@@ -86,6 +86,12 @@
#define NS_MUC_OWNER "http://jabber.org/protocol/muc#owner"
#define NS_NICK "http://jabber.org/protocol/nick"
#define NS_OOB "jabber:iq:oob"
+#define NS_OLPC_BUDDY_PROPS "http://laptop.org/xmpp/buddy-properties"
+#define NS_OLPC_ACTIVITIES "http://laptop.org/xmpp/activities"
+#define NS_OLPC_CURRENT_ACTIVITY "http://laptop.org/xmpp/current-activity"
+#define NS_OLPC_ACTIVITY_PROPS "http://laptop.org/xmpp/activity-properties"
+#define NS_OLPC_BUDDY "http://laptop.org/xmpp/buddy"
+#define NS_OLPC_ACTIVITY "http://laptop.org/xmpp/activity"
#define NS_PUBSUB "http://jabber.org/protocol/pubsub"
#define NS_PRESENCE_INVISIBLE "presence-invisible"
#define NS_PRIVACY "jabber:iq:privacy"
@@ -109,6 +115,8 @@
#define NS_TEMPPRES "urn:xmpp:temppres:0"
#define NS_GOOGLE_SHARED_STATUS "google:shared-status"
+#define NS_OLPC_ACTIVITY_PROPS "http://laptop.org/xmpp/activity-properties"
+
#define NS_TP_FT_METADATA_SERVICE "http://telepathy.freedesktop.org/xmpp/file-transfer-service"
#define NS_TP_FT_METADATA "http://telepathy.freedesktop.org/xmpp/file-transfer-metadata"
diff --git a/src/olpc-activity-manager.c b/src/olpc-activity-manager.c
new file mode 100644
index 00000000..459d4c92
--- /dev/null
+++ b/src/olpc-activity-manager.c
@@ -0,0 +1,349 @@
+/*
+ * olpc-activity-manager.c - Source for SalutOlpcActivityManager
+ * Copyright (C) 2008 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "olpc-activity-manager.h"
+
+#include <dbus/dbus-glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "connection.h"
+
+#define DEBUG_FLAG DEBUG_OLPC_ACTIVITY
+#include "debug.h"
+
+G_DEFINE_TYPE (SalutOlpcActivityManager, salut_olpc_activity_manager,
+ G_TYPE_OBJECT);
+
+/* properties */
+enum {
+ PROP_CONNECTION = 1,
+ LAST_PROP
+};
+
+/* signal enum */
+enum
+{
+ ACTIVITY_MODIFIED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = {0};
+
+/* private structure */
+typedef struct _SalutOlpcActivityManagerPrivate SalutOlpcActivityManagerPrivate;
+
+struct _SalutOlpcActivityManagerPrivate
+{
+ /* TpHandle (owned by the activity) => SalutOlpcActivity */
+ GHashTable *activities_by_room;
+
+ gboolean dispose_has_run;
+};
+
+#define SALUT_OLPC_ACTIVITY_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SALUT_TYPE_OLPC_ACTIVITY_MANAGER, SalutOlpcActivityManagerPrivate))
+
+static void
+salut_olpc_activity_manager_init (SalutOlpcActivityManager *self)
+{
+ SalutOlpcActivityManagerPrivate *priv =
+ SALUT_OLPC_ACTIVITY_MANAGER_GET_PRIVATE (self);
+ /* We just keep a weak reference on the activity object so we'll remove
+ * it from the hash when no one is using anymore */
+ priv->activities_by_room = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal, NULL, NULL);
+}
+
+static void
+salut_olpc_activity_manager_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ SalutOlpcActivityManager *self = SALUT_OLPC_ACTIVITY_MANAGER (object);
+
+ switch (property_id)
+ {
+ case PROP_CONNECTION:
+ g_value_set_object (value, self->connection);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+salut_olpc_activity_manager_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ SalutOlpcActivityManager *self = SALUT_OLPC_ACTIVITY_MANAGER (object);
+
+ switch (property_id)
+ {
+ case PROP_CONNECTION:
+ self->connection = g_value_get_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void salut_olpc_activity_manager_dispose (GObject *object);
+static void salut_olpc_activity_manager_finalize (GObject *object);
+
+static void
+salut_olpc_activity_manager_class_init (SalutOlpcActivityManagerClass *salut_olpc_activity_manager_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (salut_olpc_activity_manager_class);
+ GParamSpec *param_spec;
+
+ g_type_class_add_private (salut_olpc_activity_manager_class,
+ sizeof (SalutOlpcActivityManagerPrivate));
+
+ object_class->get_property = salut_olpc_activity_manager_get_property;
+ object_class->set_property = salut_olpc_activity_manager_set_property;
+
+ object_class->dispose = salut_olpc_activity_manager_dispose;
+ object_class->finalize = salut_olpc_activity_manager_finalize;
+
+ param_spec = g_param_spec_object (
+ "connection",
+ "SalutConnection object",
+ "The Salut Connection associated with this muc manager",
+ SALUT_TYPE_CONNECTION,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_CONNECTION,
+ param_spec);
+
+ signals[ACTIVITY_MODIFIED] = g_signal_new ("activity-modified",
+ G_OBJECT_CLASS_TYPE (salut_olpc_activity_manager_class),
+ G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 1, SALUT_TYPE_OLPC_ACTIVITY);
+}
+
+static gboolean
+remove_activity_foreach (gpointer room,
+ gpointer act,
+ gpointer activity)
+{
+ return act == activity;
+}
+
+static void
+activity_finalized_cb (gpointer data,
+ GObject *activity)
+{
+ SalutOlpcActivityManager *self = SALUT_OLPC_ACTIVITY_MANAGER (data);
+ SalutOlpcActivityManagerPrivate *priv =
+ SALUT_OLPC_ACTIVITY_MANAGER_GET_PRIVATE (self);
+
+ g_hash_table_foreach_remove (priv->activities_by_room,
+ remove_activity_foreach, activity);
+}
+
+static gboolean
+dispose_activity_foreach (gpointer room,
+ gpointer activity,
+ gpointer user_data)
+{
+ SalutOlpcActivityManager *self = SALUT_OLPC_ACTIVITY_MANAGER (user_data);
+
+ g_object_weak_unref (G_OBJECT (activity), activity_finalized_cb, self);
+ g_signal_handlers_disconnect_matched (activity, G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL, NULL, self);
+
+ return TRUE;
+}
+
+static void
+salut_olpc_activity_manager_dispose (GObject *object)
+{
+ SalutOlpcActivityManager *self = SALUT_OLPC_ACTIVITY_MANAGER (object);
+ SalutOlpcActivityManagerPrivate *priv = SALUT_OLPC_ACTIVITY_MANAGER_GET_PRIVATE (self);
+
+ if (priv->dispose_has_run)
+ return;
+
+ priv->dispose_has_run = TRUE;
+
+ if (priv->activities_by_room != NULL)
+ {
+ g_hash_table_foreach_remove (priv->activities_by_room,
+ dispose_activity_foreach, self);
+ g_hash_table_unref (priv->activities_by_room);
+ priv->activities_by_room = NULL;
+ }
+
+ if (G_OBJECT_CLASS (salut_olpc_activity_manager_parent_class)->dispose)
+ G_OBJECT_CLASS (salut_olpc_activity_manager_parent_class)->dispose (object);
+}
+
+static void
+salut_olpc_activity_manager_finalize (GObject *object)
+{
+ //SalutOlpcActivityManager *self = SALUT_OLPC_ACTIVITY_MANAGER (object);
+
+ G_OBJECT_CLASS (salut_olpc_activity_manager_parent_class)->finalize (object);
+}
+
+gboolean
+salut_olpc_activity_manager_start (SalutOlpcActivityManager *self,
+ GError **error)
+{
+ return SALUT_OLPC_ACTIVITY_MANAGER_GET_CLASS (self)->start (self, error);
+}
+
+SalutOlpcActivity *
+salut_olpc_activity_manager_get_activity_by_room (SalutOlpcActivityManager *self,
+ TpHandle room)
+{
+ SalutOlpcActivityManagerPrivate *priv =
+ SALUT_OLPC_ACTIVITY_MANAGER_GET_PRIVATE (self);
+ return g_hash_table_lookup (priv->activities_by_room,
+ GUINT_TO_POINTER (room));
+}
+
+SalutOlpcActivity *
+salut_olpc_activity_manager_get_activity_by_id (SalutOlpcActivityManager *self,
+ const gchar *activity_id)
+{
+ SalutOlpcActivityManagerPrivate *priv =
+ SALUT_OLPC_ACTIVITY_MANAGER_GET_PRIVATE (self);
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_hash_table_iter_init (&iter, priv->activities_by_room);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ SalutOlpcActivity *activity = value;
+ if (strcmp (activity->id, activity_id) == 0)
+ return activity;
+ }
+
+ return NULL;
+}
+
+SalutOlpcActivity *
+salut_olpc_activity_manager_ensure_activity_by_room (
+ SalutOlpcActivityManager *self,
+ TpHandle room)
+{
+ SalutOlpcActivity *activity;
+ SalutOlpcActivityManagerPrivate *priv =
+ SALUT_OLPC_ACTIVITY_MANAGER_GET_PRIVATE (self);
+
+ activity = g_hash_table_lookup (priv->activities_by_room,
+ GUINT_TO_POINTER (room));
+
+ if (activity != NULL)
+ {
+ return g_object_ref (activity);
+ }
+ else
+ {
+ activity = salut_olpc_activity_manager_create_activity (self, room);
+ return activity;
+ }
+}
+
+static void
+activity_modified_cb (SalutOlpcActivity *activity,
+ SalutOlpcActivityManager *self)
+{
+ g_signal_emit (self, signals[ACTIVITY_MODIFIED], 0, activity);
+}
+
+SalutOlpcActivity *
+salut_olpc_activity_manager_create_activity (SalutOlpcActivityManager *self,
+ TpHandle room)
+{
+ SalutOlpcActivity *activity;
+ SalutOlpcActivityManagerPrivate *priv =
+ SALUT_OLPC_ACTIVITY_MANAGER_GET_PRIVATE (self);
+
+ g_assert (room != 0);
+ g_assert (g_hash_table_lookup (priv->activities_by_room, GUINT_TO_POINTER (
+ room)) == NULL);
+
+ activity = SALUT_OLPC_ACTIVITY_MANAGER_GET_CLASS (self)->create_activity (
+ self);
+ salut_olpc_activity_update (activity, room, NULL, NULL, NULL, NULL, NULL,
+ TRUE);
+
+ g_hash_table_insert (priv->activities_by_room, GUINT_TO_POINTER (room),
+ activity);
+
+ g_signal_connect (activity, "modified", G_CALLBACK (activity_modified_cb),
+ self);
+ g_object_weak_ref (G_OBJECT (activity), activity_finalized_cb , self);
+
+ return activity;
+}
+
+SalutOlpcActivity *
+salut_olpc_activity_manager_got_invitation (SalutOlpcActivityManager *self,
+ TpHandle room,
+ SalutContact *inviter,
+ const gchar *id,
+ const gchar *name,
+ const gchar *type,
+ const gchar *color,
+ const gchar *tags)
+{
+ SalutOlpcActivity *activity;
+
+ activity = salut_olpc_activity_manager_ensure_activity_by_room (self, room);
+
+ salut_olpc_activity_update (activity, room, id, name, type, color, tags,
+ activity->is_private);
+
+ /* FIXME: we shouldn't add it if the local user is already in the activity
+ * as, for now, we don't manage private activity membership (it's PS job) */
+
+ /* add the inviter to the activity */
+ salut_contact_joined_activity (inviter, activity);
+
+ /* contact reffed the activity if it didn't hold a ref on it yet */
+ g_object_unref (activity);
+
+ return activity;
+}
+
+void
+salut_olpc_activity_manager_contact_joined (SalutOlpcActivityManager *self,
+ SalutContact *contact,
+ SalutOlpcActivity *activity)
+{
+ salut_contact_joined_activity (contact, activity);
+}
+
+void
+salut_olpc_activity_manager_contact_left (SalutOlpcActivityManager *mgr,
+ SalutContact *contact,
+ SalutOlpcActivity *activity)
+{
+ salut_contact_left_activity (contact, activity);
+}
diff --git a/src/olpc-activity-manager.h b/src/olpc-activity-manager.h
new file mode 100644
index 00000000..1814d1cf
--- /dev/null
+++ b/src/olpc-activity-manager.h
@@ -0,0 +1,98 @@
+/*
+ * olpc-activity-managere.h - Header for SalutOlpcActivityManager
+ * Copyright (C) 2008 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __SALUT_OLPC_ACTIVITY_MANAGER_H__
+#define __SALUT_OLPC_ACTIVITY_MANAGER_H__
+
+#include <glib-object.h>
+
+#include <telepathy-glib/telepathy-glib.h>
+
+#include "connection.h"
+#include "contact.h"
+#include "olpc-activity.h"
+
+G_BEGIN_DECLS
+
+typedef struct _SalutOlpcActivityManager SalutOlpcActivityManager;
+typedef struct _SalutOlpcActivityManagerClass SalutOlpcActivityManagerClass;
+
+struct _SalutOlpcActivityManagerClass {
+ GObjectClass parent_class;
+
+ /* public abstract methods */
+ gboolean (*start) (SalutOlpcActivityManager *self, GError **error);
+
+ /* private abstract methods */
+ SalutOlpcActivity * (*create_activity) (SalutOlpcActivityManager *self);
+};
+
+struct _SalutOlpcActivityManager {
+ GObject parent;
+
+ /* private */
+ SalutConnection *connection;
+};
+
+GType salut_olpc_activity_manager_get_type (void);
+
+/* TYPE MACROS */
+#define SALUT_TYPE_OLPC_ACTIVITY_MANAGER \
+ (salut_olpc_activity_manager_get_type ())
+#define SALUT_OLPC_ACTIVITY_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), SALUT_TYPE_OLPC_ACTIVITY_MANAGER, SalutOlpcActivityManager))
+#define SALUT_OLPC_ACTIVITY_MANAGER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), SALUT_TYPE_OLPC_ACTIVITY_MANAGER, SalutOlpcActivityManagerClass))
+#define SALUT_IS_OLPC_ACTIVITY_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), SALUT_TYPE_OLPC_ACTIVITY_MANAGER))
+#define SALUT_IS_OLPC_ACTIVITY_MANAGER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), SALUT_TYPE_OLPC_ACTIVITY_MANAGER))
+#define SALUT_OLPC_ACTIVITY_MANAGER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), SALUT_TYPE_OLPC_ACTIVITY_MANAGER, SalutOlpcActivityManagerClass))
+
+gboolean salut_olpc_activity_manager_start (SalutOlpcActivityManager *mgr,
+ GError **error);
+
+SalutOlpcActivity * salut_olpc_activity_manager_get_activity_by_room (
+ SalutOlpcActivityManager *mgr, TpHandle room);
+
+SalutOlpcActivity * salut_olpc_activity_manager_get_activity_by_id (
+ SalutOlpcActivityManager *mgr, const gchar *activity_id);
+
+SalutOlpcActivity * salut_olpc_activity_manager_ensure_activity_by_room (
+ SalutOlpcActivityManager *mgr, TpHandle room);
+
+SalutOlpcActivity * salut_olpc_activity_manager_got_invitation (
+ SalutOlpcActivityManager *mgr, TpHandle room, SalutContact *inviter,
+ const gchar *id, const gchar *name, const gchar *type, const gchar *color,
+ const gchar *tags);
+
+/* restricted methods */
+SalutOlpcActivity * salut_olpc_activity_manager_create_activity (
+ SalutOlpcActivityManager *mgr, TpHandle room);
+
+void salut_olpc_activity_manager_contact_joined (SalutOlpcActivityManager *mgr,
+ SalutContact *contact, SalutOlpcActivity *activity);
+
+void salut_olpc_activity_manager_contact_left (SalutOlpcActivityManager *mgr,
+ SalutContact *contact, SalutOlpcActivity *activity);
+
+G_END_DECLS
+
+#endif /* #ifndef __SALUT_OLPC_ACTIVITY_MANAGER_H__*/
diff --git a/src/olpc-activity.c b/src/olpc-activity.c
new file mode 100644
index 00000000..b834d56f
--- /dev/null
+++ b/src/olpc-activity.c
@@ -0,0 +1,680 @@
+/*
+ * olpc-activity.c - Source for SalutOlpcActivity
+ * Copyright (C) 2008 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "olpc-activity.h"
+
+#include <dbus/dbus-glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <wocky/wocky.h>
+
+#include "contact-manager.h"
+#include "muc-manager.h"
+#include "util.h"
+#include "namespaces.h"
+
+#define DEBUG_FLAG DEBUG_OLPC_ACTIVITY
+#include "debug.h"
+
+G_DEFINE_TYPE (SalutOlpcActivity, salut_olpc_activity, G_TYPE_OBJECT);
+
+/* properties */
+enum {
+ PROP_CONNECTION = 1,
+ LAST_PROP
+};
+
+/* signal enum */
+enum
+{
+ MODIFIED,
+ VALID,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = {0};
+
+/* private structure */
+typedef struct _SalutOlpcActivityPrivate SalutOlpcActivityPrivate;
+
+struct _SalutOlpcActivityPrivate
+{
+ /* Handles of contacts we invited to join this activity */
+ TpHandleSet *invited;
+ /* can be NULL if we are not in the activity */
+ SalutMucChannel *muc;
+
+ gboolean dispose_has_run;
+};
+
+#define SALUT_OLPC_ACTIVITY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SALUT_TYPE_OLPC_ACTIVITY, SalutOlpcActivityPrivate))
+
+static void
+salut_olpc_activity_init (SalutOlpcActivity *self)
+{
+ self->connection = NULL;
+
+ self->is_private = TRUE;
+}
+
+static void
+salut_olpc_activity_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ SalutOlpcActivity *self = SALUT_OLPC_ACTIVITY (object);
+
+ switch (property_id)
+ {
+ case PROP_CONNECTION:
+ g_value_set_object (value, self->connection);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+salut_olpc_activity_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ SalutOlpcActivity *self = SALUT_OLPC_ACTIVITY (object);
+
+ switch (property_id)
+ {
+ case PROP_CONNECTION:
+ self->connection = g_value_get_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static GObject *
+salut_olpc_activity_constructor (GType type,
+ guint n_props,
+ GObjectConstructParam *props)
+{
+ GObject *obj;
+ SalutOlpcActivity *self;
+ SalutOlpcActivityPrivate *priv;
+ TpHandleRepoIface *contact_repo;
+
+ obj = G_OBJECT_CLASS (salut_olpc_activity_parent_class)->
+ constructor (type, n_props, props);
+
+ self = SALUT_OLPC_ACTIVITY (obj);
+ priv = SALUT_OLPC_ACTIVITY_GET_PRIVATE (self);
+
+ g_assert (self->connection != NULL);
+ contact_repo = tp_base_connection_get_handles (
+ (TpBaseConnection *) self->connection, TP_HANDLE_TYPE_CONTACT);
+
+ priv->invited = tp_handle_set_new (contact_repo);
+
+ return obj;
+}
+
+static void salut_olpc_activity_dispose (GObject *object);
+static void salut_olpc_activity_finalize (GObject *object);
+
+static void
+salut_olpc_activity_class_init (SalutOlpcActivityClass *salut_olpc_activity_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (salut_olpc_activity_class);
+ GParamSpec *param_spec;
+
+ g_type_class_add_private (salut_olpc_activity_class,
+ sizeof (SalutOlpcActivityPrivate));
+
+ object_class->get_property = salut_olpc_activity_get_property;
+ object_class->set_property = salut_olpc_activity_set_property;
+
+ object_class->constructor = salut_olpc_activity_constructor;
+ object_class->dispose = salut_olpc_activity_dispose;
+ object_class->finalize = salut_olpc_activity_finalize;
+
+ param_spec = g_param_spec_object (
+ "connection",
+ "SalutConnection object",
+ "The Salut Connection associated with this muc manager",
+ SALUT_TYPE_CONNECTION,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_CONNECTION,
+ param_spec);
+
+ signals[MODIFIED] = g_signal_new ("modified",
+ G_OBJECT_CLASS_TYPE (salut_olpc_activity_class),
+ G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
+
+ signals[VALID] = g_signal_new ("valid",
+ G_OBJECT_CLASS_TYPE (salut_olpc_activity_class),
+ G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
+}
+
+static void
+salut_olpc_activity_dispose (GObject *object)
+{
+ SalutOlpcActivity *self = SALUT_OLPC_ACTIVITY (object);
+ SalutOlpcActivityPrivate *priv = SALUT_OLPC_ACTIVITY_GET_PRIVATE (self);
+
+ if (priv->dispose_has_run)
+ return;
+
+ priv->dispose_has_run = TRUE;
+
+ if (priv->muc != NULL)
+ {
+ g_signal_handlers_disconnect_matched (priv->muc, G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL, NULL, self);
+ g_object_unref (priv->muc);
+ priv->muc = NULL;
+ }
+
+ tp_handle_set_destroy (priv->invited);
+
+ if (G_OBJECT_CLASS (salut_olpc_activity_parent_class)->dispose)
+ G_OBJECT_CLASS (salut_olpc_activity_parent_class)->dispose (object);
+}
+
+static void
+salut_olpc_activity_finalize (GObject *object)
+{
+ SalutOlpcActivity *self = SALUT_OLPC_ACTIVITY (object);
+
+ g_free (self->id);
+ g_free (self->name);
+ g_free (self->type);
+ g_free (self->color);
+ g_free (self->tags);
+
+ G_OBJECT_CLASS (salut_olpc_activity_parent_class)->finalize (object);
+}
+
+GHashTable *
+salut_olpc_activity_create_properties_table (SalutOlpcActivity *self)
+{
+ GHashTable *properties;
+ GValue *val;
+
+ properties = g_hash_table_new_full (g_str_hash, g_str_equal,
+ NULL, (GDestroyNotify) tp_g_value_slice_free);
+
+ if (self->color != NULL)
+ {
+ val = tp_g_value_slice_new (G_TYPE_STRING);
+ g_value_set_static_string (val, self->color);
+ g_hash_table_insert (properties, "color", val);
+ }
+
+ if (self->name != NULL)
+ {
+ val = tp_g_value_slice_new (G_TYPE_STRING);
+ g_value_set_static_string (val, self->name);
+ g_hash_table_insert (properties, "name", val);
+ }
+
+ if (self->type != NULL)
+ {
+ val = tp_g_value_slice_new (G_TYPE_STRING);
+ g_value_set_static_string (val, self->type);
+ g_hash_table_insert (properties, "type", val);
+ }
+
+ if (self->tags != NULL)
+ {
+ val = tp_g_value_slice_new (G_TYPE_STRING);
+ g_value_set_static_string (val, self->tags);
+ g_hash_table_insert (properties, "tags", val);
+ }
+
+ val = tp_g_value_slice_new (G_TYPE_BOOLEAN);
+ g_value_set_boolean (val, self->is_private);
+ g_hash_table_insert (properties, "private", val);
+
+ return properties;
+}
+
+static gboolean
+send_properties_change_msg (SalutOlpcActivity *self,
+ GError **error)
+{
+ SalutOlpcActivityPrivate *priv = SALUT_OLPC_ACTIVITY_GET_PRIVATE (self);
+ GHashTable *properties;
+ GValue *activity_id_val;
+ WockyStanza *stanza;
+ WockyNode *top_node;
+ WockyNode *properties_node;
+ gchar *muc_name;
+ GibberMucConnection *muc_connection;
+ gboolean result;
+ GError *err = NULL;
+
+ if (priv->muc == NULL)
+ /* we are not in the muc */
+ return TRUE;
+
+ g_object_get (priv->muc,
+ "name", &muc_name,
+ "muc-connection", &muc_connection,
+ NULL);
+
+ if (muc_connection->state != GIBBER_MUC_CONNECTION_CONNECTED)
+ {
+ DEBUG ("Muc connection not connected yet. Drop activity change message");
+ g_object_unref (muc_connection);
+ g_free (muc_name);
+ return TRUE;
+ }
+
+ properties = salut_olpc_activity_create_properties_table (self);
+
+ /* add the activity id */
+ activity_id_val = g_slice_new0 (GValue);
+ g_value_init (activity_id_val, G_TYPE_STRING);
+ g_value_set_static_string (activity_id_val, self->id);
+ g_hash_table_insert (properties, "id", activity_id_val);
+
+ stanza = wocky_stanza_build (WOCKY_STANZA_TYPE_MESSAGE,
+ WOCKY_STANZA_SUB_TYPE_GROUPCHAT,
+ self->connection->name, muc_name,
+ WOCKY_NODE_START, "properties",
+ WOCKY_NODE_XMLNS, NS_OLPC_ACTIVITY_PROPS,
+ WOCKY_NODE_END, NULL);
+ top_node = wocky_stanza_get_top_node (stanza);
+
+ properties_node = wocky_node_get_child_ns (top_node, "properties",
+ NS_OLPC_ACTIVITY_PROPS);
+
+ salut_wocky_node_add_children_from_properties (properties_node,
+ properties, "property");
+
+ result = gibber_muc_connection_send (muc_connection, stanza, &err);
+ if (!result)
+ {
+ g_set_error (error, TP_ERROR, TP_ERROR_NETWORK_ERROR, "%s",
+ err->message);
+ g_error_free (err);
+ }
+
+ g_object_unref (stanza);
+ g_object_unref (muc_connection);
+ g_free (muc_name);
+ g_hash_table_unref (properties);
+
+ return result;
+}
+
+static void
+resend_invite_foreach (TpHandleSet *set,
+ TpHandle handle,
+ SalutOlpcActivity *self)
+{
+ SalutOlpcActivityPrivate *priv = SALUT_OLPC_ACTIVITY_GET_PRIVATE (self);
+ GError *error = NULL;
+
+ if (!salut_muc_channel_send_invitation (priv->muc, handle,
+ "OLPC activity properties update", &error))
+ {
+ DEBUG ("failed to re-invite contact %d to activity %s", handle,
+ self->id);
+ }
+}
+
+static void
+resend_invite (SalutOlpcActivity *self)
+{
+ SalutOlpcActivityPrivate *priv = SALUT_OLPC_ACTIVITY_GET_PRIVATE (self);
+
+ if (priv->muc == NULL)
+ /* we are not in the muc */
+ return;
+
+ /* Resend pending invitations so contacts will know about new properties */
+ tp_handle_set_foreach (priv->invited,
+ (TpHandleSetMemberFunc) resend_invite_foreach, self);
+}
+
+static void
+activity_changed (SalutOlpcActivity *self)
+{
+ SalutOlpcActivityPrivate *priv = SALUT_OLPC_ACTIVITY_GET_PRIVATE (self);
+ GError *error = NULL;
+
+ if (!send_properties_change_msg (self, &error))
+ {
+ DEBUG ("send properties changes msg failed: %s", error->message);
+ g_error_free (error);
+ error = NULL;
+ }
+
+ if (!self->is_private && priv->muc != NULL)
+ {
+ /* update announcement */
+ if (!SALUT_OLPC_ACTIVITY_GET_CLASS (self)->update (self, &error))
+ {
+ DEBUG ("update activity failed: %s", error->message);
+ g_error_free (error);
+ }
+ }
+ else
+ {
+ resend_invite (self);
+ }
+}
+
+static gboolean
+salut_olpc_activity_announce (SalutOlpcActivity *self,
+ GError **error)
+{
+ GError *err = NULL;
+
+ if (!SALUT_OLPC_ACTIVITY_GET_CLASS (self)->announce (self, &err))
+ {
+ g_set_error (error, TP_ERROR, TP_ERROR_NETWORK_ERROR, "%s",
+ err->message);
+ g_error_free (err);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+salut_olpc_activity_stop_announce (SalutOlpcActivity *self)
+{
+ SALUT_OLPC_ACTIVITY_GET_CLASS (self)->stop_announce (self);
+}
+
+gboolean
+salut_olpc_activity_update (SalutOlpcActivity *self,
+ TpHandle room,
+ const gchar *id,
+ const gchar *name,
+ const gchar *type,
+ const gchar *color,
+ const gchar *tags,
+ gboolean is_private)
+{
+ SalutOlpcActivityPrivate *priv = SALUT_OLPC_ACTIVITY_GET_PRIVATE (self);
+ gboolean changed = FALSE;
+ GError *error = NULL;
+ gboolean become_valid = FALSE;
+
+ if (room != 0 && room != self->room)
+ {
+ self->room = room;
+ }
+
+ if (id != NULL && tp_strdiff (id, self->id))
+ {
+ if (self->id == NULL)
+ become_valid = TRUE;
+
+ g_free (self->id);
+ self->id = g_strdup (id);
+ changed = TRUE;
+ }
+
+ if (name != NULL && tp_strdiff (name, self->name))
+ {
+ g_free (self->name);
+ self->name = g_strdup (name);
+ changed = TRUE;
+ }
+
+ if (type != NULL && tp_strdiff (type, self->type))
+ {
+ g_free (self->type);
+ self->type = g_strdup (type);
+ changed = TRUE;
+ }
+
+ if (color != NULL && tp_strdiff (color, self->color))
+ {
+ g_free (self->color);
+ self->color = g_strdup (color);
+ changed = TRUE;
+ }
+
+ if (tp_strdiff (tags, self->tags))
+ {
+ g_free (self->tags);
+ self->tags = g_strdup (tags);
+ changed = TRUE;
+ }
+
+ if (is_private != self->is_private)
+ {
+ self->is_private = is_private;
+ changed = TRUE;
+
+ if (priv->muc != NULL)
+ {
+ if (is_private)
+ {
+ DEBUG ("activity is not public anymore. Stop to announce it");
+ salut_olpc_activity_stop_announce (self);
+ }
+ else
+ {
+ DEBUG ("activity becomes public. Announce it");
+ if (!salut_olpc_activity_announce (self, &error))
+ {
+ DEBUG ("activity announce failed: %s", error->message);
+ g_error_free (error);
+ error = NULL;
+ }
+ }
+ }
+ }
+
+ if (become_valid)
+ {
+ g_signal_emit (self, signals[VALID], 0);
+ }
+
+ if (changed)
+ {
+ activity_changed (self);
+
+ g_signal_emit (self, signals[MODIFIED], 0);
+ }
+
+ return changed;
+}
+
+static void
+muc_channel_closed_cb (SalutMucChannel *chan,
+ SalutOlpcActivity *self)
+{
+ SalutOlpcActivityPrivate *priv = SALUT_OLPC_ACTIVITY_GET_PRIVATE (self);
+
+ g_object_unref (priv->muc);
+ priv->muc = NULL;
+}
+
+gboolean
+salut_olpc_activity_joined (SalutOlpcActivity *self,
+ GError **error)
+{
+ SalutOlpcActivityPrivate *priv = SALUT_OLPC_ACTIVITY_GET_PRIVATE (self);
+ TpHandleRepoIface *room_repo;
+ SalutMucManager *muc_manager;
+
+ if (priv->muc != NULL)
+ return TRUE;
+
+ room_repo = tp_base_connection_get_handles (
+ (TpBaseConnection *) self->connection, TP_HANDLE_TYPE_ROOM);
+
+ g_object_get (self->connection,
+ "muc-manager", &muc_manager,
+ NULL);
+
+ priv->muc = salut_muc_manager_get_text_channel (muc_manager, self->room);
+ g_object_unref (muc_manager);
+
+ if (priv->muc == NULL)
+ {
+ g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "Can't find muc channel for room %s", tp_handle_inspect (
+ room_repo, self->room));
+ return FALSE;
+ }
+
+ if (!self->is_private)
+ {
+ /* This might fail but that doesn't prevent us from joining the
+ * activity.. */
+ salut_olpc_activity_announce (self, NULL);
+ }
+
+ g_signal_connect (priv->muc, "closed", G_CALLBACK (muc_channel_closed_cb),
+ self);
+
+ return TRUE;
+}
+
+void
+salut_olpc_activity_left (SalutOlpcActivity *self)
+{
+ SalutOlpcActivityPrivate *priv = SALUT_OLPC_ACTIVITY_GET_PRIVATE (self);
+
+ if (priv->muc == NULL)
+ return;
+
+ if (!self->is_private)
+ salut_olpc_activity_stop_announce (self);
+
+ g_object_unref (priv->muc);
+ g_signal_handlers_disconnect_matched (priv->muc, G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL, NULL, self);
+ priv->muc = NULL;
+}
+
+void
+salut_olpc_activity_revoke_invitations (SalutOlpcActivity *self)
+{
+ SalutOlpcActivityPrivate *priv = SALUT_OLPC_ACTIVITY_GET_PRIVATE (self);
+ WockyStanza *msg;
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
+ (TpBaseConnection *) self->connection, TP_HANDLE_TYPE_CONTACT);
+ TpHandleRepoIface *room_repo = tp_base_connection_get_handles (
+ (TpBaseConnection *) self->connection, TP_HANDLE_TYPE_CONTACT);
+ TpIntsetFastIter iter;
+ guint contact_handle;
+ SalutContactManager *contact_mgr;
+ WockyNode *top_node;
+
+ if (tp_handle_set_size (priv->invited) <= 0)
+ return;
+
+ msg = wocky_stanza_build (WOCKY_STANZA_TYPE_MESSAGE,
+ WOCKY_STANZA_SUB_TYPE_NONE,
+ self->connection->name, NULL,
+ WOCKY_NODE_START, "uninvite",
+ WOCKY_NODE_XMLNS, NS_OLPC_ACTIVITY_PROPS,
+ WOCKY_NODE_ATTRIBUTE, "room", tp_handle_inspect (room_repo,
+ self->room),
+ WOCKY_NODE_ATTRIBUTE, "id", self->id,
+ WOCKY_NODE_END, NULL);
+ top_node = wocky_stanza_get_top_node (msg);
+
+ g_object_get (self->connection,
+ "contact-manager", &contact_mgr,
+ NULL);
+ g_assert (contact_mgr != NULL);
+
+ tp_intset_fast_iter_init (&iter, tp_handle_set_peek (priv->invited));
+
+ DEBUG ("revoke invitations for activity %s", self->id);
+ while (tp_intset_fast_iter_next (&iter, &contact_handle))
+ {
+ SalutContact *contact;
+ const gchar *to;
+
+ contact = salut_contact_manager_get_contact (contact_mgr, contact_handle);
+ if (contact == NULL)
+ {
+ DEBUG ("Can't find contact %d", contact_handle);
+ continue;
+ }
+
+ to = tp_handle_inspect (contact_repo, contact_handle);
+ wocky_node_set_attribute (top_node, "to", to);
+
+ wocky_stanza_set_to_contact (msg, WOCKY_CONTACT (contact));
+ wocky_porter_send (self->connection->porter, msg);
+
+ g_object_unref (contact);
+ }
+
+ g_object_unref (msg);
+ g_object_unref (contact_mgr);
+}
+
+void
+salut_olpc_activity_augment_invitation (SalutOlpcActivity *self,
+ TpHandle contact,
+ WockyNode *invite_node)
+{
+ SalutOlpcActivityPrivate *priv = SALUT_OLPC_ACTIVITY_GET_PRIVATE (self);
+ WockyNode *properties_node;
+ GHashTable *properties;
+ GValue *activity_id_val;
+
+ properties = salut_olpc_activity_create_properties_table (self);
+
+ properties_node = wocky_node_add_child_ns (invite_node, "properties",
+ NS_OLPC_ACTIVITY_PROPS);
+
+ /* add the activity id */
+ activity_id_val = g_slice_new0 (GValue);
+ g_value_init (activity_id_val, G_TYPE_STRING);
+ g_value_set_static_string (activity_id_val, self->id);
+ g_hash_table_insert (properties, "id", activity_id_val);
+
+ salut_wocky_node_add_children_from_properties (properties_node,
+ properties, "property");
+
+ tp_handle_set_add (priv->invited, contact);
+
+ g_hash_table_unref (properties);
+}
+
+gboolean
+salut_olpc_activity_remove_invited (SalutOlpcActivity *self,
+ TpHandle contact)
+{
+ SalutOlpcActivityPrivate *priv = SALUT_OLPC_ACTIVITY_GET_PRIVATE (self);
+
+ return tp_handle_set_remove (priv->invited, contact);
+}
diff --git a/src/olpc-activity.h b/src/olpc-activity.h
new file mode 100644
index 00000000..25e231af
--- /dev/null
+++ b/src/olpc-activity.h
@@ -0,0 +1,98 @@
+/*
+ * olpc-activity.h - Header for SalutOlpcActivity
+ * Copyright (C) 2008 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __SALUT_OLPC_ACTIVITY_H__
+#define __SALUT_OLPC_ACTIVITY_H__
+
+#include <glib-object.h>
+
+#include <telepathy-glib/telepathy-glib.h>
+
+#include "connection.h"
+
+G_BEGIN_DECLS
+
+typedef struct _SalutOlpcActivity SalutOlpcActivity;
+typedef struct _SalutOlpcActivityClass SalutOlpcActivityClass;
+
+struct _SalutOlpcActivityClass {
+ GObjectClass parent_class;
+
+ /* private abstract methods */
+ gboolean (*announce) (SalutOlpcActivity *activity, GError **error);
+ void (*stop_announce) (SalutOlpcActivity *activity);
+
+ gboolean (*update) (SalutOlpcActivity *activity, GError **error);
+};
+
+struct _SalutOlpcActivity {
+ GObject parent;
+
+ TpHandle room;
+ gchar *id;
+ gchar *name;
+ gchar *type;
+ gchar *color;
+ gchar *tags;
+ gboolean is_private;
+
+ /* private */
+ SalutConnection *connection;
+};
+
+GType salut_olpc_activity_get_type (void);
+
+/* TYPE MACROS */
+#define SALUT_TYPE_OLPC_ACTIVITY \
+ (salut_olpc_activity_get_type ())
+#define SALUT_OLPC_ACTIVITY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), SALUT_TYPE_OLPC_ACTIVITY, SalutOlpcActivity))
+#define SALUT_OLPC_ACTIVITY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), SALUT_TYPE_OLPC_ACTIVITY, SalutOlpcActivityClass))
+#define SALUT_IS_OLPC_ACTIVITY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), SALUT_TYPE_OLPC_ACTIVITY))
+#define SALUT_IS_OLPC_ACTIVITY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), SALUT_TYPE_OLPC_ACTIVITY))
+#define SALUT_OLPC_ACTIVITY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), SALUT_TYPE_OLPC_ACTIVITY, SalutOlpcActivityClass))
+
+G_END_DECLS
+
+gboolean salut_olpc_activity_update (SalutOlpcActivity *activity,
+ TpHandle room, const gchar *id, const gchar *name,
+ const gchar *type, const gchar *color, const gchar *tags,
+ gboolean is_private);
+
+gboolean salut_olpc_activity_joined (SalutOlpcActivity *activity,
+ GError **error);
+
+void salut_olpc_activity_left (SalutOlpcActivity *activity);
+
+void salut_olpc_activity_revoke_invitations (SalutOlpcActivity *activity);
+
+GHashTable * salut_olpc_activity_create_properties_table (
+ SalutOlpcActivity *activity);
+
+void salut_olpc_activity_augment_invitation (SalutOlpcActivity *activity,
+ TpHandle contact, WockyNode *invite_node);
+
+gboolean salut_olpc_activity_remove_invited (SalutOlpcActivity *activity,
+ TpHandle contact);
+
+#endif /* #ifndef __SALUT_OLPC_ACTIVITY_H__*/
diff --git a/src/presence.h b/src/presence.h
index 466af9b4..993fdf8a 100644
--- a/src/presence.h
+++ b/src/presence.h
@@ -27,6 +27,7 @@
G_BEGIN_DECLS
#define SALUT_DNSSD_CLIQUE "_clique._udp"
+#define SALUT_DNSSD_OLPC_ACTIVITY "_olpc-activity1._udp"
#define SALUT_DNSSD_PRESENCE "_presence._tcp"
/* private structure */
diff --git a/src/protocol.c b/src/protocol.c
index 1223734e..2b805c85 100644
--- a/src/protocol.c
+++ b/src/protocol.c
@@ -22,7 +22,7 @@
#include <dbus/dbus-glib.h>
#include <dbus/dbus-protocol.h>
-#include <telepathy-glib/telepathy-glib-dbus.h>
+#include <telepathy-glib/telepathy-glib.h>
#include "connection.h"
#include "contact-manager.h"
@@ -156,6 +156,7 @@ get_connection_details (TpBaseProtocol *self,
if (channel_managers != NULL)
{
GType types[] = {
+ SALUT_TYPE_CONTACT_MANAGER,
SALUT_TYPE_FT_MANAGER,
SALUT_TYPE_IM_MANAGER,
SALUT_TYPE_MUC_MANAGER,
diff --git a/src/protocol.h b/src/protocol.h
index 9b99d538..8e3b4d5b 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -63,9 +63,9 @@ GType salut_protocol_get_type (void);
SALUT_TYPE_PROTOCOL, \
SalutProtocolClass))
-#define SALUT_PROTOCOL_LOCAL_XMPP_NAME "local_xmpp"
+#define SALUT_PROTOCOL_LOCAL_XMPP_NAME "local-xmpp"
#define SALUT_PROTOCOL_LOCAL_XMPP_ENGLISH_NAME "Link-local XMPP"
-#define SALUT_PROTOCOL_LOCAL_XMPP_ICON_NAME "im-local-xmpp"
+#define SALUT_PROTOCOL_LOCAL_XMPP_ICON_NAME "im-" SALUT_PROTOCOL_LOCAL_XMPP_NAME
/**
* salut_protocol_new:
diff --git a/src/roomlist-channel.c b/src/roomlist-channel.c
index c09a643c..bdaa5c99 100644
--- a/src/roomlist-channel.c
+++ b/src/roomlist-channel.c
@@ -247,7 +247,7 @@ salut_roomlist_channel_add_room (SalutRoomlistChannel *self,
dbus_g_type_specialized_construct (TP_STRUCT_TYPE_ROOM_INFO));
dbus_g_type_struct_set (&room,
0, handle,
- 1, "im.telepathy1.Channel.Type.Text",
+ 1, "org.freedesktop.Telepathy.Channel.Type.Text",
2, keys,
G_MAXUINT);
g_ptr_array_add (priv->rooms, g_value_get_boxed (&room));
@@ -299,7 +299,7 @@ salut_roomlist_channel_remove_room (SalutRoomlistChannel *self,
* salut_roomlist_channel_get_listing_rooms
*
* Implements D-Bus method GetListingRooms
- * on interface im.telepathy1.Channel.Type.RoomList
+ * on interface org.freedesktop.Telepathy.Channel.Type.RoomList
*
* @error: Used to return a pointer to a GError detailing any error
* that occurred, D-Bus will throw the error only if this
@@ -324,7 +324,7 @@ salut_roomlist_channel_get_listing_rooms (TpSvcChannelTypeRoomList *iface,
* salut_roomlist_channel_list_rooms
*
* Implements D-Bus method ListRooms
- * on interface im.telepathy1.Channel.Type.RoomList
+ * on interface org.freedesktop.Telepathy.Channel.Type.RoomList
*
* @error: Used to return a pointer to a GError detailing any error
* that occurred, D-Bus will throw the error only if this
@@ -350,7 +350,7 @@ salut_roomlist_channel_list_rooms (TpSvcChannelTypeRoomList *iface,
* salut_roomlist_channel_stop_listing
*
* Implements D-Bus method StopListing
- * on interface im.telepathy1.Channel.Type.RoomList
+ * on interface org.freedesktop.Telepathy.Channel.Type.RoomList
*/
static void
salut_roomlist_channel_stop_listing (TpSvcChannelTypeRoomList *iface,
diff --git a/src/self.c b/src/self.c
index 775d4cc5..aeafa9bf 100644
--- a/src/self.c
+++ b/src/self.c
@@ -44,6 +44,11 @@
#include "util.h"
#include "muc-manager.h"
+#ifdef ENABLE_OLPC
+#include "olpc-activity.h"
+#include "olpc-activity-manager.h"
+#endif
+
#define DEBUG_FLAG DEBUG_SELF
#include <debug.h>
@@ -64,6 +69,10 @@ enum
PROP_JID,
PROP_EMAIL,
PROP_PUBLISHED_NAME,
+#ifdef ENABLE_OLPC
+ PROP_OLPC_KEY,
+ PROP_OLPC_COLOR
+#endif
};
/* signal enum */
@@ -82,16 +91,30 @@ struct _SalutSelfPrivate
{
SalutContactManager *contact_manager;
TpHandleRepoIface *room_repo;
+#ifdef ENABLE_OLPC
+ SalutOlpcActivityManager *olpc_activity_manager;
+#endif
GIOChannel *listener;
guint io_watch_in;
+#ifdef ENABLE_OLPC
+ /* room handle owned by the SalutOlpcActivity -> SalutOlpcActivity */
+ GHashTable *olpc_activities;
+#endif
+
GabbleCapabilitySet *caps;
GPtrArray *data_forms;
gboolean dispose_has_run;
};
+#ifdef ENABLE_OLPC
+void
+contact_manager_contact_change_cb (SalutContactManager *mgr,
+ SalutContact *contact, int changes, gpointer user_data);
+#endif
+
static void
salut_self_init (SalutSelf *obj)
{
@@ -104,12 +127,22 @@ salut_self_init (SalutSelf *obj)
obj->status = SALUT_PRESENCE_AVAILABLE;
obj->status_message = NULL;
obj->jid = NULL;
+#ifdef ENABLE_OLPC
+ obj->olpc_key = NULL;
+ obj->olpc_color = NULL;
+ obj->olpc_cur_act = NULL;
+ obj->olpc_cur_act_room = 0;
+#endif
obj->first_name = NULL;
obj->last_name = NULL;
obj->email = NULL;
obj->published_name = NULL;
+#ifdef ENABLE_OLPC
+ priv->olpc_activities = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify) g_object_unref);
+#endif
priv->listener = NULL;
}
@@ -144,6 +177,14 @@ salut_self_get_property (GObject *object,
case PROP_PUBLISHED_NAME:
g_value_set_string (value, self->published_name);
break;
+#ifdef ENABLE_OLPC
+ case PROP_OLPC_KEY:
+ g_value_set_pointer (value, self->olpc_key);
+ break;
+ case PROP_OLPC_COLOR:
+ g_value_set_string (value, self->olpc_color);
+ break;
+#endif
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -157,6 +198,9 @@ salut_self_set_property (GObject *object,
GParamSpec *pspec)
{
SalutSelf *self = SALUT_SELF (object);
+#ifdef ENABLE_OLPC
+ GArray *arr;
+#endif
switch (property_id)
{
@@ -187,6 +231,24 @@ salut_self_set_property (GObject *object,
g_free (self->published_name);
self->published_name = g_value_dup_string (value);
break;
+#ifdef ENABLE_OLPC
+ case PROP_OLPC_KEY:
+ arr = g_value_get_pointer (value);
+ if (arr != NULL)
+ {
+ if (self->olpc_key != NULL)
+ g_array_unref (self->olpc_key);
+
+ self->olpc_key = g_array_sized_new (FALSE, FALSE, sizeof (guint8),
+ arr->len);
+ g_array_append_vals (self->olpc_key, arr->data, arr->len);
+ }
+ break;
+ case PROP_OLPC_COLOR:
+ g_free (self->olpc_color);
+ self->olpc_color = g_value_dup_string (value);
+ break;
+#endif
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -211,8 +273,14 @@ salut_self_constructor (GType type,
g_assert (self->connection != NULL);
g_object_get (self->connection,
"contact-manager", &(priv->contact_manager),
+#ifdef ENABLE_OLPC
+ "olpc-activity-manager", &(priv->olpc_activity_manager),
+#endif
NULL);
g_assert (priv->contact_manager != NULL);
+#ifdef ENABLE_OLPC
+ g_assert (priv->olpc_activity_manager != NULL);
+#endif
priv->room_repo = tp_base_connection_get_handles (
(TpBaseConnection *) self->connection, TP_HANDLE_TYPE_ROOM);
@@ -238,6 +306,11 @@ salut_self_constructor (GType type,
}
}
+#ifdef ENABLE_OLPC
+ g_signal_connect (priv->contact_manager, "contact-change",
+ G_CALLBACK (contact_manager_contact_change_cb), self);
+#endif
+
priv->caps = salut_dup_self_advertised_caps ();
priv->data_forms = g_ptr_array_new ();
@@ -332,6 +405,27 @@ salut_self_class_init (SalutSelfClass *salut_self_class)
g_object_class_install_property (object_class, PROP_PUBLISHED_NAME,
param_spec);
+#ifdef ENABLE_OLPC
+ param_spec = g_param_spec_pointer (
+ "olpc-key",
+ "the OLPC key",
+ "A pointer to a GArray containing the OLPC key",
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_OLPC_KEY,
+ param_spec);
+
+ param_spec = g_param_spec_string (
+ "olpc-color",
+ "the OLPC color",
+ "The OLPC color of the self user",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_OLPC_COLOR,
+ param_spec);
+#endif
+
signals[ESTABLISHED] =
g_signal_new ("established",
G_OBJECT_CLASS_TYPE (salut_self_class),
@@ -372,6 +466,17 @@ salut_self_dispose (GObject *object)
priv->contact_manager = NULL;
}
+#ifdef ENABLE_OLPC
+ if (priv->olpc_activity_manager != NULL)
+ {
+ g_object_unref (priv->olpc_activity_manager);
+ priv->olpc_activity_manager = NULL;
+ }
+
+ if (priv->olpc_activities != NULL)
+ g_hash_table_unref (priv->olpc_activities);
+#endif
+
priv->room_repo = NULL;
if (priv->listener)
@@ -407,6 +512,12 @@ salut_self_finalize (GObject *object)
g_free (self->email);
g_free (self->published_name);
g_free (self->alias);
+#ifdef ENABLE_OLPC
+ if (self->olpc_key != NULL)
+ g_array_unref (self->olpc_key);
+ g_free (self->olpc_color);
+ g_free (self->olpc_cur_act);
+#endif
g_free (self->node);
g_free (self->hash);
g_free (self->ver);
@@ -539,6 +650,375 @@ salut_self_set_avatar (SalutSelf *self, guint8 *data,
return ret;
}
+#ifdef ENABLE_OLPC
+
+gboolean
+salut_self_add_olpc_activity (SalutSelf *self, const gchar *activity_id,
+ TpHandle room, GError **error)
+{
+ SalutOlpcActivity *activity;
+
+ g_return_val_if_fail (SALUT_IS_SELF (self), FALSE);
+ g_return_val_if_fail (activity_id != NULL, FALSE);
+ g_return_val_if_fail (room != 0, FALSE);
+
+ if (strchr (activity_id, ':') != NULL)
+ {
+ g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "Activity IDs may not contain ':'");
+ return FALSE;
+ }
+
+ activity = salut_olpc_activity_manager_ensure_activity_by_room (
+ self->priv->olpc_activity_manager, room);
+
+ if (!salut_olpc_activity_joined (activity, error))
+ {
+ g_object_unref (activity);
+ return FALSE;
+ }
+
+ salut_olpc_activity_update (activity, room, activity_id, NULL, NULL, NULL,
+ NULL, activity->is_private);
+
+ g_hash_table_insert (self->priv->olpc_activities, GUINT_TO_POINTER (room),
+ activity);
+
+ return TRUE;
+}
+
+gboolean
+salut_self_remove_olpc_activity (SalutSelf *self, SalutOlpcActivity *activity)
+{
+ SalutSelfPrivate *priv = self->priv;
+
+ g_return_val_if_fail (activity != NULL, FALSE);
+
+ g_hash_table_remove (priv->olpc_activities,
+ GUINT_TO_POINTER (activity->room));
+
+ salut_olpc_activity_left (activity);
+ salut_olpc_activity_revoke_invitations (activity);
+
+ return TRUE;
+}
+
+struct _set_olpc_activities_ctx
+{
+ SalutSelf *self;
+ TpHandleRepoIface *room_repo;
+ GHashTable *olpc_activities;
+ GHashTable *room_to_act_id;
+ GError **error;
+};
+
+static void
+_set_olpc_activities_add (gpointer key, gpointer value, gpointer user_data)
+{
+ struct _set_olpc_activities_ctx *data = user_data;
+ SalutOlpcActivity *activity;
+ const gchar *id = (const gchar *) value;
+ TpHandle room = GPOINTER_TO_UINT (key);
+
+ if (*(data->error) != NULL)
+ {
+ /* we already lost */
+ return;
+ }
+
+ activity = g_hash_table_lookup (data->olpc_activities, key);
+ if (activity == NULL)
+ {
+ /* add the activity service if it's not in data->olpc_activities */
+ if (!salut_self_add_olpc_activity (data->self, id, room, data->error))
+ return;
+ }
+ else
+ {
+ /* activity was already known */
+ salut_olpc_activity_update (activity, room, id, NULL, NULL, NULL,
+ NULL, activity->is_private);
+ }
+}
+
+static gboolean
+_set_olpc_activities_delete (gpointer key, gpointer value, gpointer user_data)
+{
+ SalutOlpcActivity *activity = (SalutOlpcActivity *) value;
+ struct _set_olpc_activities_ctx *data = user_data;
+ gboolean remove_activity;
+
+ /* delete the activity service if it's not in data->room_to_act_id */
+ remove_activity = (g_hash_table_lookup (data->room_to_act_id, key) == NULL);
+
+ if (remove_activity)
+ {
+ salut_olpc_activity_left (activity);
+ salut_olpc_activity_revoke_invitations (activity);
+ }
+
+ return remove_activity;
+}
+
+gboolean
+salut_self_set_olpc_activities (SalutSelf *self,
+ GHashTable *room_to_act_id,
+ GError **error)
+{
+ GError *e = NULL;
+ struct _set_olpc_activities_ctx data = { self, self->priv->room_repo,
+ self->priv->olpc_activities, room_to_act_id, &e };
+
+ g_return_val_if_fail (SALUT_IS_SELF (self), FALSE);
+
+ /* delete any which aren't in room_to_act_id. Can't fail */
+ g_hash_table_foreach_remove (self->priv->olpc_activities,
+ _set_olpc_activities_delete, &data);
+
+ /* add any which aren't in olpc_activities */
+ g_hash_table_foreach (room_to_act_id, _set_olpc_activities_add, &data);
+
+ if (error != NULL)
+ *error = e;
+ return (e == NULL);
+}
+
+gboolean
+salut_self_set_olpc_current_activity (SalutSelf *self,
+ const gchar *id,
+ TpHandle room,
+ GError **error)
+{
+ GError *err = NULL;
+ const gchar *room_name;
+
+ g_return_val_if_fail (SALUT_IS_SELF (self), FALSE);
+ g_return_val_if_fail (id != NULL, FALSE);
+
+ /* if one of id and room is empty, require the other to be */
+ if (room == 0)
+ {
+ room_name = "";
+
+ if (id[0] != '\0')
+ {
+ g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "In SetCurrentActivity, activity ID must be \"\" if room handle "
+ "is 0");
+ return FALSE;
+ }
+ }
+ else
+ {
+ room_name = tp_handle_inspect (self->priv->room_repo, room);
+
+ if (id[0] == '\0')
+ {
+ g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "In SetCurrentActivity, activity ID must not be \"\" if room "
+ "handle is non-zero");
+ return FALSE;
+ }
+ }
+
+ g_free (self->olpc_cur_act);
+ self->olpc_cur_act = g_strdup (id);
+ self->olpc_cur_act_room = room;
+
+ if (!SALUT_SELF_GET_CLASS (self)->update_current_activity (self, room_name,
+ &err))
+ {
+ g_set_error (error, TP_ERROR, TP_ERROR_NETWORK_ERROR, "%s",
+ err->message);
+ g_error_free (err);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+salut_self_set_olpc_activity_properties (SalutSelf *self,
+ TpHandle handle,
+ const gchar *color,
+ const gchar *name,
+ const gchar *type,
+ const gchar *tags,
+ gboolean is_private,
+ GError **error)
+{
+ SalutSelfPrivate *priv;
+ SalutOlpcActivity *activity;
+
+ g_return_val_if_fail (SALUT_IS_SELF (self), FALSE);
+
+ priv = self->priv;
+
+ activity = g_hash_table_lookup (priv->olpc_activities,
+ GUINT_TO_POINTER (handle));
+
+ if (activity == NULL)
+ {
+ /* User have to call org.laptop.Telepathy.BuddyInfo.SetActivities
+ * to create the activity */
+ g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "No activity associated with room having handle %d", handle);
+ return FALSE;
+ }
+
+ salut_olpc_activity_update (activity, handle, activity->id,
+ name, type, color, tags, is_private);
+
+ return TRUE;
+}
+
+gboolean
+salut_self_set_olpc_properties (SalutSelf *self,
+ const GArray *key,
+ const gchar *color,
+ const gchar *jid,
+ GError **error)
+{
+ GError *err = NULL;
+
+ if (key != NULL)
+ {
+ if (self->olpc_key == NULL)
+ {
+ self->olpc_key = g_array_sized_new (FALSE, FALSE, sizeof (guint8),
+ key->len);
+ }
+ else
+ {
+ g_array_remove_range (self->olpc_key, 0, self->olpc_key->len);
+ }
+
+ g_array_append_vals (self->olpc_key, key->data, key->len);
+ }
+
+ if (color != NULL)
+ {
+ g_free (self->olpc_color);
+ self->olpc_color = g_strdup (color);
+ }
+
+ if (jid != NULL)
+ {
+ g_free (self->jid);
+ self->jid = g_strdup (jid);
+ }
+
+ if (!SALUT_SELF_GET_CLASS (self)->set_olpc_properties (self, key, color, jid,
+ &err))
+ {
+ g_set_error (error, TP_ERROR, TP_ERROR_NETWORK_ERROR, "%s",
+ err->message);
+ g_error_free (err);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+typedef struct
+{
+ SalutSelfOLPCActivityFunc foreach;
+ gpointer user_data;
+} foreach_olpc_activity_ctx;
+
+static void
+foreach_olpc_activity (gpointer key, gpointer value, gpointer user_data)
+{
+ foreach_olpc_activity_ctx *ctx = user_data;
+ SalutOlpcActivity *activity = value;
+
+ DEBUG ("%s -> %u", activity->id, GPOINTER_TO_UINT (key));
+ (ctx->foreach) (activity, ctx->user_data);
+}
+
+void
+salut_self_foreach_olpc_activity (SalutSelf *self,
+ SalutSelfOLPCActivityFunc foreach,
+ gpointer user_data)
+{
+ foreach_olpc_activity_ctx ctx = { foreach, user_data };
+
+ g_return_if_fail (SALUT_IS_SELF (self));
+
+ DEBUG ("called");
+
+ g_hash_table_foreach (self->priv->olpc_activities, foreach_olpc_activity,
+ &ctx);
+
+ DEBUG ("end");
+}
+
+void
+salut_self_olpc_augment_invitation (SalutSelf *self,
+ TpHandle room,
+ TpHandle contact,
+ WockyNode *invite_node)
+{
+ SalutOlpcActivity *activity;
+
+ g_return_if_fail (SALUT_IS_SELF (self));
+
+ activity = g_hash_table_lookup (self->priv->olpc_activities,
+ GUINT_TO_POINTER (room));
+ if (activity == NULL)
+ return;
+
+ salut_olpc_activity_augment_invitation (activity, contact, invite_node);
+}
+
+typedef struct
+{
+ GHashTable *olpc_activities;
+ TpHandle contact_handle;
+} remove_from_invited_ctx;
+
+static void
+remove_from_invited (SalutOlpcActivity *act,
+ gpointer user_data)
+{
+ SalutOlpcActivity *activity;
+ remove_from_invited_ctx *data = (remove_from_invited_ctx *) user_data;
+
+ activity = g_hash_table_lookup (data->olpc_activities,
+ GUINT_TO_POINTER (act->room));
+ if (activity == NULL)
+ return;
+
+ if (salut_olpc_activity_remove_invited (activity, data->contact_handle))
+ DEBUG ("contact %d joined activity %s. Remove it from the invited list",
+ data->contact_handle, activity->id);
+}
+
+/* when a buddy changes his activity list, check if we invited him
+ * to this activity and remove him from the invited set */
+void
+contact_manager_contact_change_cb (SalutContactManager *mgr,
+ SalutContact *contact,
+ int changes,
+ gpointer user_data)
+{
+ SalutSelf *self = SALUT_SELF (user_data);
+ SalutSelfPrivate *priv = self->priv;
+ TpHandleRepoIface *handle_repo = tp_base_connection_get_handles (
+ TP_BASE_CONNECTION (self->connection), TP_HANDLE_TYPE_CONTACT);
+ TpHandle handle;
+ remove_from_invited_ctx data;
+
+ if (!(changes & SALUT_CONTACT_OLPC_ACTIVITIES))
+ return;
+
+ handle = tp_handle_lookup (handle_repo, contact->name, NULL, NULL);
+
+ data.olpc_activities = priv->olpc_activities;
+ data.contact_handle = handle;
+ salut_contact_foreach_olpc_activity (contact, remove_from_invited, &data);
+}
+#endif /* ENABLE_OLPC */
+
void
salut_self_established (SalutSelf *self)
{
diff --git a/src/self.h b/src/self.h
index 84a7eeec..4c1b51ab 100644
--- a/src/self.h
+++ b/src/self.h
@@ -32,6 +32,9 @@
#include "connection.h"
#include "presence.h"
+#ifdef ENABLE_OLPC
+#include "olpc-activity.h"
+#endif
G_BEGIN_DECLS
@@ -49,6 +52,10 @@ struct _SalutSelfClass {
gboolean (*set_alias) (SalutSelf *self, GError **error);
gboolean (*set_avatar) (SalutSelf *self, guint8 *data, gsize size,
GError **error);
+#ifdef ENABLE_OLPC
+ gboolean (*set_olpc_properties) (SalutSelf *self, const GArray *key,
+ const gchar *color, const gchar *jid, GError **error);
+#endif
/* private abstract methods */
void (*remove_avatar) (SalutSelf *self);
@@ -65,6 +72,12 @@ struct _SalutSelf {
guint8 *avatar;
gsize avatar_size;
gchar *jid;
+#ifdef ENABLE_OLPC
+ GArray *olpc_key;
+ gchar *olpc_cur_act;
+ TpHandle olpc_cur_act_room;
+ gchar *olpc_color;
+#endif
gchar *node;
gchar *hash;
gchar *ver;
@@ -114,6 +127,37 @@ gboolean salut_self_set_alias (SalutSelf *self, const gchar *alias,
const gchar *salut_self_get_alias (SalutSelf *self);
+#ifdef ENABLE_OLPC
+gboolean salut_self_set_olpc_properties (SalutSelf *self,
+ const GArray *key, const gchar *color, const gchar *jid, GError **error);
+
+gboolean salut_self_set_olpc_activity_properties (SalutSelf *self,
+ TpHandle handle,
+ const gchar *color, const gchar *name, const gchar *type,
+ const gchar *tags, gboolean is_private, GError **error);
+
+gboolean salut_self_set_olpc_activities (SalutSelf *self,
+ GHashTable *act_id_to_room, GError **error);
+
+gboolean salut_self_add_olpc_activity (SalutSelf *self,
+ const gchar *activity_id, TpHandle room, GError **error);
+
+gboolean salut_self_remove_olpc_activity (SalutSelf *self,
+ SalutOlpcActivity *activity);
+
+gboolean salut_self_set_olpc_current_activity (SalutSelf *self,
+ const gchar *id, TpHandle room, GError **error);
+
+typedef void (*SalutSelfOLPCActivityFunc)
+ (SalutOlpcActivity *activity, gpointer user_data);
+
+void salut_self_foreach_olpc_activity (SalutSelf *self,
+ SalutSelfOLPCActivityFunc foreach, gpointer user_data);
+
+void salut_self_olpc_augment_invitation (SalutSelf *self,
+ TpHandle room, TpHandle contact, WockyNode *invite_node);
+#endif
+
const GabbleCapabilitySet *salut_self_get_caps (SalutSelf *self);
void salut_self_take_caps (SalutSelf *self, GabbleCapabilitySet *caps);
diff --git a/src/text-helper.h b/src/text-helper.h
index c9c2fcde..d1ab7c6c 100644
--- a/src/text-helper.h
+++ b/src/text-helper.h
@@ -21,7 +21,7 @@
#ifndef __TEXT_HELPER_H__
#define __TEXT_HELPER_H__
-#include <telepathy-glib/telepathy-glib-dbus.h>
+#include <telepathy-glib/telepathy-glib.h>
#include <wocky/wocky.h>
diff --git a/src/tube-dbus.c b/src/tube-dbus.c
index c48421d6..08cb0016 100644
--- a/src/tube-dbus.c
+++ b/src/tube-dbus.c
@@ -43,7 +43,6 @@
#include "muc-tube-dbus.h"
#include "tube-iface.h"
#include "sha1/sha1-util.h"
-#include "util.h"
/* When we receive D-Bus messages to be delivered to the application and the
* application is not yet connected to the D-Bus tube, theses D-Bus messages
@@ -637,7 +636,7 @@ salut_tube_dbus_get_property (GObject *object,
g_value_set_string (value, priv->stream_id);
break;
case PROP_TYPE:
- g_value_set_uint (value, SALUT_TUBE_TYPE_DBUS);
+ g_value_set_uint (value, TP_TUBE_TYPE_DBUS);
break;
case PROP_SERVICE:
g_value_set_string (value, priv->service);
@@ -1536,7 +1535,7 @@ salut_tube_dbus_check_access_control (SalutTubeDBus *self,
* salut_tube_dbus_offer_async
*
* Implement D-Bus method Offer on interface
- * im.telepathy1.Channel.Type.DBusTube
+ * org.freedesktop.Telepathy.Channel.Type.DBusTube
*/
static void
salut_tube_dbus_offer_async (TpSvcChannelTypeDBusTube *self,
@@ -1576,7 +1575,7 @@ salut_tube_dbus_offer_async (TpSvcChannelTypeDBusTube *self,
* salut_tube_dbus_accept_async
*
* Implements D-Bus method Accept on interface
- * im.telepathy1.Channel.Type.DBusTube
+ * org.freedesktop.Telepathy.Channel.Type.DBusTube
*/
static void
salut_tube_dbus_accept_async (TpSvcChannelTypeDBusTube *self,
diff --git a/src/tube-iface.c b/src/tube-iface.c
index 60b9012a..5381c989 100644
--- a/src/tube-iface.c
+++ b/src/tube-iface.c
@@ -144,7 +144,7 @@ salut_tube_iface_base_init (gpointer klass)
param_spec = g_param_spec_uint (
"type",
"Tube type",
- "The SalutTubeType this D-Bus tube object.",
+ "The TpTubeType this D-Bus tube object.",
0, G_MAXUINT32, 0,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_interface_install_property (klass, param_spec);
@@ -179,7 +179,7 @@ salut_tube_iface_base_init (gpointer klass)
"state",
"Tube state",
"The TpTubeChannelState of this DBUS tube object",
- 0, G_MAXUINT32, TP_TUBE_CHANNEL_STATE_REMOTE_PENDING,
+ 0, G_MAXUINT32, TP_TUBE_STATE_REMOTE_PENDING,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_interface_install_property (klass, param_spec);
diff --git a/src/tube-stream.c b/src/tube-stream.c
index c55c4db1..fea5be7c 100644
--- a/src/tube-stream.c
+++ b/src/tube-stream.c
@@ -65,7 +65,6 @@
#include "tube-iface.h"
#include "si-bytestream-manager.h"
#include "contact-manager.h"
-#include "util.h"
static void tube_iface_init (gpointer g_iface, gpointer iface_data);
static void streamtube_iface_init (gpointer g_iface, gpointer iface_data);
@@ -718,8 +717,7 @@ local_new_connection_cb (GibberListener *listener,
static void
fire_new_remote_connection (SalutTubeStream *self,
GibberTransport *transport,
- TpHandle contact,
- const gchar *contact_id)
+ TpHandle contact)
{
SalutTubeStreamPrivate *priv = SALUT_TUBE_STREAM_GET_PRIVATE (self);
GValue access_control_param = {0,};
@@ -736,7 +734,7 @@ fire_new_remote_connection (SalutTubeStream *self,
g_assert (connection_id != 0);
tp_svc_channel_type_stream_tube_emit_new_remote_connection (self,
- contact, contact_id, &access_control_param, connection_id);
+ contact, &access_control_param, connection_id);
g_value_unset (&access_control_param);
}
@@ -1090,7 +1088,7 @@ salut_tube_stream_get_property (GObject *object,
g_value_set_uint64 (value, priv->id);
break;
case PROP_TYPE:
- g_value_set_uint (value, SALUT_TUBE_TYPE_STREAM);
+ g_value_set_uint (value, TP_TUBE_TYPE_STREAM);
break;
case PROP_SERVICE:
g_value_set_string (value, priv->service);
@@ -1859,7 +1857,7 @@ salut_tube_stream_add_bytestream (SalutTubeIface *tube,
g_signal_emit (G_OBJECT (self), signals[NEW_CONNECTION], 0, contact);
- fire_new_remote_connection (self, transport, contact, peer_id);
+ fire_new_remote_connection (self, transport, contact);
g_free (peer_id);
}
@@ -2053,7 +2051,7 @@ salut_tube_stream_check_params (TpSocketAddressType address_type,
* salut_tube_stream_offer_async
*
* Implements D-Bus method Offer
- * on im.telepathy1.Channel.Type.StreamTube
+ * on org.freedesktop.Telepathy.Channel.Type.StreamTube
*/
static void
salut_tube_stream_offer_async (TpSvcChannelTypeStreamTube *iface,
@@ -2110,7 +2108,7 @@ salut_tube_stream_offer_async (TpSvcChannelTypeStreamTube *iface,
* salut_tube_stream_accept_async
*
* Implements D-Bus method Accept
- * on im.telepathy1.Channel.Type.StreamTube
+ * on org.freedesktop.Telepathy.Channel.Type.StreamTube
*/
static void
salut_tube_stream_accept_async (TpSvcChannelTypeStreamTube *iface,
diff --git a/src/tubes-manager.c b/src/tubes-manager.c
index 45b65669..998296cc 100644
--- a/src/tubes-manager.c
+++ b/src/tubes-manager.c
@@ -57,7 +57,7 @@ static void gabble_caps_channel_manager_iface_init (
GabbleCapsChannelManagerIface *);
static SalutTubeIface * create_new_tube (SalutTubesManager *self,
- SalutTubeType type,
+ TpTubeType type,
TpHandle handle,
const gchar *service,
GHashTable *parameters,
@@ -120,7 +120,7 @@ static gboolean
extract_tube_information (TpHandleRepoIface *contact_repo,
WockyStanza *stanza,
gboolean *close_out,
- SalutTubeType *type,
+ TpTubeType *type,
TpHandle *initiator_handle,
const gchar **service,
GHashTable **parameters,
@@ -220,9 +220,9 @@ extract_tube_information (TpHandleRepoIface *contact_repo,
tube_type = wocky_node_get_attribute (tube_node, "type");
if (!tp_strdiff (tube_type, "stream"))
- *type = SALUT_TUBE_TYPE_STREAM;
+ *type = TP_TUBE_TYPE_STREAM;
else if (!tp_strdiff (tube_type, "dbus"))
- *type = SALUT_TUBE_TYPE_DBUS;
+ *type = TP_TUBE_TYPE_DBUS;
else
{
g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
@@ -293,7 +293,7 @@ iq_tube_request_cb (WockyPorter *porter,
/* tube informations */
const gchar *service;
- SalutTubeType tube_type;
+ TpTubeType tube_type;
TpHandle initiator_handle;
GHashTable *parameters;
guint64 tube_id;
@@ -706,7 +706,7 @@ generate_tube_id (SalutTubesManager *self)
static SalutTubeIface *
create_new_tube (SalutTubesManager *self,
- SalutTubeType type,
+ TpTubeType type,
TpHandle handle,
const gchar *service,
GHashTable *parameters,
@@ -720,14 +720,14 @@ create_new_tube (SalutTubesManager *self,
TpHandle self_handle = tp_base_connection_get_self_handle (base_conn);
SalutTubeIface *tube;
- if (type == SALUT_TUBE_TYPE_STREAM)
+ if (type == TP_TUBE_TYPE_STREAM)
{
tube = SALUT_TUBE_IFACE (salut_tube_stream_new (priv->conn,
handle, TP_HANDLE_TYPE_CONTACT,
self_handle, self_handle, FALSE, service,
parameters, tube_id, portnum, iq_req, TRUE));
}
- else if (type == SALUT_TUBE_TYPE_DBUS)
+ else if (type == TP_TUBE_TYPE_DBUS)
{
tube = SALUT_TUBE_IFACE (salut_tube_dbus_new (priv->conn,
handle, TP_HANDLE_TYPE_CONTACT, self_handle, NULL,
@@ -757,7 +757,7 @@ new_channel_from_request (SalutTubesManager *self,
{
SalutTubeIface *tube;
- SalutTubeType type;
+ TpTubeType type;
const gchar *ctype, *service;
TpHandle handle;
guint64 tube_id;
@@ -778,14 +778,14 @@ new_channel_from_request (SalutTubesManager *self,
service = tp_asv_get_string (request,
TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SERVICE);
- type = SALUT_TUBE_TYPE_STREAM;
+ type = TP_TUBE_TYPE_STREAM;
}
else if (!tp_strdiff (ctype, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE))
{
service = tp_asv_get_string (request,
TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME);
- type = SALUT_TUBE_TYPE_DBUS;
+ type = TP_TUBE_TYPE_DBUS;
}
else
{
@@ -991,7 +991,7 @@ salut_tubes_manager_iface_init (gpointer g_iface,
static void
add_service_to_array (const gchar *service,
GPtrArray *arr,
- SalutTubeType type)
+ TpTubeType type)
{
GValue monster = {0, };
GHashTable *fixed_properties;
@@ -1003,7 +1003,7 @@ add_service_to_array (const gchar *service,
NULL
};
- g_assert (type == SALUT_TUBE_TYPE_STREAM || type == SALUT_TUBE_TYPE_DBUS);
+ g_assert (type == TP_TUBE_TYPE_STREAM || type == TP_TUBE_TYPE_DBUS);
g_value_init (&monster, TP_STRUCT_TYPE_REQUESTABLE_CHANNEL_CLASS);
g_value_take_boxed (&monster,
@@ -1014,7 +1014,7 @@ add_service_to_array (const gchar *service,
(GDestroyNotify) tp_g_value_slice_free);
channel_type_value = tp_g_value_slice_new (G_TYPE_STRING);
- if (type == SALUT_TUBE_TYPE_STREAM)
+ if (type == TP_TUBE_TYPE_STREAM)
g_value_set_static_string (channel_type_value,
TP_IFACE_CHANNEL_TYPE_STREAM_TUBE);
else
@@ -1030,7 +1030,7 @@ add_service_to_array (const gchar *service,
target_handle_type_value = tp_g_value_slice_new (G_TYPE_STRING);
g_value_set_string (target_handle_type_value, service);
- if (type == SALUT_TUBE_TYPE_STREAM)
+ if (type == TP_TUBE_TYPE_STREAM)
g_hash_table_insert (fixed_properties,
TP_IFACE_CHANNEL_TYPE_STREAM_TUBE ".Service",
target_handle_type_value);
@@ -1142,10 +1142,10 @@ get_contact_caps_foreach (gpointer data,
if (g_str_has_prefix (ns, STREAM_CAP_PREFIX))
add_service_to_array (ns + strlen (STREAM_CAP_PREFIX), closure->arr,
- SALUT_TUBE_TYPE_STREAM);
+ TP_TUBE_TYPE_STREAM);
else if (g_str_has_prefix (ns, DBUS_CAP_PREFIX))
add_service_to_array (ns + strlen (DBUS_CAP_PREFIX), closure->arr,
- SALUT_TUBE_TYPE_DBUS);
+ TP_TUBE_TYPE_DBUS);
}
static void
diff --git a/src/util.h b/src/util.h
index 1f4876f5..03a6e8dd 100644
--- a/src/util.h
+++ b/src/util.h
@@ -32,10 +32,4 @@ void salut_wocky_node_add_children_from_properties (WockyNode *node,
GHashTable *properties, const gchar *prop);
gchar *salut_generate_id (void);
-typedef enum
-{
- SALUT_TUBE_TYPE_STREAM,
- SALUT_TUBE_TYPE_DBUS,
-} SalutTubeType;
-
#endif /* __SALUT_UTIL_H__ */
diff --git a/src/write-mgr-file.c b/src/write-mgr-file.c
index fd52820c..6a02fff8 100644
--- a/src/write-mgr-file.c
+++ b/src/write-mgr-file.c
@@ -25,7 +25,7 @@
#include <dbus/dbus-glib.h>
#include <dbus/dbus-protocol.h>
-#include <telepathy-glib/telepathy-glib-dbus.h>
+#include <telepathy-glib/telepathy-glib.h>
#include "protocol.h"
@@ -206,6 +206,14 @@ generate_group_name (GHashTable *props)
handle_type_name = "-multi";
break;
+ case TP_HANDLE_TYPE_GROUP:
+ handle_type_name = "-group";
+ break;
+
+ case TP_HANDLE_TYPE_LIST:
+ handle_type_name = "-list";
+ break;
+
default:
handle_type_name = "";
}
@@ -272,7 +280,7 @@ write_presence (GKeyFile *f,
statuses = tp_asv_get_boxed (props,
TP_PROP_PROTOCOL_INTERFACE_PRESENCE_STATUSES,
- TP_HASH_TYPE_STATUS_SPEC_MAP);
+ TP_HASH_TYPE_SIMPLE_STATUS_SPEC_MAP);
g_return_if_fail (statuses != NULL);
g_hash_table_iter_init (&iter, statuses);
diff --git a/tests/twisted/Makefile.am b/tests/twisted/Makefile.am
index b3b833de..a83c1432 100644
--- a/tests/twisted/Makefile.am
+++ b/tests/twisted/Makefile.am
@@ -51,10 +51,17 @@ TWISTED_AVAHI_TESTS = \
avahi/tubes/two-muc-stream-tubes.py \
avahi/tubes/two-muc-dbus-tubes.py
+TWISTED_AVAHI_OLPC_TESTS = \
+ avahi/olpc-activity-announcements.py
+
if WANT_TWISTED_TESTS
TWISTED_TESTS += $(TWISTED_BASIC_TESTS)
endif
+if ENABLE_OLPC
+ TWISTED_AVAHI_TESTS += $(TWISTED_AVAHI_OLPC_TESTS)
+endif
+
if USE_BACKEND_AVAHI
TWISTED_TESTS += $(TWISTED_AVAHI_TESTS)
endif
@@ -110,6 +117,7 @@ run-test.sh: run-test.sh.in Makefile
EXTRA_DIST = \
$(TWISTED_AVAHI_TESTS) \
+ $(TWISTED_AVAHI_OLPC_TESTS) \
$(TWISTED_BASIC_TESTS) \
constants.py \
run-test.sh.in \
diff --git a/tests/twisted/avahi/aliases.py b/tests/twisted/avahi/aliases.py
index 799bd54f..41c82857 100644
--- a/tests/twisted/avahi/aliases.py
+++ b/tests/twisted/avahi/aliases.py
@@ -13,8 +13,8 @@ import time
def wait_for_aliases_changed(q, handle):
e = q.expect('dbus-signal', signal='AliasesChanged',
- predicate=lambda e: handle in e.args[0])
- alias = e.args[0][handle]
+ predicate=lambda e: e.args[0][0][0] == handle)
+ _, alias = e.args[0][0]
return alias
def wait_for_contact_info_changed(q, handle):
@@ -57,7 +57,7 @@ def check_contact_info(info, txt):
def check_all_contact_info_methods(conn, handle, keys):
attrs = conn.Contacts.GetContactAttributes([handle],
- [cs.CONN_IFACE_CONTACT_INFO])[handle]
+ [cs.CONN_IFACE_CONTACT_INFO], True)[handle]
info = attrs[cs.CONN_IFACE_CONTACT_INFO + "/info"]
check_contact_info(info, keys)
@@ -69,9 +69,6 @@ def test(q, bus, conn):
q.expect('dbus-signal', signal='StatusChanged',
args=[cs.CONN_STATUS_CONNECTED, cs.CSR_NONE_SPECIFIED])
- flags = conn.Properties.Get(cs.CONN_IFACE_ALIASING, "AliasFlags")
- assertEquals(flags, 0)
-
assertContains(cs.CONN_IFACE_CONTACT_INFO,
conn.Properties.Get(cs.CONN, "Interfaces"))
ci_props = conn.Properties.GetAll(cs.CONN_IFACE_CONTACT_INFO)
@@ -130,7 +127,7 @@ def test(q, bus, conn):
check_contact_info(info, dict)
attrs = conn.Contacts.GetContactAttributes([handle],
- [cs.CONN_IFACE_ALIASING])[handle]
+ [cs.CONN_IFACE_ALIASING], True)[handle]
assertEquals(alias, attrs[cs.CONN_IFACE_ALIASING + "/alias"])
check_all_contact_info_methods(conn, handle, dict)
diff --git a/tests/twisted/avahi/caps-file-transfer.py b/tests/twisted/avahi/caps-file-transfer.py
index 13425c26..c239fdfd 100644
--- a/tests/twisted/avahi/caps-file-transfer.py
+++ b/tests/twisted/avahi/caps-file-transfer.py
@@ -140,7 +140,7 @@ def test_ft_caps_from_contact(q, bus, conn, client):
# check the Contacts interface give the same caps
caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes(
- [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS]) \
+ [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
[contact_handle][cs.CONN_IFACE_CONTACT_CAPS + '/capabilities']
assert caps_via_contacts_iface == caps, caps_via_contacts_iface
@@ -194,7 +194,7 @@ def test_ft_caps_from_contact(q, bus, conn, client):
# check the Contacts interface give the same caps
caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes(
- [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS]) \
+ [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
[contact_handle][cs.CONN_IFACE_CONTACT_CAPS + '/capabilities']
assert caps_via_contacts_iface == caps, caps_via_contacts_iface
@@ -215,7 +215,7 @@ def test_ft_caps_from_contact(q, bus, conn, client):
# check the Contacts interface give the same caps
caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes(
- [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS]) \
+ [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
[contact_handle][cs.CONN_IFACE_CONTACT_CAPS + '/capabilities']
assert caps_via_contacts_iface == caps, caps_via_contacts_iface
@@ -231,7 +231,7 @@ def test(q, bus, conn):
self_handle = conn.Properties.Get(cs.CONN, "SelfHandle")
conn_contacts_iface = dbus.Interface(conn, cs.CONN_IFACE_CONTACTS)
caps = conn_contacts_iface.GetContactAttributes(
- [self_handle], [cs.CONN_IFACE_CONTACT_CAPS]) \
+ [self_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
[self_handle][cs.CONN_IFACE_CONTACT_CAPS + '/capabilities']
assertContains(ft_metadata_caps, caps)
diff --git a/tests/twisted/avahi/caps-self.py b/tests/twisted/avahi/caps-self.py
index c176691b..4438d937 100644
--- a/tests/twisted/avahi/caps-self.py
+++ b/tests/twisted/avahi/caps-self.py
@@ -1,6 +1,6 @@
"""
Basic test of SetSelfCapabilities on interface
-im.telepathy1.Connection.Interface.ContactCapabilities
+org.freedesktop.Telepathy.Connection.Interface.ContactCapabilities
"""
from saluttest import exec_test
diff --git a/tests/twisted/avahi/close-local-pending-room.py b/tests/twisted/avahi/close-local-pending-room.py
index 5066fcfd..1e04fa37 100644
--- a/tests/twisted/avahi/close-local-pending-room.py
+++ b/tests/twisted/avahi/close-local-pending-room.py
@@ -61,18 +61,18 @@ def test(q, bus, conn):
xmpp_connection.send(message)
# group channel is created
- e = q.expect('dbus-signal', signal='NewChannels',
+ e = q.expect('dbus-signal', signal='NewChannel',
predicate=lambda e:
- e.args[0][0][1][cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT and
- e.args[0][0][1][cs.TARGET_HANDLE_TYPE] == cs.HT_ROOM)
- path = e.args[0][0][0]
+ e.args[1] == cs.CHANNEL_TYPE_TEXT and
+ e.args[2] == cs.HT_ROOM)
+ path = e.args[0]
channel = make_channel_proxy(conn, path, 'Channel')
props_iface = dbus.Interface(bus.get_object(conn.object.bus_name, path),
dbus.PROPERTIES_IFACE)
q.expect('dbus-signal', signal='MembersChanged', path=path)
- lp_members = props_iface.Get('im.telepathy1.Channel.Interface.Group1',
+ lp_members = props_iface.Get('org.freedesktop.Telepathy.Channel.Interface.Group',
'LocalPendingMembers')
assert len(lp_members) == 1
diff --git a/tests/twisted/avahi/file-transfer/file_transfer_helper.py b/tests/twisted/avahi/file-transfer/file_transfer_helper.py
index edfb1989..cb10c6b8 100644
--- a/tests/twisted/avahi/file-transfer/file_transfer_helper.py
+++ b/tests/twisted/avahi/file-transfer/file_transfer_helper.py
@@ -133,7 +133,7 @@ class FileTransferTest(object):
def create_ft_channel(self):
self.channel = make_channel_proxy(self.conn, self.ft_path, 'Channel')
- self.ft_channel = make_channel_proxy(self.conn, self.ft_path, 'Channel.Type.FileTransfer1')
+ self.ft_channel = make_channel_proxy(self.conn, self.ft_path, 'Channel.Type.FileTransfer')
self.ft_props = dbus.Interface(self.bus.get_object(
self.conn.object.bus_name, self.ft_path), PROPERTIES_IFACE)
@@ -246,7 +246,7 @@ class ReceiveFileTest(FileTransferTest):
path, props = channels[0]
# check channel properties
- # im.telepathy1.Channel D-Bus properties
+ # org.freedesktop.Telepathy.Channel D-Bus properties
assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_FILE_TRANSFER
assert props[cs.INTERFACES] == []
assert props[cs.TARGET_HANDLE] == self.handle
@@ -256,7 +256,7 @@ class ReceiveFileTest(FileTransferTest):
assert props[cs.INITIATOR_HANDLE] == self.handle
assert props[cs.INITIATOR_ID] == self.contact_name
- # im.telepathy1.Channel.Type.FileTransfer D-Bus properties
+ # org.freedesktop.Telepathy.Channel.Type.FileTransfer D-Bus properties
assert props[cs.FT_STATE] == cs.FT_STATE_PENDING
assert props[cs.FT_CONTENT_TYPE] == self.file.content_type
assert props[cs.FT_FILENAME] == self.file.name
@@ -410,7 +410,7 @@ class SendFileTest(FileTransferTest):
self.ft_path, props = self.conn.Requests.CreateChannel(request)
- # im.telepathy1.Channel D-Bus properties
+ # org.freedesktop.Telepathy.Channel D-Bus properties
assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_FILE_TRANSFER
assert props[cs.INTERFACES] == []
assert props[cs.TARGET_HANDLE] == self.handle
@@ -420,7 +420,7 @@ class SendFileTest(FileTransferTest):
assert props[cs.INITIATOR_HANDLE] == self.self_handle
assert props[cs.INITIATOR_ID] == self.self_handle_name
- # im.telepathy1.Channel.Type.FileTransfer D-Bus properties
+ # org.freedesktop.Telepathy.Channel.Type.FileTransfer D-Bus properties
assert props[cs.FT_STATE] == cs.FT_STATE_PENDING
assert props[cs.FT_CONTENT_TYPE] == self.file.content_type
assert props[cs.FT_FILENAME] == self.file.name
diff --git a/tests/twisted/avahi/file-transfer/ft-client-caps.py b/tests/twisted/avahi/file-transfer/ft-client-caps.py
index 8d6bb8df..3cb6aca3 100644
--- a/tests/twisted/avahi/file-transfer/ft-client-caps.py
+++ b/tests/twisted/avahi/file-transfer/ft-client-caps.py
@@ -131,7 +131,7 @@ def receive_caps(q, bus, conn, service, contact, contact_handle, features,
# check the Contacts interface give the same caps
caps_via_contacts_iface = conn.Contacts.GetContactAttributes(
- [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS]) \
+ [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
[contact_handle][cs.ATTR_CONTACT_CAPABILITIES]
assertSameElements(expected_caps, caps_via_contacts_iface)
@@ -151,7 +151,7 @@ def test_ft_caps_from_contact(q, bus, conn, service, contact):
# Check that we don't crash if we haven't seen any caps/presence for this
# contact yet.
caps = conn.Contacts.GetContactAttributes(
- [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS]) \
+ [contact_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
[contact_handle]
basic_caps = [(text_fixed_properties, text_allowed_properties)]
@@ -243,7 +243,7 @@ def advertise_caps(q, bus, conn, service, filters, expected_features, unexpected
# check the Contacts interface give the same caps
caps_via_contacts_iface = conn.Contacts.GetContactAttributes(
- [self_handle], [cs.CONN_IFACE_CONTACT_CAPS]) \
+ [self_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
[self_handle][cs.ATTR_CONTACT_CAPABILITIES]
assertSameElements(expected_caps, caps_via_contacts_iface)
@@ -276,7 +276,7 @@ def test_ft_caps_to_contact(q, bus, conn, service):
# Check our own caps
#
caps_via_contacts_iface = conn.Contacts.GetContactAttributes(
- [self_handle], [cs.CONN_IFACE_CONTACT_CAPS]) \
+ [self_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
[self_handle][cs.ATTR_CONTACT_CAPABILITIES]
assertEquals(basic_caps, caps_via_contacts_iface)
@@ -288,7 +288,7 @@ def test_ft_caps_to_contact(q, bus, conn, service):
# Check our own caps
caps_via_contacts_iface = conn.Contacts.GetContactAttributes(
- [self_handle], [cs.CONN_IFACE_CONTACT_CAPS]) \
+ [self_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
[self_handle][cs.ATTR_CONTACT_CAPABILITIES]
assertEquals(basic_caps, caps_via_contacts_iface)
@@ -302,7 +302,7 @@ def test_ft_caps_to_contact(q, bus, conn, service):
# Check our own caps
caps_via_contacts_iface = conn.Contacts.GetContactAttributes(
- [self_handle], [cs.CONN_IFACE_CONTACT_CAPS]) \
+ [self_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
[self_handle][cs.ATTR_CONTACT_CAPABILITIES]
assertEquals(basic_caps, caps_via_contacts_iface)
@@ -316,7 +316,7 @@ def test_ft_caps_to_contact(q, bus, conn, service):
# Check our own caps
caps_via_contacts_iface = conn.Contacts.GetContactAttributes(
- [self_handle], [cs.CONN_IFACE_CONTACT_CAPS]) \
+ [self_handle], [cs.CONN_IFACE_CONTACT_CAPS], False) \
[self_handle][cs.ATTR_CONTACT_CAPABILITIES]
assertEquals(basic_caps, caps_via_contacts_iface)
diff --git a/tests/twisted/avahi/ichat-composing.py b/tests/twisted/avahi/ichat-composing.py
index c2057fac..ae48d8a8 100644
--- a/tests/twisted/avahi/ichat-composing.py
+++ b/tests/twisted/avahi/ichat-composing.py
@@ -66,11 +66,9 @@ def test(q, bus, conn):
event.addElement('composing')
xmpp_connection.send(message)
- e = q.expect('dbus-signal', signal='MessageReceived')
- assert len(e.args[0]) == 2
- assert e.args[0][0]['message-sender-id'] == contact_name
- assert e.args[0][0]['message-sender'] == handle
- assert e.args[0][1]['content'] == OUTGOING_MESSAGE
+ e = q.expect('dbus-signal', signal='Received')
+ assert e.args[2] == handle
+ assert e.args[5] == OUTGOING_MESSAGE
if __name__ == '__main__':
exec_test(test)
diff --git a/tests/twisted/avahi/ichat-incoming-msg.py b/tests/twisted/avahi/ichat-incoming-msg.py
index bbf3bf06..71812230 100644
--- a/tests/twisted/avahi/ichat-incoming-msg.py
+++ b/tests/twisted/avahi/ichat-incoming-msg.py
@@ -53,12 +53,10 @@ def test(q, bus, conn):
boddy = msg.addElement('body', content='hi')
outbound.send(msg)
- e = q.expect('dbus-signal', signal='MessageReceived')
- assert len(e.args[0]) == 2
- assert e.args[0][0]['message-sender-id'] == contact_name
- assert e.args[0][0]['message-sender'] == handle
- assert e.args[0][0]['message-type'] == cs.MT_NORMAL
- assert e.args[0][1]['content'] == "hi"
+ e = q.expect('dbus-signal', signal='Received')
+ assert e.args[2] == handle
+ assert e.args[3] == cs.MT_NORMAL
+ assert e.args[5] == "hi"
if __name__ == '__main__':
skip_if_another_llxmpp()
diff --git a/tests/twisted/avahi/muc-invite.py b/tests/twisted/avahi/muc-invite.py
index 6f0a6116..abfc8f28 100644
--- a/tests/twisted/avahi/muc-invite.py
+++ b/tests/twisted/avahi/muc-invite.py
@@ -80,9 +80,10 @@ def test(q, bus, conn):
channel_group = make_channel_proxy(conn, path, "Channel.Interface.Group")
# check channel properties
- # im.telepathy1.Channel D-Bus properties
+ # org.freedesktop.Telepathy.Channel D-Bus properties
assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT
assertContains(cs.CHANNEL_IFACE_GROUP, props[cs.INTERFACES])
+ assertContains(cs.CHANNEL_IFACE_MESSAGES, props[cs.INTERFACES])
assert props[cs.TARGET_ID] == 'my-room'
assert props[cs.TARGET_HANDLE_TYPE] == HT_ROOM
assert props[cs.REQUESTED] == False
@@ -91,14 +92,14 @@ def test(q, bus, conn):
# we are added to local pending
e = q.expect('dbus-signal', signal='MembersChanged')
- added, removed, lp, rp, details = e.args
- assert details['message'] == 'Inviting to this room'
+ msg, added, removed, lp, rp, actor, reason = e.args
+ assert msg == 'Inviting to this room'
assert added == []
assert removed == []
assert lp == [self_handle]
assert rp == []
- assert details['actor'] == handle
- assert details['change-reason'] == 4 # invited
+ assert actor == handle
+ assert reason == 4 # invited
# TODO: join the muc, check if we are added to remote-pending and then
# to members. This would need some tweak in Salut and/or the test framework
diff --git a/tests/twisted/avahi/olpc-activity-announcements.py b/tests/twisted/avahi/olpc-activity-announcements.py
new file mode 100644
index 00000000..6b4d01a2
--- /dev/null
+++ b/tests/twisted/avahi/olpc-activity-announcements.py
@@ -0,0 +1,115 @@
+from saluttest import exec_test, wait_for_contact_in_publish
+from avahitest import AvahiAnnouncer, AvahiRecordAnnouncer, AvahiListener
+from avahitest import get_host_name, get_domain_name
+import avahi
+
+from xmppstream import setup_stream_listener, connect_to_stream
+from servicetest import make_channel_proxy, format_event, EventPattern
+
+from twisted.words.xish import xpath, domish
+import constants as cs
+
+import time
+import dbus
+import socket
+
+CHANNEL_TYPE_TEXT = "org.freedesktop.Telepathy.Channel.Type.Text"
+HT_CONTACT = 1
+HT_ROOM = 2
+HT_CONTACT_LIST = 3
+
+PUBLISHED_NAME = "acttest"
+TESTSUITE_PUBLISHED_NAME = "salutacttest"
+ACTIVITY_ID = str(time.time())
+
+def announce_address(hostname, address):
+ "Announce IN A record, address is assume to be ipv4"
+
+ data = reduce (lambda x, y: (x << 8) + int(y), address.split("."), 0)
+ ndata = socket.htonl(data)
+ rdata = [ (ndata >> (24 - x)) & 0xff for x in xrange(0, 32, 8)]
+
+ AvahiRecordAnnouncer(hostname, 0x1, 0x01, rdata)
+
+def test(q, bus, conn):
+ conn.Connect()
+ q.expect('dbus-signal', signal='StatusChanged', args=[0L, 0L])
+
+
+ activity_txt = { "type": "org.laptop.HelloMesh",
+ "name": "HelloMesh",
+ "color": "#7b83c1,#260993",
+ "txtvers": "0",
+ "activity-id": ACTIVITY_ID,
+ "room": ACTIVITY_ID
+ }
+
+ # Listen for announcements
+ l = AvahiListener(q).listen_for_service("_olpc-activity1._udp")
+
+ # Assert that the testsuite doesn't announce the activity
+ service_name = ACTIVITY_ID + ":" + TESTSUITE_PUBLISHED_NAME + "@" + get_host_name()
+ forbiden_event = EventPattern('service-added', name=service_name)
+ q.forbid_events([forbiden_event])
+
+ contact_name = PUBLISHED_NAME + "@" + get_host_name()
+
+ activity_name = ACTIVITY_ID + ":" + PUBLISHED_NAME + "@" + get_host_name()
+
+ AvahiAnnouncer(contact_name, "_presence._tcp", 1234, {})
+
+ act_hostname = ACTIVITY_ID + ":" + PUBLISHED_NAME + \
+ "._clique._udp." + get_domain_name()
+ act_address = "239.253.70.70"
+
+ announce_address(act_hostname, act_address)
+
+ # FIXME, if we use the same name as the running salut will MembersChanged
+ # isn't signalled later on, needs to be fixed.
+ AvahiAnnouncer(ACTIVITY_ID + ":" + PUBLISHED_NAME,
+ "_clique._udp", 12345, {}, hostname = act_hostname)
+ AvahiAnnouncer(activity_name, "_olpc-activity1._udp",
+ 0, activity_txt)
+
+ # Publish a contact, now get it's handle
+ handle = wait_for_contact_in_publish(q, bus, conn, contact_name)
+
+ # Assert that the remote handles signals it joined the activity
+ while True:
+ e = q.expect('dbus-signal', signal = 'ActivitiesChanged')
+ if e.args[0] == handle and e.args[1] != []:
+ assert len(e.args[1]) == 1
+ assert e.args[1][0][0] == ACTIVITY_ID
+ activity_handle = e.args[1][0][1]
+ break
+
+ act_prop_iface = dbus.Interface(conn, cs.ACTIVITY_PROPERTIES)
+ act_properties = act_prop_iface.GetProperties(activity_handle)
+ assert act_properties['private'] == False
+ assert act_properties['color'] == activity_txt['color']
+ assert act_properties['name'] == activity_txt['name']
+ assert act_properties['type'] == activity_txt['type']
+
+ room_channel = conn.RequestChannel(CHANNEL_TYPE_TEXT,
+ HT_ROOM, activity_handle, True)
+
+ q.expect('dbus-signal', signal='MembersChanged', path=room_channel,
+ args = [u'', [1L], [], [], [], 1L, 0L])
+
+ # Make it public that we joined the activity
+ q.unforbid_events([forbiden_event])
+ buddy_info_iface = dbus.Interface(conn, cs.BUDDY_INFO)
+ buddy_info_iface.SetActivities([(ACTIVITY_ID, activity_handle)])
+
+ q.expect('service-added',
+ name = ACTIVITY_ID + ":" + TESTSUITE_PUBLISHED_NAME +
+ "@" + get_host_name())
+
+ buddy_info_iface.SetActivities([])
+
+ q.expect('service-removed',
+ name = ACTIVITY_ID + ":" + TESTSUITE_PUBLISHED_NAME +
+ "@" + get_host_name())
+
+if __name__ == '__main__':
+ exec_test(test, { "published-name": TESTSUITE_PUBLISHED_NAME}, timeout=15)
diff --git a/tests/twisted/avahi/request-im.py b/tests/twisted/avahi/request-im.py
index 93e3abf7..d7d2141e 100644
--- a/tests/twisted/avahi/request-im.py
+++ b/tests/twisted/avahi/request-im.py
@@ -5,11 +5,13 @@ Test requesting of text 1-1 channels using the old and new request API.
import dbus
-from saluttest import (exec_test, wait_for_contact_in_publish)
+from saluttest import (exec_test, wait_for_contact_list,
+ wait_for_contact_in_publish)
from servicetest import call_async, EventPattern, \
tp_name_prefix, make_channel_proxy
from avahitest import get_host_name, AvahiAnnouncer
from xmppstream import setup_stream_listener
+
import constants as cs
def test(q, bus, conn):
@@ -22,6 +24,10 @@ def test(q, bus, conn):
contact_name = "test-request-im@" + get_host_name()
listener, port = setup_stream_listener(q, contact_name)
+ # FIXME: this is a hack to be sure to have all the contact list channels
+ # announced so they won't interfere with the muc ones announces.
+ wait_for_contact_list(q, conn)
+
AvahiAnnouncer(contact_name, "_presence._tcp", port, basic_txt)
handle = wait_for_contact_in_publish(q, bus, conn, contact_name)
diff --git a/tests/twisted/avahi/request-muc.py b/tests/twisted/avahi/request-muc.py
index 9ef67770..a6283b2e 100644
--- a/tests/twisted/avahi/request-muc.py
+++ b/tests/twisted/avahi/request-muc.py
@@ -8,7 +8,7 @@ import avahitest
from twisted.words.xish import domish
-from saluttest import exec_test
+from saluttest import exec_test, wait_for_contact_list
from servicetest import call_async, EventPattern, \
tp_name_prefix, tp_path_prefix, make_channel_proxy
@@ -21,6 +21,10 @@ def test(q, bus, conn):
q.expect('dbus-signal', signal='StatusChanged', args=[0L, 0L])
+ # FIXME: this is a hack to be sure to have all the contact list channels
+ # announced so they won't interfere with the muc ones announces.
+ wait_for_contact_list(q, conn)
+
# check if we can request roomlist channels
properties = conn.GetAll(
tp_name_prefix + '.Connection.Interface.Requests',
diff --git a/tests/twisted/avahi/roomlist.py b/tests/twisted/avahi/roomlist.py
index 21fb1824..7e84a1be 100644
--- a/tests/twisted/avahi/roomlist.py
+++ b/tests/twisted/avahi/roomlist.py
@@ -8,7 +8,7 @@ import avahitest
from twisted.words.xish import domish
-from saluttest import exec_test
+from saluttest import exec_test, wait_for_contact_list
from servicetest import call_async, EventPattern, \
tp_name_prefix, tp_path_prefix, wrap_channel
import constants as cs
@@ -20,11 +20,14 @@ def test(q, bus, conn):
q.expect('dbus-signal', signal='StatusChanged', args=[0L, 0L])
+ # FIXME: this is a hack to be sure to have all the contact list channels
+ # announced so they won't interfere with the roomlist ones announces.
+ wait_for_contact_list(q, conn)
+
# check if we can request roomlist channels
properties = conn.GetAll(
tp_name_prefix + '.Connection.Interface.Requests',
dbus_interface='org.freedesktop.DBus.Properties')
-
assert ({tp_name_prefix + '.Channel.ChannelType':
cs.CHANNEL_TYPE_ROOM_LIST,
tp_name_prefix + '.Channel.TargetHandleType': 0,
@@ -48,7 +51,7 @@ def test(q, bus, conn):
EventPattern('dbus-signal', signal='NewChannels'),
)
path2 = ret.value[0]
- chan2 = wrap_channel(bus.get_object(conn.bus_name, path2), "RoomList1")
+ chan2 = wrap_channel(bus.get_object(conn.bus_name, path2), "RoomList")
props = ret.value[1]
assert props[tp_name_prefix + '.Channel.ChannelType'] ==\
@@ -61,7 +64,7 @@ def test(q, bus, conn):
== conn.Properties.Get(cs.CONN, "SelfHandle")
assert props[tp_name_prefix + '.Channel.InitiatorID'] \
== self_name
- assert props[tp_name_prefix + '.Channel.Type.RoomList1.Server'] == ''
+ assert props[tp_name_prefix + '.Channel.Type.RoomList.Server'] == ''
assert new_sig.args[0][0][0] == path2
assert new_sig.args[0][0][1] == props
diff --git a/tests/twisted/avahi/set-presence.py b/tests/twisted/avahi/set-presence.py
index b6f38f1e..82343c4b 100644
--- a/tests/twisted/avahi/set-presence.py
+++ b/tests/twisted/avahi/set-presence.py
@@ -32,13 +32,13 @@ def test(q, bus, conn):
assert status == 'avail', status
assert msg is None, msg
- statuses = conn.Get(cs.CONN_IFACE_PRESENCE, 'Statuses', dbus_interface=dbus.PROPERTIES_IFACE)
+ statuses = conn.Get(cs.CONN_IFACE_SIMPLE_PRESENCE, 'Statuses', dbus_interface=dbus.PROPERTIES_IFACE)
assert 'available' in statuses
assert 'dnd' in statuses
assert 'away' in statuses
- simple_presence = dbus.Interface(conn, cs.CONN_IFACE_PRESENCE)
+ simple_presence = dbus.Interface(conn, cs.CONN_IFACE_SIMPLE_PRESENCE)
# set your status to away
simple_presence.SetPresence('away', 'At the pub')
diff --git a/tests/twisted/avahi/text-channel.py b/tests/twisted/avahi/text-channel.py
index acaed6a2..b37b1c2f 100644
--- a/tests/twisted/avahi/text-channel.py
+++ b/tests/twisted/avahi/text-channel.py
@@ -34,9 +34,7 @@ def test(q, bus, conn):
cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
cs.TARGET_HANDLE: handle})[0]
text_channel = make_channel_proxy(conn, t, "Channel.Type.Text")
- text_channel.SendMessage([{'message-type': cs.MT_NORMAL},
- {'content-type': 'text/plain',
- 'content': INCOMING_MESSAGE}], 0)
+ text_channel.Send(cs.MT_NORMAL, INCOMING_MESSAGE)
e = q.expect('incoming-connection', listener = listener)
incoming = e.connection
@@ -78,12 +76,11 @@ def test(q, bus, conn):
e.connection.send(message)
- e = q.expect('dbus-signal', signal='MessageReceived')
- assert len(e.args[0]) == 2
- assert e.args[0][0]['message-sender-id'] == contact_name
- assert e.args[0][0]['message-sender'] == handle
- assert e.args[0][0]['message-type'] == cs.MT_NORMAL
- assert e.args[0][1]['content'] == OUTGOING_MESSAGE
+ e = q.expect('dbus-signal', signal='Received')
+ assert e.args[2] == handle
+ assert e.args[3] == cs.MT_NORMAL
+ assert e.args[5] == OUTGOING_MESSAGE
+
if __name__ == '__main__':
exec_test(test)
diff --git a/tests/twisted/avahi/tubes/request-muc-tubes.py b/tests/twisted/avahi/tubes/request-muc-tubes.py
index 206f3384..21100f15 100644
--- a/tests/twisted/avahi/tubes/request-muc-tubes.py
+++ b/tests/twisted/avahi/tubes/request-muc-tubes.py
@@ -8,7 +8,7 @@ import avahitest
from twisted.words.xish import domish
-from saluttest import exec_test
+from saluttest import exec_test, wait_for_contact_list
from servicetest import call_async, EventPattern, wrap_channel, pretty
import constants as cs
@@ -19,6 +19,10 @@ def test(q, bus, conn):
q.expect('dbus-signal', signal='StatusChanged', args=[0L, 0L])
+ # FIXME: this is a hack to be sure to have all the contact list channels
+ # announced so they won't interfere with the muc ones announces.
+ wait_for_contact_list(q, conn)
+
# check if we can request tube channels
properties = conn.Properties.GetAll(cs.CONN_IFACE_REQUESTS)
assert ({cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE,
diff --git a/tests/twisted/avahi/tubes/tubetestutil.py b/tests/twisted/avahi/tubes/tubetestutil.py
index 4e342f9e..d058ef62 100644
--- a/tests/twisted/avahi/tubes/tubetestutil.py
+++ b/tests/twisted/avahi/tubes/tubetestutil.py
@@ -1,4 +1,4 @@
-from saluttest import make_connection
+from saluttest import make_connection, wait_for_contact_list
from avahitest import get_host_name
from servicetest import make_channel_proxy
@@ -10,6 +10,10 @@ def connect_two_accounts(q, bus, conn):
conn.Connect()
q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_NONE_SPECIFIED])
+ # FIXME: this is a hack to be sure to have all the contact list channels
+ # announced so they won't interfere with other channels announces.
+ wait_for_contact_list(q, conn)
+
# second connection: connect
conn2_params = {
'published-name': 'testsuite2',
@@ -21,6 +25,8 @@ def connect_two_accounts(q, bus, conn):
conn2.Connect()
q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_NONE_SPECIFIED])
+ wait_for_contact_list(q, conn2)
+
# first connection: get the contact list
publish_handle = conn.RequestHandles(cs.HT_LIST, ["publish"])[0]
conn1_publish = conn.RequestChannel(cs.CHANNEL_TYPE_CONTACT_LIST,
@@ -56,7 +62,7 @@ def connect_two_accounts(q, bus, conn):
# property first
contact1_handle_on_conn2 = 0
conn2_members = conn2_publish_proxy.Get(
- 'im.telepathy1.Channel.Interface.Group', 'Members',
+ 'org.freedesktop.Telepathy.Channel.Interface.Group', 'Members',
dbus_interface='org.freedesktop.DBus.Properties')
for h in conn2_members:
name = conn2.InspectHandles(cs.HT_CONTACT, [h])[0]
diff --git a/tests/twisted/avahi/tubes/two-muc-dbus-tubes.py b/tests/twisted/avahi/tubes/two-muc-dbus-tubes.py
index ae8864c3..6fc81097 100644
--- a/tests/twisted/avahi/tubes/two-muc-dbus-tubes.py
+++ b/tests/twisted/avahi/tubes/two-muc-dbus-tubes.py
@@ -21,9 +21,9 @@ def check_dbus_names(tube, members):
names = tube.Properties.Get(cs.CHANNEL_TYPE_DBUS_TUBE, 'DBusNames')
assert set(names.keys()) == set(members), names.keys()
-SERVICE = "im.telepathy1.Tube.Test"
+SERVICE = "org.freedesktop.Telepathy.Tube.Test"
IFACE = SERVICE
-PATH = "/im/telepathy1/Tube/Test"
+PATH = "/org/freedesktop/Telepathy/Tube/Test"
print "FIXME: MUC tubes tests are currently broken: fdo#69223"
# exiting 77 causes automake to consider the test to have been skipped
diff --git a/tests/twisted/cm/protocol.py b/tests/twisted/cm/protocol.py
index 157c6b6f..6f62f1ec 100644
--- a/tests/twisted/cm/protocol.py
+++ b/tests/twisted/cm/protocol.py
@@ -16,9 +16,9 @@ def test(q, bus, conn):
cm_prop_iface = dbus.Interface(cm, cs.PROPERTIES_IFACE)
protocols = unwrap(cm_prop_iface.Get(cs.CM, 'Protocols'))
- assertEquals(set(['local_xmpp']), set(protocols.keys()))
+ assertEquals(set(['local-xmpp']), set(protocols.keys()))
- local_props = protocols['local_xmpp']
+ local_props = protocols['local-xmpp']
local_params = local_props[cs.PROTOCOL + '.Parameters']
proto = bus.get_object(cm.bus_name, cm.object_path + '/local_xmpp')
@@ -39,7 +39,7 @@ def test(q, bus, conn):
assertContains(cs.CONN_IFACE_ALIASING, proto_props['ConnectionInterfaces'])
assertContains(cs.CONN_IFACE_AVATARS, proto_props['ConnectionInterfaces'])
assertContains(cs.CONN_IFACE_CONTACTS, proto_props['ConnectionInterfaces'])
- assertContains(cs.CONN_IFACE_PRESENCE,
+ assertContains(cs.CONN_IFACE_SIMPLE_PRESENCE,
proto_props['ConnectionInterfaces'])
assertContains(cs.CONN_IFACE_REQUESTS, proto_props['ConnectionInterfaces'])
diff --git a/tests/twisted/constants.py b/tests/twisted/constants.py
index e72c5928..8c601678 100644
--- a/tests/twisted/constants.py
+++ b/tests/twisted/constants.py
@@ -1,32 +1,10 @@
-# Copyright (C) 2009 Nokia Corporation
-# Copyright (C) 2009-2013 Collabora Ltd.
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library 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
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
-# 02110-1301 USA
-
"""
Some handy constants for other tests to share and enjoy.
"""
-from dbus import PROPERTIES_IFACE, INTROSPECTABLE_IFACE
-
-PREFIX = "im.telepathy1"
-PATH_PREFIX = '/' + PREFIX.replace('.', '/')
+from dbus import PROPERTIES_IFACE
-tp_name_prefix = PREFIX
-tp_path_prefix = PATH_PREFIX
+PREFIX = "org.freedesktop.Telepathy"
CM = PREFIX + ".ConnectionManager"
@@ -38,31 +16,42 @@ HT_GROUP = 4
CHANNEL = PREFIX + ".Channel"
-CHANNEL_IFACE_CHAT_STATE = CHANNEL + '.Interface.ChatState1'
-CHANNEL_IFACE_DESTROYABLE = CHANNEL + ".Interface.Destroyable1"
-CHANNEL_IFACE_DTMF = CHANNEL + ".Interface.DTMF1"
-CHANNEL_IFACE_GROUP = CHANNEL + ".Interface.Group1"
-CHANNEL_IFACE_HOLD = CHANNEL + ".Interface.Hold1"
-CHANNEL_IFACE_PASSWORD = CHANNEL + ".Interface.Password1"
-CHANNEL_IFACE_TUBE = CHANNEL + ".Interface.Tube1"
-CHANNEL_IFACE_SASL_AUTH = CHANNEL + ".Interface.SASLAuthentication1"
-CHANNEL_IFACE_CONFERENCE = CHANNEL + '.Interface.Conference1'
-CHANNEL_IFACE_ROOM = CHANNEL + '.Interface.Room1'
+CHANNEL_IFACE_CALL_STATE = CHANNEL + ".Interface.CallState"
+CHANNEL_IFACE_CHAT_STATE = CHANNEL + '.Interface.ChatState'
+CHANNEL_IFACE_DESTROYABLE = CHANNEL + ".Interface.Destroyable"
+CHANNEL_IFACE_DTMF = CHANNEL + ".Interface.DTMF"
+CHANNEL_IFACE_GROUP = CHANNEL + ".Interface.Group"
+CHANNEL_IFACE_HOLD = CHANNEL + ".Interface.Hold"
+CHANNEL_IFACE_MEDIA_SIGNALLING = CHANNEL + ".Interface.MediaSignalling"
+CHANNEL_IFACE_MESSAGES = CHANNEL + ".Interface.Messages"
+CHANNEL_IFACE_PASSWORD = CHANNEL + ".Interface.Password"
+CHANNEL_IFACE_TUBE = CHANNEL + ".Interface.Tube"
+CHANNEL_IFACE_SASL_AUTH = CHANNEL + ".Interface.SASLAuthentication"
+CHANNEL_IFACE_CONFERENCE = CHANNEL + '.Interface.Conference'
+CHANNEL_IFACE_ROOM = CHANNEL + '.Interface.Room2'
CHANNEL_IFACE_ROOM_CONFIG = CHANNEL + '.Interface.RoomConfig1'
-CHANNEL_IFACE_SUBJECT = CHANNEL + '.Interface.Subject1'
-CHANNEL_IFACE_FILE_TRANSFER_METADATA = CHANNEL + '.Interface.FileTransfer.Metadata1'
+CHANNEL_IFACE_SUBJECT = CHANNEL + '.Interface.Subject2'
+CHANNEL_IFACE_FILE_TRANSFER_METADATA = CHANNEL + '.Interface.FileTransfer.Metadata'
CHANNEL_TYPE_CALL = CHANNEL + ".Type.Call1"
-CHANNEL_TYPE_CONTACT_SEARCH = CHANNEL + ".Type.ContactSearch1"
+CHANNEL_TYPE_CONTACT_LIST = CHANNEL + ".Type.ContactList"
+CHANNEL_TYPE_CONTACT_SEARCH = CHANNEL + ".Type.ContactSearch"
CHANNEL_TYPE_TEXT = CHANNEL + ".Type.Text"
-CHANNEL_TYPE_STREAM_TUBE = CHANNEL + ".Type.StreamTube1"
-CHANNEL_TYPE_DBUS_TUBE = CHANNEL + ".Type.DBusTube1"
-CHANNEL_TYPE_FILE_TRANSFER = CHANNEL + ".Type.FileTransfer1"
-CHANNEL_TYPE_ROOM_LIST = CHANNEL + ".Type.RoomList1"
+CHANNEL_TYPE_TUBES = CHANNEL + ".Type.Tubes"
+CHANNEL_TYPE_STREAM_TUBE = CHANNEL + ".Type.StreamTube"
+CHANNEL_TYPE_DBUS_TUBE = CHANNEL + ".Type.DBusTube"
+CHANNEL_TYPE_TEXT = CHANNEL + ".Type.Text"
+CHANNEL_TYPE_FILE_TRANSFER = CHANNEL + ".Type.FileTransfer"
+CHANNEL_TYPE_ROOM_LIST = CHANNEL + ".Type.RoomList"
CHANNEL_TYPE_SERVER_AUTHENTICATION = \
- CHANNEL + ".Type.ServerAuthentication1"
+ CHANNEL + ".Type.ServerAuthentication"
CHANNEL_TYPE_SERVER_TLS_CONNECTION = \
- CHANNEL + ".Type.ServerTLSConnection1"
+ CHANNEL + ".Type.ServerTLSConnection"
+
+TP_AWKWARD_PROPERTIES = PREFIX + ".Properties"
+PROPERTY_FLAG_READ = 1
+PROPERTY_FLAG_WRITE = 2
+PROPERTY_FLAGS_RW = PROPERTY_FLAG_READ | PROPERTY_FLAG_WRITE
CHANNEL_TYPE = CHANNEL + '.ChannelType'
TARGET_HANDLE_TYPE = CHANNEL + '.TargetHandleType'
@@ -81,7 +70,7 @@ CALL_MUTABLE_CONTENTS = CHANNEL_TYPE_CALL + '.MutableContents'
CALL_CONTENT = PREFIX + '.Call1.Content'
CALL_CONTENT_IFACE_MEDIA = CALL_CONTENT + '.Interface.Media'
-CALL_CONTENT_IFACE_DTMF = CALL_CONTENT + '.Interface.DTMF1'
+CALL_CONTENT_IFACE_DTMF = CALL_CONTENT + '.Interface.DTMF'
CALL_CONTENT_MEDIADESCRIPTION = CALL_CONTENT + '.MediaDescription'
@@ -176,30 +165,28 @@ CONTACT_LIST_STATE_FAILURE = 2
CONTACT_LIST_STATE_SUCCESS = 3
CONN = PREFIX + ".Connection"
-CONN_IFACE_AVATARS = CONN + '.Interface.Avatars1'
-CONN_IFACE_ALIASING = CONN + '.Interface.Aliasing1'
+CONN_IFACE_AVATARS = CONN + '.Interface.Avatars'
+CONN_IFACE_ALIASING = CONN + '.Interface.Aliasing'
+CONN_IFACE_CAPS = CONN + '.Interface.Capabilities'
CONN_IFACE_CONTACTS = CONN + '.Interface.Contacts'
-CONN_IFACE_CONTACT_CAPS = CONN + '.Interface.ContactCapabilities1'
-CONN_IFACE_CONTACT_INFO = CONN + ".Interface.ContactInfo1"
-CONN_IFACE_PRESENCE = CONN + '.Interface.Presence1'
+CONN_IFACE_CONTACT_CAPS = CONN + '.Interface.ContactCapabilities'
+CONN_IFACE_CONTACT_INFO = CONN + ".Interface.ContactInfo"
+CONN_IFACE_PRESENCE = CONN + '.Interface.Presence'
+CONN_IFACE_SIMPLE_PRESENCE = CONN + '.Interface.SimplePresence'
CONN_IFACE_REQUESTS = CONN + '.Interface.Requests'
-CONN_IFACE_LOCATION = CONN + '.Interface.Location1'
+CONN_IFACE_LOCATION = CONN + '.Interface.Location'
CONN_IFACE_GABBLE_DECLOAK = CONN + '.Interface.Gabble.Decloak'
-CONN_IFACE_MAIL_NOTIFICATION = CONN + '.Interface.MailNotification1'
-CONN_IFACE_CONTACT_LIST = CONN + '.Interface.ContactList1'
-CONN_IFACE_CONTACT_GROUPS = CONN + '.Interface.ContactGroups1'
-CONN_IFACE_CLIENT_TYPES = CONN + '.Interface.ClientTypes1'
-CONN_IFACE_POWER_SAVING = CONN + '.Interface.PowerSaving1'
-CONN_IFACE_CONTACT_BLOCKING = CONN + '.Interface.ContactBlocking1'
+CONN_IFACE_MAIL_NOTIFICATION = CONN + '.Interface.MailNotification'
+CONN_IFACE_CONTACT_LIST = CONN + '.Interface.ContactList'
+CONN_IFACE_CONTACT_GROUPS = CONN + '.Interface.ContactGroups'
+CONN_IFACE_CLIENT_TYPES = CONN + '.Interface.ClientTypes'
+CONN_IFACE_POWER_SAVING = CONN + '.Interface.PowerSaving'
+CONN_IFACE_CONTACT_BLOCKING = CONN + '.Interface.ContactBlocking'
CONN_IFACE_ADDRESSING = CONN + '.Interface.Addressing1'
-CONN_IFACE_SERVICE_POINT = CONN + '.Interface.ServicePoint1'
ATTR_CONTACT_ID = CONN + '/contact-id'
ATTR_CONTACT_CAPABILITIES = CONN_IFACE_CONTACT_CAPS + '/capabilities'
-ATTR_PRESENCE = CONN_IFACE_PRESENCE + '/presence'
-ATTR_SUBSCRIBE = CONN_IFACE_CONTACT_LIST + '/subscribe'
-ATTR_PUBLISH = CONN_IFACE_CONTACT_LIST + '/publish'
-ATTR_GROUPS = CONN_IFACE_CONTACT_GROUPS + '/groups'
+ATTR_PRESENCE = CONN_IFACE_SIMPLE_PRESENCE + '/presence'
STREAM_HANDLER = PREFIX + '.Media.StreamHandler'
@@ -214,7 +201,6 @@ CONNECTION_REFUSED = ERROR + '.ConnectionRefused'
CONNECTION_FAILED = ERROR + '.ConnectionFailed'
CONNECTION_LOST = ERROR + '.ConnectionLost'
CANCELLED = ERROR + '.Cancelled'
-NOT_YOURS = ERROR + '.NotYours'
DISCONNECTED = ERROR + '.Disconnected'
REGISTRATION_EXISTS = ERROR + '.RegistrationExists'
AUTHENTICATION_FAILED = ERROR + '.AuthenticationFailed'
@@ -226,12 +212,10 @@ INVALID_HANDLE = ERROR + '.InvalidHandle'
CERT_UNTRUSTED = ERROR + '.Cert.Untrusted'
SERVICE_BUSY = ERROR + '.ServiceBusy'
SERVICE_CONFUSED = ERROR + '.ServiceConfused'
-SOFTWARE_UPGRADE_REQUIRED = ERROR + '.SoftwareUpgradeRequired'
BANNED = ERROR + '.Channel.Banned'
-DBUS_ERROR_UNKNOWN_METHOD = 'org.freedesktop.DBus.Error.UnknownMethod'
-DBUS_ERROR_NO_REPLY = 'org.freedesktop.DBus.Error.NoReply'
+UNKNOWN_METHOD = 'org.freedesktop.DBus.Error.UnknownMethod'
TUBE_PARAMETERS = CHANNEL_IFACE_TUBE + '.Parameters'
TUBE_STATE = CHANNEL_IFACE_TUBE + '.State'
@@ -277,13 +261,17 @@ SOCKET_ADDRESS_TYPE_IPV6 = 3
SOCKET_ACCESS_CONTROL_LOCALHOST = 0
SOCKET_ACCESS_CONTROL_PORT = 1
-SOCKET_ACCESS_CONTROL_CREDENTIALS = 2
+SOCKET_ACCESS_CONTROL_NETMASK = 2
+SOCKET_ACCESS_CONTROL_CREDENTIALS = 3
TUBE_STATE_LOCAL_PENDING = 0
TUBE_STATE_REMOTE_PENDING = 1
TUBE_STATE_OPEN = 2
TUBE_STATE_NOT_OFFERED = 3
+TUBE_TYPE_DBUS = 0
+TUBE_TYPE_STREAM = 1
+
MEDIA_STREAM_DIRECTION_NONE = 0
MEDIA_STREAM_DIRECTION_SEND = 1
MEDIA_STREAM_DIRECTION_RECEIVE = 2
@@ -295,6 +283,15 @@ MEDIA_STREAM_PENDING_REMOTE_SEND = 2
MEDIA_STREAM_TYPE_AUDIO = 0
MEDIA_STREAM_TYPE_VIDEO = 1
+MEDIA_STREAM_STATE_DISCONNECTED = 0
+MEDIA_STREAM_STATE_CONNECTING = 1
+MEDIA_STREAM_STATE_CONNECTED = 2
+
+MEDIA_STREAM_DIRECTION_NONE = 0
+MEDIA_STREAM_DIRECTION_SEND = 1
+MEDIA_STREAM_DIRECTION_RECEIVE = 2
+MEDIA_STREAM_DIRECTION_BIDIRECTIONAL = 3
+
FT_STATE_NONE = 0
FT_STATE_PENDING = 1
FT_STATE_ACCEPTED = 2
@@ -341,7 +338,8 @@ GF_MESSAGE_RESCIND = 128
GF_CHANNEL_SPECIFIC_HANDLES = 256
GF_ONLY_ONE_GROUP = 512
GF_HANDLE_OWNERS_NOT_AVAILABLE = 1024
-GF_MESSAGE_DEPART = 2048
+GF_PROPERTIES = 2048
+GF_MEMBERS_CHANGED_DETAILED = 4096
GC_REASON_NONE = 0
GC_REASON_OFFLINE = 1
@@ -403,7 +401,6 @@ MEDIA_CAP_IMMUTABLE_STREAMS = 32
CLIENT = PREFIX + '.Client'
-PRESENCE_UNSET = 0
PRESENCE_OFFLINE = 1
PRESENCE_AVAILABLE = 2
PRESENCE_AWAY = 3
@@ -458,6 +455,12 @@ MT_NOTICE = 2
MT_AUTO_REPLY = 3
MT_DELIVERY_REPORT = 4
+class MessageFlag(object):
+ TRUNCATED = 1
+ NON_TEXT_CONTENT = 2
+ SCROLLBACK = 4
+ RESCUED = 8
+
class SendError(object):
UNKNOWN = 0
OFFLINE = 1
@@ -467,9 +470,9 @@ class SendError(object):
NOT_IMPLEMENTED = 5
PROTOCOL = PREFIX + '.Protocol'
-PROTOCOL_IFACE_PRESENCES = PROTOCOL + '.Interface.Presence1'
-PROTOCOL_IFACE_ADDRESSING = PROTOCOL + '.Interface.Addressing1'
-PROTOCOL_IFACE_AVATARS = PROTOCOL + '.Interface.Avatars1'
+PROTOCOL_IFACE_PRESENCES = PROTOCOL + '.Interface.Presence'
+PROTOCOL_IFACE_ADDRESSING = PROTOCOL + '.Interface.Addressing'
+PROTOCOL_IFACE_AVATARS = PROTOCOL + '.Interface.Avatars'
PARAM_REQUIRED = 1
PARAM_REGISTER = 2
@@ -489,9 +492,9 @@ TLS_REJECT_REASON_UNTRUSTED = 1
# Channel.Interface.Messages
-MESSAGE_PART_SUPPORT_FLAGS = CHANNEL_TYPE_TEXT + '.MessagePartSupportFlags'
-DELIVERY_REPORTING_SUPPORT = CHANNEL_TYPE_TEXT + '.DeliveryReportingSupport'
-SUPPORTED_CONTENT_TYPES = CHANNEL_TYPE_TEXT + '.SupportedContentTypes'
+MESSAGE_PART_SUPPORT_FLAGS = CHANNEL_IFACE_MESSAGES + '.MessagePartSupportFlags'
+DELIVERY_REPORTING_SUPPORT = CHANNEL_IFACE_MESSAGES + '.DeliveryReportingSupport'
+SUPPORTED_CONTENT_TYPES = CHANNEL_IFACE_MESSAGES + '.SupportedContentTypes'
MSG_SENDING_FLAGS_REPORT_DELIVERY = 1
MSG_SENDING_FLAGS_REPORT_READ = 2
@@ -510,7 +513,15 @@ DELIVERY_STATUS_ACCEPTED = 4
DELIVERY_STATUS_READ = 5
DELIVERY_STATUS_DELETED = 6
-PASSWORD_FLAG_HINT = 4
+MEDIA_STREAM_ERROR_UNKNOWN = 0
+MEDIA_STREAM_ERROR_EOS = 1
+MEDIA_STREAM_ERROR_CODEC_NEGOTIATION_FAILED = 2
+MEDIA_STREAM_ERROR_CONNECTION_FAILED = 3
+MEDIA_STREAM_ERROR_NETWORK_ERROR = 4
+MEDIA_STREAM_ERROR_NO_CODECS = 5
+MEDIA_STREAM_ERROR_INVALID_CM_BEHAVIOR = 6
+MEDIA_STREAM_ERROR_MEDIA_ERROR = 7
+
PASSWORD_FLAG_PROVIDE = 8
# Channel.Interface.Room
@@ -523,46 +534,4 @@ SUBJECT_PRESENT = 1
SUBJECT_CAN_SET = 2
DEBUG_IFACE = PREFIX + '.Debug'
-DEBUG_PATH = PATH_PREFIX + '/debug'
-
-SERVICE_POINT_TYPE_NONE = 0
-SERVICE_POINT_TYPE_EMERGENCY = 1
-SERVICE_POINT_TYPE_COUNSELING = 2
-
-CLIENT = PREFIX + '.Client'
-CLIENT_PATH = PATH_PREFIX + '/Client'
-OBSERVER = PREFIX + '.Client.Observer'
-APPROVER = PREFIX + '.Client.Approver'
-HANDLER = PREFIX + '.Client.Handler'
-CLIENT_IFACE_REQUESTS = CLIENT + '.Interface.Requests'
-
-ACCOUNT = PREFIX + '.Account'
-ACCOUNT_IFACE_AVATAR = ACCOUNT + '.Interface.Avatar1'
-ACCOUNT_IFACE_ADDRESSING = ACCOUNT + '.Interface.Addressing1'
-ACCOUNT_IFACE_HIDDEN = ACCOUNT + '.Interface.Hidden1'
-ACCOUNT_IFACE_NOKIA_CONDITIONS = 'com.nokia.Account.Interface.Conditions'
-ACCOUNT_PATH_PREFIX = PATH_PREFIX + '/Account/'
-
-AM = PREFIX + '.AccountManager'
-AM_IFACE_HIDDEN = AM + '.Interface.Hidden1'
-AM_PATH = PATH_PREFIX + '/AccountManager'
-
-CR = PREFIX + '.ChannelRequest'
-CDO = PREFIX + '.ChannelDispatchOperation'
-
-CD = PREFIX + '.ChannelDispatcher'
-CD_IFACE_OP_LIST = PREFIX + '.ChannelDispatcher.Interface.OperationList1'
-CD_PATH = PATH_PREFIX + '/ChannelDispatcher'
-
-MC = PREFIX + '.MissionControl6'
-MC_PATH = PATH_PREFIX + '/MissionControl6'
-
-TESTDOT = PREFIX + ".Test."
-TESTSLASH = PATH_PREFIX + "/Test/"
-
-TEST_DBUS_ACCOUNT_SERVICE = TESTDOT + "DBusAccountService"
-TEST_DBUS_ACCOUNT_SERVICE_PATH = TESTSLASH + "DBusAccountService"
-TEST_DBUS_ACCOUNT_SERVICE_IFACE = TEST_DBUS_ACCOUNT_SERVICE
-
-TEST_DBUS_ACCOUNT_PLUGIN_PATH = TESTSLASH + "DBusAccountPlugin"
-TEST_DBUS_ACCOUNT_PLUGIN_IFACE = TESTDOT + "DBusAccountPlugin"
+DEBUG_PATH = '/' + PREFIX.replace('.', '/') + '/debug'
diff --git a/tests/twisted/ns.py b/tests/twisted/ns.py
index e9c24f80..b538fc4f 100644
--- a/tests/twisted/ns.py
+++ b/tests/twisted/ns.py
@@ -41,6 +41,16 @@ NS_XMPP_SASL = 'urn:ietf:params:xml:ns:xmpp-sasl'
NS_XMPP_BIND = 'urn:ietf:params:xml:ns:xmpp-bind'
NS_XMPP_TLS = 'urn:ietf:params:xml:ns:xmpp-tls'
NS_XMPP_SESSION = 'urn:ietf:params:xml:ns:xmpp-session'
+OLPC_ACTIVITIES = "http://laptop.org/xmpp/activities"
+OLPC_ACTIVITIES_NOTIFY = "%s+notify" % OLPC_ACTIVITIES
+OLPC_ACTIVITY = "http://laptop.org/xmpp/activity"
+OLPC_ACTIVITY_PROPS = "http://laptop.org/xmpp/activity-properties"
+OLPC_ACTIVITY_PROPS_NOTIFY = "%s+notify" % OLPC_ACTIVITY_PROPS
+OLPC_BUDDY = "http://laptop.org/xmpp/buddy"
+OLPC_BUDDY_PROPS = "http://laptop.org/xmpp/buddy-properties"
+OLPC_BUDDY_PROPS_NOTIFY = "%s+notify" % OLPC_BUDDY_PROPS
+OLPC_CURRENT_ACTIVITY = "http://laptop.org/xmpp/current-activity"
+OLPC_CURRENT_ACTIVITY_NOTIFY = "%s+notify" % OLPC_CURRENT_ACTIVITY
PUBSUB = "http://jabber.org/protocol/pubsub"
PUBSUB_EVENT = "%s#event" % PUBSUB
REGISTER = "jabber:iq:register"
diff --git a/tests/twisted/saluttest.py b/tests/twisted/saluttest.py
index 0517730e..fec5b1ed 100644
--- a/tests/twisted/saluttest.py
+++ b/tests/twisted/saluttest.py
@@ -54,7 +54,7 @@ def make_connection(bus, event_func, params=None):
default_params.update(params)
return servicetest.make_connection(bus, event_func, 'salut',
- 'local_xmpp', default_params)
+ 'local-xmpp', default_params)
def ensure_avahi_is_running():
bus = dbus.SystemBus()
@@ -185,11 +185,31 @@ def exec_test(fun, params=None, protocol=None, timeout=None,
make_conn)
reactor.run()
+def wait_for_contact_list(q, conn):
+ """Request contact list channels and wait for their NewChannel signals.
+ This is useful to avoid these signals to interfere with your test."""
+
+ #FIXME: this maybe racy if there are other contacts connected
+ requestotron = dbus.Interface(conn, cs.CONN_IFACE_REQUESTS)
+
+ # publish
+ requestotron.EnsureChannel({
+ cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CONTACT_LIST,
+ cs.TARGET_HANDLE_TYPE: cs.HT_LIST,
+ cs.TARGET_ID: 'publish'})
+ q.expect('dbus-signal', signal='NewChannel')
+ # subscribe
+ requestotron.EnsureChannel({
+ cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CONTACT_LIST,
+ cs.TARGET_HANDLE_TYPE: cs.HT_LIST,
+ cs.TARGET_ID: 'subscribe'})
+ q.expect('dbus-signal', signal='NewChannel')
+
def wait_for_contact_in_publish(q, bus, conn, contact_name):
handle = 0
# Wait until the record shows up in publish
while handle == 0:
- e = q.expect('dbus-signal', signal='ContactsChanged',
+ e = q.expect('dbus-signal', signal='ContactsChangedWithID',
path=conn.object_path)
for h, state in e.args[0].items():
name = e.args[1][h]
diff --git a/tests/twisted/servicetest.py b/tests/twisted/servicetest.py
index 8a813f50..bca3b13b 100644
--- a/tests/twisted/servicetest.py
+++ b/tests/twisted/servicetest.py
@@ -1,23 +1,6 @@
-# Copyright (C) 2009 Nokia Corporation
-# Copyright (C) 2009-2013 Collabora Ltd.
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library 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
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
-# 02110-1301 USA
"""
-Infrastructure code for testing Telepathy services.
+Infrastructure code for testing connection managers.
"""
from twisted.internet import glib2reactor
@@ -25,22 +8,18 @@ from twisted.internet.protocol import Protocol, Factory, ClientFactory
glib2reactor.install()
import sys
import time
-import os
import pprint
import unittest
-import dbus
-import dbus.lowlevel
-from dbus.mainloop.glib import DBusGMainLoop
-DBusGMainLoop(set_as_default=True)
+import dbus.glib
from twisted.internet import reactor
import constants as cs
-tp_name_prefix = cs.PREFIX
-tp_path_prefix = cs.PATH_PREFIX
+tp_name_prefix = 'org.freedesktop.Telepathy'
+tp_path_prefix = '/org/freedesktop/Telepathy'
class DictionarySupersetOf (object):
"""Utility class for expecting "a dictionary with at least these keys"."""
@@ -61,19 +40,16 @@ class DictionarySupersetOf (object):
except TypeError: # other is not iterable
return False
-class Event(object):
+class Event:
def __init__(self, type, **kw):
self.__dict__.update(kw)
self.type = type
(self.subqueue, self.subtype) = type.split ("-", 1)
- def __str__(self):
- return '\n'.join([ str(type(self)) ] + format_event(self))
-
def format_event(event):
ret = ['- type %s' % event.type]
- for key in sorted(dir(event)):
+ for key in dir(event):
if key != 'type' and not key.startswith('_'):
ret.append('- %s: %s' % (
key, pprint.pformat(getattr(event, key))))
@@ -175,12 +151,6 @@ class BaseEventQueue:
"""
self.forbidden_events.difference_update(set(patterns))
- def unforbid_all(self):
- """
- Remove all patterns from the set of forbidden events.
- """
- self.forbidden_events.clear()
-
def _check_forbidden(self, event):
for e in self.forbidden_events:
if e.match(event):
@@ -309,11 +279,6 @@ class IteratingEventQueue(BaseEventQueue):
def __init__(self, timeout=None):
BaseEventQueue.__init__(self, timeout)
- self._dbus_method_impls = []
- self._buses = []
- # a message filter which will claim we handled everything
- self._dbus_dev_null = \
- lambda bus, message: dbus.lowlevel.HANDLER_RESULT_HANDLED
def wait(self, queues=None):
stop = [False]
@@ -338,127 +303,6 @@ class IteratingEventQueue(BaseEventQueue):
else:
raise TimeoutError
- def add_dbus_method_impl(self, cb, bus=None, **kwargs):
- if bus is None:
- bus = self._buses[0]
-
- self._dbus_method_impls.append(
- (EventPattern('dbus-method-call', **kwargs), cb))
-
- def dbus_emit(self, path, iface, name, *a, **k):
- bus = k.pop('bus', self._buses[0])
- assert 'signature' in k, k
- message = dbus.lowlevel.SignalMessage(path, iface, name)
- message.append(*a, **k)
- bus.send_message(message)
-
- def dbus_return(self, in_reply_to, *a, **k):
- bus = k.pop('bus', self._buses[0])
- assert 'signature' in k, k
- reply = dbus.lowlevel.MethodReturnMessage(in_reply_to)
- reply.append(*a, **k)
- bus.send_message(reply)
-
- def dbus_raise(self, in_reply_to, name, message=None, bus=None):
- if bus is None:
- bus = self._buses[0]
-
- reply = dbus.lowlevel.ErrorMessage(in_reply_to, name, message)
- bus.send_message(reply)
-
- def attach_to_bus(self, bus):
- if not self._buses:
- # first-time setup
- self._dbus_filter_bound_method = self._dbus_filter
-
- self._buses.append(bus)
-
- # Only subscribe to messages on the first bus connection (assumed to
- # be the shared session bus connection used by the simulated connection
- # manager and most of the test suite), not on subsequent bus
- # connections (assumed to represent extra clients).
- #
- # When we receive a method call on the other bus connections, ignore
- # it - the eavesdropping filter installed on the first bus connection
- # will see it too.
- #
- # This is highly counter-intuitive, but it means our messages are in
- # a guaranteed order (we don't have races between messages arriving on
- # various connections).
- if len(self._buses) > 1:
- bus.add_message_filter(self._dbus_dev_null)
- return
-
- try:
- # for dbus > 1.5
- bus.add_match_string("eavesdrop=true,type='signal'")
- except dbus.DBusException:
- bus.add_match_string("type='signal'")
- bus.add_match_string("type='method_call'")
- else:
- bus.add_match_string("eavesdrop=true,type='method_call'")
-
- bus.add_message_filter(self._dbus_filter_bound_method)
-
- bus.add_signal_receiver(
- lambda *args, **kw:
- self.append(
- Event('dbus-signal',
- path=unwrap(kw['path']),
- signal=kw['member'],
- args=map(unwrap, args),
- interface=kw['interface'])),
- None,
- None,
- None,
- path_keyword='path',
- member_keyword='member',
- interface_keyword='interface',
- byte_arrays=True,
- )
-
- def cleanup(self):
- if self._buses:
- self._buses[0].remove_message_filter(self._dbus_filter_bound_method)
- for bus in self._buses[1:]:
- bus.remove_message_filter(self._dbus_dev_null)
-
- self._buses = []
- self._dbus_method_impls = []
-
- def _dbus_filter(self, bus, message):
- if isinstance(message, dbus.lowlevel.MethodCallMessage):
-
- destination = message.get_destination()
- sender = message.get_sender()
-
- if (destination == 'org.freedesktop.DBus' or
- sender == self._buses[0].get_unique_name()):
- # suppress reply and don't make an Event
- return dbus.lowlevel.HANDLER_RESULT_HANDLED
-
- e = Event('dbus-method-call', message=message,
- interface=message.get_interface(), path=message.get_path(),
- raw_args=message.get_args_list(byte_arrays=True),
- args=map(unwrap, message.get_args_list(byte_arrays=True)),
- destination=str(destination),
- method=message.get_member(),
- sender=message.get_sender(),
- handled=False)
-
- for pair in self._dbus_method_impls:
- pattern, cb = pair
- if pattern.match(e):
- cb(e)
- e.handled = True
- break
-
- self.append(e)
-
- return dbus.lowlevel.HANDLER_RESULT_HANDLED
-
- return dbus.lowlevel.HANDLER_RESULT_NOT_YET_HANDLED
-
class TestEventQueue(BaseEventQueue):
def __init__(self, events):
BaseEventQueue.__init__(self)
@@ -569,23 +413,20 @@ def call_async(test, proxy, method, *args, **kw):
kw.update({'reply_handler': reply_func, 'error_handler': error_func})
method_proxy(*args, **kw)
-def sync_dbus(bus, q, proxy):
- # Dummy D-Bus method call. We can't use DBus.Peer.Ping() because libdbus
- # replies to that message immediately, rather than handing it up to
- # dbus-glib and thence the application, which means that Ping()ing the
- # application doesn't ensure that it's processed all D-Bus messages prior
- # to our ping.
- call_async(q, dbus.Interface(proxy, 'org.freedesktop.Telepathy.Tests'),
- 'DummySyncDBus')
+def sync_dbus(bus, q, conn):
+ # Dummy D-Bus method call
+ # This won't do the right thing unless the proxy has a unique name.
+ assert conn.object.bus_name.startswith(':')
+ root_object = bus.get_object(conn.object.bus_name, '/')
+ call_async(
+ q, dbus.Interface(root_object, 'org.freedesktop.Telepathy.Tests'), 'DummySyncDBus')
q.expect('dbus-error', method='DummySyncDBus')
class ProxyWrapper:
- def __init__(self, object, default, others={}):
+ def __init__(self, object, default, others):
self.object = object
self.default_interface = dbus.Interface(object, default)
self.Properties = dbus.Interface(object, dbus.PROPERTIES_IFACE)
- self.TpProperties = \
- dbus.Interface(object, tp_name_prefix + '.Properties')
self.interfaces = dict([
(name, dbus.Interface(object, iface))
for name, iface in others.iteritems()])
@@ -599,47 +440,27 @@ class ProxyWrapper:
return getattr(self.default_interface, name)
-class ConnWrapper(ProxyWrapper):
- def inspect_contact_sync(self, handle):
- return self.inspect_contacts_sync([handle])[0]
-
- def inspect_contacts_sync(self, handles):
- h2asv = self.Contacts.GetContactAttributes(handles, [])
- ret = []
- for h in handles:
- ret.append(h2asv[h][cs.ATTR_CONTACT_ID])
- return ret
-
- def get_contact_handle_sync(self, identifier):
- return self.Contacts.GetContactByID(identifier, [])[0]
-
- def get_contact_handles_sync(self, ids):
- return [self.get_contact_handle_sync(i) for i in ids]
-
def wrap_connection(conn):
- return ConnWrapper(conn, tp_name_prefix + '.Connection',
- dict(
+ return ProxyWrapper(conn, tp_name_prefix + '.Connection',
+ dict([
+ (name, tp_name_prefix + '.Connection.Interface.' + name)
+ for name in ['Aliasing', 'Avatars', 'Capabilities', 'Contacts',
+ 'Presence', 'SimplePresence', 'Requests']] +
[('Peer', 'org.freedesktop.DBus.Peer'),
- ('Aliasing', cs.CONN_IFACE_ALIASING),
- ('Avatars', cs.CONN_IFACE_AVATARS),
- ('Contacts', cs.CONN_IFACE_CONTACTS),
('ContactCapabilities', cs.CONN_IFACE_CONTACT_CAPS),
('ContactInfo', cs.CONN_IFACE_CONTACT_INFO),
('Location', cs.CONN_IFACE_LOCATION),
- ('Presence', cs.CONN_IFACE_PRESENCE),
- ('Requests', cs.CONN_IFACE_REQUESTS),
('Future', tp_name_prefix + '.Connection.FUTURE'),
('MailNotification', cs.CONN_IFACE_MAIL_NOTIFICATION),
('ContactList', cs.CONN_IFACE_CONTACT_LIST),
('ContactGroups', cs.CONN_IFACE_CONTACT_GROUPS),
('PowerSaving', cs.CONN_IFACE_POWER_SAVING),
- ('Addressing', cs.CONN_IFACE_ADDRESSING),
]))
def wrap_channel(chan, type_, extra=None):
interfaces = {
type_: tp_name_prefix + '.Channel.Type.' + type_,
- 'Group': cs.CHANNEL_IFACE_GROUP,
+ 'Group': tp_name_prefix + '.Channel.Interface.Group',
}
if extra:
@@ -649,26 +470,14 @@ def wrap_channel(chan, type_, extra=None):
return ProxyWrapper(chan, tp_name_prefix + '.Channel', interfaces)
-
-def wrap_content(chan, extra=None):
- interfaces = { }
-
- if extra:
- interfaces.update(dict([
- (name, tp_name_prefix + '.Call1.Content.Interface.' + name)
- for name in extra]))
-
- return ProxyWrapper(chan, tp_name_prefix + '.Call1.Content', interfaces)
-
def make_connection(bus, event_func, name, proto, params):
cm = bus.get_object(
tp_name_prefix + '.ConnectionManager.%s' % name,
- tp_path_prefix + '/ConnectionManager/%s' % name,
- introspect=False)
+ tp_path_prefix + '/ConnectionManager/%s' % name)
cm_iface = dbus.Interface(cm, tp_name_prefix + '.ConnectionManager')
connection_name, connection_path = cm_iface.RequestConnection(
- proto, dbus.Dictionary(params, signature='sv'))
+ proto, params)
conn = wrap_connection(bus.get_object(connection_name, connection_path))
return conn
@@ -815,16 +624,6 @@ def install_colourer():
sys.stdout = Colourer(sys.stdout, patterns)
return sys.stdout
-# this is just to shut up unittest.
-class DummyStream(object):
- def write(self, s):
- if 'CHECK_TWISTED_VERBOSE' in os.environ:
- print s,
-
- def flush(self):
- pass
-
if __name__ == '__main__':
- stream = DummyStream()
- runner = unittest.TextTestRunner(stream=stream)
- unittest.main(testRunner=runner)
+ unittest.main()
+
diff --git a/tests/twisted/sidecars.py b/tests/twisted/sidecars.py
index 137a27f8..26a7b67c 100644
--- a/tests/twisted/sidecars.py
+++ b/tests/twisted/sidecars.py
@@ -9,7 +9,7 @@ from saluttest import exec_test
import constants as cs
from config import PLUGINS_ENABLED
-TEST_PLUGIN_IFACE = "im.telepathy1.Salut.Plugin.Test"
+TEST_PLUGIN_IFACE = "org.freedesktop.Telepathy.Salut.Plugin.Test"
if not PLUGINS_ENABLED:
print "NOTE: built without --enable-plugins, not testing plugins"
diff --git a/tests/twisted/tools/Makefile.am b/tests/twisted/tools/Makefile.am
index bab9999f..aaca6af3 100644
--- a/tests/twisted/tools/Makefile.am
+++ b/tests/twisted/tools/Makefile.am
@@ -8,12 +8,12 @@ exec-with-log.sh: exec-with-log.sh.in
# We don't use the full filename for the .in because > 99 character filenames
# in tarballs are non-portable (and automake 1.8 doesn't let us build
# non-archaic tarballs)
-im.telepathy1.ConnectionManager.%.service: %.service.in
+org.freedesktop.Telepathy.ConnectionManager.%.service: %.service.in
$(AM_V_GEN)sed -e "s|[@]abs_top_builddir[@]|@abs_top_builddir@|g" $< > $@
# D-Bus service file for testing
service_in_files = salut.service.in
-service_files = im.telepathy1.ConnectionManager.salut.service
+service_files = org.freedesktop.Telepathy.ConnectionManager.salut.service
# D-Bus config file for testing
conf_in_files = tmp-session-bus.conf.in
diff --git a/tests/twisted/tools/salut.service.in b/tests/twisted/tools/salut.service.in
index c517ba10..93adb71d 100644
--- a/tests/twisted/tools/salut.service.in
+++ b/tests/twisted/tools/salut.service.in
@@ -1,3 +1,3 @@
[D-BUS Service]
-Name=im.telepathy1.ConnectionManager.salut
+Name=org.freedesktop.Telepathy.ConnectionManager.salut
Exec=@abs_top_builddir@/tests/twisted/tools/exec-with-log.sh