[Telepathy-commits] [telepathy-glib/master] echo examples: rename files containing channel managers to im-manager.[ch]

Simon McVittie simon.mcvittie at collabora.co.uk
Wed Jan 7 07:57:13 PST 2009


---
 examples/cm/echo-message-parts/Makefile.am  |    4 +-
 examples/cm/echo-message-parts/conn.c       |    2 +-
 examples/cm/echo-message-parts/factory.c    |  389 ---------------------------
 examples/cm/echo-message-parts/factory.h    |   55 ----
 examples/cm/echo-message-parts/im-manager.c |  389 +++++++++++++++++++++++++++
 examples/cm/echo-message-parts/im-manager.h |   55 ++++
 examples/cm/echo/Makefile.am                |    4 +-
 examples/cm/echo/conn.c                     |    2 +-
 examples/cm/echo/factory.c                  |  389 ---------------------------
 examples/cm/echo/factory.h                  |   55 ----
 examples/cm/echo/im-manager.c               |  389 +++++++++++++++++++++++++++
 examples/cm/echo/im-manager.h               |   55 ++++
 12 files changed, 894 insertions(+), 894 deletions(-)
 delete mode 100644 examples/cm/echo-message-parts/factory.c
 delete mode 100644 examples/cm/echo-message-parts/factory.h
 create mode 100644 examples/cm/echo-message-parts/im-manager.c
 create mode 100644 examples/cm/echo-message-parts/im-manager.h
 delete mode 100644 examples/cm/echo/factory.c
 delete mode 100644 examples/cm/echo/factory.h
 create mode 100644 examples/cm/echo/im-manager.c
 create mode 100644 examples/cm/echo/im-manager.h

diff --git a/examples/cm/echo-message-parts/Makefile.am b/examples/cm/echo-message-parts/Makefile.am
index 4f61b15..a1d129a 100644
--- a/examples/cm/echo-message-parts/Makefile.am
+++ b/examples/cm/echo-message-parts/Makefile.am
@@ -8,8 +8,8 @@ libexample_cm_echo_2_la_SOURCES = \
     conn.h \
     connection-manager.c \
     connection-manager.h \
-    factory.c \
-    factory.h
+    im-manager.c \
+    im-manager.h
 
 # In an external project you'd use $(TP_GLIB_LIBS) (obtained from
 # pkg-config via autoconf) instead of the .la path
diff --git a/examples/cm/echo-message-parts/conn.c b/examples/cm/echo-message-parts/conn.c
index 192b87e..a8b5d02 100644
--- a/examples/cm/echo-message-parts/conn.c
+++ b/examples/cm/echo-message-parts/conn.c
@@ -18,7 +18,7 @@
 #include <telepathy-glib/handle-repo-dynamic.h>
 #include <telepathy-glib/interfaces.h>
 
