/* * Copyright (C) 2003 Marco Pesenti Gritti * * This program 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 2, or (at your option) * any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include "ephy-bookmarks-import.h" #include "ephy-debug.h" /** * NSItemType: netscape bookmark item type */ typedef enum { NS_SITE, NS_NOTES, NS_FOLDER, NS_FOLDER_END, NS_SEPARATOR, NS_UNKNOWN } NSItemType; typedef struct _XbelInfo { char *title; char *smarturl; } XbelInfo; static EphyNode * bookmark_add (EphyBookmarks *bookmarks, const char *title, const char *address, const char *topic_name) { EphyNode *topic; EphyNode *bmk; if (ephy_bookmarks_find_bookmark (bookmarks, address)) return NULL; bmk = ephy_bookmarks_add (bookmarks, title, address); if (topic_name) { topic = ephy_bookmarks_find_keyword (bookmarks, topic_name, FALSE); if (topic == NULL) { topic = ephy_bookmarks_add_keyword (bookmarks, topic_name); } ephy_bookmarks_set_keyword (bookmarks, topic, bmk); } return bmk; } gboolean ephy_bookmarks_import (EphyBookmarks *bookmarks, const char *filename) { char *type; type = gnome_vfs_get_mime_type (filename); LOG ("Importing bookmarks of type %s", type) if (type == NULL) return FALSE; if (strcmp (type, "application/x-mozilla-bookmarks") == 0) { return ephy_bookmarks_import_mozilla (bookmarks, filename); } else if (strcmp (type, "application/xbel") == 0) { return ephy_bookmarks_import_xbel (bookmarks, filename); } else if (strstr (filename, MOZILLA_BOOKMARKS_DIR) != NULL) { return ephy_bookmarks_import_mozilla (bookmarks, filename); } else if (strstr (filename, GALEON_BOOKMARKS_DIR) != NULL || strstr (filename, KDE_BOOKMARKS_DIR) != NULL) { return ephy_bookmarks_import_xbel (bookmarks, filename); } return FALSE; } static void xbel_parse_single_bookmark (EphyBookmarks *bookmarks, xmlNodePtr node, XbelInfo *xbel) { xmlNodePtr child = node; while (child != NULL) { if (xmlStrEqual (child->name, "title")) { xbel->title = xmlNodeGetContent (child); } else if (xmlStrEqual (child->name, "info")) { xbel_parse_single_bookmark (bookmarks, child->children, xbel); } else if (xmlStrEqual (child->name, "metadata")) { xbel_parse_single_bookmark (bookmarks, child->children, xbel); } else if (xmlStrEqual (child->name, "smarturl")) { xbel->smarturl = xmlNodeGetContent (child); } child = child->next; } } static void xbel_parse_folder (EphyBookmarks *bookmarks, xmlNodePtr node) { xmlNodePtr child = node; xmlChar *keyword = NULL; while (child != NULL) { if (xmlStrEqual (child->name, "title")) { keyword = xmlNodeGetContent (child); } else if (xmlStrEqual (child->name, "bookmark")) { XbelInfo *xbel; xmlChar *url; xbel = g_new0 (XbelInfo, 1); xbel->title = NULL; xbel->smarturl = NULL; url = xmlGetProp (child, "href"); xbel_parse_single_bookmark (bookmarks, child->children, xbel); bookmark_add (bookmarks, xbel->title, url, keyword); xmlFree (url); if (xbel && xbel->title) xmlFree (xbel->title); if (xbel && xbel->smarturl) xmlFree (xbel->smarturl); g_free (xbel); } else if (xmlStrEqual (child->name, "folder")) { xbel_parse_folder (bookmarks, child->children); g_free (keyword); keyword = NULL; } child = child->next; } g_free (keyword); } static void xbel_parse_bookmarks (EphyBookmarks *bookmarks, xmlNodePtr node) { xmlNodePtr child = node; while (child != NULL) { if (xmlStrEqual (child->name, "xbel")) { xbel_parse_folder (bookmarks, child->children); } child = child->next; } } static gchar * gul_general_read_line_from_file (FILE *f) { gchar *line = g_strdup (""); gchar *t; gchar *buf = g_new0 (gchar, 256); while ( ! ( strchr (buf, '\n') || feof (f) ) ) { fgets(buf, 256, f); t = line; line = g_strconcat (line, buf, NULL); g_free (t); } g_free (buf); return line; } static const gchar * gul_string_ascii_strcasestr (const gchar *a, const gchar *b) { gchar *down_a; gchar *down_b; gchar *ptr; /* copy and lower case the strings */ down_a = g_strdup (a); down_b = g_strdup (b); g_ascii_strdown (down_a, -1); g_ascii_strdown (down_b, -1); /* compare */ ptr = strstr (down_a, down_b); /* free allocated strings */ g_free (down_a); g_free (down_b); /* return result of comparison */ return ptr == NULL ? NULL : (a + (ptr - down_a)); } /** * Parses a line of a mozilla/netscape bookmark file. File must be open. */ /* this has been tested fairly well */ static NSItemType ns_get_bookmark_item (FILE *f, GString *name, GString *url) { char *line = NULL; char *found; line = gul_general_read_line_from_file (f); if ((found = (char *) gul_string_ascii_strcasestr (line, "str); found = (char *) strstr (found+9+url->len, "\">"); if (!found) { g_free (line); return NS_UNKNOWN; } g_string_assign (name, found+2); g_string_truncate (name, gul_string_ascii_strcasestr (name->str, "")-name->str); g_free (line); return NS_SITE; } else if ((found = (char *) gul_string_ascii_strcasestr (line, "
"); if (!found) return NS_UNKNOWN; g_string_assign (name, found+1); g_string_truncate (name, gul_string_ascii_strcasestr (name->str, "") - name->str); g_free (line); return NS_FOLDER; } else if ((found = (char *) gul_string_ascii_strcasestr (line, ""))) { /* end folder? */ g_free (line); return NS_FOLDER_END; } g_free (line); return NS_UNKNOWN; } /** * This function replaces some weird elements * like & ≤, etc.. * More info : http://www.w3.org/TR/html4/charset.html#h-5.3.2 * NOTE : We don't support &#D or &#xH. * Patch courtesy of Almer S. Tigelaar */ static char * ns_parse_bookmark_item (GString *string) { char *iterator, *temp; int cnt = 0; GString *result = g_string_new (NULL); g_return_val_if_fail (string != NULL, NULL); g_return_val_if_fail (string->str != NULL, NULL); iterator = string->str; for (cnt = 0, iterator = string->str; cnt <= (int)(strlen (string->str)); cnt++, iterator++) { if (*iterator == '&') { int jump = 0; int i; if (g_ascii_strncasecmp (iterator, "&", 5) == 0) { g_string_append_c (result, '&'); jump = 5; } else if (g_ascii_strncasecmp (iterator, "<", 4) == 0) { g_string_append_c (result, '<'); jump = 4; } else if (g_ascii_strncasecmp (iterator, ">", 4) == 0) { g_string_append_c (result, '>'); jump = 4; } else if (g_ascii_strncasecmp (iterator, """, 6) == 0) { g_string_append_c (result, '\"'); jump = 6; } else { /* It must be some numeric thing now */ iterator++; if (iterator && *iterator == '#') { int val; char *num, *tmp; iterator++; val = atoi (iterator); tmp = g_strdup_printf ("%d", val); jump = strlen (tmp); g_free (tmp); num = g_strdup_printf ("%c", (char) val); g_string_append (result, num); g_free (num); } } for (i = jump - 1; i > 0; i--) { iterator++; if (iterator == NULL) break; } } else { g_string_append_c (result, *iterator); } } temp = result->str; g_string_free (result, FALSE); return temp; } gboolean ephy_bookmarks_import_mozilla (EphyBookmarks *bookmarks, const char *filename) { FILE *bf; /* bookmark file */ GString *name = g_string_new (NULL); gchar *parsedname; GString *url = g_string_new (NULL); char *current_folder = NULL; if (!(bf = fopen (filename, "r"))) { g_warning ("Failed to open file: %s\n", filename); return FALSE; } while (!feof (bf)) { NSItemType t; t = ns_get_bookmark_item (bf, name, url); switch (t) { case NS_FOLDER: g_free (current_folder); current_folder = g_strdup (name->str); break; case NS_SITE: parsedname = ns_parse_bookmark_item (name); bookmark_add (bookmarks, parsedname, url->str, current_folder); break; default: break; } } fclose (bf); g_string_free (name, TRUE); g_string_free (url, TRUE); return TRUE; } gboolean ephy_bookmarks_import_xbel (EphyBookmarks *bookmarks, const char *filename) { xmlDocPtr doc; xmlNodePtr child; if (g_file_test (filename, G_FILE_TEST_EXISTS) == FALSE) return FALSE; doc = xmlParseFile (filename); g_assert (doc != NULL); child = doc->children; xbel_parse_bookmarks (bookmarks, child); xmlFreeDoc (doc); return TRUE; } #define OLD_RDF_TEMPORARY_HACK static void parse_rdf_subjects (xmlNodePtr node, GList **subjects) { xmlChar *subject; #ifdef OLD_RDF_TEMPORARY_HACK xmlNode *child; child = node->children; while (child != NULL) { if (xmlStrEqual (child->name, "Bag")) { child = child->children; while (child != NULL) { if (xmlStrEqual (child->name, "li")) { subject = xmlNodeGetContent (child); *subjects = g_list_append (*subjects, subject); } child = child->next; } return; } child = child->next; } #endif subject = xmlNodeGetContent (node); if (subject) { *subjects = g_list_append (*subjects, subject); } } static void parse_rdf_item (EphyBookmarks *bookmarks, xmlNodePtr node) { xmlChar *title = NULL; xmlChar *link = NULL; GList *subjects = NULL, *l = NULL; xmlNode *child; EphyNode *bmk; child = node->children; #ifdef OLD_RDF_TEMPORARY_HACK link = xmlGetProp (node, "about"); #endif while (child != NULL) { if (xmlStrEqual (child->name, "title")) { title = xmlNodeGetContent (child); } #ifndef OLD_RDF_TEMPORARY_HACK else if (xmlStrEqual (child->name, "link")) { link = xmlNodeGetContent (child); } #endif else if (xmlStrEqual (child->name, "subject")) { parse_rdf_subjects (child, &subjects); } else if (xmlStrEqual (child->name, "smartlink")) { if (link) xmlFree (link); link = xmlNodeGetContent (child); } child = child->next; } bmk = bookmark_add (bookmarks, title, link, NULL); if (bmk) { l = subjects; } for (; l != NULL; l = l->next) { char *topic_name = l->data; EphyNode *topic; topic = ephy_bookmarks_find_keyword (bookmarks, topic_name, FALSE); if (topic == NULL) { topic = ephy_bookmarks_add_keyword (bookmarks, topic_name); } ephy_bookmarks_set_keyword (bookmarks, topic, bmk); } xmlFree (title); xmlFree (link); g_list_foreach (subjects, (GFunc)xmlFree, NULL); g_list_free (subjects); } gboolean ephy_bookmarks_import_rdf (EphyBookmarks *bookmarks, const char *filename) { xmlDocPtr doc; xmlNodePtr child; xmlNodePtr root; if (g_file_test (filename, G_FILE_TEST_EXISTS) == FALSE) return FALSE; doc = xmlParseFile (filename); g_assert (doc != NULL); root = xmlDocGetRootElement (doc); child = root->children; while (child != NULL) { if (xmlStrEqual (child->name, "item")) { parse_rdf_item (bookmarks, child); } child = child->next; } xmlFreeDoc (doc); return TRUE; }