[telepathy-glib/master] Add basic proxies for ChannelDispatchOperation, ChannelRequest

Simon McVittie simon.mcvittie at collabora.co.uk
Tue Jun 9 01:27:57 PDT 2009


---
 docs/reference/telepathy-glib-docs.sgml         |    4 +
 docs/reference/telepathy-glib-sections.txt      |  114 ++++++++++
 docs/reference/telepathy-glib.types             |    8 +
 spec/Channel_Dispatch_Operation.xml             |    3 +-
 spec/Channel_Request.xml                        |    3 +-
 telepathy-glib/Makefile.am                      |   25 ++
 telepathy-glib/channel-dispatch-operation.c     |  223 ++++++++++++++++++
 telepathy-glib/channel-dispatch-operation.h     |   78 +++++++
 telepathy-glib/channel-dispatch-operation.xml   |    9 +
 telepathy-glib/channel-request.c                |  250 ++++++++++++++++++++
 telepathy-glib/channel-request.h                |   74 ++++++
 telepathy-glib/channel-request.xml              |    9 +
 telepathy-glib/extra-gtkdoc.h                   |   45 ++++
 telepathy-glib/stable-interfaces.xml            |    2 +
 telepathy-glib/svc-channel-dispatch-operation.h |    6 +
 telepathy-glib/svc-channel-request.h            |    6 +
 tests/dbus/Makefile.am                          |    6 +
 tests/dbus/channel-dispatch-operation.c         |  232 +++++++++++++++++++
 tests/dbus/channel-request.c                    |  276 +++++++++++++++++++++++
 19 files changed, 1369 insertions(+), 4 deletions(-)
 create mode 100644 telepathy-glib/channel-dispatch-operation.c
 create mode 100644 telepathy-glib/channel-dispatch-operation.h
 create mode 100644 telepathy-glib/channel-dispatch-operation.xml
 create mode 100644 telepathy-glib/channel-request.c
 create mode 100644 telepathy-glib/channel-request.h
 create mode 100644 telepathy-glib/channel-request.xml
 create mode 100644 telepathy-glib/svc-channel-dispatch-operation.h
 create mode 100644 telepathy-glib/svc-channel-request.h
 create mode 100644 tests/dbus/channel-dispatch-operation.c
 create mode 100644 tests/dbus/channel-request.c

diff --git a/docs/reference/telepathy-glib-docs.sgml b/docs/reference/telepathy-glib-docs.sgml
index 48260d1..cdc2e06 100644
--- a/docs/reference/telepathy-glib-docs.sgml
+++ b/docs/reference/telepathy-glib-docs.sgml
@@ -49,6 +49,8 @@
     <xi:include href="xml/account-manager.xml"/>
     <xi:include href="xml/account.xml"/>
     <xi:include href="xml/channel-dispatcher.xml"/>
+    <xi:include href="xml/channel-dispatch-operation.xml"/>
+    <xi:include href="xml/channel-request.xml"/>
   </chapter>
 
   <chapter id="ch-service-dbus">
@@ -70,6 +72,8 @@
     <xi:include href="xml/svc-account-manager.xml"/>
     <xi:include href="xml/svc-account.xml"/>
     <xi:include href="xml/svc-channel-dispatcher.xml"/>
+    <xi:include href="xml/svc-channel-dispatch-operation.xml"/>
+    <xi:include href="xml/svc-channel-request.xml"/>
   </chapter>
   <chapter id="ch-service-base">
     <title>Service-side implementation</title>
diff --git a/docs/reference/telepathy-glib-sections.txt b/docs/reference/telepathy-glib-sections.txt
index 11ba907..ccc40a5 100644
--- a/docs/reference/telepathy-glib-sections.txt
+++ b/docs/reference/telepathy-glib-sections.txt
@@ -1940,6 +1940,10 @@ TP_IFACE_CHANNEL_DISPATCHER
 TP_IFACE_QUARK_CHANNEL_DISPATCHER
 TP_IFACE_CHANNEL_DISPATCHER_INTERFACE_OPERATION_LIST
 TP_IFACE_QUARK_CHANNEL_DISPATCHER_INTERFACE_OPERATION_LIST
+TP_IFACE_CHANNEL_DISPATCH_OPERATION
+TP_IFACE_QUARK_CHANNEL_DISPATCH_OPERATION
+TP_IFACE_CHANNEL_REQUEST
+TP_IFACE_QUARK_CHANNEL_REQUEST
 TP_IFACE_MEDIA_SESSION_HANDLER
 TP_IFACE_QUARK_MEDIA_SESSION_HANDLER
 TP_IFACE_MEDIA_STREAM_HANDLER
@@ -1973,6 +1977,8 @@ tp_iface_quark_channel_type_dbus_tube
 tp_iface_quark_channel_type_stream_tube
 tp_iface_quark_channel_dispatcher
 tp_iface_quark_channel_dispatcher_interface_operation_list
+tp_iface_quark_channel_dispatch_operation
+tp_iface_quark_channel_request
 tp_iface_quark_connection
 tp_iface_quark_connection_interface_aliasing
 tp_iface_quark_connection_interface_avatars
@@ -3007,3 +3013,111 @@ tp_svc_channel_dispatcher_interface_operation_list_get_type
 TP_SVC_CHANNEL_DISPATCHER_GET_CLASS
 TP_SVC_CHANNEL_DISPATCHER_INTERFACE_OPERATION_LIST_GET_CLASS
 </SECTION>
+
+<SECTION>
+<FILE>channel-dispatch-operation</FILE>
+<INCLUDE>telepathy-glib/channel-dispatch-operation.h</INCLUDE>
+<TITLE>channel-dispatch-operation</TITLE>
+TpChannelDispatchOperation
+TpChannelDispatchOperationClass
+tp_channel_dispatch_operation_new
+<SUBSECTION>
+tp_cli_channel_dispatch_operation_callback_for_claim
+tp_cli_channel_dispatch_operation_call_claim
+tp_cli_channel_dispatch_operation_callback_for_handle_with
+tp_cli_channel_dispatch_operation_call_handle_with
+tp_cli_channel_dispatch_operation_signal_callback_channel_lost
+tp_cli_channel_dispatch_operation_connect_to_channel_lost
+tp_cli_channel_dispatch_operation_signal_callback_finished
+tp_cli_channel_dispatch_operation_connect_to_finished
+<SUBSECTION Standard>
+TP_CHANNEL_DISPATCH_OPERATION
+TP_CHANNEL_DISPATCH_OPERATION_CLASS
+TP_CHANNEL_DISPATCH_OPERATION_GET_CLASS
+TP_IS_CHANNEL_DISPATCH_OPERATION
+TP_IS_CHANNEL_DISPATCH_OPERATION_CLASS
+TP_TYPE_CHANNEL_DISPATCH_OPERATION
+tp_channel_dispatch_operation_get_type
+<SUBSECTION Private>
+# leaving these undocumented as a step towards deprecating all _run_ methods
+# (these ones have never been documented)
+tp_cli_channel_dispatch_operation_run_claim
+tp_cli_channel_dispatch_operation_run_handle_with
+</SECTION>
+
+<SECTION>
+<FILE>channel-request</FILE>
+<INCLUDE>telepathy-glib/channel-request.h</INCLUDE>
+<TITLE>channel-request</TITLE>
+TpChannelRequest
+TpChannelRequestClass
+tp_channel_request_new
+<SUBSECTION>
+tp_cli_channel_request_callback_for_cancel
+tp_cli_channel_request_call_cancel
+tp_cli_channel_request_callback_for_proceed
+tp_cli_channel_request_call_proceed
+tp_cli_channel_request_signal_callback_failed
+tp_cli_channel_request_connect_to_failed
+tp_cli_channel_request_signal_callback_succeeded
+tp_cli_channel_request_connect_to_succeeded
+<SUBSECTION Standard>
+TP_CHANNEL_REQUEST
+TP_CHANNEL_REQUEST_CLASS
+TP_CHANNEL_REQUEST_GET_CLASS
+TP_IS_CHANNEL_REQUEST
+TP_IS_CHANNEL_REQUEST_CLASS
+TP_TYPE_CHANNEL_REQUEST
+TpChannelRequestClassPrivate
+TpChannelRequestPrivate
+tp_channel_request_get_type
+<SUBSECTION Private>
+# leaving these undocumented as a step towards deprecating all _run_ methods
+# (these ones have never been documented)
+tp_cli_channel_request_run_cancel
+tp_cli_channel_request_run_proceed
+</SECTION>
+
+<SECTION>
+<FILE>svc-channel-dispatch-operation</FILE>
+<INCLUDE>telepathy-glib/svc-channel-dispatch-operation.h</INCLUDE>
+<TITLE>svc-channel-dispatch-operation</TITLE>
+TpSvcChannelDispatchOperation
+TpSvcChannelDispatchOperationClass
+tp_svc_channel_dispatch_operation_return_from_claim
+tp_svc_channel_dispatch_operation_claim_impl
+tp_svc_channel_dispatch_operation_implement_claim
+tp_svc_channel_dispatch_operation_return_from_handle_with
+tp_svc_channel_dispatch_operation_handle_with_impl
+tp_svc_channel_dispatch_operation_implement_handle_with
+tp_svc_channel_dispatch_operation_emit_channel_lost
+tp_svc_channel_dispatch_operation_emit_finished
+<SUBSECTION Standard>
+tp_svc_channel_dispatch_operation_get_type
+TP_IS_SVC_CHANNEL_DISPATCH_OPERATION
+TP_SVC_CHANNEL_DISPATCH_OPERATION
+TP_SVC_CHANNEL_DISPATCH_OPERATION_GET_CLASS
+TP_TYPE_SVC_CHANNEL_DISPATCH_OPERATION
+</SECTION>
+
+<SECTION>
+<FILE>svc-channel-request</FILE>
+<INCLUDE>telepathy-glib/svc-channel-request.h</INCLUDE>
+<TITLE>svc-channel-request</TITLE>
+TpSvcChannelRequest
+TpSvcChannelRequestClass
+tp_svc_channel_request_return_from_proceed
+tp_svc_channel_request_proceed_impl
+tp_svc_channel_request_implement_proceed
+tp_svc_channel_request_return_from_cancel
+tp_svc_channel_request_cancel_impl
+tp_svc_channel_request_implement_cancel
+tp_svc_channel_request_emit_failed
+tp_svc_channel_request_emit_succeeded
+<SUBSECTION Standard>
+tp_svc_channel_request_get_type
+TP_IS_SVC_CHANNEL_REQUEST
+TP_SVC_CHANNEL_REQUEST
+TP_SVC_CHANNEL_REQUEST_GET_CLASS
+TP_TYPE_SVC_CHANNEL_REQUEST
+</SECTION>
diff --git a/docs/reference/telepathy-glib.types b/docs/reference/telepathy-glib.types
index 47c5320..1a7171a 100644
--- a/docs/reference/telepathy-glib.types
+++ b/docs/reference/telepathy-glib.types
@@ -5,8 +5,10 @@
 #include <telepathy-glib/channel-factory-iface.h>
 #include <telepathy-glib/channel.h>
 #include <telepathy-glib/channel-dispatcher.h>