-#include "factory.h"
+#include "im-manager.h"
 
 G_DEFINE_TYPE (ExampleEcho2Connection,
     example_echo_2_connection,
diff --git a/examples/cm/echo-message-parts/factory.c b/examples/cm/echo-message-parts/factory.c
deleted file mode 100644
index a431d4d..0000000
--- a/examples/cm/echo-message-parts/factory.c
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * factory.c - an example channel factory for channels talking to a particular
- * contact. Similar code is used for 1-1 IM channels in many protocols
- * (IRC private messages ("/query"), XMPP IM etc.)
- *
- * Copyright (C) 2007 Collabora Ltd. <http://www.collabora.co.uk/>
- * Copyright (C) 2007 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 "factory.h"
-
-#include <dbus/dbus-glib.h>
-
-#include <telepathy-glib/base-connection.h>
-#include <telepathy-glib/channel-manager.h>
-#include <telepathy-glib/dbus.h>
-#include <telepathy-glib/errors.h>
-#include <telepathy-glib/interfaces.h>
-
-#include "chan.h"
-
-static void channel_manager_iface_init (gpointer, gpointer);
-
-G_DEFINE_TYPE_WITH_CODE (ExampleEcho2Factory,
-    example_echo_2_factory,
-    G_TYPE_OBJECT,
-    G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER,
-      channel_manager_iface_init))
-
-/* type definition stuff */
-
-enum
-{
-  PROP_CONNECTION = 1,
-  N_PROPS
-};
-
-struct _ExampleEcho2FactoryPrivate
-{
-  TpBaseConnection *conn;
-
-  /* GUINT_TO_POINTER (handle) => ExampleEcho2Channel */
-  GHashTable *channels;
-  gulong status_changed_id;
-};
-
-static void
-example_echo_2_factory_init (ExampleEcho2Factory *self)
-{
-  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_ECHO_2_FACTORY,
-      ExampleEcho2FactoryPrivate);
-
-  self->priv->channels = g_hash_table_new_full (g_direct_hash, g_direct_equal,
-      NULL, g_object_unref);
-}
-
-static void example_echo_2_factory_close_all (ExampleEcho2Factory *self);
-
-static void
-dispose (GObject *object)
-{
-  ExampleEcho2Factory *self = EXAMPLE_ECHO_2_FACTORY (object);
-
-  example_echo_2_factory_close_all (self);
-  g_assert (self->priv->channels == NULL);
-
-  ((GObjectClass *) example_echo_2_factory_parent_class)->dispose (object);
-}
-
-static void
-get_property (GObject *object,
-              guint property_id,
-              GValue *value,
-              GParamSpec *pspec)
-{
-  ExampleEcho2Factory *self = EXAMPLE_ECHO_2_FACTORY (object);
-
-  switch (property_id)
-    {
-    case PROP_CONNECTION:
-      g_value_set_object (value, self->priv->conn);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-    }
-}
-
-static void
-set_property (GObject *object,
-              guint property_id,
-              const GValue *value,
-              GParamSpec *pspec)
-{
-  ExampleEcho2Factory *self = EXAMPLE_ECHO_2_FACTORY (object);
-
-  switch (property_id)
-    {
-    case PROP_CONNECTION:
-      /* We don't ref the connection, because it owns a reference to the
-       * factory, and it guarantees that the factory's lifetime is
-       * less than its lifetime */
-      self->priv->conn = g_value_get_object (value);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-    }
-}
-
-static void
-status_changed_cb (TpBaseConnection *conn,
-                   guint status,
-                   guint reason,
-                   ExampleEcho2Factory *self)
-{
-  if (status == TP_CONNECTION_STATUS_DISCONNECTED)
-    example_echo_2_factory_close_all (self);
-}
-
-static void
-constructed (GObject *object)
-{
-  ExampleEcho2Factory *self = EXAMPLE_ECHO_2_FACTORY (object);
-  void (*chain_up) (GObject *) =
-      ((GObjectClass *) example_echo_2_factory_parent_class)->constructed;
-
-  if (chain_up != NULL)
-    {
-      chain_up (object);
-    }
-
-  self->priv->status_changed_id = g_signal_connect (self->priv->conn,
-      "status-changed", (GCallback) status_changed_cb, self);
-}
-
-static void
-example_echo_2_factory_class_init (ExampleEcho2FactoryClass *klass)
-{
-  GParamSpec *param_spec;
-  GObjectClass *object_class = (GObjectClass *) klass;
-
-  object_class->constructed = constructed;
-  object_class->dispose = dispose;
-  object_class->get_property = get_property;
-  object_class->set_property = set_property;
-
-  param_spec = g_param_spec_object ("connection", "Connection object",
-      "The connection that owns this channel factory",
-      TP_TYPE_BASE_CONNECTION,
-      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
-      G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
-  g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
-
-  g_type_class_add_private (klass, sizeof (ExampleEcho2FactoryPrivate));
-}
-
-static void
-example_echo_2_factory_close_all (ExampleEcho2Factory *self)
-{
-  if (self->priv->channels != NULL)
-    {
-      GHashTable *tmp = self->priv->channels;
-
-      self->priv->channels = NULL;
-      g_hash_table_destroy (tmp);
-    }
-
-  if (self->priv->status_changed_id != 0)
-    {
-      g_signal_handler_disconnect (self->priv->conn,
-          self->priv->status_changed_id);
-      self->priv->status_changed_id = 0;
-    }
-}
-
-static void
-example_echo_2_factory_foreach_channel (TpChannelManager *iface,
-                                        TpExportableChannelFunc callback,
-                                        gpointer user_data)
-{
-  ExampleEcho2Factory *self = EXAMPLE_ECHO_2_FACTORY (iface);
-  GHashTableIter iter;
-  gpointer handle, channel;
-
-  g_hash_table_iter_init (&iter, self->priv->channels);
-
-  while (g_hash_table_iter_next (&iter, &handle, &channel))
-    {
-      callback (TP_EXPORTABLE_CHANNEL (channel), user_data);
-    }
-}
-
-static void
-channel_closed_cb (ExampleEcho2Channel *chan,
-                   ExampleEcho2Factory *self)
-{
-  tp_channel_manager_emit_channel_closed_for_object (self,
-      TP_EXPORTABLE_CHANNEL (chan));
-
-  if (self->priv->channels != NULL)
-    {
-      TpHandle handle;
-      gboolean really_destroyed;
-
-      g_object_get (chan,
-          "handle", &handle,
-          "channel-destroyed", &really_destroyed,
-          NULL);
-
-      /* Re-announce the channel if it's not yet ready to go away (pending
-       * messages) */
-      if (really_destroyed)
-        {
-          g_hash_table_remove (self->priv->channels,
-              GUINT_TO_POINTER (handle));
-        }
-      else
-        {
-          tp_channel_manager_emit_new_channel (self,
-              TP_EXPORTABLE_CHANNEL (chan), NULL);
-        }
-    }
-}
-
-static ExampleEcho2Channel *
-new_channel (ExampleEcho2Factory *self,
-             TpHandle handle,
-             TpHandle initiator,
-             gpointer request_token)
-{
-  ExampleEcho2Channel *chan;
-  gchar *object_path;
-  GSList *requests = NULL;
-
-  object_path = g_strdup_printf ("%s/Echo2Channel%u",
-      self->priv->conn->object_path, handle);
-
-  chan = g_object_new (EXAMPLE_TYPE_ECHO_2_CHANNEL,
-      "connection", self->priv->conn,
-      "object-path", object_path,
-      "handle", handle,
-      "initiator-handle", initiator,
-      NULL);
-
-  g_free (object_path);
-
-  g_signal_connect (chan, "closed", (GCallback) channel_closed_cb, self);
-
-  g_hash_table_insert (self->priv->channels, GUINT_TO_POINTER (handle), chan);
-
-  if (request_token != NULL)
-    requests = g_slist_prepend (requests, request_token);
-
-  tp_channel_manager_emit_new_channel (self, TP_EXPORTABLE_CHANNEL (chan),
-      requests);
-  g_slist_free (requests);
-
-  return chan;
-}
-
-static const gchar * const fixed_properties[] = {
-    TP_IFACE_CHANNEL ".ChannelType",
-    TP_IFACE_CHANNEL ".TargetHandleType",
-    NULL
-};
-
-static const gchar * const allowed_properties[] = {
-    TP_IFACE_CHANNEL ".TargetHandle",
-    TP_IFACE_CHANNEL ".TargetID",
-    NULL
-};
-
-static void
-example_echo_2_factory_foreach_channel_class (TpChannelManager *manager,
-    TpChannelManagerChannelClassFunc func,
-    gpointer user_data)
-{
-    GHashTable *table = g_hash_table_new_full (g_str_hash, g_str_equal,
-        NULL, (GDestroyNotify) tp_g_value_slice_free);
-    GValue *value;
-
-    value = tp_g_value_slice_new (G_TYPE_STRING);
-    g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_TEXT);
-    g_hash_table_insert (table, TP_IFACE_CHANNEL ".ChannelType", value);
-
-    value = tp_g_value_slice_new (G_TYPE_UINT);
-    g_value_set_uint (value, TP_HANDLE_TYPE_CONTACT);
-    g_hash_table_insert (table, TP_IFACE_CHANNEL ".TargetHandleType", value);
-
-    func (manager, table, allowed_properties, user_data);
-
-    g_hash_table_destroy (table);
-}
-
-static gboolean
-example_echo_2_factory_request (ExampleEcho2Factory *self,
-                                gpointer request_token,
-                                GHashTable *request_properties,
-                                gboolean require_new)
-{
-  TpHandle handle;
-  ExampleEcho2Channel *chan;
-  GError *error = NULL;
-
-  if (tp_strdiff (tp_asv_get_string (request_properties,
-          TP_IFACE_CHANNEL ".ChannelType"),
-      TP_IFACE_CHANNEL_TYPE_TEXT))
-    {
-      return FALSE;
-    }
-
-  if (tp_asv_get_uint32 (request_properties,
-      TP_IFACE_CHANNEL ".TargetHandleType", NULL) != TP_HANDLE_TYPE_CONTACT)
-    {
-      return FALSE;
-    }
-
-  handle = tp_asv_get_uint32 (request_properties,
-      TP_IFACE_CHANNEL ".TargetHandle", NULL);
-  g_assert (handle != 0);
-
-  if (tp_channel_manager_asv_has_unknown_properties (request_properties,
-        fixed_properties, allowed_properties, &error))
-    {
-      goto error;
-    }
-
-  chan = g_hash_table_lookup (self->priv->channels, GUINT_TO_POINTER (handle));
-
-  if (chan == NULL)
-    {
-      chan = new_channel (self, handle, self->priv->conn->self_handle,
-          request_token);
-    }
-  else if (require_new)
-    {
-      g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
-          "An echo2 channel to contact #%u already exists", handle);
-      goto error;
-    }
-  else
-    {
-      tp_channel_manager_emit_request_already_satisfied (self,
-          request_token, TP_EXPORTABLE_CHANNEL (chan));
-    }
-
-  return TRUE;
-
-error:
-  tp_channel_manager_emit_request_failed (self, request_token,
-      error->domain, error->code, error->message);
-  g_error_free (error);
-  return TRUE;
-}
-
-static gboolean
-example_echo_2_factory_create_channel (TpChannelManager *manager,
-                                       gpointer request_token,
-                                       GHashTable *request_properties)
-{
-    return example_echo_2_factory_request (EXAMPLE_ECHO_2_FACTORY (manager),
-        request_token, request_properties, TRUE);
-}
-
-static gboolean
-example_echo_2_factory_ensure_channel (TpChannelManager *manager,
-                                       gpointer request_token,
-                                       GHashTable *request_properties)
-{
-    return example_echo_2_factory_request (EXAMPLE_ECHO_2_FACTORY (manager),
-        request_token, request_properties, FALSE);
-}
-
-static void
-channel_manager_iface_init (gpointer g_iface,
-                            gpointer data G_GNUC_UNUSED)
-{
-  TpChannelManagerIface *iface = g_iface;
-
-  iface->foreach_channel = example_echo_2_factory_foreach_channel;
-  iface->foreach_channel_class = example_echo_2_factory_foreach_channel_class;
-  iface->create_channel = example_echo_2_factory_create_channel;
-  iface->ensure_channel = example_echo_2_factory_ensure_channel;
-  /* In this channel manager, Request has the same semantics as Ensure */
-  iface->request_channel = example_echo_2_factory_ensure_channel;
-}
diff --git a/examples/cm/echo-message-parts/factory.h b/examples/cm/echo-message-parts/factory.h
deleted file mode 100644
index 6c09cb4..0000000
--- a/examples/cm/echo-message-parts/factory.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * factory.h - header for an example channel factory
- *
- * Copyright (C) 2007 Collabora Ltd. <http://www.collabora.co.uk/>
- * Copyright (C) 2007 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.
- */
-
-#ifndef EXAMPLE_ECHO_MESSAGE_PARTS_FACTORY_H
-#define EXAMPLE_ECHO_MESSAGE_PARTS_FACTORY_H
-
-#include <glib-object.h>
-#include <telepathy-glib/channel-factory-iface.h>
-
-G_BEGIN_DECLS
-
-typedef struct _ExampleEcho2Factory ExampleEcho2Factory;
-typedef struct _ExampleEcho2FactoryClass ExampleEcho2FactoryClass;
-typedef struct _ExampleEcho2FactoryPrivate ExampleEcho2FactoryPrivate;
-
-struct _ExampleEcho2FactoryClass {
-    GObjectClass parent_class;
-};
-
-struct _ExampleEcho2Factory {
-    GObject parent;
-
-    ExampleEcho2FactoryPrivate *priv;
-};
-
-GType example_echo_2_factory_get_type (void);
-
-/* TYPE MACROS */
-#define EXAMPLE_TYPE_ECHO_2_FACTORY \
-  (example_echo_2_factory_get_type ())
-#define EXAMPLE_ECHO_2_FACTORY(obj) \
-  (G_TYPE_CHECK_INSTANCE_CAST((obj), EXAMPLE_TYPE_ECHO_2_FACTORY, \
-                              ExampleEcho2Factory))
-#define EXAMPLE_ECHO_2_FACTORY_CLASS(klass) \
-  (G_TYPE_CHECK_CLASS_CAST((klass), EXAMPLE_TYPE_ECHO_2_FACTORY, \
-                           ExampleEcho2FactoryClass))
-#define EXAMPLE_IS_ECHO_2_FACTORY(obj) \
-  (G_TYPE_CHECK_INSTANCE_TYPE((obj), EXAMPLE_TYPE_ECHO_2_FACTORY))
-#define EXAMPLE_IS_ECHO_2_FACTORY_CLASS(klass) \
-  (G_TYPE_CHECK_CLASS_TYPE((klass), EXAMPLE_TYPE_ECHO_2_FACTORY))
-#define EXAMPLE_ECHO_2_FACTORY_GET_CLASS(obj) \
-  (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_ECHO_2_FACTORY, \
-                              ExampleEcho2FactoryClass))
-
-G_END_DECLS
-
-#endif
diff --git a/examples/cm/echo-message-parts/im-manager.c b/examples/cm/echo-message-parts/im-manager.c
new file mode 100644
index 0000000..87b55a2
--- /dev/null
+++ b/examples/cm/echo-message-parts/im-manager.c
@@ -0,0 +1,389 @@
+/*
+ * im-manager.c - an example channel manager for channels talking to a
+ * particular contact. Similar code is used for 1-1 IM channels in many
+ * protocols (IRC private messages ("/query"), XMPP IM etc.)
+ *
+ * Copyright (C) 2007 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 2007 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 "im-manager.h"
+
+#include <dbus/dbus-glib.h>
+
+#include <telepathy-glib/base-connection.h>
+#include <telepathy-glib/channel-manager.h>
+#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/errors.h>
+#include <telepathy-glib/interfaces.h>
+
+#include "chan.h"
+
+static void channel_manager_iface_init (gpointer, gpointer);
+
+G_DEFINE_TYPE_WITH_CODE (ExampleEcho2Factory,
+    example_echo_2_factory,
+    G_TYPE_OBJECT,
+    G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER,
+      channel_manager_iface_init))
+
+/* type definition stuff */
+
+enum
+{
+  PROP_CONNECTION = 1,
+  N_PROPS
+};
+
+struct _ExampleEcho2FactoryPrivate
+{
+  TpBaseConnection *conn;
+
+  /* GUINT_TO_POINTER (handle) => ExampleEcho2Channel */
+  GHashTable *channels;
+  gulong status_changed_id;
+};
+
+static void
+example_echo_2_factory_init (ExampleEcho2Factory *self)
+{
+  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_ECHO_2_FACTORY,
+      ExampleEcho2FactoryPrivate);
+
+  self->priv->channels = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+      NULL, g_object_unref);
+}
+
+static void example_echo_2_factory_close_all (ExampleEcho2Factory *self);
+
+static void
+dispose (GObject *object)
+{
+  ExampleEcho2Factory *self = EXAMPLE_ECHO_2_FACTORY (object);
+
+  example_echo_2_factory_close_all (self);
+  g_assert (self->priv->channels == NULL);
+
+  ((GObjectClass *) example_echo_2_factory_parent_class)->dispose (object);
+}
+
+static void
+get_property (GObject *object,
+              guint property_id,
+              GValue *value,
+              GParamSpec *pspec)
+{
+  ExampleEcho2Factory *self = EXAMPLE_ECHO_2_FACTORY (object);
+
+  switch (property_id)
+    {
+    case PROP_CONNECTION:
+      g_value_set_object (value, self->priv->conn);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+set_property (GObject *object,
+              guint property_id,
+              const GValue *value,
+              GParamSpec *pspec)
+{
+  ExampleEcho2Factory *self = EXAMPLE_ECHO_2_FACTORY (object);
+
+  switch (property_id)
+    {
+    case PROP_CONNECTION:
+      /* We don't ref the connection, because it owns a reference to the
+       * factory, and it guarantees that the factory's lifetime is
+       * less than its lifetime */
+      self->priv->conn = g_value_get_object (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+status_changed_cb (TpBaseConnection *conn,
+                   guint status,
+                   guint reason,
+                   ExampleEcho2Factory *self)
+{
+  if (status == TP_CONNECTION_STATUS_DISCONNECTED)
+    example_echo_2_factory_close_all (self);
+}
+
+static void
+constructed (GObject *object)
+{
+  ExampleEcho2Factory *self = EXAMPLE_ECHO_2_FACTORY (object);
+  void (*chain_up) (GObject *) =
+      ((GObjectClass *) example_echo_2_factory_parent_class)->constructed;
+
+  if (chain_up != NULL)
+    {
+      chain_up (object);
+    }
+
+  self->priv->status_changed_id = g_signal_connect (self->priv->conn,
+      "status-changed", (GCallback) status_changed_cb, self);
+}
+
+static void
+example_echo_2_factory_class_init (ExampleEcho2FactoryClass *klass)
+{
+  GParamSpec *param_spec;
+  GObjectClass *object_class = (GObjectClass *) klass;
+
+  object_class->constructed = constructed;
+  object_class->dispose = dispose;
+  object_class->get_property = get_property;
+  object_class->set_property = set_property;
+
+  param_spec = g_param_spec_object ("connection", "Connection object",
+      "The connection that owns this channel factory",
+      TP_TYPE_BASE_CONNECTION,
+      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
+      G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
+  g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
+
+  g_type_class_add_private (klass, sizeof (ExampleEcho2FactoryPrivate));
+}
+
+static void
+example_echo_2_factory_close_all (ExampleEcho2Factory *self)
+{
+  if (self->priv->channels != NULL)
+    {
+      GHashTable *tmp = self->priv->channels;
+
+      self->priv->channels = NULL;
+      g_hash_table_destroy (tmp);
+    }
+
+  if (self->priv->status_changed_id != 0)
+    {
+      g_signal_handler_disconnect (self->priv->conn,
+          self->priv->status_changed_id);
+      self->priv->status_changed_id = 0;
+    }
+}
+
+static void
+example_echo_2_factory_foreach_channel (TpChannelManager *iface,
+                                        TpExportableChannelFunc callback,
+                                        gpointer user_data)
+{
+  ExampleEcho2Factory *self = EXAMPLE_ECHO_2_FACTORY (iface);
+  GHashTableIter iter;
+  gpointer handle, channel;
+
+  g_hash_table_iter_init (&iter, self->priv->channels);
+
+  while (g_hash_table_iter_next (&iter, &handle, &channel))
+    {
+      callback (TP_EXPORTABLE_CHANNEL (channel), user_data);
+    }
+}
+
+static void
+channel_closed_cb (ExampleEcho2Channel *chan,
+                   ExampleEcho2Factory *self)
+{
+  tp_channel_manager_emit_channel_closed_for_object (self,
+      TP_EXPORTABLE_CHANNEL (chan));
+
+  if (self->priv->channels != NULL)
+    {
+      TpHandle handle;
+      gboolean really_destroyed;
+
+      g_object_get (chan,
+          "handle", &handle,
+          "channel-destroyed", &really_destroyed,
+          NULL);
+
+      /* Re-announce the channel if it's not yet ready to go away (pending
+       * messages) */
+      if (really_destroyed)
+        {
+          g_hash_table_remove (self->priv->channels,
+              GUINT_TO_POINTER (handle));
+        }
+      else
+        {
+          tp_channel_manager_emit_new_channel (self,
+              TP_EXPORTABLE_CHANNEL (chan), NULL);
+        }
+    }
+}
+
+static ExampleEcho2Channel *
+new_channel (ExampleEcho2Factory *self,
+             TpHandle handle,
+             TpHandle initiator,
+             gpointer request_token)
+{
+  ExampleEcho2Channel *chan;
+  gchar *object_path;
+  GSList *requests = NULL;
+
+  object_path = g_strdup_printf ("%s/Echo2Channel%u",
+      self->priv->conn->object_path, handle);
+
+  chan = g_object_new (EXAMPLE_TYPE_ECHO_2_CHANNEL,
+      "connection", self->priv->conn,
+      "object-path", object_path,
+      "handle", handle,
+      "initiator-handle", initiator,
+      NULL);
+
+  g_free (object_path);
+
+  g_signal_connect (chan, "closed", (GCallback) channel_closed_cb, self);
+
+  g_hash_table_insert (self->priv->channels, GUINT_TO_POINTER (handle), chan);
+
+  if (request_token != NULL)
+    requests = g_slist_prepend (requests, request_token);
+
+  tp_channel_manager_emit_new_channel (self, TP_EXPORTABLE_CHANNEL (chan),
+      requests);
+  g_slist_free (requests);
+
+  return chan;
+}
+
+static const gchar * const fixed_properties[] = {
+    TP_IFACE_CHANNEL ".ChannelType",
+    TP_IFACE_CHANNEL ".TargetHandleType",
+    NULL
+};
+
+static const gchar * const allowed_properties[] = {
+    TP_IFACE_CHANNEL ".TargetHandle",
+    TP_IFACE_CHANNEL ".TargetID",
+    NULL
+};
+
+static void
+example_echo_2_factory_foreach_channel_class (TpChannelManager *manager,
+    TpChannelManagerChannelClassFunc func,
+    gpointer user_data)
+{
+    GHashTable *table = g_hash_table_new_full (g_str_hash, g_str_equal,
+        NULL, (GDestroyNotify) tp_g_value_slice_free);
+    GValue *value;
+
+    value = tp_g_value_slice_new (G_TYPE_STRING);
+    g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_TEXT);
+    g_hash_table_insert (table, TP_IFACE_CHANNEL ".ChannelType", value);
+
+    value = tp_g_value_slice_new (G_TYPE_UINT);
+    g_value_set_uint (value, TP_HANDLE_TYPE_CONTACT);
+    g_hash_table_insert (table, TP_IFACE_CHANNEL ".TargetHandleType", value);
+
+    func (manager, table, allowed_properties, user_data);
+
+    g_hash_table_destroy (table);
+}
+
+static gboolean
+example_echo_2_factory_request (ExampleEcho2Factory *self,
+                                gpointer request_token,
+                                GHashTable *request_properties,
+                                gboolean require_new)
+{
+  TpHandle handle;
+  ExampleEcho2Channel *chan;
+  GError *error = NULL;
+
+  if (tp_strdiff (tp_asv_get_string (request_properties,
+          TP_IFACE_CHANNEL ".ChannelType"),
+      TP_IFACE_CHANNEL_TYPE_TEXT))
+    {
+      return FALSE;
+    }
+
+  if (tp_asv_get_uint32 (request_properties,
+      TP_IFACE_CHANNEL ".TargetHandleType", NULL) != TP_HANDLE_TYPE_CONTACT)
+    {
+      return FALSE;
+    }
+
+  handle = tp_asv_get_uint32 (request_properties,
+      TP_IFACE_CHANNEL ".TargetHandle", NULL);
+  g_assert (handle != 0);
+
+  if (tp_channel_manager_asv_has_unknown_properties (request_properties,
+        fixed_properties, allowed_properties, &error))
+    {
+      goto error;
+    }
+
+  chan = g_hash_table_lookup (self->priv->channels, GUINT_TO_POINTER (handle));
+
+  if (chan == NULL)
+    {
+      chan = new_channel (self, handle, self->priv->conn->self_handle,
+          request_token);
+    }
+  else if (require_new)
+    {
+      g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+          "An echo2 channel to contact #%u already exists", handle);
+      goto error;
+    }
+  else
+    {
+      tp_channel_manager_emit_request_already_satisfied (self,
+          request_token, TP_EXPORTABLE_CHANNEL (chan));
+    }
+
+  return TRUE;
+
+error:
+  tp_channel_manager_emit_request_failed (self, request_token,
+      error->domain, error->code, error->message);
+  g_error_free (error);
+  return TRUE;
+}
+
+static gboolean
+example_echo_2_factory_create_channel (TpChannelManager *manager,
+                                       gpointer request_token,
+                                       GHashTable *request_properties)
+{
+    return example_echo_2_factory_request (EXAMPLE_ECHO_2_FACTORY (manager),
+        request_token, request_properties, TRUE);
+}
+
+static gboolean
+example_echo_2_factory_ensure_channel (TpChannelManager *manager,
+                                       gpointer request_token,
+                                       GHashTable *request_properties)
+{
+    return example_echo_2_factory_request (EXAMPLE_ECHO_2_FACTORY (manager),
+        request_token, request_properties, FALSE);
+}
+
+static void
+channel_manager_iface_init (gpointer g_iface,
+                            gpointer data G_GNUC_UNUSED)
+{
+  TpChannelManagerIface *iface = g_iface;
+
+  iface->foreach_channel = example_echo_2_factory_foreach_channel;
+  iface->foreach_channel_class = example_echo_2_factory_foreach_channel_class;
+  iface->create_channel = example_echo_2_factory_create_channel;
+  iface->ensure_channel = example_echo_2_factory_ensure_channel;
+  /* In this channel manager, Request has the same semantics as Ensure */
+  iface->request_channel = example_echo_2_factory_ensure_channel;
+}
diff --git a/examples/cm/echo-message-parts/im-manager.h b/examples/cm/echo-message-parts/im-manager.h
new file mode 100644
index 0000000..6c09cb4
--- /dev/null
+++ b/examples/cm/echo-message-parts/im-manager.h
@@ -0,0 +1,55 @@
+/*
+ * factory.h - header for an example channel factory
+ *
+ * Copyright (C) 2007 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef EXAMPLE_ECHO_MESSAGE_PARTS_FACTORY_H
+#define EXAMPLE_ECHO_MESSAGE_PARTS_FACTORY_H
+
+#include <glib-object.h>
+#include <telepathy-glib/channel-factory-iface.h>
+
+G_BEGIN_DECLS
+
+typedef struct _ExampleEcho2Factory ExampleEcho2Factory;
+typedef struct _ExampleEcho2FactoryClass ExampleEcho2FactoryClass;
+typedef struct _ExampleEcho2FactoryPrivate ExampleEcho2FactoryPrivate;
+
+struct _ExampleEcho2FactoryClass {
+    GObjectClass parent_class;
+};
+
+struct _ExampleEcho2Factory {
+    GObject parent;
+
+    ExampleEcho2FactoryPrivate *priv;
+};
+
+GType example_echo_2_factory_get_type (void);
+
+/* TYPE MACROS */
+#define EXAMPLE_TYPE_ECHO_2_FACTORY \
+  (example_echo_2_factory_get_type ())
+#define EXAMPLE_ECHO_2_FACTORY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), EXAMPLE_TYPE_ECHO_2_FACTORY, \
+                              ExampleEcho2Factory))
+#define EXAMPLE_ECHO_2_FACTORY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), EXAMPLE_TYPE_ECHO_2_FACTORY, \
+                           ExampleEcho2FactoryClass))
+#define EXAMPLE_IS_ECHO_2_FACTORY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), EXAMPLE_TYPE_ECHO_2_FACTORY))
+#define EXAMPLE_IS_ECHO_2_FACTORY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), EXAMPLE_TYPE_ECHO_2_FACTORY))
+#define EXAMPLE_ECHO_2_FACTORY_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_ECHO_2_FACTORY, \
+                              ExampleEcho2FactoryClass))
+
+G_END_DECLS
+
+#endif
diff --git a/examples/cm/echo/Makefile.am b/examples/cm/echo/Makefile.am
index 2988773..536728a 100644
--- a/examples/cm/echo/Makefile.am
+++ b/examples/cm/echo/Makefile.am
@@ -8,8 +8,8 @@ libexample_cm_echo_la_SOURCES = \
     conn.h \
     connection-manager.c \
     connection-manager.h \
