empathy r1093 - in trunk: . libempathy src



Author: xclaesse
Date: Thu May  8 17:30:40 2008
New Revision: 1093
URL: http://svn.gnome.org/viewvc/empathy?rev=1093&view=rev

Log:
Move non-gtk parts of EmpathyFilter to EmpathyDispatcher in libempathy, gtk parts are now in EmpathyStatusIcon


Added:
   trunk/libempathy/empathy-dispatcher.c
   trunk/libempathy/empathy-dispatcher.h
Removed:
   trunk/src/empathy-filter.c
   trunk/src/empathy-filter.h
Modified:
   trunk/configure.ac
   trunk/libempathy/Makefile.am
   trunk/libempathy/empathy-debug.c
   trunk/libempathy/empathy-debug.h
   trunk/src/Makefile.am
   trunk/src/empathy-status-icon.c
   trunk/src/empathy.c

Modified: trunk/configure.ac
==============================================================================
--- trunk/configure.ac	(original)
+++ trunk/configure.ac	Thu May  8 17:30:40 2008
@@ -30,7 +30,7 @@
 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

Modified: trunk/libempathy/Makefile.am
==============================================================================
--- trunk/libempathy/Makefile.am	(original)
+++ trunk/libempathy/Makefile.am	Thu May  8 17:30:40 2008
@@ -41,7 +41,8 @@
 	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 @@
 	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 =			\

Modified: trunk/libempathy/empathy-debug.c
==============================================================================
--- trunk/libempathy/empathy-debug.c	(original)
+++ trunk/libempathy/empathy-debug.c	Thu May  8 17:30:40 2008
@@ -43,7 +43,7 @@
   { "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, }
 };

Modified: trunk/libempathy/empathy-debug.h
==============================================================================
--- trunk/libempathy/empathy-debug.h	(original)
+++ trunk/libempathy/empathy-debug.h	Thu May  8 17:30:40 2008
@@ -37,7 +37,7 @@
   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;
 

Added: trunk/libempathy/empathy-dispatcher.c
==============================================================================
--- (empty file)
+++ trunk/libempathy/empathy-dispatcher.c	Thu May  8 17:30:40 2008
@@ -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;
+}
+

Added: trunk/libempathy/empathy-dispatcher.h
==============================================================================
--- (empty file)
+++ trunk/libempathy/empathy-dispatcher.h	Thu May  8 17:30:40 2008
@@ -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__ */

Modified: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am	(original)
+++ trunk/src/Makefile.am	Thu May  8 17:30:40 2008
@@ -31,7 +31,6 @@
 	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

Modified: trunk/src/empathy-status-icon.c
==============================================================================
--- trunk/src/empathy-status-icon.c	(original)
+++ trunk/src/empathy-status-icon.c	Thu May  8 17:30:40 2008
@@ -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 @@
 	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 @@
 	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 @@
 	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 @@
 {
 	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 @@
 }
 
 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);
 
-	if (!priv->blink_timeout) {
-		priv->blink_timeout = g_timeout_add (BLINK_TIMEOUT,
-						     (GSourceFunc) status_icon_blink_timeout_cb,
-						     icon);
+	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 (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 @@
 	}
 
 	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 @@
 			       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 @@
 		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 @@
 	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 @@
 	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);

Modified: trunk/src/empathy.c
==============================================================================
--- trunk/src/empathy.c	(original)
+++ trunk/src/empathy.c	Thu May  8 17:30:40 2008
@@ -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 @@
 {
 	guint32            startup_timestamp;
 	EmpathyStatusIcon *icon;
+	EmpathyDispatcher *dispatcher;
 	GtkWidget         *window;
 	MissionControl    *mc;
 	EmpathyIdle       *idle;
@@ -402,6 +459,12 @@
 						       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 @@
 	g_object_unref (mc);
 	g_object_unref (idle);
 	g_object_unref (icon);
+	g_object_unref (dispatcher);
 
 	return EXIT_SUCCESS;
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]