Initial attempt at userscript include/ exclude directives
This commit is contained in:
parent
486aa8f5dc
commit
b85bd2d3ef
2 changed files with 235 additions and 11 deletions
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
|
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
|
||||||
|
Copyright (C) 2008 Arnaud Renevier <arenevier@fdn.fr>
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -18,6 +19,7 @@
|
||||||
#include <webkit/webkit.h>
|
#include <webkit/webkit.h>
|
||||||
#include <JavaScriptCore/JavaScript.h>
|
#include <JavaScriptCore/JavaScript.h>
|
||||||
#include <glib/gi18n.h>
|
#include <glib/gi18n.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
struct _MidoriAddons
|
struct _MidoriAddons
|
||||||
{
|
{
|
||||||
|
@ -163,6 +165,204 @@ midori_addons_init (MidoriAddons* addons)
|
||||||
gtk_box_pack_start (GTK_BOX (addons), addons->treeview, TRUE, TRUE, 0);
|
gtk_box_pack_start (GTK_BOX (addons), addons->treeview, TRUE, TRUE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define HAVE_GREGEX GLIB_CHECK_VERSION (2, 14, 0)
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_include_exclude_from_file (const gchar* filename,
|
||||||
|
GSList** includes,
|
||||||
|
GSList** excludes)
|
||||||
|
{
|
||||||
|
GIOChannel* channel;
|
||||||
|
gchar* line;
|
||||||
|
gboolean found_meta;
|
||||||
|
#if HAVE_GREGEX
|
||||||
|
GRegex* meta_re;
|
||||||
|
GMatchInfo* match_info;
|
||||||
|
#endif
|
||||||
|
gchar* meta_name;
|
||||||
|
|
||||||
|
if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
channel = g_io_channel_new_file (filename, "r", 0);
|
||||||
|
if (!channel)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
found_meta = FALSE;
|
||||||
|
/* FIXME: Implement this without GRegex for Glib < 2.14 */
|
||||||
|
#if HAVE_GREGEX
|
||||||
|
meta_re = g_regex_new (
|
||||||
|
"//[[:space:]]+@([^[:space:]]+)[[:space:]]+([^[:space:]]+)[[:space:]]*",
|
||||||
|
G_REGEX_OPTIMIZE, 0, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while (g_io_channel_read_line (channel, &line, NULL, NULL, NULL)
|
||||||
|
== G_IO_STATUS_NORMAL)
|
||||||
|
{
|
||||||
|
if (g_str_has_prefix (line, "// ==UserScript=="))
|
||||||
|
{
|
||||||
|
found_meta = TRUE;
|
||||||
|
g_free (line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#if HAVE_GREGEX
|
||||||
|
match_info = NULL;
|
||||||
|
#endif
|
||||||
|
meta_name = NULL;
|
||||||
|
if (found_meta)
|
||||||
|
{
|
||||||
|
if (g_str_has_prefix (line, "// ==/UserScript=="))
|
||||||
|
{
|
||||||
|
found_meta = FALSE;
|
||||||
|
g_free (line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#if HAVE_GREGEX
|
||||||
|
if (g_regex_match (meta_re, line, 0, &match_info))
|
||||||
|
{
|
||||||
|
meta_name = g_match_info_fetch (match_info, 1);
|
||||||
|
if (!strcmp (meta_name, "require") ||
|
||||||
|
!strcmp (meta_name, "resource"))
|
||||||
|
{
|
||||||
|
/* We don't support these, so abort here */
|
||||||
|
g_match_info_free (match_info);
|
||||||
|
g_free (meta_name);
|
||||||
|
g_free (line);
|
||||||
|
g_io_channel_shutdown (channel, false, 0);
|
||||||
|
g_regex_unref (meta_re);
|
||||||
|
g_slist_free (*includes);
|
||||||
|
g_slist_free (*excludes);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else if (!strcmp (meta_name, "include"))
|
||||||
|
{
|
||||||
|
*includes = g_slist_prepend (*includes,
|
||||||
|
g_match_info_fetch (match_info, 2));
|
||||||
|
}
|
||||||
|
else if (!strcmp (meta_name, "exclude"))
|
||||||
|
{
|
||||||
|
*excludes = g_slist_prepend (*excludes,
|
||||||
|
g_match_info_fetch (match_info, 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#if HAVE_GREGEX
|
||||||
|
g_match_info_free (match_info);
|
||||||
|
#endif
|
||||||
|
g_free (meta_name);
|
||||||
|
g_free (line);
|
||||||
|
}
|
||||||
|
g_io_channel_shutdown (channel, false, 0);
|
||||||
|
g_io_channel_unref (channel);
|
||||||
|
#if HAVE_GREGEX
|
||||||
|
g_regex_unref (meta_re);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gchar*
|
||||||
|
_convert_to_simple_regexp (const gchar* pattern)
|
||||||
|
{
|
||||||
|
guint len;
|
||||||
|
gchar* dest;
|
||||||
|
guint pos;
|
||||||
|
guint i;
|
||||||
|
gchar c;
|
||||||
|
|
||||||
|
len = strlen (pattern);
|
||||||
|
dest = g_malloc0 (len * 2 + 1);
|
||||||
|
dest[0] = '^';
|
||||||
|
pos = 1;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
c = pattern[i];
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '*':
|
||||||
|
dest[pos] = '.';
|
||||||
|
dest[pos + 1] = c;
|
||||||
|
pos++;
|
||||||
|
pos++;
|
||||||
|
break;
|
||||||
|
case '.' :
|
||||||
|
case '?' :
|
||||||
|
case '^' :
|
||||||
|
case '$' :
|
||||||
|
case '+' :
|
||||||
|
case '{' :
|
||||||
|
case '[' :
|
||||||
|
case '|' :
|
||||||
|
case '(' :
|
||||||
|
case ')' :
|
||||||
|
case ']' :
|
||||||
|
case '\\' :
|
||||||
|
dest[pos] = '\\';
|
||||||
|
dest[pos + 1] = c;
|
||||||
|
pos++;
|
||||||
|
pos++;
|
||||||
|
break;
|
||||||
|
case ' ' :
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dest[pos] = pattern[i];
|
||||||
|
pos ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_may_load_script (const gchar* uri,
|
||||||
|
GSList** includes,
|
||||||
|
GSList** excludes)
|
||||||
|
{
|
||||||
|
gboolean match;
|
||||||
|
GSList* list;
|
||||||
|
gchar* re;
|
||||||
|
|
||||||
|
if (*includes)
|
||||||
|
match = FALSE;
|
||||||
|
else
|
||||||
|
match = TRUE;
|
||||||
|
|
||||||
|
list = *includes;
|
||||||
|
while (list)
|
||||||
|
{
|
||||||
|
re = _convert_to_simple_regexp (list->data);
|
||||||
|
#if HAVE_GREGEX
|
||||||
|
if (g_regex_match_simple (re, uri, 0, 0))
|
||||||
|
{
|
||||||
|
match = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
g_free (re);
|
||||||
|
list = list->next;
|
||||||
|
}
|
||||||
|
if (!match)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
list = *excludes;
|
||||||
|
while (list)
|
||||||
|
{
|
||||||
|
re = _convert_to_simple_regexp (list->data);
|
||||||
|
#if HAVE_GREGEX
|
||||||
|
if (g_regex_match_simple (re, uri, 0, 0))
|
||||||
|
{
|
||||||
|
match = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
g_free (re);
|
||||||
|
list = list->next;
|
||||||
|
}
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
_js_script_from_file (JSContextRef js_context,
|
_js_script_from_file (JSContextRef js_context,
|
||||||
const gchar* filename,
|
const gchar* filename,
|
||||||
|
@ -199,21 +399,46 @@ midori_web_widget_window_object_cleared_cb (GtkWidget* web_widget,
|
||||||
JSObjectRef js_window,
|
JSObjectRef js_window,
|
||||||
MidoriAddons* addons)
|
MidoriAddons* addons)
|
||||||
{
|
{
|
||||||
|
gchar* addon_path;
|
||||||
|
GDir* addon_dir;
|
||||||
|
const gchar* filename;
|
||||||
|
gchar* fullname;
|
||||||
|
GSList* includes;
|
||||||
|
GSList* excludes;
|
||||||
|
const gchar* uri;
|
||||||
|
gchar* exception;
|
||||||
|
gchar* message;
|
||||||
|
|
||||||
/* FIXME: We want to honor system installed addons as well */
|
/* FIXME: We want to honor system installed addons as well */
|
||||||
gchar* addon_path = g_build_filename (g_get_user_data_dir (), PACKAGE_NAME,
|
addon_path = g_build_filename (g_get_user_data_dir (), PACKAGE_NAME,
|
||||||
_folder_for_kind (addons->kind), NULL);
|
_folder_for_kind (addons->kind), NULL);
|
||||||
GDir* addon_dir = g_dir_open (addon_path, 0, NULL);
|
if ((addon_dir = g_dir_open (addon_path, 0, NULL)))
|
||||||
if (addon_dir)
|
|
||||||
{
|
{
|
||||||
const gchar* filename;
|
|
||||||
while ((filename = g_dir_read_name (addon_dir)))
|
while ((filename = g_dir_read_name (addon_dir)))
|
||||||
{
|
{
|
||||||
gchar* fullname = g_build_filename (addon_path, filename, NULL);
|
fullname = g_build_filename (addon_path, filename, NULL);
|
||||||
gchar* exception;
|
includes = NULL;
|
||||||
|
excludes = NULL;
|
||||||
|
if (!_include_exclude_from_file (fullname, &includes, &excludes))
|
||||||
|
{
|
||||||
|
g_free (fullname);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (includes || excludes)
|
||||||
|
{
|
||||||
|
uri = webkit_web_frame_get_uri (web_frame);
|
||||||
|
if (!_may_load_script (uri, &includes, &excludes))
|
||||||
|
{
|
||||||
|
g_free (fullname);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_slist_free (includes);
|
||||||
|
g_slist_free (excludes);
|
||||||
|
exception = NULL;
|
||||||
if (!_js_script_from_file (js_context, fullname, &exception))
|
if (!_js_script_from_file (js_context, fullname, &exception))
|
||||||
{
|
{
|
||||||
gchar* message = g_strdup_printf ("console.error ('%s');",
|
message = g_strdup_printf ("console.error ('%s');", exception);
|
||||||
exception);
|
|
||||||
gjs_script_eval (js_context, message, NULL);
|
gjs_script_eval (js_context, message, NULL);
|
||||||
g_free (message);
|
g_free (message);
|
||||||
g_free (exception);
|
g_free (exception);
|
||||||
|
|
|
@ -32,7 +32,6 @@ G_BEGIN_DECLS
|
||||||
(G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_ADDONS, MidoriAddonsClass))
|
(G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_ADDONS, MidoriAddonsClass))
|
||||||
|
|
||||||
typedef struct _MidoriAddons MidoriAddons;
|
typedef struct _MidoriAddons MidoriAddons;
|
||||||
typedef struct _MidoriAddonsPrivate MidoriAddonsPrivate;
|
|
||||||
typedef struct _MidoriAddonsClass MidoriAddonsClass;
|
typedef struct _MidoriAddonsClass MidoriAddonsClass;
|
||||||
|
|
||||||
struct _MidoriAddonsClass
|
struct _MidoriAddonsClass
|
||||||
|
@ -61,7 +60,7 @@ midori_addons_new (GtkWidget* web_widget,
|
||||||
MidoriAddonKind kind);
|
MidoriAddonKind kind);
|
||||||
|
|
||||||
GtkWidget*
|
GtkWidget*
|
||||||
midori_addons_get_toolbar (MidoriAddons* console);
|
midori_addons_get_toolbar (MidoriAddons* console);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue