Logo Search packages:      
Sourcecode: galeon version File versions

bookmarks-netscape-mozilla.c

/* 
 *  Copyright (C) 2002 Ricardo Fernández Pascual
 *
 *  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.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

/* This file is based on the original netscape.c file of galeon 1.x
 *
 * Netscape bookmark importing by Nate Case <nd@kracked.com>
 * Netscape bookmark exporting by Ricardo Fernández Pascual <ric@users.sourceforge.net>
 */

#include "bookmarks-netscape-mozilla.h"
#include "gul-string.h"
#include "gul-general.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glib/gi18n.h>

/* local data types */

/**
 * NSItemType: netscape bookmark item type
 */
typedef enum
{
      NS_SITE,
      NS_NOTES,
      NS_FOLDER,
      NS_FOLDER_END,
      NS_SEPARATOR,
      NS_ALIAS,
      NS_UNKNOWN
} NSItemType;


/* local function prototypes */
static NSItemType       ns_get_bookmark_item          (FILE *f, GString *name, GString *url,
                                                 GString *nick, GString* alias_id,
                                                 GTime *added, GTime *visited);
static GTime                  ns_get_bookmark_date          (const char *line, const char *search);
static char *                 ns_parse_bookmark_item        (GString *string);

static void             netscape_export_bookmarks_item      (FILE *file, GbBookmark *b, 
                                                 gboolean use_locale);
static gchar *                ns_locale_to_utf8       (const gchar *locstr);  
static gchar *                ns_utf8_to_locale       (const gchar *locstr);


/**
 * Reads a file and returns the bookmarks in it
 */
GbBookmarkSet *
netscape_import_bookmarks (const gchar *filename, gboolean use_locale)
{
      GbBookmark *newbm = NULL;
      GbFolder *parent;
      GbBookmarkSet *ret;
      FILE *bf;  /* bookmark file */
      GString *name = g_string_new (NULL);
      gchar *parsedname;
      GString *url = g_string_new (NULL);
      GString *nick = g_string_new (NULL);
      GString *alias_id = g_string_new (NULL);
      GTime added, visited;
      gchar *str;
      gchar * (*to_utf8) (const gchar *) = 
            use_locale ? ns_locale_to_utf8 : g_strdup;
      
      if (!(bf = fopen (filename, "r"))) {
            g_warning ("Failed to open file: %s\n", filename);
            return NULL;
      }     
      
      ret = gb_bookmark_set_new ();
      parent = gb_folder_new (ret, _("Mozilla bookmarks"));
      gb_bookmark_set_set_root (ret, parent);

      while (!feof (bf)) {
            NSItemType t;
            added = visited = 0;
            t = ns_get_bookmark_item (bf, name, url, nick, alias_id, &added, &visited );
            switch (t)
            {
            case NS_FOLDER: 
                  str = to_utf8 (name->str);
                  newbm = (GbBookmark *) gb_folder_new (ret, str);
                  g_free (str);
                  if (!strcmp (name->str, _("Personal Toolbar Folder")))
                  {
                        gb_folder_set_create_toolbar (GB_FOLDER (newbm), TRUE);
                  }
                  gb_folder_add_child (parent, newbm, -1);
                  gb_bookmark_set_time_added (newbm, added);
                  parent = (GbFolder *) newbm;
                  break;
            case NS_SITE:
                  parsedname = ns_parse_bookmark_item (name);
                  str = to_utf8 (parsedname);
                  g_free (parsedname);
                  if (strstr (url->str, "%s"))
                  {
                        /* Smart bookmark - bug 136069 */
                        newbm = (GbBookmark*) gb_smart_site_new (ret, str, NULL, url->str);
                  }
                  else
                  {
                        newbm = (GbBookmark*) gb_site_new (ret, str, url->str);
                  }
                  g_free (str);

                  if (alias_id->str && strlen( alias_id->str ))
                  {
                        str = g_strconcat ("NSAlias", alias_id->str, NULL);
                        gb_bookmark_set_id (newbm, str);
                        g_free (str);
                  }

                  if (nick->str) 
                  {
                        str = to_utf8 (nick->str);
                        gb_bookmark_set_nick (newbm, str);
                        g_free (str);
                  }
                  gb_folder_add_child (parent, newbm, -1);
                  gb_bookmark_set_time_added (newbm, added);
                  gb_site_set_time_visited ((GbSite *) newbm, visited);
                  break;
            case NS_ALIAS:
                  str = g_strconcat ("NSAlias", alias_id->str, NULL);
                  newbm = (GbBookmark*) gb_alias_placeholder_new (ret, str);
                  g_free (str);
                  gb_folder_add_child (parent, newbm, -1);

            case NS_NOTES:
                  if (newbm && !GB_IS_ALIAS_PLACEHOLDER (newbm))
                  {
                        gchar *notes;
                        str = to_utf8 (name->str);
                        notes = g_strconcat (newbm->notes, str, NULL);
                        gb_bookmark_set_notes (newbm, notes);
                        g_free (notes);
                        g_free (str);
                  }
                  break;
            case NS_SEPARATOR:
                  newbm = (GbBookmark *) gb_separator_new (ret);
                  gb_folder_add_child (parent, newbm, -1);
                  newbm = NULL;
                  break;
            case NS_FOLDER_END:
                  newbm = NULL;
                  if (GB_BOOKMARK (parent)->parent != NULL)
                  {
                        parent = GB_BOOKMARK (parent)->parent;
                  }
                  break;
            default:
                  newbm = NULL;
                  break;
            }           
      }
      fclose (bf);
      g_string_free (name, TRUE);
      g_string_free (url, TRUE);
      g_string_free (nick, TRUE);
      g_string_free (alias_id, TRUE);

      gb_bookmark_set_resolve_aliases (ret);
      
      return ret;
}

