[epiphany] Use the new top-widget infrastructure to ask whether to store passwords



commit 828a97c512dd500be59825d64c899468f9598562
Author: Gustavo Noronha Silva <gns gnome org>
Date:   Wed Dec 16 18:01:32 2009 +0100

    Use the new top-widget infrastructure to ask whether to store passwords

 configure.ac          |    2 +-
 embed/ephy-web-view.c |  209 ++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 191 insertions(+), 20 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 20a3f78..9848ea5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -94,7 +94,7 @@ if test "$enable_maintainer_mode" = "yes"; then
 fi
 
 GLIB_REQUIRED=2.19.7
-GTK_REQUIRED=2.17.11
+GTK_REQUIRED=2.18.0
 LIBXML_REQUIRED=2.6.12
 LIBXSLT_REQUIRED=1.1.7
 LIBSTARTUP_NOTIFICATION_REQUIRED=0.5
diff --git a/embed/ephy-web-view.c b/embed/ephy-web-view.c
index df7639c..d693cf6 100644
--- a/embed/ephy-web-view.c
+++ b/embed/ephy-web-view.c
@@ -854,6 +854,155 @@ js_get_domain_and_path (JSContextRef js_context)
   return NULL;
 }
 
+typedef struct {
+  EphyEmbed *embed;
+  char *uri;
+  char *name_field;
+  char *password_field;
+  char *name_value;
+  char *password_value;
+} StorePasswordData;
+
+static void
+store_password_data_free (gpointer data)
+{
+  StorePasswordData *store_data = (StorePasswordData*)data;
+
+  g_free (store_data->uri);
+  g_free (store_data->name_field);
+  g_free (store_data->name_value);
+  g_free (store_data->password_field);
+  g_free (store_data->password_value);
+
+  g_slice_free (StorePasswordData, store_data);
+}
+
+static void
+store_password (GtkInfoBar *info_bar, gint response_id, gpointer data)
+{
+  StorePasswordData *store_data = (StorePasswordData*)data;
+  char *uri = store_data->uri;
+  char *name_field_name = store_data->name_field;
+  char *name_field_value = store_data->name_value;
+  char *password_field_name = store_data->password_field;
+  char *password_field_value = store_data->password_value;
+  SoupURI *soup_uri;
+
+  if (response_id != GTK_RESPONSE_YES) {
+    LOG ("Response is %d - not saving.", response_id);
+    store_password_data_free (store_data);
+    gtk_widget_destroy (GTK_WIDGET (info_bar));
+    return;
+  }
+
+  LOG ("Response is GTK_RESPONSE_YES - saving!");
+  _ephy_profile_store_form_auth_data (uri,
+                                      name_field_name,
+                                      password_field_name,
+                                      name_field_value,
+                                      password_field_value);
+
+  /* Update internal caching */
+  soup_uri = soup_uri_new (uri);
+
+  ephy_embed_single_add_form_auth (EPHY_EMBED_SINGLE (ephy_embed_shell_get_embed_single (embed_shell)),
+                                   soup_uri->host,
+                                   name_field_name,
+                                   password_field_name,
+                                   name_field_value);
+  soup_uri_free (soup_uri);
+
+  store_password_data_free (store_data);
+  gtk_widget_destroy (GTK_WIDGET (info_bar));
+}
+
+static void
+send_no_response_cb (GtkButton *button, GtkInfoBar *info_bar)
+{
+  gtk_info_bar_response (info_bar, GTK_RESPONSE_NO);
+}
+
+static void
+send_yes_response_cb (GtkButton *button, GtkInfoBar *info_bar)
+{
+  gtk_info_bar_response (info_bar, GTK_RESPONSE_YES);
+}
+
+static void
+request_decision_on_storing (StorePasswordData *store_data)
+{
+  EphyEmbed *embed = store_data->embed;
+  GtkWidget *info_bar;
+  GtkWidget *action_area;
+  GtkWidget *button_box;
+  GtkWidget *action_button;
+  GtkWidget *content_area;
+  GtkWidget *label;
+  char *message;
+
+  LOG ("Going to show infobar about %s", store_data->uri);
+
+  info_bar = gtk_info_bar_new ();
+
+  action_area = gtk_info_bar_get_action_area (GTK_INFO_BAR (info_bar));
+  button_box = gtk_hbutton_box_new ();
+  gtk_container_add (GTK_CONTAINER (action_area), button_box);
+
+  action_button = gtk_button_new_from_stock (GTK_STOCK_NO);
+  g_signal_connect (action_button, "clicked",
+                    G_CALLBACK (send_no_response_cb), info_bar);
+  gtk_box_pack_start (GTK_BOX (button_box), action_button, FALSE, FALSE, 0);
+
+  action_button = gtk_button_new_with_label (_("Store password"));
+  g_signal_connect (action_button, "clicked",
+                    G_CALLBACK (send_yes_response_cb), info_bar);
+  gtk_box_pack_start (GTK_BOX (button_box), action_button, FALSE, FALSE, 0);
+
+  label = gtk_label_new (NULL);
+  message = g_strdup_printf (_("<big><b>Would you like to store the password for %s?</b></big>"),
+                             store_data->uri);
+  gtk_label_set_markup (GTK_LABEL (label), message);
+  g_free (message);
+
+  content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (info_bar));
+  gtk_container_add (GTK_CONTAINER (content_area), label);
+
+  gtk_widget_show_all (info_bar);
+
+  g_signal_connect (info_bar, "response", G_CALLBACK (store_password), store_data);
+
+  ephy_embed_add_top_widget (embed, info_bar, FALSE);
+}
+
+static void
+should_store_cb (GnomeKeyringResult retval,
+                 GList *results,
+                 gpointer user_data)
+{
+  StorePasswordData *store_data = (StorePasswordData*)user_data;
+  GnomeKeyringNetworkPasswordData* keyring_data;
+
+  if (!results) {
+    LOG ("No result on query; asking whether we should store.");
+    request_decision_on_storing (store_data);
+    return;
+  }
+
+  /* FIXME: We use only the first result, for now; We need to do
+   * something smarter here */
+  keyring_data = (GnomeKeyringNetworkPasswordData*)results->data;
+
+  if (g_str_equal (keyring_data->user, store_data->name_value) &&
+      g_str_equal (keyring_data->password, store_data->password_value)) {
+    LOG ("User/password already stored. Not asking about storing.");
+    store_password_data_free (store_data);
+    return;
+  }
+
+  LOG ("User/password not yet stored. Asking about storing.");
+  request_decision_on_storing (store_data);
+}
+
 static JSValueRef
 form_submitted_cb (JSContextRef js_context,
                    JSObjectRef js_function,
@@ -863,16 +1012,19 @@ form_submitted_cb (JSContextRef js_context,
                    JSValueRef* js_exception)
 {
   GSList *elements = js_get_form_elements (js_context, js_this);
+  JSObjectRef js_global = JSContextGetGlobalObject (js_context);
   JSObjectRef name_element = NULL;
   JSObjectRef password_element = NULL;
+  JSObjectRef dummy_object;
   JSStringRef js_string;
   JSValueRef js_value;
+  StorePasswordData *store_data;
   char *name_field_name;
   char *name_field_value;
   char *password_field_name;
   char *password_field_value;
   char *uri;
-  SoupURI *soup_uri;
+  WebKitWebView *web_view;
 
   LOG ("Form submitted!");
 
@@ -896,27 +1048,30 @@ form_submitted_cb (JSContextRef js_context,
   password_field_value = js_value_to_string (js_context, js_value);
 
   uri = js_get_domain_and_path (js_context);
-  _ephy_profile_store_form_auth_data (uri,
-                                      name_field_name,
-                                      password_field_name,
-                                      name_field_value,
-                                      password_field_value);
 
-  /* Update internal caching */
-  soup_uri = soup_uri_new (uri);
-  g_free (uri);
+  store_data = g_slice_new (StorePasswordData);
 
-  ephy_embed_single_add_form_auth (EPHY_EMBED_SINGLE (ephy_embed_shell_get_embed_single (embed_shell)),
-                                   soup_uri->host,
-                                   name_field_name,
-                                   password_field_name,
-                                   name_field_value);
-  soup_uri_free (soup_uri);
+  store_data->uri = uri;
+  store_data->name_field = name_field_name;
+  store_data->name_value = name_field_value;
+  store_data->password_field = password_field_name;
+  store_data->password_value = password_field_value;
 
-  g_free (name_field_name);
-  g_free (name_field_value);
-  g_free (password_field_name);
-  g_free (password_field_value);
+  /* This is required because we can only hold private data on objects
+   * created with our own classes; we need to store the WebView here
+   * because it is needed for form_submitted_cb */
+  dummy_object = js_object_get_property_as_object (js_context,
+                                                   js_global,
+                                                   "_EpiphanyInternalDummy");
+  web_view = JSObjectGetPrivate (dummy_object);
+  store_data->embed = EPHY_GET_EMBED_FROM_EPHY_WEB_VIEW (web_view);
+
+  _ephy_profile_query_form_auth_data (uri,
+                                      name_field_name,
+                                      password_field_name,
+                                      should_store_cb,
+                                      store_data,
+                                      NULL);
 
   return JSValueMakeUndefined (js_context);
 }
@@ -986,6 +1141,11 @@ static void
 do_hook_into_forms (JSContextRef js_context, JSObjectRef js_form_submitted, EphyWebView *web_view)
 {
   GSList *forms = js_get_all_forms (js_context);
+  JSClassDefinition dummy_class_def;
+  JSClassRef dummy_class;
+  JSObjectRef dummy_object;
+  JSStringRef dummy_name;
+  JSObjectRef js_global;
 
   if (!forms) {
     LOG ("No forms found.");
@@ -1019,6 +1179,17 @@ do_hook_into_forms (JSContextRef js_context, JSObjectRef js_form_submitted, Ephy
       LOG ("NOT hooking into form: username element: %p / password element: %p", name_element, password_element);
   }
 
+  dummy_class_def = kJSClassDefinitionEmpty;
+  dummy_class_def.className = "dummy";
+  dummy_class = JSClassCreate (&dummy_class_def);
+  dummy_object = JSObjectMake (js_context, dummy_class, web_view);
+  g_assert (JSObjectGetPrivate (dummy_object) != NULL);
+
+  js_global = JSContextGetGlobalObject (js_context);
+  dummy_name = JSStringCreateWithUTF8CString ("_EpiphanyInternalDummy");
+  JSObjectSetProperty (js_context, js_global, dummy_name, dummy_object, 0, NULL);
+  JSStringRelease (dummy_name);
+
   g_slist_free (forms);
 }
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]