<?xml version="1.0"?>
<paste-with-annotations>
  <paste>
    <number>
      <integer>92095</integer>
    </number>
    <user>
      <string>kov</string>
    </user>
    <title>
      <string>new patch</string>
    </title>
    <contents>
      <string>diff --git a/embed/ephy-web-view.c b/embed/ephy-web-view.c
index e045a1d..e023f78 100644
--- a/embed/ephy-web-view.c
+++ b/embed/ephy-web-view.c
@@ -26,6 +26,8 @@
 #include &lt;gtk/gtk.h&gt;
 #include &lt;string.h&gt;
 #include &lt;webkit/webkit.h&gt;
+#include &lt;JavaScriptCore/JavaScript.h&gt;
+#include &lt;gnome-keyring.h&gt;
 
 #include &quot;eel-gconf-extensions.h&quot;
 #include &quot;ephy-debug.h&quot;
@@ -54,6 +56,11 @@ static void     ephy_web_view_init         (EphyWebView *gs);
 #define RELOAD_DELAY_MAX_TICKS  40  /* RELOAD_DELAY * RELOAD_DELAY_MAX_TICKS = 10 s */
 #define EMPTY_PAGE              _(&quot;Blank page&quot;) /* Title for the empty page */
 
+typedef struct {
+  char *form_username;
+  char *form_password;
+} FormAuthData;
+
 struct _EphyWebViewPrivate {
   EphyWebViewSecurityLevel security_level;
   EphyWebViewDocumentType document_type;
@@ -84,6 +91,7 @@ struct _EphyWebViewPrivate {
 
   GSList *hidden_popups;
   GSList *shown_popups;
+  GHashTable *form_auth_data;
 };
 
 typedef struct {
@@ -503,6 +511,401 @@ ephy_web_view_dispose (GObject *object)
   G_OBJECT_CLASS (ephy_web_view_parent_class)-&gt;dispose (object);
 }
 
+
+static char*
+js_value_to_string (JSContextRef js_context,
+                    JSValueRef js_value)
+{
+  gssize length;
+  char* buffer;
+  JSStringRef str = JSValueToStringCopy (js_context, js_value, NULL);
+  g_return_val_if_fail (str != NULL, NULL);
+
+  length = JSStringGetLength (str) + 1;
+
+  buffer = g_malloc0 (length);
+  JSStringGetUTF8CString (str, buffer, length);
+  JSStringRelease (str);
+
+  return buffer;
+}
+
+static JSObjectRef
+js_object_get_property_as_object (JSContextRef js_context,
+                                  JSObjectRef object,
+                                  const char *attr)
+{
+  JSStringRef attrstr = JSStringCreateWithUTF8CString (attr);
+  JSValueRef val = JSObjectGetProperty (js_context, object, attrstr, NULL);
+
+  JSStringRelease (attrstr);
+  return JSValueToObject (js_context, val, NULL);
+}
+
+static char *
+js_get_element_attribute (JSContextRef js_context,
+                          JSObjectRef object,
+                          const char *attr)
+{
+  JSStringRef attrstr = JSStringCreateWithUTF8CString (attr);
+  JSObjectRef ga = js_object_get_property_as_object (js_context, object, &quot;getAttribute&quot;);
+  JSValueRef args[1], val;
+  char *buffer = NULL;
+
+  args[0] = JSValueMakeString (js_context, attrstr);
+  val = JSObjectCallAsFunction (js_context, ga, object, 1, args, NULL);
+  JSStringRelease (attrstr);
+
+  if (JSValueIsString (js_context, val)) {
+    buffer = js_value_to_string (js_context, val);
+  }
+
+  return buffer;
+}
+
+static GSList*
+js_get_all_forms (JSContextRef js_context)
+{
+  JSObjectRef js_global;
+  JSObjectRef js_object;
+  JSValueRef js_form;
+  guint index = 0;
+  GSList *retval = NULL;
+
+  js_global = JSContextGetGlobalObject (js_context);
+
+  js_object = js_object_get_property_as_object (js_context, js_global, &quot;document&quot;);
+  if (!js_object)
+    return NULL;
+
+  js_object = js_object_get_property_as_object (js_context, js_object, &quot;forms&quot;);
+  if (!js_object)
+    return NULL;
+
+  js_form = JSObjectGetPropertyAtIndex (js_context, js_object, index++, NULL);
+  while (!JSValueIsUndefined (js_context, js_form)) {
+    retval = g_slist_prepend (retval, (gpointer)js_form);
+    js_form = JSObjectGetPropertyAtIndex (js_context, js_object, index++, NULL);
+  }
+
+  return retval;
+}
+
+static GSList*
+js_get_form_elements (JSContextRef js_context, JSValueRef js_form)
+{
+  JSObjectRef js_object = JSValueToObject (js_context, js_form, NULL);
+  JSStringRef js_name;
+  JSValueRef value;
+  guint num;
+  guint count;
+  GSList *retval = NULL;
+
+  js_object = js_object_get_property_as_object (js_context, js_object, &quot;elements&quot;);
+  if (!js_object)
+    return NULL;
+
+  js_name = JSStringCreateWithUTF8CString (&quot;length&quot;);
+  value = JSObjectGetProperty (js_context, js_object, js_name, NULL);
+  JSStringRelease (js_name);
+
+  num = (guint)JSValueToNumber (js_context, value, NULL);
+  for (count = 0; count &lt; num; count++) {
+    value = JSObjectGetPropertyAtIndex (js_context, js_object, count, NULL);
+
+    if (!JSValueIsObject (js_context, value))
+      continue;
+
+    retval = g_slist_prepend (retval, (gpointer)value);
+  }
+
+  return retval;
+}
+
+typedef struct {
+  JSContextRef contxext;
+  JSObjectRef object;
+} FillData;
+
+static void
+find_username_and_password_elements (JSContextRef js_context,
+                                     GSList *elements,
+                                     JSObjectRef *name_element,
+                                     JSObjectRef *password_element,
+                                     gboolean auto_fill,
+                                     EphyWebView *view)
+{
+  GSList *iter = elements;
+  GSList *l = NULL;
+  SoupURI *uri = NULL;
+
+    g_debug (&quot;URI: %s&quot;, webkit_web_view_get_uri (WEBKIT_WEB_VIEW (view)));
+  if (auto_fill) {
+    uri = soup_uri_new (webkit_web_view_get_uri (WEBKIT_WEB_VIEW (view)));
+    if (uri-&gt;host)
+      l = g_hash_table_lookup (view-&gt;priv-&gt;form_auth_data, uri-&gt;host);
+  }
+
+  for (; iter; iter = iter-&gt;next) {
+    JSObjectRef object;
+    char *type;
+
+    object = JSValueToObject (js_context, (JSValueRef)iter-&gt;data, NULL);
+
+    type = js_get_element_attribute (js_context, object, &quot;type&quot;);
+    if (!type)
+      continue;
+
+    if (g_str_equal (type, &quot;text&quot;)) {
+      /* We found more than one inputs of type text; we won't be
+       * saving here */
+      if (*name_element) {
+        *name_element = NULL;
+        break;
+      }
+
+      *name_element = object;
+    } else if (g_str_equal (type, &quot;password&quot;)) {
+      if (*password_element) {
+        *password_element = NULL;
+        break;
+      }
+
+      *password_element = object;
+    }
+
+    if (auto_fill) {
+      GSList *p;
+
+      for (p = l; p; p = p-&gt;next) {
+        FormAuthData *data = (FormAuthData*)p-&gt;data;
+        if (!g_strcmp0 (js_get_element_attribute (js_context, object, &quot;name&quot;), data-&gt;form_username) ||
+            !g_strcmp0 (js_get_element_attribute (js_context, object, &quot;name&quot;), data-&gt;form_password)) {
+          char *key_str;
+          GList *results = NULL;
+          JSValueRef prop_value;
+          JSStringRef prop_value_str, prop_name;
+          SoupURI *key = soup_uri_copy (uri);
+          soup_uri_set_query_from_fields (key,
+                                          &quot;form_username&quot;,
+                                          data-&gt;form_username,
+                                          &quot;form_password&quot;,
+                                          data-&gt;form_password,
+                                          NULL);
+          key_str = soup_uri_to_string (key, FALSE);
+
+#if 0
+          data = g_slice_new (FillData);
+          data-&gt;context = js_context;
+          data-&gt;object = object;
+#endif
+
+          g_debug (&quot;QUERY %s&quot;, key_str);
+          gnome_keyring_find_network_password_sync (NULL,
+                                                    NULL,
+                                                    key_str,
+                                                    NULL,
+                                                    NULL,
+                                                    NULL,
+                                                    0,
+                                                    &amp;results);
+
+          if (!results) {
+            g_debug (&quot;NO RESULTS&quot;);
+            return;
+          }
+
+          prop_name = JSStringCreateWithUTF8CString (&quot;value&quot;);
+          g_debug (&quot;USER %s PASS %s&quot;, ((GnomeKeyringNetworkPasswordData*)results-&gt;data)-&gt;user, ((GnomeKeyringNetworkPasswordData*)results-&gt;data)-&gt;password);
+
+          if (!g_strcmp0 (js_get_element_attribute (js_context, object, &quot;name&quot;), data-&gt;form_username)) {
+            prop_value_str = JSStringCreateWithUTF8CString (((GnomeKeyringNetworkPasswordData*)results-&gt;data)-&gt;user);
+          } else {
+            prop_value_str = JSStringCreateWithUTF8CString (((GnomeKeyringNetworkPasswordData*)results-&gt;data)-&gt;password);
+          }
+
+          prop_value = JSValueMakeString (js_context, prop_value_str);
+          JSObjectSetProperty (js_context, object, prop_name, prop_value, 0, NULL);
+          g_free (key_str);
+          soup_uri_free (key);
+        }
+      }
+    }
+
+    g_free (type);
+  }
+
+  if (auto_fill)
+    soup_uri_free (uri);
+}
+
+static JSValueRef
+do_form_submitted_cb (JSContextRef js_context,
+                      JSObjectRef js_function,
+                      JSObjectRef js_this,
+                      size_t argument_count,
+                      const JSValueRef js_arguments[],
+                      JSValueRef* js_exception)
+{
+  GSList *elements = js_get_form_elements (js_context, js_this);
+  JSObjectRef name_element = NULL;
+  JSObjectRef password_element = NULL;
+  JSStringRef js_string;
+  JSValueRef js_value;
+  char *name_field_name;
+  char *name_field_value;
+  char *password_field_name;
+  char *password_field_value;
+
+  find_username_and_password_elements (js_context, elements, &amp;name_element, &amp;password_element, FALSE, NULL);
+  g_slist_free (elements);
+
+  if (!name_element || !password_element)
+    return JSValueMakeUndefined (js_context);
+
+  name_field_name = js_get_element_attribute (js_context, name_element, &quot;name&quot;);
+  password_field_name = js_get_element_attribute (js_context, password_element, &quot;name&quot;);
+
+  js_string = JSStringCreateWithUTF8CString (&quot;value&quot;);
+  js_value = JSObjectGetProperty (js_context, name_element, js_string, NULL);
+
+  name_field_value = js_value_to_string (js_context, js_value);
+
+  js_value = JSObjectGetProperty (js_context, password_element, js_string, NULL);
+  JSStringRelease (js_string);
+
+  password_field_value = js_value_to_string (js_context, js_value);
+
+  {
+    SoupURI *fake_uri;
+    char *fake_uri_str;
+    guint32 item_id;
+
+    /* FIXME: replace with call to function Xan is finishing */
+    g_debug (&quot;%s / %s | %s / %s&quot;, name_field_name, name_field_value, password_field_name, password_field_value);
+
+    fake_uri = soup_uri_new (&quot;http://twitter.com/&quot;);
+    /* Store the form login and password names encoded in the
+     * URL. A bit of an abuse of keyring, but oh well */
+    soup_uri_set_query_from_fields (fake_uri,
+                                    &quot;form_username&quot;,
+                                    name_field_name,
+                                    &quot;form_password&quot;,
+                                    password_field_name,
+                                    NULL);
+    fake_uri_str = soup_uri_to_string (fake_uri, FALSE);
+    gnome_keyring_set_network_password_sync (NULL,
+                                             name_field_value,
+                                             NULL,
+                                             fake_uri_str,
+                                             NULL,
+                                             fake_uri-&gt;scheme,
+                                             NULL,
+                                             fake_uri-&gt;port,
+                                             password_field_value,
+                                             &amp;item_id);
+    soup_uri_free (fake_uri);
+    g_free (fake_uri_str);
+  }
+
+  g_free (name_field_name);
+  g_free (name_field_value);
+  g_free (password_field_name);
+  g_free (password_field_value);
+
+  return JSValueMakeUndefined (js_context);
+}
+
+static void
+hook_form (JSContextRef js_context, JSValueRef js_form, JSObjectRef form_submitted_cb)
+{
+  JSObjectRef object = JSValueToObject (js_context, js_form, NULL);
+  JSObjectRef add_event_listener = js_object_get_property_as_object (js_context, object, &quot;addEventListener&quot;);
+  JSStringRef event_name;
+  JSValueRef args[3], val;
+  JSValueRef js_exception;
+
+  event_name = JSStringCreateWithUTF8CString (&quot;submit&quot;);
+  args[0] = JSValueMakeString (js_context, event_name);
+  JSStringRelease (event_name);
+
+  args[1] = form_submitted_cb;
+  args[2] = JSValueMakeBoolean (js_context, TRUE);
+  val = JSObjectCallAsFunction (js_context, add_event_listener, object, 3, args, &amp;js_exception);
+}
+
+static void
+do_hook_into_forms (JSContextRef js_context, JSObjectRef form_submitted_cb, EphyWebView *web_view)
+{
+  GSList *forms;
+
+  for (forms = js_get_all_forms (js_context); forms; forms = forms-&gt;next) {
+    JSValueRef form = (JSValueRef)forms-&gt;data;
+    GSList *elements = js_get_form_elements (js_context, form);
+    JSObjectRef name_element = NULL;
+    JSObjectRef password_element = NULL;
+
+    find_username_and_password_elements (js_context, elements, &amp;name_element, &amp;password_element, TRUE, web_view);
+
+    g_slist_free (elements);
+
+    /* We have a field that may be the user, and one for a password. */
+    if (name_element &amp;&amp; password_element)
+      hook_form (js_context, form, form_submitted_cb);
+  }
+
+  g_slist_free (forms);
+}
+
+static void
+_ephy_web_view_hook_into_forms (EphyWebView *web_view)
+{
+  WebKitWebFrame *web_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view));
+  JSGlobalContextRef js_context;
+  JSObjectRef js_global;
+  JSStringRef js_function_name;
+  JSObjectRef js_function_object;
+
+  js_context = webkit_web_frame_get_global_context (web_frame);
+  js_global = JSContextGetGlobalObject (js_context);
+
+  js_function_name = JSStringCreateWithUTF8CString (&quot;_EpiphanyInternalFormSubmitted&quot;);
+  js_function_object = JSObjectMakeFunctionWithCallback (js_context,
+                                                         js_function_name,
+                                                         (JSObjectCallAsFunctionCallback)do_form_submitted_cb);
+  JSObjectSetProperty (js_context, js_global, js_function_name, js_function_object, 0, NULL);
+  JSStringRelease (js_function_name);
+
+  do_hook_into_forms (js_context, js_function_object, EPHY_WEB_VIEW (web_view));
+}
+
+static void
+form_auth_data_free (FormAuthData *data)
+{
+  g_free (data-&gt;form_username);
+  g_free (data-&gt;form_password);
+
+  g_slice_free (FormAuthData, data);
+}
+
+static void
+free_form_auth_data_list (gpointer data)
+{
+  GSList *p, *l = (GSList*)data;
+
+  for (p = l; p; p = p-&gt;next)
+    form_auth_data_free ((FormAuthData*)p-&gt;data);
+
+  g_slist_free (l);
+}
+
+static void
+remove_form_auth_data (gpointer key, gpointer value, gpointer user_data)
+{
+  if (value)
+    free_form_auth_data_list ((GSList*)value);
+}
+
 static void
 ephy_web_view_finalize (GObject *object)
 {
@@ -518,6 +921,13 @@ ephy_web_view_finalize (GObject *object)
     priv-&gt;non_search_regex = NULL;
   }
 
