1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2007-2008 Collabora Ltd.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 * Authors: Xavier Claessens <xclaesse@gmail.com>
26 #include <glib/gi18n.h>
28 #include <telepathy-glib/enums.h>
29 #include <telepathy-glib/channel.h>
30 #include <telepathy-glib/connection.h>
31 #include <telepathy-glib/util.h>
33 #include <libmissioncontrol/mission-control.h>
34 #include <libmissioncontrol/mc-account.h>
36 #include <libempathy/empathy-tp-chat.h>
37 #include <libempathy/empathy-tp-call.h>
38 #include <libempathy/empathy-tp-group.h>
39 #include <libempathy/empathy-utils.h>
40 #include <libempathy/empathy-debug.h>
42 #include <libempathy-gtk/empathy-chat.h>
43 #include <libempathy-gtk/empathy-images.h>
44 #include <libempathy-gtk/empathy-contact-dialogs.h>
46 #include "empathy-filter.h"
47 #include "empathy-chat-window.h"
48 #include "empathy-call-window.h"
50 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
51 EMPATHY_TYPE_FILTER, EmpathyFilterPriv))
53 #define DEBUG_DOMAIN "Filter"
55 struct _EmpathyFilterPriv {
62 static void empathy_filter_class_init (EmpathyFilterClass *klass);
63 static void empathy_filter_init (EmpathyFilter *filter);
65 G_DEFINE_TYPE (EmpathyFilter, empathy_filter, G_TYPE_OBJECT);
72 typedef void (*FilterFunc) (EmpathyFilter *filter,
76 EmpathyFilterEvent public;
79 } EmpathyFilterEventExt;
82 filter_event_free (EmpathyFilterEventExt *event)
84 g_free (event->public.icon_name);
85 g_free (event->public.message);
86 g_slice_free (EmpathyFilterEventExt, event);
90 filter_emit_event (EmpathyFilter *filter,
91 const gchar *icon_name,
96 EmpathyFilterPriv *priv = GET_PRIV (filter);
97 EmpathyFilterEventExt *event;
99 empathy_debug (DEBUG_DOMAIN, "Emit event, icon_name=%s message='%s'",
102 event = g_slice_new0 (EmpathyFilterEventExt);
104 event->user_data = user_data;
105 event->public.icon_name = g_strdup (icon_name);
106 event->public.message = g_strdup (message);
108 priv->events = g_slist_append (priv->events, event);
109 if (priv->events->data == event) {
110 g_object_notify (G_OBJECT (filter), "top-event");
115 empathy_filter_activate_event (EmpathyFilter *filter,
116 EmpathyFilterEvent *event)
118 EmpathyFilterPriv *priv = GET_PRIV (filter);
119 EmpathyFilterEventExt *event_ext;
123 g_return_if_fail (EMPATHY_IS_FILTER (filter));
124 g_return_if_fail (event != NULL);
126 if (!(l = g_slist_find (priv->events, event))) {
130 empathy_debug (DEBUG_DOMAIN, "Activating event");
132 event_ext = (EmpathyFilterEventExt*) event;
133 if (event_ext->func) {
134 event_ext->func (filter, event_ext->user_data);
137 is_top = (l == priv->events);
138 priv->events = g_slist_delete_link (priv->events, l);
140 g_object_notify (G_OBJECT (filter), "top-event");
143 filter_event_free (event_ext);
147 empathy_filter_get_top_event (EmpathyFilter *filter)
149 EmpathyFilterPriv *priv = GET_PRIV (filter);
151 g_return_val_if_fail (EMPATHY_IS_FILTER (filter), NULL);
153 return priv->events ? priv->events->data : NULL;
157 filter_chat_dispatch (EmpathyFilter *filter,
160 EmpathyTpChat *tp_chat = EMPATHY_TP_CHAT (user_data);
165 id = empathy_tp_chat_get_id (tp_chat);
166 account = empathy_tp_chat_get_account (tp_chat);
167 chat = empathy_chat_window_find_chat (account, id);
170 empathy_chat_set_tp_chat (chat, tp_chat);
172 chat = empathy_chat_new (tp_chat);
175 empathy_chat_window_present_chat (chat);
176 g_object_unref (tp_chat);
180 filter_chat_message_received_cb (EmpathyTpChat *tp_chat,
181 EmpathyMessage *message,
182 EmpathyFilter *filter)
184 EmpathyContact *sender;
187 g_signal_handlers_disconnect_by_func (tp_chat,
188 filter_chat_message_received_cb,
191 sender = empathy_message_get_sender (message);
192 msg = g_strdup_printf (_("New message from %s:\n%s"),
193 empathy_contact_get_name (sender),
194 empathy_message_get_body (message));
196 filter_emit_event (filter, EMPATHY_IMAGE_NEW_MESSAGE, msg,
197 filter_chat_dispatch, tp_chat);
203 filter_chat_handle_channel (EmpathyFilter *filter,
205 gboolean is_incoming)
207 EmpathyTpChat *tp_chat;
209 empathy_debug (DEBUG_DOMAIN, "New text channel to be filtered: %p",
212 tp_chat = empathy_tp_chat_new (channel, FALSE);
214 filter_chat_dispatch (filter, tp_chat);
216 g_signal_connect (tp_chat, "message-received",
217 G_CALLBACK (filter_chat_message_received_cb),
223 filter_call_dispatch (EmpathyFilter *filter,
226 EmpathyTpCall *call = EMPATHY_TP_CALL (user_data);
228 empathy_call_window_new (call);
229 g_object_unref (call);
233 filter_call_contact_notify_cb (EmpathyTpCall *call,
235 EmpathyFilter *filter)
237 EmpathyContact *contact;
240 g_object_get (call, "contact", &contact, NULL);
245 empathy_contact_run_until_ready (contact,
246 EMPATHY_CONTACT_READY_NAME,
249 msg = g_strdup_printf (_("Incoming call from %s"),
250 empathy_contact_get_name (contact));
252 filter_emit_event (filter, EMPATHY_IMAGE_VOIP, msg,
253 filter_call_dispatch, call);
256 g_object_unref (contact);
260 filter_call_handle_channel (EmpathyFilter *filter,
262 gboolean is_incoming)
266 empathy_debug (DEBUG_DOMAIN, "New media channel to be filtered: %p",
269 call = empathy_tp_call_new (channel);
271 filter_call_dispatch (filter, call);
273 g_signal_connect (call, "notify::contact",
274 G_CALLBACK (filter_call_contact_notify_cb),
280 filter_contact_list_subscribe (EmpathyFilter *filter,
283 EmpathyContact *contact = EMPATHY_CONTACT (user_data);
285 empathy_subscription_dialog_show (contact, NULL);
286 g_object_unref (contact);
290 filter_contact_list_local_pending_cb (EmpathyTpGroup *group,
291 EmpathyContact *contact,
292 EmpathyContact *actor,
295 EmpathyFilter *filter)
299 empathy_debug (DEBUG_DOMAIN, "New local pending contact");
301 empathy_contact_run_until_ready (contact,
302 EMPATHY_CONTACT_READY_NAME,
305 str = g_string_new (NULL);
306 g_string_printf (str, _("Subscription requested by %s"),
307 empathy_contact_get_name (contact));
308 if (!G_STR_EMPTY (message)) {
309 g_string_append_printf (str, _("\nMessage: %s"), message);
312 filter_emit_event (filter, GTK_STOCK_DIALOG_QUESTION, str->str,
313 filter_contact_list_subscribe,
314 g_object_ref (contact));
316 g_string_free (str, TRUE);
320 filter_contact_list_ready_cb (EmpathyTpGroup *group,
322 EmpathyFilter *filter)
326 if (tp_strdiff ("publish", empathy_tp_group_get_name (group))) {
327 g_object_unref (group);
331 empathy_debug (DEBUG_DOMAIN, "Publish contact list ready");
333 g_signal_connect (group, "local-pending",
334 G_CALLBACK (filter_contact_list_local_pending_cb),
337 pendings = empathy_tp_group_get_local_pendings (group);
338 for (l = pendings; l; l = l->next) {
339 EmpathyPendingInfo *info = l->data;
341 filter_contact_list_local_pending_cb (group, info->member,
342 info->actor, info->reason,
343 info->message, filter);
344 empathy_pending_info_free (info);
346 g_list_free (pendings);
350 filter_contact_list_destroy_cb (EmpathyTpGroup *group,
351 EmpathyFilter *filter)
353 g_object_unref (group);
357 filter_contact_list_handle_channel (EmpathyFilter *filter,
359 gboolean is_incoming)
361 EmpathyTpGroup *group;
363 group = empathy_tp_group_new (channel);
364 g_signal_connect (group, "notify::ready",
365 G_CALLBACK (filter_contact_list_ready_cb),
367 g_signal_connect (group, "destroy",
368 G_CALLBACK (filter_contact_list_destroy_cb),
373 filter_connection_invalidated_cb (TpConnection *connection,
377 EmpathyFilter *filter)
379 EmpathyFilterPriv *priv = GET_PRIV (filter);
383 empathy_debug (DEBUG_DOMAIN, "connection invalidated: %s", message);
385 g_hash_table_iter_init (&iter, priv->accounts);
386 while (g_hash_table_iter_next (&iter, &key, &value)) {
387 if (value == connection) {
388 g_hash_table_remove (priv->accounts, key);
394 typedef void (*HandleChannelFunc) (EmpathyFilter *filter,
396 gboolean is_incoming);
399 filter_conection_new_channel_cb (TpConnection *connection,
400 const gchar *object_path,
401 const gchar *channel_type,
404 gboolean suppress_handler,
408 HandleChannelFunc func = NULL;
410 gpointer had_channels;
412 had_channels = g_object_get_data (G_OBJECT (connection), "had-channels");
413 if (had_channels == NULL) {
417 if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TEXT)) {
418 func = filter_chat_handle_channel;
420 else if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA)) {
421 func = filter_call_handle_channel;
423 else if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST)) {
424 func = filter_contact_list_handle_channel;
426 empathy_debug (DEBUG_DOMAIN, "Unknown channel type %s",
431 channel = tp_channel_new (connection, object_path, channel_type,
432 handle_type, handle, NULL);
433 tp_channel_run_until_ready (channel, NULL, NULL);
435 /* We abuse of suppress_handler, TRUE means OUTGOING */
436 func (EMPATHY_FILTER (filter), channel, suppress_handler);
438 g_object_unref (channel);
442 filter_connection_list_channels_cb (TpConnection *connection,
443 const GPtrArray *channels,
450 g_object_set_data (G_OBJECT (connection), "had-channels",
451 GUINT_TO_POINTER (1));
453 for (i = 0; i < channels->len; i++) {
456 values = g_ptr_array_index (channels, i);
457 filter_conection_new_channel_cb (connection,
458 g_value_get_boxed (g_value_array_get_nth (values, 0)),
459 g_value_get_string (g_value_array_get_nth (values, 1)),
460 g_value_get_uint (g_value_array_get_nth (values, 2)),
461 g_value_get_uint (g_value_array_get_nth (values, 3)),
462 TRUE, user_data, filter);
467 filter_connection_ready_cb (TpConnection *connection,
469 EmpathyFilter *filter)
471 empathy_debug (DEBUG_DOMAIN, "Connection ready, accepting new channels");
473 tp_cli_connection_connect_to_new_channel (connection,
474 filter_conection_new_channel_cb,
476 G_OBJECT (filter), NULL);
477 tp_cli_connection_call_list_channels (connection, -1,
478 filter_connection_list_channels_cb,
484 filter_update_account (EmpathyFilter *filter,
487 EmpathyFilterPriv *priv = GET_PRIV (filter);
488 TpConnection *connection;
491 connection = g_hash_table_lookup (priv->accounts, account);
496 connection = mission_control_get_tpconnection (priv->mc, account, NULL);
501 g_hash_table_insert (priv->accounts, g_object_ref (account), connection);
502 g_signal_connect (connection, "invalidated",
503 G_CALLBACK (filter_connection_invalidated_cb),
506 g_object_get (connection, "connection-ready", &ready, NULL);
508 filter_connection_ready_cb (connection, NULL, filter);
510 g_signal_connect (connection, "notify::connection-ready",
511 G_CALLBACK (filter_connection_ready_cb),
517 filter_status_changed_cb (MissionControl *mc,
518 TpConnectionStatus status,
520 TpConnectionStatusReason reason,
521 const gchar *unique_name,
522 EmpathyFilter *filter)
526 account = mc_account_lookup (unique_name);
527 filter_update_account (filter, account);
528 g_object_unref (account);
532 filter_finalize (GObject *object)
534 EmpathyFilterPriv *priv = GET_PRIV (object);
536 empathy_disconnect_account_status_changed (priv->token);
537 g_object_unref (priv->mc);
539 g_slist_foreach (priv->events, (GFunc) filter_event_free, NULL);
540 g_slist_free (priv->events);
542 g_hash_table_destroy (priv->accounts);
546 filter_get_property (GObject *object,
551 EmpathyFilterPriv *priv = GET_PRIV (object);
555 g_value_set_pointer (value, priv->events ? priv->events->data : NULL);
558 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
564 empathy_filter_class_init (EmpathyFilterClass *klass)
566 GObjectClass *object_class = G_OBJECT_CLASS (klass);
568 object_class->finalize = filter_finalize;
569 object_class->get_property = filter_get_property;
571 g_object_class_install_property (object_class,
573 g_param_spec_pointer ("top-event",
575 "The first event in the events list",
578 g_type_class_add_private (object_class, sizeof (EmpathyFilterPriv));
582 empathy_filter_init (EmpathyFilter *filter)
584 EmpathyFilterPriv *priv = GET_PRIV (filter);
587 priv->mc = empathy_mission_control_new ();
588 priv->token = empathy_connect_to_account_status_changed (priv->mc,
589 G_CALLBACK (filter_status_changed_cb),
592 priv->accounts = g_hash_table_new_full (empathy_account_hash,
593 empathy_account_equal,
596 accounts = mc_accounts_list_by_enabled (TRUE);
597 for (l = accounts; l; l = l->next) {
598 filter_update_account (filter, l->data);
599 g_object_unref (l->data);
601 g_list_free (accounts);
605 empathy_filter_new (void)
607 static EmpathyFilter *filter = NULL;
610 filter = g_object_new (EMPATHY_TYPE_FILTER, NULL);
611 g_object_add_weak_pointer (G_OBJECT (filter), (gpointer) &filter);
613 g_object_ref (filter);