]> spindle.queued.net Git - midori/commitdiff
Support importing bookmarks from Opera 6 bookmark files
authorChristian Dywan <christian@twotoasts.de>
Sun, 15 Nov 2009 20:45:29 +0000 (21:45 +0100)
committerChristian Dywan <christian@twotoasts.de>
Mon, 16 Nov 2009 16:45:09 +0000 (17:45 +0100)
midori/midori-array.c
midori/midori-browser.c

index 7004bea1f5298f12c1df0e260a38dd788967adac..e1f4003eea15ae4dbea658d8e8d7f7b153a3dc9e 100644 (file)
@@ -15,6 +15,7 @@
     #include <config.h>
 #endif
 
+#include <glib/gstdio.h>
 #include <glib/gi18n.h>
 
 #if HAVE_LIBXML
@@ -217,15 +218,96 @@ katze_array_from_xmlDocPtr (KatzeArray* array,
     return TRUE;
 }
 
+static gboolean
+katze_array_from_opera_file (KatzeArray* array,
+                             FILE*       file)
+{
+    gchar line[200];
+    KatzeArray* folder = array;
+    KatzeItem* item = NULL;
+
+    while (fgets (line, 200, file))
+    {
+        g_strstrip (line);
+        if (line[0] == '\0')
+        {
+            item = NULL;
+            continue;
+        }
+        else if (line[0] == '-')
+        {
+            item = NULL;
+            if (folder != array)
+                folder = katze_item_get_parent ((KatzeItem*)folder);
+            else
+                g_warning ("A level-up although we are at the top level");
+            continue;
+        }
+
+        if (line[0] == '#')
+        {
+            const gchar* element = &line[1];
+            if (!g_ascii_strncasecmp (element, "FOLDER", 6))
+            {
+                item = (KatzeItem*)katze_array_new (KATZE_TYPE_ARRAY);
+                katze_array_add_item (folder, item);
+                folder = (KatzeArray*)item;
+            }
+            else if (!g_ascii_strncasecmp (element, "URL", 3))
+            {
+                item = katze_item_new ();
+                katze_array_add_item (folder, item);
+            }
+            else
+                g_warning ("Unexpected element: %s", element);
+        }
+        else if (item)
+        {
+            gchar** parts = g_strsplit (line, "=", 2);
+            if (parts && parts[0] && parts[1])
+            {
+                if (g_str_equal (parts[0], "NAME"))
+                    katze_item_set_name (item, parts[1]);
+                else if (g_str_equal (parts[0], "URL"))
+                    katze_item_set_uri (item, parts[1]);
+                else if (g_str_equal (parts[0], "DESCRIPTION"))
+                    katze_item_set_text (item, parts[1]);
+                else if (g_str_equal (parts[0], "CREATED"))
+                    katze_item_set_added (item,
+                        g_ascii_strtoull (parts[1], NULL, 10));
+                /* FIXME: Implement visited time
+                else if (g_str_equal (parts[0], "VISITED"))
+                    katze_item_set_visited (item,
+                        g_ascii_strtoull (parts[1], NULL, 10)); */
+                /* FIXME: Implement bookmarkbar flag
+                else if (g_str_equal (parts[0], "ON PERSONALBAR"))
+                    ; */
+                /* FIXME: Implement websites as panels
+                else if (g_str_equal (parts[0], "IN PANEL"))
+                    ; */
+            }
+            else
+                g_warning ("Broken property: %s", line);
+            g_strfreev (parts);
+        }
+        else
+            g_warning ("Unexpected property outside of element: %s", line);
+    }
+    return TRUE;
+}
+
 /**
  * midori_array_from_file:
  * @array: a #KatzeArray
  * @filename: a filename to load from
- * @format: the desired format
+ * @format: "xbel", "opera", or %NULL
  * @error: a #GError or %NULL
  *
  * Loads the contents of a file in the specified format.
  *
+ * Since 0.2.2 @format can be %NULL to indicate that the
+ *   file should be loaded if it's any supported format.
+ *
  * Return value: %TRUE on success, %FALSE otherwise
  *
  * Since: 0.1.6
@@ -236,11 +318,8 @@ midori_array_from_file (KatzeArray*  array,
                         const gchar* format,
                         GError**     error)
 {
-    xmlDocPtr doc;
-
     g_return_val_if_fail (katze_array_is_a (array, KATZE_TYPE_ITEM), FALSE);
     g_return_val_if_fail (filename != NULL, FALSE);
-    g_return_val_if_fail (!g_strcmp0 (format, "xbel"), FALSE);
     g_return_val_if_fail (!error || !*error, FALSE);
 
     if (!g_file_test (filename, G_FILE_TEST_EXISTS))
@@ -252,26 +331,77 @@ midori_array_from_file (KatzeArray*  array,
         return FALSE;
     }
 
-    if ((doc = xmlParseFile (filename)) == NULL)
+    /* Opera6 */
+    if (!g_strcmp0 (format, "opera")
+    || (!format && g_str_has_suffix (filename, ".adr")))
     {
-        /* No valid xml or broken encoding */
-        if (error)
-            *error = g_error_new_literal (G_FILE_ERROR, G_FILE_ERROR_FAILED,
-                                          _("Malformed document."));
-        return FALSE;
+        FILE* file;
+        if ((file = g_fopen (filename, "r")))
+        {
+            guint verify;
+            gchar line[50];
+
+            verify = 0;
+            while (fgets (line, 50, file))
+            {
+                g_strstrip (line);
+                if (verify == 0 && !strcmp (line, "Opera Hotlist version 2.0"))
+                    verify++;
+                else if (verify == 1
+                     && !strcmp (line, "Options: encoding = utf8, version=3"))
+                    verify++;
+                else if (verify == 2)
+                {
+                    if (!katze_array_from_opera_file (array, file))
+                    {
+                        /* Parsing failed */
+                        fclose (file);
+                        if (error)
+                            *error = g_error_new_literal (G_FILE_ERROR,
+                                G_FILE_ERROR_FAILED, _("Malformed document."));
+                        return FALSE;
+                    }
+                    return TRUE;
+                }
+                else
+                    break;
+            }
+            fclose (file);
+        }
     }
 