+  if (priv-&gt;form_auth_data) {
+    g_hash_table_foreach (priv-&gt;form_auth_data,
+                          (GHFunc)remove_form_auth_data,
+                          NULL);
+    g_hash_table_destroy (priv-&gt;form_auth_data);
+  }
+
   ephy_web_view_popups_manager_reset (EPHY_WEB_VIEW (object));
 
   g_free (priv-&gt;address);
@@ -1058,6 +1468,115 @@ mime_type_policy_decision_requested_cb (WebKitWebView *web_view,
 }
 
 static void
+load_status_cb (WebKitWebView *web_view,
+                GParamSpec *pspec,
+                gpointer user_data)
+{
+  WebKitLoadStatus status = webkit_web_view_get_load_status (web_view);
+
+  if (status == WEBKIT_LOAD_FINISHED) {
+    if (!eel_gconf_get_boolean (CONF_PRIVACY_REMEMBER_PASSWORDS))
+      return;
+
+    _ephy_web_view_hook_into_forms (EPHY_WEB_VIEW (web_view));
+  }
+}
+
+static FormAuthData*
+form_auth_data_new (const char *form_username,
+                    const char *form_password)
+{
+  FormAuthData *data;
+
+  data = g_slice_new (FormAuthData);
+  data-&gt;form_username = g_strdup (form_username);
+  data-&gt;form_password = g_strdup (form_password);
+
+  return data;
+}
+
+static void
+get_attr_cb (GnomeKeyringResult result,
+             GnomeKeyringAttributeList *attributes,
+             EphyWebView *view)
+{
+  int i = 0;
+  GnomeKeyringAttribute *attribute;
+  EphyWebViewPrivate *priv = view-&gt;priv;
+  char *server = NULL;
+
+  if (result != GNOME_KEYRING_RESULT_OK)
+    return;
+
+  attribute = (GnomeKeyringAttribute*)attributes-&gt;data;
+  for (i = 0; i &lt; attributes-&gt;len; i++) {
+    if (attribute[i].type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING) {
+      if (g_str_equal (attribute[i].name, &quot;server&quot;)) {
+        server = g_strdup (attribute[i].value.string);
+        break;
+      }
+    }
+  }
+
+  if (server &amp;&amp;
+      g_strstr_len (server, -1, &quot;form%5Fusername&quot;) &amp;&amp;
+      g_strstr_len (server, -1, &quot;form%5Fpassword&quot;)) {
+    /* This is a stored login/password from a form, cache the form
+     * names locally so we don't need to hit the keyring daemon all
+     * the time */
+    const char *form_username, *form_password;
+    GHashTable *t;
+    GSList *l;
+    FormAuthData *form_data;
+    SoupURI *uri = soup_uri_new (server);
+    t = soup_form_decode (uri-&gt;query);
+    form_username = g_hash_table_lookup (t, &quot;form_username&quot;);
+    form_password = g_hash_table_lookup (t, &quot;form_password&quot;);
+
+    form_data = form_auth_data_new (form_username, form_password);
+    l = g_hash_table_lookup (priv-&gt;form_auth_data,
+                             uri-&gt;host);
+    g_debug (&quot;APPENDING %s = %s:%s&quot;, uri-&gt;host, form_data-&gt;form_username, form_data-&gt;form_password);
+    l = g_slist_append (l, form_data);
+    g_hash_table_replace (priv-&gt;form_auth_data,
+                          g_strdup (uri-&gt;host),
+                          l);
+
+    soup_uri_free (uri);
+    g_hash_table_destroy (t);
+  }
+
+  g_free (server);
+}
+
+static void
+store_form_data_cb (GnomeKeyringResult result, GList *l, EphyWebView *view)
+{
+  GList *p;
+
+  if (result != GNOME_KEYRING_RESULT_OK)
+    return;
+
+  for (p = l; p; p = p-&gt;next) {
+    guint key_id = GPOINTER_TO_UINT (p-&gt;data);
+    gnome_keyring_item_get_attributes (GNOME_KEYRING_DEFAULT,
+                                       key_id,
+                                       (GnomeKeyringOperationGetAttributesCallback) get_attr_cb,
+                                       view,
+                                       NULL);
+  }
+}
+
+static void
+cache_keyring_form_data (EphyWebView *view)
+{
+  gnome_keyring_list_item_ids (GNOME_KEYRING_DEFAULT,
+                               (GnomeKeyringOperationGetListCallback)store_form_data_cb,
+                               view,
+                               NULL);
+}
+                
+static void
 ephy_web_view_init (EphyWebView *web_view)
 {
   EphyWebViewPrivate *priv;
@@ -1088,6 +1607,16 @@ ephy_web_view_init (EphyWebView *web_view)
                     G_CALLBACK (mime_type_policy_decision_requested_cb),
                     NULL);
 
