[telepathy-doc/master] A D-Bus Tube Example in C

Danielle Madeley danielle.madeley at collabora.co.uk
Thu Nov 19 23:21:45 PST 2009


---
 configure.ac                                       |    1 +
 docs/examples/Makefile.am                          |    1 +
 .../glib_mc5_dbus_tube_handler/Makefile.am         |   10 +
 .../glib_mc5_dbus_tube_handler/example-handler.c   |  365 ++++++++++++++++++++
 .../glib_mc5_dbus_tube_handler/example-handler.h   |   35 ++
 docs/examples/glib_mc5_dbus_tube_handler/example.c |   41 +++
 6 files changed, 453 insertions(+), 0 deletions(-)
 create mode 100644 docs/examples/glib_mc5_dbus_tube_handler/Makefile.am
 create mode 100644 docs/examples/glib_mc5_dbus_tube_handler/example-handler.c
 create mode 100644 docs/examples/glib_mc5_dbus_tube_handler/example-handler.h
 create mode 100644 docs/examples/glib_mc5_dbus_tube_handler/example.c

diff --git a/configure.ac b/configure.ac
index d50c8b7..dcd5575 100644
--- a/configure.ac
+++ b/configure.ac
@@ -36,6 +36,7 @@ AC_OUTPUT([
       docs/examples/glib_dbus_tube/Makefile
       docs/examples/glib_stream_tube/Makefile
       docs/examples/glib_mc5_connections/Makefile
+      docs/examples/glib_mc5_dbus_tube_handler/Makefile
       docs/examples/glib_mc5_observer/Makefile
       docs/examples/glib_mc5_ft_handler/Makefile
       docs/examples/gtk_presence_app/Makefile
diff --git a/docs/examples/Makefile.am b/docs/examples/Makefile.am
index cd1af68..7b09e8d 100644
--- a/docs/examples/Makefile.am
+++ b/docs/examples/Makefile.am
@@ -8,6 +8,7 @@ example_dirs = \
 	glib_dbus_tube \
 	glib_stream_tube \
 	glib_mc5_connections \
+	glib_mc5_dbus_tube_handler \
 	glib_mc5_observer \
 	glib_mc5_ft_handler \
 	gtk_presence_app \
diff --git a/docs/examples/glib_mc5_dbus_tube_handler/Makefile.am b/docs/examples/glib_mc5_dbus_tube_handler/Makefile.am
new file mode 100644
index 0000000..e3b381c
--- /dev/null
+++ b/docs/examples/glib_mc5_dbus_tube_handler/Makefile.am
@@ -0,0 +1,10 @@
+INCLUDES = $(TELEPATHY_GLIB_CFLAGS)
+LDADD = $(TELEPATHY_GLIB_LIBS)
+
+noinst_PROGRAMS = example
+
+example_SOURCES = \
+	example-handler.c example-handler.h \
+	example.c
+
+include $(top_srcdir)/docs/rsync-dist.make
diff --git a/docs/examples/glib_mc5_dbus_tube_handler/example-handler.c b/docs/examples/glib_mc5_dbus_tube_handler/example-handler.c
new file mode 100644
index 0000000..2ad0ef1
--- /dev/null
+++ b/docs/examples/glib_mc5_dbus_tube_handler/example-handler.c
@@ -0,0 +1,365 @@
+#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/interfaces.h>
+#include <telepathy-glib/gtypes.h>
+#include <telepathy-glib/enums.h>
+#include <telepathy-glib/channel.h>
+#include <telepathy-glib/connection.h>
+#include <telepathy-glib/svc-generic.h>
+#include <telepathy-glib/svc-client.h>
+#include <telepathy-glib/util.h>
+
+#include "example-handler.h"
+
+#define SERVICE_NAME "org.freedesktop.Telepathy.Examples.TubeClient"
+
+static void client_iface_init (gpointer, gpointer);
+static void observer_iface_init (gpointer, gpointer);
+
+#define GET_PRIVATE(obj)	(G_TYPE_INSTANCE_GET_PRIVATE ((obj), TYPE_EXAMPLE_HANDLER, ExampleHandlerPrivate))
+
+G_DEFINE_TYPE_WITH_CODE (ExampleHandler, example_handler, G_TYPE_OBJECT,
+    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES,
+      tp_dbus_properties_mixin_iface_init);
+    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CLIENT, NULL);
+    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CLIENT_HANDLER, observer_iface_init);
+    );
+
+static const char *client_interfaces[] = {
+    TP_IFACE_CLIENT_HANDLER,
+    NULL
+};
+
+enum
+{
+  PROP_0,
+  PROP_INTERFACES,
+  PROP_CHANNEL_FILTER,
+  PROP_BYPASS_APPROVAL,
+  PROP_HANDLED_CHANNELS
+};
+
+typedef struct _ExampleHandlerPrivate ExampleHandlerPrivate;
+struct _ExampleHandlerPrivate
+{
+  TpTubeState state;
+  char *address;
+};
+
+static void
+open_tube (ExampleHandler *self)
+{
+  ExampleHandlerPrivate *priv = GET_PRIVATE (self);
+
+  /* we can't be sure what order we will get our address and the open status
+   * so check here that we have both */
+  if (priv->state != TP_TUBE_STATE_OPEN || priv->address == NULL)
+    {
+      return;
+    }
+
+  g_print ("Ready to connect to D-Bus address = %s\n", priv->address);
+
+  /* make a connection to the named D-Bus bus here.
+   * Each member of the MUC is assigned a well-known address by the Connection
+   * Manager, track the DBusNamesChanged signal to find out when users appear
+   * or disappear on the bus. You can publish objects under this unique
+   * address or make method calls to someone elses objects. */
+}
+
+static void
+tube_state_changed_callback (TpChannel *channel,
+                             guint      state,
+                             gpointer   user_data,
+                             GObject   *weak_obj)
+{
+  ExampleHandler *self = EXAMPLE_HANDLER (weak_obj);
+  ExampleHandlerPrivate *priv = GET_PRIVATE (self);
+
+  priv->state = state;
+
+  open_tube (self);
+}
+
+static void
+dbus_names_changed_callback (TpChannel    *channel,
+                             GHashTable   *added,
+                             const GArray *removed,
+                             gpointer      user_data,
+                             GObject      *weak_obj)
+{
+  ExampleHandler *self = EXAMPLE_HANDLER (weak_obj);
+  ExampleHandlerPrivate *priv = GET_PRIVATE (self);
+
+  /* the mapping between Handles and the unique D-Bus addresses of other users
+   * has been updated because people have joined or left the MUC */
+
+  g_print ("DBus names changed\n");
+}
+
+static void
+tube_accept_callback (TpChannel    *channel,
+                      const char   *address,
+                      const GError *in_error,
+                      gpointer      user_data,
+                      GObject      *weak_obj)
+{
+  ExampleHandler *self = EXAMPLE_HANDLER (weak_obj);
+  ExampleHandlerPrivate *priv = GET_PRIVATE (self);
+
+  if (in_error != NULL)
+    {
+      g_error ("%s", in_error->message);
+    }
+
+  priv->address = g_strdup (address);
+
+  open_tube (self);
+}
+
+static void
+tube_channel_ready (TpChannel    *channel,
+                    const GError *in_error,
+                    gpointer      user_data)
+{
+  ExampleHandler *self = EXAMPLE_HANDLER (user_data);
+
+  if (in_error != NULL)
+    {
+      g_error ("%s", in_error->message);
+    }
+
+  GError *error = NULL;
+
+  g_print ("Channel ready\n");
+
+  tp_cli_channel_interface_tube_connect_to_tube_channel_state_changed (
+      channel, tube_state_changed_callback,
+      NULL, NULL, G_OBJECT (self), &error);
+  if (error != NULL)
+    {
+      g_error ("%s", error->message);
+    }
+  tp_cli_channel_type_dbus_tube_connect_to_dbus_names_changed (
+      channel, dbus_names_changed_callback,
+      NULL, NULL, G_OBJECT (self), &error);
+  if (error != NULL)
+    {
+      g_error ("%s", error->message);
+    }
+
+  tp_cli_channel_type_dbus_tube_call_accept (channel, -1,
+      TP_SOCKET_ACCESS_CONTROL_LOCALHOST, tube_accept_callback,
+      NULL, NULL, G_OBJECT (self));
+}
+
+static void
+example_handler_handle_channels (TpSvcClientHandler   *self,
+                                 const char            *account,
+                                 const char            *connection,
+                                 const GPtrArray       *channels,
+                                 const GPtrArray       *requests_satisfied,
+                                 guint64                user_action_time,
+                                 GHashTable            *handler_info,
+                                 DBusGMethodInvocation *context)
+{
+  GError *error = NULL;
+
+  TpDBusDaemon *bus = tp_dbus_daemon_dup (&error);
+  if (error != NULL)
+    {
+      g_error ("%s", error->message);
+    }
+
+  TpConnection *conn = tp_connection_new (bus, NULL, connection, &error);
+  if (error != NULL)
+    {
+      g_error ("%s", error->message);
+    }
+
+  /* channels is of type a(oa{sv}) */
+  int i;
+  for (i = 0; i < channels->len; i++)
+    {
+      GValueArray *channel = g_ptr_array_index (channels, i);
+
+      char *path = g_value_get_boxed (g_value_array_get_nth (channel, 0));
+      GHashTable *map = g_value_get_boxed (g_value_array_get_nth (channel, 1));
+
+      const char *type = tp_asv_get_string (map,
+          TP_IFACE_CHANNEL ".ChannelType");
+      const char *service = tp_asv_get_string (map,
+          TP_IFACE_CHANNEL_TYPE_DBUS_TUBE ".ServiceName");
+
+      if (tp_strdiff (type, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE) ||
+          tp_strdiff (service, SERVICE_NAME))
+        {
+          continue;
+        }
+
+      g_print ("Got tube channel: %s\n", path);
+
+      TpChannel *chan = tp_channel_new_from_properties (conn, path, map,
+          &error);
+      if (error != NULL)
+        {
+          g_error ("%s", error->message);
+        }
+      tp_channel_call_when_ready (chan, tube_channel_ready, self);
+    }
+
+  g_object_unref (conn);
+  g_object_unref (bus);
+
+  tp_svc_client_handler_return_from_handle_channels (context);
+}
+
+static void
+example_handler_get_property (GObject    *self,
+                               guint       property_id,
+                               GValue     *value,
+                               GParamSpec *pspec)
+{
+  switch (property_id)
+    {
+      case PROP_INTERFACES:
+        g_print (" :: interfaces\n");
+        g_value_set_boxed (value, client_interfaces);
+        break;
+
+      case PROP_CHANNEL_FILTER:
+        g_print (" :: channel-filter\n");
+
+        /* this is the same map as the Python handler example */
+        GPtrArray *array = g_ptr_array_new ();
+        GHashTable *map = tp_asv_new (
+              TP_IFACE_CHANNEL ".ChannelType", G_TYPE_STRING,
+                  TP_IFACE_CHANNEL_TYPE_DBUS_TUBE,
+              TP_IFACE_CHANNEL ".TargetHandleType", G_TYPE_UINT,
+                  TP_HANDLE_TYPE_ROOM,
+              TP_IFACE_CHANNEL ".Requested", G_TYPE_BOOLEAN,
+                  FALSE,
+              TP_IFACE_CHANNEL_TYPE_DBUS_TUBE ".ServiceName", G_TYPE_STRING,
+                  SERVICE_NAME,
+              NULL
+            );
+
+        g_ptr_array_add (array, map);
+        g_value_take_boxed (value, array);
+        break;
+
+      case PROP_BYPASS_APPROVAL:
+        g_print (" :: bypass-approval\n");
+        g_value_set_boolean (value, FALSE);
+        break;
+
+      case PROP_HANDLED_CHANNELS:
+        g_print (" :: handled-channels\n");
+
+          {
+            GPtrArray *array = g_ptr_array_new ();
+            g_value_take_boxed (value, array);
+          }
+
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (self, property_id, pspec);
+        break;
+    }
+}
+
+static void
+example_handler_class_init (ExampleHandlerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->get_property = example_handler_get_property;
+
+  /* D-Bus properties are exposed as GObject properties through the
+   * TpDBusPropertiesMixin */
+  /* properties on the Client interface */
+  static TpDBusPropertiesMixinPropImpl client_props[] = {
+        { "Interfaces", "interfaces", NULL },
+        { NULL }
+  };
+
+  /* properties on the Client.Handler interface */
+  static TpDBusPropertiesMixinPropImpl client_handler_props[] = {
+        { "HandlerChannelFilter", "channel-filter", NULL },
+        { "BypassApproval", "bypass-approval", NULL },
+        { "HandledChannels", "handled-channels", NULL },
+        { NULL }
+  };
+
+  /* complete list of interfaces with properties */
+  static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
+        { TP_IFACE_CLIENT,
+          tp_dbus_properties_mixin_getter_gobject_properties,
+          NULL,
+          client_props
+        },
+        { TP_IFACE_CLIENT_HANDLER,
+          tp_dbus_properties_mixin_getter_gobject_properties,
+          NULL,
+          client_handler_props
+        },
+        { NULL }
+  };
+
+  g_object_class_install_property (object_class, PROP_INTERFACES,
+      g_param_spec_boxed ("interfaces",
+                          "Interfaces",
+                          "Available D-Bus Interfaces",
+                          G_TYPE_STRV,
+                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (object_class, PROP_CHANNEL_FILTER,
+      g_param_spec_boxed ("channel-filter",
+                          "Channel Filter",
+                          "Filter for channels we observe",
+                          TP_ARRAY_TYPE_CHANNEL_CLASS_LIST,
+                          G_PARAM_READABLE));
+
+  g_object_class_install_property (object_class, PROP_BYPASS_APPROVAL,
+      g_param_spec_boolean ("bypass-approval",
+                            "Bypass Approval",
+                            "Whether or not this Client should bypass approval",
+                            FALSE,
+                            G_PARAM_READABLE));
+
+  g_object_class_install_property (object_class, PROP_HANDLED_CHANNELS,
+      g_param_spec_boxed ("handled-channels",
+                          "Handled Channels",
+                          "List of channels we're handling",
+                          TP_ARRAY_TYPE_OBJECT_PATH_LIST,
+                          G_PARAM_READABLE));
+
+  /* call our mixin class init */
+  klass->dbus_props_class.interfaces = prop_interfaces;
+  tp_dbus_properties_mixin_class_init (object_class,
+      G_STRUCT_OFFSET (ExampleHandlerClass, dbus_props_class));
+
+  g_type_class_add_private (klass, sizeof (ExampleHandlerPrivate));
+}
+
+static void
+example_handler_init (ExampleHandler *self)
+{
+}
+
+static void
+observer_iface_init (gpointer g_iface, gpointer iface_data)
+{
+  TpSvcClientHandlerClass *klass = (TpSvcClientHandlerClass *) g_iface;
+
+#define IMPLEMENT(x) tp_svc_client_handler_implement_##x (klass, \
+    example_handler_##x)
+  IMPLEMENT (handle_channels);
+#undef IMPLEMENT
+}
+
+ExampleHandler *
+example_handler_new (void)
+{
+  return g_object_new (TYPE_EXAMPLE_HANDLER, NULL);
+}
diff --git a/docs/examples/glib_mc5_dbus_tube_handler/example-handler.h b/docs/examples/glib_mc5_dbus_tube_handler/example-handler.h
new file mode 100644
index 0000000..b9149a2
--- /dev/null
+++ b/docs/examples/glib_mc5_dbus_tube_handler/example-handler.h
@@ -0,0 +1,35 @@
+#ifndef __EXAMPLE_HANDLER_H__
+#define __EXAMPLE_HANDLER_H__
+
+#include <glib-object.h>
+#include <telepathy-glib/dbus-properties-mixin.h>
+
+G_BEGIN_DECLS
+
+#define TYPE_EXAMPLE_HANDLER	(example_handler_get_type ())
+#define EXAMPLE_HANDLER(obj)	(G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_EXAMPLE_HANDLER, ExampleHandler))
+#define EXAMPLE_HANDLER_CLASS(obj)	(G_TYPE_CHECK_CLASS_CAST ((obj), TYPE_EXAMPLE_HANDLER, ExampleHandlerClass))
+#define IS_EXAMPLE_HANDLER(obj)	(G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_EXAMPLE_HANDLER))
+#define IS_EXAMPLE_HANDLER_CLASS(obj)	(G_TYPE_CHECK_CLASS_TYPE ((obj), TYPE_EXAMPLE_HANDLER))
+#define EXAMPLE_HANDLER_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_EXAMPLE_HANDLER, ExampleHandlerClass))
+
+typedef struct _ExampleHandler ExampleHandler;
+
+struct _ExampleHandler
+{
+	GObject parent;
+};
+
+typedef struct _ExampleHandlerClass ExampleHandlerClass;
+struct _ExampleHandlerClass
+{
+	GObjectClass parent_class;
+	TpDBusPropertiesMixinClass dbus_props_class;
+};
+
+GType example_handler_get_type (void);
+ExampleHandler *example_handler_new (void);
+
+G_END_DECLS
+
+#endif
diff --git a/docs/examples/glib_mc5_dbus_tube_handler/example.c b/docs/examples/glib_mc5_dbus_tube_handler/example.c
new file mode 100644
index 0000000..313afe4
--- /dev/null
+++ b/docs/examples/glib_mc5_dbus_tube_handler/example.c
@@ -0,0 +1,41 @@
+/*
+ * An example of talking to MC5 to get available connections
+ */
+
+#include <glib.h>
+#include <dbus/dbus-glib.h>
+
+#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/defs.h>
+
+#include "example-handler.h"
+
+#define CLIENT_NAME "ExampleHandler"
+
+static GMainLoop *loop = NULL;
+
+int
+main (int argc, char **argv)
+{
+  GError *error = NULL;
+
+  g_type_init ();
+
+  loop = g_main_loop_new (NULL, FALSE);
+
+  TpDBusDaemon *tpdbus = tp_dbus_daemon_dup (NULL);
+  DBusGConnection *dbus = tp_get_bus ();
+
+  ExampleHandler *example_handler = example_handler_new ();
+
+  /* register well-known name */
+  g_assert (tp_dbus_daemon_request_name (tpdbus,
+      TP_CLIENT_BUS_NAME_BASE CLIENT_NAME,
+      TRUE, NULL));
+  /* register ExampleObserver on the bus */
+  dbus_g_connection_register_g_object (dbus,
+      TP_CLIENT_OBJECT_PATH_BASE CLIENT_NAME,
+      G_OBJECT (example_handler));
+
+  g_main_loop_run (loop);
+}
-- 
1.5.6.5




More information about the telepathy-commits mailing list