-    if (!katze_array_from_xmlDocPtr (array, doc))
+    /* XBEL */
+    if (!g_strcmp0 (format, "xbel")
+     || !format)
     {
-        /* Parsing failed */
+        xmlDocPtr doc;
+
+        if ((doc = xmlParseFile (filename)) == NULL)
+        {
+            /* No valid xml or broken encoding */
+            if (error)
+                *error = g_error_new_literal (G_FILE_ERROR, G_FILE_ERROR_FAILED,
+                                              _("Malformed document."));
+            return FALSE;
+        }
+
+        if (!katze_array_from_xmlDocPtr (array, doc))
+        {
+            /* Parsing failed */
+            xmlFreeDoc (doc);
+            if (error)
+                *error = g_error_new_literal (G_FILE_ERROR, G_FILE_ERROR_FAILED,
+                                              _("Malformed document."));
+            return FALSE;
+        }
         xmlFreeDoc (doc);
-        if (error)
-            *error = g_error_new_literal (G_FILE_ERROR, G_FILE_ERROR_FAILED,
-                                          _("Malformed document."));
-        return FALSE;
+        return TRUE;
     }
-    xmlFreeDoc (doc);
-    return TRUE;
+
+    if (error)
+        *error = g_error_new_literal (G_FILE_ERROR, G_FILE_ERROR_FAILED,
+                                      _("Unrecognized bookmark format."));
+    return FALSE;
 }
 #endif
 
index 593f6eafb9215db65931711cea658d17fd6a8a64..c7a84f482d39978af9dac56d259eeaa5f26262bc 100644 (file)
@@ -4031,6 +4031,7 @@ _action_bookmarks_import_activate (GtkAction*     action,
     } BookmarkClient;
     static const BookmarkClient bookmark_clients[] = {
         { ".local/share/data/Arora/bookmarks.xbel", N_("Arora") },
+        { ".opera/bookmarks.adr", N_("Opera") },
     };
 
     GtkWidget* dialog;
@@ -4039,6 +4040,7 @@ _action_bookmarks_import_activate (GtkAction*     action,
     GtkWidget* label;
     GtkWidget* combo;
     GtkComboBox* combobox;
+    GtkComboBox* combobox_folder;
     guint i;
     KatzeItem* item;
 
@@ -4082,16 +4084,17 @@ _action_bookmarks_import_activate (GtkAction*     action,
     gtk_size_group_add_widget (sizegroup, label);
     gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
     combo = gtk_combo_box_new_text ();
-    combobox = GTK_COMBO_BOX (combo);
-    gtk_combo_box_append_text (combobox, _("Toplevel folder"));
-    gtk_combo_box_set_active (combobox, 0);
+    combobox_folder = GTK_COMBO_BOX (combo);
+    gtk_combo_box_append_text (combobox_folder, _("Toplevel folder"));
+    gtk_combo_box_set_active (combobox_folder, 0);
     i = 0;
     while ((item = katze_array_get_nth_item (browser->bookmarks, i++)))
     {
         if (KATZE_IS_ARRAY (item))
         {
             const gchar* name = katze_item_get_name (item);
-            gtk_combo_box_append_text (combobox, name);
+            if (name)
+                gtk_combo_box_append_text (combobox_folder, name);
         }
     }
     gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
@@ -4111,7 +4114,7 @@ _action_bookmarks_import_activate (GtkAction*     action,
         i = gtk_combo_box_get_active (combobox);
         path = g_build_filename (g_get_home_dir (), bookmark_clients[i].path, NULL);
 
-        selected = gtk_combo_box_get_active_text (combobox);
+        selected = gtk_combo_box_get_active_text (combobox_folder);
         folder = browser->bookmarks;
         if (g_strcmp0 (selected, _("Toplevel folder")))
         {
@@ -4127,7 +4130,7 @@ _action_bookmarks_import_activate (GtkAction*     action,
         g_free (selected);
 
         error = NULL;
-        if (!midori_array_from_file (folder, path, "xbel", &error))
+        if (!midori_array_from_file (folder, path, NULL, &error))
         {
             GtkWidget* error_dialog = gtk_message_dialog_new (
                 GTK_WINDOW (browser), GTK_DIALOG_DESTROY_WITH_PARENT,