+  g_signal_connect (web_view, &quot;notify::load-status&quot;,
+                    G_CALLBACK (load_status_cb),
+                    NULL);
+
+  priv-&gt;form_auth_data = g_hash_table_new_full (g_str_hash,
+                                                g_str_equal,
+                                                g_free,
+                                                NULL);
+  cache_keyring_form_data (web_view);
+
   g_signal_connect_object (web_view, &quot;icon-loaded&quot;,
                            G_CALLBACK (favicon_cb),
                            web_view, (GConnectFlags)0);
@@ -2462,3 +2991,5 @@ ephy_web_view_save (EphyWebView *view, const char *uri)
 
   ephy_web_view_save_sub_resources (view, uri, subresources);
 }
+
+
diff --git a/embed/ephy-web-view.h b/embed/ephy-web-view.h
index 5ed358b..31a41ae 100644
--- a/embed/ephy-web-view.h
+++ b/embed/ephy-web-view.h
@@ -221,6 +221,8 @@ void                       ephy_web_view_popups_manager_reset    (EphyWebView
 void                       ephy_web_view_save                    (EphyWebView                     *view,
                                                                   const char                      *uri);
 
+void                       ephy_web_view_hook_into_forms         (EphyWebView                     *web_view);
+
 G_END_DECLS
 
 #endif
diff --git a/src/ephy-profile-migration.c b/src/ephy-profile-migration.c
index c0c319d..ee558d1 100644
--- a/src/ephy-profile-migration.c
+++ b/src/ephy-profile-migration.c
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
 /*
  *  Copyright &#xC2;&#xA9; 2009 Xan L&#xC3;&#xB3;pez
  *
@@ -47,7 +48,7 @@
  *  - Add your function at the end of the 'migrators' array
  */
 
-#define PROFILE_MIGRATION_VERSION 3
+#define PROFILE_MIGRATION_VERSION 4
 
 typedef void (*EphyProfileMigrator) (void);
 
@@ -147,7 +148,8 @@ decrypt (const char *data)
 }
 
 static void
