diff options
author | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2013-10-14 15:35:26 +0100 |
---|---|---|
committer | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2013-10-14 15:35:26 +0100 |
commit | a8f8a94c917a97c40e8e43997b12290bc9264c09 (patch) | |
tree | 1a67d2c3334284c157703553d538352af3c3e416 /plugins | |
parent | 4b7a4f7b487064eca0754d9602505dae12d0033e (diff) | |
parent | 1108a8aa37c2fa4ef14ad9f5a198ac5f80f2d765 (diff) |
Merge remote-tracking branch 'wjt/xmpp-console'
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=66085
Reviewed-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
Conflicts:
plugins/console/channel.c
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/Makefile.am | 11 | ||||
-rw-r--r-- | plugins/console/channel-manager.c | 277 | ||||
-rw-r--r-- | plugins/console/channel-manager.h | 52 | ||||
-rw-r--r-- | plugins/console/channel.c (renamed from plugins/console.c) | 298 | ||||
-rw-r--r-- | plugins/console/channel.h | 53 | ||||
-rw-r--r-- | plugins/console/debug.c | 36 | ||||
-rw-r--r-- | plugins/console/debug.h | 28 | ||||
-rw-r--r-- | plugins/console/plugin.c | 91 | ||||
-rw-r--r-- | plugins/console/plugin.h (renamed from plugins/console.h) | 37 | ||||
-rwxr-xr-x | plugins/telepathy-gabble-xmpp-console | 163 |
10 files changed, 722 insertions, 324 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am index a51160472..2b0007901 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -62,8 +62,15 @@ libgateways_la_SOURCES = \ gateways.h libconsole_la_SOURCES = \ - console.c \ - console.h + console/channel-manager.c \ + console/channel-manager.h \ + console/channel.c \ + console/channel.h \ + console/debug.c \ + console/debug.h \ + console/plugin.c \ + console/plugin.h \ + $(NULL) AM_CFLAGS = $(ERROR_CFLAGS) \ -I $(top_srcdir) -I $(top_builddir) \ diff --git a/plugins/console/channel-manager.c b/plugins/console/channel-manager.c new file mode 100644 index 000000000..3d826db1c --- /dev/null +++ b/plugins/console/channel-manager.c @@ -0,0 +1,277 @@ +/* XML console plugin + * + * Copyright © 2011–2013 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 "config.h" +#include "console/channel-manager.h" + +#include "extensions/extensions.h" +#include "console/channel.h" + +static void channel_manager_iface_init (gpointer, gpointer); + +G_DEFINE_TYPE_WITH_CODE (GabbleConsoleChannelManager, gabble_console_channel_manager, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER, channel_manager_iface_init) + G_IMPLEMENT_INTERFACE (GABBLE_TYPE_CAPS_CHANNEL_MANAGER, NULL); + ) + +enum { + PROP_CONNECTION = 1, +}; + +static void connection_status_changed_cb ( + TpBaseConnection *conn, + guint status, + guint reason, + GabbleConsoleChannelManager *self); +static void gabble_console_channel_manager_close_all ( + GabbleConsoleChannelManager *self); + +static void +gabble_console_channel_manager_init (GabbleConsoleChannelManager *self) +{ + g_weak_ref_init (&self->plugin_connection_ref, NULL); +} + + +static void +gabble_console_channel_manager_constructed (GObject *object) +{ + GabbleConsoleChannelManager *self = GABBLE_CONSOLE_CHANNEL_MANAGER (object); + GabblePluginConnection *plugin_connection; + + G_OBJECT_CLASS (gabble_console_channel_manager_parent_class)->constructed (object); + + plugin_connection = g_weak_ref_get (&self->plugin_connection_ref); + if (plugin_connection != NULL) + { + g_signal_connect_object (plugin_connection, "status-changed", + G_CALLBACK (connection_status_changed_cb), self, 0); + g_object_unref (plugin_connection); + } +} + + +static void +gabble_console_channel_manager_set_property ( + GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GabbleConsoleChannelManager *self = GABBLE_CONSOLE_CHANNEL_MANAGER (object); + + switch (property_id) + { + case PROP_CONNECTION: + g_weak_ref_set (&self->plugin_connection_ref, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +gabble_console_channel_manager_get_property ( + GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GabbleConsoleChannelManager *self = GABBLE_CONSOLE_CHANNEL_MANAGER (object); + + switch (property_id) + { + case PROP_CONNECTION: + g_value_take_object (value, g_weak_ref_get (&self->plugin_connection_ref)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + + +static void +gabble_console_channel_manager_dispose ( + GObject *object) +{ + GabbleConsoleChannelManager *self = GABBLE_CONSOLE_CHANNEL_MANAGER (object); + + gabble_console_channel_manager_close_all (self); + g_weak_ref_clear (&self->plugin_connection_ref); + + G_OBJECT_CLASS (gabble_console_channel_manager_parent_class)->dispose (object); +} + + +static void +connection_status_changed_cb ( + TpBaseConnection *conn, + guint status, + guint reason, + GabbleConsoleChannelManager *self) +{ + switch (status) + { + case TP_CONNECTION_STATUS_DISCONNECTED: + gabble_console_channel_manager_close_all (self); + break; + + default: + return; + } +} + +static void +gabble_console_channel_manager_close_all ( + GabbleConsoleChannelManager *self) +{ + TpBaseChannel *channel; + + while ((channel = g_queue_peek_head (&self->console_channels)) != NULL) + { + tp_base_channel_close (channel); + } +} + + +static void +gabble_console_channel_manager_class_init (GabbleConsoleChannelManagerClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + + oclass->constructed = gabble_console_channel_manager_constructed; + oclass->set_property = gabble_console_channel_manager_set_property; + oclass->get_property = gabble_console_channel_manager_get_property; + oclass->dispose = gabble_console_channel_manager_dispose; + + g_object_class_install_property (oclass, PROP_CONNECTION, + g_param_spec_object ("plugin-connection", "Gabble Plugin Connection", + "Gabble Plugin Connection", + GABBLE_TYPE_PLUGIN_CONNECTION, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); +} + + +static const gchar * const allowed[] = { + TP_PROP_CHANNEL_CHANNEL_TYPE, + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, + NULL +}; + +static void +gabble_console_channel_manager_type_foreach_channel_class (GType type, + TpChannelManagerTypeChannelClassFunc func, + gpointer user_data) +{ + GHashTable *table = tp_asv_new ( + TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, GABBLE_IFACE_GABBLE_PLUGIN_CONSOLE, + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_NONE, + NULL); + + func (type, table, NULL, user_data); + + g_hash_table_unref (table); +} + + +static void +console_channel_closed_cb ( + GabbleConsoleChannel *channel, + gpointer user_data) +{ + GabbleConsoleChannelManager *self = GABBLE_CONSOLE_CHANNEL_MANAGER (user_data); + + tp_channel_manager_emit_channel_closed_for_object (self, + TP_EXPORTABLE_CHANNEL (channel)); + + if (g_queue_remove (&self->console_channels, channel)) + { + g_object_unref (channel); + } +} + + +static gboolean +gabble_console_channel_manager_create_channel ( + TpChannelManager *manager, + gpointer request_token, + GHashTable *request_properties) +{ + GabbleConsoleChannelManager *self = GABBLE_CONSOLE_CHANNEL_MANAGER (manager); + GabblePluginConnection *connection; + TpBaseChannel *channel = NULL; + GError *error = NULL; + GSList *request_tokens; + + if (tp_strdiff (tp_asv_get_string (request_properties, + TP_IFACE_CHANNEL ".ChannelType"), + GABBLE_IFACE_GABBLE_PLUGIN_CONSOLE)) + return FALSE; + + if (tp_asv_get_uint32 (request_properties, + TP_IFACE_CHANNEL ".TargetHandleType", NULL) != 0) + { + g_set_error (&error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, + "Console channels can't have a target handle"); + goto error; + } + + if (tp_channel_manager_asv_has_unknown_properties (request_properties, + allowed, + allowed, + &error)) + goto error; + + connection = g_weak_ref_get (&self->plugin_connection_ref); + g_return_val_if_fail (connection != NULL, FALSE); + + channel = g_object_new (GABBLE_TYPE_CONSOLE_CHANNEL, + "connection", connection, + NULL); + tp_base_channel_register (channel); + g_signal_connect (channel, "closed", (GCallback) console_channel_closed_cb, + self); + g_queue_push_tail (&self->console_channels, channel); + + request_tokens = g_slist_prepend (NULL, request_token); + tp_channel_manager_emit_new_channel (self, + TP_EXPORTABLE_CHANNEL (channel), request_tokens); + g_slist_free (request_tokens); + + g_object_unref (connection); + 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 void +channel_manager_iface_init (gpointer g_iface, + gpointer iface_data) +{ + TpChannelManagerIface *iface = g_iface; + + iface->type_foreach_channel_class = gabble_console_channel_manager_type_foreach_channel_class; + iface->create_channel = gabble_console_channel_manager_create_channel; +} diff --git a/plugins/console/channel-manager.h b/plugins/console/channel-manager.h new file mode 100644 index 000000000..5e7a8b94d --- /dev/null +++ b/plugins/console/channel-manager.h @@ -0,0 +1,52 @@ +/* XML console plugin + * + * Copyright © 2011–2013 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 <gabble/gabble.h> + +typedef struct _GabbleConsoleChannelManager GabbleConsoleChannelManager; +typedef struct _GabbleConsoleChannelManagerClass GabbleConsoleChannelManagerClass; + +struct _GabbleConsoleChannelManagerClass { + GObjectClass parent_class; +}; + +struct _GabbleConsoleChannelManager { + GObject parent; + + GWeakRef plugin_connection_ref; + GQueue console_channels; +}; + +GType gabble_console_channel_manager_get_type (void); + +#define GABBLE_TYPE_CONSOLE_CHANNEL_MANAGER \ + (gabble_console_channel_manager_get_type ()) +#define GABBLE_CONSOLE_CHANNEL_MANAGER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), GABBLE_TYPE_CONSOLE_CHANNEL_MANAGER, GabbleConsoleChannelManager)) +#define GABBLE_CONSOLE_CHANNEL_MANAGER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), GABBLE_TYPE_CONSOLE_CHANNEL_MANAGER,\ + GabbleConsoleChannelManagerClass)) +#define GABBLE_IS_CONSOLE_CHANNEL_MANAGER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_CONSOLE_CHANNEL_MANAGER)) +#define GABBLE_IS_CONSOLE_CHANNEL_MANAGER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GABBLE_TYPE_CONSOLE_CHANNEL_MANAGER)) +#define GABBLE_CONSOLE_CHANNEL_MANAGER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_CONSOLE_CHANNEL_MANAGER,\ + GabbleConsoleChannelManagerClass)) diff --git a/plugins/console.c b/plugins/console/channel.c index b0da5a62b..3ddbef905 100644 --- a/plugins/console.c +++ b/plugins/console/channel.c @@ -18,8 +18,7 @@ */ #include "config.h" - -#include "console.h" +#include "console/channel.h" #include <string.h> @@ -27,148 +26,19 @@ #include <telepathy-glib/telepathy-glib-dbus.h> #include <wocky/wocky.h> - -#include "extensions/extensions.h" - #include <gabble/gabble.h> +#include "extensions/extensions.h" -/************************* - * Plugin implementation * - *************************/ - -static guint debug = 0; - -#define DEBUG(format, ...) \ -G_STMT_START { \ - if (debug != 0) \ - g_debug ("%s: " format, G_STRFUNC, ## __VA_ARGS__); \ -} G_STMT_END - -static const GDebugKey debug_keys[] = { - { "console", 1 }, - { NULL, 0 } -}; - -static void plugin_iface_init ( - gpointer g_iface, - gpointer data); - -static const gchar * const sidecar_interfaces[] = { - GABBLE_IFACE_GABBLE_PLUGIN_CONSOLE, - NULL -}; - -G_DEFINE_TYPE_WITH_CODE (GabbleConsolePlugin, gabble_console_plugin, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (GABBLE_TYPE_PLUGIN, plugin_iface_init); - ) - -static void -gabble_console_plugin_init (GabbleConsolePlugin *self) -{ -} - -static void -gabble_console_plugin_class_init (GabbleConsolePluginClass *klass) -{ -} - -static void -gabble_console_plugin_create_sidecar_async ( - GabblePlugin *plugin, - const gchar *sidecar_interface, - GabblePluginConnection *connection, - WockySession *session, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *result = g_simple_async_result_new (G_OBJECT (plugin), - callback, user_data, - gabble_console_plugin_create_sidecar_async); - GabbleSidecar *sidecar = NULL; - - if (!tp_strdiff (sidecar_interface, GABBLE_IFACE_GABBLE_PLUGIN_CONSOLE)) - { - sidecar = g_object_new (GABBLE_TYPE_CONSOLE_SIDECAR, - "connection", connection, - "session", session, - NULL); - } - else - { - g_simple_async_result_set_error (result, TP_ERROR, - 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 GabbleSidecar * -gabble_console_plugin_create_sidecar_finish ( - GabblePlugin *plugin, - GAsyncResult *result, - GError **error) -{ - GabbleSidecar *sidecar; - - if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), - error)) - return NULL; - - g_return_val_if_fail (g_simple_async_result_is_valid (result, - G_OBJECT (plugin), gabble_console_plugin_create_sidecar_async), NULL); - - sidecar = GABBLE_SIDECAR (g_simple_async_result_get_op_res_gpointer ( - G_SIMPLE_ASYNC_RESULT (result))); - - return g_object_ref (sidecar); -} - -static void -plugin_iface_init ( - gpointer g_iface, - gpointer data G_GNUC_UNUSED) -{ - GabblePluginInterface *iface = g_iface; - - iface->name = "XMPP console"; - iface->version = PACKAGE_VERSION; - iface->sidecar_interfaces = sidecar_interfaces; - iface->create_sidecar_async = gabble_console_plugin_create_sidecar_async; - iface->create_sidecar_finish = gabble_console_plugin_create_sidecar_finish; -} - -GabblePlugin * -gabble_plugin_create (void) -{ - debug = g_parse_debug_string (g_getenv ("GABBLE_DEBUG"), debug_keys, - G_N_ELEMENTS (debug_keys) - 1); - DEBUG ("loaded"); - - return g_object_new (GABBLE_TYPE_CONSOLE_PLUGIN, - NULL); -} - -/************************** - * Sidecar implementation * - **************************/ +#include "console/debug.h" enum { PROP_0, - PROP_CONNECTION, - PROP_SESSION, PROP_SPEW }; -struct _GabbleConsoleSidecarPrivate +struct _GabbleConsoleChannelPrivate { WockySession *session; - TpBaseConnection *connection; WockyXmppReader *reader; WockyXmppWriter *writer; @@ -183,43 +53,58 @@ struct _GabbleConsoleSidecarPrivate gulong sending_id; }; -static void sidecar_iface_init ( - gpointer g_iface, - gpointer data); static void console_iface_init ( gpointer g_iface, gpointer data); -static void gabble_console_sidecar_set_spew ( - GabbleConsoleSidecar *self, +static void gabble_console_channel_set_spew ( + GabbleConsoleChannel *self, gboolean spew); +gchar *gabble_console_channel_get_path (TpBaseChannel *chan); +static void gabble_console_channel_close (TpBaseChannel *chan); -G_DEFINE_TYPE_WITH_CODE (GabbleConsoleSidecar, gabble_console_sidecar, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (GABBLE_TYPE_SIDECAR, sidecar_iface_init); +G_DEFINE_TYPE_WITH_CODE (GabbleConsoleChannel, gabble_console_channel, + TP_TYPE_BASE_CHANNEL, G_IMPLEMENT_INTERFACE (GABBLE_TYPE_SVC_GABBLE_PLUGIN_CONSOLE, console_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, - tp_dbus_properties_mixin_iface_init); ) static void -gabble_console_sidecar_init (GabbleConsoleSidecar *self) +gabble_console_channel_init (GabbleConsoleChannel *self) { - self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GABBLE_TYPE_CONSOLE_SIDECAR, - GabbleConsoleSidecarPrivate); + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GABBLE_TYPE_CONSOLE_CHANNEL, + GabbleConsoleChannelPrivate); self->priv->reader = wocky_xmpp_reader_new_no_stream_ns ( WOCKY_XMPP_NS_JABBER_CLIENT); self->priv->writer = wocky_xmpp_writer_new_no_stream (); } + +static void +gabble_console_channel_constructed (GObject *object) +{ + GabbleConsoleChannel *self = GABBLE_CONSOLE_CHANNEL (object); + void (*chain_up)(GObject *) = + G_OBJECT_CLASS (gabble_console_channel_parent_class)->constructed; + + if (chain_up != NULL) + chain_up (object); + + self->priv->session = g_object_ref ( + gabble_plugin_connection_get_session ( + GABBLE_PLUGIN_CONNECTION ( + tp_base_channel_get_connection ( + TP_BASE_CHANNEL (self))))); + g_return_if_fail (self->priv->session != NULL); +} + static void -gabble_console_sidecar_get_property ( +gabble_console_channel_get_property ( GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { - GabbleConsoleSidecar *self = GABBLE_CONSOLE_SIDECAR (object); + GabbleConsoleChannel *self = GABBLE_CONSOLE_CHANNEL (object); switch (property_id) { @@ -233,28 +118,18 @@ gabble_console_sidecar_get_property ( } static void -gabble_console_sidecar_set_property ( +gabble_console_channel_set_property ( GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { - GabbleConsoleSidecar *self = GABBLE_CONSOLE_SIDECAR (object); + GabbleConsoleChannel *self = GABBLE_CONSOLE_CHANNEL (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; - case PROP_SPEW: - gabble_console_sidecar_set_spew (self, g_value_get_boolean (value)); + gabble_console_channel_set_spew (self, g_value_get_boolean (value)); break; default: @@ -263,15 +138,14 @@ gabble_console_sidecar_set_property ( } static void -gabble_console_sidecar_dispose (GObject *object) +gabble_console_channel_dispose (GObject *object) { void (*chain_up) (GObject *) = - G_OBJECT_CLASS (gabble_console_sidecar_parent_class)->dispose; - GabbleConsoleSidecar *self = GABBLE_CONSOLE_SIDECAR (object); + G_OBJECT_CLASS (gabble_console_channel_parent_class)->dispose; + GabbleConsoleChannel *self = GABBLE_CONSOLE_CHANNEL (object); - gabble_console_sidecar_set_spew (self, FALSE); + gabble_console_channel_set_spew (self, FALSE); - tp_clear_object (&self->priv->connection); tp_clear_object (&self->priv->reader); tp_clear_object (&self->priv->writer); tp_clear_object (&self->priv->session); @@ -281,46 +155,25 @@ gabble_console_sidecar_dispose (GObject *object) } static void -gabble_console_sidecar_class_init (GabbleConsoleSidecarClass *klass) +gabble_console_channel_class_init (GabbleConsoleChannelClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + TpBaseChannelClass *channel_class = TP_BASE_CHANNEL_CLASS (klass); static TpDBusPropertiesMixinPropImpl console_props[] = { { "SpewStanzas", "spew-stanzas", "spew-stanzas" }, { NULL }, }; - static TpDBusPropertiesMixinIfaceImpl interfaces[] = { - { GABBLE_IFACE_GABBLE_PLUGIN_CONSOLE, - tp_dbus_properties_mixin_getter_gobject_properties, - /* FIXME: if we were feeling clever, we'd override the setter so that - * we can monitor the bus name of any application which sets - * SpewStanzas to TRUE and flip it back to false when that application - * dies. - * - * Alternatively, we could just replace this sidecar with a channel. - */ - tp_dbus_properties_mixin_setter_gobject_properties, - console_props - }, - { NULL }, - }; - - object_class->get_property = gabble_console_sidecar_get_property; - object_class->set_property = gabble_console_sidecar_set_property; - object_class->dispose = gabble_console_sidecar_dispose; - g_type_class_add_private (klass, sizeof (GabbleConsoleSidecarPrivate)); + object_class->constructed = gabble_console_channel_constructed; + object_class->get_property = gabble_console_channel_get_property; + object_class->set_property = gabble_console_channel_set_property; + object_class->dispose = gabble_console_channel_dispose; - g_object_class_install_property (object_class, PROP_CONNECTION, - g_param_spec_object ("connection", "Connection", - "Gabble connection", - GABBLE_TYPE_PLUGIN_CONNECTION, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + channel_class->channel_type = GABBLE_IFACE_GABBLE_PLUGIN_CONSOLE; + channel_class->get_object_path_suffix = gabble_console_channel_get_path; + channel_class->close = gabble_console_channel_close; - 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)); + g_type_class_add_private (klass, sizeof (GabbleConsoleChannelPrivate)); g_object_class_install_property (object_class, PROP_SPEW, g_param_spec_boolean ("spew-stanzas", "SpewStanzas", @@ -328,19 +181,26 @@ gabble_console_sidecar_class_init (GabbleConsoleSidecarClass *klass) FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - klass->props_class.interfaces = interfaces; - tp_dbus_properties_mixin_class_init (object_class, - G_STRUCT_OFFSET (GabbleConsoleSidecarClass, props_class)); + tp_dbus_properties_mixin_implement_interface (object_class, + GABBLE_IFACE_QUARK_GABBLE_PLUGIN_CONSOLE, + tp_dbus_properties_mixin_getter_gobject_properties, + tp_dbus_properties_mixin_setter_gobject_properties, + console_props); } -static void sidecar_iface_init ( - gpointer g_iface, - gpointer data) +gchar * +gabble_console_channel_get_path (TpBaseChannel *chan) +{ + return g_strdup_printf ("console%p", chan); +} + +static void +gabble_console_channel_close (TpBaseChannel *chan) { - GabbleSidecarInterface *iface = g_iface; + GabbleConsoleChannel *self = GABBLE_CONSOLE_CHANNEL (chan); - iface->interface = GABBLE_IFACE_GABBLE_PLUGIN_CONSOLE; - iface->get_immutable_properties = NULL; + gabble_console_channel_set_spew (self, FALSE); + tp_base_channel_destroyed (chan); } static gboolean @@ -349,7 +209,7 @@ incoming_cb ( WockyStanza *stanza, gpointer user_data) { - GabbleConsoleSidecar *self = GABBLE_CONSOLE_SIDECAR (user_data); + GabbleConsoleChannel *self = GABBLE_CONSOLE_CHANNEL (user_data); const guint8 *body; gsize length; @@ -365,7 +225,7 @@ sending_cb ( WockyStanza *stanza, gpointer user_data) { - GabbleConsoleSidecar *self = GABBLE_CONSOLE_SIDECAR (user_data); + GabbleConsoleChannel *self = GABBLE_CONSOLE_CHANNEL (user_data); if (stanza != NULL) { @@ -380,11 +240,11 @@ sending_cb ( } static void -gabble_console_sidecar_set_spew ( - GabbleConsoleSidecar *self, +gabble_console_channel_set_spew ( + GabbleConsoleChannel *self, gboolean spew) { - GabbleConsoleSidecarPrivate *priv = self->priv; + GabbleConsoleChannelPrivate *priv = self->priv; if (!spew != !priv->spew) { @@ -425,7 +285,7 @@ return_from_send_iq ( GAsyncResult *result, gpointer user_data) { - GabbleConsoleSidecar *self = GABBLE_CONSOLE_SIDECAR (source); + GabbleConsoleChannel *self = GABBLE_CONSOLE_CHANNEL (source); DBusGMethodInvocation *context = user_data; GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); GError *error = NULL; @@ -524,12 +384,12 @@ validate_jid (const gchar **to, */ static gboolean parse_me_a_stanza ( - GabbleConsoleSidecar *self, + GabbleConsoleChannel *self, const gchar *xml, WockyStanza **stanza_out, GError **error) { - GabbleConsoleSidecarPrivate *priv = self->priv; + GabbleConsoleChannelPrivate *priv = self->priv; WockyStanza *stanza; wocky_xmpp_reader_reset (priv->reader); @@ -555,13 +415,13 @@ parse_me_a_stanza ( static void console_send_iq ( - GabbleSvcGabblePluginConsole *sidecar, + GabbleSvcGabblePluginConsole *channel, const gchar *type_str, const gchar *to, const gchar *body, DBusGMethodInvocation *context) { - GabbleConsoleSidecar *self = GABBLE_CONSOLE_SIDECAR (sidecar); + GabbleConsoleChannel *self = GABBLE_CONSOLE_CHANNEL (channel); WockyPorter *porter = wocky_session_get_porter (self->priv->session); WockyStanzaSubType sub_type; WockyStanza *fragment; @@ -641,11 +501,11 @@ stanza_looks_coherent ( static void console_send_stanza ( - GabbleSvcGabblePluginConsole *sidecar, + GabbleSvcGabblePluginConsole *channel, const gchar *xml, DBusGMethodInvocation *context) { - GabbleConsoleSidecar *self = GABBLE_CONSOLE_SIDECAR (sidecar); + GabbleConsoleChannel *self = GABBLE_CONSOLE_CHANNEL (channel); WockyPorter *porter = wocky_session_get_porter (self->priv->session); WockyStanza *stanza = NULL; GError *error = NULL; diff --git a/plugins/console/channel.h b/plugins/console/channel.h new file mode 100644 index 000000000..7e41c5ad2 --- /dev/null +++ b/plugins/console/channel.h @@ -0,0 +1,53 @@ +/* XML console plugin + * + * Copyright © 2011 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 <telepathy-glib/telepathy-glib.h> + +typedef struct _GabbleConsoleChannel GabbleConsoleChannel; +typedef struct _GabbleConsoleChannelClass GabbleConsoleChannelClass; +typedef struct _GabbleConsoleChannelPrivate GabbleConsoleChannelPrivate; + +struct _GabbleConsoleChannel { + TpBaseChannel parent; + + GabbleConsoleChannelPrivate *priv; +}; + +struct _GabbleConsoleChannelClass { + TpBaseChannelClass parent; +}; + +GType gabble_console_channel_get_type (void); + +#define GABBLE_TYPE_CONSOLE_CHANNEL \ + (gabble_console_channel_get_type ()) +#define GABBLE_CONSOLE_CHANNEL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GABBLE_TYPE_CONSOLE_CHANNEL, \ + GabbleConsoleChannel)) +#define GABBLE_CONSOLE_CHANNEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GABBLE_TYPE_CONSOLE_CHANNEL, \ + GabbleConsoleChannelClass)) +#define GABBLE_IS_CONSOLE_CHANNEL(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GABBLE_TYPE_CONSOLE_CHANNEL)) +#define GABBLE_IS_CONSOLE_CHANNEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GABBLE_TYPE_CONSOLE_CHANNEL)) +#define GABBLE_CONSOLE_CHANNEL_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_CONSOLE_CHANNEL, \ + GabbleConsoleChannelClass)) diff --git a/plugins/console/debug.c b/plugins/console/debug.c new file mode 100644 index 000000000..29dcf161b --- /dev/null +++ b/plugins/console/debug.c @@ -0,0 +1,36 @@ +/* XML console plugin + * + * Copyright © 2011 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.h> + +#include "console/debug.h" + +int debug = 0; + +static const GDebugKey debug_keys[] = { + { "console", 1 }, + { NULL, 0 } +}; + +void +gabble_console_debug_init (void) +{ + debug = g_parse_debug_string (g_getenv ("GABBLE_DEBUG"), debug_keys, + G_N_ELEMENTS (debug_keys) - 1); +} diff --git a/plugins/console/debug.h b/plugins/console/debug.h new file mode 100644 index 000000000..78031722d --- /dev/null +++ b/plugins/console/debug.h @@ -0,0 +1,28 @@ +/* XML console plugin + * + * Copyright © 2011 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 + */ + +extern int debug; + +#define DEBUG(format, ...) \ +G_STMT_START { \ + if (debug != 0) \ + g_debug ("%s: " format, G_STRFUNC, ## __VA_ARGS__); \ +} G_STMT_END + +void gabble_console_debug_init (void); diff --git a/plugins/console/plugin.c b/plugins/console/plugin.c new file mode 100644 index 000000000..c17cf71b0 --- /dev/null +++ b/plugins/console/plugin.c @@ -0,0 +1,91 @@ +/* XML console plugin + * + * Copyright © 2011 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 "config.h" +#include "console/plugin.h" + +#include <telepathy-glib/telepathy-glib.h> +#include <wocky/wocky.h> +#include <gabble/gabble.h> +#include "extensions/extensions.h" + +#include "console/channel-manager.h" +#include "console/channel.h" +#include "console/debug.h" + +static void plugin_iface_init ( + gpointer g_iface, + gpointer data); + +static const gchar * const sidecar_interfaces[] = { + GABBLE_IFACE_GABBLE_PLUGIN_CONSOLE, + NULL +}; + +G_DEFINE_TYPE_WITH_CODE (GabbleConsolePlugin, gabble_console_plugin, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GABBLE_TYPE_PLUGIN, plugin_iface_init); + ) + +static void +gabble_console_plugin_init (GabbleConsolePlugin *self) +{ +} + +static void +gabble_console_plugin_class_init (GabbleConsolePluginClass *klass) +{ +} + +static GPtrArray * +gabble_console_plugin_create_channel_managers (GabblePlugin *plugin, + GabblePluginConnection *plugin_connection) +{ + GPtrArray *ret = g_ptr_array_new (); + + g_ptr_array_add (ret, + g_object_new (GABBLE_TYPE_CONSOLE_CHANNEL_MANAGER, + "plugin-connection", plugin_connection, + NULL)); + + return ret; +} + +static void +plugin_iface_init ( + gpointer g_iface, + gpointer data G_GNUC_UNUSED) +{ + GabblePluginInterface *iface = g_iface; + + iface->name = "XMPP console"; + iface->version = PACKAGE_VERSION; + iface->create_channel_managers = gabble_console_plugin_create_channel_managers; +} + +GabblePlugin * +gabble_plugin_create (void) +{ + gabble_console_debug_init (); + + DEBUG ("loaded"); + + return g_object_new (GABBLE_TYPE_CONSOLE_PLUGIN, + NULL); +} diff --git a/plugins/console.h b/plugins/console/plugin.h index e646d067e..153484f91 100644 --- a/plugins/console.h +++ b/plugins/console/plugin.h @@ -19,10 +19,6 @@ #include <glib-object.h> -#include <gio/gio.h> -#include <wocky/wocky.h> -#include <telepathy-glib/telepathy-glib.h> - typedef struct _GabbleConsolePlugin GabbleConsolePlugin; typedef struct _GabbleConsolePluginClass GabbleConsolePluginClass; typedef struct _GabbleConsolePluginPrivate GabbleConsolePluginPrivate; @@ -53,36 +49,3 @@ GType gabble_console_plugin_get_type (void); #define GABBLE_CONSOLE_PLUGIN_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_CONSOLE_PLUGIN, \ GabbleConsolePluginClass)) - -typedef struct _GabbleConsoleSidecar GabbleConsoleSidecar; -typedef struct _GabbleConsoleSidecarClass GabbleConsoleSidecarClass; -typedef struct _GabbleConsoleSidecarPrivate GabbleConsoleSidecarPrivate; - -struct _GabbleConsoleSidecar { - GObject parent; - GabbleConsoleSidecarPrivate *priv; -}; - -struct _GabbleConsoleSidecarClass { - GObjectClass parent; - - TpDBusPropertiesMixinClass props_class; -}; - -GType gabble_console_sidecar_get_type (void); - -#define GABBLE_TYPE_CONSOLE_SIDECAR \ - (gabble_console_sidecar_get_type ()) -#define GABBLE_CONSOLE_SIDECAR(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), GABBLE_TYPE_CONSOLE_SIDECAR, \ - GabbleConsoleSidecar)) -#define GABBLE_CONSOLE_SIDECAR_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), GABBLE_TYPE_CONSOLE_SIDECAR, \ - GabbleConsoleSidecarClass)) -#define GABBLE_IS_CONSOLE_SIDECAR(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GABBLE_TYPE_CONSOLE_SIDECAR)) -#define GABBLE_IS_CONSOLE_SIDECAR_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), GABBLE_TYPE_CONSOLE_SIDECAR)) -#define GABBLE_CONSOLE_SIDECAR_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_CONSOLE_SIDECAR, \ - GabbleConsoleSidecarClass)) diff --git a/plugins/telepathy-gabble-xmpp-console b/plugins/telepathy-gabble-xmpp-console index 8b96469d8..a72c92b55 100755 --- a/plugins/telepathy-gabble-xmpp-console +++ b/plugins/telepathy-gabble-xmpp-console @@ -3,10 +3,10 @@ """ The world's worst XMPP console user interface. -Pass it the bus name of a Gabble connection; type some words; get minimalistic +Pass it a Gabble account name; type some words; get minimalistic error reporting. -Copyright © 2011 Collabora Ltd. <http://www.collabora.co.uk/> +Copyright © 2011–2013 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 @@ -24,23 +24,13 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ import sys -import re from xml.dom import minidom -from gi.repository import Gtk -from gi.repository import GLib -from gi.repository import Gio -from gi.repository import GtkSource +from gi.repository import Gtk, GLib, Gio, GtkSource +from gi.repository import TelepathyGLib as Tp PADDING = 6 -def pathify(name): - return '/' + name.replace('.', '/') - -def nameify(path): - return (path[1:]).replace('/', '.') - -CONN_FUTURE_IFACE = "org.freedesktop.Telepathy.Connection.FUTURE" CONSOLE_IFACE = "org.freedesktop.Telepathy.Gabble.Plugin.Console" class StanzaViewer(Gtk.ScrolledWindow): @@ -302,32 +292,27 @@ class Window(Gtk.Window): STANZA_PAGE = 1 SNOOPY_PAGE = 2 - def __init__(self, bus, connection_bus_name): + def __init__(self, account): Gtk.Window.__init__(self) self.set_title('XMPP Console') self.set_default_size(600, 371) - conn_future_proxy = Gio.DBusProxy.new_sync(bus, 0, None, - connection_bus_name, pathify(connection_bus_name), - CONN_FUTURE_IFACE, None) - try: - sidecar_path, _ = conn_future_proxy.EnsureSidecar('(s)', CONSOLE_IFACE) - except Exception, e: - print """ -Couldn't connect to the XMPP console interface on '%(connection_bus_name)s': - %(e)s -Check that it's a running Jabber connection, and that you have the console -plugin installed.""" % locals() + request = Tp.AccountChannelRequest.new( + account, + { Tp.PROP_CHANNEL_CHANNEL_TYPE: CONSOLE_IFACE }, + 0) + request.create_and_handle_channel_async(None, self.__create_cb, None) - raise SystemExit(2) - - self.console_proxy = Gio.DBusProxy.new_sync(bus, 0, None, - connection_bus_name, sidecar_path, CONSOLE_IFACE, None) + self.connect('destroy', Window.__destroy_cb) + def __build_ui(self): # Build up the UI + self.grid = Gtk.Grid() + self.add(self.grid) + self.nb = Gtk.Notebook() - self.add(self.nb) + self.grid.attach(self.nb, 0, 0, 1, 1) self.iq = IQPage(self.console_proxy) self.nb.insert_page(self.iq, @@ -344,57 +329,103 @@ plugin installed.""" % locals() Gtk.Label.new_with_mnemonic("_Monitor network traffic"), self.SNOOPY_PAGE) - self.connect('destroy', Window.__destroy_cb) + self.infobar = Gtk.InfoBar() + self.infobar.set_message_type(Gtk.MessageType.WARNING) + self.infobar.set_no_show_all(True) + label = Gtk.Label("The connection went away! Time to leave.") + label.show() + self.infobar.get_content_area().add(label) + self.infobar_close_button = self.infobar.add_button("Close", Gtk.ResponseType.CLOSE) + self.infobar.connect('response', lambda infobar, response: Gtk.main_quit()) + self.infobar.connect('close', lambda infobar: Gtk.main_quit()) + + self.grid.attach_next_to(self.infobar, self.nb, + Gtk.PositionType.BOTTOM, 1, 1) + + def __create_cb(self, request, result, _): + try: + channel, context = request.create_and_handle_channel_finish(result) + channel.connect('invalidated', self.__channel_invalidated_cb) + + bus_name = channel.get_bus_name() + sidecar_path = channel.get_object_path() + + bus = Gio.bus_get_sync(Gio.BusType.SESSION, None) + self.console_proxy = Gio.DBusProxy.new_sync(bus, 0, None, + bus_name, sidecar_path, CONSOLE_IFACE, None) + + except GLib.GError as e: + print """ +Couldn't connect to the XMPP console interface on '%(name)s': +%(e)s +Check that you have the console plugin installed.""" % { + 'name': request.get_account().get_path_suffix(), + 'e': e, + } + raise SystemExit(2) + + self.__build_ui() + self.show_all() + + def __channel_invalidated_cb(self, channel, domain, code, message): + self.infobar.show() + self.infobar_close_button.grab_focus() + self.nb.set_sensitive(False) + # TODO: try to reconnect? def __destroy_cb(self): - self.snoopy.teardown() + try: + self.snoopy.teardown() + except GLib.GError, e: + print "Couldn't turn off the monitor (maybe the connection went away?)" + print e Gtk.main_quit() -GABBLE_PREFIX = 'org.freedesktop.Telepathy.Connection.gabble.jabber.' - -AM_BUS_NAME = 'org.freedesktop.Telepathy.AccountManager' -ACCOUNT_PREFIX = '/org/freedesktop/Telepathy/Account' -ACCOUNT_IFACE = 'org.freedesktop.Telepathy.Account' +def usage(am): + xmpp_accounts = sorted( + account.get_path_suffix() + for account in am.dup_valid_accounts() + if account.get_cm_name() == 'gabble') -def usage(): print """ Usage: %(arg0)s gabble/jabber/blahblah - %(arg0)s %(prefix)sblahblah -List account identifiers using `mc-tool list | grep gabble`. -List connection bus names using `qdbus | grep gabble`. +Here are some account identifiers: + + %(accounts)s """ % { 'arg0': sys.argv[0], - 'prefix': GABBLE_PREFIX, + 'accounts': '\n '.join(xmpp_accounts), } raise SystemExit(1) -if __name__ == '__main__': - bus = Gio.bus_get_sync(Gio.BusType.SESSION, None) - - if len(sys.argv) != 2: - usage() - - thing = sys.argv[1] - - if re.match('^gabble/jabber/[a-zA-Z0-9_]+$', thing): - # Looks like an account path to me. - account_proxy = Gio.DBusProxy.new_sync(bus, 0, None, - AM_BUS_NAME, '%s/%s' % (ACCOUNT_PREFIX, thing), - ACCOUNT_IFACE, None) - path = account_proxy.get_cached_property('Connection').get_string() - if path == '/': - print "%s is not online" % thing - raise SystemExit(1) - else: - thing = nameify(path) +def am_prepared_cb(am, result, account_suffix): + try: + am.prepare_finish(result) + except GLib.GError as e: + print e + raise SystemExit(2) + + if account_suffix is None: + usage(am) - if not re.match('^%s[a-zA-Z0-9_]+$' % GABBLE_PREFIX, thing): - usage() + for account in am.dup_valid_accounts(): + if account.get_path_suffix() == account_suffix: + if account.get_connection() is None: + print "%s is not online." % account_suffix + raise SystemExit(2) + else: + win = Window(account) + return + + usage(am) + +if __name__ == '__main__': + account_suffix = sys.argv[1] if len(sys.argv) == 2 else None - win = Window(bus, thing) - win.show_all() + am = Tp.AccountManager.dup() + am.prepare_async([], am_prepared_cb, account_suffix) Gtk.main() |