static GTime
ns_get_bookmark_date (const char *line, const char *search)
{
      const char *found = gul_string_ascii_strcasestr (line, search);
      if (!found)
      {
            return 0;
      }
      else
      {
            return atoi (found + strlen (search) + 1);
      }
}

/** 
 * 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, GString *nick,
                  GString* alias_id, GTime *added, GTime *visited)
{
      char *line = NULL;
      char *found;

      line = gul_general_read_line_from_file (f);

      if ((found = (char *) gul_string_ascii_strcasestr (line, "<A HREF="))) 
      {  /* declare site? */
            g_string_assign (url, found+9);  /* url=URL+ ADD_DATE ... */
            g_string_truncate (url, strstr(url->str, "\"")-url->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, 
                                           "</A>")-name->str);
            if ((found = (char *) gul_string_ascii_strcasestr (line, 
                                          "SHORTCUTURL=")))
            {
                  g_string_assign (nick, found+13);
                  g_string_truncate (nick, strstr(nick->str, "\"")
                                 - nick->str);
            } 
            else
            {
                  g_string_assign (nick, "");
            }
            *added = ns_get_bookmark_date (line, "ADD_DATE=");
            *visited = ns_get_bookmark_date (line, "LAST_VISIT=");

            g_string_assign (alias_id, "");
            if ((found = (char *) gul_string_ascii_strcasestr (line, "ALIASID=")) ||
                (found = (char *) gul_string_ascii_strcasestr (line, "ALIASOF=")))
            {
                  g_string_assign (alias_id, found+9);
                  g_string_truncate (alias_id, strstr(alias_id->str, "\"")
                                 - alias_id->str);
                  if (found[5] == 'O' || found[5] == 'o')
                  {
                        g_free (line);
                        return NS_ALIAS;
                  }
            }
            g_free (line);
            return NS_SITE;
      } 
      else if ((found = (char *) gul_string_ascii_strcasestr (line, "<DT><H3"))) 
      { /* declare folder? */
            found = (char *) strstr(found+7, ">");
            if (!found) return NS_UNKNOWN;
            g_string_assign (name, found+1);
            g_string_truncate (name, gul_string_ascii_strcasestr (name->str,
                           "</H3>") - name->str);
            *added = ns_get_bookmark_date (line, "ADD_DATE=");
            g_free (line);
            return NS_FOLDER;       
      } 
      else if ((found = (char *) gul_string_ascii_strcasestr (line, "</DL>"))) 
      {     /* end folder? */
            g_free (line);
            return NS_FOLDER_END;
      }
      else if ((found = (char *) gul_string_ascii_strcasestr (line, "<HR>"))) 
      {    /* separator */
            g_free (line);
            return NS_SEPARATOR;
      }

      /* Now look for comments - remove any trailing <br> - bug 125904*/
      if ((found = (char *) gul_string_ascii_strcasestr (line, "<BR>\n")))
      {
            found[0] = '\n';
            found[1] = '\0';
      }

      if ((found = (char *) gul_string_ascii_strcasestr (line, "<DD>"))) 
      {    /* comments */
            g_string_assign (name, found+4);
            g_free (line);
            return NS_NOTES;
      }
      else if (strchr(line, '<')==NULL && strchr(line, '>')==NULL)
      {    /* continued comments (probably) */
            g_string_assign (name, line);
            g_free (line);
            return NS_NOTES;
      }
      g_free (line);
      return NS_UNKNOWN;
}