+#include <telepathy-glib/channel-dispatch-operation.h>
 #include <telepathy-glib/channel-iface.h>
 #include <telepathy-glib/channel-manager.h>
+#include <telepathy-glib/channel-request.h>
 #include <telepathy-glib/connection.h>
 #include <telepathy-glib/connection-manager.h>
 #include <telepathy-glib/contact.h>
@@ -20,6 +22,8 @@
 #include <telepathy-glib/svc-account-manager.h>
 #include <telepathy-glib/svc-channel.h>
 #include <telepathy-glib/svc-channel-dispatcher.h>
+#include <telepathy-glib/svc-channel-dispatch-operation.h>
+#include <telepathy-glib/svc-channel-request.h>
 #include <telepathy-glib/svc-connection.h>
 #include <telepathy-glib/svc-connection-manager.h>
 #include <telepathy-glib/svc-generic.h>
@@ -33,8 +37,10 @@ tp_base_connection_manager_get_type
 tp_channel_factory_iface_get_type
 tp_channel_get_type
 tp_channel_dispatcher_get_type
+tp_channel_dispatch_operation_get_type
 tp_channel_iface_get_type
 tp_channel_manager_get_type
+tp_channel_request_get_type
 tp_connection_get_type
 tp_connection_manager_get_type
 tp_contact_get_type
@@ -52,6 +58,7 @@ tp_svc_account_manager_get_type
 tp_svc_channel_get_type
 tp_svc_channel_dispatcher_get_type
 tp_svc_channel_dispatcher_interface_operation_list_get_type
+tp_svc_channel_dispatch_operation_get_type
 tp_svc_channel_interface_call_state_get_type
 tp_svc_channel_interface_chat_state_get_type
 tp_svc_channel_interface_dtmf_get_type
@@ -59,6 +66,7 @@ tp_svc_channel_interface_group_get_type
 tp_svc_channel_interface_hold_get_type
 tp_svc_channel_interface_media_signalling_get_type
 tp_svc_channel_interface_password_get_type
+tp_svc_channel_request_get_type
 tp_svc_channel_type_contact_list_get_type
 tp_svc_channel_type_room_list_get_type
 tp_svc_channel_type_streamed_media_get_type
diff --git a/spec/Channel_Dispatch_Operation.xml b/spec/Channel_Dispatch_Operation.xml
index a44712c..82d73b5 100644
--- a/spec/Channel_Dispatch_Operation.xml
+++ b/spec/Channel_Dispatch_Operation.xml
@@ -21,8 +21,7 @@
       MA 02110-1301, USA.</p>
   </tp:license>
 
-  <interface name="org.freedesktop.Telepathy.ChannelDispatchOperation"
-    tp:causes-havoc="not yet final">
+  <interface name="org.freedesktop.Telepathy.ChannelDispatchOperation">
 
     <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
       <p>A channel dispatch operation is an object in the ChannelDispatcher
diff --git a/spec/Channel_Request.xml b/spec/Channel_Request.xml
index c69266a..bd42952 100644
--- a/spec/Channel_Request.xml
+++ b/spec/Channel_Request.xml
@@ -21,8 +21,7 @@
       MA 02110-1301, USA.</p>
   </tp:license>
 
-  <interface name="org.freedesktop.Telepathy.ChannelRequest"
-    tp:causes-havoc="not yet final">
+  <interface name="org.freedesktop.Telepathy.ChannelRequest">
 
     <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
       <p>A channel request is an object in the ChannelDispatcher representing
diff --git a/telepathy-glib/Makefile.am b/telepathy-glib/Makefile.am
index 29fd8ba..6f817c3 100644
--- a/telepathy-glib/Makefile.am
+++ b/telepathy-glib/Makefile.am
@@ -42,6 +42,9 @@ EXTRA_DIST = \
     account.xml \
     account-manager.xml \
     channel.xml \
+    channel-dispatcher.xml \
+    channel-dispatch-operation.xml \
+    channel-request.xml \
     connection.xml \
     connection-manager.xml \
     dbus-daemon.xml \
@@ -123,8 +126,10 @@ tpginclude_HEADERS = \
     channel.h \
     channel-iface.h \
     channel-dispatcher.h \
+    channel-dispatch-operation.h \
     channel-factory-iface.h \
     channel-manager.h \
+    channel-request.h \
     connection.h \
     connection-manager.h \
     contact.h \
@@ -175,6 +180,8 @@ nodist_libtelepathy_glib_internal_la_SOURCES = \
     _gen/tp-cli-account-manager-body.h \
     _gen/tp-cli-channel-body.h \
     _gen/tp-cli-channel-dispatcher-body.h \
+    _gen/tp-cli-channel-dispatch-operation-body.h \
+    _gen/tp-cli-channel-request-body.h \
     _gen/tp-cli-connection-body.h \
     _gen/tp-cli-connection-manager-body.h \
     _gen/tp-cli-dbus-daemon-body.h \
@@ -185,6 +192,8 @@ nodist_libtelepathy_glib_internal_la_SOURCES = \
     _gen/tp-svc-account-manager.c \
     _gen/tp-svc-channel.c \
     _gen/tp-svc-channel-dispatcher.c \
+    _gen/tp-svc-channel-dispatch-operation.c \
+    _gen/tp-svc-channel-request.c \
     _gen/tp-svc-connection.c \
     _gen/tp-svc-connection-manager.c \
     _gen/tp-svc-generic.c \
