diff options
author | Xavier Claessens <xclaesse@src.gnome.org> | 2008-05-09 01:30:40 +0800 |
---|---|---|
committer | Xavier Claessens <xclaesse@src.gnome.org> | 2008-05-09 01:30:40 +0800 |
commit | 64030b865ce54a5e2442e98a4724b8f2099d2809 (patch) | |
tree | 2784f531dd981623eabaeb53787951e009579d39 | |
parent | 5567b074722bf1243a52086d34a80e04c2e11867 (diff) | |
download | gsoc2013-empathy-64030b865ce54a5e2442e98a4724b8f2099d2809.tar gsoc2013-empathy-64030b865ce54a5e2442e98a4724b8f2099d2809.tar.gz gsoc2013-empathy-64030b865ce54a5e2442e98a4724b8f2099d2809.tar.bz2 gsoc2013-empathy-64030b865ce54a5e2442e98a4724b8f2099d2809.tar.lz gsoc2013-empathy-64030b865ce54a5e2442e98a4724b8f2099d2809.tar.xz gsoc2013-empathy-64030b865ce54a5e2442e98a4724b8f2099d2809.tar.zst gsoc2013-empathy-64030b865ce54a5e2442e98a4724b8f2099d2809.zip |
Move non-gtk parts of EmpathyFilter to EmpathyDispatcher in libempathy, gtk parts are now in EmpathyStatusIcon
svn path=/trunk/; revision=1093
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | libempathy/Makefile.am | 6 | ||||
-rw-r--r-- | libempathy/empathy-debug.c | 2 | ||||
-rw-r--r-- | libempathy/empathy-debug.h | 2 | ||||
-rw-r--r-- | libempathy/empathy-dispatcher.c | 681 | ||||
-rw-r--r-- | libempathy/empathy-dispatcher.h | 72 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/empathy-filter.c | 1001 | ||||
-rw-r--r-- | src/empathy-filter.h | 61 | ||||
-rw-r--r-- | src/empathy-status-icon.c | 308 | ||||
-rw-r--r-- | src/empathy.c | 64 |
11 files changed, 1101 insertions, 1099 deletions
diff --git a/configure.ac b/configure.ac index d460a4771..80f48caeb 100644 --- a/configure.ac +++ b/configure.ac @@ -30,7 +30,7 @@ GTK_REQUIRED=2.12.0 GCONF_REQUIRED=1.2.0 LIBGLADE_REQUIRED=2.0.0 LIBPANELAPPLET_REQUIRED=2.10.0 -TELEPATHY_GLIB_REQUIRED=0.7.6 +TELEPATHY_GLIB_REQUIRED=0.7.7 MISSION_CONTROL_REQUIRED=4.61 ENCHANT_REQUIRED=1.2.0 ISO_CODES_REQUIRED=0.35 diff --git a/libempathy/Makefile.am b/libempathy/Makefile.am index 16696b432..0db883d3d 100644 --- a/libempathy/Makefile.am +++ b/libempathy/Makefile.am @@ -41,7 +41,8 @@ libempathy_la_SOURCES = \ empathy-irc-network-manager.c \ empathy-irc-network.c \ empathy-irc-server.c \ - empathy-tube-handler.c + empathy-tube-handler.c \ + empathy-dispatcher.c # do not distribute generated files nodist_libempathy_la_SOURCES =\ @@ -81,7 +82,8 @@ libempathy_headers = \ empathy-irc-network-manager.h \ empathy-irc-network.h \ empathy-irc-server.h \ - empathy-tube-handler.h + empathy-tube-handler.h \ + empathy-dispatcher.h libempathy_includedir = $(includedir)/libempathy/ libempathy_include_HEADERS = \ diff --git a/libempathy/empathy-debug.c b/libempathy/empathy-debug.c index 16d61c37c..b0f7d1810 100644 --- a/libempathy/empathy-debug.c +++ b/libempathy/empathy-debug.c @@ -43,7 +43,7 @@ static GDebugKey keys[] = { { "Contact", EMPATHY_DEBUG_CONTACT }, { "Account", EMPATHY_DEBUG_ACCOUNT }, { "Irc", EMPATHY_DEBUG_IRC }, - { "Filter", EMPATHY_DEBUG_FILTER }, + { "Dispatcher", EMPATHY_DEBUG_DISPATCHER }, { "Other", EMPATHY_DEBUG_OTHER }, { 0, } }; diff --git a/libempathy/empathy-debug.h b/libempathy/empathy-debug.h index 5f15b8c1b..42403ca15 100644 --- a/libempathy/empathy-debug.h +++ b/libempathy/empathy-debug.h @@ -37,7 +37,7 @@ typedef enum EMPATHY_DEBUG_CONTACT = 1 << 3, EMPATHY_DEBUG_ACCOUNT = 1 << 4, EMPATHY_DEBUG_IRC = 1 << 5, - EMPATHY_DEBUG_FILTER = 1 << 6, + EMPATHY_DEBUG_DISPATCHER = 1 << 6, EMPATHY_DEBUG_OTHER = 1 << 7, } EmpathyDebugFlags; diff --git a/libempathy/empathy-dispatcher.c b/libempathy/empathy-dispatcher.c new file mode 100644 index 000000000..741b01db6 --- /dev/null +++ b/libempathy/empathy-dispatcher.c @@ -0,0 +1,681 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2007-2008 Collabora Ltd. + * + * 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 + * + * Authors: Xavier Claessens <xclaesse@gmail.com> + */ + +#include <config.h> + +#include <string.h> + +#include <glib/gi18n.h> + +#include <telepathy-glib/enums.h> +#include <telepathy-glib/connection.h> +#include <telepathy-glib/util.h> +#include <telepathy-glib/dbus.h> +#include <telepathy-glib/proxy-subclass.h> + +#include <libmissioncontrol/mission-control.h> +#include <libmissioncontrol/mc-account.h> + +#include <extensions/extensions.h> + +#include "empathy-dispatcher.h" +#include "empathy-utils.h" +#include "empathy-tube-handler.h" +#include "empathy-contact-factory.h" + +#define DEBUG_FLAG EMPATHY_DEBUG_DISPATCHER +#include <libempathy/empathy-debug.h> + +#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyDispatcher) +typedef struct { + GHashTable *connections; + gpointer token; + MissionControl *mc; + GHashTable *tubes; +} EmpathyDispatcherPriv; + +G_DEFINE_TYPE (EmpathyDispatcher, empathy_dispatcher, G_TYPE_OBJECT); + +enum { + DISPATCH_CHANNEL, + FILTER_CHANNEL, + FILTER_TUBE, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; +static EmpathyDispatcher *dispatcher = NULL; + +void +empathy_dispatcher_channel_process (EmpathyDispatcher *dispatcher, + TpChannel *channel) +{ + g_signal_emit (dispatcher, signals[DISPATCH_CHANNEL], 0, channel); +} + +typedef struct { + EmpathyDispatcherTube public; + EmpathyContactFactory *factory; + gchar *bus_name; + gchar *object_path; + guint ref_count; + gboolean handled; +} DispatcherTube; + +GType +empathy_dispatcher_tube_get_type (void) +{ + static GType type_id = 0; + + if (!type_id) { + type_id = g_boxed_type_register_static ("EmpathyDispatcherTube", + (GBoxedCopyFunc) empathy_dispatcher_tube_ref, + (GBoxedFreeFunc) empathy_dispatcher_tube_unref); + } + + return type_id; +} + +EmpathyDispatcherTube * +empathy_dispatcher_tube_ref (EmpathyDispatcherTube *data) +{ + DispatcherTube *tube = (DispatcherTube*) data; + + g_return_val_if_fail (tube != NULL, NULL); + + tube->ref_count++; + + return data; +} + +void +empathy_dispatcher_tube_unref (EmpathyDispatcherTube *data) +{ + DispatcherTube *tube = (DispatcherTube*) data; + + g_return_if_fail (tube != NULL); + + if (--tube->ref_count == 0) { + if (!tube->handled) { + DEBUG ("Tube can't be handled, closing"); + tp_cli_channel_type_tubes_call_close_tube (tube->public.channel, -1, + tube->public.id, + NULL, NULL, NULL, + NULL); + } + + g_free (tube->bus_name); + g_free (tube->object_path); + g_object_unref (tube->factory); + g_object_unref (tube->public.channel); + g_object_unref (tube->public.initiator); + g_slice_free (DispatcherTube, tube); + } +} + +static void +dispatcher_tubes_handle_tube_cb (TpProxy *channel, + const GError *error, + gpointer user_data, + GObject *dispatcher) +{ + DispatcherTube *tube = user_data; + + if (error) { + DEBUG ("Error: %s", error->message); + } else { + tube->handled = TRUE; + } +} + +void +empathy_dispatcher_tube_process (EmpathyDispatcher *dispatcher, + EmpathyDispatcherTube *user_data) +{ + DispatcherTube *tube = (DispatcherTube*) user_data; + + if (tube->public.activatable) { + TpProxy *connection; + TpProxy *thandler; + gchar *object_path; + guint handle_type; + guint handle; + + /* Create the proxy for the tube handler */ + thandler = g_object_new (TP_TYPE_PROXY, + "dbus-connection", tp_get_bus (), + "bus-name", tube->bus_name, + "object-path", tube->object_path, + NULL); + tp_proxy_add_interface_by_id (thandler, EMP_IFACE_QUARK_TUBE_HANDLER); + + /* Give the tube to the handler */ + g_object_get (tube->public.channel, + "connection", &connection, + "object-path", &object_path, + "handle_type", &handle_type, + "handle", &handle, + NULL); + + DEBUG ("Dispatching tube"); + emp_cli_tube_handler_call_handle_tube (thandler, -1, + connection->bus_name, + connection->object_path, + object_path, handle_type, + handle, tube->public.id, + dispatcher_tubes_handle_tube_cb, + empathy_dispatcher_tube_ref (user_data), + (GDestroyNotify) empathy_dispatcher_tube_unref, + G_OBJECT (dispatcher)); + + g_object_unref (thandler); + g_object_unref (connection); + g_free (object_path); + } +} + +static void +dispatcher_tubes_new_tube_cb (TpChannel *channel, + guint id, + guint initiator, + guint type, + const gchar *service, + GHashTable *parameters, + guint state, + gpointer user_data, + GObject *dispatcher) +{ + EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); + static TpDBusDaemon *daemon = NULL; + DispatcherTube *tube; + McAccount *account; + guint number; + gchar **names; + gboolean running = FALSE; + GError *error = NULL; + + /* Increase tube count */ + number = GPOINTER_TO_UINT (g_hash_table_lookup (priv->tubes, channel)); + g_hash_table_replace (priv->tubes, g_object_ref (channel), + GUINT_TO_POINTER (++number)); + DEBUG ("Increased tube count for channel %p: %d", channel, number); + + /* We dispatch only local pending tubes */ + if (state != TP_TUBE_STATE_LOCAL_PENDING) { + return; + } + + if (!daemon) { + daemon = tp_dbus_daemon_new (tp_get_bus ()); + } + + account = empathy_channel_get_account (channel); + tube = g_slice_new (DispatcherTube); + tube->ref_count = 1; + tube->handled = FALSE; + tube->factory = empathy_contact_factory_new (); + tube->bus_name = empathy_tube_handler_build_bus_name (type, service); + tube->object_path = empathy_tube_handler_build_object_path (type, service); + tube->public.activatable = FALSE; + tube->public.id = id; + tube->public.channel = g_object_ref (channel); + tube->public.initiator = empathy_contact_factory_get_from_handle (tube->factory, + account, + initiator); + g_object_unref (account); + + /* Check if that bus-name has an owner, if it has one that means the + * app is already running and we can directly give the channel. */ + tp_cli_dbus_daemon_run_name_has_owner (daemon, -1, tube->bus_name, + &running, NULL, NULL); + if (running) { + DEBUG ("Tube handler running"); + tube->public.activatable = TRUE; + empathy_dispatcher_tube_process (EMPATHY_DISPATCHER (dispatcher), + (EmpathyDispatcherTube*) tube); + empathy_dispatcher_tube_unref ((EmpathyDispatcherTube*) tube); + return; + } + + /* Check if that bus-name is activatable, if not that means the + * application needed to handle this tube isn't installed. */ + if (!tp_cli_dbus_daemon_run_list_activatable_names (daemon, -1, + &names, &error, + NULL)) { + DEBUG ("Error listing activatable names: %s", error->message); + g_clear_error (&error); + } else { + gchar **name; + + for (name = names; *name; name++) { + if (!tp_strdiff (*name, tube->bus_name)) { + tube->public.activatable = TRUE; + break; + } + } + g_strfreev (names); + } + + g_signal_emit (dispatcher, signals[FILTER_TUBE], 0, tube); + empathy_dispatcher_tube_unref ((EmpathyDispatcherTube*) tube); +} + +static void +dispatcher_tubes_list_tubes_cb (TpChannel *channel, + const GPtrArray *tubes, + const GError *error, + gpointer user_data, + GObject *dispatcher) +{ + guint i; + + if (error) { + DEBUG ("Error: %s", error->message); + return; + } + + for (i = 0; i < tubes->len; i++) { + GValueArray *values; + + values = g_ptr_array_index (tubes, i); + dispatcher_tubes_new_tube_cb (channel, + g_value_get_uint (g_value_array_get_nth (values, 0)), + g_value_get_uint (g_value_array_get_nth (values, 1)), + g_value_get_uint (g_value_array_get_nth (values, 2)), + g_value_get_string (g_value_array_get_nth (values, 3)), + g_value_get_boxed (g_value_array_get_nth (values, 4)), + g_value_get_uint (g_value_array_get_nth (values, 5)), + user_data, dispatcher); + } +} + +static void +dispatcher_tubes_channel_invalidated_cb (TpProxy *proxy, + guint domain, + gint code, + gchar *message, + EmpathyDispatcher *dispatcher) +{ + EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); + + DEBUG ("Error: %s", message); + + g_hash_table_remove (priv->tubes, proxy); +} + +static void +dispatcher_tubes_tube_closed_cb (TpChannel *channel, + guint id, + gpointer user_data, + GObject *dispatcher) +{ + EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); + guint number; + + number = GPOINTER_TO_UINT (g_hash_table_lookup (priv->tubes, channel)); + if (number == 1) { + DEBUG ("No more tube, closing channel"); + tp_cli_channel_call_close (channel, -1, NULL, NULL, NULL, NULL); + } + else if (number > 1) { + DEBUG ("Decrease tube count: %d", number); + g_hash_table_replace (priv->tubes, g_object_ref (channel), + GUINT_TO_POINTER (--number)); + } +} + +static void +dispatcher_tubes_handle_channel (EmpathyDispatcher *dispatcher, + TpChannel *channel) +{ + EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); + + if (g_hash_table_lookup (priv->tubes, channel)) { + return; + } + + DEBUG ("Handling new channel"); + + g_hash_table_insert (priv->tubes, g_object_ref (channel), + GUINT_TO_POINTER (0)); + + g_signal_connect (channel, "invalidated", + G_CALLBACK (dispatcher_tubes_channel_invalidated_cb), + dispatcher); + + tp_cli_channel_type_tubes_connect_to_tube_closed (channel, + dispatcher_tubes_tube_closed_cb, + NULL, NULL, + G_OBJECT (dispatcher), NULL); + tp_cli_channel_type_tubes_connect_to_new_tube (channel, + dispatcher_tubes_new_tube_cb, + NULL, NULL, + G_OBJECT (dispatcher), NULL); + tp_cli_channel_type_tubes_call_list_tubes (channel, -1, + dispatcher_tubes_list_tubes_cb, + NULL, NULL, + G_OBJECT (dispatcher)); +} + +static void +dispatcher_connection_invalidated_cb (TpConnection *connection, + guint domain, + gint code, + gchar *message, + EmpathyDispatcher *dispatcher) +{ + EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); + GHashTableIter iter; + gpointer key, value; + + DEBUG ("Error: %s", message); + + g_hash_table_iter_init (&iter, priv->connections); + while (g_hash_table_iter_next (&iter, &key, &value)) { + if (value == connection) { + g_hash_table_remove (priv->connections, key); + break; + } + } +} + +static void +dispatcher_connection_new_channel_cb (TpConnection *connection, + const gchar *object_path, + const gchar *channel_type, + guint handle_type, + guint handle, + gboolean suppress_handler, + gpointer user_data, + GObject *object) +{ + EmpathyDispatcher *dispatcher = EMPATHY_DISPATCHER (object); + TpChannel *channel; + gpointer had_channels; + + had_channels = g_object_get_data (G_OBJECT (connection), "had-channels"); + if (had_channels == NULL) { + /* ListChannels didn't return yet, return to avoid duplicate + * dispatching */ + return; + } + + channel = tp_channel_new (connection, object_path, channel_type, + handle_type, handle, NULL); + tp_channel_run_until_ready (channel, NULL, NULL); + + if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TUBES)) { + dispatcher_tubes_handle_channel (dispatcher, channel); + } + + if (suppress_handler) { + g_signal_emit (dispatcher, signals[DISPATCH_CHANNEL], 0, channel); + } else { + g_signal_emit (dispatcher, signals[FILTER_CHANNEL], 0, channel); + } + + g_object_unref (channel); +} + +static void +dispatcher_connection_list_channels_cb (TpConnection *connection, + const GPtrArray *channels, + const GError *error, + gpointer user_data, + GObject *dispatcher) +{ + guint i; + + if (error) { + DEBUG ("Error: %s", error->message); + return; + } + + g_object_set_data (G_OBJECT (connection), "had-channels", + GUINT_TO_POINTER (1)); + + for (i = 0; i < channels->len; i++) { + GValueArray *values; + + values = g_ptr_array_index (channels, i); + dispatcher_connection_new_channel_cb (connection, + g_value_get_boxed (g_value_array_get_nth (values, 0)), + g_value_get_string (g_value_array_get_nth (values, 1)), + g_value_get_uint (g_value_array_get_nth (values, 2)), + g_value_get_uint (g_value_array_get_nth (values, 3)), + FALSE, user_data, dispatcher); + } +} + +static void +dispatcher_connection_advertise_capabilities_cb (TpConnection *connection, + const GPtrArray *capabilities, + const GError *error, + gpointer user_data, + GObject *dispatcher) +{ + if (error) { + DEBUG ("Error: %s", error->message); + } +} + +static void +dispatcher_connection_ready_cb (TpConnection *connection, + const GError *error, + gpointer dispatcher) +{ + GPtrArray *capabilities; + GType cap_type; + GValue cap = {0, }; + const gchar *remove = NULL; + + if (error) { + dispatcher_connection_invalidated_cb (connection, + error->domain, + error->code, + error->message, + dispatcher); + return; + } + + g_signal_connect (connection, "invalidated", + G_CALLBACK (dispatcher_connection_invalidated_cb), + dispatcher); + tp_cli_connection_connect_to_new_channel (connection, + dispatcher_connection_new_channel_cb, + NULL, NULL, + G_OBJECT (dispatcher), NULL); + tp_cli_connection_call_list_channels (connection, -1, + dispatcher_connection_list_channels_cb, + NULL, NULL, + G_OBJECT (dispatcher)); + + /* Advertise VoIP capabilities */ + capabilities = g_ptr_array_sized_new (1); + cap_type = dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, + G_TYPE_UINT, G_TYPE_INVALID); + g_value_init (&cap, cap_type); + g_value_take_boxed (&cap, dbus_g_type_specialized_construct (cap_type)); + dbus_g_type_struct_set (&cap, + 0, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, + 1, TP_CHANNEL_MEDIA_CAPABILITY_AUDIO | + TP_CHANNEL_MEDIA_CAPABILITY_VIDEO | + TP_CHANNEL_MEDIA_CAPABILITY_NAT_TRAVERSAL_STUN | + TP_CHANNEL_MEDIA_CAPABILITY_NAT_TRAVERSAL_GTALK_P2P, + G_MAXUINT); + g_ptr_array_add (capabilities, g_value_get_boxed (&cap)); + + tp_cli_connection_interface_capabilities_call_advertise_capabilities ( + connection, -1, + capabilities, &remove, + dispatcher_connection_advertise_capabilities_cb, + NULL, NULL, G_OBJECT (dispatcher)); + /* FIXME: Is that leaked? */ +} + +static void +dispatcher_update_account (EmpathyDispatcher *dispatcher, + McAccount *account) +{ + EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); + TpConnection *connection; + + connection = g_hash_table_lookup (priv->connections, account); + if (connection) { + return; + } + + connection = mission_control_get_tpconnection (priv->mc, account, NULL); + if (!connection) { + return; + } + + g_hash_table_insert (priv->connections, g_object_ref (account), connection); + tp_connection_call_when_ready (connection, + dispatcher_connection_ready_cb, + dispatcher); +} + +static void +dispatcher_status_changed_cb (MissionControl *mc, + TpConnectionStatus status, + McPresence presence, + TpConnectionStatusReason reason, + const gchar *unique_name, + EmpathyDispatcher *dispatcher) +{ + McAccount *account; + + account = mc_account_lookup (unique_name); + dispatcher_update_account (dispatcher, account); + g_object_unref (account); +} + +static guint +dispatcher_channel_hash (gconstpointer key) +{ + TpProxy *channel = TP_PROXY (key); + + return g_str_hash (channel->object_path); +} + +static gboolean +dispatcher_channel_equal (gconstpointer a, + gconstpointer b) +{ + TpProxy *channel_a = TP_PROXY (a); + TpProxy *channel_b = TP_PROXY (b); + + return g_str_equal (channel_a->object_path, channel_b->object_path); +} + +static void +dispatcher_finalize (GObject *object) +{ + EmpathyDispatcherPriv *priv = GET_PRIV (object); + + empathy_disconnect_account_status_changed (priv->token); + g_object_unref (priv->mc); + + g_hash_table_destroy (priv->connections); + g_hash_table_destroy (priv->tubes); +} + +static void +empathy_dispatcher_class_init (EmpathyDispatcherClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = dispatcher_finalize; + + signals[DISPATCH_CHANNEL] = + g_signal_new ("dispatch-channel", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, TP_TYPE_CHANNEL); + signals[FILTER_CHANNEL] = + g_signal_new ("filter-channel", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, TP_TYPE_CHANNEL); + signals[FILTER_TUBE] = + g_signal_new ("filter-tube", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__BOXED, + G_TYPE_NONE, + 1, EMPATHY_TYPE_DISPATCHER_TUBE); + + g_type_class_add_private (object_class, sizeof (EmpathyDispatcherPriv)); +} + +static void +empathy_dispatcher_init (EmpathyDispatcher *dispatcher) +{ + GList *accounts, *l; + EmpathyDispatcherPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (dispatcher, + EMPATHY_TYPE_DISPATCHER, EmpathyDispatcherPriv); + + dispatcher->priv = priv; + priv->tubes = g_hash_table_new_full (dispatcher_channel_hash, + dispatcher_channel_equal, + g_object_unref, NULL); + + priv->mc = empathy_mission_control_new (); + priv->token = empathy_connect_to_account_status_changed (priv->mc, + G_CALLBACK (dispatcher_status_changed_cb), + dispatcher, NULL); + + priv->connections = g_hash_table_new_full (empathy_account_hash, + empathy_account_equal, + g_object_unref, + g_object_unref); + accounts = mc_accounts_list_by_enabled (TRUE); + for (l = accounts; l; l = l->next) { + dispatcher_update_account (dispatcher, l->data); + g_object_unref (l->data); + } + g_list_free (accounts); +} + +EmpathyDispatcher * +empathy_dispatcher_new (void) +{ + if (!dispatcher) { + dispatcher = g_object_new (EMPATHY_TYPE_DISPATCHER, NULL); + g_object_add_weak_pointer (G_OBJECT (dispatcher), (gpointer) &dispatcher); + } else { + g_object_ref (dispatcher); + } + + return dispatcher; +} + diff --git a/libempathy/empathy-dispatcher.h b/libempathy/empathy-dispatcher.h new file mode 100644 index 000000000..0cc59c8b8 --- /dev/null +++ b/libempathy/empathy-dispatcher.h @@ -0,0 +1,72 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2007-2008 Collabora Ltd. + * + * 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 + * + * Authors: Xavier Claessens <xclaesse@gmail.com> + */ + +#ifndef __EMPATHY_DISPATCHER_H__ +#define __EMPATHY_DISPATCHER_H__ + +#include <glib.h> + +#include <telepathy-glib/channel.h> + +#include "empathy-contact.h" + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_DISPATCHER (empathy_dispatcher_get_type ()) +#define EMPATHY_DISPATCHER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_DISPATCHER, EmpathyDispatcher)) +#define EMPATHY_DISPATCHER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EMPATHY_TYPE_DISPATCHER, EmpathyDispatcherClass)) +#define EMPATHY_IS_DISPATCHER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_DISPATCHER)) +#define EMPATHY_IS_DISPATCHER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_DISPATCHER)) +#define EMPATHY_DISPATCHER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_DISPATCHER, EmpathyDispatcherClass)) + +typedef struct _EmpathyDispatcher EmpathyDispatcher; +typedef struct _EmpathyDispatcherClass EmpathyDispatcherClass; + +struct _EmpathyDispatcher { + GObject parent; + gpointer priv; +}; + +struct _EmpathyDispatcherClass { + GObjectClass parent_class; +}; + +#define EMPATHY_TYPE_DISPATCHER_TUBE (empathy_dispatcher_tube_get_type ()) +typedef struct { + EmpathyContact *initiator; + TpChannel *channel; + guint id; + gboolean activatable; +} EmpathyDispatcherTube; + +GType empathy_dispatcher_get_type (void) G_GNUC_CONST; +EmpathyDispatcher * empathy_dispatcher_new (void); +void empathy_dispatcher_channel_process(EmpathyDispatcher *dispatcher, + TpChannel *channel); +GType empathy_dispatcher_tube_get_type (void); +EmpathyDispatcherTube *empathy_dispatcher_tube_ref (EmpathyDispatcherTube *tube); +void empathy_dispatcher_tube_unref (EmpathyDispatcherTube *tube); +void empathy_dispatcher_tube_process (EmpathyDispatcher *dispatcher, + EmpathyDispatcherTube *tube); + +G_END_DECLS + +#endif /* __EMPATHY_DISPATCHER_H__ */ diff --git a/src/Makefile.am b/src/Makefile.am index f82bac38e..dc87087ec 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -31,7 +31,6 @@ empathy_SOURCES = \ empathy-main-window.c empathy-main-window.h \ empathy-preferences.c empathy-preferences.h \ empathy-call-window.c empathy-call-window.h \ - empathy-filter.c empathy-filter.h \ ephy-spinner.c ephy-spinner.h empathy_accounts_SOURCES = empathy-accounts.c diff --git a/src/empathy-filter.c b/src/empathy-filter.c deleted file mode 100644 index e1305fe11..000000000 --- a/src/empathy-filter.c +++ /dev/null @@ -1,1001 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2007-2008 Collabora Ltd. - * - * 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 - * - * Authors: Xavier Claessens <xclaesse@gmail.com> - */ - -#include <config.h> - -#include <string.h> - -#include <glib/gi18n.h> - -#include <telepathy-glib/enums.h> -#include <telepathy-glib/channel.h> -#include <telepathy-glib/connection.h> -#include <telepathy-glib/util.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/proxy-subclass.h> - -#include <libmissioncontrol/mission-control.h> -#include <libmissioncontrol/mc-account.h> - -#include <extensions/extensions.h> - -#include <libempathy/empathy-tp-chat.h> -#include <libempathy/empathy-tp-call.h> -#include <libempathy/empathy-tp-group.h> -#include <libempathy/empathy-utils.h> -#include <libempathy/empathy-tube-handler.h> -#include <libempathy/empathy-contact-factory.h> - -#include <libempathy-gtk/empathy-chat.h> -#include <libempathy-gtk/empathy-images.h> -#include <libempathy-gtk/empathy-contact-dialogs.h> - -#include "empathy-filter.h" -#include "empathy-chat-window.h" -#include "empathy-call-window.h" - -#define DEBUG_FLAG EMPATHY_DEBUG_FILTER -#include <libempathy/empathy-debug.h> - -#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyFilter) -typedef struct { - GSList *events; - GHashTable *accounts; - gpointer token; - MissionControl *mc; - GHashTable *tubes; -} EmpathyFilterPriv; - -G_DEFINE_TYPE (EmpathyFilter, empathy_filter, G_TYPE_OBJECT); - -enum { - PROP_0, - PROP_TOP_EVENT, -}; - -typedef void (*FilterFunc) (EmpathyFilter *filter, - gpointer user_data); - -typedef struct { - EmpathyFilterEvent public; - FilterFunc func; - gpointer user_data; -} EmpathyFilterEventExt; - -static guint -filter_channel_hash (gconstpointer key) -{ - TpProxy *channel = TP_PROXY (key); - - return g_str_hash (channel->object_path); -} - -static gboolean -filter_channel_equal (gconstpointer a, - gconstpointer b) -{ - TpProxy *channel_a = TP_PROXY (a); - TpProxy *channel_b = TP_PROXY (b); - - return g_str_equal (channel_a->object_path, channel_b->object_path); -} - -static void -filter_event_free (EmpathyFilterEventExt *event) -{ - g_free (event->public.icon_name); - g_free (event->public.message); - g_slice_free (EmpathyFilterEventExt, event); -} - -static void -filter_emit_event (EmpathyFilter *filter, - const gchar *icon_name, - const gchar *message, - FilterFunc func, - gpointer user_data) -{ - EmpathyFilterPriv *priv = GET_PRIV (filter); - EmpathyFilterEventExt *event; - - DEBUG ("Emit event, icon_name=%s message='%s'", icon_name, message); - - event = g_slice_new0 (EmpathyFilterEventExt); - event->func = func; - event->user_data = user_data; - event->public.icon_name = g_strdup (icon_name); - event->public.message = g_strdup (message); - - priv->events = g_slist_append (priv->events, event); - if (priv->events->data == event) { - g_object_notify (G_OBJECT (filter), "top-event"); - } -} - -void -empathy_filter_activate_event (EmpathyFilter *filter, - EmpathyFilterEvent *event) -{ - EmpathyFilterPriv *priv = GET_PRIV (filter); - EmpathyFilterEventExt *event_ext; - GSList *l; - gboolean is_top; - - g_return_if_fail (EMPATHY_IS_FILTER (filter)); - g_return_if_fail (event != NULL); - - if (!(l = g_slist_find (priv->events, event))) { - return; - } - - DEBUG ("Activating event"); - - is_top = (l == priv->events); - priv->events = g_slist_delete_link (priv->events, l); - if (is_top) { - g_object_notify (G_OBJECT (filter), "top-event"); - } - - event_ext = (EmpathyFilterEventExt*) event; - if (event_ext->func) { - event_ext->func (filter, event_ext->user_data); - } - - filter_event_free (event_ext); -} - -EmpathyFilterEvent * -empathy_filter_get_top_event (EmpathyFilter *filter) -{ - EmpathyFilterPriv *priv = GET_PRIV (filter); - - g_return_val_if_fail (EMPATHY_IS_FILTER (filter), NULL); - - return priv->events ? priv->events->data : NULL; -} - -static void -filter_chat_dispatch (EmpathyFilter *filter, - gpointer user_data) -{ - EmpathyTpChat *tp_chat = EMPATHY_TP_CHAT (user_data); - EmpathyChat *chat = NULL; - const gchar *id; - - id = empathy_tp_chat_get_id (tp_chat); - if (!id) { - EmpathyContact *contact; - - contact = empathy_tp_chat_get_remote_contact (tp_chat); - if (contact) { - id = empathy_contact_get_id (contact); - } - } - - if (id) { - McAccount *account; - - account = empathy_tp_chat_get_account (tp_chat); - chat = empathy_chat_window_find_chat (account, id); - } - - if (chat) { - empathy_chat_set_tp_chat (chat, tp_chat); - } else { - chat = empathy_chat_new (tp_chat); - } - - empathy_chat_window_present_chat (chat); - g_object_unref (tp_chat); -} - -static void -filter_chat_message_received_cb (EmpathyTpChat *tp_chat, - EmpathyMessage *message, - EmpathyFilter *filter) -{ - EmpathyContact *sender; - gchar *msg; - - g_signal_handlers_disconnect_by_func (tp_chat, - filter_chat_message_received_cb, - filter); - - sender = empathy_message_get_sender (message); - msg = g_strdup_printf (_("New message from %s:\n%s"), - empathy_contact_get_name (sender), - empathy_message_get_body (message)); - - filter_emit_event (filter, EMPATHY_IMAGE_NEW_MESSAGE, msg, - filter_chat_dispatch, tp_chat); - - g_free (msg); -} - -static void -filter_chat_handle_channel (EmpathyFilter *filter, - TpChannel *channel, - gboolean is_incoming) -{ - EmpathyTpChat *tp_chat; - - DEBUG ("New text channel to be filtered: %p", channel); - - tp_chat = empathy_tp_chat_new (channel, FALSE); - empathy_run_until_ready (tp_chat); - if (is_incoming) { - filter_chat_dispatch (filter, tp_chat); - } else { - g_signal_connect (tp_chat, "message-received", - G_CALLBACK (filter_chat_message_received_cb), - filter); - } -} - -static void -filter_call_dispatch (EmpathyFilter *filter, - gpointer user_data) -{ - EmpathyTpCall *call = EMPATHY_TP_CALL (user_data); - - empathy_call_window_new (call); - g_object_unref (call); -} - -static void -filter_call_contact_notify_cb (EmpathyTpCall *call, - gpointer unused, - EmpathyFilter *filter) -{ - EmpathyContact *contact; - gchar *msg; - - g_object_get (call, "contact", &contact, NULL); - if (!contact) { - return; - } - - empathy_contact_run_until_ready (contact, - EMPATHY_CONTACT_READY_NAME, - NULL); - - msg = g_strdup_printf (_("Incoming call from %s"), - empathy_contact_get_name (contact)); - - filter_emit_event (filter, EMPATHY_IMAGE_VOIP, msg, - filter_call_dispatch, call); - - g_free (msg); - g_object_unref (contact); -} - -static void -filter_call_handle_channel (EmpathyFilter *filter, - TpChannel *channel, - gboolean is_incoming) -{ - EmpathyTpCall *call; - - DEBUG ("New media channel to be filtered: %p", channel); - - call = empathy_tp_call_new (channel); - if (is_incoming) { - filter_call_dispatch (filter, call); - } else { - g_signal_connect (call, "notify::contact", - G_CALLBACK (filter_call_contact_notify_cb), - filter); - } -} - -static void -filter_contact_list_subscribe (EmpathyFilter *filter, - gpointer user_data) -{ - EmpathyContact *contact = EMPATHY_CONTACT (user_data); - - empathy_subscription_dialog_show (contact, NULL); - g_object_unref (contact); -} - -static void -filter_contact_list_local_pending_cb (EmpathyTpGroup *group, - EmpathyContact *contact, - EmpathyContact *actor, - guint reason, - gchar *message, - EmpathyFilter *filter) -{ - GString *str; - - DEBUG ("New local pending contact"); - - empathy_contact_run_until_ready (contact, - EMPATHY_CONTACT_READY_NAME, - NULL); - - str = g_string_new (NULL); - g_string_printf (str, _("Subscription requested by %s"), - empathy_contact_get_name (contact)); - if (!G_STR_EMPTY (message)) { - g_string_append_printf (str, _("\nMessage: %s"), message); - } - - filter_emit_event (filter, GTK_STOCK_DIALOG_QUESTION, str->str, - filter_contact_list_subscribe, - g_object_ref (contact)); - - g_string_free (str, TRUE); -} - -static void -filter_contact_list_ready_cb (EmpathyTpGroup *group, - gpointer unused, - EmpathyFilter *filter) -{ - GList *pendings, *l; - - if (tp_strdiff ("publish", empathy_tp_group_get_name (group))) { - g_object_unref (group); - return; - } - - DEBUG ("Publish contact list ready"); - - g_signal_connect (group, "local-pending", - G_CALLBACK (filter_contact_list_local_pending_cb), - filter); - - pendings = empathy_tp_group_get_local_pendings (group); - for (l = pendings; l; l = l->next) { - EmpathyPendingInfo *info = l->data; - - filter_contact_list_local_pending_cb (group, info->member, - info->actor, info->reason, - info->message, filter); - empathy_pending_info_free (info); - } - g_list_free (pendings); -} - -static void -filter_tubes_async_cb (TpProxy *channel, - const GError *error, - gpointer user_data, - GObject *filter) -{ - if (error) { - DEBUG ("Error %s: %s", (gchar*) user_data, error->message); - } -} - -typedef struct { - EmpathyContactFactory *factory; - EmpathyContact *initiator; - TpChannel *channel; - guint id; - gchar *bus_name; - gchar *object_path; - gboolean activatable; -} FilterTubesData; - -static void -filter_tubes_dispatch (EmpathyFilter *filter, - gpointer user_data) -{ - FilterTubesData *data = user_data; - - if (data->activatable) { - TpProxy *connection; - TpProxy *thandler; - gchar *object_path; - guint handle_type; - guint handle; - - /* Create the proxy for the tube handler */ - thandler = g_object_new (TP_TYPE_PROXY, - "dbus-connection", tp_get_bus (), - "bus-name", data->bus_name, - "object-path", data->object_path, - NULL); - tp_proxy_add_interface_by_id (thandler, EMP_IFACE_QUARK_TUBE_HANDLER); - - /* Give the tube to the handler */ - g_object_get (data->channel, - "connection", &connection, - "object-path", &object_path, - "handle_type", &handle_type, - "handle", &handle, - NULL); - - DEBUG ("Dispatching tube"); - emp_cli_tube_handler_call_handle_tube (thandler, -1, - connection->bus_name, - connection->object_path, - object_path, handle_type, - handle, data->id, - filter_tubes_async_cb, - "handling tube", NULL, - G_OBJECT (filter)); - - g_object_unref (thandler); - g_object_unref (connection); - g_free (object_path); - } else { - GtkWidget *dialog; - gchar *str; - - /* Tell the user that the tube can't be handled */ - str = g_strdup_printf (_("%s offered you an invitation, but " - "you don't have the needed external " - "application to handle it."), - empathy_contact_get_name (data->initiator)); - - dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, str); - gtk_window_set_title (GTK_WINDOW (dialog), - _("Invitation Error")); - g_free (str); - - gtk_widget_show (dialog); - g_signal_connect (dialog, "response", - G_CALLBACK (gtk_widget_destroy), - NULL); - - DEBUG ("Tube can't be handled, closing"); - tp_cli_channel_type_tubes_call_close_tube (data->channel, -1, - data->id, - NULL, NULL, NULL, - NULL); - } - - g_free (data->bus_name); - g_free (data->object_path); - g_object_unref (data->channel); - g_object_unref (data->initiator); - g_object_unref (data->factory); - g_slice_free (FilterTubesData, data); -} - -static void -filter_tubes_new_tube_cb (TpChannel *channel, - guint id, - guint initiator, - guint type, - const gchar *service, - GHashTable *parameters, - guint state, - gpointer user_data, - GObject *filter) -{ - EmpathyFilterPriv *priv = GET_PRIV (filter); - static TpDBusDaemon *daemon = NULL; - FilterTubesData *data; - McAccount *account; - guint number; - gchar *msg; - gchar **names; - gboolean running = FALSE; - const gchar *icon_name; - GError *error = NULL; - - /* Increase tube count */ - number = GPOINTER_TO_UINT (g_hash_table_lookup (priv->tubes, channel)); - g_hash_table_replace (priv->tubes, g_object_ref (channel), - GUINT_TO_POINTER (++number)); - DEBUG ("Increased tube count for channel %p: %d", channel, number); - - /* We dispatch only local pending tubes */ - if (state != TP_TUBE_STATE_LOCAL_PENDING) { - return; - } - - if (!daemon) { - daemon = tp_dbus_daemon_new (tp_get_bus ()); - } - - account = empathy_channel_get_account (channel); - data = g_slice_new (FilterTubesData); - data->activatable = FALSE; - data->id = id; - data->channel = g_object_ref (channel); - data->factory = empathy_contact_factory_new (); - data->initiator = empathy_contact_factory_get_from_handle (data->factory, - account, - initiator); - data->bus_name = empathy_tube_handler_build_bus_name (type, service); - data->object_path = empathy_tube_handler_build_object_path (type, service); - g_object_unref (account); - - /* Check if that bus-name has an owner, if it has one that means the - * app is already running and we can directly give the channel. */ - tp_cli_dbus_daemon_run_name_has_owner (daemon, -1, data->bus_name, - &running, NULL, NULL); - if (running) { - DEBUG ("Tube handler running"); - data->activatable = TRUE; - filter_tubes_dispatch (EMPATHY_FILTER (filter), data); - return; - } - - /* Check if that bus-name is activatable, if not that means the - * application needed to handle this tube isn't installed. */ - if (!tp_cli_dbus_daemon_run_list_activatable_names (daemon, -1, - &names, &error, - NULL)) { - DEBUG ("Error listing activatable names: %s", error->message); - g_clear_error (&error); - } else { - gchar **name; - - for (name = names; *name; name++) { - if (!tp_strdiff (*name, data->bus_name)) { - data->activatable = TRUE; - break; - } - } - g_strfreev (names); - } - - empathy_contact_run_until_ready (data->initiator, - EMPATHY_CONTACT_READY_NAME, NULL); - - if (data->activatable) { - icon_name = GTK_STOCK_EXECUTE; - msg = g_strdup_printf (_("%s is offering you an invitation. An external " - "application will be started to handle it."), - empathy_contact_get_name (data->initiator)); - } else { - icon_name = GTK_STOCK_DIALOG_ERROR; - msg = g_strdup_printf (_("%s is offering you an invitation, but " - "you don't have the needed external " - "application to handle it."), - empathy_contact_get_name (data->initiator)); - } - - filter_emit_event (EMPATHY_FILTER (filter), icon_name, msg, - filter_tubes_dispatch, data); - - g_free (msg); -} - -static void -filter_tubes_list_tubes_cb (TpChannel *channel, - const GPtrArray *tubes, - const GError *error, - gpointer user_data, - GObject *filter) -{ - guint i; - - if (error) { - DEBUG ("Error listing tubes: %s", error->message); - return; - } - - for (i = 0; i < tubes->len; i++) { - GValueArray *values; - - values = g_ptr_array_index (tubes, i); - filter_tubes_new_tube_cb (channel, - g_value_get_uint (g_value_array_get_nth (values, 0)), - g_value_get_uint (g_value_array_get_nth (values, 1)), - g_value_get_uint (g_value_array_get_nth (values, 2)), - g_value_get_string (g_value_array_get_nth (values, 3)), - g_value_get_boxed (g_value_array_get_nth (values, 4)), - g_value_get_uint (g_value_array_get_nth (values, 5)), - user_data, filter); - } -} - -static void -filter_tubes_channel_invalidated_cb (TpProxy *proxy, - guint domain, - gint code, - gchar *message, - EmpathyFilter *filter) -{ - EmpathyFilterPriv *priv = GET_PRIV (filter); - - DEBUG ("Channel %p invalidated: %s", proxy, message); - - g_hash_table_remove (priv->tubes, proxy); -} - -static void -filter_tubes_tube_closed_cb (TpChannel *channel, - guint id, - gpointer user_data, - GObject *filter) -{ - EmpathyFilterPriv *priv = GET_PRIV (filter); - guint number; - - number = GPOINTER_TO_UINT (g_hash_table_lookup (priv->tubes, channel)); - if (number == 1) { - DEBUG ("Ended tube count for channel %p, closing channel", - channel); - tp_cli_channel_call_close (channel, -1, NULL, NULL, NULL, NULL); - } - else if (number > 1) { - DEBUG ("Decrease tube count for channel %p: %d", channel, number); - g_hash_table_replace (priv->tubes, g_object_ref (channel), - GUINT_TO_POINTER (--number)); - } -} - -static void -filter_tubes_handle_channel (EmpathyFilter *filter, - TpChannel *channel, - gboolean is_incoming) -{ - EmpathyFilterPriv *priv = GET_PRIV (filter); - - if (g_hash_table_lookup (priv->tubes, channel)) { - return; - } - - DEBUG ("Handling new channel"); - - g_hash_table_insert (priv->tubes, g_object_ref (channel), - GUINT_TO_POINTER (0)); - - g_signal_connect (channel, "invalidated", - G_CALLBACK (filter_tubes_channel_invalidated_cb), - filter); - - tp_cli_channel_type_tubes_connect_to_tube_closed (channel, - filter_tubes_tube_closed_cb, - NULL, NULL, - G_OBJECT (filter), NULL); - tp_cli_channel_type_tubes_connect_to_new_tube (channel, - filter_tubes_new_tube_cb, - NULL, NULL, - G_OBJECT (filter), NULL); - tp_cli_channel_type_tubes_call_list_tubes (channel, -1, - filter_tubes_list_tubes_cb, - NULL, NULL, - G_OBJECT (filter)); -} - -static void -filter_contact_list_destroy_cb (EmpathyTpGroup *group, - EmpathyFilter *filter) -{ - g_object_unref (group); -} - -static void -filter_contact_list_handle_channel (EmpathyFilter *filter, - TpChannel *channel, - gboolean is_incoming) -{ - EmpathyTpGroup *group; - - group = empathy_tp_group_new (channel); - g_signal_connect (group, "notify::ready", - G_CALLBACK (filter_contact_list_ready_cb), - filter); - g_signal_connect (group, "destroy", - G_CALLBACK (filter_contact_list_destroy_cb), - filter); -} - -static void -filter_connection_invalidated_cb (TpConnection *connection, - guint domain, - gint code, - gchar *message, - EmpathyFilter *filter) -{ - EmpathyFilterPriv *priv = GET_PRIV (filter); - GHashTableIter iter; - gpointer key, value; - - DEBUG ("connection invalidated: %s", message); - - g_hash_table_iter_init (&iter, priv->accounts); - while (g_hash_table_iter_next (&iter, &key, &value)) { - if (value == connection) { - g_hash_table_remove (priv->accounts, key); - break; - } - } -} - -typedef void (*HandleChannelFunc) (EmpathyFilter *filter, - TpChannel *channel, - gboolean is_incoming); - -static void -filter_conection_new_channel_cb (TpConnection *connection, - const gchar *object_path, - const gchar *channel_type, - guint handle_type, - guint handle, - gboolean suppress_handler, - gpointer user_data, - GObject *filter) -{ - HandleChannelFunc func = NULL; - TpChannel *channel; - gpointer had_channels; - - had_channels = g_object_get_data (G_OBJECT (connection), "had-channels"); - if (had_channels == NULL) { - return; - } - - if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TEXT)) { - func = filter_chat_handle_channel; - } - else if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA)) { - func = filter_call_handle_channel; - } - else if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST)) { - func = filter_contact_list_handle_channel; - } - else if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TUBES)) { - func = filter_tubes_handle_channel; - } else { - DEBUG ("Unknown channel type %s", channel_type); - return; - } - - channel = tp_channel_new (connection, object_path, channel_type, - handle_type, handle, NULL); - tp_channel_run_until_ready (channel, NULL, NULL); - - /* We abuse of suppress_handler, TRUE means OUTGOING */ - func (EMPATHY_FILTER (filter), channel, suppress_handler); - - g_object_unref (channel); -} - -static void -filter_connection_list_channels_cb (TpConnection *connection, - const GPtrArray *channels, - const GError *error, - gpointer user_data, - GObject *filter) -{ - guint i; - - if (error) { - DEBUG ("Error listing channels: %s", error->message); - return; - } - - g_object_set_data (G_OBJECT (connection), "had-channels", - GUINT_TO_POINTER (1)); - - for (i = 0; i < channels->len; i++) { - GValueArray *values; - - values = g_ptr_array_index (channels, i); - filter_conection_new_channel_cb (connection, - g_value_get_boxed (g_value_array_get_nth (values, 0)), - g_value_get_string (g_value_array_get_nth (values, 1)), - g_value_get_uint (g_value_array_get_nth (values, 2)), - g_value_get_uint (g_value_array_get_nth (values, 3)), - TRUE, user_data, filter); - } -} - -static void -filter_connection_advertise_capabilities_cb (TpConnection *connection, - const GPtrArray *capabilities, - const GError *error, - gpointer user_data, - GObject *filter) -{ - if (error) { - DEBUG ("Error advertising capabilities: %s", error->message); - } -} - -static void -filter_connection_ready_cb (TpConnection *connection, - gpointer unused, - EmpathyFilter *filter) -{ - GPtrArray *capabilities; - GType cap_type; - GValue cap = {0, }; - const gchar *remove = NULL; - - DEBUG ("Connection ready, accepting new channels"); - - tp_cli_connection_connect_to_new_channel (connection, - filter_conection_new_channel_cb, - NULL, NULL, - G_OBJECT (filter), NULL); - tp_cli_connection_call_list_channels (connection, -1, - filter_connection_list_channels_cb, - NULL, NULL, - G_OBJECT (filter)); - - /* Advertise VoIP capabilities */ - capabilities = g_ptr_array_sized_new (1); - cap_type = dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, - G_TYPE_UINT, G_TYPE_INVALID); - g_value_init (&cap, cap_type); - g_value_take_boxed (&cap, dbus_g_type_specialized_construct (cap_type)); - dbus_g_type_struct_set (&cap, - 0, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, - 1, TP_CHANNEL_MEDIA_CAPABILITY_AUDIO | - TP_CHANNEL_MEDIA_CAPABILITY_VIDEO | - TP_CHANNEL_MEDIA_CAPABILITY_NAT_TRAVERSAL_STUN | - TP_CHANNEL_MEDIA_CAPABILITY_NAT_TRAVERSAL_GTALK_P2P, - G_MAXUINT); - g_ptr_array_add (capabilities, g_value_get_boxed (&cap)); - - tp_cli_connection_interface_capabilities_call_advertise_capabilities ( - connection, -1, - capabilities, &remove, - filter_connection_advertise_capabilities_cb, - NULL, NULL, G_OBJECT (filter)); -} - -static void -filter_update_account (EmpathyFilter *filter, - McAccount *account) -{ - EmpathyFilterPriv *priv = GET_PRIV (filter); - TpConnection *connection; - gboolean ready; - - connection = g_hash_table_lookup (priv->accounts, account); - if (connection) { - return; - } - - connection = mission_control_get_tpconnection (priv->mc, account, NULL); - if (!connection) { - return; - } - - g_hash_table_insert (priv->accounts, g_object_ref (account), connection); - g_signal_connect (connection, "invalidated", - G_CALLBACK (filter_connection_invalidated_cb), - filter); - - g_object_get (connection, "connection-ready", &ready, NULL); - if (ready) { - filter_connection_ready_cb (connection, NULL, filter); - } else { - g_signal_connect (connection, "notify::connection-ready", - G_CALLBACK (filter_connection_ready_cb), - filter); - } -} - -static void -filter_status_changed_cb (MissionControl *mc, - TpConnectionStatus status, - McPresence presence, - TpConnectionStatusReason reason, - const gchar *unique_name, - EmpathyFilter *filter) -{ - McAccount *account; - - account = mc_account_lookup (unique_name); - filter_update_account (filter, account); - g_object_unref (account); -} - -static void -filter_finalize (GObject *object) -{ - EmpathyFilterPriv *priv = GET_PRIV (object); - - empathy_disconnect_account_status_changed (priv->token); - g_object_unref (priv->mc); - - g_slist_foreach (priv->events, (GFunc) filter_event_free, NULL); - g_slist_free (priv->events); - - g_hash_table_destroy (priv->accounts); - g_hash_table_destroy (priv->tubes); -} - -static void -filter_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec) -{ - EmpathyFilterPriv *priv = GET_PRIV (object); - - switch (param_id) { - case PROP_TOP_EVENT: - g_value_set_pointer (value, priv->events ? priv->events->data : NULL); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - }; -} - -static void -empathy_filter_class_init (EmpathyFilterClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = filter_finalize; - object_class->get_property = filter_get_property; - - g_object_class_install_property (object_class, - PROP_TOP_EVENT, - g_param_spec_pointer ("top-event", - "The top event", - "The first event in the events list", - G_PARAM_READABLE)); - - g_type_class_add_private (object_class, sizeof (EmpathyFilterPriv)); -} - -static void -empathy_filter_init (EmpathyFilter *filter) -{ - GList *accounts, *l; - EmpathyFilterPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (filter, - EMPATHY_TYPE_FILTER, EmpathyFilterPriv); - - filter->priv = priv; - priv->tubes = g_hash_table_new_full (filter_channel_hash, - filter_channel_equal, - g_object_unref, NULL); - - priv->mc = empathy_mission_control_new (); - priv->token = empathy_connect_to_account_status_changed (priv->mc, - G_CALLBACK (filter_status_changed_cb), - filter, NULL); - - priv->accounts = g_hash_table_new_full (empathy_account_hash, - empathy_account_equal, - g_object_unref, - g_object_unref); - accounts = mc_accounts_list_by_enabled (TRUE); - for (l = accounts; l; l = l->next) { - filter_update_account (filter, l->data); - g_object_unref (l->data); - } - g_list_free (accounts); -} - -EmpathyFilter * -empathy_filter_new (void) -{ - static EmpathyFilter *filter = NULL; - - if (!filter) { - filter = g_object_new (EMPATHY_TYPE_FILTER, NULL); - g_object_add_weak_pointer (G_OBJECT (filter), (gpointer) &filter); - } else { - g_object_ref (filter); - } - - return filter; -} - diff --git a/src/empathy-filter.h b/src/empathy-filter.h deleted file mode 100644 index 67b3238c3..000000000 --- a/src/empathy-filter.h +++ /dev/null @@ -1,61 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Copyright (C) 2007-2008 Collabora Ltd. - * - * 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 - * - * Authors: Xavier Claessens <xclaesse@gmail.com> - */ - -#ifndef __EMPATHY_FILTER_H__ -#define __EMPATHY_FILTER_H__ - -#include <glib.h> - -G_BEGIN_DECLS - -#define EMPATHY_TYPE_FILTER (empathy_filter_get_type ()) -#define EMPATHY_FILTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_FILTER, EmpathyFilter)) -#define EMPATHY_FILTER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EMPATHY_TYPE_FILTER, EmpathyFilterClass)) -#define EMPATHY_IS_FILTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_FILTER)) -#define EMPATHY_IS_FILTER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_FILTER)) -#define EMPATHY_FILTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_FILTER, EmpathyFilterClass)) - -typedef struct _EmpathyFilter EmpathyFilter; -typedef struct _EmpathyFilterClass EmpathyFilterClass; - -struct _EmpathyFilter { - GObject parent; - gpointer priv; -}; - -struct _EmpathyFilterClass { - GObjectClass parent_class; -}; - -typedef struct { - gchar *icon_name; - gchar *message; -} EmpathyFilterEvent; - -GType empathy_filter_get_type (void) G_GNUC_CONST; -EmpathyFilter * empathy_filter_new (void); -void empathy_filter_activate_event (EmpathyFilter *filter, - EmpathyFilterEvent *event); -EmpathyFilterEvent *empathy_filter_get_top_event (EmpathyFilter *filter); - -G_END_DECLS - -#endif /* __EMPATHY_FILTER_H__ */ diff --git a/src/empathy-status-icon.c b/src/empathy-status-icon.c index bcb1f9f47..bd18b2d28 100644 --- a/src/empathy-status-icon.c +++ b/src/empathy-status-icon.c @@ -27,8 +27,14 @@ #include <glade/glade.h> #include <glib/gi18n.h> +#include <telepathy-glib/util.h> + #include <libempathy/empathy-utils.h> #include <libempathy/empathy-idle.h> +#include <libempathy/empathy-contact-manager.h> +#include <libempathy/empathy-dispatcher.h> +#include <libempathy/empathy-tp-chat.h> +#include <libempathy/empathy-tp-group.h> #include <libempathy-gtk/empathy-presence-chooser.h> #include <libempathy-gtk/empathy-conf.h> @@ -36,24 +42,27 @@ #include <libempathy-gtk/empathy-accounts-dialog.h> #include <libempathy-gtk/empathy-images.h> #include <libempathy-gtk/empathy-new-message-dialog.h> +#include <libempathy-gtk/empathy-contact-dialogs.h> #include "empathy-status-icon.h" #include "empathy-preferences.h" -#include "empathy-filter.h" -#define DEBUG_FLAG EMPATHY_DEBUG_FILTER +#define DEBUG_FLAG EMPATHY_DEBUG_DISPATCHER #include <libempathy/empathy-debug.h> /* Number of ms to wait when blinking */ #define BLINK_TIMEOUT 500 +typedef struct _StatusIconEvent StatusIconEvent; + #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyStatusIcon) typedef struct { GtkStatusIcon *icon; EmpathyIdle *idle; MissionControl *mc; - EmpathyFilter *filter; - EmpathyFilterEvent *event; + EmpathyDispatcher *dispatcher; + EmpathyContactManager *contact_manager; + GSList *events; gboolean showing_event_icon; guint blink_timeout; gpointer token; @@ -65,9 +74,27 @@ typedef struct { GtkWidget *status_item; } EmpathyStatusIconPriv; +typedef void (*StatusIconEventFunc) (EmpathyStatusIcon *icon, + gpointer user_data); + +struct _StatusIconEvent { + gchar *icon_name; + gchar *message; + StatusIconEventFunc func; + gpointer user_data; +}; + G_DEFINE_TYPE (EmpathyStatusIcon, empathy_status_icon, G_TYPE_OBJECT); static void +status_icon_event_free (StatusIconEvent *event) +{ + g_free (event->icon_name); + g_free (event->message); + g_slice_free (StatusIconEvent, event); +} + +static void status_icon_set_visibility (EmpathyStatusIcon *icon, gboolean visible, gboolean store) @@ -126,8 +153,8 @@ status_icon_update_tooltip (EmpathyStatusIcon *icon) EmpathyStatusIconPriv *priv = GET_PRIV (icon); const gchar *tooltip = NULL; - if (priv->event) { - tooltip = priv->event->message; + if (priv->events) { + tooltip = ((StatusIconEvent*)priv->events->data)->message; } if (!tooltip) { @@ -143,8 +170,8 @@ status_icon_update_icon (EmpathyStatusIcon *icon) EmpathyStatusIconPriv *priv = GET_PRIV (icon); const gchar *icon_name; - if (priv->event && priv->showing_event_icon) { - icon_name = priv->event->icon_name; + if (priv->events && priv->showing_event_icon) { + icon_name = ((StatusIconEvent*)priv->events->data)->icon_name; } else { McPresence state; @@ -177,15 +204,21 @@ status_icon_activate_cb (GtkStatusIcon *status_icon, { EmpathyStatusIconPriv *priv = GET_PRIV (icon); - DEBUG ("Activated: %s", priv->event ? "event" : "toggle"); + DEBUG ("Activated: %s", priv->events ? "event" : "toggle"); + + if (priv->events) { + StatusIconEvent *event; - if (priv->event) { - empathy_filter_activate_event (priv->filter, priv->event); - priv->event = empathy_filter_get_top_event (priv->filter); + event = priv->events->data; + if (event->func) { + event->func (icon, event->user_data); + } + status_icon_event_free (event); + priv->events = g_slist_remove (priv->events, event); status_icon_update_tooltip (icon); status_icon_update_icon (icon); - if (!priv->event && priv->blink_timeout) { + if (!priv->events && priv->blink_timeout) { g_source_remove (priv->blink_timeout); priv->blink_timeout = 0; } @@ -291,20 +324,225 @@ status_icon_blink_timeout_cb (EmpathyStatusIcon *icon) } static void -status_icon_top_event_notify_cb (EmpathyStatusIcon *icon) +status_icon_event_add (EmpathyStatusIcon *icon, + const gchar *icon_name, + const gchar *message, + StatusIconEventFunc func, + gpointer user_data) { EmpathyStatusIconPriv *priv = GET_PRIV (icon); + StatusIconEvent *event; + gboolean had_events; - priv->event = empathy_filter_get_top_event (priv->filter); - priv->showing_event_icon = priv->event != NULL; - status_icon_update_icon (icon); - status_icon_update_tooltip (icon); + DEBUG ("Adding event: %s", message); + + event = g_slice_new (StatusIconEvent); + event->icon_name = g_strdup (icon_name); + event->message = g_strdup (message); + event->func = func; + event->user_data = user_data; + + had_events = (priv->events != NULL); + priv->events = g_slist_append (priv->events, event); + if (!had_events) { + priv->showing_event_icon = TRUE; + status_icon_update_icon (icon); + status_icon_update_tooltip (icon); + + if (!priv->blink_timeout) { + priv->blink_timeout = g_timeout_add (BLINK_TIMEOUT, + (GSourceFunc) status_icon_blink_timeout_cb, + icon); + } + } +} + +static void +status_icon_channel_process (EmpathyStatusIcon *icon, + gpointer user_data) +{ + EmpathyStatusIconPriv *priv = GET_PRIV (icon); + TpChannel *channel = TP_CHANNEL (user_data); + + empathy_dispatcher_channel_process (priv->dispatcher, channel); + g_object_unref (channel); +} + +static void +status_icon_chat_message_received_cb (EmpathyTpChat *tp_chat, + EmpathyMessage *message, + EmpathyStatusIcon *icon) +{ + EmpathyContact *sender; + gchar *msg; + TpChannel *channel; + + sender = empathy_message_get_sender (message); + msg = g_strdup_printf (_("New message from %s:\n%s"), + empathy_contact_get_name (sender), + empathy_message_get_body (message)); + + channel = empathy_tp_chat_get_channel (tp_chat); + status_icon_event_add (icon, EMPATHY_IMAGE_NEW_MESSAGE, msg, + status_icon_channel_process, + g_object_ref (channel)); + + g_free (msg); + g_object_unref (tp_chat); +} + +static void +status_icon_filter_channel_cb (EmpathyDispatcher *dispatcher, + TpChannel *channel, + EmpathyStatusIcon *icon) +{ + gchar *channel_type; + + g_object_get (channel, "channel-type", &channel_type, NULL); + if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TEXT)) { + EmpathyTpChat *tp_chat; + + tp_chat = empathy_tp_chat_new (channel); + g_signal_connect (tp_chat, "message-received", + G_CALLBACK (status_icon_chat_message_received_cb), + icon); + } + else if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA)) { + EmpathyTpGroup *tp_group; + EmpathyContact *contact; + gchar *msg; + + tp_group = empathy_tp_group_new (channel); + empathy_run_until_ready (tp_group); + empathy_tp_group_get_invitation (tp_group, &contact); + empathy_contact_run_until_ready (contact, + EMPATHY_CONTACT_READY_NAME, + NULL); + + msg = g_strdup_printf (_("Incoming call from %s"), + empathy_contact_get_name (contact)); + + status_icon_event_add (icon, EMPATHY_IMAGE_VOIP, msg, + status_icon_channel_process, + g_object_ref (channel)); + + g_free (msg); + g_object_unref (contact); + g_object_unref (tp_group); + } + + g_free (channel_type); +} + +static void +status_icon_tube_process (EmpathyStatusIcon *icon, + gpointer user_data) +{ + EmpathyStatusIconPriv *priv = GET_PRIV (icon); + EmpathyDispatcherTube *tube = (EmpathyDispatcherTube*) user_data; - if (!priv->blink_timeout) { - priv->blink_timeout = g_timeout_add (BLINK_TIMEOUT, - (GSourceFunc) status_icon_blink_timeout_cb, - icon); + if (tube->activatable) { + empathy_dispatcher_tube_process (priv->dispatcher, tube); + } else { + GtkWidget *dialog; + gchar *str; + + /* Tell the user that the tube can't be handled */ + str = g_strdup_printf (_("%s offered you an invitation, but " + "you don't have the needed external " + "application to handle it."), + empathy_contact_get_name (tube->initiator)); + + dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, str); + gtk_window_set_title (GTK_WINDOW (dialog), + _("Invitation Error")); + g_free (str); + + gtk_widget_show (dialog); + g_signal_connect (dialog, "response", + G_CALLBACK (gtk_widget_destroy), + NULL); } + + empathy_dispatcher_tube_unref (tube); +} + +static void +status_icon_filter_tube_cb (EmpathyDispatcher *dispatcher, + EmpathyDispatcherTube *tube, + EmpathyStatusIcon *icon) +{ + const gchar *icon_name; + gchar *msg; + + empathy_contact_run_until_ready (tube->initiator, + EMPATHY_CONTACT_READY_NAME, NULL); + + if (tube->activatable) { + icon_name = GTK_STOCK_EXECUTE; + msg = g_strdup_printf (_("%s is offering you an invitation. An external " + "application will be started to handle it."), + empathy_contact_get_name (tube->initiator)); + } else { + icon_name = GTK_STOCK_DIALOG_ERROR; + msg = g_strdup_printf (_("%s is offering you an invitation, but " + "you don't have the needed external " + "application to handle it."), + empathy_contact_get_name (tube->initiator)); + } + + status_icon_event_add (icon, icon_name, msg, status_icon_tube_process, + empathy_dispatcher_tube_ref (tube)); + + g_free (msg); +} + +static void +status_icon_pending_subscribe (EmpathyStatusIcon *icon, + gpointer user_data) +{ + EmpathyContact *contact = EMPATHY_CONTACT (user_data); + + empathy_subscription_dialog_show (contact, NULL); + g_object_unref (contact); +} + +static void +status_icon_pendings_changed_cb (EmpathyContactList *list, + EmpathyContact *contact, + EmpathyContact *actor, + guint reason, + gchar *message, + gboolean is_pending, + EmpathyStatusIcon *icon) +{ + GString *str; + + if (!is_pending) { + /* FIXME: remove event if any */ + return; + } + + DEBUG ("New local pending contact"); + + empathy_contact_run_until_ready (contact, + EMPATHY_CONTACT_READY_NAME, + NULL); + + str = g_string_new (NULL); + g_string_printf (str, _("Subscription requested by %s"), + empathy_contact_get_name (contact)); + if (!G_STR_EMPTY (message)) { + g_string_append_printf (str, _("\nMessage: %s"), message); + } + + status_icon_event_add (icon, GTK_STOCK_DIALOG_QUESTION, str->str, + status_icon_pending_subscribe, + g_object_ref (contact)); + + g_string_free (str, TRUE); } static void @@ -317,11 +555,13 @@ status_icon_finalize (GObject *object) } empathy_disconnect_account_status_changed (priv->token); + g_slist_foreach (priv->events, (GFunc) status_icon_event_free, NULL); + g_slist_free (priv->events); g_object_unref (priv->icon); g_object_unref (priv->idle); - g_object_unref (priv->filter); g_object_unref (priv->mc); + g_object_unref (priv->contact_manager); } static void @@ -342,11 +582,9 @@ status_icon_status_changed_cb (MissionControl *mc, const gchar *unique_name, EmpathyStatusIcon *icon) { + EmpathyStatusIconPriv *priv = GET_PRIV (icon); GList *accounts, *l; guint connection_status = 1; - EmpathyStatusIconPriv *priv; - - priv = GET_PRIV (icon); /* Check for a connected account */ accounts = mc_accounts_list_by_enabled (TRUE); @@ -354,8 +592,9 @@ status_icon_status_changed_cb (MissionControl *mc, connection_status = mission_control_get_connection_status (priv->mc, l->data, NULL); - if (connection_status == 0) + if (connection_status == 0) { break; + } } mc_accounts_list_free (accounts); @@ -372,7 +611,8 @@ empathy_status_icon_init (EmpathyStatusIcon *icon) priv->icon = gtk_status_icon_new (); priv->mc = empathy_mission_control_new (); priv->idle = empathy_idle_new (); - priv->filter = empathy_filter_new (); + priv->dispatcher = empathy_dispatcher_new (); + priv->contact_manager = empathy_contact_manager_new (); priv->token = empathy_connect_to_account_status_changed (priv->mc, G_CALLBACK (status_icon_status_changed_cb), icon, NULL); @@ -389,9 +629,15 @@ empathy_status_icon_init (EmpathyStatusIcon *icon) g_signal_connect_swapped (priv->idle, "notify", G_CALLBACK (status_icon_idle_notify_cb), icon); - g_signal_connect_swapped (priv->filter, "notify::top-event", - G_CALLBACK (status_icon_top_event_notify_cb), - icon); + g_signal_connect (priv->dispatcher, "filter-channel", + G_CALLBACK (status_icon_filter_channel_cb), + icon); + g_signal_connect (priv->dispatcher, "filter-tube", + G_CALLBACK (status_icon_filter_tube_cb), + icon); + g_signal_connect (priv->contact_manager, "pendings-changed", + G_CALLBACK (status_icon_pendings_changed_cb), + icon); g_signal_connect (priv->icon, "activate", G_CALLBACK (status_icon_activate_cb), icon); diff --git a/src/empathy.c b/src/empathy.c index f28eae959..242f946a1 100644 --- a/src/empathy.c +++ b/src/empathy.c @@ -38,11 +38,16 @@ #include <libempathy/empathy-idle.h> #include <libempathy/empathy-utils.h> +#include <libempathy/empathy-dispatcher.h> +#include <libempathy/empathy-tp-chat.h> +#include <libempathy/empathy-tp-call.h> #include <libempathy-gtk/empathy-conf.h> #include "empathy-main-window.h" #include "empathy-status-icon.h" +#include "empathy-call-window.h" +#include "empathy-chat-window.h" #include "bacon-message-connection.h" #define DEBUG_FLAG EMPATHY_DEBUG_OTHER @@ -51,6 +56,57 @@ static BaconMessageConnection *connection = NULL; static void +dispatch_channel_cb (EmpathyDispatcher *dispatcher, + TpChannel *channel, + gpointer user_data) +{ + gchar *channel_type; + + g_object_get (channel, "channel-type", &channel_type, NULL); + if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TEXT)) { + EmpathyTpChat *tp_chat; + EmpathyChat *chat = NULL; + const gchar *id; + + tp_chat = empathy_tp_chat_new (channel); + empathy_run_until_ready (tp_chat); + + id = empathy_tp_chat_get_id (tp_chat); + if (!id) { + EmpathyContact *contact; + + contact = empathy_tp_chat_get_remote_contact (tp_chat); + if (contact) { + id = empathy_contact_get_id (contact); + } + } + + if (id) { + McAccount *account; + + account = empathy_tp_chat_get_account (tp_chat); + chat = empathy_chat_window_find_chat (account, id); + } + + if (chat) { + empathy_chat_set_tp_chat (chat, tp_chat); + } else { + chat = empathy_chat_new (tp_chat); + } + + empathy_chat_window_present_chat (chat); + g_object_unref (tp_chat); + } + else if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA)) { + EmpathyTpCall *tp_call; + + tp_call = empathy_tp_call_new (channel); + empathy_call_window_new (tp_call); + g_object_unref (tp_call); + } +} + +static void service_ended_cb (MissionControl *mc, gpointer user_data) { @@ -300,6 +356,7 @@ main (int argc, char *argv[]) { guint32 startup_timestamp; EmpathyStatusIcon *icon; + EmpathyDispatcher *dispatcher; GtkWidget *window; MissionControl *mc; EmpathyIdle *idle; @@ -402,6 +459,12 @@ main (int argc, char *argv[]) window); } + /* Handle channels */ + dispatcher = empathy_dispatcher_new (); + g_signal_connect (dispatcher, "dispatch-channel", + G_CALLBACK (dispatch_channel_cb), + NULL); + gtk_main (); empathy_idle_set_state (idle, MC_PRESENCE_OFFLINE); @@ -409,6 +472,7 @@ main (int argc, char *argv[]) g_object_unref (mc); g_object_unref (idle); g_object_unref (icon); + g_object_unref (dispatcher); return EXIT_SUCCESS; } |