/**
 * This function replaces some weird elements
 * like &amp; &le;, 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 <almer1@dds.nl>
 */
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, "&amp;", 5) == 0) {
                  
                        g_string_append_c (result, '&');
                        jump = 5;
                  } else if (g_ascii_strncasecmp (iterator, "&lt;", 4) == 0) {
                  
                        g_string_append_c (result, '<');
                        jump = 4;
                  } else if (g_ascii_strncasecmp (iterator, "&gt;", 4) == 0) {

                        g_string_append_c (result, '>');
                        jump = 4;
                  } else if (g_ascii_strncasecmp (iterator, "&quot;", 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;
}

/**
 * Exports bookmarks to netscape or mozilla
 * Will overwrite the file!
 */
gboolean
netscape_export_bookmarks (const gchar *filename, GbBookmarkSet *set, 
                     gboolean use_locale)
{
      FILE *file;
      GbBookmark *it;

      g_return_val_if_fail (filename != NULL, FALSE);

      if (!(file = fopen (filename, "w"))) 
      {
            g_warning (_("Could not open file: %s"), filename);
            return FALSE;
      }

      /* write the headers */
      fputs ("<!DOCTYPE NETSCAPE-Bookmark-file-1>\n", file);
      fputs ("<!-- This file was automatically generated by Galeon\n", file);
      fputs ("It will be read and overwritten.\n", file);
      fputs ("Do Not Edit! -->\n", file);
      if (!use_locale)
      {
            fputs ("<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html;"
                   " charset=UTF-8\">\n", file);
      }
      fputs ("<TITLE>Bookmarks</TITLE>\n", file);
      fputs ("<H1>Bookmarks</H1>\n", file);
      fputs ("\n", file);
      fputs ("<DL><p>\n", file);

      /* write the bookmarks */
      for (it = set->root->child; it; it = it->next) 
      {
            netscape_export_bookmarks_item (file, it, use_locale);
      }
      
      /* finish */
      fputs ("</DL><p>\n", file);

      fclose (file);    
      return TRUE;
}

static void 
netscape_export_bookmarks_item (FILE *file, GbBookmark *b, gboolean use_locale)
{
      gchar *str, *str1;
      gchar * (*from_utf8) (const gchar *) = 
            use_locale ? ns_utf8_to_locale : g_strdup;
      

      if (GB_IS_SITE (b))
      {
            fputs ("\t<DT><A HREF=\"", file);
            str = gul_string_strdup_replace (GB_SITE (b)->url, "\"", "&quot;");
            fputs (str, file);
            g_free (str);
            fputs ("\"", file);
            if (b->time_added > 0)
            {
                  fprintf (file, " ADD_DATE=\"%d\"", b->time_added);
            }
            if (b->time_modified > 0) 
            {
                  fprintf (file, " LAST_MODIFIED=\"%d\"", b->time_modified);
            }
            if (GB_SITE (b)->time_visited > 0)
            {
                  fprintf (file, " LAST_VISIT=\"%d\"", GB_SITE (b)->time_visited);
            }
            /* support a mozilla-only feature, but won't harm netscape */
            if (strlen (b->nick) > 0) {
                  fputs (" SHORTCUTURL=\"", file);
                  str = from_utf8 (b->nick);
                  fputs (str, file);
                  g_free (str);
                  fputs ("\"", file);
            }
            fputs (">", file);
            str1 = g_markup_escape_text (b->name, -1);
            str = from_utf8 (str1);
            fputs (str, file);
            g_free (str);
            g_free (str1);
            fputs ("</A>\n", file);
            if (strlen (b->notes) > 0) {
                  fputs ("<DD>", file);
                  str = from_utf8 (b->notes);
                  fputs (str, file);
                  g_free (str);
                  fputs ("\n", file);
            }
      } 
      else if (GB_IS_FOLDER (b))
      {
            fputs ("<DT><H3 ADD_DATE=\"0\">", file); 
            str1 = g_markup_escape_text (b->name, -1);
            str = from_utf8 (str1);
            fputs (str, file);
            g_free (str);
            g_free (str1);
            fputs ("</H3>\n", file);
            if (strlen (b->notes) > 0) {
                  fputs ("<DD>", file);
                  str = from_utf8 (b->notes);
                  fputs (str, file);
                  g_free (str);
                  fputs ("\n", file);
            }
            fputs ("<DL><p>\n", file);
            /* FIXME: Alias catogories are not exported */
            if (!b->alias_of)
            {
                  GbBookmark *it;
                  for (it = GB_FOLDER (b)->child; it != NULL; it = it->next) 
                  {
                        netscape_export_bookmarks_item (file, it, use_locale);
                  }
            }
            else
            {
                  g_warning ("Detected a bookmark item type that I can't export!");
            }
            fputs ("</DL><p>\n", file);
      }
      else if (GB_IS_SEPARATOR (b))
      {
            fputs ("<HR>\n", file);
      }
      else
      {
            g_warning ("Detected a bookmark item type that I can't export!");
      }
}

static gchar *
ns_locale_to_utf8 (const gchar *locstr)
{
      gchar *ret = g_locale_to_utf8 (locstr, -1, NULL, NULL, NULL);
      return ret ? ret : g_strdup ("");
}

static gchar *
ns_utf8_to_locale (const gchar *locstr)
{
      gchar *ret = g_locale_from_utf8 (locstr, -1, NULL, NULL, NULL);
      return ret ? ret : g_strdup ("");
}




Generated by  Doxygen 1.6.0   Back to index