2 * Copyright (C) 2007-2008 Collabora Ltd.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 * Authors: Xavier Claessens <xclaesse@gmail.com>
24 #include <glib/gi18n.h>
26 #include <telepathy-glib/util.h>
28 #include <libempathy/empathy-dispatcher.h>
29 #include <libempathy/empathy-contact-factory.h>
30 #include <libempathy/empathy-contact-manager.h>
31 #include <libempathy/empathy-tp-chat.h>
32 #include <libempathy/empathy-tp-group.h>
33 #include <libempathy/empathy-utils.h>
35 #include <extensions/extensions.h>
37 #include <libempathy-gtk/empathy-images.h>
38 #include <libempathy-gtk/empathy-contact-dialogs.h>
40 #include "empathy-event-manager.h"
42 #define DEBUG_FLAG EMPATHY_DEBUG_DISPATCHER
43 #include <libempathy/empathy-debug.h>
45 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyEventManager)
48 EmpathyEventManager *manager;
49 EmpathyDispatchOperation *operation;
50 guint approved_handler;
51 guint claimed_handler;
52 } EventManagerApproval;
55 EmpathyDispatcher *dispatcher;
56 EmpathyContactManager *contact_manager;
58 /* Ongoing approvals */
60 } EmpathyEventManagerPriv;
62 typedef struct _EventPriv EventPriv;
63 typedef void (*EventFunc) (EventPriv *event);
67 EmpathyEventManager *manager;
68 EventManagerApproval *approval;
79 static guint signals[LAST_SIGNAL];
81 G_DEFINE_TYPE (EmpathyEventManager, empathy_event_manager, G_TYPE_OBJECT);
83 static EmpathyEventManager * manager_singleton = NULL;
85 static EventManagerApproval *
86 event_manager_approval_new (EmpathyEventManager *manager,
87 EmpathyDispatchOperation *operation)
89 EventManagerApproval *result = g_slice_new0 (EventManagerApproval);
90 result->operation = g_object_ref (operation);
91 result->manager = manager;
97 event_manager_approval_free (EventManagerApproval *approval)
99 g_signal_handler_disconnect (approval->operation,
100 approval->approved_handler);
101 g_signal_handler_disconnect (approval->operation,
102 approval->claimed_handler);
103 g_object_unref (approval->operation);
104 g_slice_free (EventManagerApproval, approval);
107 static void event_remove (EventPriv *event);
110 event_free (EventPriv *event)
112 g_free (event->public.icon_name);
113 g_free (event->public.message);
115 if (event->public.contact) {
116 g_object_unref (event->public.contact);
119 g_slice_free (EventPriv, event);
123 event_remove (EventPriv *event)
125 EmpathyEventManagerPriv *priv = GET_PRIV (event->manager);
127 DEBUG ("Removing event %p", event);
128 priv->events = g_slist_remove (priv->events, event);
129 g_signal_emit (event->manager, signals[EVENT_REMOVED], 0, event);
134 event_manager_add (EmpathyEventManager *manager,
135 EmpathyContact *contact,
136 const gchar *icon_name,
137 const gchar *message,
138 EventManagerApproval *approval,
142 EmpathyEventManagerPriv *priv = GET_PRIV (manager);
145 event = g_slice_new0 (EventPriv);
146 event->public.contact = contact ? g_object_ref (contact) : NULL;
147 event->public.icon_name = g_strdup (icon_name);
148 event->public.message = g_strdup (message);
150 event->user_data = user_data;
151 event->manager = manager;
154 event->approval = approval;
156 g_signal_connect_swapped (channel, "invalidated",
157 G_CALLBACK (event_remove),
162 DEBUG ("Adding event %p", event);
163 priv->events = g_slist_prepend (priv->events, event);
164 g_signal_emit (event->manager, signals[EVENT_ADDED], 0, event);
168 event_channel_process_func (EventPriv *event)
170 empathy_dispatch_operation_approve (event->approval->operation);
174 event_manager_chat_message_received_cb (EmpathyTpChat *tp_chat,
175 EmpathyMessage *message,
176 EventManagerApproval *approval)
178 EmpathyContact *sender;
182 g_signal_handlers_disconnect_by_func (tp_chat,
183 event_manager_chat_message_received_cb,
186 sender = empathy_message_get_sender (message);
187 msg = g_strdup_printf (_("New message from %s:\n%s"),
188 empathy_contact_get_name (sender),
189 empathy_message_get_body (message));
191 channel = empathy_tp_chat_get_channel (tp_chat);
192 event_manager_add (approval->manager, sender, EMPATHY_IMAGE_NEW_MESSAGE, msg,
193 approval, event_channel_process_func, NULL);
199 event_manager_approval_done (EventManagerApproval *approval)
201 EmpathyEventManagerPriv *priv = GET_PRIV (approval->manager);
204 priv->approvals = g_slist_remove (priv->approvals, approval);
206 for (l = priv->events; l; l = l->next) {
207 EventPriv *event = l->data;
209 if (event->approval == approval) {
210 event_remove (event);
215 event_manager_approval_free (approval);
219 event_manager_operation_approved_cb (EmpathyDispatchOperation *operation,
220 EventManagerApproval *approval)
222 event_manager_approval_done (approval);
226 event_manager_operation_claimed_cb (EmpathyDispatchOperation *operation,
227 EventManagerApproval *approval)
229 event_manager_approval_done (approval);
233 event_manager_approve_channel_cb (EmpathyDispatcher *dispatcher,
234 EmpathyDispatchOperation *operation, EmpathyEventManager *manager)
236 const gchar *channel_type;
237 EventManagerApproval *approval;
238 EmpathyEventManagerPriv *priv = GET_PRIV (manager);
240 channel_type = empathy_dispatch_operation_get_channel_type (operation);
242 if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TEXT))
244 EmpathyTpChat *tp_chat =
246 empathy_dispatch_operation_get_channel_wrapper (operation));
248 approval = event_manager_approval_new (manager, operation);
249 priv->approvals = g_slist_prepend (priv->approvals, approval);
251 g_signal_connect (tp_chat, "message-received",
252 G_CALLBACK (event_manager_chat_message_received_cb), approval);
253 g_object_unref (G_OBJECT (tp_chat));
255 approval->approved_handler = g_signal_connect (operation, "approved",
256 G_CALLBACK (event_manager_operation_approved_cb), approval);
258 approval->claimed_handler = g_signal_connect (operation, "claimed",
259 G_CALLBACK (event_manager_operation_claimed_cb), approval);
263 else if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA)) {
264 EmpathyTpGroup *tp_group;
265 EmpathyContact *contact;
268 tp_group = empathy_tp_group_new (channel);
269 empathy_run_until_ready (tp_group);
270 empathy_tp_group_get_invitation (tp_group, &contact);
271 empathy_contact_run_until_ready (contact,
272 EMPATHY_CONTACT_READY_NAME,
275 msg = g_strdup_printf (_("Incoming call from %s"),
276 empathy_contact_get_name (contact));
278 event_manager_add (manager, contact, EMPATHY_IMAGE_VOIP, msg,
279 channel, event_channel_process_func, NULL);
282 g_object_unref (contact);
283 g_object_unref (tp_group);
285 else if (!tp_strdiff (channel_type, EMP_IFACE_CHANNEL_TYPE_FILE_TRANSFER)) {
286 EmpathyContact *contact;
290 EmpathyContactFactory *factory;
292 factory = empathy_contact_factory_dup_singleton ();
293 handle = tp_channel_get_handle (channel, NULL);
294 account = empathy_channel_get_account (channel);
296 contact = empathy_contact_factory_get_from_handle (factory,
300 empathy_contact_run_until_ready (contact,
301 EMPATHY_CONTACT_READY_NAME, NULL);
303 msg = g_strdup_printf (_("Incoming file transfer from %s"),
304 empathy_contact_get_name (contact));
306 event_manager_add (manager, contact,
307 EMPATHY_IMAGE_DOCUMENT_SEND,
309 event_channel_process_func, NULL);
311 g_object_unref (factory);
312 g_object_unref (account);
315 g_free (channel_type);
319 #if 0 /* FIXME dispatcher */
321 #define TUBE_NO_APP_MESSAGE _("%s is offering you an invitation, but " \
322 "you don't have the needed external " \
323 "application to handle it.")
327 event_tube_process_func (EventPriv *event)
329 EmpathyEventManagerPriv *priv = GET_PRIV (event->manager);
330 EmpathyDispatcherTube *tube = (EmpathyDispatcherTube*) event->user_data;
332 if (tube->activatable) {
333 empathy_dispatcher_tube_process (priv->dispatcher, tube);
338 /* Tell the user that the tube can't be handled */
339 str = g_strdup_printf (TUBE_NO_APP_MESSAGE,
340 empathy_contact_get_name (tube->initiator));
342 dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
346 gtk_window_set_title (GTK_WINDOW (dialog),
347 _("Invitation Error"));
350 gtk_widget_show (dialog);
351 g_signal_connect (dialog, "response",
352 G_CALLBACK (gtk_widget_destroy),
356 empathy_dispatcher_tube_unref (tube);
357 event_remove (event);
361 event_manager_filter_tube_cb (EmpathyDispatcher *dispatcher,
362 EmpathyDispatcherTube *tube,
363 EmpathyEventManager *manager)
365 const gchar *icon_name;
368 empathy_contact_run_until_ready (tube->initiator,
369 EMPATHY_CONTACT_READY_NAME, NULL);
371 if (tube->activatable) {
372 icon_name = GTK_STOCK_EXECUTE;
373 msg = g_strdup_printf (_("%s is offering you an invitation. An external "
374 "application will be started to handle it."),
375 empathy_contact_get_name (tube->initiator));
377 icon_name = GTK_STOCK_DIALOG_ERROR;
378 msg = g_strdup_printf (TUBE_NO_APP_MESSAGE,
379 empathy_contact_get_name (tube->initiator));
382 event_manager_add (manager, tube->initiator, icon_name, msg,
383 tube->channel, event_tube_process_func,
384 empathy_dispatcher_tube_ref (tube));
391 event_pending_subscribe_func (EventPriv *event)
393 empathy_subscription_dialog_show (event->public.contact, NULL);
394 event_remove (event);
398 event_manager_pendings_changed_cb (EmpathyContactList *list,
399 EmpathyContact *contact,
400 EmpathyContact *actor,
404 EmpathyEventManager *manager)
406 EmpathyEventManagerPriv *priv = GET_PRIV (manager);
412 for (l = priv->events; l; l = l->next) {
413 EventPriv *event = l->data;
415 if (event->public.contact == contact &&
416 event->func == event_pending_subscribe_func) {
417 event_remove (event);
425 empathy_contact_run_until_ready (contact,
426 EMPATHY_CONTACT_READY_NAME,
429 str = g_string_new (NULL);
430 g_string_printf (str, _("Subscription requested by %s"),
431 empathy_contact_get_name (contact));
432 if (!G_STR_EMPTY (message)) {
433 g_string_append_printf (str, _("\nMessage: %s"), message);
436 event_manager_add (manager, contact, GTK_STOCK_DIALOG_QUESTION, str->str,
437 NULL, event_pending_subscribe_func, NULL);
439 g_string_free (str, TRUE);
443 event_manager_constructor (GType type,
445 GObjectConstructParam *props)
449 if (manager_singleton) {
450 retval = g_object_ref (manager_singleton);
452 retval = G_OBJECT_CLASS (empathy_event_manager_parent_class)->constructor
453 (type, n_props, props);
455 manager_singleton = EMPATHY_EVENT_MANAGER (retval);
456 g_object_add_weak_pointer (retval, (gpointer *) &manager_singleton);
463 event_manager_finalize (GObject *object)
465 EmpathyEventManagerPriv *priv = GET_PRIV (object);
467 g_slist_foreach (priv->events, (GFunc) event_free, NULL);
468 g_slist_foreach (priv->approvals, (GFunc) event_manager_approval_free, NULL);
469 g_slist_free (priv->events);
470 g_object_unref (priv->contact_manager);
471 g_object_unref (priv->dispatcher);
475 empathy_event_manager_class_init (EmpathyEventManagerClass *klass)
477 GObjectClass *object_class = G_OBJECT_CLASS (klass);
479 object_class->finalize = event_manager_finalize;
480 object_class->constructor = event_manager_constructor;
482 signals[EVENT_ADDED] =
483 g_signal_new ("event-added",
484 G_TYPE_FROM_CLASS (klass),
488 g_cclosure_marshal_VOID__POINTER,
492 signals[EVENT_REMOVED] =
493 g_signal_new ("event-removed",
494 G_TYPE_FROM_CLASS (klass),
498 g_cclosure_marshal_VOID__POINTER,
502 g_type_class_add_private (object_class, sizeof (EmpathyEventManagerPriv));
506 empathy_event_manager_init (EmpathyEventManager *manager)
508 EmpathyEventManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
509 EMPATHY_TYPE_EVENT_MANAGER, EmpathyEventManagerPriv);
511 manager->priv = priv;
513 priv->dispatcher = empathy_get_dispatcher ();
514 priv->contact_manager = empathy_contact_manager_dup_singleton ();
515 g_signal_connect (priv->dispatcher, "approve",
516 G_CALLBACK (event_manager_approve_channel_cb),
518 /*g_signal_connect (priv->dispatcher, "dispatch-channel",
519 G_CALLBACK (event_manager_dispatch_channel_cb),
522 #if 0 /* FIXME dispatcher */
523 g_signal_connect (priv->dispatcher, "filter-tube",
524 G_CALLBACK (event_manager_filter_tube_cb),
527 g_signal_connect (priv->contact_manager, "pendings-changed",
528 G_CALLBACK (event_manager_pendings_changed_cb),
532 EmpathyEventManager *
533 empathy_event_manager_dup_singleton (void)
535 return g_object_new (EMPATHY_TYPE_EVENT_MANAGER, NULL);
539 empathy_event_manager_get_events (EmpathyEventManager *manager)
541 EmpathyEventManagerPriv *priv = GET_PRIV (manager);
543 g_return_val_if_fail (EMPATHY_IS_EVENT_MANAGER (manager), NULL);
549 empathy_event_manager_get_top_event (EmpathyEventManager *manager)
551 EmpathyEventManagerPriv *priv = GET_PRIV (manager);
553 g_return_val_if_fail (EMPATHY_IS_EVENT_MANAGER (manager), NULL);
555 return priv->events ? priv->events->data : NULL;
559 empathy_event_activate (EmpathyEvent *event_public)
561 EventPriv *event = (EventPriv*) event_public;
563 g_return_if_fail (event_public != NULL);
568 event_remove (event);