-parse_and_decrypt_signons (const char *signons)
+parse_and_decrypt_signons (const char *signons,
+                           gboolean handle_forms)
 {
   int version;
   gchar **lines;
@@ -248,16 +250,26 @@ parse_and_decrypt_signons (const char *signons)
     while (begin + 4 &lt; end) {
       char *username = NULL;
       char *password = NULL;
+      char *form_username = NULL;
+      char *form_password = NULL;
       guint32 item_id;
 
       /* The username */
-      begin++; /* Skip username element */
+      if (handle_forms) {
+        form_username = g_strdup (lines[begin++]);
+      } else {
+        begin++; /* Skip username element */
+      }
       username = decrypt (lines[begin++]);
       
       /* The password */
       /* The element name has a leading '*' */
       if (lines[begin][0] == '*') {
-        begin++; /* Skip password element */
+        if (handle_forms) {
+          form_password = g_strdup (lines[begin++]);
+        } else {
+          begin++; /* Skip password element */
+        }
         password = decrypt (lines[begin++]);
       } else {
         /* Maybe the file is broken, skip to the next block */
@@ -278,7 +290,35 @@ parse_and_decrypt_signons (const char *signons)
           begin++;
       }
 
-      if (username &amp;&amp; password)
+      if (handle_forms &amp;&amp; username &amp;&amp; password &amp;&amp; 
+          !g_str_equal (form_username, &quot;&quot;) &amp;&amp;
+          !g_str_equal (form_password, &quot;*&quot;)) {
+        SoupURI *fake_uri;
+        char *fake_uri_str;
+        
+        fake_uri = soup_uri_copy (uri);
+        /* Store the form login and password names encoded in the
+         * URL. A bit of an abuse of keyring, but oh well */
+        soup_uri_set_query_from_fields (fake_uri,
+                                        FORM_USERNAME_KEY,
+                                        form_username,
+                                        FORM_PASSWORD_KEY,
+                                        form_password,
+                                        NULL);
+        fake_uri_str = soup_uri_to_string (fake_uri, FALSE);
+        gnome_keyring_set_network_password_sync (NULL,
+                                                 username,
+                                                 realm,
+                                                 fake_uri_str,
+                                                 NULL,
+                                                 fake_uri-&gt;scheme,
+                                                 NULL,
+                                                 fake_uri-&gt;port,
+                                                 password,
+                                                 &amp;item_id);
+        soup_uri_free (fake_uri);
+        g_free (fake_uri_str);
+      } else if (!handle_forms &amp;&amp; username &amp;&amp; password) {
         gnome_keyring_set_network_password_sync (NULL,
                                                  username,
                                                  realm,
@@ -289,8 +329,12 @@ parse_and_decrypt_signons (const char *signons)
                                                  uri-&gt;port, 
                                                  password,
                                                  &amp;item_id);
+      }
+
       g_free (username);
       g_free (password);
+      g_free (form_username);
+      g_free (form_password);
     }
 
     soup_uri_free (uri);
@@ -331,7 +375,7 @@ migrate_passwords ()
     g_free (dest);
   }
 