-    factory.c \
-    factory.h
+    im-manager.c \
+    im-manager.h
 
 # In an external project you'd use $(TP_GLIB_LIBS) (obtained from
 # pkg-config via autoconf) instead of the .la path
diff --git a/examples/cm/echo/conn.c b/examples/cm/echo/conn.c
index 7b43c77..1d7c186 100644
--- a/examples/cm/echo/conn.c
+++ b/examples/cm/echo/conn.c
@@ -18,7 +18,7 @@
 #include <telepathy-glib/handle-repo-dynamic.h>
 #include <telepathy-glib/interfaces.h>
 
-#include "factory.h"
+#include "im-manager.h"
 
 G_DEFINE_TYPE (ExampleEchoConnection,
     example_echo_connection,
diff --git a/examples/cm/echo/factory.c b/examples/cm/echo/factory.c
deleted file mode 100644
index 5a968e6..0000000
--- a/examples/cm/echo/factory.c
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * factory.c - an example channel factory for channels talking to a particular
- * contact. Similar code is used for 1-1 IM channels in many protocols
- * (IRC private messages ("/query"), XMPP IM etc.)
- *
- * Copyright (C) 2007 Collabora Ltd. <http://www.collabora.co.uk/>
- * Copyright (C) 2007 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 "factory.h"
-
-#include <dbus/dbus-glib.h>
-
-#include <telepathy-glib/base-connection.h>
-#include <telepathy-glib/channel-manager.h>
-#include <telepathy-glib/dbus.h>
-#include <telepathy-glib/errors.h>
-#include <telepathy-glib/interfaces.h>
-
-#include "chan.h"
-
-static void channel_manager_iface_init (gpointer, gpointer);
-
-G_DEFINE_TYPE_WITH_CODE (ExampleEchoFactory,
-    example_echo_factory,
-    G_TYPE_OBJECT,
-    G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER,
-      channel_manager_iface_init))
-
-/* type definition stuff */
-
-enum
-{
-  PROP_CONNECTION = 1,
-  N_PROPS
-};
-
-struct _ExampleEchoFactoryPrivate
-{
-  TpBaseConnection *conn;
-
-  /* GUINT_TO_POINTER (handle) => ExampleEchoChannel */
-  GHashTable *channels;
-  gulong status_changed_id;
-};
-
-static void
-example_echo_factory_init (ExampleEchoFactory *self)
-{
-  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_ECHO_FACTORY,
-      ExampleEchoFactoryPrivate);
-
-  self->priv->channels = g_hash_table_new_full (g_direct_hash, g_direct_equal,
-      NULL, g_object_unref);
-}
-
-static void example_echo_factory_close_all (ExampleEchoFactory *self);
-
-static void
-dispose (GObject *object)
-{
-  ExampleEchoFactory *self = EXAMPLE_ECHO_FACTORY (object);
-
-  example_echo_factory_close_all (self);
-  g_assert (self->priv->channels == NULL);
-
-  ((GObjectClass *) example_echo_factory_parent_class)->dispose (object);
-}
-
-static void
-get_property (GObject *object,
-              guint property_id,
-              GValue *value,
-              GParamSpec *pspec)
-{
-  ExampleEchoFactory *self = EXAMPLE_ECHO_FACTORY (object);
-
-  switch (property_id)
-    {
-    case PROP_CONNECTION:
-      g_value_set_object (value, self->priv->conn);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-    }
-}
-
-static void
-set_property (GObject *object,
-              guint property_id,
-              const GValue *value,
-              GParamSpec *pspec)
-{
-  ExampleEchoFactory *self = EXAMPLE_ECHO_FACTORY (object);
-
-  switch (property_id)
-    {
-    case PROP_CONNECTION:
-      /* We don't ref the connection, because it owns a reference to the
-       * factory, and it guarantees that the factory's lifetime is
-       * less than its lifetime */
-      self->priv->conn = g_value_get_object (value);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-    }
-}
-
-static void
-status_changed_cb (TpBaseConnection *conn,
-                   guint status,
-                   guint reason,
-                   ExampleEchoFactory *self)
-{
-  if (status == TP_CONNECTION_STATUS_DISCONNECTED)
-    example_echo_factory_close_all (self);
-}
-
-static void
-constructed (GObject *object)
-{
-  ExampleEchoFactory *self = EXAMPLE_ECHO_FACTORY (object);
-  void (*chain_up) (GObject *) =
-      ((GObjectClass *) example_echo_factory_parent_class)->constructed;
-
-  if (chain_up != NULL)
-    {
-      chain_up (object);
-    }
-
-  self->priv->status_changed_id = g_signal_connect (self->priv->conn,
-      "status-changed", (GCallback) status_changed_cb, self);
-}
-
-static void
-example_echo_factory_class_init (ExampleEchoFactoryClass *klass)
-{
-  GParamSpec *param_spec;
-  GObjectClass *object_class = (GObjectClass *) klass;
-
-  object_class->constructed = constructed;
-  object_class->dispose = dispose;
-  object_class->get_property = get_property;
-  object_class->set_property = set_property;
-
-  param_spec = g_param_spec_object ("connection", "Connection object",
-      "The connection that owns this channel factory",
-      TP_TYPE_BASE_CONNECTION,
-      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
-      G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
-  g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
-
-  g_type_class_add_private (klass, sizeof (ExampleEchoFactoryPrivate));
-}
-
-static void
-example_echo_factory_close_all (ExampleEchoFactory *self)
-{
-  if (self->priv->channels != NULL)
-    {
-      GHashTable *tmp = self->priv->channels;
-
-      self->priv->channels = NULL;
-      g_hash_table_destroy (tmp);
-    }
-
-  if (self->priv->status_changed_id != 0)
-    {
-      g_signal_handler_disconnect (self->priv->conn,
-          self->priv->status_changed_id);
-      self->priv->status_changed_id = 0;
-    }
-}
-
-static void
-example_echo_factory_foreach_channel (TpChannelManager *iface,
-                                      TpExportableChannelFunc callback,
-                                      gpointer user_data)
-{
-  ExampleEchoFactory *self = EXAMPLE_ECHO_FACTORY (iface);
-  GHashTableIter iter;
-  gpointer handle, channel;
-
-  g_hash_table_iter_init (&iter, self->priv->channels);
-
-  while (g_hash_table_iter_next (&iter, &handle, &channel))
-    {
-      callback (TP_EXPORTABLE_CHANNEL (channel), user_data);
-    }
-}
-
-static void
-channel_closed_cb (ExampleEchoChannel *chan,
-                   ExampleEchoFactory *self)
-{
-  tp_channel_manager_emit_channel_closed_for_object (self,
-      TP_EXPORTABLE_CHANNEL (chan));
-
-  if (self->priv->channels != NULL)
-    {
-      TpHandle handle;
-      gboolean really_destroyed;
-
-      g_object_get (chan,
-          "handle", &handle,
-          "channel-destroyed", &really_destroyed,
-          NULL);
-
-      /* Re-announce the channel if it's not yet ready to go away (pending
-       * messages) */
-      if (really_destroyed)
-        {
-          g_hash_table_remove (self->priv->channels,
-              GUINT_TO_POINTER (handle));
-        }
-      else
-        {
-          tp_channel_manager_emit_new_channel (self,
-              TP_EXPORTABLE_CHANNEL (chan), NULL);
-        }
-    }
-}
-
-static ExampleEchoChannel *
-new_channel (ExampleEchoFactory *self,
-             TpHandle handle,
-             TpHandle initiator,
-             gpointer request_token)
-{
-  ExampleEchoChannel *chan;
-  gchar *object_path;
-  GSList *requests = NULL;
-
-  object_path = g_strdup_printf ("%s/EchoChannel%u",
-      self->priv->conn->object_path, handle);
-
-  chan = g_object_new (EXAMPLE_TYPE_ECHO_CHANNEL,
-      "connection", self->priv->conn,
-      "object-path", object_path,
-      "handle", handle,
-      "initiator-handle", initiator,
-      NULL);
-
-  g_free (object_path);
-
-  g_signal_connect (chan, "closed", (GCallback) channel_closed_cb, self);
-
-  g_hash_table_insert (self->priv->channels, GUINT_TO_POINTER (handle), chan);
-
-  if (request_token != NULL)
-    requests = g_slist_prepend (requests, request_token);
-
-  tp_channel_manager_emit_new_channel (self, TP_EXPORTABLE_CHANNEL (chan),
-      requests);
-  g_slist_free (requests);
-
-  return chan;
-}
-
-static const gchar * const fixed_properties[] = {
-    TP_IFACE_CHANNEL ".ChannelType",
-    TP_IFACE_CHANNEL ".TargetHandleType",
-    NULL
-};
-
-static const gchar * const allowed_properties[] = {
-    TP_IFACE_CHANNEL ".TargetHandle",
-    TP_IFACE_CHANNEL ".TargetID",
-    NULL
-};
-
-static void
-example_echo_factory_foreach_channel_class (TpChannelManager *manager,
-    TpChannelManagerChannelClassFunc func,
-    gpointer user_data)
-{
-    GHashTable *table = g_hash_table_new_full (g_str_hash, g_str_equal,
-        NULL, (GDestroyNotify) tp_g_value_slice_free);
-    GValue *value;
-
-    value = tp_g_value_slice_new (G_TYPE_STRING);
-    g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_TEXT);
-    g_hash_table_insert (table, TP_IFACE_CHANNEL ".ChannelType", value);
-
-    value = tp_g_value_slice_new (G_TYPE_UINT);
-    g_value_set_uint (value, TP_HANDLE_TYPE_CONTACT);
-    g_hash_table_insert (table, TP_IFACE_CHANNEL ".TargetHandleType", value);
-
-    func (manager, table, allowed_properties, user_data);
-
-    g_hash_table_destroy (table);
-}
-
-static gboolean
-example_echo_factory_request (ExampleEchoFactory *self,
-                              gpointer request_token,
-                              GHashTable *request_properties,
-                              gboolean require_new)
-{
-  TpHandle handle;
-  ExampleEchoChannel *chan;
-  GError *error = NULL;
-
-  if (tp_strdiff (tp_asv_get_string (request_properties,
-          TP_IFACE_CHANNEL ".ChannelType"),
-      TP_IFACE_CHANNEL_TYPE_TEXT))
-    {
-      return FALSE;
-    }
-
-  if (tp_asv_get_uint32 (request_properties,
-      TP_IFACE_CHANNEL ".TargetHandleType", NULL) != TP_HANDLE_TYPE_CONTACT)
-    {
-      return FALSE;
-    }
-
-  handle = tp_asv_get_uint32 (request_properties,
-      TP_IFACE_CHANNEL ".TargetHandle", NULL);
-  g_assert (handle != 0);
-
-  if (tp_channel_manager_asv_has_unknown_properties (request_properties,
-        fixed_properties, allowed_properties, &error))
-    {
-      goto error;
-    }
-
-  chan = g_hash_table_lookup (self->priv->channels, GUINT_TO_POINTER (handle));
-
-  if (chan == NULL)
-    {
-      chan = new_channel (self, handle, self->priv->conn->self_handle,
-          request_token);
-    }
-  else if (require_new)
-    {
-      g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
-          "An echo channel to contact #%u already exists", handle);
-      goto error;
-    }
-  else
-    {
-      tp_channel_manager_emit_request_already_satisfied (self,
-          request_token, TP_EXPORTABLE_CHANNEL (chan));
-    }
-
-  return TRUE;
-
-error:
-  tp_channel_manager_emit_request_failed (self, request_token,
-      error->domain, error->code, error->message);
-  g_error_free (error);
-  return TRUE;
-}
-
-static gboolean
-example_echo_factory_create_channel (TpChannelManager *manager,
-                                     gpointer request_token,
-                                     GHashTable *request_properties)
-{
-    return example_echo_factory_request (EXAMPLE_ECHO_FACTORY (manager),
-        request_token, request_properties, TRUE);
-}
-
-static gboolean
-example_echo_factory_ensure_channel (TpChannelManager *manager,
-                                     gpointer request_token,
-                                     GHashTable *request_properties)
-{
-    return example_echo_factory_request (EXAMPLE_ECHO_FACTORY (manager),
-        request_token, request_properties, FALSE);
-}
-
-static void
-channel_manager_iface_init (gpointer g_iface,
-                            gpointer iface_data G_GNUC_UNUSED)
-{
-  TpChannelManagerIface *iface = g_iface;
-
-  iface->foreach_channel = example_echo_factory_foreach_channel;
-  iface->foreach_channel_class = example_echo_factory_foreach_channel_class;
-  iface->create_channel = example_echo_factory_create_channel;
-  iface->ensure_channel = example_echo_factory_ensure_channel;
-  /* In this channel manager, Request has the same semantics as Ensure */
-  iface->request_channel = example_echo_factory_ensure_channel;
-}
diff --git a/examples/cm/echo/factory.h b/examples/cm/echo/factory.h
deleted file mode 100644
index 4b74cb2..0000000
--- a/examples/cm/echo/factory.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * factory.h - header for an example channel factory
- *
- * Copyright (C) 2007 Collabora Ltd. <http://www.collabora.co.uk/>
- * Copyright (C) 2007 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.
- */
-
-#ifndef __EXAMPLE_FACTORY_H__
-#define __EXAMPLE_FACTORY_H__
-
-#include <glib-object.h>
-#include <telepathy-glib/channel-factory-iface.h>
-
-G_BEGIN_DECLS
-
-typedef struct _ExampleEchoFactory ExampleEchoFactory;
-typedef struct _ExampleEchoFactoryClass ExampleEchoFactoryClass;
-typedef struct _ExampleEchoFactoryPrivate ExampleEchoFactoryPrivate;
-
-struct _ExampleEchoFactoryClass {
-    GObjectClass parent_class;
-};
-
-struct _ExampleEchoFactory {
-    GObject parent;
-
-    ExampleEchoFactoryPrivate *priv;
-};
-
-GType example_echo_factory_get_type (void);
-
-/* TYPE MACROS */
-#define EXAMPLE_TYPE_ECHO_FACTORY \
-  (example_echo_factory_get_type ())
-#define EXAMPLE_ECHO_FACTORY(obj) \
-  (G_TYPE_CHECK_INSTANCE_CAST((obj), EXAMPLE_TYPE_ECHO_FACTORY, \
-                              ExampleEchoFactory))
-#define EXAMPLE_ECHO_FACTORY_CLASS(klass) \
-  (G_TYPE_CHECK_CLASS_CAST((klass), EXAMPLE_TYPE_ECHO_FACTORY, \
-                           ExampleEchoFactoryClass))
-#define EXAMPLE_IS_ECHO_FACTORY(obj) \
-  (G_TYPE_CHECK_INSTANCE_TYPE((obj), EXAMPLE_TYPE_ECHO_FACTORY))
-#define EXAMPLE_IS_ECHO_FACTORY_CLASS(klass) \
-  (G_TYPE_CHECK_CLASS_TYPE((klass), EXAMPLE_TYPE_ECHO_FACTORY))
-#define EXAMPLE_ECHO_FACTORY_GET_CLASS(obj) \
-  (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_ECHO_FACTORY, \
-                              ExampleEchoFactoryClass))
-
-G_END_DECLS
-
-#endif /* #ifndef __EXAMPLE_FACTORY_H__ */
diff --git a/examples/cm/echo/im-manager.c b/examples/cm/echo/im-manager.c
new file mode 100644
index 0000000..540d12a
--- /dev/null
+++ b/examples/cm/echo/im-manager.c
@@ -0,0 +1,389 @@
+/*
+ * im-manager.c - an example channel manager for channels talking to a
+ * particular contact. Similar code is used for 1-1 IM channels in many
+ * protocols (IRC private messages ("/query"), XMPP IM etc.)
+ *
+ * Copyright (C) 2007 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 2007 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 "im-manager.h"
+
+#include <dbus/dbus-glib.h>
+
+#include <telepathy-glib/base-connection.h>
+#include <telepathy-glib/channel-manager.h>
+#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/errors.h>
+#include <telepathy-glib/interfaces.h>
+
+#include "chan.h"
+
+static void channel_manager_iface_init (gpointer, gpointer);
+
+G_DEFINE_TYPE_WITH_CODE (ExampleEchoFactory,
+    example_echo_factory,
+    G_TYPE_OBJECT,
+    G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER,
+      channel_manager_iface_init))
+
+/* type definition stuff */
+
+enum
+{
+  PROP_CONNECTION = 1,
+  N_PROPS
+};
+
+struct _ExampleEchoFactoryPrivate
+{
+  TpBaseConnection *conn;
+
+  /* GUINT_TO_POINTER (handle) => ExampleEchoChannel */
+  GHashTable *channels;
+  gulong status_changed_id;
+};
+
+static void
+example_echo_factory_init (ExampleEchoFactory *self)
+{
+  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_ECHO_FACTORY,
+      ExampleEchoFactoryPrivate);
+
+  self->priv->channels = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+      NULL, g_object_unref);
+}
+
+static void example_echo_factory_close_all (ExampleEchoFactory *self);
+
+static void
+dispose (GObject *object)
+{
+  ExampleEchoFactory *self = EXAMPLE_ECHO_FACTORY (object);
+
+  example_echo_factory_close_all (self);
+  g_assert (self->priv->channels == NULL);
+
+  ((GObjectClass *) example_echo_factory_parent_class)->dispose (object);
+}
+
+static void
+get_property (GObject *object,
+              guint property_id,
+              GValue *value,
+              GParamSpec *pspec)
+{
+  ExampleEchoFactory *self = EXAMPLE_ECHO_FACTORY (object);
+
+  switch (property_id)
+    {
+    case PROP_CONNECTION:
+      g_value_set_object (value, self->priv->conn);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+set_property (GObject *object,
+              guint property_id,
+              const GValue *value,
+              GParamSpec *pspec)
+{
+  ExampleEchoFactory *self = EXAMPLE_ECHO_FACTORY (object);
+
+  switch (property_id)
+    {
+    case PROP_CONNECTION:
+      /* We don't ref the connection, because it owns a reference to the
+       * factory, and it guarantees that the factory's lifetime is
+       * less than its lifetime */
+      self->priv->conn = g_value_get_object (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+status_changed_cb (TpBaseConnection *conn,
+                   guint status,
+                   guint reason,
+                   ExampleEchoFactory *self)
+{
+  if (status == TP_CONNECTION_STATUS_DISCONNECTED)
+    example_echo_factory_close_all (self);
+}
+
+static void
+constructed (GObject *object)
+{
+  ExampleEchoFactory *self = EXAMPLE_ECHO_FACTORY (object);
+  void (*chain_up) (GObject *) =
+      ((GObjectClass *) example_echo_factory_parent_class)->constructed;
+
+  if (chain_up != NULL)
+    {
+      chain_up (object);
+    }
+
+  self->priv->status_changed_id = g_signal_connect (self->priv->conn,
+      "status-changed", (GCallback) status_changed_cb, self);
+}
+
+static void
+example_echo_factory_class_init (ExampleEchoFactoryClass *klass)
+{
+  GParamSpec *param_spec;
+  GObjectClass *object_class = (GObjectClass *) klass;
+
+  object_class->constructed = constructed;
+  object_class->dispose = dispose;
+  object_class->get_property = get_property;
+  object_class->set_property = set_property;
+
+  param_spec = g_param_spec_object ("connection", "Connection object",
+      "The connection that owns this channel factory",
+      TP_TYPE_BASE_CONNECTION,
+      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
+      G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
+  g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
+
+  g_type_class_add_private (klass, sizeof (ExampleEchoFactoryPrivate));
+}
+
+static void
+example_echo_factory_close_all (ExampleEchoFactory *self)
+{
+  if (self->priv->channels != NULL)
+    {
+      GHashTable *tmp = self->priv->channels;
+
+      self->priv->channels = NULL;
+      g_hash_table_destroy (tmp);
+    }
+
+  if (self->priv->status_changed_id != 0)
+    {
+      g_signal_handler_disconnect (self->priv->conn,
+          self->priv->status_changed_id);
+      self->priv->status_changed_id = 0;
+    }
+}
+
+static void
+example_echo_factory_foreach_channel (TpChannelManager *iface,
+                                      TpExportableChannelFunc callback,
+                                      gpointer user_data)
+{
+  ExampleEchoFactory *self = EXAMPLE_ECHO_FACTORY (iface);
+  GHashTableIter iter;
+  gpointer handle, channel;
+
+  g_hash_table_iter_init (&iter, self->priv->channels);
+
+  while (g_hash_table_iter_next (&iter, &handle, &channel))
+    {
+      callback (TP_EXPORTABLE_CHANNEL (channel), user_data);
+    }
+}
+
+static void
+channel_closed_cb (ExampleEchoChannel *chan,
+                   ExampleEchoFactory *self)
+{
+  tp_channel_manager_emit_channel_closed_for_object (self,
+      TP_EXPORTABLE_CHANNEL (chan));
+
+  if (self->priv->channels != NULL)
+    {
+      TpHandle handle;
+      gboolean really_destroyed;
+
+      g_object_get (chan,
+          "handle", &handle,
+          "channel-destroyed", &really_destroyed,
+          NULL);
+
+      /* Re-announce the channel if it's not yet ready to go away (pending
+       * messages) */
+      if (really_destroyed)
+        {
+          g_hash_table_remove (self->priv->channels,
+              GUINT_TO_POINTER (handle));
+        }
+      else
+        {
+          tp_channel_manager_emit_new_channel (self,
+              TP_EXPORTABLE_CHANNEL (chan), NULL);
+        }
+    }
+}
+
+static ExampleEchoChannel *
+new_channel (ExampleEchoFactory *self,
+             TpHandle handle,
+             TpHandle initiator,
+             gpointer request_token)
+{
+  ExampleEchoChannel *chan;
+  gchar *object_path;
+  GSList *requests = NULL;
+
+  object_path = g_strdup_printf ("%s/EchoChannel%u",
+      self->priv->conn->object_path, handle);
+
+  chan = g_object_new (EXAMPLE_TYPE_ECHO_CHANNEL,
+      "connection", self->priv->conn,
+      "object-path", object_path,
+      "handle", handle,
+      "initiator-handle", initiator,
+      NULL);
+
+  g_free (object_path);
+
+  g_signal_connect (chan, "closed", (GCallback) channel_closed_cb, self);
+
+  g_hash_table_insert (self->priv->channels, GUINT_TO_POINTER (handle), chan);
+
+  if (request_token != NULL)
+    requests = g_slist_prepend (requests, request_token);
+
+  tp_channel_manager_emit_new_channel (self, TP_EXPORTABLE_CHANNEL (chan),
+      requests);
+  g_slist_free (requests);
+
+  return chan;
+}
+
+static const gchar * const fixed_properties[] = {
+    TP_IFACE_CHANNEL ".ChannelType",
+    TP_IFACE_CHANNEL ".TargetHandleType",
+    NULL
+};
+
+static const gchar * const allowed_properties[] = {
+    TP_IFACE_CHANNEL ".TargetHandle",
+    TP_IFACE_CHANNEL ".TargetID",
+    NULL
+};
+
+static void
+example_echo_factory_foreach_channel_class (TpChannelManager *manager,
+    TpChannelManagerChannelClassFunc func,
+    gpointer user_data)
+{
+    GHashTable *table = g_hash_table_new_full (g_str_hash, g_str_equal,
+        NULL, (GDestroyNotify) tp_g_value_slice_free);
+    GValue *value;
+
+    value = tp_g_value_slice_new (G_TYPE_STRING);
+    g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_TEXT);
+    g_hash_table_insert (table, TP_IFACE_CHANNEL ".ChannelType", value);
+
+    value = tp_g_value_slice_new (G_TYPE_UINT);
+    g_value_set_uint (value, TP_HANDLE_TYPE_CONTACT);
+    g_hash_table_insert (table, TP_IFACE_CHANNEL ".TargetHandleType", value);
+
+    func (manager, table, allowed_properties, user_data);
+
+    g_hash_table_destroy (table);
+}
+
+static gboolean
+example_echo_factory_request (ExampleEchoFactory *self,
+                              gpointer request_token,
+                              GHashTable *request_properties,
+                              gboolean require_new)
+{
+  TpHandle handle;
+  ExampleEchoChannel *chan;
+  GError *error = NULL;
+
+  if (tp_strdiff (tp_asv_get_string (request_properties,
+          TP_IFACE_CHANNEL ".ChannelType"),
+      TP_IFACE_CHANNEL_TYPE_TEXT))
+    {
+      return FALSE;
+    }
+
+  if (tp_asv_get_uint32 (request_properties,
+      TP_IFACE_CHANNEL ".TargetHandleType", NULL) != TP_HANDLE_TYPE_CONTACT)
+    {
+      return FALSE;
+    }
+
+  handle = tp_asv_get_uint32 (request_properties,
+      TP_IFACE_CHANNEL ".TargetHandle", NULL);
+  g_assert (handle != 0);
+
+  if (tp_channel_manager_asv_has_unknown_properties (request_properties,
+        fixed_properties, allowed_properties, &error))
+    {
+      goto error;
+    }
+
+  chan = g_hash_table_lookup (self->priv->channels, GUINT_TO_POINTER (handle));
+
+  if (chan == NULL)
+    {
+      chan = new_channel (self, handle, self->priv->conn->self_handle,
+          request_token);
+    }
+  else if (require_new)
+    {
+      g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+          "An echo channel to contact #%u already exists", handle);
+      goto error;
+    }
+  else
+    {
+      tp_channel_manager_emit_request_already_satisfied (self,
+          request_token, TP_EXPORTABLE_CHANNEL (chan));
+    }
+
+  return TRUE;
+
+error:
+  tp_channel_manager_emit_request_failed (self, request_token,
+      error->domain, error->code, error->message);
+  g_error_free (error);
+  return TRUE;
+}
+
+static gboolean
+example_echo_factory_create_channel (TpChannelManager *manager,
+                                     gpointer request_token,
+                                     GHashTable *request_properties)
+{
+    return example_echo_factory_request (EXAMPLE_ECHO_FACTORY (manager),
+        request_token, request_properties, TRUE);
+}
+
+static gboolean
+example_echo_factory_ensure_channel (TpChannelManager *manager,
+                                     gpointer request_token,
+                                     GHashTable *request_properties)
+{
+    return example_echo_factory_request (EXAMPLE_ECHO_FACTORY (manager),
+        request_token, request_properties, FALSE);
+}
+
+static void
+channel_manager_iface_init (gpointer g_iface,
+                            gpointer iface_data G_GNUC_UNUSED)
+{
+  TpChannelManagerIface *iface = g_iface;
+
+  iface->foreach_channel = example_echo_factory_foreach_channel;
+  iface->foreach_channel_class = example_echo_factory_foreach_channel_class;
+  iface->create_channel = example_echo_factory_create_channel;
+  iface->ensure_channel = example_echo_factory_ensure_channel;
+  /* In this channel manager, Request has the same semantics as Ensure */
+  iface->request_channel = example_echo_factory_ensure_channel;
+}
diff --git a/examples/cm/echo/im-manager.h b/examples/cm/echo/im-manager.h
new file mode 100644
index 0000000..4b74cb2
--- /dev/null
+++ b/examples/cm/echo/im-manager.h
@@ -0,0 +1,55 @@
+/*
+ * factory.h - header for an example channel factory
+ *
+ * Copyright (C) 2007 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef __EXAMPLE_FACTORY_H__
+#define __EXAMPLE_FACTORY_H__
+
+#include <glib-object.h>
+#include <telepathy-glib/channel-factory-iface.h>
+
+G_BEGIN_DECLS
+
+typedef struct _ExampleEchoFactory ExampleEchoFactory;
+typedef struct _ExampleEchoFactoryClass ExampleEchoFactoryClass;
+typedef struct _ExampleEchoFactoryPrivate ExampleEchoFactoryPrivate;
+
+struct _ExampleEchoFactoryClass {
+    GObjectClass parent_class;
+};
+
+struct _ExampleEchoFactory {
+    GObject parent;
+
+    ExampleEchoFactoryPrivate *priv;
+};
+
+GType example_echo_factory_get_type (void);
+
+/* TYPE MACROS */
+#define EXAMPLE_TYPE_ECHO_FACTORY \
+  (example_echo_factory_get_type ())
+#define EXAMPLE_ECHO_FACTORY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), EXAMPLE_TYPE_ECHO_FACTORY, \
+                              ExampleEchoFactory))
+#define EXAMPLE_ECHO_FACTORY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), EXAMPLE_TYPE_ECHO_FACTORY, \
+                           ExampleEchoFactoryClass))
+#define EXAMPLE_IS_ECHO_FACTORY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), EXAMPLE_TYPE_ECHO_FACTORY))
+#define EXAMPLE_IS_ECHO_FACTORY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), EXAMPLE_TYPE_ECHO_FACTORY))
+#define EXAMPLE_ECHO_FACTORY_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), EXAMPLE_TYPE_ECHO_FACTORY, \
+                              ExampleEchoFactoryClass))
+
+G_END_DECLS
+
+#endif /* #ifndef __EXAMPLE_FACTORY_H__ */
-- 
1.5.6.5




More information about the Telepathy-commits mailing list