Initial attempt at userscript include/ exclude directives

This commit is contained in:
Arnaud Renevier 2008-07-28 15:21:08 +02:00 committed by Christian Dywan
parent 486aa8f5dc
commit b85bd2d3ef
2 changed files with 235 additions and 11 deletions

View file

@ -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);

View file

@ -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