327 lines
11 KiB
C
327 lines
11 KiB
C
/*
|
|
Copyright (C) 2010 Christian Dywan <christian@twotoasts.de>
|
|
Copyright (C) 2010 Alexander Butenko <a.butenka@gmail.com>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
See the file COPYING for the full license text.
|
|
*/
|
|
|
|
#include "midori-bookmarks.h"
|
|
#include "panels/midori-bookmarks.h"
|
|
#include "midori-app.h"
|
|
#include "midori-array.h"
|
|
#include "sokoke.h"
|
|
#include "midori-core.h"
|
|
|
|
#include <glib/gstdio.h>
|
|
#include <glib/gi18n.h>
|
|
|
|
#include <config.h>
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
void
|
|
midori_bookmarks_dbtracer (void* dummy,
|
|
const char* query)
|
|
{
|
|
g_printerr ("%s\n", query);
|
|
}
|
|
|
|
void
|
|
midori_bookmarks_add_item_cb (KatzeArray* array,
|
|
KatzeItem* item,
|
|
sqlite3* db)
|
|
{
|
|
midori_bookmarks_insert_item_db (db, item,
|
|
katze_item_get_meta_integer (item, "parentid"));
|
|
}
|
|
|
|
void
|
|
midori_bookmarks_remove_item_cb (KatzeArray* array,
|
|
KatzeItem* item,
|
|
sqlite3* db)
|
|
{
|
|
gchar* sqlcmd;
|
|
char* errmsg = NULL;
|
|
|
|
|
|
sqlcmd = sqlite3_mprintf (
|
|
"DELETE FROM bookmarks WHERE id = %" G_GINT64_FORMAT ";",
|
|
katze_item_get_meta_integer (item, "id"));
|
|
|
|
if (sqlite3_exec (db, sqlcmd, NULL, NULL, &errmsg) != SQLITE_OK)
|
|
{
|
|
g_printerr (_("Failed to remove history item: %s\n"), errmsg);
|
|
sqlite3_free (errmsg);
|
|
}
|
|
|
|
sqlite3_free (sqlcmd);
|
|
}
|
|
|
|
#define _APPEND_TO_SQL_ERRORMSG(custom_errmsg) \
|
|
do { \
|
|
if (sql_errmsg) \
|
|
{ \
|
|
g_string_append_printf (errmsg_str, "%s : %s\n", custom_errmsg, sql_errmsg); \
|
|
sqlite3_free (sql_errmsg); \
|
|
} \
|
|
else \
|
|
g_string_append (errmsg_str, custom_errmsg); \
|
|
} while (0)
|
|
|
|
gboolean
|
|
midori_bookmarks_import_from_old_db (sqlite3* db,
|
|
const gchar* oldfile,
|
|
gchar** errmsg)
|
|
{
|
|
gint sql_errcode;
|
|
gboolean failure = FALSE;
|
|
gchar* sql_errmsg = NULL;
|
|
GString* errmsg_str = g_string_new (NULL);
|
|
gchar* attach_stmt = sqlite3_mprintf ("ATTACH DATABASE %Q AS old_db;", oldfile);
|
|
const gchar* convert_stmts =
|
|
"BEGIN TRANSACTION;"
|
|
"INSERT INTO main.bookmarks (parentid, title, uri, desc, app, toolbar) "
|
|
"SELECT NULL AS parentid, title, uri, desc, app, toolbar "
|
|
"FROM old_db.bookmarks;"
|
|
"UPDATE main.bookmarks SET parentid = ("
|
|
"SELECT id FROM main.bookmarks AS b1 WHERE b1.title = ("
|
|
"SELECT folder FROM old_db.bookmarks WHERE title = main.bookmarks.title));"
|
|
"COMMIT;";
|
|
const gchar* detach_stmt = "DETACH DATABASE old_db;";
|
|
|
|
*errmsg = NULL;
|
|
sql_errcode = sqlite3_exec (db, attach_stmt, NULL, NULL, &sql_errmsg);
|
|
sqlite3_free (attach_stmt);
|
|
|
|
if (sql_errcode != SQLITE_OK)
|
|
{
|
|
_APPEND_TO_SQL_ERRORMSG (_("failed to ATTACH old db"));
|
|
goto convert_failed;
|
|
}
|
|
|
|
if (sqlite3_exec (db, convert_stmts, NULL, NULL, &sql_errmsg) != SQLITE_OK)
|
|
{
|
|
failure = TRUE;
|
|
_APPEND_TO_SQL_ERRORMSG (_("failed to import from old db"));
|
|
|
|
/* try to get back to previous state */
|
|
if (sqlite3_exec (db, "ROLLBACK TRANSACTION;", NULL, NULL, &sql_errmsg) != SQLITE_OK)
|
|
_APPEND_TO_SQL_ERRORMSG (_("failed to rollback the transaction"));
|
|
}
|
|
|
|
if (sqlite3_exec (db, detach_stmt, NULL, NULL, &sql_errmsg) != SQLITE_OK)
|
|
_APPEND_TO_SQL_ERRORMSG (_("failed to DETACH "));
|
|
|
|
if (failure)
|
|
{
|
|
convert_failed:
|
|
*errmsg = g_string_free (errmsg_str, FALSE);
|
|
g_print ("ERRORR: %s\n", errmsg_str->str);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
#undef _APPEND_TO_SQL_ERRORMSG
|
|
|
|
KatzeArray*
|
|
midori_bookmarks_new (char** errmsg)
|
|
{
|
|
sqlite3* db;
|
|
gchar* oldfile;
|
|
gchar* newfile;
|
|
gboolean newfile_did_exist, oldfile_exists;
|
|
const gchar* create_stmt;
|
|
gchar* sql_errmsg = NULL;
|
|
gchar* import_errmsg = NULL;
|
|
KatzeArray* array;
|
|
|
|
g_return_val_if_fail (errmsg != NULL, NULL);
|
|
|
|
oldfile = midori_paths_get_config_filename_for_writing ("bookmarks.db");
|
|
oldfile_exists = g_access (oldfile, F_OK) == 0;
|
|
newfile = midori_paths_get_config_filename_for_writing ("bookmarks_v2.db");
|
|
newfile_did_exist = g_access (newfile, F_OK) == 0;
|
|
|
|
/* sqlite3_open will create the file if it did not exists already */
|
|
if (sqlite3_open (newfile, &db) != SQLITE_OK)
|
|
{
|
|
*errmsg = g_strdup_printf (_("Failed to open database: %s\n"),
|
|
db ? sqlite3_errmsg (db) : "(db = NULL)");
|
|
goto init_failed;
|
|
}
|
|
|
|
if (midori_debug ("bookmarks"))
|
|
sqlite3_trace (db, midori_bookmarks_dbtracer, NULL);
|
|
|
|
create_stmt = /* Table structure */
|
|
"CREATE TABLE IF NOT EXISTS bookmarks "
|
|
"(id INTEGER PRIMARY KEY AUTOINCREMENT, "
|
|
"parentid INTEGER DEFAULT NULL, "
|
|
"title TEXT, uri TEXT, desc TEXT, app INTEGER, toolbar INTEGER, "
|
|
"pos_panel INTEGER, pos_bar INTEGER, "
|
|
"created DATE DEFAULT CURRENT_TIMESTAMP, "
|
|
"last_visit DATE, visit_count INTEGER DEFAULT 0, "
|
|
"nick TEXT, "
|
|
"FOREIGN KEY(parentid) REFERENCES bookmarks(id) "
|
|
"ON DELETE CASCADE); PRAGMA foreign_keys = ON;"
|
|
|
|
/* trigger: insert panel position */
|
|
"CREATE TRIGGER IF NOT EXISTS bookmarkInsertPosPanel "
|
|
"AFTER INSERT ON bookmarks FOR EACH ROW "
|
|
"BEGIN UPDATE bookmarks SET pos_panel = ("
|
|
"SELECT ifnull(MAX(pos_panel),0)+1 FROM bookmarks WHERE "
|
|
"(NEW.parentid IS NOT NULL AND parentid = NEW.parentid) "
|
|
"OR (NEW.parentid IS NULL AND parentid IS NULL)) "
|
|
"WHERE id = NEW.id; END;"
|
|
|
|
/* trigger: insert Bookmarkbar position */
|
|
"CREATE TRIGGER IF NOT EXISTS bookmarkInsertPosBar "
|
|
"AFTER INSERT ON bookmarks FOR EACH ROW WHEN NEW.toolbar=1 "
|
|
"BEGIN UPDATE bookmarks SET pos_bar = ("
|
|
"SELECT ifnull(MAX(pos_bar),0)+1 FROM bookmarks WHERE "
|
|
"((NEW.parentid IS NOT NULL AND parentid = NEW.parentid) "
|
|
"OR (NEW.parentid IS NULL AND parentid IS NULL)) AND toolbar=1) "
|
|
"WHERE id = NEW.id; END;"
|
|
|
|
/* trigger: update panel position */
|
|
"CREATE TRIGGER IF NOT EXISTS bookmarkUpdatePosPanel "
|
|
"BEFORE UPDATE OF parentid ON bookmarks FOR EACH ROW "
|
|
"WHEN ((NEW.parentid IS NULL OR OLD.parentid IS NULL) "
|
|
"AND NEW.parentid IS NOT OLD.parentid) OR "
|
|
"((NEW.parentid IS NOT NULL AND OLD.parentid IS NOT NULL) "
|
|
"AND NEW.parentid!=OLD.parentid) "
|
|
"BEGIN UPDATE bookmarks SET pos_panel = pos_panel-1 "
|
|
"WHERE ((OLD.parentid IS NOT NULL AND parentid = OLD.parentid) "
|
|
"OR (OLD.parentid IS NULL AND parentid IS NULL)) AND pos_panel > OLD.pos_panel; "
|
|
"UPDATE bookmarks SET pos_panel = ("
|
|
"SELECT ifnull(MAX(pos_panel),0)+1 FROM bookmarks "
|
|
"WHERE (NEW.parentid IS NOT NULL AND parentid = NEW.parentid) "
|
|
"OR (NEW.parentid IS NULL AND parentid IS NULL)) "
|
|
"WHERE id = OLD.id; END;"
|
|
|
|
/* trigger: update Bookmarkbar position */
|
|
"CREATE TRIGGER IF NOT EXISTS bookmarkUpdatePosBar0 "
|
|
"AFTER UPDATE OF parentid, toolbar ON bookmarks FOR EACH ROW "
|
|
"WHEN ((NEW.parentid IS NULL OR OLD.parentid IS NULL) "
|
|
"AND NEW.parentid IS NOT OLD.parentid) "
|
|
"OR ((NEW.parentid IS NOT NULL AND OLD.parentid IS NOT NULL) "
|
|
"AND NEW.parentid!=OLD.parentid) OR (OLD.toolbar=1 AND NEW.toolbar=0) "
|
|
"BEGIN UPDATE bookmarks SET pos_bar = NULL WHERE id = NEW.id; "
|
|
"UPDATE bookmarks SET pos_bar = pos_bar-1 "
|
|
"WHERE ((OLD.parentid IS NOT NULL AND parentid = OLD.parentid) "
|
|
"OR (OLD.parentid IS NULL AND parentid IS NULL)) AND pos_bar > OLD.pos_bar; END;"
|
|
|
|
/* trigger: update Bookmarkbar position */
|
|
"CREATE TRIGGER IF NOT EXISTS bookmarkUpdatePosBar1 "
|
|
"BEFORE UPDATE OF parentid, toolbar ON bookmarks FOR EACH ROW "
|
|
"WHEN ((NEW.parentid IS NULL OR OLD.parentid IS NULL) "
|
|
"AND NEW.parentid IS NOT OLD.parentid) OR "
|
|
"((NEW.parentid IS NOT NULL AND OLD.parentid IS NOT NULL) "
|
|
"AND NEW.parentid!=OLD.parentid) OR (OLD.toolbar=0 AND NEW.toolbar=1) "
|
|
"BEGIN UPDATE bookmarks SET pos_bar = ("
|
|
"SELECT ifnull(MAX(pos_bar),0)+1 FROM bookmarks WHERE "
|
|
"(NEW.parentid IS NOT NULL AND parentid = NEW.parentid) "
|
|
"OR (NEW.parentid IS NULL AND parentid IS NULL)) "
|
|
"WHERE id = OLD.id; END;"
|
|
|
|
/* trigger: delete panel position */
|
|
"CREATE TRIGGER IF NOT EXISTS bookmarkDeletePosPanel "
|
|
"AFTER DELETE ON bookmarks FOR EACH ROW "
|
|
"BEGIN UPDATE bookmarks SET pos_panel = pos_panel-1 "
|
|
"WHERE ((OLD.parentid IS NOT NULL AND parentid = OLD.parentid) "
|
|
"OR (OLD.parentid IS NULL AND parentid IS NULL)) AND pos_panel > OLD.pos_panel; END;"
|
|
|
|
/* trigger: delete Bookmarkbar position */
|
|
"CREATE TRIGGER IF NOT EXISTS bookmarkDeletePosBar "
|
|
"AFTER DELETE ON bookmarks FOR EACH ROW WHEN OLD.toolbar=1 "
|
|
"BEGIN UPDATE bookmarks SET pos_bar = pos_bar-1 "
|
|
"WHERE ((OLD.parentid IS NOT NULL AND parentid = OLD.parentid) "
|
|
"OR (OLD.parentid IS NULL AND parentid IS NULL)) AND pos_bar > OLD.pos_bar; END;";
|
|
|
|
|
|
if (newfile_did_exist)
|
|
{
|
|
/* we are done */
|
|
goto init_success;
|
|
}
|
|
else
|
|
{
|
|
/* initial creation */
|
|
if (sqlite3_exec (db, create_stmt, NULL, NULL, &sql_errmsg) != SQLITE_OK)
|
|
{
|
|
*errmsg = g_strdup_printf (_("Couldn't create bookmarks table: %s\n"),
|
|
sql_errmsg ? sql_errmsg : "(err = NULL)");
|
|
sqlite3_free (sql_errmsg);
|
|
|
|
/* we can as well remove the new file */
|
|
g_unlink (newfile);
|
|
goto init_failed;
|
|
}
|
|
|
|
}
|
|
|
|
if (oldfile_exists)
|
|
/* import from old db */
|
|
if (!midori_bookmarks_import_from_old_db (db, oldfile, &import_errmsg))
|
|
{
|
|
*errmsg = g_strdup_printf (_("Couldn't import from old database: %s\n"),
|
|
import_errmsg ? import_errmsg : "(err = NULL)");
|
|
g_free (import_errmsg);
|
|
}
|
|
|
|
init_success:
|
|
g_free (newfile);
|
|
g_free (oldfile);
|
|
array = katze_array_new (KATZE_TYPE_ARRAY);
|
|
g_signal_connect (array, "add-item",
|
|
G_CALLBACK (midori_bookmarks_add_item_cb), db);
|
|
g_signal_connect (array, "remove-item",
|
|
G_CALLBACK (midori_bookmarks_remove_item_cb), db);
|
|
g_object_set_data (G_OBJECT (array), "db", db);
|
|
return array;
|
|
|
|
init_failed:
|
|
g_free (newfile);
|
|
g_free (oldfile);
|
|
|
|
if (db)
|
|
sqlite3_close (db);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
midori_bookmarks_import (const gchar* filename,
|
|
sqlite3* db)
|
|
{
|
|
KatzeArray* bookmarks;
|
|
GError* error = NULL;
|
|
|
|
bookmarks = katze_array_new (KATZE_TYPE_ARRAY);
|
|
|
|
if (!midori_array_from_file (bookmarks, filename, "xbel", &error))
|
|
{
|
|
g_warning (_("The bookmarks couldn't be saved. %s"), error->message);
|
|
g_error_free (error);
|
|
return;
|
|
}
|
|
midori_bookmarks_import_array_db (db, bookmarks, 0);
|
|
}
|
|
|
|
void
|
|
midori_bookmarks_on_quit (KatzeArray* array)
|
|
{
|
|
g_return_if_fail (KATZE_IS_ARRAY (array));
|
|
|
|
sqlite3* db = g_object_get_data (G_OBJECT (array), "db");
|
|
g_return_if_fail (db != NULL);
|
|
sqlite3_close (db);
|
|
}
|
|
|