-  parse_and_decrypt_signons (contents);
+  parse_and_decrypt_signons (contents, FALSE);
 
   /* Save the contents in a backup directory for future data
      extraction when we support more features */
@@ -350,12 +394,45 @@ migrate_passwords ()
 #endif
 }
 
+static void
+migrate_passwords2 ()
+{
+#ifdef ENABLE_NSS
+  char *dest, *contents;
+  gsize length;
+  GError *error = NULL;
+
+  dest = g_build_filename (ephy_dot_dir (),
+                           &quot;gecko-passwords.txt&quot;,
+                           NULL);
+  if (!g_file_test (dest, G_FILE_TEST_EXISTS)) {
+    g_free (dest);
+    return;
+  }
+
+  if (!ephy_nss_glue_init ())
+    return;
+
+  if (!g_file_get_contents (dest, &amp;contents, &amp;length, &amp;error)) {
+    g_free (dest);
+  }
+
+  parse_and_decrypt_signons (contents, TRUE);
+  g_free (contents);
+
+  ephy_nss_glue_close ();
+#endif
+}
+
 const EphyProfileMigrator migrators[] = {
   migrate_cookies,
   migrate_passwords,
  /* Yes, again! Version 2 had some bugs, so we need to run
     migrate_passwords again to possibly migrate more passwords*/
-  migrate_passwords
+  migrate_passwords,
+  /* Very similar to migrate_passwords, but this migrates
+   * login/passwords for page forms, which we previously ignored */
+  migrate_passwords2
 };
 
 #define PROFILE_MIGRATION_FILE &quot;.migrated&quot;
diff --git a/src/ephy-profile-migration.h b/src/ephy-profile-migration.h
index 51114a8..21b6bd2 100644
--- a/src/ephy-profile-migration.h
+++ b/src/ephy-profile-migration.h
@@ -20,6 +20,9 @@
 #ifndef EPHY_PROFILE_MIGRATION_H
 #define EPHY_PROFILE_MIGRATION_H
 
+#define FORM_USERNAME_KEY &quot;form_username&quot;
+#define FORM_PASSWORD_KEY &quot;form_password&quot;
+
 void _ephy_profile_migrate (void);
 
 #endif
</string>
    </contents>
    <universal-time>
      <integer>3469808732</integer>
    </universal-time>
    <channel>
      <string>#webkit-gtk</string>
    </channel>
    <colorization-mode>
      <string>WebKit (text or diff)</string>
    </colorization-mode>
    <maybe-spam>
      <null/>
    </maybe-spam>
    <is-unicode>
      <keyword>TRUE</keyword>
    </is-unicode>
    <deletion-requested>
      <null/>
    </deletion-requested>
    <deletion-requested-email>
      <null/>
    </deletion-requested-email>
    <expiration-time>
      <null/>
    </expiration-time>
  </paste>
</paste-with-annotations>
