diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/empathy-accounts-dialog.c | 141 | ||||
-rw-r--r-- | src/empathy-accounts.c | 19 | ||||
-rw-r--r-- | src/empathy-auth-client.c | 41 | ||||
-rw-r--r-- | src/empathy-chat-window.c | 61 | ||||
-rw-r--r-- | src/empathy-event-manager.c | 127 | ||||
-rw-r--r-- | src/empathy-event-manager.h | 2 | ||||
-rw-r--r-- | src/empathy-main-window.c | 173 | ||||
-rw-r--r-- | src/empathy-main-window.ui | 14 | ||||
-rw-r--r-- | src/empathy-notifications-approver.c | 10 | ||||
-rw-r--r-- | src/empathy-status-icon.c | 2 |
11 files changed, 487 insertions, 104 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index d57035b3a..8c51ded77 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -22,6 +22,7 @@ LDADD = \ $(top_builddir)/libempathy-gtk/libempathy-gtk.la \ $(top_builddir)/libempathy/libempathy.la \ $(top_builddir)/extensions/libemp-extensions.la \ + $(GCR_LIBS) \ $(EMPATHY_LIBS) \ $(LIBCHAMPLAIN_LIBS) \ $(WEBKIT_LIBS) diff --git a/src/empathy-accounts-dialog.c b/src/empathy-accounts-dialog.c index 8eda73bb4..196ffceb5 100644 --- a/src/empathy-accounts-dialog.c +++ b/src/empathy-accounts-dialog.c @@ -1485,6 +1485,101 @@ accounts_dialog_model_set_selected (EmpathyAccountsDialog *dialog, if (accounts_dialog_get_settings_iter (dialog, settings, &iter)) gtk_tree_selection_select_iter (selection, &iter); } + +static void +accounts_dialog_treeview_enabled_cb (GtkMenuItem *item, + TpAccount *account) +{ + gboolean enabled; + + enabled = tp_account_is_enabled (account); + tp_account_set_enabled_async (account, !enabled, NULL, NULL); +} + +static gboolean +accounts_dialog_treeview_button_press_event_cb (GtkTreeView *view, + GdkEventButton *event, + EmpathyAccountsDialog *dialog) +{ + EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog); + TpAccount *account = NULL; + GtkTreeModel *model = NULL; + GtkTreePath *path = NULL; + GtkTreeIter iter; + GtkWidget *menu; + GtkWidget *item_enable, *item_disable; + GtkWidget *image_enable, *image_disable; + + /* ignore multiple clicks */ + if (event->type != GDK_BUTTON_PRESS) + return TRUE; + + if (event->button != 3) + goto finally; + + /* Selection is not yet set, so we have to get account from event position */ + model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview)); + if (!gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (priv->treeview), + event->x, event->y, &path, NULL, NULL, NULL)) + goto finally; + + if (!gtk_tree_model_get_iter (model, &iter, path)) + goto finally; + + gtk_tree_model_get (model, &iter, COL_ACCOUNT, &account, -1); + + /* Create the menu */ + menu = gtk_menu_new (); + + /* Get images for menu items */ + image_enable = gtk_image_new_from_icon_name (empathy_icon_name_for_presence ( + tp_account_manager_get_most_available_presence ( + priv->account_manager, NULL, NULL)), + GTK_ICON_SIZE_MENU); + image_disable = gtk_image_new_from_icon_name ( + empathy_icon_name_for_presence (TP_CONNECTION_PRESENCE_TYPE_OFFLINE), + GTK_ICON_SIZE_MENU); + + /* Menu items: to enabled/disable the account */ + item_enable = gtk_image_menu_item_new_with_mnemonic (_("_Enable")); + item_disable = gtk_image_menu_item_new_with_mnemonic (_("_Disable")); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item_enable), + image_enable); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item_disable), + image_disable); + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item_enable); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item_disable); + + if (tp_account_is_enabled (account)) + { + tp_g_signal_connect_object (item_disable, "activate", + G_CALLBACK (accounts_dialog_treeview_enabled_cb), account, 0); + gtk_widget_set_sensitive (item_enable, FALSE); + } + else + { + tp_g_signal_connect_object (item_enable, "activate", + G_CALLBACK (accounts_dialog_treeview_enabled_cb), account, 0); + gtk_widget_set_sensitive (item_disable, FALSE); + } + + gtk_widget_show (item_enable); + gtk_widget_show (item_disable); + + /* FIXME: Add here presence items, to be able to set per-account presence */ + + /* Popup menu */ + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, + event->button, event->time); + +finally: + tp_clear_object (&account); + gtk_tree_path_free (path); + + return FALSE; +} + static void accounts_dialog_add (EmpathyAccountsDialog *dialog, EmpathyAccountSettings *settings) @@ -2002,6 +2097,8 @@ accounts_dialog_build_ui (EmpathyAccountsDialog *dialog) "button_add", "clicked", accounts_dialog_button_add_clicked_cb, "button_remove", "clicked", accounts_dialog_button_remove_clicked_cb, "button_import", "clicked", accounts_dialog_button_import_clicked_cb, + "treeview", "button-press-event", + accounts_dialog_treeview_button_press_event_cb, NULL); content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); @@ -2292,10 +2389,10 @@ empathy_accounts_dialog_show_application (GdkScreen *screen, gboolean hidden) { GError *error = NULL; - const gchar *argv[4] = { NULL, }; - gint i = 0; - gchar *account_option = NULL; + GString *cmd; gchar *path; + GAppInfo *app_info; + GdkAppLaunchContext *context = NULL; g_return_if_fail (GDK_IS_SCREEN (screen)); g_return_if_fail (!selected_account || TP_IS_ACCOUNT (selected_account)); @@ -2310,40 +2407,48 @@ empathy_accounts_dialog_show_application (GdkScreen *screen, path = g_build_filename (BIN_DIR, "empathy-accounts", NULL); } - argv[i++] = path; + cmd = g_string_new (path); + g_free (path); if (selected_account != NULL) { - const gchar *account_path; - - account_path = tp_proxy_get_object_path (TP_PROXY (selected_account)); - account_option = g_strdup_printf ("--select-account=%s", - &account_path[strlen (TP_ACCOUNT_OBJECT_PATH_BASE)]); - - argv[i++] = account_option; + g_string_append_printf (cmd, " --select-account=%s", + tp_account_get_path_suffix (selected_account)); } if (if_needed) - argv[i++] = "--if-needed"; + g_string_append_printf (cmd, " --if-needed"); if (hidden) - argv[i++] = "--hidden"; + g_string_append_printf (cmd, " --hidden"); DEBUG ("Launching empathy-accounts (if_needed: %d, hidden: %d, account: %s)", if_needed, hidden, selected_account == NULL ? "<none selected>" : tp_proxy_get_object_path (TP_PROXY (selected_account))); - gdk_spawn_on_screen (screen, NULL, (gchar**) argv, NULL, G_SPAWN_SEARCH_PATH, - NULL, NULL, NULL, &error); - if (error != NULL) + app_info = g_app_info_create_from_commandline (cmd->str, NULL, 0, &error); + if (app_info == NULL) + { + DEBUG ("Failed to create app info: %s", error->message); + g_error_free (error); + goto out; + } + + context = gdk_app_launch_context_new (); + gdk_app_launch_context_set_display (context, gdk_screen_get_display (screen)); + + if (!g_app_info_launch (app_info, NULL, (GAppLaunchContext *) context, + &error)) { g_warning ("Failed to open accounts dialog: %s", error->message); g_error_free (error); } - g_free (account_option); - g_free (path); +out: + tp_clear_object (&app_info); + tp_clear_object (&context); + g_string_free (cmd, TRUE); } gboolean diff --git a/src/empathy-accounts.c b/src/empathy-accounts.c index 6d0561b14..05cb269c1 100644 --- a/src/empathy-accounts.c +++ b/src/empathy-accounts.c @@ -93,7 +93,6 @@ account_manager_ready_for_accounts_cb (GObject *source_object, gpointer user_data) { TpAccountManager *manager = TP_ACCOUNT_MANAGER (source_object); - const gchar *account_id = (const gchar*) user_data; GError *error = NULL; if (!tp_account_manager_prepare_finish (manager, result, &error)) @@ -103,7 +102,9 @@ account_manager_ready_for_accounts_cb (GObject *source_object, return; } - if (account_id != NULL) + account_manager_prepared = TRUE; + + if (selected_account_name != NULL) { gchar *account_path; TpAccount *account = NULL; @@ -112,7 +113,7 @@ account_manager_ready_for_accounts_cb (GObject *source_object, /* create and prep the corresponding TpAccount so it's fully ready by the * time we try to select it in the accounts dialog */ account_path = g_strdup_printf ("%s%s", TP_ACCOUNT_OBJECT_PATH_BASE, - account_id); + selected_account_name); bus = tp_dbus_daemon_dup (NULL); if ((account = tp_account_new (bus, account_path, &error))) { @@ -124,6 +125,8 @@ account_manager_ready_for_accounts_cb (GObject *source_object, DEBUG ("Failed to find account with path %s: %s", account_path, error->message); g_clear_error (&error); + + maybe_show_accounts_ui (manager); } g_object_unref (bus); @@ -132,7 +135,6 @@ account_manager_ready_for_accounts_cb (GObject *source_object, else { maybe_show_accounts_ui (manager); - account_manager_prepared = TRUE; } } @@ -140,13 +142,8 @@ static int app_command_line_cb (GApplication *app, GApplicationCommandLine *cmdline) { - gchar **argv; - gint argc; - g_application_hold (app); - argv = g_application_command_line_get_arguments (cmdline, &argc); - /* if the window is ready, present it; otherwise, it will be presented when * the accounts manager is prepared */ if (account_manager_prepared) @@ -160,8 +157,6 @@ app_command_line_cb (GApplication *app, g_object_unref (account_manager); } - g_strfreev (argv); - return 0; } @@ -247,7 +242,7 @@ main (int argc, char *argv[]) account_manager = tp_account_manager_dup (); tp_account_manager_prepare_async (account_manager, NULL, - account_manager_ready_for_accounts_cb, selected_account_name); + account_manager_ready_for_accounts_cb, NULL); g_signal_connect (app, "command-line", G_CALLBACK (app_command_line_cb), NULL); diff --git a/src/empathy-auth-client.c b/src/empathy-auth-client.c index 17b66a57d..530aa17ec 100644 --- a/src/empathy-auth-client.c +++ b/src/empathy-auth-client.c @@ -29,9 +29,12 @@ #define DEBUG_FLAG EMPATHY_DEBUG_TLS #include <libempathy/empathy-debug.h> #include <libempathy/empathy-auth-factory.h> +#include <libempathy/empathy-server-sasl-handler.h> #include <libempathy/empathy-server-tls-handler.h> #include <libempathy/empathy-tls-verifier.h> +#include <libempathy/empathy-utils.h> +#include <libempathy-gtk/empathy-password-dialog.h> #include <libempathy-gtk/empathy-tls-dialog.h> #include <libempathy-gtk/empathy-ui-utils.h> @@ -90,6 +93,7 @@ tls_dialog_response_cb (GtkDialog *dialog, GHashTable *details = NULL; EmpathyTLSDialog *tls_dialog = EMPATHY_TLS_DIALOG (dialog); gboolean remember = FALSE; + EmpathyTLSVerifier *verifier = EMPATHY_TLS_VERIFIER (user_data); DEBUG ("Response %d", response_id); @@ -114,7 +118,7 @@ tls_dialog_response_cb (GtkDialog *dialog, } if (remember) - empathy_tls_certificate_store_ca (certificate); + empathy_tls_verifier_store_exception (verifier); g_object_unref (certificate); g_hash_table_unref (details); @@ -130,6 +134,7 @@ tls_dialog_response_cb (GtkDialog *dialog, static void display_interactive_dialog (EmpathyTLSCertificate *certificate, + EmpathyTLSVerifier *verifier, EmpTLSCertificateRejectReason reason, GHashTable *details) { @@ -140,8 +145,9 @@ display_interactive_dialog (EmpathyTLSCertificate *certificate, stop_timer (); tls_dialog = empathy_tls_dialog_new (certificate, reason, details); - g_signal_connect (tls_dialog, "response", - G_CALLBACK (tls_dialog_response_cb), NULL); + g_signal_connect_data (tls_dialog, "response", + G_CALLBACK (tls_dialog_response_cb), g_object_ref (verifier), + (GClosureNotify)g_object_unref, 0); gtk_widget_show (tls_dialog); } @@ -156,6 +162,7 @@ verifier_verify_cb (GObject *source, GError *error = NULL; EmpathyTLSCertificate *certificate = NULL; GHashTable *details = NULL; + gchar *hostname = NULL; g_object_get (source, "certificate", &certificate, @@ -167,7 +174,8 @@ verifier_verify_cb (GObject *source, if (error != NULL) { DEBUG ("Error: %s", error->message); - display_interactive_dialog (certificate, reason, details); + display_interactive_dialog (certificate, EMPATHY_TLS_VERIFIER (source), + reason, details); g_error_free (error); } @@ -176,11 +184,12 @@ verifier_verify_cb (GObject *source, empathy_tls_certificate_accept_async (certificate, NULL, NULL); } + g_free (hostname); g_object_unref (certificate); } static void -auth_factory_new_handler_cb (EmpathyAuthFactory *factory, +auth_factory_new_tls_handler_cb (EmpathyAuthFactory *factory, EmpathyServerTLSHandler *handler, gpointer user_data) { @@ -204,6 +213,23 @@ auth_factory_new_handler_cb (EmpathyAuthFactory *factory, g_free (hostname); } +static void +auth_factory_new_sasl_handler_cb (EmpathyAuthFactory *factory, + EmpathyServerSASLHandler *handler, + gpointer user_data) +{ + GtkWidget *dialog; + + DEBUG ("New SASL server handler received from the factory"); + + /* If the handler has the password it will deal with it itself. */ + if (!empathy_server_sasl_handler_has_password (handler)) + { + dialog = empathy_password_dialog_new (handler); + gtk_widget_show (dialog); + } +} + int main (int argc, char **argv) @@ -238,7 +264,10 @@ main (int argc, factory = empathy_auth_factory_dup_singleton (); g_signal_connect (factory, "new-server-tls-handler", - G_CALLBACK (auth_factory_new_handler_cb), NULL); + G_CALLBACK (auth_factory_new_tls_handler_cb), NULL); + + g_signal_connect (factory, "new-server-sasl-handler", + G_CALLBACK (auth_factory_new_sasl_handler_cb), NULL); if (!empathy_auth_factory_register (factory, &error)) { diff --git a/src/empathy-chat-window.c b/src/empathy-chat-window.c index 16329ee7b..9f893dc7e 100644 --- a/src/empathy-chat-window.c +++ b/src/empathy-chat-window.c @@ -74,8 +74,6 @@ typedef struct { EmpathyChat *current_chat; GList *chats; - GList *chats_new_msg; - GList *chats_composing; gboolean page_added; gboolean dnd_same_window; EmpathyChatroomManager *chatroom_manager; @@ -423,8 +421,14 @@ chat_window_contact_menu_update (EmpathyChatWindowPriv *priv, if (orig_submenu == NULL || !gtk_widget_get_visible (orig_submenu)) { submenu = empathy_chat_get_contact_menu (priv->current_chat); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu), submenu); - gtk_widget_show (menu); + if (submenu != NULL) { + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu), submenu); + gtk_widget_show (menu); + gtk_widget_set_sensitive (menu, TRUE); + } + else { + gtk_widget_set_sensitive (menu, FALSE); + } } else { tp_g_signal_connect_object (orig_submenu, "notify::visible", @@ -439,11 +443,8 @@ get_all_unread_messages (EmpathyChatWindowPriv *priv) GList *l; guint nb = 0; - for (l = priv->chats_new_msg; l != NULL; l = g_list_next (l)) { - EmpathyChat *chat = l->data; - - nb += empathy_chat_get_nb_unread_messages (chat); - } + for (l = priv->chats; l != NULL; l = g_list_next (l)) + nb += empathy_chat_get_nb_unread_messages (EMPATHY_CHAT (l->data)); return nb; } @@ -525,7 +526,7 @@ chat_window_title_update (EmpathyChatWindowPriv *priv) } static void -chat_window_icon_update (EmpathyChatWindowPriv *priv) +chat_window_icon_update (EmpathyChatWindowPriv *priv, gboolean new_messages) { GdkPixbuf *icon; EmpathyContact *remote_contact; @@ -535,7 +536,7 @@ chat_window_icon_update (EmpathyChatWindowPriv *priv) n_chats = g_list_length (priv->chats); /* Update window icon */ - if (priv->chats_new_msg) { + if (new_messages) { gtk_window_set_icon_name (GTK_WINDOW (priv->dialog), EMPATHY_IMAGE_MESSAGE); } else { @@ -598,7 +599,7 @@ chat_window_update (EmpathyChatWindow *window) chat_window_title_update (priv); - chat_window_icon_update (priv); + chat_window_icon_update (priv, get_all_unread_messages (priv) > 0); chat_window_close_button_update (priv, num_pages); @@ -659,10 +660,10 @@ chat_window_update_chat_tab (EmpathyChat *chat) /* No TpChat, we are disconnected */ icon_name = NULL; } - else if (g_list_find (priv->chats_new_msg, chat)) { + else if (empathy_chat_get_nb_unread_messages (chat) > 0) { icon_name = EMPATHY_IMAGE_MESSAGE; } - else if (g_list_find (priv->chats_composing, chat)) { + else if (empathy_chat_is_composing (chat)) { icon_name = EMPATHY_IMAGE_TYPING; } else if (remote_contact) { @@ -707,7 +708,7 @@ chat_window_update_chat_tab (EmpathyChat *chat) _("Topic:"), subject); } - if (g_list_find (priv->chats_composing, chat)) { + if (empathy_chat_is_composing (chat)) { append_markup_printf (tooltip, "\n%s", _("Typing a message.")); } @@ -1236,16 +1237,6 @@ chat_window_composing_cb (EmpathyChat *chat, gboolean is_composing, EmpathyChatWindow *window) { - EmpathyChatWindowPriv *priv; - - priv = GET_PRIV (window); - - if (is_composing && !g_list_find (priv->chats_composing, chat)) { - priv->chats_composing = g_list_prepend (priv->chats_composing, chat); - } else { - priv->chats_composing = g_list_remove (priv->chats_composing, chat); - } - chat_window_update_chat_tab (chat); } @@ -1348,7 +1339,7 @@ chat_window_show_or_update_notification (EmpathyChatWindow *window, } static void -chat_window_set_highlight_room_tab_label (EmpathyChat *chat) +chat_window_set_highlight_room_labels (EmpathyChat *chat) { gchar *markup; GtkWidget *widget; @@ -1362,6 +1353,10 @@ chat_window_set_highlight_room_tab_label (EmpathyChat *chat) widget = g_object_get_data (G_OBJECT (chat), "chat-window-tab-label"); gtk_label_set_markup (GTK_LABEL (widget), markup); + + widget = g_object_get_data (G_OBJECT (chat), "chat-window-menu-label"); + gtk_label_set_markup (GTK_LABEL (widget), markup); + g_free (markup); } @@ -1417,8 +1412,8 @@ chat_window_new_message_cb (EmpathyChat *chat, return; } - if (!g_list_find (priv->chats_new_msg, chat)) { - priv->chats_new_msg = g_list_prepend (priv->chats_new_msg, chat); + /* Update the chat tab if this is the first unread message */ + if (empathy_chat_get_nb_unread_messages (chat) == 1) { chat_window_update_chat_tab (chat); } @@ -1453,7 +1448,7 @@ chat_window_new_message_cb (EmpathyChat *chat, if (needs_urgency) { if (!has_focus) { chat_window_set_urgency_hint (window, TRUE); - chat_window_set_highlight_room_tab_label (chat); + chat_window_set_highlight_room_labels (chat); } empathy_sound_manager_play (priv->sound_mgr, GTK_WIDGET (priv->dialog), @@ -1467,7 +1462,7 @@ chat_window_new_message_cb (EmpathyChat *chat, /* update the number of unread messages and the window icon */ chat_window_title_update (priv); - chat_window_icon_update (priv); + chat_window_icon_update (priv, TRUE); } static GtkNotebook * @@ -1526,7 +1521,6 @@ chat_window_page_switched_cb (GtkNotebook *notebook, } priv->current_chat = chat; - priv->chats_new_msg = g_list_remove (priv->chats_new_msg, chat); empathy_chat_messages_read (chat); chat_window_update_chat_tab (chat); @@ -1618,9 +1612,7 @@ chat_window_page_removed_cb (GtkNotebook *notebook, /* Keep list of chats up to date */ priv->chats = g_list_remove (priv->chats, chat); - priv->chats_new_msg = g_list_remove (priv->chats_new_msg, chat); empathy_chat_messages_read (chat); - priv->chats_composing = g_list_remove (priv->chats_composing, chat); if (priv->chats == NULL) { g_object_unref (window); @@ -1638,7 +1630,6 @@ chat_window_focus_in_event_cb (GtkWidget *widget, priv = GET_PRIV (window); - priv->chats_new_msg = g_list_remove (priv->chats_new_msg, priv->current_chat); empathy_chat_messages_read (priv->current_chat); chat_window_set_urgency_hint (window, FALSE); @@ -2093,8 +2084,6 @@ empathy_chat_window_init (EmpathyChatWindow *window) /* Set up private details */ priv->chats = NULL; - priv->chats_new_msg = NULL; - priv->chats_composing = NULL; priv->current_chat = NULL; priv->notification = NULL; diff --git a/src/empathy-event-manager.c b/src/empathy-event-manager.c index 5516328cc..93656c3a9 100644 --- a/src/empathy-event-manager.c +++ b/src/empathy-event-manager.c @@ -76,6 +76,7 @@ typedef struct { typedef struct { TpBaseClient *approver; + TpBaseClient *auth_approver; EmpathyContactManager *contact_manager; GSList *events; /* Ongoing approvals */ @@ -165,10 +166,8 @@ event_free (EventPriv *event) if (event->autoremove_timeout_id != 0) g_source_remove (event->autoremove_timeout_id); - if (event->public.contact) - { - g_object_unref (event->public.contact); - } + tp_clear_object (&(event->public.contact)); + tp_clear_object (&(event->public.account)); g_slice_free (EventPriv, event); } @@ -212,6 +211,7 @@ display_notify_area (EmpathyEventManager *self) static void event_manager_add (EmpathyEventManager *manager, + TpAccount *account, EmpathyContact *contact, EmpathyEventType type, const gchar *icon_name, @@ -225,6 +225,7 @@ event_manager_add (EmpathyEventManager *manager, EventPriv *event; event = g_slice_new0 (EventPriv); + event->public.account = account != NULL ? g_object_ref (account) : NULL; event->public.contact = contact ? g_object_ref (contact) : NULL; event->public.type = type; event->public.icon_name = g_strdup (icon_name); @@ -421,11 +422,46 @@ out: } static void +reject_auth_channel_claim_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + TpChannelDispatchOperation *cdo = TP_CHANNEL_DISPATCH_OPERATION (source); + GError *error = NULL; + + if (!tp_channel_dispatch_operation_claim_finish (cdo, result, &error)) + { + DEBUG ("Failed to claim channel: %s", error->message); + + g_error_free (error); + return; + } + + tp_cli_channel_call_close (TP_CHANNEL (user_data), -1, + NULL, NULL, NULL, NULL); +} + +static void reject_approval (EventManagerApproval *approval) { /* We have to claim the channel before closing it */ - tp_channel_dispatch_operation_claim_async (approval->operation, - reject_channel_claim_cb, g_object_ref (approval->handler_instance)); + + /* Unfortunately, we need to special case the auth channels for the + * time being as they don't have a wrapper object handler in + * approval->handler_instance as they're not actually handled by + * this process, so we can just use a noddy callback to call Close() + * directly. */ + if (approval->handler_instance != NULL) + { + tp_channel_dispatch_operation_claim_async (approval->operation, + reject_channel_claim_cb, g_object_ref (approval->handler_instance)); + } + else if (tp_channel_get_channel_type_id (approval->main_channel) + == TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION) + { + tp_channel_dispatch_operation_claim_async (approval->operation, + reject_auth_channel_claim_cb, approval->main_channel); + } } static void @@ -549,9 +585,9 @@ event_manager_chat_message_received_cb (EmpathyTpChat *tp_chat, event_update (approval->manager, event, EMPATHY_IMAGE_NEW_MESSAGE, header, msg); else - event_manager_add (approval->manager, sender, EMPATHY_EVENT_TYPE_CHAT, - EMPATHY_IMAGE_NEW_MESSAGE, header, msg, approval, - event_text_channel_process_func, NULL); + event_manager_add (approval->manager, NULL, sender, + EMPATHY_EVENT_TYPE_CHAT, EMPATHY_IMAGE_NEW_MESSAGE, header, msg, + approval, event_text_channel_process_func, NULL); empathy_sound_manager_play (priv->sound_mgr, window, EMPATHY_SOUND_CONVERSATION_NEW); @@ -625,8 +661,8 @@ event_manager_media_channel_got_contact (EventManagerApproval *approval) video ? _("Incoming video call from %s") :_("Incoming call from %s"), empathy_contact_get_alias (approval->contact)); - event_manager_add (approval->manager, approval->contact, - EMPATHY_EVENT_TYPE_VOIP, + event_manager_add (approval->manager, NULL, + approval->contact, EMPATHY_EVENT_TYPE_VOIP, video ? EMPATHY_IMAGE_VIDEO_CALL : EMPATHY_IMAGE_VOIP, header, NULL, approval, event_channel_process_voip_func, NULL); @@ -758,9 +794,10 @@ display_invite_room_dialog (EventManagerApproval *approval) tp_channel_get_identifier (approval->main_channel)); } - event_manager_add (approval->manager, approval->contact, - EMPATHY_EVENT_TYPE_INVITATION, EMPATHY_IMAGE_GROUP_MESSAGE, msg, - invite_msg, approval, event_room_channel_process_func, NULL); + event_manager_add (approval->manager, NULL, + approval->contact, EMPATHY_EVENT_TYPE_INVITATION, + EMPATHY_IMAGE_GROUP_MESSAGE, msg, invite_msg, approval, + event_room_channel_process_func, NULL); empathy_sound_manager_play (priv->sound_mgr, window, EMPATHY_SOUND_CONVERSATION_NEW); @@ -807,8 +844,9 @@ event_manager_ft_got_contact_cb (TpConnection *connection, header = g_strdup_printf (_("Incoming file transfer from %s"), empathy_contact_get_alias (approval->contact)); - event_manager_add (approval->manager, approval->contact, - EMPATHY_EVENT_TYPE_TRANSFER, EMPATHY_IMAGE_DOCUMENT_SEND, header, NULL, + event_manager_add (approval->manager, NULL, + approval->contact, EMPATHY_EVENT_TYPE_TRANSFER, + EMPATHY_IMAGE_DOCUMENT_SEND, header, NULL, approval, event_channel_process_func, NULL); /* FIXME better sound for incoming file transfers ?*/ @@ -819,8 +857,14 @@ event_manager_ft_got_contact_cb (TpConnection *connection, g_object_unref (window); } -/* If there is a file-transfer or media channel consider it as the - * main one. */ +static void +event_manager_auth_process_func (EventPriv *event) +{ + empathy_event_approve ((EmpathyEvent *) event); +} + +/* If there is a file-transfer, media, or auth channel consider it as + * the main one. */ static TpChannel * find_main_channel (GList *channels) { @@ -838,7 +882,8 @@ find_main_channel (GList *channels) channel_type = tp_channel_get_channel_type_id (channel); if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_STREAMED_MEDIA || - channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_FILE_TRANSFER) + channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_FILE_TRANSFER || + channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION) return channel; else if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_TEXT) @@ -962,6 +1007,13 @@ approve_channels (TpSimpleApprover *approver, empathy_tp_contact_factory_get_from_handle (connection, handle, event_manager_ft_got_contact_cb, approval, NULL, G_OBJECT (self)); } + else if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION) + { + event_manager_add (approval->manager, account, NULL, EMPATHY_EVENT_TYPE_AUTH, + GTK_STOCK_DIALOG_AUTHENTICATION, tp_account_get_display_name (account), + _("Password required"), approval, + event_manager_auth_process_func, NULL); + } else { GError error = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, @@ -1023,7 +1075,7 @@ event_manager_pendings_changed_cb (EmpathyContactList *list, else event_msg = NULL; - event_manager_add (manager, contact, EMPATHY_EVENT_TYPE_SUBSCRIPTION, + event_manager_add (manager, NULL, contact, EMPATHY_EVENT_TYPE_SUBSCRIPTION, GTK_STOCK_DIALOG_QUESTION, header, event_msg, NULL, event_pending_subscribe_func, NULL); @@ -1066,7 +1118,7 @@ event_manager_presence_changed_cb (EmpathyContact *contact, header = g_strdup_printf (_("%s is now offline."), empathy_contact_get_alias (contact)); - event_manager_add (manager, contact, EMPATHY_EVENT_TYPE_PRESENCE, + event_manager_add (manager, NULL, contact, EMPATHY_EVENT_TYPE_PRESENCE, EMPATHY_IMAGE_AVATAR_DEFAULT, header, NULL, NULL, NULL, NULL); } } @@ -1087,7 +1139,7 @@ event_manager_presence_changed_cb (EmpathyContact *contact, header = g_strdup_printf (_("%s is now online."), empathy_contact_get_alias (contact)); - event_manager_add (manager, contact, EMPATHY_EVENT_TYPE_PRESENCE, + event_manager_add (manager, NULL, contact, EMPATHY_EVENT_TYPE_PRESENCE, EMPATHY_IMAGE_AVATAR_DEFAULT, header, NULL, NULL, NULL, NULL); } } @@ -1150,6 +1202,7 @@ event_manager_finalize (GObject *object) g_slist_free (priv->approvals); g_object_unref (priv->contact_manager); g_object_unref (priv->approver); + g_object_unref (priv->auth_approver); g_object_unref (priv->gsettings_notif); g_object_unref (priv->gsettings_ui); g_object_unref (priv->sound_mgr); @@ -1191,7 +1244,6 @@ empathy_event_manager_class_init (EmpathyEventManagerClass *klass) g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - g_type_class_add_private (object_class, sizeof (EmpathyEventManagerPriv)); } @@ -1262,12 +1314,41 @@ empathy_event_manager_init (EmpathyEventManager *manager) TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT, NULL)); + /* I don't feel good about doing this, and I'm sorry, but the + * capabilities connection feature is added earlier because it's + * needed for EmpathyTpChat. If the capabilities feature is required + * then preparing an auth channel (which of course appears in the + * CONNECTING state) will never be prepared. So the options are + * either to create another approver like I've done, or to port + * EmpathyTpChat and its users to not depend on the connection being + * prepared with capabilities. I chose the former, obviously. :-) */ + + priv->auth_approver = tp_simple_approver_new (dbus, + "Empathy.AuthEventManager", FALSE, approve_channels, manager, + NULL); + + /* SASL auth channels */ + tp_base_client_take_approver_filter (priv->auth_approver, + tp_asv_new ( + TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, + TP_IFACE_CHANNEL_TYPE_SERVER_AUTHENTICATION, + TP_PROP_CHANNEL_TYPE_SERVER_AUTHENTICATION_AUTHENTICATION_METHOD, + G_TYPE_STRING, + TP_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION, + NULL)); + if (!tp_base_client_register (priv->approver, &error)) { DEBUG ("Failed to register Approver: %s", error->message); g_error_free (error); } + if (!tp_base_client_register (priv->auth_approver, &error)) + { + DEBUG ("Failed to register auth Approver: %s", error->message); + g_error_free (error); + } + g_object_unref (dbus); } diff --git a/src/empathy-event-manager.h b/src/empathy-event-manager.h index cc81d2ddb..16d97c6df 100644 --- a/src/empathy-event-manager.h +++ b/src/empathy-event-manager.h @@ -55,9 +55,11 @@ typedef enum { EMPATHY_EVENT_TYPE_SUBSCRIPTION, EMPATHY_EVENT_TYPE_PRESENCE, EMPATHY_EVENT_TYPE_INVITATION, + EMPATHY_EVENT_TYPE_AUTH, } EmpathyEventType; typedef struct { + TpAccount *account; EmpathyContact *contact; EmpathyEventType type; gchar *icon_name; diff --git a/src/empathy-main-window.c b/src/empathy-main-window.c index db5818c0c..88335b654 100644 --- a/src/empathy-main-window.c +++ b/src/empathy-main-window.c @@ -122,6 +122,7 @@ struct _EmpathyMainWindowPriv { GtkWidget *presence_toolbar; GtkWidget *presence_chooser; GtkWidget *errors_vbox; + GtkWidget *auth_vbox; GtkWidget *search_bar; GtkWidget *notebook; GtkWidget *no_entry_label; @@ -142,8 +143,13 @@ struct _EmpathyMainWindowPriv { GtkWidget *edit_context_separator; guint size_timeout_id; + + /* reffed TpAccount* => visible GtkInfoBar* */ GHashTable *errors; + /* EmpathyEvent* => visible GtkInfoBar* */ + GHashTable *auths; + /* stores a mapping from TpAccount to Handler ID to prevent * to listen more than once to the status-changed signal */ GHashTable *status_changed_handlers; @@ -286,12 +292,146 @@ main_window_flash_start (EmpathyMainWindow *window) } static void +main_window_remove_auth (EmpathyMainWindow *window, + EmpathyEvent *event) +{ + EmpathyMainWindowPriv *priv = GET_PRIV (window); + GtkWidget *error_widget; + + error_widget = g_hash_table_lookup (priv->auths, event); + if (error_widget != NULL) { + gtk_widget_destroy (error_widget); + g_hash_table_remove (priv->auths, event); + } +} + +static void +main_window_auth_add_clicked_cb (GtkButton *button, + EmpathyMainWindow *window) +{ + EmpathyEvent *event; + + event = g_object_get_data (G_OBJECT (button), "event"); + + empathy_event_approve (event); + + main_window_remove_auth (window, event); +} + +static void +main_window_auth_close_clicked_cb (GtkButton *button, + EmpathyMainWindow *window) +{ + EmpathyEvent *event; + + event = g_object_get_data (G_OBJECT (button), "event"); + + empathy_event_decline (event); + main_window_remove_auth (window, event); +} + +static void +main_window_auth_display (EmpathyMainWindow *window, + EmpathyEvent *event) +{ + EmpathyMainWindowPriv *priv = GET_PRIV (window); + TpAccount *account = event->account; + GtkWidget *info_bar; + GtkWidget *content_area; + GtkWidget *image; + GtkWidget *label; + GtkWidget *add_button; + GtkWidget *close_button; + GtkWidget *action_area; + GtkWidget *action_table; + const gchar *icon_name; + gchar *str; + + if (g_hash_table_lookup (priv->auths, event) != NULL) { + return; + } + + info_bar = gtk_info_bar_new (); + gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar), GTK_MESSAGE_QUESTION); + + gtk_widget_set_no_show_all (info_bar, TRUE); + gtk_box_pack_start (GTK_BOX (priv->auth_vbox), info_bar, FALSE, TRUE, 0); + gtk_widget_show (info_bar); + + icon_name = tp_account_get_icon_name (account); + image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_widget_show (image); + + str = g_markup_printf_escaped ("<b>%s</b>\n%s", + tp_account_get_display_name (account), + _("Password required")); + + label = gtk_label_new (str); + gtk_label_set_use_markup (GTK_LABEL (label), TRUE); + gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + gtk_widget_show (label); + + g_free (str); + + content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (info_bar)); + gtk_box_pack_start (GTK_BOX (content_area), image, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (content_area), label, TRUE, TRUE, 0); + + image = gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_BUTTON); + add_button = gtk_button_new (); + gtk_button_set_image (GTK_BUTTON (add_button), image); + gtk_widget_set_tooltip_text (add_button, _("Provide Password")); + gtk_widget_show (add_button); + + image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_BUTTON); + close_button = gtk_button_new (); + gtk_button_set_image (GTK_BUTTON (close_button), image); + gtk_widget_set_tooltip_text (close_button, _("Disconnect")); + gtk_widget_show (close_button); + + action_table = gtk_table_new (1, 2, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (action_table), 6); + gtk_widget_show (action_table); + + action_area = gtk_info_bar_get_action_area (GTK_INFO_BAR (info_bar)); + gtk_box_pack_start (GTK_BOX (action_area), action_table, FALSE, FALSE, 0); + + gtk_table_attach (GTK_TABLE (action_table), add_button, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_SHRINK), + (GtkAttachOptions) (GTK_SHRINK), 0, 0); + gtk_table_attach (GTK_TABLE (action_table), close_button, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_SHRINK), + (GtkAttachOptions) (GTK_SHRINK), 0, 0); + + g_object_set_data_full (G_OBJECT (info_bar), + "event", event, NULL); + g_object_set_data_full (G_OBJECT (add_button), + "event", event, NULL); + g_object_set_data_full (G_OBJECT (close_button), + "event", event, NULL); + + g_signal_connect (add_button, "clicked", + G_CALLBACK (main_window_auth_add_clicked_cb), + window); + g_signal_connect (close_button, "clicked", + G_CALLBACK (main_window_auth_close_clicked_cb), + window); + + gtk_widget_show (priv->auth_vbox); + + g_hash_table_insert (priv->auths, event, info_bar); +} + +static void main_window_event_added_cb (EmpathyEventManager *manager, EmpathyEvent *event, EmpathyMainWindow *window) { if (event->contact) { main_window_flash_start (window); + } else if (event->type == EMPATHY_EVENT_TYPE_AUTH) { + main_window_auth_display (window, event); } } @@ -303,6 +443,11 @@ main_window_event_removed_cb (EmpathyEventManager *manager, EmpathyMainWindowPriv *priv = GET_PRIV (window); FlashForeachData data; + if (event->type == EMPATHY_EVENT_TYPE_AUTH) { + main_window_remove_auth (window, event); + return; + } + if (!event->contact) { return; } @@ -593,6 +738,7 @@ main_window_error_display (EmpathyMainWindow *window, G_CALLBACK (main_window_error_retry_clicked_cb), window); + gtk_widget_set_tooltip_text (priv->errors_vbox, error_message); gtk_widget_show (priv->errors_vbox); g_hash_table_insert (priv->errors, g_object_ref (account), info_bar); @@ -711,6 +857,7 @@ empathy_main_window_finalize (GObject *window) g_object_unref (priv->contact_manager); g_object_unref (priv->sound_mgr); g_hash_table_destroy (priv->errors); + g_hash_table_destroy (priv->auths); /* disconnect all handlers of status-changed signal */ g_hash_table_iter_init (&iter, priv->status_changed_handlers); @@ -1334,9 +1481,9 @@ main_window_help_debug_cb (GtkAction *action, { GdkScreen *screen = gdk_screen_get_default (); GError *error = NULL; - gchar *argv[2] = { NULL, }; - gint i = 0; gchar *path; + GAppInfo *app_info; + GdkAppLaunchContext *context = NULL; g_return_if_fail (GDK_IS_SCREEN (screen)); @@ -1349,17 +1496,26 @@ main_window_help_debug_cb (GtkAction *action, path = g_build_filename (BIN_DIR, "empathy-debugger", NULL); } - argv[i++] = path; + app_info = g_app_info_create_from_commandline (path, NULL, 0, &error); + if (app_info == NULL) { + DEBUG ("Failed to create app info: %s", error->message); + g_error_free (error); + goto out; + } - gdk_spawn_on_screen (screen, NULL, argv, NULL, - G_SPAWN_SEARCH_PATH, - NULL, NULL, NULL, &error); + context = gdk_app_launch_context_new (); + gdk_app_launch_context_set_display (context, gdk_screen_get_display (screen)); - if (error) { + if (!g_app_info_launch (app_info, NULL, (GAppLaunchContext *) context, + &error)) { g_warning ("Failed to open debug window: %s", error->message); g_error_free (error); + goto out; } +out: + tp_clear_object (&app_info); + tp_clear_object (&context); g_free (path); } @@ -1591,6 +1747,7 @@ empathy_main_window_init (EmpathyMainWindow *window) gui = empathy_builder_get_file (filename, "main_vbox", &priv->main_vbox, "errors_vbox", &priv->errors_vbox, + "auth_vbox", &priv->auth_vbox, "ui_manager", &priv->ui_manager, "view_show_offline", &show_offline_widget, "view_show_protocols", &priv->show_protocols, @@ -1660,6 +1817,8 @@ empathy_main_window_init (EmpathyMainWindow *window) g_object_unref, NULL); + priv->auths = g_hash_table_new (NULL, NULL); + priv->status_changed_handlers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, diff --git a/src/empathy-main-window.ui b/src/empathy-main-window.ui index 8356a1af7..e684c6bdf 100644 --- a/src/empathy-main-window.ui +++ b/src/empathy-main-window.ui @@ -309,6 +309,18 @@ </packing> </child> <child> + <object class="GtkVBox" id="auth_vbox"> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">3</property> + </packing> + </child> + <child> <object class="GtkNotebook" id="notebook"> <property name="visible">True</property> <property name="can_focus">True</property> @@ -340,7 +352,7 @@ </child> </object> <packing> - <property name="position">3</property> + <property name="position">4</property> </packing> </child> </object> diff --git a/src/empathy-notifications-approver.c b/src/empathy-notifications-approver.c index 0bfe03274..e0d540cdc 100644 --- a/src/empathy-notifications-approver.c +++ b/src/empathy-notifications-approver.c @@ -314,7 +314,11 @@ event_added_cb (EmpathyEventManager *manager, if (self->priv->event != NULL) return; + if (event->type == EMPATHY_EVENT_TYPE_AUTH) + return; + self->priv->event = event; + update_notification (self); } @@ -326,6 +330,9 @@ event_removed_cb (EmpathyEventManager *manager, if (event != self->priv->event) return; + if (event->type == EMPATHY_EVENT_TYPE_AUTH) + return; + self->priv->event = empathy_event_manager_get_top_event ( self->priv->event_mgr); @@ -340,6 +347,9 @@ event_updated_cb (EmpathyEventManager *manager, if (event != self->priv->event) return; + if (event->type == EMPATHY_EVENT_TYPE_AUTH) + return; + if (empathy_notify_manager_notification_is_enabled (self->priv->notify_mgr)) update_notification (self); } diff --git a/src/empathy-status-icon.c b/src/empathy-status-icon.c index 0c834a670..38a68d433 100644 --- a/src/empathy-status-icon.c +++ b/src/empathy-status-icon.c @@ -159,7 +159,7 @@ status_icon_event_added_cb (EmpathyEventManager *manager, DEBUG ("New event %p", event); priv->event = event; - if (event->must_ack) { + if (event->must_ack || event->type == EMPATHY_EVENT_TYPE_AUTH) { priv->showing_event_icon = TRUE; status_icon_update_icon (icon); status_icon_update_tooltip (icon); |