@@ -200,6 +209,8 @@ nodist_geninclude_HEADERS = \
     _gen/tp-cli-account-manager.h \
     _gen/tp-cli-channel.h \
     _gen/tp-cli-channel-dispatcher.h \
+    _gen/tp-cli-channel-dispatch-operation.h \
+    _gen/tp-cli-channel-request.h \
     _gen/tp-cli-connection.h \
     _gen/tp-cli-connection-manager.h \
     _gen/tp-cli-dbus-daemon.h \
@@ -210,6 +221,8 @@ nodist_geninclude_HEADERS = \
     _gen/tp-svc-account-manager.h \
     _gen/tp-svc-channel.h \
     _gen/tp-svc-channel-dispatcher.h \
+    _gen/tp-svc-channel-dispatch-operation.h \
+    _gen/tp-svc-channel-request.h \
     _gen/tp-svc-connection.h \
     _gen/tp-svc-connection-manager.h \
     _gen/tp-svc-generic.h \
@@ -246,7 +259,9 @@ libtelepathy_glib_internal_la_SOURCES = \
     channel-group.c \
     channel-internal.h \
     channel-dispatcher.c \
+    channel-dispatch-operation.c \
     channel-manager.c \
+    channel-request.c \
     connection.c \
     connection-internal.h \
     connection-handles.c \
@@ -405,6 +420,16 @@ _gen/tp-cli-%-body.h _gen/tp-cli-%.h: _gen/tp-spec-%.xml \
 			subclass_assert=--subclass-assert=TP_IS_CHANNEL_DISPATCHER; \
 			maybe_reentrant=--generate-reentrant; \
 			;; \
+		channel-dispatch-operation) \
+			subclass=--subclass=TpChannelDispatchOperation; \
+			subclass_assert=--subclass-assert=TP_IS_CHANNEL_DISPATCH_OPERATION; \
+			maybe_reentrant=--generate-reentrant; \
+			;; \
+		channel-request) \
+			subclass=--subclass=TpChannelRequest; \
+			subclass_assert=--subclass-assert=TP_IS_CHANNEL_REQUEST; \
+			maybe_reentrant=--generate-reentrant; \
+			;; \
 		connection-manager) \
 			subclass=--subclass=TpConnectionManager; \
 			subclass_assert=--subclass-assert=TP_IS_CONNECTION_MANAGER \
