summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDanielle Madeley <danielle.madeley@collabora.co.uk>2009-11-20 18:21:45 +1100
committerDanielle Madeley <danielle.madeley@collabora.co.uk>2009-11-20 18:21:45 +1100
commit5f823fdbe336f201a27dbc2ed40be58997335e08 (patch)
treea142074b7c00501862b1a48fcc282c160eff90aa
parente65f531d4fd825402c2e6382900e89b95d152e53 (diff)
A D-Bus Tube Example in C
-rw-r--r--configure.ac1
-rw-r--r--docs/examples/Makefile.am1
-rw-r--r--docs/examples/glib_mc5_dbus_tube_handler/Makefile.am10
-rw-r--r--docs/examples/glib_mc5_dbus_tube_handler/example-handler.c365
-rw-r--r--docs/examples/glib_mc5_dbus_tube_handler/example-handler.h35
-rw-r--r--docs/examples/glib_mc5_dbus_tube_handler/example.c41
6 files changed, 453 insertions, 0 deletions
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);
+}