summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2010-01-11 20:37:51 +0000
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2010-01-11 20:37:51 +0000
commit0e4b405ad5393afa134ff867546f0a227e18f6fa (patch)
treee3e0bb6096b072ec24a6e0ae05b69b243523695f /plugins
parent092af3fb811d6b6d010903835a2c63102ca35543 (diff)
plugins: add a gateway-registration plugin
Diffstat (limited to 'plugins')
-rw-r--r--plugins/Makefile.am11
-rw-r--r--plugins/gateways.c345
-rw-r--r--plugins/gateways.h85
3 files changed, 441 insertions, 0 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 4301e126..041f3d1d 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -1,5 +1,10 @@
plugindir = $(libdir)/telepathy/gabble-0
+# installable plugins
+plugin_LTLIBRARIES = \
+ gateways.la
+
+# testing-only plugins
noinst_LTLIBRARIES = \
test.la
@@ -9,6 +14,12 @@ test_la_SOURCES = \
test_la_LDFLAGS = -module -avoid-version -rpath $(plugindir) -lm
+gateways_la_SOURCES = \
+ gateways.c \
+ gateways.h
+
+gateways_la_LDFLAGS = -module -avoid-version
+
AM_CFLAGS = $(ERROR_CFLAGS) @DBUS_CFLAGS@ @GLIB_CFLAGS@ @WOCKY_CFLAGS@ \
@TP_GLIB_CFLAGS@ \
-I $(top_gabbledir)/gabble -I $(top_builddir)/gabble \
diff --git a/plugins/gateways.c b/plugins/gateways.c
new file mode 100644
index 00000000..2ba11161
--- /dev/null
+++ b/plugins/gateways.c
@@ -0,0 +1,345 @@
+/* Gateway registration plugin
+ *
+ * Copyright © 2010 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * 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 "gateways.h"
+
+#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/util.h>
+#include <telepathy-glib/errors.h>
+
+#include <wocky/wocky-namespaces.h>
+#include <wocky/wocky-xmpp-error.h>
+
+#include "extensions/extensions.h"
+
+#include <gabble/gabble.h>
+
+/*************************
+ * Plugin implementation *
+ *************************/
+
+static void plugin_iface_init (
+ gpointer g_iface,
+ gpointer data);
+
+static const gchar * const sidecar_interfaces[] = {
+ GABBLE_IFACE_GABBLE_PLUGIN_GATEWAYS,
+ NULL
+};
+
+G_DEFINE_TYPE_WITH_CODE (GabbleGatewayPlugin, gabble_gateway_plugin,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GABBLE_TYPE_PLUGIN, plugin_iface_init);
+ )
+
+static void
+gabble_gateway_plugin_init (GabbleGatewayPlugin *self)
+{
+}
+
+static void
+gabble_gateway_plugin_class_init (GabbleGatewayPluginClass *klass)
+{
+}
+
+static void
+gabble_gateway_plugin_create_sidecar (
+ GabblePlugin *plugin,
+ const gchar *sidecar_interface,
+ TpBaseConnection *connection,
+ WockySession *session,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result = g_simple_async_result_new (G_OBJECT (plugin),
+ callback, user_data,
+ /* sic: all plugins share gabble_plugin_create_sidecar_finish() so we
+ * need to use the same source tag.
+ */
+ gabble_plugin_create_sidecar);
+ GabbleSidecar *sidecar = NULL;
+
+ if (!tp_strdiff (sidecar_interface, GABBLE_IFACE_GABBLE_PLUGIN_GATEWAYS))
+ {
+ sidecar = g_object_new (GABBLE_TYPE_GATEWAY_SIDECAR,
+ "connection", connection,
+ "session", session,
+ NULL);
+ }
+ else
+ {
+ g_simple_async_result_set_error (result, TP_ERRORS,
+ TP_ERROR_NOT_IMPLEMENTED, "'%s' not implemented", sidecar_interface);
+ }
+
+ if (sidecar != NULL)
+ g_simple_async_result_set_op_res_gpointer (result, sidecar,
+ g_object_unref);
+
+ g_simple_async_result_complete_in_idle (result);
+ g_object_unref (result);
+}
+
+static void
+plugin_iface_init (
+ gpointer g_iface,
+ gpointer data G_GNUC_UNUSED)
+{
+ GabblePluginInterface *iface = g_iface;
+
+ iface->name = "Gateway registration plugin";
+ iface->sidecar_interfaces = sidecar_interfaces;
+ iface->create_sidecar = gabble_gateway_plugin_create_sidecar;
+}
+
+GabblePlugin *
+gabble_plugin_create ()
+{
+ return g_object_new (GABBLE_TYPE_GATEWAY_PLUGIN,
+ NULL);
+}
+
+/**************************
+ * Sidecar implementation *
+ **************************/
+
+enum {
+ PROP_0,
+ PROP_CONNECTION,
+ PROP_SESSION
+};
+
+struct _GabbleGatewaySidecarPrivate
+{
+ WockySession *session;
+ TpBaseConnection *connection;
+};
+
+static void sidecar_iface_init (
+ gpointer g_iface,
+ gpointer data);
+
+static void gateway_iface_init (
+ gpointer g_iface,
+ gpointer data);
+
+G_DEFINE_TYPE_WITH_CODE (GabbleGatewaySidecar, gabble_gateway_sidecar,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GABBLE_TYPE_SIDECAR, sidecar_iface_init);
+ G_IMPLEMENT_INTERFACE (GABBLE_TYPE_SVC_GABBLE_PLUGIN_GATEWAYS,
+ gateway_iface_init);
+ )
+
+static void
+gabble_gateway_sidecar_init (GabbleGatewaySidecar *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GABBLE_TYPE_GATEWAY_SIDECAR,
+ GabbleGatewaySidecarPrivate);
+}
+
+static void
+gabble_gateway_sidecar_set_property (
+ GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GabbleGatewaySidecar *self = GABBLE_GATEWAY_SIDECAR (object);
+
+ switch (property_id)
+ {
+ case PROP_CONNECTION:
+ g_assert (self->priv->connection == NULL); /* construct-only */
+ self->priv->connection = g_value_dup_object (value);
+ break;
+
+ case PROP_SESSION:
+ g_assert (self->priv->session == NULL); /* construct-only */
+ self->priv->session = g_value_dup_object (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ }
+}
+
+static void
+gabble_gateway_sidecar_dispose (GObject *object)
+{
+ GabbleGatewaySidecar *self = GABBLE_GATEWAY_SIDECAR (object);
+
+ if (self->priv->connection != NULL)
+ {
+ g_object_unref (self->priv->connection);
+ self->priv->connection = NULL;
+ }
+
+ if (self->priv->session != NULL)
+ {
+ g_object_unref (self->priv->session);
+ self->priv->session = NULL;
+ }
+}
+
+static void
+gabble_gateway_sidecar_class_init (GabbleGatewaySidecarClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->set_property = gabble_gateway_sidecar_set_property;
+ object_class->dispose = gabble_gateway_sidecar_dispose;
+
+ g_type_class_add_private (klass, sizeof (GabbleGatewaySidecarPrivate));
+
+ g_object_class_install_property (object_class, PROP_CONNECTION,
+ g_param_spec_object ("connection", "Connection",
+ "Telepathy connection",
+ TP_TYPE_BASE_CONNECTION,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class, PROP_SESSION,
+ g_param_spec_object ("session", "Session",
+ "Wocky session",
+ WOCKY_TYPE_SESSION,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+}
+
+static void sidecar_iface_init (
+ gpointer g_iface,
+ gpointer data)
+{
+ GabbleSidecarInterface *iface = g_iface;
+
+ iface->interface = GABBLE_IFACE_GABBLE_PLUGIN_GATEWAYS;
+ iface->get_immutable_properties = NULL;
+}
+
+static void
+register_cb (GObject *porter,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ DBusGMethodInvocation *context = user_data;
+ WockyXmppStanza *reply;
+ GError *error = NULL;
+
+ reply = wocky_porter_send_iq_finish (WOCKY_PORTER (porter), result, &error);
+
+ if (reply == NULL)
+ goto finally;
+
+ error = wocky_xmpp_stanza_to_gerror (reply); /* NULL on success */
+ g_object_unref (reply);
+
+finally:
+ if (error == NULL)
+ {
+ gabble_svc_gabble_plugin_gateways_return_from_register (context);
+ }
+ else
+ {
+ GError *tp_error = NULL;
+
+ /* specific error cases for registration: 'conflict' and
+ * 'not-acceptable' are documented */
+ if (error->domain == WOCKY_XMPP_ERROR)
+ {
+ switch (error->code)
+ {
+ case WOCKY_XMPP_ERROR_CONFLICT:
+ g_set_error (&tp_error, TP_ERRORS, TP_ERROR_REGISTRATION_EXISTS,
+ "someone else registered that username: %s", error->message);
+ break;
+
+ case WOCKY_XMPP_ERROR_NOT_ACCEPTABLE:
+ g_set_error (&tp_error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+ "registration not acceptable: %s", error->message);
+ break;
+
+ default:
+ gabble_set_tp_error_from_wocky (error, &tp_error);
+ break;
+ }
+ }
+
+ dbus_g_method_return_error (context, tp_error);
+ g_error_free (error);
+ g_error_free (tp_error);
+ }
+}
+
+static void
+gateways_register (
+ GabbleSvcGabblePluginGateways *sidecar,
+ const gchar *gateway,
+ const gchar *username,
+ const gchar *password,
+ DBusGMethodInvocation *context)
+{
+ GabbleGatewaySidecar *self = GABBLE_GATEWAY_SIDECAR (sidecar);
+ WockyPorter *porter = wocky_session_get_porter (self->priv->session);
+ WockyXmppStanza *stanza;
+
+ /* This is a *really* minimal implementation. We're meant to ask the gateway
+ * what parameters it supports (a XEP-0077 pseudo-form or a XEP-0004 data
+ * form), then fill in the blanks to actually make a request.
+ *
+ * However, because we're hard-coded to take only a username and a password,
+ * we might as well just fire off a request with those in and see if it
+ * works. If it doesn't, then we couldn't have registered anyway...
+ *
+ * A more general API for service registration could look like this:
+ *
+ * method Plugin.GetService() -> o, a{s(*)} [where * is some
+ * representation of the type of the parameter]
+ * property Service.Parameters: readable a{s(*)} [likewise]
+ * property Service.Registered: readable b
+ * method Service.Register(a{sv})
+ * method Service.Unregister()
+ * method Service.Release() [distributed refcounting]
+ */
+
+ stanza = wocky_xmpp_stanza_build (WOCKY_STANZA_TYPE_IQ,
+ WOCKY_STANZA_SUB_TYPE_SET,
+ NULL, gateway,
+ WOCKY_NODE, "query", WOCKY_NODE_XMLNS, WOCKY_XEP77_NS_REGISTER,
+ WOCKY_NODE, "username",
+ WOCKY_NODE_TEXT, username,
+ WOCKY_NODE_END,
+ WOCKY_NODE, "password",
+ WOCKY_NODE_TEXT, password,
+ WOCKY_NODE_END,
+ WOCKY_NODE_END,
+ WOCKY_STANZA_END);
+
+ wocky_porter_send_iq_async (porter, stanza, NULL, register_cb, context);
+
+ g_object_unref (stanza);
+}
+
+static void
+gateway_iface_init (
+ gpointer klass,
+ gpointer data G_GNUC_UNUSED)
+{
+#define IMPLEMENT(x) gabble_svc_gabble_plugin_gateways_implement_##x (\
+ klass, gateways_##x)
+ IMPLEMENT (register);
+#undef IMPLEMENT
+}
diff --git a/plugins/gateways.h b/plugins/gateways.h
new file mode 100644
index 00000000..766fa4be
--- /dev/null
+++ b/plugins/gateways.h
@@ -0,0 +1,85 @@
+/* Gateway registration plugin
+ *
+ * Copyright © 2010 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * 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 <glib-object.h>
+
+#include <gio/gio.h>
+#include <wocky/wocky-session.h>
+
+typedef struct _GabbleGatewayPlugin GabbleGatewayPlugin;
+typedef struct _GabbleGatewayPluginClass GabbleGatewayPluginClass;
+typedef struct _GabbleGatewayPluginPrivate GabbleGatewayPluginPrivate;
+
+struct _GabbleGatewayPlugin {
+ GObject parent;
+ GabbleGatewayPluginPrivate *priv;
+};
+
+struct _GabbleGatewayPluginClass {
+ GObjectClass parent;
+};
+
+GType gabble_gateway_plugin_get_type (void);
+
+#define GABBLE_TYPE_GATEWAY_PLUGIN \
+ (gabble_gateway_plugin_get_type ())
+#define GABBLE_GATEWAY_PLUGIN(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), GABBLE_TYPE_GATEWAY_PLUGIN, \
+ GabbleGatewayPlugin))
+#define GABBLE_GATEWAY_PLUGIN_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), GABBLE_TYPE_GATEWAY_PLUGIN, \
+ GabbleGatewayPluginClass))
+#define GABBLE_IS_GATEWAY_PLUGIN(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GABBLE_TYPE_GATEWAY_PLUGIN))
+#define GABBLE_IS_GATEWAY_PLUGIN_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), GABBLE_TYPE_GATEWAY_PLUGIN))
+#define GABBLE_GATEWAY_PLUGIN_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_GATEWAY_PLUGIN, \
+ GabbleGatewayPluginClass))
+
+typedef struct _GabbleGatewaySidecar GabbleGatewaySidecar;
+typedef struct _GabbleGatewaySidecarClass GabbleGatewaySidecarClass;
+typedef struct _GabbleGatewaySidecarPrivate GabbleGatewaySidecarPrivate;
+
+struct _GabbleGatewaySidecar {
+ GObject parent;
+ GabbleGatewaySidecarPrivate *priv;
+};
+
+struct _GabbleGatewaySidecarClass {
+ GObjectClass parent;
+};
+
+GType gabble_gateway_sidecar_get_type (void);
+
+#define GABBLE_TYPE_GATEWAY_SIDECAR \
+ (gabble_gateway_sidecar_get_type ())
+#define GABBLE_GATEWAY_SIDECAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), GABBLE_TYPE_GATEWAY_SIDECAR, \
+ GabbleGatewaySidecar))
+#define GABBLE_GATEWAY_SIDECAR_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), GABBLE_TYPE_GATEWAY_SIDECAR, \
+ GabbleGatewaySidecarClass))
+#define GABBLE_IS_GATEWAY_SIDECAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GABBLE_TYPE_GATEWAY_SIDECAR))
+#define GABBLE_IS_GATEWAY_SIDECAR_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), GABBLE_TYPE_GATEWAY_SIDECAR))
+#define GABBLE_GATEWAY_SIDECAR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_GATEWAY_SIDECAR, \
+ GabbleGatewaySidecarClass))