diff --git a/telepathy-glib/channel-dispatch-operation.c b/telepathy-glib/channel-dispatch-operation.c
new file mode 100644
index 0000000..f47a14c
--- /dev/null
+++ b/telepathy-glib/channel-dispatch-operation.c
@@ -0,0 +1,223 @@
+/*
+ * channel-dispatch-operation.c - proxy for incoming channels seeking approval
+ *
+ * Copyright (C) 2009 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * 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 "telepathy-glib/channel-dispatch-operation.h"
+
+#include <telepathy-glib/defs.h>
+#include <telepathy-glib/errors.h>
+#include <telepathy-glib/interfaces.h>
+#include <telepathy-glib/proxy-subclass.h>
+
+#define DEBUG_FLAG TP_DEBUG_DISPATCHER
+#include "telepathy-glib/dbus-internal.h"
+#include "telepathy-glib/debug-internal.h"
+
+#include "telepathy-glib/_gen/tp-cli-channel-dispatch-operation-body.h"
+
+/**
+ * SECTION:channel-dispatch-operation
+ * @title: TpChannelDispatchOperation
+ * @short_description: proxy object for a to the Telepathy channel
+ *  dispatcher
+ * @see_also: #TpChannelDispatcher
+ *
+ * One of the channel dispatcher's functions is to offer incoming channels to
+ * Approver clients for approval. Approvers respond to the channel dispatcher
+ * via a #TpChannelDispatchOperation object.
+ */
+
+/**
+ * TpChannelDispatchOperation:
+ *
+ * One of the channel dispatcher's functions is to offer incoming channels to
+ * Approver clients for approval. An approver should generally ask the user
+ * whether they want to participate in the requested communication channels
+ * (join the chat or chatroom, answer the call, accept the file transfer, or
+ * whatever is appropriate). A collection of channels offered in this way
+ * is represented by a ChannelDispatchOperation object.
+ *
+ * If the user wishes to accept the communication channels, the approver
+ * should call tp_cli_channel_dispatch_operation_call_handle_with() to
+ * indicate the user's or approver's preferred handler for the channels (the
+ * empty string indicates no particular preference, and will cause any
+ * suitable handler to be used).
+ *
+ * If the user wishes to reject the communication channels, or if the user
+ * accepts the channels and the approver will handle them itself, the approver
+ * should call tp_cli_channel_dispatch_operation_call_claim(). If this method
+ * succeeds, the approver immediately has control over the channels as their
+ * primary handler, and may do anything with them (in particular, it may close
+ * them in whatever way seems most appropriate).
+ *
+ * There are various situations in which the channel dispatch operation will
+ * be closed, causing the #TpProxy::invalidated signal to be emitted. If this
+ * happens, the approver should stop prompting the user.
+ *
+ * Because all approvers are launched simultaneously, the user might respond
+ * to another approver; if this happens, the invalidated signal will be
+ * emitted with the domain %TP_DBUS_ERRORS and the error code
+ * %TP_DBUS_ERROR_OBJECT_REMOVED.
+ *
+ * If a channel closes, the D-Bus signal ChannelLost is emitted; this class
+ * doesn't (yet) have a GObject binding for this signal, but you can use
+ * tp_cli_channel_dispatch_operation_connect_to_channel_lost(). If all channels
+ * close, there is nothing more to dispatch, so the invalidated signal will be
+ * emitted with the domain %TP_DBUS_ERRORS and the error code
+ * %TP_DBUS_ERROR_OBJECT_REMOVED.
+ *
+ * If the channel dispatcher crashes or exits, the invalidated
+ * signal will be emitted with the domain %TP_DBUS_ERRORS and the error code
+ * %TP_DBUS_ERROR_NAME_OWNER_LOST. In a high-quality implementation, the
+ * dispatcher should be restarted, at which point it will create new
+ * channel dispatch operations for any undispatched channels, and the approver
+ * will be notified again.
+ *
+ * This proxy is usable but incomplete: accessors for the D-Bus properties will
+ * be added in a later version of telepathy-glib, along with a mechanism
+ * similar to tp_connection_call_when_ready().
+ *
+ * Since: 0.7.UNRELEASED
+ */
+
+/**
+ * TpChannelDispatchOperationClass:
+ *
+ * The class of a #TpChannelDispatchOperation.
+ */
+
+struct _TpChannelDispatchOperationPrivate {
+    gpointer dummy;
+};
+
+G_DEFINE_TYPE (TpChannelDispatchOperation, tp_channel_dispatch_operation,
+    TP_TYPE_PROXY);
+
+static void
+tp_channel_dispatch_operation_init (TpChannelDispatchOperation *self)
+{
+  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+      TP_TYPE_CHANNEL_DISPATCH_OPERATION, TpChannelDispatchOperationPrivate);
+}
+
+static void
+tp_channel_dispatch_operation_finished_cb (TpChannelDispatchOperation *self,
+    gpointer unused G_GNUC_UNUSED,
+    GObject *object G_GNUC_UNUSED)
+{
+  GError e = { TP_DBUS_ERRORS, TP_DBUS_ERROR_OBJECT_REMOVED,
+      "ChannelDispatchOperation finished and was removed" };
+
+  tp_proxy_invalidate ((TpProxy *) self, &e);
+}
+
+static void
+tp_channel_dispatch_operation_constructed (GObject *object)
+{
+  TpChannelDispatchOperation *self = TP_CHANNEL_DISPATCH_OPERATION (object);
+  void (*chain_up) (GObject *) =
+    ((GObjectClass *) tp_channel_dispatch_operation_parent_class)->constructed;
+  GError *error = NULL;
+  TpProxySignalConnection *sc;
+
+  if (chain_up != NULL)
+    chain_up (object);
+
+  g_return_if_fail (tp_proxy_get_dbus_daemon (self) != NULL);
+
+  sc = tp_cli_channel_dispatch_operation_connect_to_finished (self,
+      tp_channel_dispatch_operation_finished_cb, NULL, NULL, NULL, &error);
+
+  if (sc == NULL)
+    {
+      g_critical ("Couldn't connect to Finished: %s", error->message);
+      g_error_free (error);
+      g_assert_not_reached ();
+      return;
+    }
+}
+
+static void
+tp_channel_dispatch_operation_class_init (TpChannelDispatchOperationClass *klass)
+{
+  GType tp_type = TP_TYPE_CHANNEL_DISPATCH_OPERATION;
+  TpProxyClass *proxy_class = (TpProxyClass *) klass;
+  GObjectClass *object_class = (GObjectClass *) klass;
+
+  g_type_class_add_private (klass, sizeof (TpChannelDispatchOperationPrivate));
+
+  object_class->constructed = tp_channel_dispatch_operation_constructed;
+
+  proxy_class->interface = TP_IFACE_QUARK_CHANNEL_DISPATCH_OPERATION;
+  tp_proxy_or_subclass_hook_on_interface_add (tp_type,
+      tp_cli_channel_dispatch_operation_add_signals);
+  tp_proxy_subclass_add_error_mapping (tp_type,
+      TP_ERROR_PREFIX, TP_ERRORS, TP_TYPE_ERROR);
+  proxy_class->must_have_unique_name = TRUE;
+}
+
+/**
+ * tp_channel_dispatch_operation_new:
+ * @bus_daemon: Proxy for the D-Bus daemon
+ * @object_path: The non-NULL object path of this channel dispatch operation
+ * @immutable_properties: As many as are known of the immutable D-Bus
+ *  properties of this channel dispatch operation, or %NULL if none are known
+ * @error: Used to raise an error if %NULL is returned
+ *
+ * Convenience function to create a new channel dispatch operation proxy.
+ *
+ * The @immutable_properties argument is not yet used.
+ *
+ * Returns: a new reference to an channel dispatch operation proxy, or %NULL if
+ *    @object_path is not syntactically valid or the channel dispatcher is not
+ *    running
+ */
+TpChannelDispatchOperation *
+tp_channel_dispatch_operation_new (TpDBusDaemon *bus_daemon,
+    const gchar *object_path,
+    GHashTable *immutable_properties G_GNUC_UNUSED,
+    GError **error)
+{
+  TpChannelDispatchOperation *self;
+  gchar *unique_name;
+
+  g_return_val_if_fail (bus_daemon != NULL, NULL);
+  g_return_val_if_fail (object_path != NULL, NULL);
+  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+  if (!tp_dbus_check_valid_object_path (object_path, error))
+    return NULL;
+
+  if (!_tp_dbus_daemon_get_name_owner (bus_daemon, -1,
+      TP_CHANNEL_DISPATCHER_BUS_NAME, &unique_name, error))
+    return NULL;
+
+  self = TP_CHANNEL_DISPATCH_OPERATION (g_object_new (
+        TP_TYPE_CHANNEL_DISPATCH_OPERATION,
+        "dbus-daemon", bus_daemon,
+        "dbus-connection", ((TpProxy *) bus_daemon)->dbus_connection,
+        "bus-name", unique_name,
+        "object-path", object_path,
+        NULL));
+
+  g_free (unique_name);
+
+  return self;
+}
diff --git a/telepathy-glib/channel-dispatch-operation.h b/telepathy-glib/channel-dispatch-operation.h
new file mode 100644
index 0000000..aaa5085
--- /dev/null
+++ b/telepathy-glib/channel-dispatch-operation.h
@@ -0,0 +1,78 @@
+/*
+ * channel-dispatch-operation.h - proxy for channels awaiting approval
+ *
+ * Copyright (C) 2009 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * 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 TP_CHANNEL_DISPATCH_OPERATION_H
+#define TP_CHANNEL_DISPATCH_OPERATION_H
+
+#include <telepathy-glib/proxy.h>
+#include <telepathy-glib/dbus.h>
+
+G_BEGIN_DECLS
+
+typedef struct _TpChannelDispatchOperation
+    TpChannelDispatchOperation;
+typedef struct _TpChannelDispatchOperationClass
+    TpChannelDispatchOperationClass;
+typedef struct _TpChannelDispatchOperationPrivate
+    TpChannelDispatchOperationPrivate;
+typedef struct _TpChannelDispatchOperationClassPrivate
+    TpChannelDispatchOperationClassPrivate;
+
+struct _TpChannelDispatchOperation {
+    /*<private>*/
+    TpProxy parent;
+    TpChannelDispatchOperationPrivate *priv;
+};
+
+struct _TpChannelDispatchOperationClass {
+    /*<private>*/
+    TpProxyClass parent_class;
+    GCallback _padding[7];
+    TpChannelDispatchOperationClassPrivate *priv;
+};
+
+GType tp_channel_dispatch_operation_get_type (void);
+
+#define TP_TYPE_CHANNEL_DISPATCH_OPERATION \
+  (tp_channel_dispatch_operation_get_type ())
+#define TP_CHANNEL_DISPATCH_OPERATION(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), TP_TYPE_CHANNEL_DISPATCH_OPERATION, \
+                               TpChannelDispatchOperation))
+#define TP_CHANNEL_DISPATCH_OPERATION_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), TP_TYPE_CHANNEL_DISPATCH_OPERATION, \
+                            TpChannelDispatchOperationClass))
+#define TP_IS_CHANNEL_DISPATCH_OPERATION(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TP_TYPE_CHANNEL_DISPATCH_OPERATION))
+#define TP_IS_CHANNEL_DISPATCH_OPERATION_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), TP_TYPE_CHANNEL_DISPATCH_OPERATION))
+#define TP_CHANNEL_DISPATCH_OPERATION_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TYPE_CHANNEL_DISPATCH_OPERATION, \
+                              TpChannelDispatchOperationClass))
+
+TpChannelDispatchOperation *tp_channel_dispatch_operation_new (
+    TpDBusDaemon *bus_daemon, const gchar *object_path,
+    GHashTable *immutable_properties, GError **error);
+
+G_END_DECLS
+
+#include <telepathy-glib/_gen/tp-cli-channel-dispatch-operation.h>
+
+#endif
diff --git a/telepathy-glib/channel-dispatch-operation.xml b/telepathy-glib/channel-dispatch-operation.xml
new file mode 100644
index 0000000..a870d4d
--- /dev/null
+++ b/telepathy-glib/channel-dispatch-operation.xml
@@ -0,0 +1,9 @@
+<tp:spec
+  xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
+  xmlns:xi="http://www.w3.org/2001/XInclude">
+
+<tp:title>CDO interfaces</tp:title>
+
+<xi:include href="../spec/Channel_Dispatch_Operation.xml"/>
+
+</tp:spec>
diff --git a/telepathy-glib/channel-request.c b/telepathy-glib/channel-request.c
new file mode 100644
index 0000000..45ad969
--- /dev/null
+++ b/telepathy-glib/channel-request.c
@@ -0,0 +1,250 @@
+/*
+ * channel-request.c - proxy for a request to the Telepathy channel dispatcher
+ *
+ * Copyright (C) 2009 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * 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 "telepathy-glib/channel-request.h"
+
+#include <telepathy-glib/defs.h>
+#include <telepathy-glib/errors.h>
+#include <telepathy-glib/interfaces.h>
+#include <telepathy-glib/proxy-subclass.h>
+
+#define DEBUG_FLAG TP_DEBUG_DISPATCHER
+#include "telepathy-glib/dbus-internal.h"
+#include "telepathy-glib/debug-internal.h"
+
+#include "telepathy-glib/_gen/tp-cli-channel-request-body.h"
+
+/**
+ * SECTION:channel-request
+ * @title: TpChannelRequest
+ * @short_description: proxy object for a request to the Telepathy channel
+ *  dispatcher
+ * @see_also: #TpChannelDispatcher
+ *
+ * Requesting a channel from the channel dispatcher can take some time, so an
+ * object is created in the channel dispatcher to represent each request.
+ * Objects of the #TpChannelRequest class provide access to one of those
+ * objects.
+ */
+
+/**
+ * TpChannelRequest:
+ *
+ * Requesting a channel from the channel dispatcher can take some time, so an
+ * object is created in the channel dispatcher to represent each request. This
+ * proxy represents one of those objects.
+ *
+ * Any client can call tp_cli_channel_request_call_cancel() at any time to
+ * attempt to cancel the request.
+ *
+ * On success, the #TpChannelRequest::succeeded signal will be emitted.
+ * Immediately after that, the #TpProxy::invalidated signal will be emitted,
+ * with the domain %TP_DBUS_ERRORS and the error code
+ * %TP_DBUS_ERROR_OBJECT_REMOVED (this is not an error condition, it merely
+ * indicates that the channel request no longer exists).
+ *
+ * On failure, the #TpProxy::invalidated signal will be emitted with some
+ * other suitable error, usually from the %TP_ERRORS domain.
+ *
+ * If the channel dispatcher crashes or exits, the #TpProxy::invalidated
+ * signal will be emitted with the domain %TP_DBUS_ERRORS and the error code
+ * %TP_DBUS_ERROR_NAME_OWNER_LOST.
+ *
+ * This proxy is usable but incomplete: accessors for the Account,
+ * UserActionTime, PreferredHandler, Requests and Interfaces properties will
+ * be added in a later version of telepathy-glib, along with a mechanism
+ * similar to tp_connection_call_when_ready().
+ *
+ * Until suitable convenience methods are implemented, the generic
+ * tp_cli_dbus_properties_call_get_all() method can be used to get those
+ * properties.
+ *
+ * Since: 0.7.UNRELEASED
+ */
+
+/**
+ * TpChannelRequestClass:
+ *
+ * The class of a #TpChannelRequest.
+ */
+
+static guint signal_id_succeeded = 0;
+
+struct _TpChannelRequestPrivate {
+    gpointer dummy;
+};
+
+G_DEFINE_TYPE (TpChannelRequest, tp_channel_request, TP_TYPE_PROXY);
+
+static void
+tp_channel_request_init (TpChannelRequest *self)
+{
+  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TYPE_CHANNEL_REQUEST,
+      TpChannelRequestPrivate);
+}
+
+static void
+tp_channel_request_failed_cb (TpChannelRequest *self,
+    const gchar *error_name,
+    const gchar *message,
+    gpointer unused G_GNUC_UNUSED,
+    GObject *object G_GNUC_UNUSED)
+{
+  GError *error = NULL;
+
+  tp_proxy_dbus_error_to_gerror (self, error_name, message, &error);
+  tp_proxy_invalidate ((TpProxy *) self, error);
+  g_error_free (error);
+}
+
+static void
+tp_channel_request_succeeded_cb (TpChannelRequest *self,
+    gpointer unused G_GNUC_UNUSED,
+    GObject *object G_GNUC_UNUSED)
+{
+  GError e = { TP_DBUS_ERRORS, TP_DBUS_ERROR_OBJECT_REMOVED,
+      "ChannelRequest succeeded and was removed" };
+
+  g_signal_emit (self, signal_id_succeeded, 0);
+  tp_proxy_invalidate ((TpProxy *) self, &e);
+}
+
+static void
+tp_channel_request_constructed (GObject *object)
+{
+  TpChannelRequest *self = TP_CHANNEL_REQUEST (object);
+  void (*chain_up) (GObject *) =
+    ((GObjectClass *) tp_channel_request_parent_class)->constructed;
+  GError *error = NULL;
+  TpProxySignalConnection *sc;
+
+  if (chain_up != NULL)
+    chain_up (object);
+
+  g_return_if_fail (tp_proxy_get_dbus_daemon (self) != NULL);
+
+  sc = tp_cli_channel_request_connect_to_failed (self,
+      tp_channel_request_failed_cb, NULL, NULL, NULL, &error);
+
+  if (sc == NULL)
+    {
+      g_critical ("Couldn't connect to Failed: %s", error->message);
+      g_error_free (error);
+      g_assert_not_reached ();
+      return;
+    }
+
+  sc = tp_cli_channel_request_connect_to_succeeded (self,
+      tp_channel_request_succeeded_cb, NULL, NULL, NULL, &error);
+
+  if (sc == NULL)
+    {
+      g_critical ("Couldn't connect to Succeeded: %s", error->message);
+      g_error_free (error);
+      g_assert_not_reached ();
+      return;
+    }
+}
+
+static void
+tp_channel_request_class_init (TpChannelRequestClass *klass)
+{
+  GType tp_type = TP_TYPE_CHANNEL_REQUEST;
+  TpProxyClass *proxy_class = (TpProxyClass *) klass;
+  GObjectClass *object_class = (GObjectClass *) klass;
+
+  g_type_class_add_private (klass, sizeof (TpChannelRequestPrivate));
+
+  object_class->constructed = tp_channel_request_constructed;
+
+  proxy_class->interface = TP_IFACE_QUARK_CHANNEL_REQUEST;
+  tp_proxy_or_subclass_hook_on_interface_add (tp_type,
+      tp_cli_channel_request_add_signals);
+  tp_proxy_subclass_add_error_mapping (tp_type,
+      TP_ERROR_PREFIX, TP_ERRORS, TP_TYPE_ERROR);
+  proxy_class->must_have_unique_name = TRUE;
+
+  /**
+   * TpChannelRequest::succeeded:
+   * @self: the channel request proxy
+   *
+   * Emitted when the channel request succeeds.
+   */
+  signal_id_succeeded = g_signal_new ("succeeded",
+      G_OBJECT_CLASS_TYPE (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+      0,
+      NULL, NULL,
+      g_cclosure_marshal_VOID__VOID,
+      G_TYPE_NONE, 0);
+}
+
+/**
+ * tp_channel_request_new:
+ * @bus_daemon: Proxy for the D-Bus daemon
+ * @object_path: The non-NULL object path of this channel request
+ * @immutable_properties: As many as are known of the immutable D-Bus
+ *  properties of this channel request, or %NULL if none are known
+ * @error: Used to raise an error if %NULL is returned
+ *
+ * Convenience function to create a new channel request proxy.
+ *
+ * If the channel request was newly created, the client making the request
+ * is responsible for calling tp_cli_channel_request_call_proceed() when it
+ * is ready for the channel request to proceed.
+ *
+ * The @immutable_properties argument is not yet used.
+ *
+ * Returns: a new reference to an channel request proxy, or %NULL if
+ *    @object_path is not syntactically valid or the channel dispatcher is
+ *    not running
+ */
+TpChannelRequest *
+tp_channel_request_new (TpDBusDaemon *bus_daemon,
+    const gchar *object_path,
+    GHashTable *immutable_properties G_GNUC_UNUSED,
+    GError **error)
+{
+  TpChannelRequest *self;
+  gchar *unique_name;
+
+  g_return_val_if_fail (bus_daemon != NULL, NULL);
+  g_return_val_if_fail (object_path != NULL, NULL);
+  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+  if (!tp_dbus_check_valid_object_path (object_path, error))
+    return NULL;
+
+  if (!_tp_dbus_daemon_get_name_owner (bus_daemon, -1,
+      TP_CHANNEL_DISPATCHER_BUS_NAME, &unique_name, error))
+    return NULL;
+
+  self = TP_CHANNEL_REQUEST (g_object_new (TP_TYPE_CHANNEL_REQUEST,
+        "dbus-daemon", bus_daemon,
+        "dbus-connection", ((TpProxy *) bus_daemon)->dbus_connection,
+        "bus-name", unique_name,
+        "object-path", object_path,
+        NULL));
+
+  g_free (unique_name);
+
+  return self;
+}
diff --git a/telepathy-glib/channel-request.h b/telepathy-glib/channel-request.h
new file mode 100644
index 0000000..50c9ce7
--- /dev/null
+++ b/telepathy-glib/channel-request.h
@@ -0,0 +1,74 @@
+/*
+ * channel-request.h - proxy for a request to the channel dispatcher
+ *
+ * Copyright (C) 2009 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * 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 TP_CHANNEL_REQUEST_H
+#define TP_CHANNEL_REQUEST_H
+
+#include <telepathy-glib/proxy.h>
+#include <telepathy-glib/dbus.h>
+
+G_BEGIN_DECLS
+
+typedef struct _TpChannelRequest TpChannelRequest;
+typedef struct _TpChannelRequestClass TpChannelRequestClass;
+typedef struct _TpChannelRequestPrivate TpChannelRequestPrivate;
+typedef struct _TpChannelRequestClassPrivate TpChannelRequestClassPrivate;
+
+struct _TpChannelRequest {
+    /*<private>*/
+    TpProxy parent;
+    TpChannelRequestPrivate *priv;
+};
+
+struct _TpChannelRequestClass {
+    /*<private>*/
+    TpProxyClass parent_class;
+    GCallback _padding[7];
+    TpChannelRequestClassPrivate *priv;
+};
+
+GType tp_channel_request_get_type (void);
+
+#define TP_TYPE_CHANNEL_REQUEST \
+  (tp_channel_request_get_type ())
+#define TP_CHANNEL_REQUEST(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), TP_TYPE_CHANNEL_REQUEST, \
+                               TpChannelRequest))
+#define TP_CHANNEL_REQUEST_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), TP_TYPE_CHANNEL_REQUEST, \
+                            TpChannelRequestClass))
+#define TP_IS_CHANNEL_REQUEST(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TP_TYPE_CHANNEL_REQUEST))
+#define TP_IS_CHANNEL_REQUEST_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), TP_TYPE_CHANNEL_REQUEST))
+#define TP_CHANNEL_REQUEST_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TYPE_CHANNEL_REQUEST, \
+                              TpChannelRequestClass))
+
+TpChannelRequest *tp_channel_request_new (TpDBusDaemon *bus_daemon,
+    const gchar *object_path, GHashTable *immutable_properties,
+    GError **error);
+
+G_END_DECLS
+
+#include <telepathy-glib/_gen/tp-cli-channel-request.h>
+
+#endif
diff --git a/telepathy-glib/channel-request.xml b/telepathy-glib/channel-request.xml
new file mode 100644
index 0000000..2b4068c
--- /dev/null
+++ b/telepathy-glib/channel-request.xml
@@ -0,0 +1,9 @@
+<tp:spec
+  xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
+  xmlns:xi="http://www.w3.org/2001/XInclude">
+
+<tp:title>CR interfaces</tp:title>
+
+<xi:include href="../spec/Channel_Request.xml"/>
+
+</tp:spec>
diff --git a/telepathy-glib/extra-gtkdoc.h b/telepathy-glib/extra-gtkdoc.h
index 26d289c..5ecff48 100644
--- a/telepathy-glib/extra-gtkdoc.h
+++ b/telepathy-glib/extra-gtkdoc.h
@@ -244,6 +244,51 @@
  */
 
 /**
+ * SECTION:svc-channel-dispatch-operation
+ * @title: Service-side Channel Dispatch Operation interface
+ * @short_description: GInterface for Telepathy ChannelDispatchOperation object
+ *
+ * This interface (auto-generated from the Telepathy
+ * spec) makes it easier to export an object implementing the Telepathy
+ * ChannelDispatchOperation interface, with the correct method and signal
+ * signatures, and emit signals from that object in a type-safe way.
+ *
+ * You don't need these interfaces unless you're implementing a
+ * Telepathy ChannelDispatcher, such as Mission Control.
+ */
+
+/**
+ * SECTION:svc-channel-request
+ * @title: Service-side Channel Request interface
+ * @short_description: GInterface for Telepathy ChannelRequest object
+ *
+ * This interface (auto-generated from the Telepathy
+ * spec) makes it easier to export an object implementing the Telepathy
+ * ChannelRequest interface, with the correct method and signal
+ * signatures, and emit signals from that object in a type-safe way.
+ *
+ * You don't need these interfaces unless you're implementing a
+ * Telepathy ChannelDispatcher, such as Mission Control.
+ */
+
+/**
+ * SECTION:svc-channel-dispatcher
+ * @title: Service-side Channel Dispatcher interface
+ * @short_description: GInterfaces for Telepathy ChannelDispatcher object
+ *
+ * The #TpSvcChannelDispatcher interface (auto-generated from the Telepathy
+ * spec) makes it easier to export an object implementing the Telepathy
+ * ChannelDispatcher interface, with the correct method and signal signatures,
+ * and emit signals from that object in a type-safe way.
+ *
+ * Similarly, #TpSvcChannelDispatcherInterfaceOperationList helps to
+ * implement the optional OperationList interface.
+ *
+ * You don't need these interfaces unless you're implementing a
+ * Telepathy ChannelDispatcher, such as Mission Control.
+ */
+
+/**
  * SECTION:svc-media-interfaces
  * @title: Service-side media streaming helper interfaces
  * @short_description: media session and media stream
diff --git a/telepathy-glib/stable-interfaces.xml b/telepathy-glib/stable-interfaces.xml
index 1f710ab..d3a2c16 100644
--- a/telepathy-glib/stable-interfaces.xml
+++ b/telepathy-glib/stable-interfaces.xml
@@ -16,6 +16,8 @@
 <xi:include href="account.xml"/>
 
 <xi:include href="channel-dispatcher.xml"/>
+<xi:include href="channel-dispatch-operation.xml"/>
+<xi:include href="channel-request.xml"/>
 
 <xi:include href="../spec/generic-types.xml"/>
 <xi:include href="../spec/errors.xml"/>
diff --git a/telepathy-glib/svc-channel-dispatch-operation.h b/telepathy-glib/svc-channel-dispatch-operation.h
new file mode 100644
index 0000000..ae74c54
--- /dev/null
+++ b/telepathy-glib/svc-channel-dispatch-operation.h
@@ -0,0 +1,6 @@
+#ifndef __TP_META_SVC_CHANNEL_DISPATCH_OPERATION_H__
+#define __TP_META_SVC_CHANNEL_DISPATCH_OPERATION_H__
+
+#include <telepathy-glib/_gen/tp-svc-channel-dispatch-operation.h>
+
+#endif
diff --git a/telepathy-glib/svc-channel-request.h b/telepathy-glib/svc-channel-request.h
new file mode 100644
index 0000000..f849a82
--- /dev/null
+++ b/telepathy-glib/svc-channel-request.h
@@ -0,0 +1,6 @@
+#ifndef __TP_META_SVC_CHANNEL_REQUEST_H__
+#define __TP_META_SVC_CHANNEL_REQUEST_H__
+
+#include <telepathy-glib/_gen/tp-svc-channel-request.h>
+
+#endif
diff --git a/tests/dbus/Makefile.am b/tests/dbus/Makefile.am
index 7a1b1f8..073ad35 100644
--- a/tests/dbus/Makefile.am
+++ b/tests/dbus/Makefile.am
@@ -6,7 +6,9 @@ noinst_PROGRAMS = \
     test-call-cancellation \
     test-callable-example \
     test-channel-dispatcher \
+    test-channel-dispatch-operation \
     test-channel-introspect \
+    test-channel-request \
     test-cli-group \
     test-cm \
     test-connection \
@@ -50,8 +52,12 @@ test_call_cancellation_SOURCES = call-cancellation.c
 
 test_channel_dispatcher_SOURCES = channel-dispatcher.c
 
+test_channel_dispatch_operation_SOURCES = channel-dispatch-operation.c
+
 test_channel_introspect_SOURCES = channel-introspect.c
 
+test_channel_request_SOURCES = channel-request.c
+
 test_callable_example_SOURCES = callable-example.c
 test_callable_example_LDADD = \
     $(LDADD) \
diff --git a/tests/dbus/channel-dispatch-operation.c b/tests/dbus/channel-dispatch-operation.c
new file mode 100644
index 0000000..84c57f6
--- /dev/null
+++ b/tests/dbus/channel-dispatch-operation.c
@@ -0,0 +1,232 @@
+/* A very basic feature test for TpChannelDispatchOperation
+ *
+ * Copyright (C) 2009 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Copying and distribution of this file, with or without modification,
+ * are permitted in any medium without royalty provided the copyright
+ * notice and this notice are preserved.
+ */
+
+#include <telepathy-glib/channel-dispatch-operation.h>
+#include <telepathy-glib/defs.h>
+#include <telepathy-glib/debug.h>
+#include <telepathy-glib/svc-channel-dispatch-operation.h>
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "tests/lib/util.h"
+
+/* This object implements no methods and no properties - TpChannelRequest
+ * doesn't actually use them yet */
+
+static GType test_simple_cdo_get_type (void);
+
+typedef struct {
+    GObject parent;
+} TestSimpleCDO;
+
+typedef struct {
+    GObjectClass parent;
+} TestSimpleCDOClass;
+
+G_DEFINE_TYPE_WITH_CODE (TestSimpleCDO, test_simple_cdo, G_TYPE_OBJECT,
+    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_DISPATCH_OPERATION, NULL));
+
+static void
+test_simple_cdo_init (TestSimpleCDO *self)
+{
+}
+
+static void
+test_simple_cdo_class_init (TestSimpleCDOClass *klass)
+{
+}
+
+typedef struct {
+    GMainLoop *mainloop;
+    TpDBusDaemon *dbus;
+
+    DBusGConnection *private_conn;
+    TpDBusDaemon *private_dbus;
+    GObject *cdo_service;
+
+    TpChannelDispatchOperation *cdo;
+    GError *error /* initialized where needed */;
+} Test;
+
+static void
+setup (Test *test,
+       gconstpointer data)
+{
+  DBusConnection *libdbus;
+
+  g_type_init ();
+  tp_debug_set_flags ("all");
+
+  test->mainloop = g_main_loop_new (NULL, FALSE);
+  test->dbus = tp_dbus_daemon_dup (NULL);
+  g_assert (test->dbus != NULL);
+
+  libdbus = dbus_bus_get_private (DBUS_BUS_STARTER, NULL);
+  g_assert (libdbus != NULL);
+  dbus_connection_setup_with_g_main (libdbus, NULL);
+  dbus_connection_set_exit_on_disconnect (libdbus, FALSE);
+  test->private_conn = dbus_connection_get_g_connection (libdbus);
+  /* transfer ref */
+  dbus_g_connection_ref (test->private_conn);
+  dbus_connection_unref (libdbus);
+  g_assert (test->private_conn != NULL);
+  test->private_dbus = tp_dbus_daemon_new (test->private_conn);
+  g_assert (test->private_dbus != NULL);
+
+  test->cdo = NULL;
+
+  test->cdo_service = g_object_new (test_simple_cdo_get_type (),
+      NULL);
+  dbus_g_connection_register_g_object (test->private_conn, "/whatever",
+      test->cdo_service);
+}
+
+static void
+teardown (Test *test,
+          gconstpointer data)
+{
+  if (test->cdo != NULL)
+    {
+      g_object_unref (test->cdo);
+      test->cdo = NULL;
+    }
+
+  tp_dbus_daemon_release_name (test->dbus, TP_CHANNEL_DISPATCHER_BUS_NAME,
+      NULL);
+
+  if (test->private_dbus != NULL)
+    {
+      tp_dbus_daemon_release_name (test->private_dbus,
+          TP_CHANNEL_DISPATCHER_BUS_NAME, NULL);
+
+      g_object_unref (test->private_dbus);
+      test->private_dbus = NULL;
+    }
+
+#if 0
+  /* not leaking this object would crash dbus-glib (fd.o #5688) */
+  g_object_unref (test->cdo_service);
+  test->cdo_service = NULL;
+#endif
+
+  if (test->private_conn != NULL)
+    {
+      dbus_connection_close (dbus_g_connection_get_connection (
+            test->private_conn));
+
+      dbus_g_connection_unref (test->private_conn);
+      test->private_conn = NULL;
+    }
+
+  g_object_unref (test->dbus);
+  test->dbus = NULL;
+  g_main_loop_unref (test->mainloop);
+  test->mainloop = NULL;
+}
+
+static void
+test_new (Test *test,
+          gconstpointer data G_GNUC_UNUSED)
+{
+  gboolean ok;
+
+  /* CD not running */
+  test->cdo = tp_channel_dispatch_operation_new (test->dbus,
+      "/whatever", NULL, NULL);
+  g_assert (test->cdo == NULL);
+
+  ok = tp_dbus_daemon_request_name (test->private_dbus,
+      TP_CHANNEL_DISPATCHER_BUS_NAME, FALSE, NULL);
+  g_assert (ok);
+
+  test->cdo = tp_channel_dispatch_operation_new (test->dbus,
+      "not even syntactically valid", NULL, NULL);
+  g_assert (test->cdo == NULL);
+
+  test->cdo = tp_channel_dispatch_operation_new (test->dbus,
+      "/whatever", NULL, NULL);
+  g_assert (test->cdo != NULL);
+}
+
+static void
+test_crash (Test *test,
+    gconstpointer data G_GNUC_UNUSED)
+{
+  gboolean ok;
+
+  ok = tp_dbus_daemon_request_name (test->private_dbus,
+      TP_CHANNEL_DISPATCHER_BUS_NAME, FALSE, NULL);
+  g_assert (ok);
+
+  test->cdo = tp_channel_dispatch_operation_new (test->dbus, "/whatever",
+      NULL, NULL);
+  g_assert (test->cdo != NULL);
+  g_assert (tp_proxy_get_invalidated (test->cdo) == NULL);
+
+  tp_dbus_daemon_release_name (test->private_dbus,
+      TP_CHANNEL_DISPATCHER_BUS_NAME, NULL);
+
+  test_proxy_run_until_dbus_queue_processed (test->cdo);
+
+  g_assert (tp_proxy_get_invalidated (test->cdo) == NULL);
+
+  dbus_connection_close (dbus_g_connection_get_connection (
+        test->private_conn));
+  dbus_g_connection_unref (test->private_conn);
+  test->private_conn = NULL;
+
+  test_proxy_run_until_dbus_queue_processed (test->cdo);
+
+  g_assert (tp_proxy_get_invalidated (test->cdo) != NULL);
+  g_assert (tp_proxy_get_invalidated (test->cdo)->domain == TP_DBUS_ERRORS);
+  g_assert (tp_proxy_get_invalidated (test->cdo)->code ==
+      TP_DBUS_ERROR_NAME_OWNER_LOST);
+}
+
+static void
+test_finished (Test *test,
+    gconstpointer data G_GNUC_UNUSED)
+{
+  gboolean ok;
+
+  ok = tp_dbus_daemon_request_name (test->private_dbus,
+      TP_CHANNEL_DISPATCHER_BUS_NAME, FALSE, NULL);
+  g_assert (ok);
+
+  test->cdo = tp_channel_dispatch_operation_new (test->dbus, "/whatever",
+      NULL, NULL);
+  g_assert (test->cdo != NULL);
+  g_assert (tp_proxy_get_invalidated (test->cdo) == NULL);
+
+  tp_svc_channel_dispatch_operation_emit_finished (test->cdo_service);
+
+  test_proxy_run_until_dbus_queue_processed (test->cdo);
+
+  g_assert (tp_proxy_get_invalidated (test->cdo) != NULL);
+  g_assert (tp_proxy_get_invalidated (test->cdo)->domain == TP_DBUS_ERRORS);
+  g_assert (tp_proxy_get_invalidated (test->cdo)->code ==
+      TP_DBUS_ERROR_OBJECT_REMOVED);
+}
+
+int
+main (int argc,
+      char **argv)
+{
+  g_test_init (&argc, &argv, NULL);
+  g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
+
+  g_test_add ("/cdo/new", Test, NULL, setup, test_new, teardown);
+  g_test_add ("/cdo/crash", Test, NULL, setup, test_crash, teardown);
+  g_test_add ("/cdo/finished", Test, NULL, setup, test_finished, teardown);
+
+  return g_test_run ();
+}
diff --git a/tests/dbus/channel-request.c b/tests/dbus/channel-request.c
new file mode 100644
index 0000000..1699997
--- /dev/null
+++ b/tests/dbus/channel-request.c
@@ -0,0 +1,276 @@
+/* A very basic feature test for TpChannelRequest
+ *
+ * Copyright (C) 2009 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Copying and distribution of this file, with or without modification,
+ * are permitted in any medium without royalty provided the copyright
+ * notice and this notice are preserved.
+ */
+
+#include <telepathy-glib/channel-request.h>
+#include <telepathy-glib/defs.h>
+#include <telepathy-glib/debug.h>
+#include <telepathy-glib/svc-channel-request.h>
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "tests/lib/util.h"
+
+/* This object implements no methods and no properties - TpChannelRequest
+ * doesn't actually use them yet */
+
+static GType test_simple_cr_get_type (void);
+
+typedef struct {
+    GObject parent;
+} TestSimpleCR;
+
+typedef struct {
+    GObjectClass parent;
+} TestSimpleCRClass;
+
+G_DEFINE_TYPE_WITH_CODE (TestSimpleCR, test_simple_cr, G_TYPE_OBJECT,
+    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_REQUEST, NULL));
+
+static void
+test_simple_cr_init (TestSimpleCR *self)
+{
+}
+
+static void
+test_simple_cr_class_init (TestSimpleCRClass *klass)
+{
+}
+
+typedef struct {
+    GMainLoop *mainloop;
+    TpDBusDaemon *dbus;
+
+    DBusGConnection *private_conn;
+    TpDBusDaemon *private_dbus;
+    GObject *cr_service;
+
+    TpChannelRequest *cr;
+    GError *error /* initialized where needed */;
+
+    guint succeeded;
+} Test;
+
+static void
+setup (Test *test,
+       gconstpointer data)
+{
+  DBusConnection *libdbus;
+
+  g_type_init ();
+  tp_debug_set_flags ("all");
+
+  test->mainloop = g_main_loop_new (NULL, FALSE);
+  test->dbus = tp_dbus_daemon_dup (NULL);
+  g_assert (test->dbus != NULL);
+
+  libdbus = dbus_bus_get_private (DBUS_BUS_STARTER, NULL);
+  g_assert (libdbus != NULL);
+  dbus_connection_setup_with_g_main (libdbus, NULL);
+  dbus_connection_set_exit_on_disconnect (libdbus, FALSE);
+  test->private_conn = dbus_connection_get_g_connection (libdbus);
+  /* transfer ref */
+  dbus_g_connection_ref (test->private_conn);
+  dbus_connection_unref (libdbus);
+  g_assert (test->private_conn != NULL);
+  test->private_dbus = tp_dbus_daemon_new (test->private_conn);
+  g_assert (test->private_dbus != NULL);
+
+  test->cr = NULL;
+
+  test->cr_service = g_object_new (test_simple_cr_get_type (),
+      NULL);
+  dbus_g_connection_register_g_object (test->private_conn, "/whatever",
+      test->cr_service);
+}
+
+static void
+teardown (Test *test,
+          gconstpointer data)
+{
+  if (test->cr != NULL)
+    {
+      g_object_unref (test->cr);
+      test->cr = NULL;
+    }
+
+  if (test->private_dbus != NULL)
+    {
+      tp_dbus_daemon_release_name (test->private_dbus,
+          TP_CHANNEL_DISPATCHER_BUS_NAME, NULL);
+
+      g_object_unref (test->private_dbus);
+      test->private_dbus = NULL;
+    }
+
+#if 0
+  /* not leaking this object would crash dbus-glib (fd.o #5688) */
+  g_object_unref (test->cr_service);
+  test->cr_service = NULL;
+#endif
+
+  if (test->private_conn != NULL)
+    {
+      dbus_connection_close (dbus_g_connection_get_connection (
+            test->private_conn));
+
+      dbus_g_connection_unref (test->private_conn);
+      test->private_conn = NULL;
+    }
+
+  g_object_unref (test->dbus);
+  test->dbus = NULL;
+
+  g_main_loop_unref (test->mainloop);
+  test->mainloop = NULL;
+}
+
+static void
+test_new (Test *test,
+          gconstpointer data G_GNUC_UNUSED)
+{
+  gboolean ok;
+
+  /* CD not running */
+  test->cr = tp_channel_request_new (test->dbus,
+      "/whatever", NULL, NULL);
+  g_assert (test->cr == NULL);
+
+  ok = tp_dbus_daemon_request_name (test->private_dbus,
+      TP_CHANNEL_DISPATCHER_BUS_NAME, FALSE, NULL);
+  g_assert (ok);
+
+  test->cr = tp_channel_request_new (test->dbus,
+      "not even syntactically valid", NULL, NULL);
+  g_assert (test->cr == NULL);
+
+  test->cr = tp_channel_request_new (test->dbus, "/whatever", NULL, NULL);
+  g_assert (test->cr != NULL);
+}
+
+static void
+test_crash (Test *test,
+    gconstpointer data G_GNUC_UNUSED)
+{
+  gboolean ok;
+
+  ok = tp_dbus_daemon_request_name (test->private_dbus,
+      TP_CHANNEL_DISPATCHER_BUS_NAME, FALSE, NULL);
+  g_assert (ok);
+
+  test->cr = tp_channel_request_new (test->dbus, "/whatever", NULL, NULL);
+  g_assert (test->cr != NULL);
+  g_assert (tp_proxy_get_invalidated (test->cr) == NULL);
+
+  tp_dbus_daemon_release_name (test->private_dbus,
+      TP_CHANNEL_DISPATCHER_BUS_NAME, NULL);
+
+  test_proxy_run_until_dbus_queue_processed (test->cr);
+
+  g_assert (tp_proxy_get_invalidated (test->cr) == NULL);
+
+  dbus_connection_close (dbus_g_connection_get_connection (
+        test->private_conn));
+  dbus_g_connection_unref (test->private_conn);
+  test->private_conn = NULL;
+
+  test_proxy_run_until_dbus_queue_processed (test->cr);
+
+  g_assert (tp_proxy_get_invalidated (test->cr) != NULL);
+  g_assert (tp_proxy_get_invalidated (test->cr)->domain == TP_DBUS_ERRORS);
+  g_assert (tp_proxy_get_invalidated (test->cr)->code ==
+      TP_DBUS_ERROR_NAME_OWNER_LOST);
+}
+
+static void
+succeeded_cb (Test *test)
+{
+  test->succeeded++;
+}
+
+static void
+test_succeeded (Test *test,
+    gconstpointer data G_GNUC_UNUSED)
+{
+  gboolean ok;
+
+  ok = tp_dbus_daemon_request_name (test->private_dbus,
+      TP_CHANNEL_DISPATCHER_BUS_NAME, FALSE, NULL);
+  g_assert (ok);
+
+  test->cr = tp_channel_request_new (test->dbus, "/whatever", NULL, NULL);
+  g_assert (test->cr != NULL);
+  g_assert (tp_proxy_get_invalidated (test->cr) == NULL);
+
+  g_signal_connect_swapped (test->cr, "succeeded", G_CALLBACK (succeeded_cb),
+      test);
+
+  tp_svc_channel_request_emit_succeeded (test->cr_service);
+
+  test_proxy_run_until_dbus_queue_processed (test->cr);
+
+  g_assert (tp_proxy_get_invalidated (test->cr) != NULL);
+  g_assert (tp_proxy_get_invalidated (test->cr)->domain == TP_DBUS_ERRORS);
+  g_assert (tp_proxy_get_invalidated (test->cr)->code ==
+      TP_DBUS_ERROR_OBJECT_REMOVED);
+  g_assert_cmpuint (test->succeeded, ==, 1);
+
+  g_signal_handlers_disconnect_by_func (test->cr, G_CALLBACK (succeeded_cb),
+      test);
+}
+
+static void
+test_failed (Test *test,
+    gconstpointer data G_GNUC_UNUSED)
+{
+  gboolean ok;
+
+  ok = tp_dbus_daemon_request_name (test->private_dbus,
+      TP_CHANNEL_DISPATCHER_BUS_NAME, FALSE, NULL);
+  g_assert (ok);
+
+  test->cr = tp_channel_request_new (test->dbus, "/whatever", NULL, NULL);
+  g_assert (test->cr != NULL);
+  g_assert (tp_proxy_get_invalidated (test->cr) == NULL);
+
+  g_signal_connect_swapped (test->cr, "succeeded", G_CALLBACK (succeeded_cb),
+      test);
+
+  tp_svc_channel_request_emit_failed (test->cr_service,
+      TP_ERROR_STR_NOT_YOURS, "lalala");
+
+  test_proxy_run_until_dbus_queue_processed (test->cr);
+
+  g_assert (tp_proxy_get_invalidated (test->cr) != NULL);
+  g_assert (tp_proxy_get_invalidated (test->cr)->domain == TP_ERRORS);
+  g_assert (tp_proxy_get_invalidated (test->cr)->code == TP_ERROR_NOT_YOURS);
+  g_assert_cmpstr (tp_proxy_get_invalidated (test->cr)->message, ==,
+      "lalala");
+  g_assert_cmpuint (test->succeeded, ==, 0);
+
+  g_signal_handlers_disconnect_by_func (test->cr, G_CALLBACK (succeeded_cb),
+      test);
+}
+
+int
+main (int argc,
+      char **argv)
+{
+  g_test_init (&argc, &argv, NULL);
+  g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
+
+  g_test_add ("/cr/new", Test, NULL, setup, test_new, teardown);
+  g_test_add ("/cr/crash", Test, NULL, setup, test_crash, teardown);
+  g_test_add ("/cr/succeeded", Test, NULL, setup, test_succeeded, teardown);
+  g_test_add ("/cr/failed", Test, NULL, setup, test_failed, teardown);
+
+  return g_test_run ();
+}
-- 
1.5.6.5




More information about the telepathy-commits mailing list