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>
19 * Sjoerd Simons <sjoerd.simons@collabora.co.uk>
25 #include <glib/gi18n.h>
27 #include <telepathy-glib/account-manager.h>
28 #include <telepathy-glib/util.h>
29 #include <telepathy-glib/interfaces.h>
31 #include <libempathy/empathy-dispatcher.h>
32 #include <libempathy/empathy-idle.h>
33 #include <libempathy/empathy-tp-contact-factory.h>
34 #include <libempathy/empathy-contact-manager.h>
35 #include <libempathy/empathy-tp-chat.h>
36 #include <libempathy/empathy-tp-call.h>
37 #include <libempathy/empathy-tp-file.h>
38 #include <libempathy/empathy-utils.h>
39 #include <libempathy/empathy-call-factory.h>
41 #include <extensions/extensions.h>
43 #include <libempathy-gtk/empathy-conf.h>
44 #include <libempathy-gtk/empathy-images.h>
45 #include <libempathy-gtk/empathy-contact-dialogs.h>
46 #include <libempathy-gtk/empathy-sound.h>
48 #include "empathy-event-manager.h"
49 #include "empathy-main-window.h"
50 #include "empathy-tube-dispatch.h"
52 #define DEBUG_FLAG EMPATHY_DEBUG_DISPATCHER
53 #include <libempathy/empathy-debug.h>
55 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyEventManager)
57 #define NOTIFICATION_TIMEOUT 2 /* seconds */
59 /* The time interval in milliseconds between 2 incoming rings */
60 #define MS_BETWEEN_RING 500
63 EmpathyEventManager
*manager
;
64 EmpathyDispatchOperation
*operation
;
65 gulong approved_handler
;
66 gulong claimed_handler
;
67 gulong invalidated_handler
;
68 /* Remove contact if applicable */
69 EmpathyContact
*contact
;
70 /* Tube dispatcher if applicable */
71 EmpathyTubeDispatch
*tube_dispatch
;
72 /* option signal handler and it's instance */
74 GObject
*handler_instance
;
75 /* optional accept widget */
77 } EventManagerApproval
;
80 EmpathyDispatcher
*dispatcher
;
81 EmpathyContactManager
*contact_manager
;
83 /* Ongoing approvals */
87 } EmpathyEventManagerPriv
;
89 typedef struct _EventPriv EventPriv
;
90 typedef void (*EventFunc
) (EventPriv
*event
);
94 EmpathyEventManager
*manager
;
95 EventManagerApproval
*approval
;
108 static guint signals
[LAST_SIGNAL
];
110 G_DEFINE_TYPE (EmpathyEventManager
, empathy_event_manager
, G_TYPE_OBJECT
);
112 static EmpathyEventManager
* manager_singleton
= NULL
;
114 static EventManagerApproval
*
115 event_manager_approval_new (EmpathyEventManager
*manager
,
116 EmpathyDispatchOperation
*operation
)
118 EventManagerApproval
*result
= g_slice_new0 (EventManagerApproval
);
119 result
->operation
= g_object_ref (operation
);
120 result
->manager
= manager
;
126 event_manager_approval_free (EventManagerApproval
*approval
)
128 g_signal_handler_disconnect (approval
->operation
,
129 approval
->approved_handler
);
130 g_signal_handler_disconnect (approval
->operation
,
131 approval
->claimed_handler
);
132 g_signal_handler_disconnect (approval
->operation
,
133 approval
->invalidated_handler
);
134 g_object_unref (approval
->operation
);
136 if (approval
->handler
!= 0)
137 g_signal_handler_disconnect (approval
->handler_instance
,
140 if (approval
->contact
!= NULL
)
141 g_object_unref (approval
->contact
);
143 if (approval
->tube_dispatch
!= NULL
)
144 g_object_unref (approval
->tube_dispatch
);
146 if (approval
->dialog
!= NULL
)
148 gtk_widget_destroy (approval
->dialog
);
151 g_slice_free (EventManagerApproval
, approval
);
154 static void event_remove (EventPriv
*event
);
157 event_free (EventPriv
*event
)
159 g_free (event
->public.icon_name
);
160 g_free (event
->public.header
);
161 g_free (event
->public.message
);
163 if (event
->public.contact
)
165 g_object_unref (event
->public.contact
);
168 g_slice_free (EventPriv
, event
);
172 event_remove (EventPriv
*event
)
174 EmpathyEventManagerPriv
*priv
= GET_PRIV (event
->manager
);
176 DEBUG ("Removing event %p", event
);
177 priv
->events
= g_slist_remove (priv
->events
, event
);
178 g_signal_emit (event
->manager
, signals
[EVENT_REMOVED
], 0, event
);
183 autoremove_event_timeout_cb (EventPriv
*event
)
185 event_remove (event
);
190 event_manager_add (EmpathyEventManager
*manager
,
191 EmpathyContact
*contact
,
192 EmpathyEventType type
,
193 const gchar
*icon_name
,
195 const gchar
*message
,
196 EventManagerApproval
*approval
,
200 EmpathyEventManagerPriv
*priv
= GET_PRIV (manager
);
203 event
= g_slice_new0 (EventPriv
);
204 event
->public.contact
= contact
? g_object_ref (contact
) : NULL
;
205 event
->public.type
= type
;
206 event
->public.icon_name
= g_strdup (icon_name
);
207 event
->public.header
= g_strdup (header
);
208 event
->public.message
= g_strdup (message
);
209 event
->public.must_ack
= (func
!= NULL
);
210 event
->inhibit
= FALSE
;
212 event
->user_data
= user_data
;
213 event
->manager
= manager
;
214 event
->approval
= approval
;
216 DEBUG ("Adding event %p", event
);
217 priv
->events
= g_slist_prepend (priv
->events
, event
);
218 g_signal_emit (event
->manager
, signals
[EVENT_ADDED
], 0, event
);
220 if (!event
->public.must_ack
)
222 g_timeout_add_seconds (NOTIFICATION_TIMEOUT
,
223 (GSourceFunc
) autoremove_event_timeout_cb
, event
);
228 event_channel_process_func (EventPriv
*event
)
230 empathy_dispatch_operation_approve (event
->approval
->operation
);
234 event_text_channel_process_func (EventPriv
*event
)
236 EmpathyTpChat
*tp_chat
;
238 if (event
->approval
->handler
!= 0)
240 tp_chat
= EMPATHY_TP_CHAT
241 (empathy_dispatch_operation_get_channel_wrapper (event
->approval
->operation
));
243 g_signal_handler_disconnect (tp_chat
, event
->approval
->handler
);
244 event
->approval
->handler
= 0;
247 empathy_dispatch_operation_approve (event
->approval
->operation
);
251 event_lookup_by_approval (EmpathyEventManager
*manager
,
252 EventManagerApproval
*approval
)
254 EmpathyEventManagerPriv
*priv
= GET_PRIV (manager
);
256 EventPriv
*retval
= NULL
;
258 for (l
= priv
->events
; l
; l
= l
->next
)
260 EventPriv
*event
= l
->data
;
262 if (event
->approval
== approval
)
273 event_update (EmpathyEventManager
*manager
, EventPriv
*event
,
274 const char *icon_name
, const char *header
, const char *msg
)
276 g_free (event
->public.icon_name
);
277 g_free (event
->public.header
);
278 g_free (event
->public.message
);
280 event
->public.icon_name
= g_strdup (icon_name
);
281 event
->public.header
= g_strdup (header
);
282 event
->public.message
= g_strdup (msg
);
284 g_signal_emit (manager
, signals
[EVENT_UPDATED
], 0, event
);
288 event_manager_call_window_confirmation_dialog_response_cb (GtkDialog
*dialog
,
289 gint response
, gpointer user_data
)
291 EventManagerApproval
*approval
= user_data
;
293 gtk_widget_destroy (approval
->dialog
);
294 approval
->dialog
= NULL
;
296 if (response
!= GTK_RESPONSE_ACCEPT
)
298 EmpathyTpCall
*call
=
300 empathy_dispatch_operation_get_channel_wrapper (
301 approval
->operation
));
304 if (empathy_dispatch_operation_claim (approval
->operation
))
305 empathy_tp_call_close (call
);
306 g_object_unref (call
);
311 EmpathyCallFactory
*factory
= empathy_call_factory_get ();
312 empathy_call_factory_claim_channel (factory
, approval
->operation
);
317 event_channel_process_voip_func (EventPriv
*event
)
323 if (event
->approval
->dialog
!= NULL
)
325 gtk_window_present (GTK_WINDOW (event
->approval
->dialog
));
329 dialog
= gtk_message_dialog_new (NULL
, 0,
330 GTK_MESSAGE_QUESTION
, GTK_BUTTONS_NONE
, _("Incoming call"));
331 gtk_message_dialog_format_secondary_text (
332 GTK_MESSAGE_DIALOG (dialog
),
333 _("%s is calling you, do you want to answer?"),
334 empathy_contact_get_name (event
->approval
->contact
));
336 gtk_dialog_set_default_response (GTK_DIALOG (dialog
),
339 button
= gtk_dialog_add_button (GTK_DIALOG (dialog
),
340 _("_Reject"), GTK_RESPONSE_REJECT
);
341 image
= gtk_image_new_from_icon_name ("call-stop",
342 GTK_ICON_SIZE_BUTTON
);
343 gtk_button_set_image (GTK_BUTTON (button
), image
);
345 button
= gtk_dialog_add_button (GTK_DIALOG (dialog
),
346 _("_Answer"), GTK_RESPONSE_ACCEPT
);
348 image
= gtk_image_new_from_icon_name ("call-start", GTK_ICON_SIZE_BUTTON
);
349 gtk_button_set_image (GTK_BUTTON (button
), image
);
351 g_signal_connect (dialog
, "response",
352 G_CALLBACK (event_manager_call_window_confirmation_dialog_response_cb
),
355 gtk_widget_show (dialog
);
357 event
->approval
->dialog
= dialog
;
361 event_manager_chat_message_received_cb (EmpathyTpChat
*tp_chat
,
362 EmpathyMessage
*message
, EventManagerApproval
*approval
)
364 EmpathyContact
*sender
;
370 /* try to update the event if it's referring to a chat which is already in the
372 event
= event_lookup_by_approval (approval
->manager
, approval
);
374 sender
= empathy_message_get_sender (message
);
375 header
= empathy_contact_get_name (sender
);
376 msg
= empathy_message_get_body (message
);
378 channel
= empathy_tp_chat_get_channel (tp_chat
);
381 event_update (approval
->manager
, event
, EMPATHY_IMAGE_NEW_MESSAGE
, header
, msg
);
383 event_manager_add (approval
->manager
, sender
, EMPATHY_EVENT_TYPE_CHAT
,
384 EMPATHY_IMAGE_NEW_MESSAGE
, header
, msg
, approval
,
385 event_text_channel_process_func
, NULL
);
387 empathy_sound_play (empathy_main_window_get (),
388 EMPATHY_SOUND_CONVERSATION_NEW
);
392 event_manager_approval_done (EventManagerApproval
*approval
)
394 EmpathyEventManagerPriv
*priv
= GET_PRIV (approval
->manager
);
397 if (approval
->operation
!= NULL
)
401 channel_type
= empathy_dispatch_operation_get_channel_type_id (
402 approval
->operation
);
403 if (channel_type
== TP_IFACE_QUARK_CHANNEL_TYPE_STREAMED_MEDIA
)
406 if (priv
->ringing
== 0)
407 empathy_sound_stop (EMPATHY_SOUND_PHONE_INCOMING
);
411 priv
->approvals
= g_slist_remove (priv
->approvals
, approval
);
413 for (l
= priv
->events
; l
; l
= l
->next
)
415 EventPriv
*event
= l
->data
;
417 if (event
->approval
== approval
)
419 event_remove (event
);
424 event_manager_approval_free (approval
);
428 event_manager_operation_approved_cb (EmpathyDispatchOperation
*operation
,
429 EventManagerApproval
*approval
)
431 event_manager_approval_done (approval
);
435 event_manager_operation_claimed_cb (EmpathyDispatchOperation
*operation
,
436 EventManagerApproval
*approval
)
438 event_manager_approval_done (approval
);
442 event_manager_operation_invalidated_cb (EmpathyDispatchOperation
*operation
,
443 guint domain
, gint code
, gchar
*message
,
444 EventManagerApproval
*approval
)
446 event_manager_approval_done (approval
);
450 event_manager_media_channel_got_contact (EventManagerApproval
*approval
)
452 EmpathyEventManagerPriv
*priv
= GET_PRIV (approval
->manager
);
455 header
= g_strdup_printf (_("Incoming call from %s"),
456 empathy_contact_get_name (approval
->contact
));
458 event_manager_add (approval
->manager
, approval
->contact
,
459 EMPATHY_EVENT_TYPE_VOIP
, EMPATHY_IMAGE_VOIP
, header
, NULL
, approval
,
460 event_channel_process_voip_func
, NULL
);
465 if (priv
->ringing
== 1)
466 empathy_sound_start_playing (empathy_main_window_get (),
467 EMPATHY_SOUND_PHONE_INCOMING
, MS_BETWEEN_RING
);
471 event_manager_media_channel_contact_changed_cb (EmpathyTpCall
*call
,
472 GParamSpec
*param
, EventManagerApproval
*approval
)
474 EmpathyContact
*contact
;
476 g_object_get (G_OBJECT (call
), "contact", &contact
, NULL
);
481 approval
->contact
= contact
;
482 event_manager_media_channel_got_contact (approval
);
486 event_manager_tube_approved_cb (EventPriv
*event
)
488 empathy_tube_dispatch_handle (event
->approval
->tube_dispatch
);
492 event_manager_add_tube_approval (EventManagerApproval
*approval
,
493 EmpathyTubeDispatchAbility ability
)
495 const gchar
*icon_name
;
499 header
= g_strdup_printf (_("%s is offering you an invitation"),
500 empathy_contact_get_name (approval
->contact
));
502 if (ability
== EMPATHY_TUBE_DISPATCHABILITY_POSSIBLE
)
504 icon_name
= GTK_STOCK_EXECUTE
;
505 msg
= _("An external application will be started to handle it.");
509 icon_name
= GTK_STOCK_DIALOG_ERROR
;
510 msg
= _("You don't have the needed external "
511 "application to handle it.");
514 event_manager_add (approval
->manager
, approval
->contact
,
515 EMPATHY_EVENT_TYPE_TUBE
, icon_name
, header
, msg
, approval
,
516 event_manager_tube_approved_cb
, approval
);
519 /* FIXME better sound for incoming tubes ? */
520 empathy_sound_play (empathy_main_window_get (),
521 EMPATHY_SOUND_CONVERSATION_NEW
);
525 event_manager_tube_dispatch_ability_cb (GObject
*object
,
526 GParamSpec
*spec
, gpointer user_data
)
528 EventManagerApproval
*approval
= (EventManagerApproval
*) user_data
;
529 EmpathyTubeDispatchAbility dispatchability
;
532 empathy_tube_dispatch_is_dispatchable (approval
->tube_dispatch
);
534 if (dispatchability
!= EMPATHY_TUBE_DISPATCHABILITY_UNKNOWN
)
536 event_manager_add_tube_approval (approval
, dispatchability
);
537 g_signal_handler_disconnect (object
, approval
->handler
);
538 approval
->handler
= 0;
543 event_manager_tube_got_contact_cb (EmpathyTpContactFactory
*factory
,
544 EmpathyContact
*contact
,
549 EventManagerApproval
*approval
= (EventManagerApproval
*) user_data
;
550 EmpathyTubeDispatchAbility dispatchability
;
554 /* FIXME: We should probably still display the event */
555 DEBUG ("Error: %s", error
->message
);
559 approval
->contact
= g_object_ref (contact
);
561 dispatchability
= empathy_tube_dispatch_is_dispatchable
562 (approval
->tube_dispatch
);
564 switch (dispatchability
)
566 case EMPATHY_TUBE_DISPATCHABILITY_UNKNOWN
:
567 approval
->handler
= g_signal_connect (approval
->tube_dispatch
,
568 "notify::dispatchability",
569 G_CALLBACK (event_manager_tube_dispatch_ability_cb
), approval
);
570 approval
->handler_instance
= G_OBJECT (approval
->tube_dispatch
);
572 case EMPATHY_TUBE_DISPATCHABILITY_POSSIBLE
:
574 case EMPATHY_TUBE_DISPATCHABILITY_IMPOSSIBLE
:
575 event_manager_add_tube_approval (approval
, dispatchability
);
581 invite_dialog_response_cb (GtkDialog
*dialog
,
583 EventManagerApproval
*approval
)
585 EmpathyTpChat
*tp_chat
;
587 TpHandle self_handle
;
590 gtk_widget_destroy (GTK_WIDGET (approval
->dialog
));
591 approval
->dialog
= NULL
;
593 tp_chat
= EMPATHY_TP_CHAT (empathy_dispatch_operation_get_channel_wrapper (
594 approval
->operation
));
596 if (response
!= GTK_RESPONSE_OK
)
599 DEBUG ("Muc invitation rejected");
601 if (empathy_dispatch_operation_claim (approval
->operation
))
602 empathy_tp_chat_close (tp_chat
);
606 DEBUG ("Muc invitation accepted");
609 channel
= empathy_tp_chat_get_channel (tp_chat
);
611 self_handle
= tp_channel_group_get_self_handle (channel
);
612 members
= g_array_sized_new (FALSE
, FALSE
, sizeof (TpHandle
), 1);
613 g_array_append_val (members
, self_handle
);
615 tp_cli_channel_interface_group_call_add_members (channel
, -1, members
,
616 "", NULL
, NULL
, NULL
, NULL
);
618 empathy_dispatch_operation_approve (approval
->operation
);
620 g_array_free (members
, TRUE
);
624 event_room_channel_process_func (EventPriv
*event
)
626 GtkWidget
*dialog
, *button
, *image
;
627 TpChannel
*channel
= empathy_dispatch_operation_get_channel (
628 event
->approval
->operation
);
630 if (event
->approval
->dialog
!= NULL
)
632 gtk_window_present (GTK_WINDOW (event
->approval
->dialog
));
637 dialog
= gtk_message_dialog_new (NULL
, 0,
638 GTK_MESSAGE_QUESTION
, GTK_BUTTONS_NONE
, _("Room invitation"));
640 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog
),
641 _("%s is inviting you to join %s"),
642 empathy_contact_get_name (event
->approval
->contact
),
643 tp_channel_get_identifier (channel
));
645 gtk_dialog_set_default_response (GTK_DIALOG (dialog
),
648 button
= gtk_dialog_add_button (GTK_DIALOG (dialog
),
649 _("_Decline"), GTK_RESPONSE_CANCEL
);
650 image
= gtk_image_new_from_icon_name (GTK_STOCK_CANCEL
, GTK_ICON_SIZE_BUTTON
);
651 gtk_button_set_image (GTK_BUTTON (button
), image
);
653 button
= gtk_dialog_add_button (GTK_DIALOG (dialog
),
654 _("_Join"), GTK_RESPONSE_OK
);
655 image
= gtk_image_new_from_icon_name (GTK_STOCK_APPLY
, GTK_ICON_SIZE_BUTTON
);
656 gtk_button_set_image (GTK_BUTTON (button
), image
);
658 g_signal_connect (dialog
, "response",
659 G_CALLBACK (invite_dialog_response_cb
), event
->approval
);
661 gtk_widget_show (dialog
);
663 event
->approval
->dialog
= dialog
;
667 event_manager_muc_invite_got_contact_cb (EmpathyTpContactFactory
*factory
,
668 EmpathyContact
*contact
,
673 EventManagerApproval
*approval
= (EventManagerApproval
*) user_data
;
675 const gchar
*invite_msg
;
677 TpHandle self_handle
;
681 /* FIXME: We should probably still display the event */
682 DEBUG ("Error: %s", error
->message
);
686 approval
->contact
= g_object_ref (contact
);
687 channel
= empathy_dispatch_operation_get_channel (approval
->operation
);
689 self_handle
= tp_channel_group_get_self_handle (channel
);
690 tp_channel_group_get_local_pending_info (channel
, self_handle
, NULL
, NULL
,
693 msg
= g_strdup_printf (_("%s invited you to join %s"),
694 empathy_contact_get_name (approval
->contact
),
695 tp_channel_get_identifier (channel
));
697 event_manager_add (approval
->manager
, approval
->contact
,
698 EMPATHY_EVENT_TYPE_CHAT
, EMPATHY_IMAGE_GROUP_MESSAGE
, msg
, invite_msg
,
699 approval
, event_room_channel_process_func
, NULL
);
701 empathy_sound_play (empathy_main_window_get (),
702 EMPATHY_SOUND_CONVERSATION_NEW
);
708 event_manager_ft_got_contact_cb (EmpathyTpContactFactory
*factory
,
709 EmpathyContact
*contact
,
714 EventManagerApproval
*approval
= (EventManagerApproval
*) user_data
;
717 approval
->contact
= contact
;
719 header
= g_strdup_printf (_("Incoming file transfer from %s"),
720 empathy_contact_get_name (approval
->contact
));
722 event_manager_add (approval
->manager
, approval
->contact
,
723 EMPATHY_EVENT_TYPE_TRANSFER
, EMPATHY_IMAGE_DOCUMENT_SEND
, header
, NULL
,
724 approval
, event_channel_process_func
, NULL
);
726 /* FIXME better sound for incoming file transfers ?*/
727 empathy_sound_play (empathy_main_window_get (),
728 EMPATHY_SOUND_CONVERSATION_NEW
);
734 event_manager_approve_channel_cb (EmpathyDispatcher
*dispatcher
,
735 EmpathyDispatchOperation
*operation
, EmpathyEventManager
*manager
)
737 const gchar
*channel_type
;
738 EventManagerApproval
*approval
;
739 EmpathyEventManagerPriv
*priv
= GET_PRIV (manager
);
741 channel_type
= empathy_dispatch_operation_get_channel_type (operation
);
743 approval
= event_manager_approval_new (manager
, operation
);
744 priv
->approvals
= g_slist_prepend (priv
->approvals
, approval
);
746 approval
->approved_handler
= g_signal_connect (operation
, "approved",
747 G_CALLBACK (event_manager_operation_approved_cb
), approval
);
749 approval
->claimed_handler
= g_signal_connect (operation
, "claimed",
750 G_CALLBACK (event_manager_operation_claimed_cb
), approval
);
752 approval
->invalidated_handler
= g_signal_connect (operation
, "invalidated",
753 G_CALLBACK (event_manager_operation_invalidated_cb
), approval
);
755 if (!tp_strdiff (channel_type
, TP_IFACE_CHANNEL_TYPE_TEXT
))
757 EmpathyTpChat
*tp_chat
=
759 empathy_dispatch_operation_get_channel_wrapper (operation
));
760 TpChannel
*channel
= empathy_tp_chat_get_channel (tp_chat
);
762 if (tp_proxy_has_interface (channel
, TP_IFACE_CHANNEL_INTERFACE_GROUP
))
764 /* Are we in local-pending ? */
765 TpHandle self_handle
, inviter
;
767 self_handle
= tp_channel_group_get_self_handle (channel
);
769 if (self_handle
!= 0 && tp_channel_group_get_local_pending_info (
770 channel
, self_handle
, &inviter
, NULL
, NULL
))
772 /* We are invited to a room */
773 EmpathyTpContactFactory
*factory
;
774 TpConnection
*connection
;
776 DEBUG ("Have been invited to %s. Ask user if he wants to accept",
777 tp_channel_get_identifier (channel
));
779 connection
= empathy_tp_chat_get_connection (tp_chat
);
780 factory
= empathy_tp_contact_factory_dup_singleton (connection
);
782 empathy_tp_contact_factory_get_from_handle (factory
,
783 inviter
, event_manager_muc_invite_got_contact_cb
,
784 approval
, NULL
, G_OBJECT (manager
));
786 g_object_unref (factory
);
790 /* if we are not invited, let's wait for the first message */
793 /* 1-1 text channel, wait for the first message */
794 approval
->handler
= g_signal_connect (tp_chat
, "message-received",
795 G_CALLBACK (event_manager_chat_message_received_cb
), approval
);
796 approval
->handler_instance
= G_OBJECT (tp_chat
);
798 else if (!tp_strdiff (channel_type
, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA
))
800 EmpathyContact
*contact
;
801 EmpathyTpCall
*call
= EMPATHY_TP_CALL (
802 empathy_dispatch_operation_get_channel_wrapper (operation
));
804 g_object_get (G_OBJECT (call
), "contact", &contact
, NULL
);
808 g_signal_connect (call
, "notify::contact",
809 G_CALLBACK (event_manager_media_channel_contact_changed_cb
),
814 approval
->contact
= contact
;
815 event_manager_media_channel_got_contact (approval
);
819 else if (!tp_strdiff (channel_type
, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER
))
822 TpConnection
*connection
;
824 EmpathyTpContactFactory
*factory
;
826 channel
= empathy_dispatch_operation_get_channel (operation
);
827 handle
= tp_channel_get_handle (channel
, NULL
);
829 connection
= tp_channel_borrow_connection (channel
);
830 factory
= empathy_tp_contact_factory_dup_singleton (connection
);
831 empathy_tp_contact_factory_get_from_handle (factory
, handle
,
832 event_manager_ft_got_contact_cb
, approval
, NULL
, G_OBJECT (manager
));
834 g_object_unref (factory
);
836 else if (!tp_strdiff (channel_type
, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE
) ||
837 !tp_strdiff (channel_type
, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE
))
841 TpHandleType handle_type
;
842 TpConnection
*connection
;
843 EmpathyTpContactFactory
*factory
;
845 channel
= empathy_dispatch_operation_get_channel (operation
);
846 handle
= tp_channel_get_handle (channel
, &handle_type
);
848 /* Only understand p2p tubes */
849 if (handle_type
!= TP_HANDLE_TYPE_CONTACT
)
852 approval
->tube_dispatch
= empathy_tube_dispatch_new (operation
);
853 connection
= tp_channel_borrow_connection (channel
);
854 factory
= empathy_tp_contact_factory_dup_singleton (connection
);
855 empathy_tp_contact_factory_get_from_handle (factory
, handle
,
856 event_manager_tube_got_contact_cb
, approval
, NULL
, G_OBJECT (manager
));
860 DEBUG ("Unknown channel type (%s), ignoring..", channel_type
);
865 event_pending_subscribe_func (EventPriv
*event
)
867 empathy_subscription_dialog_show (event
->public.contact
, NULL
);
868 event_remove (event
);
872 event_manager_pendings_changed_cb (EmpathyContactList
*list
,
873 EmpathyContact
*contact
, EmpathyContact
*actor
,
874 guint reason
, gchar
*message
, gboolean is_pending
,
875 EmpathyEventManager
*manager
)
877 EmpathyEventManagerPriv
*priv
= GET_PRIV (manager
);
878 gchar
*header
, *event_msg
;
884 for (l
= priv
->events
; l
; l
= l
->next
)
886 EventPriv
*event
= l
->data
;
888 if (event
->public.contact
== contact
&&
889 event
->func
== event_pending_subscribe_func
)
891 event_remove (event
);
899 header
= g_strdup_printf (_("Subscription requested by %s"),
900 empathy_contact_get_name (contact
));
902 if (!EMP_STR_EMPTY (message
))
903 event_msg
= g_strdup_printf (_("\nMessage: %s"), message
);
907 event_manager_add (manager
, contact
, EMPATHY_EVENT_TYPE_SUBSCRIPTION
,
908 GTK_STOCK_DIALOG_QUESTION
, header
, event_msg
, NULL
,
909 event_pending_subscribe_func
, NULL
);
916 event_manager_presence_changed_cb (EmpathyContactMonitor
*monitor
,
917 EmpathyContact
*contact
,
918 TpConnectionPresenceType current
,
919 TpConnectionPresenceType previous
,
920 EmpathyEventManager
*manager
)
923 gchar
*header
= NULL
;
924 gboolean preference
= FALSE
;
927 account
= empathy_contact_get_account (contact
);
928 idle
= empathy_idle_dup_singleton ();
930 if (empathy_idle_account_is_just_connected (idle
, account
))
933 if (tp_connection_presence_type_cmp_availability (previous
,
934 TP_CONNECTION_PRESENCE_TYPE_OFFLINE
) > 0)
936 /* contact was online */
937 empathy_conf_get_bool (empathy_conf_get (),
938 EMPATHY_PREFS_NOTIFICATIONS_CONTACT_SIGNOUT
, &preference
);
939 if (preference
&& tp_connection_presence_type_cmp_availability (current
,
940 TP_CONNECTION_PRESENCE_TYPE_OFFLINE
) <= 0)
942 /* someone is logging off */
943 header
= g_strdup_printf (_("%s is now offline."),
944 empathy_contact_get_name (contact
));
946 event_manager_add (manager
, contact
, EMPATHY_EVENT_TYPE_PRESENCE
,
947 GTK_STOCK_DIALOG_INFO
, header
, NULL
, NULL
, NULL
, NULL
);
952 /* contact was offline */
953 empathy_conf_get_bool (empathy_conf_get (),
954 EMPATHY_PREFS_NOTIFICATIONS_CONTACT_SIGNIN
, &preference
);
955 if (preference
&& tp_connection_presence_type_cmp_availability (current
,
956 TP_CONNECTION_PRESENCE_TYPE_OFFLINE
) > 0)
958 /* someone is logging in */
959 header
= g_strdup_printf (_("%s is now online."),
960 empathy_contact_get_name (contact
));
962 event_manager_add (manager
, contact
, EMPATHY_EVENT_TYPE_PRESENCE
,
963 GTK_STOCK_DIALOG_INFO
, header
, NULL
, NULL
, NULL
, NULL
);
969 g_object_unref (idle
);
974 event_manager_constructor (GType type
,
976 GObjectConstructParam
*props
)
980 if (manager_singleton
) {
981 retval
= g_object_ref (manager_singleton
);
983 retval
= G_OBJECT_CLASS (empathy_event_manager_parent_class
)->constructor
984 (type
, n_props
, props
);
986 manager_singleton
= EMPATHY_EVENT_MANAGER (retval
);
987 g_object_add_weak_pointer (retval
, (gpointer
) &manager_singleton
);
994 event_manager_finalize (GObject
*object
)
996 EmpathyEventManagerPriv
*priv
= GET_PRIV (object
);
998 if (priv
->ringing
> 0)
999 empathy_sound_stop (EMPATHY_SOUND_PHONE_INCOMING
);
1001 g_slist_foreach (priv
->events
, (GFunc
) event_free
, NULL
);
1002 g_slist_free (priv
->events
);
1003 g_slist_foreach (priv
->approvals
, (GFunc
) event_manager_approval_free
, NULL
);
1004 g_slist_free (priv
->approvals
);
1005 g_object_unref (priv
->contact_manager
);
1006 g_object_unref (priv
->dispatcher
);
1010 empathy_event_manager_class_init (EmpathyEventManagerClass
*klass
)
1012 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
1014 object_class
->finalize
= event_manager_finalize
;
1015 object_class
->constructor
= event_manager_constructor
;
1017 signals
[EVENT_ADDED
] =
1018 g_signal_new ("event-added",
1019 G_TYPE_FROM_CLASS (klass
),
1023 g_cclosure_marshal_VOID__POINTER
,
1027 signals
[EVENT_REMOVED
] =
1028 g_signal_new ("event-removed",
1029 G_TYPE_FROM_CLASS (klass
),
1033 g_cclosure_marshal_VOID__POINTER
,
1034 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1036 signals
[EVENT_UPDATED
] =
1037 g_signal_new ("event-updated",
1038 G_TYPE_FROM_CLASS (klass
),
1042 g_cclosure_marshal_VOID__POINTER
,
1043 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1046 g_type_class_add_private (object_class
, sizeof (EmpathyEventManagerPriv
));
1050 empathy_event_manager_init (EmpathyEventManager
*manager
)
1052 EmpathyEventManagerPriv
*priv
= G_TYPE_INSTANCE_GET_PRIVATE (manager
,
1053 EMPATHY_TYPE_EVENT_MANAGER
, EmpathyEventManagerPriv
);
1054 EmpathyContactMonitor
*monitor
;
1055 EmpathyContactList
*list_iface
;
1057 list_iface
= EMPATHY_CONTACT_LIST (empathy_contact_manager_dup_singleton ());
1058 monitor
= empathy_contact_list_get_monitor (list_iface
);
1059 g_object_unref (list_iface
);
1061 manager
->priv
= priv
;
1063 priv
->dispatcher
= empathy_dispatcher_dup_singleton ();
1064 priv
->contact_manager
= empathy_contact_manager_dup_singleton ();
1065 g_signal_connect (priv
->dispatcher
, "approve",
1066 G_CALLBACK (event_manager_approve_channel_cb
), manager
);
1067 g_signal_connect (priv
->contact_manager
, "pendings-changed",
1068 G_CALLBACK (event_manager_pendings_changed_cb
), manager
);
1069 g_signal_connect (monitor
, "contact-presence-changed",
1070 G_CALLBACK (event_manager_presence_changed_cb
), manager
);
1073 EmpathyEventManager
*
1074 empathy_event_manager_dup_singleton (void)
1076 return g_object_new (EMPATHY_TYPE_EVENT_MANAGER
, NULL
);
1080 empathy_event_manager_get_events (EmpathyEventManager
*manager
)
1082 EmpathyEventManagerPriv
*priv
= GET_PRIV (manager
);
1084 g_return_val_if_fail (EMPATHY_IS_EVENT_MANAGER (manager
), NULL
);
1086 return priv
->events
;
1090 empathy_event_manager_get_top_event (EmpathyEventManager
*manager
)
1092 EmpathyEventManagerPriv
*priv
= GET_PRIV (manager
);
1094 g_return_val_if_fail (EMPATHY_IS_EVENT_MANAGER (manager
), NULL
);
1096 return priv
->events
? priv
->events
->data
: NULL
;
1100 empathy_event_activate (EmpathyEvent
*event_public
)
1102 EventPriv
*event
= (EventPriv
*) event_public
;
1104 g_return_if_fail (event_public
!= NULL
);
1107 event
->func (event
);
1109 event_remove (event
);
1113 empathy_event_inhibit_updates (EmpathyEvent
*event_public
)
1115 EventPriv
*event
= (EventPriv
*) event_public
;
1117 g_return_if_fail (event_public
!= NULL
);
1119 event
->inhibit
= TRUE
;