/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* * Copyright © 2000-2003 Marco Pesenti Gritti * Copyright © 2003, 2004, 2005 Christian Persch * Copyright © 2010, 2017 Igalia S.L. * * This file is part of Epiphany. * * Epiphany is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Epiphany is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Epiphany. If not, see . */ #include "ephy-firefox-sync-dialog.h" #include "ephy-debug.h" #include "ephy-embed-prefs.h" #include "ephy-embed-shell.h" #include "ephy-prefs.h" #include "ephy-settings.h" #include "ephy-shell.h" #include "ephy-sync-service.h" #include "ephy-sync-utils.h" #include "ephy-time-helpers.h" #include "synced-tabs-dialog.h" #define FXA_IFRAME_URL "https://accounts.firefox.com/signin?service=sync&context=fx_desktop_v3" struct _EphyFirefoxSyncDialog { HdyWindow parent_instance; GtkWidget *sync_page_group; GtkWidget *sync_firefox_iframe_box; GtkWidget *sync_firefox_iframe_label; GtkWidget *sync_firefox_account_group; GtkWidget *sync_firefox_account_row; GtkWidget *sync_options_group; GtkWidget *sync_bookmarks_switch; GtkWidget *sync_passwords_switch; GtkWidget *sync_history_switch; GtkWidget *sync_open_tabs_switch; GtkWidget *sync_frequency_row; GtkWidget *sync_now_button; GtkWidget *synced_tabs_button; GtkWidget *sync_device_name_entry; GtkWidget *sync_device_name_change_button; GtkWidget *sync_device_name_save_button; GtkWidget *sync_device_name_cancel_button; WebKitWebView *fxa_web_view; WebKitUserContentManager *fxa_manager; WebKitUserScript *fxa_script; }; G_DEFINE_TYPE (EphyFirefoxSyncDialog, ephy_firefox_sync_dialog, HDY_TYPE_WINDOW) static const guint sync_frequency_minutes[] = { 5, 15, 30, 60 }; static void sync_collection_toggled_cb (GtkWidget *sw, gboolean sw_active, EphyFirefoxSyncDialog *sync_dialog) { EphySynchronizableManager *manager = NULL; EphyShell *shell = ephy_shell_get_default (); EphySyncService *service = ephy_shell_get_sync_service (shell); if (GTK_WIDGET (sw) == sync_dialog->sync_bookmarks_switch) { manager = EPHY_SYNCHRONIZABLE_MANAGER (ephy_shell_get_bookmarks_manager (shell)); } else if (GTK_WIDGET (sw) == sync_dialog->sync_passwords_switch) { manager = EPHY_SYNCHRONIZABLE_MANAGER (ephy_embed_shell_get_password_manager (EPHY_EMBED_SHELL (shell))); } else if (GTK_WIDGET (sw) == sync_dialog->sync_history_switch) { manager = EPHY_SYNCHRONIZABLE_MANAGER (ephy_shell_get_history_manager (shell)); } else if (GTK_WIDGET (sw) == sync_dialog->sync_open_tabs_switch) { manager = EPHY_SYNCHRONIZABLE_MANAGER (ephy_shell_get_open_tabs_manager (shell)); ephy_open_tabs_manager_clear_cache (EPHY_OPEN_TABS_MANAGER (manager)); } else { g_assert_not_reached (); } if (sw_active) { ephy_sync_service_register_manager (service, manager); } else { ephy_sync_service_unregister_manager (service, manager); ephy_synchronizable_manager_set_is_initial_sync (manager, TRUE); } } static void sync_set_last_sync_time (EphyFirefoxSyncDialog *sync_dialog) { gint64 sync_time = ephy_sync_utils_get_sync_time (); if (sync_time) { char *time = ephy_time_helpers_utf_friendly_time (sync_time); /* Translators: the %s refers to the time at which the last sync was made. * For example: Today 04:34 PM, Sun 11:25 AM, May 31 06:41 PM. */ char *text = g_strdup_printf (_("Last synchronized: %s"), time); hdy_action_row_set_subtitle (HDY_ACTION_ROW (sync_dialog->sync_firefox_account_row), text); g_free (text); g_free (time); } } static void sync_finished_cb (EphySyncService *service, EphyFirefoxSyncDialog *sync_dialog) { g_assert (EPHY_IS_SYNC_SERVICE (service)); g_assert (EPHY_IS_FIREFOX_SYNC_DIALOG (sync_dialog)); gtk_widget_set_sensitive (sync_dialog->sync_now_button, TRUE); sync_set_last_sync_time (sync_dialog); } static void sync_sign_in_details_show (EphyFirefoxSyncDialog *sync_dialog, const char *text) { char *message; g_assert (EPHY_IS_FIREFOX_SYNC_DIALOG (sync_dialog)); message = g_strdup_printf ("%s", text); gtk_label_set_markup (GTK_LABEL (sync_dialog->sync_firefox_iframe_label), message); gtk_widget_set_visible (sync_dialog->sync_firefox_iframe_label, TRUE); g_free (message); } static void sync_sign_in_error_cb (EphySyncService *service, const char *error, EphyFirefoxSyncDialog *sync_dialog) { g_assert (EPHY_IS_SYNC_SERVICE (service)); g_assert (EPHY_IS_FIREFOX_SYNC_DIALOG (sync_dialog)); /* Display the error message and reload the iframe. */ sync_sign_in_details_show (sync_dialog, error); webkit_web_view_load_uri (sync_dialog->fxa_web_view, FXA_IFRAME_URL); } static void sync_secrets_store_finished_cb (EphySyncService *service, GError *error, EphyFirefoxSyncDialog *sync_dialog) { g_assert (EPHY_IS_SYNC_SERVICE (service)); g_assert (EPHY_IS_FIREFOX_SYNC_DIALOG (sync_dialog)); if (!error) { hdy_preferences_row_set_title (HDY_PREFERENCES_ROW (sync_dialog->sync_firefox_account_row), ephy_sync_utils_get_sync_user ()); gtk_widget_hide (sync_dialog->sync_page_group); gtk_widget_show (sync_dialog->sync_firefox_account_group); gtk_widget_show (sync_dialog->sync_options_group); } else { /* Display the error message and reload the iframe. */ sync_sign_in_details_show (sync_dialog, error->message); webkit_web_view_load_uri (sync_dialog->fxa_web_view, FXA_IFRAME_URL); } } static void sync_message_to_fxa_content (EphyFirefoxSyncDialog *sync_dialog, const char *web_channel_id, const char *command, const char *message_id, JsonObject *data) { JsonNode *node; JsonObject *detail; JsonObject *message; char *detail_str; char *script; const char *type; g_assert (EPHY_FIREFOX_SYNC_DIALOG (sync_dialog)); g_assert (web_channel_id); g_assert (command); g_assert (message_id); g_assert (data); message = json_object_new (); json_object_set_string_member (message, "command", command); json_object_set_string_member (message, "messageId", message_id); json_object_set_object_member (message, "data", json_object_ref (data)); detail = json_object_new (); json_object_set_string_member (detail, "id", web_channel_id); json_object_set_object_member (detail, "message", message); node = json_node_new (JSON_NODE_OBJECT); json_node_set_object (node, detail); type = "WebChannelMessageToContent"; detail_str = json_to_string (node, FALSE); script = g_strdup_printf ("let e = new window.CustomEvent(\"%s\", {detail: %s});" "window.dispatchEvent(e);", type, detail_str); /* We don't expect any response from the server. */ webkit_web_view_run_javascript (sync_dialog->fxa_web_view, script, NULL, NULL, NULL); g_free (script); g_free (detail_str); json_object_unref (detail); json_node_unref (node); } static gboolean sync_parse_message_from_fxa_content (const char *message, char **web_channel_id, char **message_id, char **command, JsonObject **data, char **error_msg) { JsonNode *node; JsonObject *object; JsonObject *detail; JsonObject *msg; JsonObject *msg_data = NULL; const char *type; const char *channel_id; const char *cmd; const char *error = NULL; gboolean success = FALSE; g_assert (message); g_assert (web_channel_id); g_assert (message_id); g_assert (command); g_assert (data); g_assert (error_msg); /* Expected message format is: * { * type: "WebChannelMessageToChrome", * detail: { * id: (string, the id of the WebChannel), * message: { * messageId: (optional string, the message id), * command: (string, the message command), * data: (optional JSON object, the message data) * } * } * } */ node = json_from_string (message, NULL); if (!node) { error = "Message is not a valid JSON"; goto out_error; } object = json_node_get_object (node); if (!object) { error = "Message is not a JSON object"; goto out_error; } type = json_object_get_string_member (object, "type"); if (!type) { error = "Message has missing or invalid 'type' member"; goto out_error; } else if (strcmp (type, "WebChannelMessageToChrome")) { error = "Message type is not WebChannelMessageToChrome"; goto out_error; } detail = json_object_get_object_member (object, "detail"); if (!detail) { error = "Message has missing or invalid 'detail' member"; goto out_error; } channel_id = json_object_get_string_member (detail, "id"); if (!channel_id) { error = "'Detail' object has missing or invalid 'id' member"; goto out_error; } msg = json_object_get_object_member (detail, "message"); if (!msg) { error = "'Detail' object has missing or invalid 'message' member"; goto out_error; } cmd = json_object_get_string_member (msg, "command"); if (!cmd) { error = "'Message' object has missing or invalid 'command' member"; goto out_error; } *web_channel_id = g_strdup (channel_id); *command = g_strdup (cmd); *message_id = json_object_has_member (msg, "messageId") ? g_strdup (json_object_get_string_member (msg, "messageId")) : NULL; if (json_object_has_member (msg, "data")) msg_data = json_object_get_object_member (msg, "data"); *data = msg_data ? json_object_ref (msg_data) : NULL; success = TRUE; *error_msg = NULL; goto out_no_error; out_error: *web_channel_id = NULL; *command = NULL; *message_id = NULL; *error_msg = g_strdup (error); out_no_error: json_node_unref (node); return success; } static void sync_message_from_fxa_content_cb (WebKitUserContentManager *manager, WebKitJavascriptResult *result, EphyFirefoxSyncDialog *sync_dialog) { JsonObject *data = NULL; char *message = NULL; char *web_channel_id = NULL; char *message_id = NULL; char *command = NULL; char *error_msg = NULL; gboolean is_error = FALSE; message = jsc_value_to_string (webkit_javascript_result_get_js_value (result)); if (!message) { g_warning ("Failed to get JavaScript result as string"); is_error = TRUE; goto out; } if (!sync_parse_message_from_fxa_content (message, &web_channel_id, &message_id, &command, &data, &error_msg)) { g_warning ("Failed to parse message from FxA Content Server: %s", error_msg); is_error = TRUE; goto out; } LOG ("WebChannelMessageToChrome: received %s command", command); if (!g_strcmp0 (command, "fxaccounts:can_link_account")) { /* Confirm a relink. Respond with {ok: true}. */ JsonObject *response = json_object_new (); json_object_set_boolean_member (response, "ok", TRUE); sync_message_to_fxa_content (sync_dialog, web_channel_id, command, message_id, response); json_object_unref (response); } else if (!g_strcmp0 (command, "fxaccounts:login")) { /* Extract sync tokens and pass them to the sync service. */ const char *email = json_object_get_string_member (data, "email"); const char *uid = json_object_get_string_member (data, "uid"); const char *session_token = json_object_get_string_member (data, "sessionToken"); const char *key_fetch_token = json_object_get_string_member (data, "keyFetchToken"); const char *unwrap_kb = json_object_get_string_member (data, "unwrapBKey"); if (!email || !uid || !session_token || !key_fetch_token || !unwrap_kb) { g_warning ("Message data has missing or invalid members"); is_error = TRUE; goto out; } if (!json_object_has_member (data, "verified") || !JSON_NODE_HOLDS_VALUE (json_object_get_member (data, "verified"))) { g_warning ("Message data has missing or invalid 'verified' member"); is_error = TRUE; goto out; } ephy_sync_service_sign_in (ephy_shell_get_sync_service (ephy_shell_get_default ()), email, uid, session_token, key_fetch_token, unwrap_kb); } out: if (data) json_object_unref (data); g_free (message); g_free (web_channel_id); g_free (message_id); g_free (command); g_free (error_msg); if (is_error) { sync_sign_in_details_show (sync_dialog, _("Something went wrong, please try again later.")); webkit_web_view_load_uri (sync_dialog->fxa_web_view, FXA_IFRAME_URL); } } static void sync_open_webmail_clicked_cb (WebKitUserContentManager *manager, WebKitJavascriptResult *result, EphyFirefoxSyncDialog *sync_page) { EphyShell *shell; EphyEmbed *embed; GtkWindow *window; GtkWidget *prefs_dialog; char *url; url = jsc_value_to_string (webkit_javascript_result_get_js_value (result)); if (url) { /* Open a new tab to the webmail URL. */ shell = ephy_shell_get_default (); window = gtk_application_get_active_window (GTK_APPLICATION (shell)); embed = ephy_shell_new_tab (shell, EPHY_WINDOW (window), NULL, EPHY_NEW_TAB_JUMP); ephy_web_view_load_url (ephy_embed_get_web_view (embed), url); /* Close the preferences dialog. */ prefs_dialog = gtk_widget_get_toplevel (GTK_WIDGET (sync_page)); gtk_widget_destroy (GTK_WIDGET (prefs_dialog)); g_free (url); } } static void sync_setup_firefox_iframe (EphyFirefoxSyncDialog *sync_dialog) { EphyEmbedShell *shell; WebKitWebsiteDataManager *manager; WebKitWebContext *embed_context; WebKitWebContext *sync_context; GtkWidget *frame; const char *script; if (!sync_dialog->fxa_web_view) { script = /* Handle sign-in messages from the FxA content server. */ "function handleToChromeMessage(event) {" " let e = JSON.stringify({type: event.type, detail: event.detail});" " window.webkit.messageHandlers.toChromeMessageHandler.postMessage(e);" "};" "window.addEventListener('WebChannelMessageToChrome', handleToChromeMessage);" /* Handle open-webmail click event. */ "function handleOpenWebmailClick(event) {" " if (event.target.id == 'open-webmail' && event.target.hasAttribute('href'))" " window.webkit.messageHandlers.openWebmailClickHandler.postMessage(event.target.getAttribute('href'));" "};" "var stage = document.getElementById('stage');" "if (stage)" " stage.addEventListener('click', handleOpenWebmailClick);"; sync_dialog->fxa_script = webkit_user_script_new (script, WEBKIT_USER_CONTENT_INJECT_TOP_FRAME, WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_END, NULL, NULL); sync_dialog->fxa_manager = webkit_user_content_manager_new (); webkit_user_content_manager_add_script (sync_dialog->fxa_manager, sync_dialog->fxa_script); g_signal_connect (sync_dialog->fxa_manager, "script-message-received::toChromeMessageHandler", G_CALLBACK (sync_message_from_fxa_content_cb), sync_dialog); g_signal_connect (sync_dialog->fxa_manager, "script-message-received::openWebmailClickHandler", G_CALLBACK (sync_open_webmail_clicked_cb), sync_dialog); webkit_user_content_manager_register_script_message_handler (sync_dialog->fxa_manager, "toChromeMessageHandler"); webkit_user_content_manager_register_script_message_handler (sync_dialog->fxa_manager, "openWebmailClickHandler"); shell = ephy_embed_shell_get_default (); embed_context = ephy_embed_shell_get_web_context (shell); manager = webkit_web_context_get_website_data_manager (embed_context); sync_context = webkit_web_context_new_with_website_data_manager (manager); webkit_web_context_set_preferred_languages (sync_context, g_object_get_data (G_OBJECT (embed_context), "preferred-languages")); sync_dialog->fxa_web_view = WEBKIT_WEB_VIEW (g_object_new (WEBKIT_TYPE_WEB_VIEW, "user-content-manager", sync_dialog->fxa_manager, "settings", ephy_embed_prefs_get_settings (), "web-context", sync_context, NULL)); gtk_widget_set_vexpand (GTK_WIDGET (sync_dialog->fxa_web_view), TRUE); gtk_widget_set_visible (GTK_WIDGET (sync_dialog->fxa_web_view), TRUE); frame = gtk_frame_new (NULL); gtk_widget_set_visible (frame, TRUE); gtk_container_add (GTK_CONTAINER (frame), GTK_WIDGET (sync_dialog->fxa_web_view)); gtk_box_pack_start (GTK_BOX (sync_dialog->sync_firefox_iframe_box), frame, TRUE, TRUE, 0); g_object_unref (sync_context); } webkit_web_view_load_uri (sync_dialog->fxa_web_view, FXA_IFRAME_URL); gtk_widget_set_visible (sync_dialog->sync_firefox_iframe_label, FALSE); } static void on_sync_sign_out_button_clicked (GtkWidget *button, EphyFirefoxSyncDialog *sync_dialog) { EphySyncService *service = ephy_shell_get_sync_service (ephy_shell_get_default ()); ephy_sync_service_sign_out (service); /* Show Firefox Accounts iframe. */ sync_setup_firefox_iframe (sync_dialog); gtk_widget_hide (sync_dialog->sync_firefox_account_group); gtk_widget_hide (sync_dialog->sync_options_group); gtk_widget_show (sync_dialog->sync_page_group); hdy_action_row_set_subtitle (HDY_ACTION_ROW (sync_dialog->sync_firefox_account_row), NULL); } static void on_sync_sync_now_button_clicked (GtkWidget *button, EphyFirefoxSyncDialog *sync_dialog) { EphySyncService *service = ephy_shell_get_sync_service (ephy_shell_get_default ()); gtk_widget_set_sensitive (button, FALSE); ephy_sync_service_sync (service); } static void on_sync_synced_tabs_button_clicked (GtkWidget *button, EphyFirefoxSyncDialog *sync_dialog) { EphyOpenTabsManager *manager; SyncedTabsDialog *synced_tabs_dialog; manager = ephy_shell_get_open_tabs_manager (ephy_shell_get_default ()); synced_tabs_dialog = synced_tabs_dialog_new (manager); gtk_window_set_transient_for (GTK_WINDOW (synced_tabs_dialog), GTK_WINDOW (sync_dialog)); gtk_window_set_modal (GTK_WINDOW (synced_tabs_dialog), TRUE); gtk_window_present_with_time (GTK_WINDOW (synced_tabs_dialog), gtk_get_current_event_time ()); } static void on_sync_device_name_change_button_clicked (GtkWidget *button, EphyFirefoxSyncDialog *sync_dialog) { gtk_widget_set_sensitive (GTK_WIDGET (sync_dialog->sync_device_name_entry), TRUE); gtk_widget_set_visible (GTK_WIDGET (sync_dialog->sync_device_name_change_button), FALSE); gtk_widget_set_visible (GTK_WIDGET (sync_dialog->sync_device_name_save_button), TRUE); gtk_widget_set_visible (GTK_WIDGET (sync_dialog->sync_device_name_cancel_button), TRUE); } static void on_sync_device_name_save_button_clicked (GtkWidget *button, EphyFirefoxSyncDialog *sync_dialog) { EphySyncService *service = ephy_shell_get_sync_service (ephy_shell_get_default ()); const char *text; text = gtk_entry_get_text (GTK_ENTRY (sync_dialog->sync_device_name_entry)); if (!g_strcmp0 (text, "")) { char *name = ephy_sync_utils_get_device_name (); gtk_entry_set_text (GTK_ENTRY (sync_dialog->sync_device_name_entry), name); g_free (name); } else { ephy_sync_service_update_device_name (service, text); } gtk_widget_set_sensitive (GTK_WIDGET (sync_dialog->sync_device_name_entry), FALSE); gtk_widget_set_visible (GTK_WIDGET (sync_dialog->sync_device_name_change_button), TRUE); gtk_widget_set_visible (GTK_WIDGET (sync_dialog->sync_device_name_save_button), FALSE); gtk_widget_set_visible (GTK_WIDGET (sync_dialog->sync_device_name_cancel_button), FALSE); } static void on_sync_device_name_cancel_button_clicked (GtkWidget *button, EphyFirefoxSyncDialog *sync_dialog) { char *name; name = ephy_sync_utils_get_device_name (); gtk_entry_set_text (GTK_ENTRY (sync_dialog->sync_device_name_entry), name); gtk_widget_set_sensitive (GTK_WIDGET (sync_dialog->sync_device_name_entry), FALSE); gtk_widget_set_visible (GTK_WIDGET (sync_dialog->sync_device_name_change_button), TRUE); gtk_widget_set_visible (GTK_WIDGET (sync_dialog->sync_device_name_save_button), FALSE); gtk_widget_set_visible (GTK_WIDGET (sync_dialog->sync_device_name_cancel_button), FALSE); g_free (name); } static void prefs_sync_page_finalize (GObject *object) { EphyFirefoxSyncDialog *sync_dialog = EPHY_FIREFOX_SYNC_DIALOG (object); if (sync_dialog->fxa_web_view != NULL) { webkit_user_content_manager_unregister_script_message_handler (sync_dialog->fxa_manager, "toChromeMessageHandler"); webkit_user_content_manager_unregister_script_message_handler (sync_dialog->fxa_manager, "openWebmailClickHandler"); webkit_user_script_unref (sync_dialog->fxa_script); g_object_unref (sync_dialog->fxa_manager); } G_OBJECT_CLASS (ephy_firefox_sync_dialog_parent_class)->finalize (object); } static void ephy_firefox_sync_dialog_class_init (EphyFirefoxSyncDialogClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/epiphany/gtk/firefox-sync-dialog.ui"); object_class->finalize = prefs_sync_page_finalize; gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_page_group); gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_firefox_iframe_box); gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_firefox_iframe_label); gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_firefox_account_group); gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_firefox_account_row); gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_options_group); gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_bookmarks_switch); gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_passwords_switch); gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_history_switch); gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_open_tabs_switch); gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_frequency_row); gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_now_button); gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, synced_tabs_button); gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_device_name_entry); gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_device_name_change_button); gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_device_name_save_button); gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_device_name_cancel_button); gtk_widget_class_bind_template_callback (widget_class, on_sync_sign_out_button_clicked); gtk_widget_class_bind_template_callback (widget_class, on_sync_sync_now_button_clicked); gtk_widget_class_bind_template_callback (widget_class, on_sync_synced_tabs_button_clicked); gtk_widget_class_bind_template_callback (widget_class, on_sync_device_name_change_button_clicked); gtk_widget_class_bind_template_callback (widget_class, on_sync_device_name_save_button_clicked); gtk_widget_class_bind_template_callback (widget_class, on_sync_device_name_cancel_button_clicked); } static gboolean sync_frequency_get_mapping (GValue *value, GVariant *variant, gpointer user_data) { uint minutes = g_variant_get_uint32 (variant); for (gint i = 0; i < (gint)G_N_ELEMENTS (sync_frequency_minutes); i++) { if (sync_frequency_minutes[i] != minutes) continue; g_value_set_int (value, i); return TRUE; } return FALSE; } static GVariant * sync_frequency_set_mapping (const GValue *value, const GVariantType *expected_type, gpointer user_data) { gint i = g_value_get_int (value); if (i >= (gint)G_N_ELEMENTS (sync_frequency_minutes)) return NULL; return g_variant_new_uint32 (sync_frequency_minutes[i]); } static GListModel * create_sync_frequency_minutes_model () { GListStore *list_store = g_list_store_new (HDY_TYPE_VALUE_OBJECT); HdyValueObject *obj; g_auto (GValue) value = G_VALUE_INIT; guint i; g_value_init (&value, G_TYPE_UINT); for (i = 0; i < G_N_ELEMENTS (sync_frequency_minutes); i++) { g_value_set_uint (&value, sync_frequency_minutes[i]); obj = hdy_value_object_new (&value); g_list_store_insert (list_store, i, obj); g_clear_object (&obj); } return G_LIST_MODEL (list_store); } static gchar * get_sync_frequency_minutes_name (HdyValueObject *value) { return g_strdup_printf ("%u min", g_value_get_uint (hdy_value_object_get_value (value))); } void ephy_firefox_sync_dialog_setup (EphyFirefoxSyncDialog *sync_dialog) { EphySyncService *service = ephy_shell_get_sync_service (ephy_shell_get_default ()); GSettings *sync_settings = ephy_settings_get (EPHY_PREFS_SYNC_SCHEMA); char *user = ephy_sync_utils_get_sync_user (); char *name = ephy_sync_utils_get_device_name (); g_autoptr (GListModel) sync_frequency_minutes_model = create_sync_frequency_minutes_model (); gtk_entry_set_text (GTK_ENTRY (sync_dialog->sync_device_name_entry), name); if (!user) { sync_setup_firefox_iframe (sync_dialog); gtk_widget_hide (sync_dialog->sync_firefox_account_group); gtk_widget_hide (sync_dialog->sync_options_group); } else { sync_set_last_sync_time (sync_dialog); hdy_preferences_row_set_title (HDY_PREFERENCES_ROW (sync_dialog->sync_firefox_account_row), user); gtk_widget_hide (sync_dialog->sync_page_group); } g_settings_bind (sync_settings, EPHY_PREFS_SYNC_BOOKMARKS_ENABLED, sync_dialog->sync_bookmarks_switch, "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind (sync_settings, EPHY_PREFS_SYNC_PASSWORDS_ENABLED, sync_dialog->sync_passwords_switch, "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind (sync_settings, EPHY_PREFS_SYNC_HISTORY_ENABLED, sync_dialog->sync_history_switch, "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind (sync_settings, EPHY_PREFS_SYNC_OPEN_TABS_ENABLED, sync_dialog->sync_open_tabs_switch, "active", G_SETTINGS_BIND_DEFAULT); hdy_combo_row_bind_name_model (HDY_COMBO_ROW (sync_dialog->sync_frequency_row), sync_frequency_minutes_model, (HdyComboRowGetNameFunc)get_sync_frequency_minutes_name, NULL, NULL); g_settings_bind_with_mapping (sync_settings, EPHY_PREFS_SYNC_FREQUENCY, sync_dialog->sync_frequency_row, "selected-index", G_SETTINGS_BIND_DEFAULT, sync_frequency_get_mapping, sync_frequency_set_mapping, NULL, NULL); g_object_bind_property (sync_dialog->sync_open_tabs_switch, "active", sync_dialog->synced_tabs_button, "sensitive", G_BINDING_SYNC_CREATE); g_signal_connect_object (service, "sync-secrets-store-finished", G_CALLBACK (sync_secrets_store_finished_cb), sync_dialog, 0); g_signal_connect_object (service, "sync-sign-in-error", G_CALLBACK (sync_sign_in_error_cb), sync_dialog, 0); g_signal_connect_object (service, "sync-finished", G_CALLBACK (sync_finished_cb), sync_dialog, 0); g_signal_connect_object (sync_dialog->sync_bookmarks_switch, "notify::active", G_CALLBACK (sync_collection_toggled_cb), sync_dialog, 0); g_signal_connect_object (sync_dialog->sync_passwords_switch, "notify::active", G_CALLBACK (sync_collection_toggled_cb), sync_dialog, 0); g_signal_connect_object (sync_dialog->sync_history_switch, "notify::active", G_CALLBACK (sync_collection_toggled_cb), sync_dialog, 0); g_signal_connect_object (sync_dialog->sync_open_tabs_switch, "notify::active", G_CALLBACK (sync_collection_toggled_cb), sync_dialog, 0); g_free (user); g_free (name); } static void ephy_firefox_sync_dialog_init (EphyFirefoxSyncDialog *sync_dialog) { gtk_widget_init_template (GTK_WIDGET (sync_dialog)); ephy_firefox_sync_dialog_setup (sync_dialog); } GtkWidget * ephy_firefox_sync_dialog_new () { return GTK_WIDGET (g_object_new (EPHY_TYPE_FIREFOX_SYNC_DIALOG, NULL)); }