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>
30 #include <telepathy-glib/simple-approver.h>
32 #include <libempathy/empathy-dispatcher.h>
33 #include <libempathy/empathy-idle.h>
34 #include <libempathy/empathy-tp-contact-factory.h>
35 #include <libempathy/empathy-contact-manager.h>
36 #include <libempathy/empathy-tp-chat.h>
37 #include <libempathy/empathy-tp-call.h>
38 #include <libempathy/empathy-tp-file.h>
39 #include <libempathy/empathy-utils.h>
40 #include <libempathy/empathy-call-factory.h>
41 #include <libempathy/empathy-gsettings.h>
43 #include <extensions/extensions.h>
45 #include <libempathy-gtk/empathy-images.h>
46 #include <libempathy-gtk/empathy-contact-dialogs.h>
47 #include <libempathy-gtk/empathy-sound.h>
49 #include "empathy-event-manager.h"
50 #include "empathy-main-window.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 TpChannelDispatchOperation
*operation
;
65 gulong invalidated_handler
;
66 /* Remove contact if applicable */
67 EmpathyContact
*contact
;
68 /* option signal handler and it's instance */
70 GObject
*handler_instance
;
71 /* optional accept widget */
73 /* Channel of the CDO that will be used during the approval */
74 TpChannel
*main_channel
;
75 gboolean auto_approved
;
76 } EventManagerApproval
;
79 EmpathyDispatcher
*dispatcher
;
80 TpBaseClient
*approver
;
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
;
99 guint autoremove_timeout_id
;
109 static guint signals
[LAST_SIGNAL
];
111 G_DEFINE_TYPE (EmpathyEventManager
, empathy_event_manager
, G_TYPE_OBJECT
);
113 static EmpathyEventManager
* manager_singleton
= NULL
;
115 static EventManagerApproval
*
116 event_manager_approval_new (EmpathyEventManager
*manager
,
117 TpChannelDispatchOperation
*operation
,
118 TpChannel
*main_channel
)
120 EventManagerApproval
*result
= g_slice_new0 (EventManagerApproval
);
121 result
->operation
= g_object_ref (operation
);
122 result
->manager
= manager
;
123 result
->main_channel
= g_object_ref (main_channel
);
129 event_manager_approval_free (EventManagerApproval
*approval
)
131 g_signal_handler_disconnect (approval
->operation
,
132 approval
->invalidated_handler
);
133 g_object_unref (approval
->operation
);
135 g_object_unref (approval
->main_channel
);
137 if (approval
->handler
!= 0)
138 g_signal_handler_disconnect (approval
->handler_instance
,
141 if (approval
->handler_instance
!= NULL
)
142 g_object_unref (approval
->handler_instance
);
144 if (approval
->contact
!= NULL
)
145 g_object_unref (approval
->contact
);
147 if (approval
->dialog
!= NULL
)
149 gtk_widget_destroy (approval
->dialog
);
152 g_slice_free (EventManagerApproval
, approval
);
155 static void event_remove (EventPriv
*event
);
158 event_free (EventPriv
*event
)
160 g_free (event
->public.icon_name
);
161 g_free (event
->public.header
);
162 g_free (event
->public.message
);
164 if (event
->autoremove_timeout_id
!= 0)
165 g_source_remove (event
->autoremove_timeout_id
);
167 if (event
->public.contact
)
169 g_object_unref (event
->public.contact
);
172 g_slice_free (EventPriv
, event
);
176 event_remove (EventPriv
*event
)
178 EmpathyEventManagerPriv
*priv
= GET_PRIV (event
->manager
);
180 DEBUG ("Removing event %p", event
);
182 priv
->events
= g_slist_remove (priv
->events
, event
);
183 g_signal_emit (event
->manager
, signals
[EVENT_REMOVED
], 0, event
);
188 autoremove_event_timeout_cb (EventPriv
*event
)
190 event
->autoremove_timeout_id
= 0;
191 event_remove (event
);
196 display_notify_area (void)
199 GSettings
*gsettings
;
202 gsettings
= g_settings_new (EMPATHY_PREFS_UI_SCHEMA
);
204 result
= g_settings_get_boolean (gsettings
,
205 EMPATHY_PREFS_UI_EVENTS_NOTIFY_AREA
);
206 g_object_unref (gsettings
);
212 event_manager_add (EmpathyEventManager
*manager
,
213 EmpathyContact
*contact
,
214 EmpathyEventType type
,
215 const gchar
*icon_name
,
217 const gchar
*message
,
218 EventManagerApproval
*approval
,
222 EmpathyEventManagerPriv
*priv
= GET_PRIV (manager
);
225 event
= g_slice_new0 (EventPriv
);
226 event
->public.contact
= contact
? g_object_ref (contact
) : NULL
;
227 event
->public.type
= type
;
228 event
->public.icon_name
= g_strdup (icon_name
);
229 event
->public.header
= g_strdup (header
);
230 event
->public.message
= g_strdup (message
);
231 event
->public.must_ack
= (func
!= NULL
);
232 event
->inhibit
= FALSE
;
234 event
->user_data
= user_data
;
235 event
->manager
= manager
;
236 event
->approval
= approval
;
238 DEBUG ("Adding event %p", event
);
239 priv
->events
= g_slist_prepend (priv
->events
, event
);
241 if (!display_notify_area ())
243 /* Don't fire the 'event-added' signal as we activate the event now */
244 if (approval
!= NULL
)
245 approval
->auto_approved
= TRUE
;
247 empathy_event_activate (&event
->public);
251 g_signal_emit (event
->manager
, signals
[EVENT_ADDED
], 0, event
);
253 if (!event
->public.must_ack
)
255 event
->autoremove_timeout_id
= g_timeout_add_seconds (
256 NOTIFICATION_TIMEOUT
, (GSourceFunc
) autoremove_event_timeout_cb
,
262 handle_with_cb (GObject
*source
,
263 GAsyncResult
*result
,
266 TpChannelDispatchOperation
*cdo
= TP_CHANNEL_DISPATCH_OPERATION (source
);
267 GError
*error
= NULL
;
269 if (!tp_channel_dispatch_operation_handle_with_finish (cdo
, result
, &error
))
271 DEBUG ("HandleWith failed: %s\n", error
->message
);
272 g_error_free (error
);
277 handle_with_time_cb (GObject
*source
,
278 GAsyncResult
*result
,
281 TpChannelDispatchOperation
*cdo
= TP_CHANNEL_DISPATCH_OPERATION (source
);
282 GError
*error
= NULL
;
284 if (!tp_channel_dispatch_operation_handle_with_time_finish (cdo
, result
,
287 if (g_error_matches (error
, TP_ERRORS
, TP_ERROR_NOT_IMPLEMENTED
))
289 EventManagerApproval
*approval
= user_data
;
291 DEBUG ("HandleWithTime() is not implemented, falling back to "
292 "HandleWith(). Please upgrade to telepathy-mission-control "
295 tp_channel_dispatch_operation_handle_with_async (approval
->operation
,
296 NULL
, handle_with_cb
, approval
);
300 DEBUG ("HandleWithTime failed: %s\n", error
->message
);
302 g_error_free (error
);
307 event_manager_approval_approve (EventManagerApproval
*approval
)
311 if (approval
->auto_approved
)
313 timestamp
= EMPATHY_DISPATCHER_NON_USER_ACTION
;
317 timestamp
= gtk_get_current_event_time ();
319 if (timestamp
== GDK_CURRENT_TIME
)
320 timestamp
= EMPATHY_DISPATCHER_CURRENT_TIME
;
323 g_assert (approval
->operation
!= NULL
);
325 tp_channel_dispatch_operation_handle_with_time_async (approval
->operation
,
326 NULL
, timestamp
, handle_with_time_cb
, approval
);
330 event_channel_process_func (EventPriv
*event
)
332 event_manager_approval_approve (event
->approval
);
336 event_text_channel_process_func (EventPriv
*event
)
338 EmpathyTpChat
*tp_chat
;
339 gint64 timestamp
= gtk_get_current_event_time ();
340 if (timestamp
== GDK_CURRENT_TIME
)
341 timestamp
= EMPATHY_DISPATCHER_CURRENT_TIME
;
343 if (event
->approval
->handler
!= 0)
345 tp_chat
= EMPATHY_TP_CHAT (event
->approval
->handler_instance
);
347 g_signal_handler_disconnect (tp_chat
, event
->approval
->handler
);
348 event
->approval
->handler
= 0;
351 event_manager_approval_approve (event
->approval
);
355 event_lookup_by_approval (EmpathyEventManager
*manager
,
356 EventManagerApproval
*approval
)
358 EmpathyEventManagerPriv
*priv
= GET_PRIV (manager
);
360 EventPriv
*retval
= NULL
;
362 for (l
= priv
->events
; l
; l
= l
->next
)
364 EventPriv
*event
= l
->data
;
366 if (event
->approval
== approval
)
377 event_update (EmpathyEventManager
*manager
, EventPriv
*event
,
378 const char *icon_name
, const char *header
, const char *msg
)
380 g_free (event
->public.icon_name
);
381 g_free (event
->public.header
);
382 g_free (event
->public.message
);
384 event
->public.icon_name
= g_strdup (icon_name
);
385 event
->public.header
= g_strdup (header
);
386 event
->public.message
= g_strdup (msg
);
388 g_signal_emit (manager
, signals
[EVENT_UPDATED
], 0, event
);
392 reject_channel_claim_cb (GObject
*source
,
393 GAsyncResult
*result
,
396 TpChannelDispatchOperation
*cdo
= TP_CHANNEL_DISPATCH_OPERATION (source
);
397 GError
*error
= NULL
;
399 if (!tp_channel_dispatch_operation_claim_finish (cdo
, result
, &error
))
401 DEBUG ("Failed to claim channel: %s", error
->message
);
403 g_error_free (error
);
407 if (EMPATHY_IS_TP_CALL (user_data
))
409 empathy_tp_call_close (user_data
);
411 else if (EMPATHY_IS_TP_CHAT (user_data
))
413 empathy_tp_chat_leave (user_data
);
415 else if (EMPATHY_IS_TP_FILE (user_data
))
417 empathy_tp_file_close (user_data
);
421 g_object_unref (user_data
);
425 reject_approval (EventManagerApproval
*approval
)
427 /* We have to claim the channel before closing it */
428 tp_channel_dispatch_operation_claim_async (approval
->operation
,
429 reject_channel_claim_cb
, g_object_ref (approval
->handler_instance
));
433 event_manager_call_window_confirmation_dialog_response_cb (GtkDialog
*dialog
,
434 gint response
, gpointer user_data
)
436 EventManagerApproval
*approval
= user_data
;
438 gtk_widget_destroy (approval
->dialog
);
439 approval
->dialog
= NULL
;
441 if (response
!= GTK_RESPONSE_ACCEPT
)
443 reject_approval (approval
);
447 event_manager_approval_approve (approval
);
452 event_channel_process_voip_func (EventPriv
*event
)
461 if (event
->approval
->dialog
!= NULL
)
463 gtk_window_present (GTK_WINDOW (event
->approval
->dialog
));
467 call
= EMPATHY_TP_CALL (event
->approval
->handler_instance
);
469 video
= empathy_tp_call_has_initial_video (call
);
471 dialog
= gtk_message_dialog_new (NULL
, 0,
472 GTK_MESSAGE_QUESTION
, GTK_BUTTONS_NONE
,
473 video
? _("Incoming video call"): _("Incoming call"));
475 gtk_message_dialog_format_secondary_text (
476 GTK_MESSAGE_DIALOG (dialog
), video
?
477 _("%s is video calling you. Do you want to answer?"):
478 _("%s is calling you. Do you want to answer?"),
479 empathy_contact_get_alias (event
->approval
->contact
));
481 title
= g_strdup_printf (_("Incoming call from %s"),
482 empathy_contact_get_alias (event
->approval
->contact
));
484 gtk_window_set_title (GTK_WINDOW (dialog
), title
);
487 /* Set image of the dialog */
490 image
= gtk_image_new_from_icon_name (EMPATHY_IMAGE_VIDEO_CALL
,
491 GTK_ICON_SIZE_DIALOG
);
495 image
= gtk_image_new_from_icon_name (EMPATHY_IMAGE_VOIP
,
496 GTK_ICON_SIZE_DIALOG
);
499 gtk_message_dialog_set_image (GTK_MESSAGE_DIALOG (dialog
), image
);
500 gtk_widget_show (image
);
502 gtk_dialog_set_default_response (GTK_DIALOG (dialog
),
505 button
= gtk_dialog_add_button (GTK_DIALOG (dialog
),
506 _("_Reject"), GTK_RESPONSE_REJECT
);
507 image
= gtk_image_new_from_icon_name ("call-stop",
508 GTK_ICON_SIZE_BUTTON
);
509 gtk_button_set_image (GTK_BUTTON (button
), image
);
511 button
= gtk_dialog_add_button (GTK_DIALOG (dialog
),
512 _("_Answer"), GTK_RESPONSE_ACCEPT
);
514 image
= gtk_image_new_from_icon_name ("call-start", GTK_ICON_SIZE_BUTTON
);
515 gtk_button_set_image (GTK_BUTTON (button
), image
);
517 g_signal_connect (dialog
, "response",
518 G_CALLBACK (event_manager_call_window_confirmation_dialog_response_cb
),
521 gtk_widget_show (dialog
);
523 event
->approval
->dialog
= dialog
;
527 event_manager_chat_message_received_cb (EmpathyTpChat
*tp_chat
,
528 EmpathyMessage
*message
,
529 EventManagerApproval
*approval
)
531 GtkWidget
*window
= empathy_main_window_dup ();
532 EmpathyContact
*sender
;
538 /* try to update the event if it's referring to a chat which is already in the
540 event
= event_lookup_by_approval (approval
->manager
, approval
);
542 sender
= empathy_message_get_sender (message
);
543 header
= empathy_contact_get_alias (sender
);
544 msg
= empathy_message_get_body (message
);
546 channel
= empathy_tp_chat_get_channel (tp_chat
);
549 event_update (approval
->manager
, event
, EMPATHY_IMAGE_NEW_MESSAGE
, header
,
552 event_manager_add (approval
->manager
, sender
, EMPATHY_EVENT_TYPE_CHAT
,
553 EMPATHY_IMAGE_NEW_MESSAGE
, header
, msg
, approval
,
554 event_text_channel_process_func
, NULL
);
556 empathy_sound_play (window
, EMPATHY_SOUND_CONVERSATION_NEW
);
558 g_object_unref (window
);
562 event_manager_approval_done (EventManagerApproval
*approval
)
564 EmpathyEventManagerPriv
*priv
= GET_PRIV (approval
->manager
);
567 if (approval
->operation
!= NULL
)
571 channel_type
= tp_channel_get_channel_type_id (approval
->main_channel
);
573 if (channel_type
== TP_IFACE_QUARK_CHANNEL_TYPE_STREAMED_MEDIA
)
576 if (priv
->ringing
== 0)
577 empathy_sound_stop (EMPATHY_SOUND_PHONE_INCOMING
);
581 priv
->approvals
= g_slist_remove (priv
->approvals
, approval
);
583 for (l
= priv
->events
; l
; l
= l
->next
)
585 EventPriv
*event
= l
->data
;
587 if (event
->approval
== approval
)
589 event_remove (event
);
594 event_manager_approval_free (approval
);
598 cdo_invalidated_cb (TpProxy
*cdo
,
602 EventManagerApproval
*approval
)
604 DEBUG ("ChannelDispatchOperation has been invalidated: %s", message
);
606 event_manager_approval_done (approval
);
610 event_manager_media_channel_got_contact (EventManagerApproval
*approval
)
612 EmpathyEventManagerPriv
*priv
= GET_PRIV (approval
->manager
);
613 GtkWidget
*window
= empathy_main_window_dup ();
618 call
= EMPATHY_TP_CALL (approval
->handler_instance
);
620 video
= empathy_tp_call_has_initial_video (call
);
622 header
= g_strdup_printf (
623 video
? _("Incoming video call from %s") :_("Incoming call from %s"),
624 empathy_contact_get_alias (approval
->contact
));
626 event_manager_add (approval
->manager
, approval
->contact
,
627 EMPATHY_EVENT_TYPE_VOIP
,
628 video
? EMPATHY_IMAGE_VIDEO_CALL
: EMPATHY_IMAGE_VOIP
,
629 header
, NULL
, approval
,
630 event_channel_process_voip_func
, NULL
);
635 if (priv
->ringing
== 1)
636 empathy_sound_start_playing (window
,
637 EMPATHY_SOUND_PHONE_INCOMING
, MS_BETWEEN_RING
);
639 g_object_unref (window
);
643 event_manager_media_channel_contact_changed_cb (EmpathyTpCall
*call
,
644 GParamSpec
*param
, EventManagerApproval
*approval
)
646 EmpathyContact
*contact
;
648 g_object_get (G_OBJECT (call
), "contact", &contact
, NULL
);
653 approval
->contact
= contact
;
654 event_manager_media_channel_got_contact (approval
);
658 invite_dialog_response_cb (GtkDialog
*dialog
,
660 EventManagerApproval
*approval
)
662 EmpathyTpChat
*tp_chat
;
664 gtk_widget_destroy (GTK_WIDGET (approval
->dialog
));
665 approval
->dialog
= NULL
;
667 tp_chat
= EMPATHY_TP_CHAT (approval
->handler_instance
);
669 if (response
!= GTK_RESPONSE_OK
)
672 DEBUG ("Muc invitation rejected");
674 reject_approval (approval
);
679 DEBUG ("Muc invitation accepted");
681 /* We'll join the room when handling the channel */
682 event_manager_approval_approve (approval
);
686 event_room_channel_process_func (EventPriv
*event
)
688 GtkWidget
*dialog
, *button
, *image
;
689 TpChannel
*channel
= event
->approval
->main_channel
;
692 if (event
->approval
->dialog
!= NULL
)
694 gtk_window_present (GTK_WINDOW (event
->approval
->dialog
));
699 dialog
= gtk_message_dialog_new (NULL
, 0,
700 GTK_MESSAGE_QUESTION
, GTK_BUTTONS_NONE
, _("Room invitation"));
702 title
= g_strdup_printf (_("Invitation to join %s"),
703 tp_channel_get_identifier (channel
));
705 gtk_window_set_title (GTK_WINDOW (dialog
), title
);
708 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog
),
709 _("%s is inviting you to join %s"),
710 empathy_contact_get_alias (event
->approval
->contact
),
711 tp_channel_get_identifier (channel
));
713 gtk_dialog_set_default_response (GTK_DIALOG (dialog
),
716 button
= gtk_dialog_add_button (GTK_DIALOG (dialog
),
717 _("_Decline"), GTK_RESPONSE_CANCEL
);
718 image
= gtk_image_new_from_icon_name (GTK_STOCK_CANCEL
, GTK_ICON_SIZE_BUTTON
);
719 gtk_button_set_image (GTK_BUTTON (button
), image
);
721 button
= gtk_dialog_add_button (GTK_DIALOG (dialog
),
722 _("_Join"), GTK_RESPONSE_OK
);
723 image
= gtk_image_new_from_icon_name (GTK_STOCK_APPLY
, GTK_ICON_SIZE_BUTTON
);
724 gtk_button_set_image (GTK_BUTTON (button
), image
);
726 g_signal_connect (dialog
, "response",
727 G_CALLBACK (invite_dialog_response_cb
), event
->approval
);
729 gtk_widget_show (dialog
);
731 event
->approval
->dialog
= dialog
;
735 event_manager_muc_invite_got_contact_cb (TpConnection
*connection
,
736 EmpathyContact
*contact
,
741 EventManagerApproval
*approval
= (EventManagerApproval
*) user_data
;
742 GtkWidget
*window
= empathy_main_window_dup ();
743 const gchar
*invite_msg
;
745 TpHandle self_handle
;
749 /* FIXME: We should probably still display the event */
750 DEBUG ("Error: %s", error
->message
);
754 approval
->contact
= g_object_ref (contact
);
756 self_handle
= tp_channel_group_get_self_handle (approval
->main_channel
);
757 tp_channel_group_get_local_pending_info (approval
->main_channel
, self_handle
,
758 NULL
, NULL
, &invite_msg
);
760 msg
= g_strdup_printf (_("%s invited you to join %s"),
761 empathy_contact_get_alias (approval
->contact
),
762 tp_channel_get_identifier (approval
->main_channel
));
764 event_manager_add (approval
->manager
, approval
->contact
,
765 EMPATHY_EVENT_TYPE_INVITATION
, EMPATHY_IMAGE_GROUP_MESSAGE
, msg
,
766 invite_msg
, approval
, event_room_channel_process_func
, NULL
);
768 empathy_sound_play (window
, EMPATHY_SOUND_CONVERSATION_NEW
);
771 g_object_unref (window
);
775 event_manager_ft_got_contact_cb (TpConnection
*connection
,
776 EmpathyContact
*contact
,
781 EventManagerApproval
*approval
= (EventManagerApproval
*) user_data
;
782 GtkWidget
*window
= empathy_main_window_dup ();
785 approval
->contact
= g_object_ref (contact
);
787 header
= g_strdup_printf (_("Incoming file transfer from %s"),
788 empathy_contact_get_alias (approval
->contact
));
790 event_manager_add (approval
->manager
, approval
->contact
,
791 EMPATHY_EVENT_TYPE_TRANSFER
, EMPATHY_IMAGE_DOCUMENT_SEND
, header
, NULL
,
792 approval
, event_channel_process_func
, NULL
);
794 /* FIXME better sound for incoming file transfers ?*/
795 empathy_sound_play (window
, EMPATHY_SOUND_CONVERSATION_NEW
);
798 g_object_unref (window
);
801 /* If there is a file-transfer or media channel consider it as the
804 find_main_channel (GList
*channels
)
807 TpChannel
*text
= NULL
;
809 for (l
= channels
; l
!= NULL
; l
= g_list_next (l
))
811 TpChannel
*channel
= l
->data
;
814 if (tp_proxy_get_invalidated (channel
) != NULL
)
817 channel_type
= tp_channel_get_channel_type_id (channel
);
819 if (channel_type
== TP_IFACE_QUARK_CHANNEL_TYPE_STREAMED_MEDIA
||
820 channel_type
== TP_IFACE_QUARK_CHANNEL_TYPE_FILE_TRANSFER
)
823 else if (channel_type
== TP_IFACE_QUARK_CHANNEL_TYPE_TEXT
)
831 approve_channels (TpSimpleApprover
*approver
,
833 TpConnection
*connection
,
835 TpChannelDispatchOperation
*dispatch_operation
,
836 TpAddDispatchOperationContext
*context
,
839 EmpathyEventManager
*self
= user_data
;
840 EmpathyEventManagerPriv
*priv
= GET_PRIV (self
);
842 EventManagerApproval
*approval
;
845 channel
= find_main_channel (channels
);
848 GError error
= { TP_ERRORS
, TP_ERROR_INVALID_ARGUMENT
,
849 "Unknown channel type" };
851 DEBUG ("Failed to find the main channel; ignoring");
853 tp_add_dispatch_operation_context_fail (context
, &error
);
857 approval
= event_manager_approval_new (self
, dispatch_operation
, channel
);
858 priv
->approvals
= g_slist_prepend (priv
->approvals
, approval
);
860 approval
->invalidated_handler
= g_signal_connect (dispatch_operation
,
861 "invalidated", G_CALLBACK (cdo_invalidated_cb
), approval
);
863 channel_type
= tp_channel_get_channel_type_id (channel
);
865 if (channel_type
== TP_IFACE_QUARK_CHANNEL_TYPE_TEXT
)
867 EmpathyTpChat
*tp_chat
;
869 tp_chat
= empathy_tp_chat_new (channel
);
870 approval
->handler_instance
= G_OBJECT (tp_chat
);
872 if (tp_proxy_has_interface (channel
, TP_IFACE_CHANNEL_INTERFACE_GROUP
))
874 /* Are we in local-pending ? */
877 if (empathy_tp_chat_is_invited (tp_chat
, &inviter
))
879 /* We are invited to a room */
880 DEBUG ("Have been invited to %s. Ask user if he wants to accept",
881 tp_channel_get_identifier (channel
));
883 empathy_tp_contact_factory_get_from_handle (connection
,
884 inviter
, event_manager_muc_invite_got_contact_cb
,
885 approval
, NULL
, G_OBJECT (self
));
890 /* We are not invited, approve the channel right now */
891 tp_add_dispatch_operation_context_accept (context
);
893 approval
->auto_approved
= TRUE
;
894 event_manager_approval_approve (approval
);
898 /* 1-1 text channel, wait for the first message */
899 approval
->handler
= g_signal_connect (tp_chat
, "message-received",
900 G_CALLBACK (event_manager_chat_message_received_cb
), approval
);
902 else if (channel_type
== TP_IFACE_QUARK_CHANNEL_TYPE_STREAMED_MEDIA
)
904 EmpathyContact
*contact
;
905 EmpathyTpCall
*call
= empathy_tp_call_new (channel
);
907 approval
->handler_instance
= G_OBJECT (call
);
909 g_object_get (G_OBJECT (call
), "contact", &contact
, NULL
);
913 g_signal_connect (call
, "notify::contact",
914 G_CALLBACK (event_manager_media_channel_contact_changed_cb
),
919 approval
->contact
= contact
;
920 event_manager_media_channel_got_contact (approval
);
924 else if (channel_type
== TP_IFACE_QUARK_CHANNEL_TYPE_FILE_TRANSFER
)
927 EmpathyTpFile
*tp_file
= empathy_tp_file_new (channel
);
929 approval
->handler_instance
= G_OBJECT (tp_file
);
931 handle
= tp_channel_get_handle (channel
, NULL
);
933 connection
= tp_channel_borrow_connection (channel
);
934 empathy_tp_contact_factory_get_from_handle (connection
, handle
,
935 event_manager_ft_got_contact_cb
, approval
, NULL
, G_OBJECT (self
));
939 GError error
= { TP_ERRORS
, TP_ERROR_INVALID_ARGUMENT
,
940 "Invalid channel type" };
942 DEBUG ("Unknown channel type (%s), ignoring..",
943 g_quark_to_string (channel_type
));
945 tp_add_dispatch_operation_context_fail (context
, &error
);
950 tp_add_dispatch_operation_context_accept (context
);
954 event_pending_subscribe_func (EventPriv
*event
)
956 empathy_subscription_dialog_show (event
->public.contact
, NULL
);
957 event_remove (event
);
961 event_manager_pendings_changed_cb (EmpathyContactList
*list
,
962 EmpathyContact
*contact
, EmpathyContact
*actor
,
963 guint reason
, gchar
*message
, gboolean is_pending
,
964 EmpathyEventManager
*manager
)
966 EmpathyEventManagerPriv
*priv
= GET_PRIV (manager
);
967 gchar
*header
, *event_msg
;
973 for (l
= priv
->events
; l
; l
= l
->next
)
975 EventPriv
*event
= l
->data
;
977 if (event
->public.contact
== contact
&&
978 event
->func
== event_pending_subscribe_func
)
980 event_remove (event
);
988 header
= g_strdup_printf (_("Subscription requested by %s"),
989 empathy_contact_get_alias (contact
));
991 if (!EMP_STR_EMPTY (message
))
992 event_msg
= g_strdup_printf (_("\nMessage: %s"), message
);
996 event_manager_add (manager
, contact
, EMPATHY_EVENT_TYPE_SUBSCRIPTION
,
997 GTK_STOCK_DIALOG_QUESTION
, header
, event_msg
, NULL
,
998 event_pending_subscribe_func
, NULL
);
1005 event_manager_presence_changed_cb (EmpathyContact
*contact
,
1006 TpConnectionPresenceType current
,
1007 TpConnectionPresenceType previous
,
1008 EmpathyEventManager
*manager
)
1011 gchar
*header
= NULL
;
1013 GSettings
*gsettings
= g_settings_new (EMPATHY_PREFS_NOTIFICATIONS_SCHEMA
);
1014 GtkWidget
*window
= empathy_main_window_dup ();
1016 account
= empathy_contact_get_account (contact
);
1017 idle
= empathy_idle_dup_singleton ();
1019 if (empathy_idle_account_is_just_connected (idle
, account
))
1022 if (tp_connection_presence_type_cmp_availability (previous
,
1023 TP_CONNECTION_PRESENCE_TYPE_OFFLINE
) > 0)
1025 /* contact was online */
1026 if (tp_connection_presence_type_cmp_availability (current
,
1027 TP_CONNECTION_PRESENCE_TYPE_OFFLINE
) <= 0)
1029 /* someone is logging off */
1030 empathy_sound_play (window
, EMPATHY_SOUND_CONTACT_DISCONNECTED
);
1032 if (g_settings_get_boolean (gsettings
,
1033 EMPATHY_PREFS_NOTIFICATIONS_CONTACT_SIGNOUT
))
1035 header
= g_strdup_printf (_("%s is now offline."),
1036 empathy_contact_get_alias (contact
));
1038 event_manager_add (manager
, contact
, EMPATHY_EVENT_TYPE_PRESENCE
,
1039 EMPATHY_IMAGE_AVATAR_DEFAULT
, header
, NULL
, NULL
, NULL
, NULL
);
1045 /* contact was offline */
1046 if (tp_connection_presence_type_cmp_availability (current
,
1047 TP_CONNECTION_PRESENCE_TYPE_OFFLINE
) > 0)
1049 /* someone is logging in */
1050 empathy_sound_play (window
, EMPATHY_SOUND_CONTACT_CONNECTED
);
1052 if (g_settings_get_boolean (gsettings
,
1053 EMPATHY_PREFS_NOTIFICATIONS_CONTACT_SIGNIN
))
1055 header
= g_strdup_printf (_("%s is now online."),
1056 empathy_contact_get_alias (contact
));
1058 event_manager_add (manager
, contact
, EMPATHY_EVENT_TYPE_PRESENCE
,
1059 EMPATHY_IMAGE_AVATAR_DEFAULT
, header
, NULL
, NULL
, NULL
, NULL
);
1066 g_object_unref (idle
);
1067 g_object_unref (gsettings
);
1068 g_object_unref (window
);
1072 event_manager_members_changed_cb (EmpathyContactList
*list
,
1073 EmpathyContact
*contact
,
1074 EmpathyContact
*actor
,
1078 EmpathyEventManager
*manager
)
1081 g_signal_connect (contact
, "presence-changed",
1082 G_CALLBACK (event_manager_presence_changed_cb
), manager
);
1084 g_signal_handlers_disconnect_by_func (contact
,
1085 event_manager_presence_changed_cb
, manager
);
1089 event_manager_constructor (GType type
,
1091 GObjectConstructParam
*props
)
1095 if (manager_singleton
) {
1096 retval
= g_object_ref (manager_singleton
);
1098 retval
= G_OBJECT_CLASS (empathy_event_manager_parent_class
)->constructor
1099 (type
, n_props
, props
);
1101 manager_singleton
= EMPATHY_EVENT_MANAGER (retval
);
1102 g_object_add_weak_pointer (retval
, (gpointer
) &manager_singleton
);
1109 event_manager_finalize (GObject
*object
)
1111 EmpathyEventManagerPriv
*priv
= GET_PRIV (object
);
1113 if (priv
->ringing
> 0)
1114 empathy_sound_stop (EMPATHY_SOUND_PHONE_INCOMING
);
1116 g_slist_foreach (priv
->events
, (GFunc
) event_free
, NULL
);
1117 g_slist_free (priv
->events
);
1118 g_slist_foreach (priv
->approvals
, (GFunc
) event_manager_approval_free
, NULL
);
1119 g_slist_free (priv
->approvals
);
1120 g_object_unref (priv
->contact_manager
);
1121 g_object_unref (priv
->dispatcher
);
1122 g_object_unref (priv
->approver
);
1126 empathy_event_manager_class_init (EmpathyEventManagerClass
*klass
)
1128 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
1130 object_class
->finalize
= event_manager_finalize
;
1131 object_class
->constructor
= event_manager_constructor
;
1133 signals
[EVENT_ADDED
] =
1134 g_signal_new ("event-added",
1135 G_TYPE_FROM_CLASS (klass
),
1139 g_cclosure_marshal_VOID__POINTER
,
1143 signals
[EVENT_REMOVED
] =
1144 g_signal_new ("event-removed",
1145 G_TYPE_FROM_CLASS (klass
),
1149 g_cclosure_marshal_VOID__POINTER
,
1150 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1152 signals
[EVENT_UPDATED
] =
1153 g_signal_new ("event-updated",
1154 G_TYPE_FROM_CLASS (klass
),
1158 g_cclosure_marshal_VOID__POINTER
,
1159 G_TYPE_NONE
, 1, G_TYPE_POINTER
);
1162 g_type_class_add_private (object_class
, sizeof (EmpathyEventManagerPriv
));
1166 empathy_event_manager_init (EmpathyEventManager
*manager
)
1168 EmpathyEventManagerPriv
*priv
= G_TYPE_INSTANCE_GET_PRIVATE (manager
,
1169 EMPATHY_TYPE_EVENT_MANAGER
, EmpathyEventManagerPriv
);
1171 GError
*error
= NULL
;
1173 manager
->priv
= priv
;
1175 priv
->dispatcher
= empathy_dispatcher_dup_singleton ();
1176 priv
->contact_manager
= empathy_contact_manager_dup_singleton ();
1177 g_signal_connect (priv
->contact_manager
, "pendings-changed",
1178 G_CALLBACK (event_manager_pendings_changed_cb
), manager
);
1180 g_signal_connect (priv
->contact_manager
, "members-changed",
1181 G_CALLBACK (event_manager_members_changed_cb
), manager
);
1183 dbus
= tp_dbus_daemon_dup (&error
);
1186 DEBUG ("Failed to get TpDBusDaemon: %s", error
->message
);
1187 g_error_free (error
);
1191 priv
->approver
= tp_simple_approver_new (dbus
, "Empathy.EventManager", FALSE
,
1192 approve_channels
, manager
, NULL
);
1194 /* Private text channels */
1195 tp_base_client_take_approver_filter (priv
->approver
,
1197 TP_PROP_CHANNEL_CHANNEL_TYPE
, G_TYPE_STRING
, TP_IFACE_CHANNEL_TYPE_TEXT
,
1198 TP_PROP_CHANNEL_TARGET_HANDLE_TYPE
, G_TYPE_UINT
, TP_HANDLE_TYPE_CONTACT
,
1201 /* Muc text channels */
1202 tp_base_client_take_approver_filter (priv
->approver
,
1204 TP_PROP_CHANNEL_CHANNEL_TYPE
, G_TYPE_STRING
, TP_IFACE_CHANNEL_TYPE_TEXT
,
1205 TP_PROP_CHANNEL_TARGET_HANDLE_TYPE
, G_TYPE_UINT
, TP_HANDLE_TYPE_ROOM
,
1209 tp_base_client_take_approver_filter (priv
->approver
,
1211 TP_PROP_CHANNEL_CHANNEL_TYPE
, G_TYPE_STRING
,
1212 TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER
,
1213 TP_PROP_CHANNEL_TARGET_HANDLE_TYPE
, G_TYPE_UINT
, TP_HANDLE_TYPE_CONTACT
,
1217 tp_base_client_take_approver_filter (priv
->approver
,
1219 TP_PROP_CHANNEL_CHANNEL_TYPE
, G_TYPE_STRING
,
1220 TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA
,
1221 TP_PROP_CHANNEL_TARGET_HANDLE_TYPE
, G_TYPE_UINT
, TP_HANDLE_TYPE_CONTACT
,
1224 if (!tp_base_client_register (priv
->approver
, &error
))
1226 DEBUG ("Failed to register Approver: %s", error
->message
);
1227 g_error_free (error
);
1230 g_object_unref (dbus
);
1233 EmpathyEventManager
*
1234 empathy_event_manager_dup_singleton (void)
1236 return g_object_new (EMPATHY_TYPE_EVENT_MANAGER
, NULL
);
1240 empathy_event_manager_get_events (EmpathyEventManager
*manager
)
1242 EmpathyEventManagerPriv
*priv
= GET_PRIV (manager
);
1244 g_return_val_if_fail (EMPATHY_IS_EVENT_MANAGER (manager
), NULL
);
1246 return priv
->events
;
1250 empathy_event_manager_get_top_event (EmpathyEventManager
*manager
)
1252 EmpathyEventManagerPriv
*priv
= GET_PRIV (manager
);
1254 g_return_val_if_fail (EMPATHY_IS_EVENT_MANAGER (manager
), NULL
);
1256 return priv
->events
? priv
->events
->data
: NULL
;
1260 empathy_event_activate (EmpathyEvent
*event_public
)
1262 EventPriv
*event
= (EventPriv
*) event_public
;
1264 g_return_if_fail (event_public
!= NULL
);
1267 event
->func (event
);
1269 event_remove (event
);
1273 empathy_event_inhibit_updates (EmpathyEvent
*event_public
)
1275 EventPriv
*event
= (EventPriv
*) event_public
;
1277 g_return_if_fail (event_public
!= NULL
);
1279 event
->inhibit
= TRUE
;
1283 empathy_event_approve (EmpathyEvent
*event_public
)
1285 EventPriv
*event
= (EventPriv
*) event_public
;
1287 g_return_if_fail (event_public
!= NULL
);
1289 event_manager_approval_approve (event
->approval
);
1293 empathy_event_decline (EmpathyEvent
*event_public
)
1295 EventPriv
*event
= (EventPriv
*) event_public
;
1297 g_return_if_fail (event_public
!= NULL
);
1299 reject_approval (event
->approval
);