commit: a7ba36264f3a62013d393075bd992ac252d3e51a
parent abb47b4c0faf2eadcdce62c285fea8af7edd8894
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Sun, 3 Nov 2019 21:34:46 +0100
Add support for XBEL Bookmarks
Diffstat:
6 files changed, 100 insertions(+), 30 deletions(-)
diff --git a/KnowledgeBase.md b/KnowledgeBase.md
@@ -2,3 +2,20 @@
- WebKit2 Extensions Tutorial: https://blogs.igalia.com/carlosgc/2013/09/10/webkit2gtk-web-process-extensions/
- https://trac.torproject.org/projects/tor/wiki/doc/ImportantGoogleChromeBugs / https://trac.torproject.org/projects/tor/ticket/1925
- https://webkit.org/blog/3476/content-blockers-first-look/
+
+# Bookmark formats
+The different plain-text formats used by web browsers found in the wild, done
+in Augmented Backus–Naur Form (ABNF).
+
+url = *CHAR
+title = *CHAR
+
+## uzbl
+bookmark = URL TAB title [TAB tags]
+tags = *(*CHAR SP)
+
+Documenter comment: How does it manages when the separator (TAB here) is
+present in the title?
+
+## qutebrowser
+bookmark = URL SP title
diff --git a/Makefile b/Makefile
@@ -24,7 +24,7 @@ INKSCAPE ?= inkscape
# for i in 24 32 48 64 128 256; do echo icons/hicolor/${i}x${i}/apps/badwolf.png; done | tr '\n' ' '
ICON_SIZES = icons/hicolor/24x24/apps/badwolf.png icons/hicolor/32x32/apps/badwolf.png icons/hicolor/48x48/apps/badwolf.png icons/hicolor/64x64/apps/badwolf.png icons/hicolor/128x128/apps/badwolf.png icons/hicolor/256x256/apps/badwolf.png
-DEPS = gtk+-3.0 webkit2gtk-4.0 libsoup-2.4
+DEPS = gtk+-3.0 webkit2gtk-4.0 libsoup-2.4 libxml-2.0
SRCS = bookmarks.c uri.c uri_test.c keybindings.c downloads.c badwolf.c
OBJS = bookmarks.o uri.o keybindings.o downloads.o badwolf.o
OBJS_test = uri_test.o
diff --git a/README.md b/README.md
@@ -55,6 +55,7 @@ Dependencies are:
- C11 Compiler (such as clang or gcc)
- [WebKitGTK](https://webkitgtk.org/), only the latest stable is supported
+- [libxml-2.0](http://www.xmlsoft.org/), no known version limitation
- POSIX make with extension for shell in variables (works with GNU, {Net,Free,Open}BSD)
- A pkg-config implementation (pkgconf is recommended)
- (optionnal) gettext implementation (such as GNU Gettext)
diff --git a/badwolf.1 b/badwolf.1
@@ -75,8 +75,14 @@ A more generic variable name is also intended to be used in the future.
.El
.Sh FILES
.Bl -tag -width Ds -compact
-.It Pa ${XDG_DATA_HOME:-$HOME/.local/share}/badwolf/URLs.txt
-File containing a URL on each line. [UNSTABLE]
+.It Pa ${XDG_DATA_HOME:-$HOME/.local/share}/badwolf/bookmarks.xbel
+XBEL (XML Bookmark Exchange Language) file, known to be currently supported by:
+.Xr elinks 1 ,
+.Xr konqueror 1 ,
+.Xr kbookmarkeditor 1 . Doing a symbolic link from their path works fine.
+.Pp
+For more information about this format see:
+.Lk http://pyxml.sourceforge.net/topics/xbel/
.It Pa ${XDG_DATA_HOME:-$HOME/.local/share}/badwolf/webkit-web-extensions/
Directory containing the
.Lk https://webkitgtk.org/reference/webkit2gtk/stable/WebKitWebExtension.html WebKitWebExtensions
diff --git a/badwolf.c b/badwolf.c
@@ -7,6 +7,7 @@
#include "config.h"
#include "downloads.h"
#include "bookmarks.h"
+#include "config.h"
#include "keybindings.h"
#include "uri.h"
diff --git a/bookmarks.c b/bookmarks.c
@@ -1,45 +1,90 @@
-#include "badwolf.h"
#include "bookmarks.h"
-#include <gtk/gtk.h>
+#include "badwolf.h"
+
#include <glib/gprintf.h> /* g_fprintf() */
+#include <gtk/gtk.h>
+#include <libxml/xpath.h>
void
-location_completion_init()
+location_completion_setup(GtkListStore *list_store)
{
- GtkTreeIter iter;
- GtkListStore *list_store;
- GIOChannel *file_channel;
- GError *file_err = NULL;
- gchar *file_line;
+ gtk_entry_completion_set_model(location_completion, GTK_TREE_MODEL(list_store));
+ gtk_entry_completion_set_text_column(location_completion, 0);
+}
- location_completion = gtk_entry_completion_new();
+void
+location_completion_cleanup(xmlXPathObjectPtr xpathObj, xmlXPathContextPtr xpathCtx, xmlDocPtr doc)
+{
+ if(xpathObj != NULL) xmlXPathFreeObject(xpathObj);
+ if(xpathCtx != NULL) xmlXPathFreeContext(xpathCtx);
+ if(doc != NULL) xmlFreeDoc(doc);
+}
- list_store = gtk_list_store_new(1, G_TYPE_STRING);
+GtkTreeIter
+load_xpath_results(GtkListStore *list_store, xmlNodeSetPtr nodes)
+{
+ GtkTreeIter iter;
+ int size;
- gchar *filename = g_build_filename(g_get_user_data_dir(), "badwolf", "URLs.txt", NULL);
- g_fprintf(stderr, "URL Completion: loading at %s\n", filename);
- file_channel = g_io_channel_new_file(filename, "r", &file_err);
+ size = (nodes) ? nodes->nodeNr : 0;
- if(file_channel != NULL)
- {
- while(G_IO_STATUS_NORMAL ==
- g_io_channel_read_line(file_channel, &file_line, NULL, NULL, &file_err))
+ g_fprintf(stderr, "Bookmarks: Found %d bookmarks.\n", size);
+ for(int i = 0; i < size; i++)
+ if(nodes->nodeTab[i])
{
gtk_list_store_append(list_store, &iter);
- gtk_list_store_set(list_store, &iter, 0, g_strchomp(file_line), -1);
+ gtk_list_store_set(
+ list_store, &iter, 0, (char *)xmlXPathCastNodeToString(nodes->nodeTab[i]), -1);
}
- g_free(file_line);
- g_io_channel_unref(file_channel);
- //g_io_channel_shutdown(file_channel, FALSE, &file_err);
- g_fprintf(stderr, "URL Completion: Done.\n");
- }
- else
- g_fprintf(stderr, "URL Completion: Failed to load file.\n");
+ return iter;
+}
+
+void
+location_completion_init()
+{
+ const xmlChar *xpathExpr = "//bookmark/@href";
+ char *filename = g_build_filename(g_get_user_data_dir(), "badwolf", "bookmarks.xbel", NULL);
+ xmlDocPtr doc = NULL;
+ xmlXPathContextPtr xpathCtx = NULL;
+ xmlXPathObjectPtr xpathObj = NULL;
+ GtkTreeIter iter;
+ GtkListStore *list_store = gtk_list_store_new(1, G_TYPE_STRING);
+
+ location_completion = gtk_entry_completion_new();
gtk_list_store_append(list_store, &iter);
gtk_list_store_set(list_store, &iter, 0, homepage, -1);
- gtk_entry_completion_set_model(location_completion, GTK_TREE_MODEL(list_store));
- gtk_entry_completion_set_text_column(location_completion, 0);
+ g_fprintf(stderr, "Bookmarks: loading at %s\n", filename);
+ doc = xmlParseFile(filename);
+ if(doc == NULL)
+ {
+ g_fprintf(stderr, "Bookmarks: unable to parse file \"%s\"\n", filename);
+ location_completion_cleanup(xpathObj, xpathCtx, doc);
+ return;
+ }
+
+ xpathCtx = xmlXPathNewContext(doc);
+ if(xpathCtx == NULL)
+ {
+ g_fprintf(stderr, "Bookmarks: unable to create new XPath context\n");
+ location_completion_cleanup(xpathObj, xpathCtx, doc);
+ return;
+ }
+
+ xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx);
+ if(xpathObj == NULL)
+ {
+ g_fprintf(stderr, "Bookmarks: unable to evaluate xpath expression \"%s\"\n", xpathExpr);
+ location_completion_cleanup(xpathObj, xpathCtx, doc);
+ return;
+ }
+
+ iter = load_xpath_results(list_store, xpathObj->nodesetval);
+
+ location_completion_cleanup(xpathObj, xpathCtx, doc);
+ location_completion_setup(list_store);
+
+ g_fprintf(stderr, "Bookmarks: Done.\n");
}