/* -*- 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));
}