1127 lines
36 KiB
C
1127 lines
36 KiB
C
/*
|
|
Copyright (C) 2013 Stephan Haller <nomad@froevel.de>
|
|
|
|
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 "cookie-permission-manager.h"
|
|
|
|
#include <errno.h>
|
|
|
|
/* Remove next line if we found a way to show details in infobar */
|
|
#define NO_INFOBAR_DETAILS
|
|
|
|
/* Define this class in GObject system */
|
|
G_DEFINE_TYPE(CookiePermissionManager,
|
|
cookie_permission_manager,
|
|
G_TYPE_OBJECT)
|
|
|
|
/* Properties */
|
|
enum
|
|
{
|
|
PROP_0,
|
|
|
|
PROP_EXTENSION,
|
|
PROP_APPLICATION,
|
|
|
|
PROP_DATABASE,
|
|
PROP_DATABASE_FILENAME,
|
|
PROP_ASK_FOR_UNKNOWN_POLICY,
|
|
|
|
PROP_LAST
|
|
};
|
|
|
|
static GParamSpec* CookiePermissionManagerProperties[PROP_LAST]={ 0, };
|
|
|
|
/* Private structure - access only by public API if needed */
|
|
#define COOKIE_PERMISSION_MANAGER_GET_PRIVATE(obj) \
|
|
(G_TYPE_INSTANCE_GET_PRIVATE((obj), TYPE_COOKIE_PERMISSION_MANAGER, CookiePermissionManagerPrivate))
|
|
|
|
struct _CookiePermissionManagerPrivate
|
|
{
|
|
/* Extension related */
|
|
MidoriExtension *extension;
|
|
MidoriApp *application;
|
|
sqlite3 *database;
|
|
gchar *databaseFilename;
|
|
gboolean askForUnknownPolicy;
|
|
|
|
/* Cookie jar related */
|
|
SoupSession *session;
|
|
SoupCookieJar *cookieJar;
|
|
SoupSessionFeatureInterface *featureIface;
|
|
gint cookieJarChangedID;
|
|
};
|
|
|
|
enum
|
|
{
|
|
DOMAIN_COLUMN,
|
|
PATH_COLUMN,
|
|
NAME_COLUMN,
|
|
VALUE_COLUMN,
|
|
EXPIRE_DATE_COLUMN,
|
|
N_COLUMN
|
|
};
|
|
|
|
struct _CookiePermissionManagerModalInfobar
|
|
{
|
|
GMainLoop *mainLoop;
|
|
gint response;
|
|
};
|
|
|
|
typedef struct _CookiePermissionManagerModalInfobar CookiePermissionManagerModalInfobar;
|
|
|
|
/* IMPLEMENTATION: Private variables and methods */
|
|
|
|
/* Show common error dialog */
|
|
static void _cookie_permission_manager_error(CookiePermissionManager *self, const gchar *inReason)
|
|
{
|
|
GtkWidget *dialog;
|
|
|
|
/* Show confirmation dialog for undetermined cookies */
|
|
dialog=gtk_message_dialog_new(NULL,
|
|
GTK_DIALOG_MODAL,
|
|
GTK_MESSAGE_ERROR,
|
|
GTK_BUTTONS_OK,
|
|
_("A fatal error occurred which prevents "
|
|
"the cookie permission manager extension "
|
|
"to continue. You should disable it."));
|
|
|
|
gtk_window_set_title(GTK_WINDOW(dialog), _("Error in cookie permission manager extension"));
|
|
gtk_window_set_icon_name(GTK_WINDOW (dialog), "midori");
|
|
|
|
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
|
|
"%s:\n%s",
|
|
_("Reason"),
|
|
inReason);
|
|
|
|
gtk_dialog_run(GTK_DIALOG(dialog));
|
|
|
|
/* Free up allocated resources */
|
|
gtk_widget_destroy(dialog);
|
|
}
|
|
|
|
/* Open database containing policies for cookie domains.
|
|
* Create database and setup table structure if it does not exist yet.
|
|
*/
|
|
static void _cookie_permission_manager_open_database(CookiePermissionManager *self)
|
|
{
|
|
CookiePermissionManagerPrivate *priv=self->priv;
|
|
const gchar *configDir;
|
|
gchar *error=NULL;
|
|
gint success;
|
|
sqlite3_stmt *statement=NULL;
|
|
|
|
/* Close any open database */
|
|
if(priv->database)
|
|
{
|
|
g_free(priv->databaseFilename);
|
|
priv->databaseFilename=NULL;
|
|
|
|
sqlite3_close(priv->database);
|
|
priv->database=NULL;
|
|
|
|
g_object_notify_by_pspec(G_OBJECT(self), CookiePermissionManagerProperties[PROP_DATABASE]);
|
|
g_object_notify_by_pspec(G_OBJECT(self), CookiePermissionManagerProperties[PROP_DATABASE_FILENAME]);
|
|
}
|
|
|
|
/* Build path to database file */
|
|
configDir=midori_extension_get_config_dir(priv->extension);
|
|
if(!configDir)
|
|
return;
|
|
|
|
if(katze_mkdir_with_parents(configDir, 0700))
|
|
{
|
|
g_warning(_("Could not create configuration folder for extension: %s"), g_strerror(errno));
|
|
|
|
_cookie_permission_manager_error(self, _("Could not create configuration folder for extension."));
|
|
return;
|
|
}
|
|
|
|
/* Open database */
|
|
priv->databaseFilename=g_build_filename(configDir, COOKIE_PERMISSION_DATABASE, NULL);
|
|
success=sqlite3_open(priv->databaseFilename, &priv->database);
|
|
if(success!=SQLITE_OK)
|
|
{
|
|
g_warning(_("Could not open database of extenstion: %s"), sqlite3_errmsg(priv->database));
|
|
|
|
g_free(priv->databaseFilename);
|
|
priv->databaseFilename=NULL;
|
|
|
|
if(priv->database) sqlite3_close(priv->database);
|
|
priv->database=NULL;
|
|
|
|
_cookie_permission_manager_error(self, _("Could not open database of extension."));
|
|
return;
|
|
}
|
|
|
|
/* Create table structure if it does not exist */
|
|
success=sqlite3_exec(priv->database,
|
|
"CREATE TABLE IF NOT EXISTS "
|
|
"policies(domain text, value integer);",
|
|
NULL,
|
|
NULL,
|
|
&error);
|
|
|
|
if(success==SQLITE_OK)
|
|
{
|
|
success=sqlite3_exec(priv->database,
|
|
"CREATE UNIQUE INDEX IF NOT EXISTS "
|
|
"domain ON policies (domain);",
|
|
NULL,
|
|
NULL,
|
|
&error);
|
|
}
|
|
|
|
if(success==SQLITE_OK)
|
|
{
|
|
success=sqlite3_exec(priv->database,
|
|
"PRAGMA journal_mode=TRUNCATE;",
|
|
NULL,
|
|
NULL,
|
|
&error);
|
|
}
|
|
|
|
if(success!=SQLITE_OK || error)
|
|
{
|
|
_cookie_permission_manager_error(self, _("Could not set up database structure of extension."));
|
|
|
|
if(error)
|
|
{
|
|
g_critical(_("Failed to execute database statement: %s"), error);
|
|
sqlite3_free(error);
|
|
}
|
|
|
|
g_free(priv->databaseFilename);
|
|
priv->databaseFilename=NULL;
|
|
|
|
sqlite3_close(priv->database);
|
|
priv->database=NULL;
|
|
return;
|
|
}
|
|
|
|
// Delete all cookies allowed only in one session
|
|
success=sqlite3_prepare_v2(priv->database,
|
|
"SELECT domain FROM policies WHERE value=? ORDER BY domain DESC;",
|
|
-1,
|
|
&statement,
|
|
NULL);
|
|
if(statement && success==SQLITE_OK) success=sqlite3_bind_int(statement, 1, COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT_FOR_SESSION);
|
|
if(statement && success==SQLITE_OK)
|
|
{
|
|
while(sqlite3_step(statement)==SQLITE_ROW)
|
|
{
|
|
gchar *domain=(gchar*)sqlite3_column_text(statement, 0);
|
|
GSList *cookies, *cookie;
|
|
|
|
#ifdef HAVE_LIBSOUP_2_40_0
|
|
SoupURI *uri;
|
|
|
|
uri=soup_uri_new(NULL);
|
|
soup_uri_set_host(uri, domain);
|
|
cookies=soup_cookie_jar_get_cookie_list(priv->cookieJar, uri, TRUE);
|
|
for(cookie=cookies; cookie; cookie->next)
|
|
{
|
|
soup_cookie_jar_delete_cookie(priv->cookieJar, (SoupCookie*)cookie->data);
|
|
}
|
|
soup_cookies_free(cookies);
|
|
soup_uri_free(uri);
|
|
#else
|
|
cookies=soup_cookie_jar_all_cookies(priv->cookieJar);
|
|
for(cookie=cookies; cookie; cookie=cookie->next)
|
|
{
|
|
if(soup_cookie_domain_matches((SoupCookie*)cookie->data, domain))
|
|
{
|
|
soup_cookie_jar_delete_cookie(priv->cookieJar, (SoupCookie*)cookie->data);
|
|
}
|
|
}
|
|
soup_cookies_free(cookies);
|
|
#endif
|
|
}
|
|
}
|
|
else g_warning(_("SQL fails: %s"), sqlite3_errmsg(priv->database));
|
|
|
|
sqlite3_finalize(statement);
|
|
|
|
g_object_notify_by_pspec(G_OBJECT(self), CookiePermissionManagerProperties[PROP_DATABASE]);
|
|
g_object_notify_by_pspec(G_OBJECT(self), CookiePermissionManagerProperties[PROP_DATABASE_FILENAME]);
|
|
}
|
|
|
|
/* Get policy for cookies from domain */
|
|
static gint _cookie_permission_manager_get_policy(CookiePermissionManager *self, SoupCookie *inCookie)
|
|
{
|
|
CookiePermissionManagerPrivate *priv=self->priv;
|
|
sqlite3_stmt *statement=NULL;
|
|
gchar *domain;
|
|
gint error;
|
|
gint policy=COOKIE_PERMISSION_MANAGER_POLICY_UNDETERMINED;
|
|
gboolean foundPolicy=FALSE;
|
|
|
|
/* Check for open database */
|
|
g_return_val_if_fail(priv->database, COOKIE_PERMISSION_MANAGER_POLICY_UNDETERMINED);
|
|
|
|
/* Lookup policy for cookie domain in database */
|
|
domain=g_strdup(soup_cookie_get_domain(inCookie));
|
|
if(*domain=='.') *domain='%';
|
|
|
|
error=sqlite3_prepare_v2(priv->database,
|
|
"SELECT domain, value FROM policies WHERE domain LIKE ? ORDER BY domain DESC;",
|
|
-1,
|
|
&statement,
|
|
NULL);
|
|
if(statement && error==SQLITE_OK) error=sqlite3_bind_text(statement, 1, domain, -1, NULL);
|
|
if(statement && error==SQLITE_OK)
|
|
{
|
|
while(policy==COOKIE_PERMISSION_MANAGER_POLICY_UNDETERMINED &&
|
|
sqlite3_step(statement)==SQLITE_ROW)
|
|
{
|
|
gchar *policyDomain=(gchar*)sqlite3_column_text(statement, 0);
|
|
|
|
if(soup_cookie_domain_matches(inCookie, policyDomain))
|
|
{
|
|
policy=sqlite3_column_int(statement, 1);
|
|
foundPolicy=TRUE;
|
|
}
|
|
}
|
|
}
|
|
else g_warning(_("SQL fails: %s"), sqlite3_errmsg(priv->database));
|
|
|
|
sqlite3_finalize(statement);
|
|
|
|
/* Check if policy is undetermined. If it is then check if this policy was set by user.
|
|
* If it was not set by user check if we should ask user for his decision
|
|
*/
|
|
if(!priv->askForUnknownPolicy && !foundPolicy)
|
|
{
|
|
switch(soup_cookie_jar_get_accept_policy(priv->cookieJar))
|
|
{
|
|
case SOUP_COOKIE_JAR_ACCEPT_ALWAYS:
|
|
case SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY:
|
|
policy=COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT;
|
|
break;
|
|
|
|
case SOUP_COOKIE_JAR_ACCEPT_NEVER:
|
|
policy=COOKIE_PERMISSION_MANAGER_POLICY_BLOCK;
|
|
break;
|
|
|
|
default:
|
|
g_critical(_("Could not determine global cookie policy to set for domain: %s"), domain);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Release allocated resources */
|
|
g_free(domain);
|
|
|
|
return(policy);
|
|
}
|
|
|
|
/* Ask user what to do with cookies from domain(s) which were neither marked accepted nor blocked */
|
|
static gint _cookie_permission_manager_sort_cookies_by_domain(SoupCookie *inLeft, SoupCookie *inRight)
|
|
{
|
|
const gchar *domainLeft=soup_cookie_get_domain(inLeft);
|
|
const gchar *domainRight=soup_cookie_get_domain(inRight);
|
|
|
|
if(*domainLeft=='.') domainLeft++;
|
|
if(*domainRight=='.') domainRight++;
|
|
|
|
return(g_ascii_strcasecmp(domainLeft, domainRight));
|
|
}
|
|
|
|
static GSList* _cookie_permission_manager_get_number_domains_and_cookies(CookiePermissionManager *self,
|
|
GSList *inCookies,
|
|
gint *ioNumberDomains,
|
|
gint *ioNumberCookies)
|
|
{
|
|
GSList *sortedList, *iter;
|
|
gint domains, cookies;
|
|
const gchar *lastDomain=NULL;
|
|
const gchar *cookieDomain;
|
|
|
|
/* Make copy and sort cookies in new list */
|
|
sortedList=g_slist_copy(inCookies);
|
|
|
|
/* Sort cookies by domain to prevent a doman counted multiple times */
|
|
sortedList=g_slist_sort(sortedList, (GCompareFunc)_cookie_permission_manager_sort_cookies_by_domain);
|
|
|
|
/* Iterate through list and count domains and cookies */
|
|
domains=cookies=0;
|
|
for(iter=sortedList; iter; iter=iter->next)
|
|
{
|
|
cookieDomain=soup_cookie_get_domain((SoupCookie*)iter->data);
|
|
|
|
if(!lastDomain || g_ascii_strcasecmp(lastDomain, cookieDomain)!=0)
|
|
{
|
|
domains++;
|
|
lastDomain=cookieDomain;
|
|
}
|
|
|
|
cookies++;
|
|
}
|
|
|
|
/* Store counted numbers to final variables */
|
|
if(ioNumberDomains) *ioNumberDomains=domains;
|
|
if(ioNumberCookies) *ioNumberCookies=cookies;
|
|
|
|
/* Return the copied but sorted cookie list. Caller is responsible to free
|
|
* this list with g_slist_free
|
|
*/
|
|
return(sortedList);
|
|
}
|
|
|
|
/* FIXME: Find a way to add "details" widget */
|
|
#ifndef NO_INFOBAR_DETAILS
|
|
static void _cookie_permission_manager_when_ask_expander_changed(CookiePermissionManager *self,
|
|
GParamSpec *inSpec,
|
|
gpointer inUserData)
|
|
{
|
|
GtkExpander *expander=GTK_EXPANDER(inUserData);
|
|
|
|
midori_extension_set_boolean(self->priv->extension, "show-details-when-ask", gtk_expander_get_expanded(expander));
|
|
}
|
|
#endif
|
|
|
|
static gboolean _cookie_permission_manager_on_infobar_webview_navigate(WebKitWebView *inView,
|
|
WebKitWebFrame *inFrame,
|
|
WebKitNetworkRequest *inRequest,
|
|
WebKitWebNavigationAction *inAction,
|
|
WebKitWebPolicyDecision *inDecision,
|
|
gpointer inUserData)
|
|
{
|
|
/* Destroy info bar - that calls another callback which quits main loop */
|
|
GtkWidget *infobar=GTK_WIDGET(inUserData);
|
|
|
|
gtk_widget_destroy(infobar);
|
|
|
|
/* Let the default handler decide */
|
|
return(FALSE);
|
|
}
|
|
|
|
static void _cookie_permission_manager_on_infobar_destroy(GtkWidget* inInfobar,
|
|
gpointer inUserData)
|
|
{
|
|
CookiePermissionManagerModalInfobar *modalInfo=(CookiePermissionManagerModalInfobar*)inUserData;
|
|
|
|
/* Quit main loop */
|
|
if(g_main_loop_is_running(modalInfo->mainLoop)) g_main_loop_quit(modalInfo->mainLoop);
|
|
}
|
|
|
|
static void _cookie_permission_manager_on_infobar_policy_decision(GtkWidget* inInfobar,
|
|
gint inResponse,
|
|
gpointer inUserData)
|
|
{
|
|
CookiePermissionManagerModalInfobar *modalInfo;
|
|
|
|
/* Get modal info struct */
|
|
modalInfo=(CookiePermissionManagerModalInfobar*)g_object_get_data(G_OBJECT(inInfobar), "cookie-permission-manager-infobar-data");
|
|
|
|
/* Store response */
|
|
modalInfo->response=inResponse;
|
|
|
|
/* Quit main loop */
|
|
if(g_main_loop_is_running(modalInfo->mainLoop)) g_main_loop_quit(modalInfo->mainLoop);
|
|
}
|
|
|
|
static gint _cookie_permission_manager_ask_for_policy(CookiePermissionManager *self,
|
|
MidoriView *inView,
|
|
SoupMessage *inMessage,
|
|
GSList *inUnknownCookies)
|
|
{
|
|
/* Ask user for policy of unkndown domains in an undistracting way.
|
|
* The idea is to put the message not in a modal window but into midori's info bar.
|
|
* Then we'll set up our own GMainLoop to simulate a modal info bar. We need to
|
|
* connect to all possible signals of info bar, web view and so on to handle user's
|
|
* decision and to get out of our own GMainLoop. After that webkit resumes processing
|
|
* data.
|
|
*/
|
|
CookiePermissionManagerPrivate *priv=self->priv;
|
|
GtkWidget *infobar;
|
|
/* FIXME: Find a way to add "details" widget */
|
|
#ifndef NO_INFOBAR_DETAILS
|
|
GtkWidget *widget;
|
|
GtkWidget *contentArea;
|
|
GtkWidget *vbox, *hbox;
|
|
GtkWidget *expander;
|
|
GtkListStore *listStore;
|
|
GtkTreeIter listIter;
|
|
GtkWidget *scrolled;
|
|
GtkWidget *list;
|
|
GtkCellRenderer *renderer;
|
|
GtkTreeViewColumn *column;
|
|
#endif
|
|
gchar *text;
|
|
gint numberDomains, numberCookies;
|
|
GSList *sortedCookies, *cookies;
|
|
WebKitWebView *webkitView;
|
|
CookiePermissionManagerModalInfobar modalInfo;
|
|
|
|
/* Get webkit view of midori view */
|
|
webkitView=WEBKIT_WEB_VIEW(midori_view_get_web_view(inView));
|
|
|
|
/* Create a copy of cookies and sort them */
|
|
sortedCookies=_cookie_permission_manager_get_number_domains_and_cookies(self,
|
|
inUnknownCookies,
|
|
&numberDomains,
|
|
&numberCookies);
|
|
|
|
/* FIXME: Find a way to add "details" widget */
|
|
#ifndef NO_INFOBAR_DETAILS
|
|
/* Create list model and fill in data */
|
|
listStore=gtk_list_store_new(N_COLUMN,
|
|
G_TYPE_STRING, /* DOMAIN_COLUMN */
|
|
G_TYPE_STRING, /* PATH_COLUMN */
|
|
G_TYPE_STRING, /* NAME_COLUMN */
|
|
G_TYPE_STRING, /* VALUE_COLUMN */
|
|
G_TYPE_STRING /* EXPIRE_DATE_COLUMN */);
|
|
|
|
for(cookies=sortedCookies; cookies; cookies=cookies->next)
|
|
{
|
|
SoupCookie *cookie=(SoupCookie*)cookies->data;
|
|
SoupDate *cookieDate=soup_cookie_get_expires(cookie);
|
|
|
|
if(cookieDate) text=soup_date_to_string(cookieDate, SOUP_DATE_HTTP);
|
|
else text=g_strdup(_("Till session end"));
|
|
|
|
gtk_list_store_append(listStore, &listIter);
|
|
gtk_list_store_set(listStore,
|
|
&listIter,
|
|
DOMAIN_COLUMN, soup_cookie_get_domain(cookie),
|
|
PATH_COLUMN, soup_cookie_get_path(cookie),
|
|
NAME_COLUMN, soup_cookie_get_name(cookie),
|
|
VALUE_COLUMN, soup_cookie_get_value(cookie),
|
|
EXPIRE_DATE_COLUMN, text,
|
|
-1);
|
|
|
|
g_free(text);
|
|
}
|
|
#endif
|
|
|
|
/* Create description text */
|
|
if(numberDomains==1)
|
|
{
|
|
const gchar *cookieDomain=soup_cookie_get_domain((SoupCookie*)sortedCookies->data);
|
|
|
|
if(*cookieDomain=='.') cookieDomain++;
|
|
|
|
if(numberCookies>1)
|
|
text=g_strdup_printf(_("The website %s wants to store %d cookies."), cookieDomain, numberCookies);
|
|
else
|
|
text=g_strdup_printf(_("The website %s wants to store a cookie."), cookieDomain);
|
|
}
|
|
else
|
|
{
|
|
text=g_strdup_printf(_("Multiple websites want to store %d cookies in total."), numberCookies);
|
|
}
|
|
|
|
/* Create info bar message and buttons */
|
|
infobar=midori_view_add_info_bar(inView,
|
|
GTK_MESSAGE_QUESTION,
|
|
text,
|
|
G_CALLBACK(_cookie_permission_manager_on_infobar_policy_decision),
|
|
NULL,
|
|
_("_Accept"), COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT,
|
|
_("Accept for this _session"), COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT_FOR_SESSION,
|
|
_("De_ny"), COOKIE_PERMISSION_MANAGER_POLICY_BLOCK,
|
|
_("Deny _this time"), COOKIE_PERMISSION_MANAGER_POLICY_UNDETERMINED,
|
|
NULL);
|
|
g_free(text);
|
|
|
|
/* midori_view_add_info_bar() in version 0.4.8 expects a GObject as user data
|
|
* but I don't want to create an GObject just for a simple struct. So set object
|
|
* data by our own
|
|
*/
|
|
g_object_set_data(G_OBJECT(infobar), "cookie-permission-manager-infobar-data", &modalInfo);
|
|
|
|
/* FIXME: Find a way to add "details" widget */
|
|
#ifndef NO_INFOBAR_DETAILS
|
|
/* Get content area of infobar */
|
|
#if HAVE_GTK_INFO_BAR
|
|
contentArea=gtk_info_bar_get_content_area(GTK_INFO_BAR(infobar));
|
|
#else
|
|
contentArea=infobar;
|
|
#endif
|
|
|
|
/* Create list and set up columns of list */
|
|
list=gtk_tree_view_new_with_model(GTK_TREE_MODEL(listStore));
|
|
#ifndef HAVE_GTK3
|
|
gtk_widget_set_size_request(list, -1, 100);
|
|
#endif
|
|
|
|
renderer=gtk_cell_renderer_text_new();
|
|
column=gtk_tree_view_column_new_with_attributes(_("Domain"),
|
|
renderer,
|
|
"text", DOMAIN_COLUMN,
|
|
NULL);
|
|
gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
|
|
|
|
renderer=gtk_cell_renderer_text_new();
|
|
column=gtk_tree_view_column_new_with_attributes(_("Path"),
|
|
renderer,
|
|
"text", PATH_COLUMN,
|
|
NULL);
|
|
gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
|
|
|
|
renderer=gtk_cell_renderer_text_new();
|
|
column=gtk_tree_view_column_new_with_attributes(_("Name"),
|
|
renderer,
|
|
"text", NAME_COLUMN,
|
|
NULL);
|
|
gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
|
|
|
|
renderer=gtk_cell_renderer_text_new();
|
|
column=gtk_tree_view_column_new_with_attributes(_("Value"),
|
|
renderer,
|
|
"text", VALUE_COLUMN,
|
|
NULL);
|
|
g_object_set(G_OBJECT(renderer),
|
|
"ellipsize", PANGO_ELLIPSIZE_END,
|
|
"width-chars", 30,
|
|
NULL);
|
|
gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
|
|
|
|
renderer=gtk_cell_renderer_text_new();
|
|
column=gtk_tree_view_column_new_with_attributes(_("Expire date"),
|
|
renderer,
|
|
"text", EXPIRE_DATE_COLUMN,
|
|
NULL);
|
|
gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
|
|
|
|
scrolled=gtk_scrolled_window_new(NULL, NULL);
|
|
#ifdef HAVE_GTK3
|
|
gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(scrolled), 100);
|
|
#endif
|
|
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
|
gtk_container_add(GTK_CONTAINER(scrolled), list);
|
|
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
|
|
gtk_container_add(GTK_CONTAINER(expander), scrolled);
|
|
|
|
gtk_widget_show_all(vbox);
|
|
gtk_container_add(GTK_CONTAINER(contentArea), vbox);
|
|
|
|
/* Set state of expander based on config 'show-details-when-ask' */
|
|
gtk_expander_set_expanded(GTK_EXPANDER(expander),
|
|
midori_extension_get_boolean(priv->extension, "show-details-when-ask"));
|
|
g_signal_connect_swapped(expander, "notify::expanded", G_CALLBACK(_cookie_permission_manager_when_ask_expander_changed), self);
|
|
#endif
|
|
|
|
/* Show all widgets of info bar */
|
|
gtk_widget_show_all(infobar);
|
|
|
|
/* Connect signals to quit main loop */
|
|
g_signal_connect(webkitView, "navigation-policy-decision-requested", G_CALLBACK(_cookie_permission_manager_on_infobar_webview_navigate), infobar);
|
|
g_signal_connect(infobar, "destroy", G_CALLBACK(_cookie_permission_manager_on_infobar_destroy), &modalInfo);
|
|
|
|
/* Let info bar be modal and set response to default */
|
|
modalInfo.response=COOKIE_PERMISSION_MANAGER_POLICY_UNDETERMINED;
|
|
modalInfo.mainLoop=g_main_loop_new(NULL, FALSE);
|
|
|
|
GDK_THREADS_LEAVE();
|
|
g_main_loop_run(modalInfo.mainLoop);
|
|
GDK_THREADS_ENTER();
|
|
|
|
g_main_loop_unref(modalInfo.mainLoop);
|
|
|
|
modalInfo.mainLoop=NULL;
|
|
|
|
/* Disconnect signal handler to webkit's web view */
|
|
g_signal_handlers_disconnect_by_func(webkitView, G_CALLBACK(_cookie_permission_manager_on_infobar_webview_navigate), infobar);
|
|
|
|
/* Store user's decision in database if it is not a temporary block.
|
|
* We use the already sorted list of cookies to prevent multiple
|
|
* updates of database for the same domain. This sorted list is a copy
|
|
* to avoid a reorder of cookies
|
|
*/
|
|
if(modalInfo.response!=COOKIE_PERMISSION_MANAGER_POLICY_UNDETERMINED)
|
|
{
|
|
const gchar *lastDomain=NULL;
|
|
|
|
/* Iterate through cookies and store decision for each domain once */
|
|
for(cookies=sortedCookies; cookies; cookies=cookies->next)
|
|
{
|
|
SoupCookie *cookie=(SoupCookie*)cookies->data;
|
|
const gchar *cookieDomain=soup_cookie_get_domain(cookie);
|
|
|
|
if(*cookieDomain=='.') cookieDomain++;
|
|
|
|
/* Store decision if new domain found while iterating through cookies */
|
|
if(!lastDomain || g_ascii_strcasecmp(lastDomain, cookieDomain)!=0)
|
|
{
|
|
gchar *sql;
|
|
gchar *error=NULL;
|
|
gint success;
|
|
|
|
sql=sqlite3_mprintf("INSERT OR REPLACE INTO policies (domain, value) VALUES ('%q', %d);",
|
|
cookieDomain,
|
|
modalInfo.response);
|
|
success=sqlite3_exec(priv->database, sql, NULL, NULL, &error);
|
|
if(success!=SQLITE_OK) g_warning(_("SQL fails: %s"), error);
|
|
if(error) sqlite3_free(error);
|
|
sqlite3_free(sql);
|
|
|
|
lastDomain=cookieDomain;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Free up allocated resources */
|
|
g_slist_free(sortedCookies);
|
|
|
|
/* Return response */
|
|
return(modalInfo.response==COOKIE_PERMISSION_MANAGER_POLICY_UNDETERMINED ?
|
|
COOKIE_PERMISSION_MANAGER_POLICY_BLOCK : modalInfo.response);
|
|
}
|
|
|
|
/* A cookie was changed outside a request (e.g. Javascript) */
|
|
static void _cookie_permission_manager_on_cookie_changed(CookiePermissionManager *self,
|
|
SoupCookie *inOldCookie,
|
|
SoupCookie *inNewCookie,
|
|
SoupCookieJar *inCookieJar)
|
|
{
|
|
/* Do not check changed cookies because they must have been allowed before.
|
|
* Also do not check removed cookies because they are removed ;)
|
|
*/
|
|
if(inNewCookie==NULL || inOldCookie) return;
|
|
|
|
/* New cookie is a new cookie so check */
|
|
switch(_cookie_permission_manager_get_policy(self, inNewCookie))
|
|
{
|
|
case COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT:
|
|
case COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT_FOR_SESSION:
|
|
break;
|
|
|
|
case COOKIE_PERMISSION_MANAGER_POLICY_UNDETERMINED:
|
|
/* Fallthrough!
|
|
* The problem here is that we don't know the view to ask user
|
|
* for policy to follow for this cookie domain. Therefore we
|
|
* delete the cookie from jar and assume that we will be asked
|
|
* again in _cookie_permission_manager_on_response_received().
|
|
*/
|
|
|
|
default:
|
|
soup_cookie_jar_delete_cookie(inCookieJar, inNewCookie);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* We received the HTTP headers of the request and it contains cookie-managing headers */
|
|
static void _cookie_permission_manager_on_response_received(WebKitWebView *inView,
|
|
WebKitWebFrame *inFrame,
|
|
WebKitWebResource *inResource,
|
|
WebKitNetworkResponse *inResponse,
|
|
gpointer inUserData)
|
|
{
|
|
g_return_if_fail(IS_COOKIE_PERMISSION_MANAGER(inUserData));
|
|
|
|
CookiePermissionManager *self=COOKIE_PERMISSION_MANAGER(inUserData);
|
|
CookiePermissionManagerPrivate *priv=self->priv;
|
|
GSList *newCookies, *cookie;
|
|
GSList *unknownCookies=NULL, *acceptedCookies=NULL;
|
|
SoupURI *firstParty;
|
|
SoupCookieJarAcceptPolicy cookiePolicy;
|
|
gint unknownCookiesPolicy;
|
|
SoupMessage *message;
|
|
|
|
/* If policy is to deny all cookies return immediately */
|
|
cookiePolicy=soup_cookie_jar_get_accept_policy(priv->cookieJar);
|
|
if(cookiePolicy==SOUP_COOKIE_JAR_ACCEPT_NEVER) return;
|
|
|
|
/* Get SoupMessage */
|
|
message=webkit_network_response_get_message(inResponse);
|
|
if(!message || !SOUP_IS_MESSAGE(message)) return;
|
|
|
|
/* Iterate through cookies in response and check if they should be
|
|
* blocked (remove from cookies list) or accepted (added to cookie jar).
|
|
* If we could not determine what to do collect these cookies and
|
|
* ask user
|
|
*/
|
|
newCookies=soup_cookies_from_response(message);
|
|
firstParty=soup_message_get_first_party(message);
|
|
for(cookie=newCookies; cookie; cookie=cookie->next)
|
|
{
|
|
switch(_cookie_permission_manager_get_policy(self, cookie->data))
|
|
{
|
|
case COOKIE_PERMISSION_MANAGER_POLICY_BLOCK:
|
|
soup_cookie_free(cookie->data);
|
|
break;
|
|
|
|
case COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT:
|
|
case COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT_FOR_SESSION:
|
|
if((cookiePolicy==SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY &&
|
|
firstParty!=NULL &&
|
|
firstParty->host &&
|
|
soup_cookie_domain_matches(cookie->data, firstParty->host)) ||
|
|
cookiePolicy==SOUP_COOKIE_JAR_ACCEPT_ALWAYS)
|
|
{
|
|
acceptedCookies=g_slist_prepend(acceptedCookies, cookie->data);
|
|
}
|
|
else soup_cookie_free(cookie->data);
|
|
break;
|
|
|
|
case COOKIE_PERMISSION_MANAGER_POLICY_UNDETERMINED:
|
|
default:
|
|
if((cookiePolicy==SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY &&
|
|
firstParty!=NULL &&
|
|
firstParty->host &&
|
|
soup_cookie_domain_matches(cookie->data, firstParty->host)) ||
|
|
cookiePolicy==SOUP_COOKIE_JAR_ACCEPT_ALWAYS)
|
|
{
|
|
unknownCookies=g_slist_prepend(unknownCookies, cookie->data);
|
|
}
|
|
else soup_cookie_free(cookie->data);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Prepending an item to list is the fastest method but the order of cookies
|
|
* is reversed now and may be added to cookie jar in the wrong order. So we
|
|
* need to reverse list now of both - undetermined and accepted cookies
|
|
*/
|
|
unknownCookies=g_slist_reverse(unknownCookies);
|
|
acceptedCookies=g_slist_reverse(acceptedCookies);
|
|
|
|
/* Ask user for his decision what to do with cookies whose policy is undetermined
|
|
* But only ask if there is any undetermined one
|
|
*/
|
|
if(g_slist_length(unknownCookies)>0)
|
|
{
|
|
/* Get view */
|
|
MidoriView *view;
|
|
|
|
view=MIDORI_VIEW(g_object_get_data(G_OBJECT(inView), "midori-view"));
|
|
|
|
/* Ask for user's decision */
|
|
unknownCookiesPolicy=_cookie_permission_manager_ask_for_policy(self, view, message, unknownCookies);
|
|
if(unknownCookiesPolicy==COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT ||
|
|
unknownCookiesPolicy==COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT_FOR_SESSION)
|
|
{
|
|
/* Add accepted undetermined cookies to cookie jar */
|
|
for(cookie=unknownCookies; cookie; cookie=cookie->next)
|
|
{
|
|
soup_cookie_jar_add_cookie(priv->cookieJar, (SoupCookie*)cookie->data);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Free cookies because they should be blocked */
|
|
for(cookie=unknownCookies; cookie; cookie=cookie->next)
|
|
{
|
|
soup_cookie_free((SoupCookie*)cookie->data);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Add accepted cookies to cookie jar */
|
|
for(cookie=acceptedCookies; cookie; cookie=cookie->next)
|
|
{
|
|
soup_cookie_jar_add_cookie(priv->cookieJar, (SoupCookie*)cookie->data);
|
|
}
|
|
|
|
/* Free list of cookies */
|
|
g_slist_free(unknownCookies);
|
|
g_slist_free(acceptedCookies);
|
|
g_slist_free(newCookies);
|
|
}
|
|
|
|
/* A tab to a browser was added */
|
|
static void _cookie_permission_manager_on_add_tab(CookiePermissionManager *self, MidoriView *inView, gpointer inUserData)
|
|
{
|
|
/* Listen to starting network requests */
|
|
WebKitWebView *webkitView=WEBKIT_WEB_VIEW(midori_view_get_web_view(inView));
|
|
|
|
g_object_set_data(G_OBJECT(webkitView), "midori-view", inView);
|
|
g_signal_connect(webkitView, "resource-response-received", G_CALLBACK(_cookie_permission_manager_on_response_received), self);
|
|
}
|
|
|
|
/* A browser window was added */
|
|
static void _cookie_permission_manager_on_add_browser(CookiePermissionManager *self,
|
|
MidoriBrowser *inBrowser,
|
|
gpointer inUserData)
|
|
{
|
|
GList *tabs, *iter;
|
|
|
|
/* Set up all current available tabs in browser */
|
|
tabs=midori_browser_get_tabs(inBrowser);
|
|
for(iter=tabs; iter; iter=g_list_next(iter))
|
|
{
|
|
_cookie_permission_manager_on_add_tab(self, iter->data, inBrowser);
|
|
}
|
|
g_list_free(tabs);
|
|
|
|
/* Listen to new tabs opened in browser and existing ones closed */
|
|
g_signal_connect_swapped(inBrowser, "add-tab", G_CALLBACK(_cookie_permission_manager_on_add_tab), self);
|
|
}
|
|
|
|
/* Application property has changed */
|
|
static void _cookie_permission_manager_on_application_changed(CookiePermissionManager *self)
|
|
{
|
|
CookiePermissionManagerPrivate *priv=COOKIE_PERMISSION_MANAGER(self)->priv;
|
|
GList *browsers, *iter;
|
|
|
|
/* Set up all current open browser windows */
|
|
browsers=midori_app_get_browsers(priv->application);
|
|
for(iter=browsers; iter; iter=g_list_next(iter))
|
|
{
|
|
_cookie_permission_manager_on_add_browser(self, MIDORI_BROWSER(iter->data), priv->application);
|
|
}
|
|
g_list_free(browsers);
|
|
|
|
/* Listen to new browser windows opened and existing ones closed */
|
|
g_signal_connect_swapped(priv->application, "add-browser", G_CALLBACK(_cookie_permission_manager_on_add_browser), self);
|
|
}
|
|
|
|
/* IMPLEMENTATION: GObject */
|
|
|
|
/* Finalize this object */
|
|
static void cookie_permission_manager_finalize(GObject *inObject)
|
|
{
|
|
CookiePermissionManager *self=COOKIE_PERMISSION_MANAGER(inObject);
|
|
CookiePermissionManagerPrivate *priv=self->priv;
|
|
GList *browsers, *browser;
|
|
GList *tabs, *tab;
|
|
WebKitWebView *webkitView;
|
|
|
|
/* Dispose allocated resources */
|
|
if(priv->databaseFilename)
|
|
{
|
|
g_free(priv->databaseFilename);
|
|
priv->databaseFilename=NULL;
|
|
g_object_notify_by_pspec(inObject, CookiePermissionManagerProperties[PROP_DATABASE_FILENAME]);
|
|
}
|
|
|
|
if(priv->database)
|
|
{
|
|
sqlite3_close(priv->database);
|
|
priv->database=NULL;
|
|
g_object_notify_by_pspec(inObject, CookiePermissionManagerProperties[PROP_DATABASE]);
|
|
}
|
|
|
|
g_signal_handler_disconnect(priv->cookieJar, priv->cookieJarChangedID);
|
|
g_object_steal_data(G_OBJECT(priv->cookieJar), "cookie-permission-manager");
|
|
|
|
g_signal_handlers_disconnect_by_data(priv->application, self);
|
|
|
|
browsers=midori_app_get_browsers(priv->application);
|
|
for(browser=browsers; browser; browser=g_list_next(browser))
|
|
{
|
|
g_signal_handlers_disconnect_by_data(browser->data, self);
|
|
|
|
tabs=midori_browser_get_tabs(MIDORI_BROWSER(browser->data));
|
|
for(tab=tabs; tab; tab=g_list_next(tab))
|
|
{
|
|
webkitView=WEBKIT_WEB_VIEW(midori_view_get_web_view(MIDORI_VIEW(tab->data)));
|
|
g_signal_handlers_disconnect_by_data(webkitView, self);
|
|
}
|
|
g_list_free(tabs);
|
|
}
|
|
g_list_free(browsers);
|
|
|
|
/* Call parent's class finalize method */
|
|
G_OBJECT_CLASS(cookie_permission_manager_parent_class)->finalize(inObject);
|
|
}
|
|
|
|
/* Set/get properties */
|
|
static void cookie_permission_manager_set_property(GObject *inObject,
|
|
guint inPropID,
|
|
const GValue *inValue,
|
|
GParamSpec *inSpec)
|
|
{
|
|
CookiePermissionManager *self=COOKIE_PERMISSION_MANAGER(inObject);
|
|
|
|
switch(inPropID)
|
|
{
|
|
/* Construct-only properties */
|
|
case PROP_EXTENSION:
|
|
self->priv->extension=g_value_get_object(inValue);
|
|
_cookie_permission_manager_open_database(self);
|
|
break;
|
|
|
|
case PROP_APPLICATION:
|
|
self->priv->application=g_value_get_object(inValue);
|
|
_cookie_permission_manager_on_application_changed(self);
|
|
break;
|
|
|
|
case PROP_ASK_FOR_UNKNOWN_POLICY:
|
|
cookie_permission_manager_set_ask_for_unknown_policy(self, g_value_get_boolean(inValue));
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void cookie_permission_manager_get_property(GObject *inObject,
|
|
guint inPropID,
|
|
GValue *outValue,
|
|
GParamSpec *inSpec)
|
|
{
|
|
CookiePermissionManager *self=COOKIE_PERMISSION_MANAGER(inObject);
|
|
|
|
switch(inPropID)
|
|
{
|
|
case PROP_EXTENSION:
|
|
g_value_set_object(outValue, self->priv->extension);
|
|
break;
|
|
|
|
case PROP_APPLICATION:
|
|
g_value_set_object(outValue, self->priv->application);
|
|
break;
|
|
|
|
case PROP_DATABASE:
|
|
g_value_set_pointer(outValue, self->priv->database);
|
|
break;
|
|
|
|
case PROP_DATABASE_FILENAME:
|
|
g_value_set_string(outValue, self->priv->databaseFilename);
|
|
break;
|
|
|
|
case PROP_ASK_FOR_UNKNOWN_POLICY:
|
|
g_value_set_boolean(outValue, self->priv->askForUnknownPolicy);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Class initialization
|
|
* Override functions in parent classes and define properties and signals
|
|
*/
|
|
static void cookie_permission_manager_class_init(CookiePermissionManagerClass *klass)
|
|
{
|
|
GObjectClass *gobjectClass=G_OBJECT_CLASS(klass);
|
|
|
|
/* Override functions */
|
|
gobjectClass->finalize=cookie_permission_manager_finalize;
|
|
gobjectClass->set_property=cookie_permission_manager_set_property;
|
|
gobjectClass->get_property=cookie_permission_manager_get_property;
|
|
|
|
/* Set up private structure */
|
|
g_type_class_add_private(klass, sizeof(CookiePermissionManagerPrivate));
|
|
|
|
/* Define properties */
|
|
CookiePermissionManagerProperties[PROP_EXTENSION]=
|
|
g_param_spec_object("extension",
|
|
_("Extension instance"),
|
|
_("The Midori extension instance for this extension"),
|
|
MIDORI_TYPE_EXTENSION,
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
|
|
|
CookiePermissionManagerProperties[PROP_APPLICATION]=
|
|
g_param_spec_object("application",
|
|
_("Application instance"),
|
|
_("The Midori application instance this extension belongs to"),
|
|
MIDORI_TYPE_APP,
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
|
|
|
CookiePermissionManagerProperties[PROP_DATABASE]=
|
|
g_param_spec_pointer("database",
|
|
_("Database instance"),
|
|
_("Pointer to sqlite database instance used by this extension"),
|
|
G_PARAM_READABLE);
|
|
|
|
CookiePermissionManagerProperties[PROP_DATABASE_FILENAME]=
|
|
g_param_spec_string("database-filename",
|
|
_("Database path"),
|
|
_("Path to sqlite database instance used by this extension"),
|
|
NULL,
|
|
G_PARAM_READABLE);
|
|
|
|
CookiePermissionManagerProperties[PROP_ASK_FOR_UNKNOWN_POLICY]=
|
|
g_param_spec_boolean("ask-for-unknown-policy",
|
|
_("Ask for unknown policy"),
|
|
_("If true this extension ask for policy for every unknown domain."
|
|
"If false this extension uses the global cookie policy set in Midori settings."),
|
|
TRUE,
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
|
|
|
|
g_object_class_install_properties(gobjectClass, PROP_LAST, CookiePermissionManagerProperties);
|
|
}
|
|
|
|
/* Object initialization
|
|
* Create private structure and set up default values
|
|
*/
|
|
static void cookie_permission_manager_init(CookiePermissionManager *self)
|
|
{
|
|
CookiePermissionManagerPrivate *priv;
|
|
|
|
priv=self->priv=COOKIE_PERMISSION_MANAGER_GET_PRIVATE(self);
|
|
|
|
/* Set up default values */
|
|
priv->database=NULL;
|
|
priv->databaseFilename=NULL;
|
|
priv->askForUnknownPolicy=TRUE;
|
|
|
|
/* Hijack session's cookie jar to handle cookies requests on our own in HTTP streams
|
|
* but remember old handlers to restore them on deactivation
|
|
*/
|
|
priv->session=webkit_get_default_session();
|
|
priv->cookieJar=SOUP_COOKIE_JAR(soup_session_get_feature(priv->session, SOUP_TYPE_COOKIE_JAR));
|
|
priv->featureIface=SOUP_SESSION_FEATURE_GET_CLASS(priv->cookieJar);
|
|
g_object_set_data(G_OBJECT(priv->cookieJar), "cookie-permission-manager", self);
|
|
|
|
/* Listen to changed cookies set or changed by other sources like javascript */
|
|
priv->cookieJarChangedID=g_signal_connect_swapped(priv->cookieJar, "changed", G_CALLBACK(_cookie_permission_manager_on_cookie_changed), self);
|
|
}
|
|
|
|
/* Implementation: Public API */
|
|
|
|
/* Create new object */
|
|
CookiePermissionManager* cookie_permission_manager_new(MidoriExtension *inExtension, MidoriApp *inApp)
|
|
{
|
|
return(g_object_new(TYPE_COOKIE_PERMISSION_MANAGER,
|
|
"extension", inExtension,
|
|
"application", inApp,
|
|
NULL));
|
|
}
|
|
|
|
/* Get/set policy to ask for policy if unknown for a domain */
|
|
gboolean cookie_permission_manager_get_ask_for_unknown_policy(CookiePermissionManager *self)
|
|
{
|
|
g_return_val_if_fail(IS_COOKIE_PERMISSION_MANAGER(self), FALSE);
|
|
|
|
return(self->priv->askForUnknownPolicy);
|
|
}
|
|
|
|
void cookie_permission_manager_set_ask_for_unknown_policy(CookiePermissionManager *self, gboolean inDoAsk)
|
|
{
|
|
g_return_if_fail(IS_COOKIE_PERMISSION_MANAGER(self));
|
|
|
|
if(inDoAsk!=self->priv->askForUnknownPolicy)
|
|
{
|
|
self->priv->askForUnknownPolicy=inDoAsk;
|
|
midori_extension_set_boolean(self->priv->extension, "ask-for-unknown-policy", inDoAsk);
|
|
g_object_notify_by_pspec(G_OBJECT(self), CookiePermissionManagerProperties[PROP_ASK_FOR_UNKNOWN_POLICY]);
|
|
}
|
|
}
|
|
|
|
/************************************************************************************/
|
|
|
|
/* Implementation: Enumeration */
|
|
GType cookie_permission_manager_policy_get_type(void)
|
|
{
|
|
static volatile gsize g_define_type_id__volatile=0;
|
|
|
|
if(g_once_init_enter(&g_define_type_id__volatile))
|
|
{
|
|
static const GEnumValue values[]=
|
|
{
|
|
{ COOKIE_PERMISSION_MANAGER_POLICY_UNDETERMINED, "COOKIE_PERMISSION_MANAGER_POLICY_UNDETERMINED", N_("Undetermined") },
|
|
{ COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT, "COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT", N_("Accept") },
|
|
{ COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT_FOR_SESSION, "COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT_FOR_SESSION", N_("Accept for session") },
|
|
{ COOKIE_PERMISSION_MANAGER_POLICY_BLOCK, "COOKIE_PERMISSION_MANAGER_POLICY_BLOCK", N_("Block") },
|
|
{ 0, NULL, NULL }
|
|
};
|
|
|
|
GType g_define_type_id=g_enum_register_static(g_intern_static_string("CookiePermissionManagerPolicy"), values);
|
|
g_once_init_leave(&g_define_type_id__volatile, g_define_type_id);
|
|
}
|
|
|
|
return(g_define_type_id__volatile);
|
|
}
|