summaryrefslogtreecommitdiff
path: root/data/extensions/spyblock@gnu.org/lib
diff options
context:
space:
mode:
Diffstat (limited to 'data/extensions/spyblock@gnu.org/lib')
-rw-r--r--data/extensions/spyblock@gnu.org/lib/Public.jsm202
-rw-r--r--data/extensions/spyblock@gnu.org/lib/antiadblockInit.js98
-rw-r--r--data/extensions/spyblock@gnu.org/lib/appSupport.js851
-rw-r--r--data/extensions/spyblock@gnu.org/lib/child/bootstrap.js97
-rw-r--r--data/extensions/spyblock@gnu.org/lib/child/contentPolicy.js518
-rw-r--r--data/extensions/spyblock@gnu.org/lib/child/contextMenu.js137
-rw-r--r--data/extensions/spyblock@gnu.org/lib/child/dataCollector.js108
-rw-r--r--data/extensions/spyblock@gnu.org/lib/child/elemHide.js403
-rw-r--r--data/extensions/spyblock@gnu.org/lib/child/elemHideEmulation.js118
-rw-r--r--data/extensions/spyblock@gnu.org/lib/child/flasher.js99
-rw-r--r--data/extensions/spyblock@gnu.org/lib/child/main.js31
-rw-r--r--data/extensions/spyblock@gnu.org/lib/child/objectTabs.js405
-rw-r--r--data/extensions/spyblock@gnu.org/lib/child/requestNotifier.js444
-rw-r--r--data/extensions/spyblock@gnu.org/lib/child/subscribeLinks.js118
-rw-r--r--data/extensions/spyblock@gnu.org/lib/child/utils.js141
-rw-r--r--data/extensions/spyblock@gnu.org/lib/common.js53
-rw-r--r--data/extensions/spyblock@gnu.org/lib/contentPolicy.js415
-rw-r--r--data/extensions/spyblock@gnu.org/lib/coreUtils.js36
-rw-r--r--data/extensions/spyblock@gnu.org/lib/customizableUI.js320
-rw-r--r--data/extensions/spyblock@gnu.org/lib/downloader.js421
-rw-r--r--data/extensions/spyblock@gnu.org/lib/elemHide.js396
-rw-r--r--data/extensions/spyblock@gnu.org/lib/elemHideEmulation.js81
-rw-r--r--data/extensions/spyblock@gnu.org/lib/elemHideFF.js106
-rw-r--r--data/extensions/spyblock@gnu.org/lib/events.js106
-rw-r--r--data/extensions/spyblock@gnu.org/lib/ext_background.js79
-rw-r--r--data/extensions/spyblock@gnu.org/lib/ext_common.js124
-rw-r--r--data/extensions/spyblock@gnu.org/lib/filterClasses.js1061
-rw-r--r--data/extensions/spyblock@gnu.org/lib/filterListener.js320
-rw-r--r--data/extensions/spyblock@gnu.org/lib/filterNotifier.js86
-rw-r--r--data/extensions/spyblock@gnu.org/lib/filterStorage.js786
-rw-r--r--data/extensions/spyblock@gnu.org/lib/io.js279
-rw-r--r--data/extensions/spyblock@gnu.org/lib/keySelector.js227
-rw-r--r--data/extensions/spyblock@gnu.org/lib/legacyIO.js335
-rw-r--r--data/extensions/spyblock@gnu.org/lib/main.js84
-rw-r--r--data/extensions/spyblock@gnu.org/lib/matcher.js458
-rw-r--r--data/extensions/spyblock@gnu.org/lib/messageResponder.js431
-rw-r--r--data/extensions/spyblock@gnu.org/lib/messaging.js316
-rw-r--r--data/extensions/spyblock@gnu.org/lib/notification.js475
-rw-r--r--data/extensions/spyblock@gnu.org/lib/objectTabs.js113
-rw-r--r--data/extensions/spyblock@gnu.org/lib/prefs.js197
-rw-r--r--data/extensions/spyblock@gnu.org/lib/requestNotifier.js209
-rw-r--r--data/extensions/spyblock@gnu.org/lib/subscriptionClasses.js584
-rw-r--r--data/extensions/spyblock@gnu.org/lib/sync.js459
-rw-r--r--data/extensions/spyblock@gnu.org/lib/synchronizer.js365
-rw-r--r--data/extensions/spyblock@gnu.org/lib/ui.js1906
-rw-r--r--data/extensions/spyblock@gnu.org/lib/utils.js751
-rw-r--r--data/extensions/spyblock@gnu.org/lib/whitelisting.js46
-rw-r--r--data/extensions/spyblock@gnu.org/lib/windowObserver.js99
48 files changed, 0 insertions, 15494 deletions
diff --git a/data/extensions/spyblock@gnu.org/lib/Public.jsm b/data/extensions/spyblock@gnu.org/lib/Public.jsm
deleted file mode 100644
index ecd7e95..0000000
--- a/data/extensions/spyblock@gnu.org/lib/Public.jsm
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * @fileOverview Public Adblock Plus API.
- */
-
-var EXPORTED_SYMBOLS = ["AdblockPlus"];
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cr = Components.results;
-const Cu = Components.utils;
-
-Cu.import("resource://gre/modules/Services.jsm");
-
-function require(module)
-{
- let result = {};
- result.wrappedJSObject = result;
- Services.obs.notifyObservers(result, "adblockplus-require", module);
- return result.exports;
-}
-
-let {FilterStorage} = require("filterStorage");
-let {Filter} = require("filterClasses");
-let {Subscription, SpecialSubscription, RegularSubscription, DownloadableSubscription, ExternalSubscription} = require("subscriptionClasses");
-
-const externalPrefix = "~external~";
-
-/**
- * Class implementing public Adblock Plus API
- * @class
- */
-var AdblockPlus =
-{
- /**
- * Returns current subscription count
- * @type Integer
- */
- get subscriptionCount()
- {
- return FilterStorage.subscriptions.length;
- },
-
- /**
- * Gets a subscription by its URL
- */
- getSubscription: function(/**String*/ id) /**IAdblockPlusSubscription*/
- {
- if (id in FilterStorage.knownSubscriptions)
- return createSubscriptionWrapper(FilterStorage.knownSubscriptions[id]);
-
- return null;
- },
-
- /**
- * Gets a subscription by its position in the list
- */
- getSubscriptionAt: function(/**Integer*/ index) /**IAdblockPlusSubscription*/
- {
- if (index < 0 || index >= FilterStorage.subscriptions.length)
- return null;
-
- return createSubscriptionWrapper(FilterStorage.subscriptions[index]);
- },
-
- /**
- * Updates an external subscription and creates it if necessary
- */
- updateExternalSubscription: function(/**String*/ id, /**String*/ title, /**Array of Filter*/ filters) /**String*/
- {
- if (id.substr(0, externalPrefix.length) != externalPrefix)
- id = externalPrefix + id;
- let subscription = Subscription.knownSubscriptions[id];
- if (typeof subscription == "undefined")
- subscription = new ExternalSubscription(id, title);
-
- subscription.lastDownload = parseInt(new Date().getTime() / 1000);
-
- let newFilters = [];
- for (let filter of filters)
- {
- filter = Filter.fromText(Filter.normalize(filter));
- if (filter)
- newFilters.push(filter);
- }
-
- if (id in FilterStorage.knownSubscriptions)
- FilterStorage.updateSubscriptionFilters(subscription, newFilters);
- else
- {
- subscription.filters = newFilters;
- FilterStorage.addSubscription(subscription);
- }
-
- return id;
- },
-
- /**
- * Removes an external subscription by its identifier
- */
- removeExternalSubscription: function(/**String*/ id) /**Boolean*/
- {
- if (id.substr(0, externalPrefix.length) != externalPrefix)
- id = externalPrefix + id;
- if (!(id in FilterStorage.knownSubscriptions))
- return false;
-
- FilterStorage.removeSubscription(FilterStorage.knownSubscriptions[id]);
- return true;
- },
-
- /**
- * Adds user-defined filters to the list
- */
- addPatterns: function(/**Array of String*/ filters)
- {
- for (let filter of filters)
- {
- filter = Filter.fromText(Filter.normalize(filter));
- if (filter)
- {
- filter.disabled = false;
- FilterStorage.addFilter(filter);
- }
- }
- },
-
- /**
- * Removes user-defined filters from the list
- */
- removePatterns: function(/**Array of String*/ filters)
- {
- for (let filter of filters)
- {
- filter = Filter.fromText(Filter.normalize(filter));
- if (filter)
- FilterStorage.removeFilter(filter);
- }
- },
-
- /**
- * Returns installed Adblock Plus version
- */
- getInstalledVersion: function() /**String*/
- {
- return require("info").addonVersion;
- },
-
- /**
- * Returns source code revision this Adblock Plus build was created from (if available)
- */
- getInstalledBuild: function() /**String*/
- {
- return "";
- },
-};
-
-/**
- * Wraps a subscription into IAdblockPlusSubscription structure.
- */
-function createSubscriptionWrapper(/**Subscription*/ subscription) /**IAdblockPlusSubscription*/
-{
- if (!subscription)
- return null;
-
- return {
- url: subscription.url,
- special: subscription instanceof SpecialSubscription,
- title: subscription.title,
- autoDownload: true,
- disabled: subscription.disabled,
- external: subscription instanceof ExternalSubscription,
- lastDownload: subscription instanceof RegularSubscription ? subscription.lastDownload : 0,
- downloadStatus: subscription instanceof DownloadableSubscription ? subscription.downloadStatus : "synchronize_ok",
- lastModified: subscription instanceof DownloadableSubscription ? subscription.lastModified : null,
- expires: subscription instanceof DownloadableSubscription ? subscription.expires : 0,
- getPatterns: function()
- {
- let result = subscription.filters.map(function(filter)
- {
- return filter.text;
- });
- return result;
- }
- };
-}
diff --git a/data/extensions/spyblock@gnu.org/lib/antiadblockInit.js b/data/extensions/spyblock@gnu.org/lib/antiadblockInit.js
deleted file mode 100644
index c5b845f..0000000
--- a/data/extensions/spyblock@gnu.org/lib/antiadblockInit.js
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-"use strict";
-
-const {Prefs} = require("prefs");
-const {ActiveFilter} = require("filterClasses");
-const {FilterStorage} = require("filterStorage");
-const {FilterNotifier} = require("filterNotifier");
-const {Subscription} = require("subscriptionClasses");
-const {Notification} = require("notification");
-
-let ext;
-if (typeof window != "undefined" && window.ext)
- ({ext} = window);
-else
- ext = require("ext_background");
-
-exports.initAntiAdblockNotification = function initAntiAdblockNotification()
-{
- let notification = {
- id: "antiadblock",
- type: "question",
- title: ext.i18n.getMessage("notification_antiadblock_title"),
- message: ext.i18n.getMessage("notification_antiadblock_message"),
- urlFilters: []
- };
-
- function notificationListener(approved)
- {
- let subscription = Subscription.fromURL(Prefs.subscriptions_antiadblockurl);
- if (subscription.url in FilterStorage.knownSubscriptions)
- subscription.disabled = !approved;
- }
-
- function addAntiAdblockNotification(subscription)
- {
- let urlFilters = [];
- for (let filter of subscription.filters)
- {
- if (filter instanceof ActiveFilter)
- {
- for (let domain in filter.domains)
- {
- let urlFilter = "||" + domain + "^$document";
- if (domain && filter.domains[domain] &&
- urlFilters.indexOf(urlFilter) == -1)
- urlFilters.push(urlFilter);
- }
- }
- }
- notification.urlFilters = urlFilters;
- Notification.addNotification(notification);
- Notification.addQuestionListener(notification.id, notificationListener);
- }
-
- function removeAntiAdblockNotification()
- {
- Notification.removeNotification(notification);
- Notification.removeQuestionListener(notification.id, notificationListener);
- }
-
- let antiAdblockSubscription = Subscription.fromURL(
- Prefs.subscriptions_antiadblockurl
- );
- if (antiAdblockSubscription.lastDownload && antiAdblockSubscription.disabled)
- addAntiAdblockNotification(antiAdblockSubscription);
-
- function onSubscriptionChange(subscription)
- {
- let url = Prefs.subscriptions_antiadblockurl;
- if (url != subscription.url)
- return;
-
- if (url in FilterStorage.knownSubscriptions && subscription.disabled)
- addAntiAdblockNotification(subscription);
- else
- removeAntiAdblockNotification();
- }
-
- FilterNotifier.on("subscription.updated", onSubscriptionChange);
- FilterNotifier.on("subscription.removed", onSubscriptionChange);
- FilterNotifier.on("subscription.disabled", onSubscriptionChange);
-};
diff --git a/data/extensions/spyblock@gnu.org/lib/appSupport.js b/data/extensions/spyblock@gnu.org/lib/appSupport.js
deleted file mode 100644
index ba8fdd1..0000000
--- a/data/extensions/spyblock@gnu.org/lib/appSupport.js
+++ /dev/null
@@ -1,851 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * @fileOverview Various application-specific functions.
- */
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/AddonManager.jsm");
-
-/**
- * Checks whether an application window is known and should get Adblock Plus
- * user interface elements.
- * @result Boolean
- */
-exports.isKnownWindow = (/**Window*/ window) => false;
-
-/**
- * HACK: In some applications the window finishes initialization during load
- * event processing which makes an additional delay necessary. This flag
- * indicates that.
- * @type Boolean
- */
-exports.delayInitialization = false;
-
-/**
- * Retrieves the browser element for an application window.
- * @type function(window)
- */
-exports.getBrowser = null;
-
-/**
- * Adds a new browser tab in the given application window.
- * @type function(window, url, event)
- */
-exports.addTab = null;
-
-/**
- * Retrieves the current browser location for an application window.
- */
-exports.getCurrentLocation = function getCurrentLocation(/**Window*/ window) /**nsIURI|String*/
-{
- let browser = (exports.getBrowser ? exports.getBrowser(window) : null);
- return (browser ? browser.currentURI : null);
-}
-
-
-/**
- * The ID (or a list of possible IDs) of the content area context menu.
- * @type String|String[]
- */
-exports.contentContextMenu = null;
-
-/**
- * Determines the default placement of the toolbar icon via object properties
- * parent, before and after.
- * @type Object
- */
-exports.defaultToolbarPosition = null;
-
-/**
- * The properties parent, before, after determine the placement of the status
- * bar icon.
- * @type Object
- */
-exports.statusbarPosition = null;
-
-/**
- * The properties parent, before, after determine the placement of the Tools
- * submenu.
- * @type Object
- */
-exports.toolsMenu = null;
-
-/**
- * Maps windows to their bottom bar info.
- */
-let bottomBars = new WeakMap();
-
-/**
- * Adds a bottom bar to the application window.
- * @type function(window, element)
- */
-exports.addBottomBar = null;
-
-function _addBottomBar(window, parent, element)
-{
- if (bottomBars.has(window) || !parent)
- return null;
-
- let bar = {elements: []};
- for (let child = element.firstElementChild; child; child = child.nextElementSibling)
- {
- let clone = child.cloneNode(true);
- parent.appendChild(clone);
- bar.elements.push(clone);
- }
-
- bottomBars.set(window, bar);
- return bar;
-};
-
-/**
- * Removes the bottom bar from the application window.
- * @type function(window)
- */
-exports.removeBottomBar = null;
-
-function _removeBottomBar(window)
-{
- if (!bottomBars.has(window))
- return null;
-
- let bar = bottomBars.get(window);
- for (let i = 0; i < bar.elements.length; i++)
- if (bar.elements[i].parentNode)
- bar.elements[i].parentNode.removeChild(bar.elements[i]);
-
- bottomBars.delete(window);
- return bar;
-};
-
-/**
- * Maps windows to a list of progress listeners.
- */
-let progressListeners = new WeakMap();
-
-/**
- * Makes sure that a function is called whenever the displayed browser location changes.
- */
-exports.addBrowserLocationListener = function addBrowserLocationListener(/**Window*/ window, /**Function*/ callback, /**Boolean*/ ignoreSameDoc)
-{
- let browser = (exports.getBrowser ? exports.getBrowser(window) : null);
- if (browser)
- {
- let dummy = function() {};
- let progressListener =
- {
- callback: callback,
- onLocationChange: function(progress, request, uri, flags)
- {
- if (!ignoreSameDoc || !flags || !(flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT))
- this.callback();
- },
- onProgressChange: dummy,
- onSecurityChange: dummy,
- onStateChange: dummy,
- onStatusChange: dummy,
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference])
- };
- browser.addProgressListener(progressListener);
-
- if (progressListeners.has(window))
- progressListeners.get(window).push(progressListener);
- else
- progressListeners.set(window, [progressListener]);
- }
-};
-
-/**
- * Removes a location listener registered for a window.
- */
-exports.removeBrowserLocationListener = function removeBrowserLocationListener(/**Window*/ window, /**Function*/ callback)
-{
- if (!progressListeners.has(window))
- return;
-
- let browser = (exports.getBrowser ? exports.getBrowser(window) : null);
- let listeners = progressListeners.get(window);
- for (let i = 0; i < listeners.length; i++)
- {
- if (listeners[i].callback == callback)
- {
- if (browser)
- browser.removeProgressListener(listeners[i]);
- listeners.splice(i--, 1);
- }
- }
-};
-
-/**
- * Removes all location listeners registered for a window, to be called on
- * cleanup.
- */
-exports.removeBrowserLocationListeners = function removeBrowserLocationListeners(/**Window*/ window)
-{
- if (!progressListeners.has(window))
- return;
-
- let browser = (exports.getBrowser ? exports.getBrowser(window) : null);
- if (browser)
- {
- let listeners = progressListeners.get(window);
- for (let i = 0; i < listeners.length; i++)
- browser.removeProgressListener(listeners[i]);
- }
- progressListeners.delete(window);
-};
-
-let {application} = require("info");
-switch (application)
-{
- case "firefox":
- {
- exports.isKnownWindow = function ff_isKnownWindow(window)
- {
- return (window.document.documentElement.getAttribute("windowtype") == "navigator:browser");
- };
-
- exports.getBrowser = (window) => window.gBrowser;
-
- exports.addTab = function ff_addTab(window, url, event)
- {
- if (event)
- window.openNewTabWith(url, null, null, event, false);
- else
- window.gBrowser.loadOneTab(url, {inBackground: false});
- };
-
- exports.contentContextMenu = "contentAreaContextMenu";
-
- exports.defaultToolbarPosition = {
- parent: "nav-bar"
- };
-
- exports.toolsMenu = {
- parent: "menu_ToolsPopup"
- };
-
- exports.addBottomBar = function fx_addBottomBar(window, element)
- {
- let bar = _addBottomBar(window, window.document.getElementById("appcontent"), element);
- if (bar)
- {
- let display = window.document.getElementById("statusbar-display");
- bar.changedFixed = display && !display.hasAttribute("fixed");
- if (bar.changedFixed)
- display.setAttribute("fixed", "true");
- }
- };
-
- exports.removeBottomBar = function fx_removeBottomBar(window)
- {
- let bar = _removeBottomBar(window);
- if (bar && bar.changedFixed)
- window.document.getElementById("statusbar-display").removeAttribute("fixed");
- };
-
- break;
- }
-
- case "seamonkey":
- {
- exports.isKnownWindow = function sm_isKnownWindow(window)
- {
- let type = window.document.documentElement.getAttribute("windowtype");
- return (type == "navigator:browser" || type == "mail:3pane" || type == "mail:messageWindow");
- };
-
- exports.addTab = function sm_addTab(window, url, event)
- {
- if (event || !("gBrowser" in window))
- window.openNewTabWith(url, null, null, event, false);
- else
- window.gBrowser.loadOneTab(url, {inBackground: false});
- };
-
- exports.getBrowser = function sm_getBrowser(window)
- {
- if ("gBrowser" in window)
- return window.gBrowser;
- else if ("getMessageBrowser" in window)
- return window.getMessageBrowser();
- else
- return null;
- };
-
- exports.getCurrentLocation = function sm_getCurrentLocation(window)
- {
- if ("currentHeaderData" in window && "content-base" in window.currentHeaderData)
- {
- // This is a blog entry
- return window.currentHeaderData["content-base"].headerValue;
- }
- else if ("currentHeaderData" in window && "from" in window.currentHeaderData)
- {
- // This is a mail/newsgroup entry
- try
- {
- let headerParser = Cc["@mozilla.org/messenger/headerparser;1"].getService(Ci.nsIMsgHeaderParser);
- let emailAddress = headerParser.extractHeaderAddressMailboxes(window.currentHeaderData.from.headerValue);
- return "mailto:" + emailAddress.replace(/^[\s"]+/, "").replace(/[\s"]+$/, "").replace(/\s/g, "%20");
- }
- catch(e)
- {
- return null;
- }
- }
- else
- {
- let browser = exports.getBrowser(window);
- return (browser ? browser.currentURI : null);
- }
- };
-
- // for Seamonkey we have to ignore same document flag because of
- // bug #1035171 (https://bugzilla.mozilla.org/show_bug.cgi?id=1035171)
- let origAddBrowserLocationListener = exports.addBrowserLocationListener;
- exports.addBrowserLocationListener = function sm_addBrowserLocationListener(window, callback, ignoreSameDoc)
- {
- origAddBrowserLocationListener(window, callback, false);
- };
-
- exports.contentContextMenu = ["contentAreaContextMenu", "mailContext"];
-
- exports.defaultToolbarPosition = {
- parent: ["PersonalToolbar", "msgToolbar"],
- before: ["bookmarks-button", "button-junk"]
- };
-
- exports.statusbarPosition = {
- parent: "status-bar"
- };
-
- exports.toolsMenu = {
- parent: "taskPopup",
- after: "downloadmgr"
- };
-
- exports.addBottomBar = function sm_addBottomBar(window, element)
- {
- _addBottomBar(window, window.document.getElementById("appcontent") || window.document.getElementById("messagepanebox"), element);
- };
-
- exports.removeBottomBar = _removeBottomBar;
-
- break;
- }
-
- case "thunderbird":
- {
- exports.isKnownWindow = function tb_isKnownWindow(window)
- {
- let type = window.document.documentElement.getAttribute("windowtype");
- return (type == "mail:3pane" || type == "mail:messageWindow");
- };
-
- exports.delayInitialization = true;
-
- exports.getBrowser = (window) => window.getBrowser();
-
- exports.addTab = function tb_addTab(window, url, event)
- {
- let tabmail = window.document.getElementById("tabmail");
- if (!tabmail)
- {
- let wnd = Services.wm.getMostRecentWindow("mail:3pane");
- if (window)
- tabmail = wnd.document.getElementById("tabmail");
- }
-
- if (tabmail)
- tabmail.openTab("contentTab", {contentPage: url});
- else
- {
- window.openDialog("chrome://messenger/content/", "_blank",
- "chrome,dialog=no,all", null,
- {
- tabType: "contentTab",
- tabParams: {contentPage: url}
- });
- }
- };
-
- exports.contentContextMenu = ["mailContext", "pageContextMenu"];
-
- exports.defaultToolbarPosition = {
- parent: "header-view-toolbar",
- before: "hdrReplyButton",
- addClass: "msgHeaderView-button"
- };
-
- exports.statusbarPosition = {
- parent: "status-bar"
- };
-
- exports.toolsMenu = {
- parent: "taskPopup",
- after: "javaScriptConsole"
- };
-
- exports.getCurrentLocation = function getCurrentLocation(window)
- {
- let browser = exports.getBrowser(window);
- if (!browser)
- return null;
-
- if (browser.id == "messagepane" && "currentHeaderData" in window && "content-base" in window.currentHeaderData)
- {
- // This is a blog entry
- return window.currentHeaderData["content-base"].headerValue;
- }
- else if (browser.id == "messagepane" && "currentHeaderData" in window && "from" in window.currentHeaderData)
- {
- // This is a mail/newsgroup entry
- try
- {
- let headerParser = Cc["@mozilla.org/messenger/headerparser;1"].getService(Ci.nsIMsgHeaderParser);
- let emailAddress = headerParser.extractHeaderAddressMailboxes(window.currentHeaderData.from.headerValue);
- return "mailto:" + emailAddress.replace(/^[\s"]+/, "").replace(/[\s"]+$/, "").replace(/\s/g, "%20");
- }
- catch(e)
- {
- return null;
- }
- }
- else
- return browser.currentURI;
- }
-
- exports.addBottomBar = function tb_addBottomBar(window, element)
- {
- let browser = exports.getBrowser(window);
- if (!browser)
- return;
-
- let parent = window.document.getElementById("messagepanebox");
- if (!parent || !(parent.compareDocumentPosition(browser) & Ci.nsIDOMNode.DOCUMENT_POSITION_CONTAINED_BY))
- parent = browser.parentNode;
-
- _addBottomBar(window, parent, element);
- };
-
- exports.removeBottomBar = _removeBottomBar;
-
- let BrowserChangeListener = function(window, callback)
- {
- this.window = window;
- this.callback = callback;
- this.onSelect = this.onSelect.bind(this);
- this.attach();
- };
- BrowserChangeListener.prototype = {
- window: null,
- callback: null,
- currentBrowser: null,
-
- setBrowser: function(browser)
- {
- if (browser != this.currentBrowser)
- {
- let oldBrowser = this.currentBrowser;
- this.currentBrowser = browser;
- this.callback(oldBrowser, browser);
- }
- },
-
- onSelect: function()
- {
- this.setBrowser(exports.getBrowser(this.window));
- },
-
- attach: function()
- {
- this.onSelect();
-
- let tabmail = this.window.document.getElementById("tabmail");
- if (tabmail)
- tabmail.tabContainer.addEventListener("select", this.onSelect, false);
- },
- detach: function()
- {
- let tabmail = this.window.document.getElementById("tabmail");
- if (tabmail)
- tabmail.tabContainer.removeEventListener("select", this.onSelect, false);
-
- this.setBrowser(null);
- }
- };
-
- exports.addBrowserLocationListener = function(/**Window*/ window, /**Function*/ callback, /**Boolean*/ ignoreSameDoc)
- {
- if (progressListeners.has(window))
- {
- progressListeners.get(window).locationCallbacks.push(callback);
- return;
- }
-
- let callbacks = [callback];
- let dummy = function() {};
- let progressListener =
- {
- onLocationChange: function(progress, request, uri, flags)
- {
- if (!ignoreSameDoc || !flags || !(flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT))
- for (let i = 0; i < callbacks.length; i++)
- callbacks[i]();
- },
- onProgressChange: dummy,
- onSecurityChange: dummy,
- onStateChange: dummy,
- onStatusChange: dummy,
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference])
- };
- let messageListener =
- {
- onStartHeaders: dummy,
- onEndHeaders: function()
- {
- let browser = exports.getBrowser(window);
- if (browser.id == "messagepane")
- for (let i = 0; i < callbacks.length; i++)
- callbacks[i]();
- },
- onEndAttachments: dummy,
- onBeforeShowHeaderPane: dummy
- };
-
- let listener = new BrowserChangeListener(window, function(oldBrowser, newBrowser)
- {
- if (oldBrowser)
- oldBrowser.removeProgressListener(progressListener);
- if (newBrowser)
- newBrowser.addProgressListener(progressListener);
- progressListener.onLocationChange();
- });
- listener.locationCallbacks = callbacks;
-
- if ("gMessageListeners" in window)
- window.gMessageListeners.push(messageListener);
- listener.messageListener = messageListener;
-
- progressListeners.set(window, listener);
- };
-
- exports.removeBrowserLocationListener = function(/**Window*/ window, /**Function*/ callback)
- {
- if (!progressListeners.has(window))
- return;
-
- let callbacks = progressListeners.get(window).locationCallbacks;
- for (let i = 0; i < callbacks.length; i++)
- if (callbacks[i] == callback)
- callbacks.splice(i--, 1);
- };
-
- exports.removeBrowserLocationListeners = function(/**Window*/ window)
- {
- if (!progressListeners.has(window))
- return;
-
- let listener = progressListeners.get(window);
-
- let messageListener = listener.messageListener;
- let index = ("gMessageListeners" in window ? window.gMessageListeners.indexOf(messageListener) : -1);
- if (index >= 0)
- window.gMessageListeners.splice(index, 1);
-
- listener.detach();
- progressListeners.delete(window);
- };
-
- // Make sure to close/reopen list of blockable items when the user changes tabs
- let {WindowObserver} = require("windowObserver");
- new WindowObserver({
- listeners: new WeakMap(),
- applyToWindow: function(window)
- {
- if (!exports.isKnownWindow(window) || this.listeners.has(window))
- return;
-
- let {Utils} = require("utils");
- Utils.runAsync(function()
- {
- let listener = new BrowserChangeListener(window, function(oldBrowser, newBrowser)
- {
- if (bottomBars.has(window))
- {
- let {UI} = require("ui")
- UI.toggleBottombar(window);
- UI.toggleBottombar(window);
- }
- });
- this.listeners.set(window, listener);
- }.bind(this));
- },
- removeFromWindow: function(window)
- {
- if (!this.listeners.has(window))
- return;
-
- let listener = this.listeners.get(window);
- listener.detach();
- this.listeners.delete(window);
- }
- });
-
- break;
- }
-
- case "fennec2":
- case "adblockbrowser":
- {
- exports.isKnownWindow = (window) => window.document.documentElement.id == "main-window";
-
- exports.getBrowser = (window) => window.BrowserApp.selectedBrowser;
-
- exports.addTab = (window, url, event) => window.BrowserApp.addTab(url, {selected: true});
-
- let BrowserChangeListener = function(window, callback)
- {
- this.window = window;
- this.callback = callback;
- this.onSelect = this.onSelect.bind(this);
- this.attach = this.attach.bind(this);
- if (window.BrowserApp.deck)
- this.attach();
- else
- window.addEventListener("UIReady", this.attach, false);
- };
- BrowserChangeListener.prototype = {
- window: null,
- callback: null,
- currentBrowser: null,
-
- setBrowser: function(browser)
- {
- if (browser != this.currentBrowser)
- {
- let oldBrowser = this.currentBrowser;
- this.currentBrowser = browser;
- this.callback(oldBrowser, browser);
- }
- },
-
- onSelect: function()
- {
- let {Utils} = require("utils");
- Utils.runAsync(function()
- {
- this.setBrowser(exports.getBrowser(this.window));
- }.bind(this));
- },
-
- attach: function()
- {
- this.window.removeEventListener("UIReady", this.attach, false);
- this.onSelect();
- this.window.BrowserApp.deck.addEventListener("TabSelect", this.onSelect, false);
- },
- detach: function()
- {
- this.window.BrowserApp.deck.removeEventListener("TabSelect", this.onSelect, false);
-
- this.setBrowser(null);
- }
- };
-
- exports.addBrowserLocationListener = function ffn_addBrowserLocationListener(/**Window*/ window, /**Function*/ callback, /**Boolean*/ ignoreSameDoc)
- {
- if (progressListeners.has(window))
- {
- progressListeners.get(window).locationCallbacks.push(callback);
- return;
- }
-
- let callbacks = [callback];
- let dummy = function() {};
- let progressListener =
- {
- onLocationChange: function(progress, request, uri, flags)
- {
- if (!ignoreSameDoc || !flags || !(flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT))
- for (let i = 0; i < callbacks.length; i++)
- callbacks[i]();
- },
- onProgressChange: dummy,
- onSecurityChange: dummy,
- onStateChange: dummy,
- onStatusChange: dummy,
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference])
- };
-
- let listener = new BrowserChangeListener(window, function(oldBrowser, newBrowser)
- {
- if (oldBrowser && typeof oldBrowser.removeProgressListener == "function")
- oldBrowser.removeProgressListener(progressListener);
- if (newBrowser && typeof newBrowser.removeProgressListener == "function")
- newBrowser.addProgressListener(progressListener);
- progressListener.onLocationChange();
- });
- listener.locationCallbacks = callbacks;
-
- progressListeners.set(window, listener);
- };
-
- exports.removeBrowserLocationListener = function ffn_removeBrowserLocationListener(/**Window*/ window, /**Function*/ callback)
- {
- if (!progressListeners.has(window))
- return;
-
- let callbacks = progressListeners.get(window).locationCallbacks;
- for (let i = 0; i < callbacks.length; i++)
- if (callbacks[i] == callback)
- callbacks.splice(i--, 1);
- };
-
- exports.removeBrowserLocationListeners = function ffn_removeBrowserLocationListeners(/**Window*/ window)
- {
- if (!progressListeners.has(window))
- return;
-
- let listener = progressListeners.get(window);
- listener.detach();
- progressListeners.delete(window);
- };
-
- let {Filter} = require("filterClasses");
- let {Prefs} = require("prefs");
- let {Policy} = require("contentPolicy");
- let {UI} = require("ui");
- let {Utils} = require("utils");
-
- let toggleWhitelist = function(window)
- {
- if (!Prefs.enabled)
- {
- Prefs.enabled = true;
- return;
- }
-
- let location = exports.getCurrentLocation(window);
- let host = null;
- if (location instanceof Ci.nsIURL && Policy.isBlockableScheme(location))
- {
- try
- {
- host = location.host.replace(/^www\./, "");
- } catch (e) {}
- }
-
- if (!host)
- return;
-
- if (Policy.isWhitelisted(location.spec))
- UI.removeWhitelist(window);
- else
- UI.toggleFilter(Filter.fromText("@@||" + host + "^$document"));
- };
-
- let menuItem = null;
- onShutdown.add(function()
- {
- let window = null;
- for (window of UI.applicationWindows)
- break;
-
- if (window && menuItem)
- window.NativeWindow.menu.remove(menuItem);
- });
-
- UI.updateIconState = function fmn_updateIconState(window, icon)
- {
- if (menuItem !== null)
- {
- window.NativeWindow.menu.remove(menuItem);
- menuItem = null;
- }
-
- let action;
- let host = null;
- if (Prefs.enabled)
- {
- let location = exports.getCurrentLocation(window);
- if (location instanceof Ci.nsIURL && Policy.isBlockableScheme(location))
- {
- try
- {
- host = location.host.replace(/^www\./, "");
- } catch (e) {}
- }
- if (!host)
- return;
-
- if (host && Policy.isWhitelisted(location.spec))
- action = "enable_site";
- else if (host)
- action = "disable_site";
- }
- else
- action = "enable";
-
- let actionText = Utils.getString("mobile_menu_" + action);
- if (host)
- actionText = actionText.replace(/\?1\?/g, host);
-
- let iconUrl = require("info").addonRoot + "icon64.png";
- menuItem = window.NativeWindow.menu.add(actionText, iconUrl, toggleWhitelist.bind(null, window));
- };
-
- UI.openSubscriptionDialog = function(window, url, title, mainURL, mainTitle)
- {
- let dialogTitle = this.overlay.attributes.subscriptionDialogTitle;
- let dialogMessage = this.overlay.attributes.subscriptionDialogMessage.replace(/\?1\?/, title).replace(/\?2\?/, url);
- if (Utils.confirm(window, dialogMessage, dialogTitle))
- this.setSubscription(url, title);
- };
-
- UI.openFiltersDialog = function()
- {
- let window = UI.currentWindow;
- if (!window)
- return
-
- let browser = exports.addTab(window, "about:addons").browser;
- browser.addEventListener("load", function openAddonPrefs(event)
- {
- browser.removeEventListener("load", openAddonPrefs, true);
- Utils.runAsync(function()
- {
- // The page won't be ready until the add-on manager data is loaded so we call this method
- // to know when the data will be ready.
- AddonManager.getAddonsByTypes(["extension", "theme", "locale"], function()
- {
- let event = new Event("Event");
- event.initEvent("popstate", true, false);
- event.state = {id: require("info").addonID};
- browser._contentWindow.dispatchEvent(event);
- });
- });
- }, true);
- };
-
- break;
- }
-}
diff --git a/data/extensions/spyblock@gnu.org/lib/child/bootstrap.js b/data/extensions/spyblock@gnu.org/lib/child/bootstrap.js
deleted file mode 100644
index 477ca44..0000000
--- a/data/extensions/spyblock@gnu.org/lib/child/bootstrap.js
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-(function()
-{
- const Cc = Components.classes;
- const Ci = Components.interfaces;
- const Cr = Components.results;
- const Cu = Components.utils;
-
- let {Loader, main, unload} = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {});
- let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
- Cu.importGlobalProperties(["atob", "btoa", "File", "URL", "URLSearchParams",
- "TextDecoder", "TextEncoder"]);
-
- let shutdownHandlers = [];
- let onShutdown =
- {
- done: false,
- add: function(handler)
- {
- if (shutdownHandlers.indexOf(handler) < 0)
- shutdownHandlers.push(handler);
- },
- remove: function(handler)
- {
- let index = shutdownHandlers.indexOf(handler);
- if (index >= 0)
- shutdownHandlers.splice(index, 1);
- }
- };
-
- function init()
- {
- let url = new URL(Components.stack.filename);
- let params = new URLSearchParams(url.search.substr(1));
- let info = JSON.parse(params.get("info"));
-
- let loader = Loader({
- paths: {
- "": info.addonRoot + "lib/"
- },
- globals: {
- Components, Cc, Ci, Cu, Cr, atob, btoa, File, URL, URLSearchParams,
- TextDecoder, TextEncoder, onShutdown
- },
- modules: {"info": info, "messageManager": this},
- id: info.addonID
- });
- onShutdown.add(() => unload(loader, "disable"))
-
- main(loader, "child/main");
- }
-
- function shutdown(message)
- {
- if (message.data == Components.stack.filename)
- {
- onShutdown.done = true;
- for (let i = shutdownHandlers.length - 1; i >= 0; i --)
- {
- try
- {
- shutdownHandlers[i]();
- }
- catch (e)
- {
- Cu.reportError(e);
- }
- }
- shutdownHandlers = null;
- }
- }
-
- addMessageListener("AdblockPlus:Shutdown", shutdown);
- onShutdown.add(() =>
- {
- removeMessageListener("AdblockPlus:Shutdown", shutdown);
- });
-
- init();
-})();
diff --git a/data/extensions/spyblock@gnu.org/lib/child/contentPolicy.js b/data/extensions/spyblock@gnu.org/lib/child/contentPolicy.js
deleted file mode 100644
index 97ea7b1..0000000
--- a/data/extensions/spyblock@gnu.org/lib/child/contentPolicy.js
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * @fileOverview Content policy implementation, responsible for blocking things.
- */
-
-"use strict";
-
-try
-{
- // Hack: SDK loader masks our Components object with a getter.
- let proto = Object.getPrototypeOf(this);
- let property = Object.getOwnPropertyDescriptor(proto, "Components");
- if (property && property.get)
- delete proto.Components;
-}
-catch (e)
-{
- Cu.reportError(e);
-}
-
-let {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let {port} = require("messaging");
-let {Utils} = require("utils");
-let {getFrames, isPrivate, getRequestWindow} = require("child/utils");
-let {objectMouseEventHander} = require("child/objectTabs");
-let {RequestNotifier} = require("child/requestNotifier");
-
-/**
- * Randomly generated class name, to be applied to collapsed nodes.
- * @type Promise.<string>
- */
-let collapsedClass = port.emitWithResponse("getCollapsedClass");
-
-/**
- * Maps numerical content type IDs to strings.
- * @type Map.<number,string>
- */
-let types = new Map();
-
-/**
- * Contains nodes stored by storeNodes() mapped by their IDs.
- * @type Map.<string,DOMNode[]>
- */
-let storedNodes = new Map();
-
-/**
- * Process-dependent prefix to be used for unique nodes identifiers returned
- * by storeNodes().
- * @type string
- */
-let nodesIDPrefix = Services.appinfo.processID + " ";
-
-/**
- * Counter used to generate unique nodes identifiers in storeNodes().
- * @type number
- */
-let maxNodesID = 0;
-
-port.on("deleteNodes", onDeleteNodes);
-port.on("refilterNodes", onRefilterNodes);
-
-/**
- * Processes parent's response to the ShouldAllow message.
- * @param {nsIDOMWindow} window window that the request is associated with
- * @param {nsIDOMElement} node DOM element that the request is associated with
- * @param {Object|undefined} response object received as response
- * @return {Boolean} false if the request should be blocked
- */
-function processPolicyResponse(window, node, response)
-{
- if (typeof response == "undefined")
- return true;
-
- let {allow, collapse, hits} = response;
- let isObject = false;
- for (let hit of hits)
- {
- if (hit.contentType == "OBJECT")
- isObject = true;
-
- let context = node;
- if (typeof hit.frameIndex == "number")
- {
- context = window;
- for (let i = 0; i < hit.frameIndex; i++)
- context = context.parent;
- context = context.document;
- }
- RequestNotifier.addNodeData(context, window.top, hit);
- }
-
- if (node.nodeType == Ci.nsIDOMNode.ELEMENT_NODE)
- {
- // Track mouse events for objects
- if (allow && isObject)
- {
- node.addEventListener("mouseover", objectMouseEventHander, true);
- node.addEventListener("mouseout", objectMouseEventHander, true);
- }
-
- if (collapse)
- schedulePostProcess(node);
- }
- return allow;
-}
-
-/**
- * Checks whether a request should be allowed, hides it if necessary
- * @param {nsIDOMWindow} window
- * @param {nsIDOMElement} node
- * @param {String} contentType
- * @param {String} location location of the request, filter key if contentType is ELEMHIDE
- * @return {Boolean} false if the request should be blocked
- */
-let shouldAllow = exports.shouldAllow = function(window, node, contentType, location)
-{
- return processPolicyResponse(window, node, port.emitSync("shouldAllow", {
- contentType,
- location,
- frames: getFrames(window),
- isPrivate: isPrivate(window)
- }));
-};
-
-/**
- * Asynchronously checks whether a request should be allowed.
- * @param {nsIDOMWindow} window
- * @param {nsIDOMElement} node
- * @param {String} contentType
- * @param {String} location location of the request, filter key if contentType is ELEMHIDE
- * @param {Function} callback callback to be called with a boolean value, if
- * false the request should be blocked
- */
-let shouldAllowAsync = exports.shouldAllowAsync = function(window, node, contentType, location, callback)
-{
- port.emitWithResponse("shouldAllow", {
- contentType,
- location,
- frames: getFrames(window),
- isPrivate: isPrivate(window)
- }).then(response =>
- {
- callback(processPolicyResponse(window, node, response));
- });
-};
-
-/**
- * Stores nodes and generates a unique ID for them that can be used for
- * Policy.refilterNodes() later. It's important that Policy.deleteNodes() is
- * called later, otherwise the nodes will be leaked.
- * @param {DOMNode[]} nodes list of nodes to be stored
- * @return {string} unique ID for the nodes
- */
-let storeNodes = exports.storeNodes = function(nodes)
-{
- let id = nodesIDPrefix + (++maxNodesID);
- storedNodes.set(id, nodes);
- return id;
-};
-
-/**
- * Called via message whenever Policy.deleteNodes() is called in the parent.
- */
-function onDeleteNodes(id, sender)
-{
- storedNodes.delete(id);
-}
-
-/**
- * Called via message whenever Policy.refilterNodes() is called in the parent.
- */
-function onRefilterNodes({nodesID, entry}, sender)
-{
- let nodes = storedNodes.get(nodesID);
- if (nodes)
- for (let node of nodes)
- if (node.nodeType == Ci.nsIDOMNode.ELEMENT_NODE)
- Utils.runAsync(refilterNode.bind(this, node, entry));
-}
-
-/**
- * Re-checks filters on an element.
- */
-function refilterNode(/**Node*/ node, /**Object*/ entry)
-{
- let wnd = Utils.getWindow(node);
- if (!wnd || wnd.closed)
- return;
-
- if (entry.type == "OBJECT")
- {
- node.removeEventListener("mouseover", objectMouseEventHander, true);
- node.removeEventListener("mouseout", objectMouseEventHander, true);
- }
-
- shouldAllow(wnd, node, entry.type, entry.location, (allow) => {
- // Force node to be collapsed
- if (!allow)
- schedulePostProcess(node)
- });
-}
-
-/**
- * Actual nsIContentPolicy and nsIChannelEventSink implementation
- * @class
- */
-var PolicyImplementation =
-{
- classDescription: "Adblock Plus content policy",
- classID: Components.ID("cfeaabe6-1dd1-11b2-a0c6-cb5c268894c9"),
- contractID: "@adblockplus.org/abp/policy;1",
- xpcom_categories: ["content-policy", "net-channel-event-sinks"],
-
- /**
- * Registers the content policy on startup.
- */
- init: function()
- {
- // Populate types map
- let iface = Ci.nsIContentPolicy;
- for (let name in iface)
- if (name.indexOf("TYPE_") == 0 && name != "TYPE_DATAREQUEST")
- types.set(iface[name], name.substr(5));
-
- let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
- registrar.registerFactory(this.classID, this.classDescription, this.contractID, this);
-
- let catMan = Utils.categoryManager;
- for (let category of this.xpcom_categories)
- catMan.addCategoryEntry(category, this.contractID, this.contractID, false, true);
-
- Services.obs.addObserver(this, "document-element-inserted", true);
-
- onShutdown.add(() =>
- {
- Services.obs.removeObserver(this, "document-element-inserted");
-
- for (let category of this.xpcom_categories)
- catMan.deleteCategoryEntry(category, this.contractID, false);
-
- registrar.unregisterFactory(this.classID, this);
- });
- },
-
- //
- // nsISupports interface implementation
- //
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPolicy, Ci.nsIObserver,
- Ci.nsIChannelEventSink, Ci.nsIFactory, Ci.nsISupportsWeakReference]),
-
- //
- // nsIContentPolicy interface implementation
- //
-
- shouldLoad: function(contentType, contentLocation, requestOrigin, node, mimeTypeGuess, extra)
- {
- // Ignore requests without context and top-level documents
- if (!node || contentType == Ci.nsIContentPolicy.TYPE_DOCUMENT)
- return Ci.nsIContentPolicy.ACCEPT;
-
- // Bail out early for chrome: an resource: URLs, this is a work-around for
- // https://bugzil.la/1127744 and https://bugzil.la/1247640
- let location = Utils.unwrapURL(contentLocation);
- if (location.schemeIs("chrome") || location.schemeIs("resource"))
- return Ci.nsIContentPolicy.ACCEPT;
-
- // Ignore standalone objects
- if (contentType == Ci.nsIContentPolicy.TYPE_OBJECT && node.ownerDocument && !/^text\/|[+\/]xml$/.test(node.ownerDocument.contentType))
- return Ci.nsIContentPolicy.ACCEPT;
-
- let wnd = Utils.getWindow(node);
- if (!wnd)
- return Ci.nsIContentPolicy.ACCEPT;
-
- // Data loaded by plugins should be associated with the document
- if (contentType == Ci.nsIContentPolicy.TYPE_OBJECT_SUBREQUEST && node instanceof Ci.nsIDOMElement)
- node = node.ownerDocument;
-
- // Fix type for objects misrepresented as frames or images
- if (contentType != Ci.nsIContentPolicy.TYPE_OBJECT && (node instanceof Ci.nsIDOMHTMLObjectElement || node instanceof Ci.nsIDOMHTMLEmbedElement))
- contentType = Ci.nsIContentPolicy.TYPE_OBJECT;
-
- let result = shouldAllow(wnd, node, types.get(contentType), location.spec);
- return (result ? Ci.nsIContentPolicy.ACCEPT : Ci.nsIContentPolicy.REJECT_REQUEST);
- },
-
- shouldProcess: function(contentType, contentLocation, requestOrigin, insecNode, mimeType, extra)
- {
- return Ci.nsIContentPolicy.ACCEPT;
- },
-
- //
- // nsIObserver interface implementation
- //
- _openers: new WeakMap(),
- _alreadyLoaded: Symbol(),
-
- observe: function(subject, topic, data, uri)
- {
- switch (topic)
- {
- case "document-element-inserted":
- {
- let window = subject.defaultView;
- if (!window)
- return;
-
- let type = window.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebNavigation)
- .QueryInterface(Ci.nsIDocShellTreeItem)
- .itemType;
- if (type != Ci.nsIDocShellTreeItem.typeContent)
- return;
-
- let opener = this._openers.get(window);
- if (opener == this._alreadyLoaded)
- {
- // This window has loaded already, ignore it regardless of whether
- // window.opener is still set.
- return;
- }
-
- if (opener && Cu.isDeadWrapper(opener))
- opener = null;
-
- if (!opener)
- {
- // We don't know the opener for this window yet, try to find it
- opener = window.opener;
- if (!opener)
- return;
-
- // The opener might be an intermediate window, get the real one
- while (opener.location == "about:blank" && opener.opener)
- opener = opener.opener;
-
- this._openers.set(window, opener);
-
- let forgetPopup = event =>
- {
- subject.removeEventListener("DOMContentLoaded", forgetPopup);
- this._openers.set(window, this._alreadyLoaded);
- };
- subject.addEventListener("DOMContentLoaded", forgetPopup);
- }
-
- if (!uri)
- uri = window.location.href;
- if (!shouldAllow(opener, opener.document, "POPUP", uri))
- {
- window.stop();
- Utils.runAsync(() => window.close());
- }
- else if (uri == "about:blank")
- {
- // An about:blank pop-up most likely means that a load will be
- // initiated asynchronously. Wait for that.
- Utils.runAsync(() =>
- {
- let channel = window.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDocShell)
- .QueryInterface(Ci.nsIDocumentLoader)
- .documentChannel;
- if (channel)
- this.observe(subject, topic, data, channel.URI.spec);
- });
- }
- break;
- }
- }
- },
-
- //
- // nsIChannelEventSink interface implementation
- //
-
- asyncOnChannelRedirect: function(oldChannel, newChannel, flags, callback)
- {
- let async = false;
- try
- {
- // nsILoadInfo.contentPolicyType was introduced in Gecko 35, then
- // renamed to nsILoadInfo.externalContentPolicyType in Gecko 44.
- let loadInfo = oldChannel.loadInfo;
- let contentType = ("externalContentPolicyType" in loadInfo ?
- loadInfo.externalContentPolicyType : loadInfo.contentPolicyType);
- if (!contentType)
- return;
-
- let wnd = getRequestWindow(newChannel);
- if (!wnd)
- return;
-
- if (contentType == Ci.nsIContentPolicy.TYPE_DOCUMENT)
- {
- if (wnd.history.length <= 1 && wnd.opener)
- {
- // Special treatment for pop-up windows - this will close the window
- // rather than preventing the redirect. Note that we might not have
- // seen the original channel yet because the redirect happened before
- // the async code in observe() had a chance to run.
- this.observe(wnd.document, "document-element-inserted", null, oldChannel.URI.spec);
- this.observe(wnd.document, "document-element-inserted", null, newChannel.URI.spec);
- }
- return;
- }
-
- shouldAllowAsync(wnd, wnd.document, types.get(contentType), newChannel.URI.spec, function(allow)
- {
- callback.onRedirectVerifyCallback(allow ? Cr.NS_OK : Cr.NS_BINDING_ABORTED);
- });
- async = true;
- }
- catch (e)
- {
- // We shouldn't throw exceptions here - this will prevent the redirect.
- Cu.reportError(e);
- }
- finally
- {
- if (!async)
- callback.onRedirectVerifyCallback(Cr.NS_OK);
- }
- },
-
- //
- // nsIFactory interface implementation
- //
-
- createInstance: function(outer, iid)
- {
- if (outer)
- throw Cr.NS_ERROR_NO_AGGREGATION;
- return this.QueryInterface(iid);
- }
-};
-PolicyImplementation.init();
-
-/**
- * Nodes scheduled for post-processing (might be null).
- * @type Node[]
- */
-let scheduledNodes = null;
-
-/**
- * Schedules a node for post-processing.
- */
-function schedulePostProcess(/**Element*/ node)
-{
- if (scheduledNodes)
- scheduledNodes.push(node);
- else
- {
- scheduledNodes = [node];
- Utils.runAsync(postProcessNodes);
- }
-}
-
-/**
- * Processes nodes scheduled for post-processing (typically hides them).
- */
-function postProcessNodes()
-{
- collapsedClass.then(cls =>
- {
- let nodes = scheduledNodes;
- scheduledNodes = null;
-
- // Resolving class is async initially so the nodes might have already been
- // processed in the meantime.
- if (!nodes)
- return;
-
- for (let node of nodes)
- {
- // adjust frameset's cols/rows for frames
- let parentNode = node.parentNode;
- if (parentNode && parentNode instanceof Ci.nsIDOMHTMLFrameSetElement)
- {
- let hasCols = (parentNode.cols && parentNode.cols.indexOf(",") > 0);
- let hasRows = (parentNode.rows && parentNode.rows.indexOf(",") > 0);
- if ((hasCols || hasRows) && !(hasCols && hasRows))
- {
- let index = -1;
- for (let frame = node; frame; frame = frame.previousSibling)
- if (frame instanceof Ci.nsIDOMHTMLFrameElement || frame instanceof Ci.nsIDOMHTMLFrameSetElement)
- index++;
-
- let property = (hasCols ? "cols" : "rows");
- let weights = parentNode[property].split(",");
- weights[index] = "0";
- parentNode[property] = weights.join(",");
- }
- }
- else
- node.classList.add(cls);
- }
- });
-}
diff --git a/data/extensions/spyblock@gnu.org/lib/child/contextMenu.js b/data/extensions/spyblock@gnu.org/lib/child/contextMenu.js
deleted file mode 100644
index 297ef3e..0000000
--- a/data/extensions/spyblock@gnu.org/lib/child/contextMenu.js
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-"use strict";
-
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-let {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
-
-let {Utils} = require("utils");
-let {RequestNotifier} = require("child/requestNotifier");
-let {storeNodes} = require("child/contentPolicy");
-
-/**
- * Determines the context menu entries to be shown for a contextmenu event.
- * @param {Event} event
- * @return {Array}
- */
-function getContextInfo(event)
-{
- let items = [];
- let target = event.target;
- if (target.localName == "menupopup" && target.triggerNode)
- {
- // SeaMonkey gives us the context menu's popupshowing event
- target = target.triggerNode;
- }
- if (target instanceof Ci.nsIDOMHTMLMapElement || target instanceof Ci.nsIDOMHTMLAreaElement)
- {
- // HTML image maps will usually receive events when the mouse pointer is
- // over a different element, get the real event target.
- let rect = target.getClientRects()[0];
- target = target.ownerDocument.elementFromPoint(Math.max(rect.left, 0), Math.max(rect.top, 0));
- }
-
- if (!target)
- return items;
-
- let addMenuItem = function([node, nodeData])
- {
- let nodeID = null;
- if (node && node.nodeType == Ci.nsIDOMNode.ELEMENT_NODE)
- nodeID = storeNodes([node]);
- items.push([nodeID, nodeData]);
- }.bind(this);
-
- // Look up data that we have for the node
- let data = RequestNotifier.getDataForNode(target);
- let hadImage = false;
- if (data && !data[1].filter)
- {
- addMenuItem(data);
- hadImage = (data[1].type == "IMAGE");
- }
-
- // Look for frame data
- let wnd = Utils.getWindow(target);
- if (wnd.frameElement)
- {
- let data = RequestNotifier.getDataForNode(wnd.frameElement, true);
- if (data && !data[1].filter)
- addMenuItem(data);
- }
-
- // Look for a background image
- if (!hadImage)
- {
- let extractImageURL = function(computedStyle, property)
- {
- let value = computedStyle.getPropertyCSSValue(property);
- // CSSValueList
- if ("length" in value && value.length >= 1)
- value = value[0];
- // CSSValuePrimitiveType
- if ("primitiveType" in value && value.primitiveType == value.CSS_URI)
- return Utils.unwrapURL(value.getStringValue()).spec;
-
- return null;
- };
-
- let node = target;
- while (node)
- {
- if (node.nodeType == Ci.nsIDOMNode.ELEMENT_NODE)
- {
- let style = wnd.getComputedStyle(node, "");
- let bgImage = extractImageURL(style, "background-image") || extractImageURL(style, "list-style-image");
- if (bgImage)
- {
- let data = RequestNotifier.getDataForNode(wnd.document, true, "IMAGE", bgImage);
- if (data && !data[1].filter)
- {
- addMenuItem(data);
- break;
- }
- }
- }
-
- node = node.parentNode;
- }
- }
-
- return items;
-};
-
-let ContextMenuObserver =
-{
- observe: function(subject, topic, data)
- {
- if (subject.wrappedJSObject)
- subject = subject.wrappedJSObject;
-
- if (subject.addonInfo)
- subject.addonInfo.adblockplus = getContextInfo(subject.event);
- },
- QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference, Ci.nsIObserver])
-};
-
-Services.obs.addObserver(ContextMenuObserver, "content-contextmenu", true);
-Services.obs.addObserver(ContextMenuObserver, "AdblockPlus:content-contextmenu", true);
-onShutdown.add(() => {
- Services.obs.removeObserver(ContextMenuObserver, "content-contextmenu");
- Services.obs.removeObserver(ContextMenuObserver, "AdblockPlus:content-contextmenu");
-});
diff --git a/data/extensions/spyblock@gnu.org/lib/child/dataCollector.js b/data/extensions/spyblock@gnu.org/lib/child/dataCollector.js
deleted file mode 100644
index 09c334a..0000000
--- a/data/extensions/spyblock@gnu.org/lib/child/dataCollector.js
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * @fileOverview Collects some data for a content window, to be attached to
- * issue reports.
- */
-
-"use strict";
-
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-let {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
-let {PrivateBrowsingUtils} = Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm", {});
-
-let {port} = require("messaging");
-let {Utils} = require("utils");
-
-port.on("collectData", onCollectData);
-
-function onCollectData({outerWindowID, screenshotWidth}, sender)
-{
- let window = Services.wm.getOuterWindowWithId(outerWindowID);
- if (window)
- {
- return Task.spawn(function*()
- {
- let data = {};
- data.isPrivate = PrivateBrowsingUtils.isContentWindowPrivate(window);
- data.opener = window.opener ? window.opener.location.href : null;
- data.referrer = window.document.referrer;
- data.frames = yield scanFrames(window);
- data.screenshot = yield createScreenshot(window, screenshotWidth);
- return data;
- });
- }
-}
-
-function scanFrames(window)
-{
- let frames = [];
- for (let i = 0; i < window.frames.length; i++)
- {
- let frame = window.frames[i];
- frames.push({
- url: frame.location.href,
- frames: scanFrames(frame)
- });
- }
- return frames;
-}
-
-function* createScreenshot(window, screenshotWidth)
-{
- let canvas = window.document.createElement("canvas");
- canvas.width = screenshotWidth;
-
- let context = canvas.getContext("2d");
- let wndWidth = window.document.documentElement.scrollWidth;
- let wndHeight = window.document.documentElement.scrollHeight;
-
- // Copy scaled screenshot of the webpage, according to the specified width.
-
- // Gecko doesn't like sizes more than 64k, restrict to 30k to be on the safe side.
- // Also, make sure height is at most five times the width to keep image size down.
- let copyWidth = Math.min(wndWidth, 30000);
- let copyHeight = Math.min(wndHeight, 30000, copyWidth * 5);
- let copyX = Math.max(Math.min(window.scrollX - copyWidth / 2, wndWidth - copyWidth), 0);
- let copyY = Math.max(Math.min(window.scrollY - copyHeight / 2, wndHeight - copyHeight), 0);
-
- let scalingFactor = screenshotWidth / copyWidth;
- canvas.height = copyHeight * scalingFactor;
-
- context.save();
- context.scale(scalingFactor, scalingFactor);
- context.drawWindow(window, copyX, copyY, copyWidth, copyHeight, "rgb(255,255,255)");
- context.restore();
-
- // Reduce colors
- let pixelData = context.getImageData(0, 0, canvas.width, canvas.height);
- let data = pixelData.data;
- let mapping = [0x00, 0x55, 0xAA, 0xFF];
- for (let i = 0; i < data.length; i++)
- {
- data[i] = mapping[data[i] >> 6];
-
- if (i % 5000 == 0)
- {
- // Take a break every 5000 bytes to prevent browser hangs
- yield new Promise((resolve, reject) => Utils.runAsync(resolve));
- }
- }
-
- return pixelData;
-}
diff --git a/data/extensions/spyblock@gnu.org/lib/child/elemHide.js b/data/extensions/spyblock@gnu.org/lib/child/elemHide.js
deleted file mode 100644
index 988adee..0000000
--- a/data/extensions/spyblock@gnu.org/lib/child/elemHide.js
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * @fileOverview Serves CSS for element hiding and processes hits.
- */
-
-try
-{
- // Hack: SDK loader masks our Components object with a getter.
- let proto = Object.getPrototypeOf(this);
- let property = Object.getOwnPropertyDescriptor(proto, "Components");
- if (property && property.get)
- delete proto.Components;
-}
-catch (e)
-{
- Cu.reportError(e);
-}
-
-let {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let {shouldAllowAsync} = require("child/contentPolicy");
-let {getFrames, isPrivate, getRequestWindow} = require("child/utils");
-let {RequestNotifier} = require("child/requestNotifier");
-let {port} = require("messaging");
-let {Utils} = require("utils");
-
-const notImplemented = () => Cr.NS_ERROR_NOT_IMPLEMENTED;
-
-/**
- * about: URL module used to count hits.
- * @class
- */
-let AboutHandler =
-{
- classID: Components.ID("{55fb7be0-1dd2-11b2-98e6-9e97caf8ba67}"),
- classDescription: "Element hiding hit registration protocol handler",
- aboutPrefix: "abp-elemhide",
-
- /**
- * Registers handler on startup.
- */
- init: function()
- {
- let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
- registrar.registerFactory(this.classID, this.classDescription,
- "@mozilla.org/network/protocol/about;1?what=" + this.aboutPrefix, this);
- onShutdown.add(function()
- {
- registrar.unregisterFactory(this.classID, this);
- }.bind(this));
- },
-
- //
- // Factory implementation
- //
-
- createInstance: function(outer, iid)
- {
- if (outer != null)
- throw Cr.NS_ERROR_NO_AGGREGATION;
-
- return this.QueryInterface(iid);
- },
-
- //
- // About module implementation
- //
-
- getURIFlags: function(uri)
- {
- return Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT;
- },
-
- newChannel: function(uri, loadInfo)
- {
- let match = /\?hit(\d+)$/.exec(uri.path);
- if (match)
- return new HitRegistrationChannel(uri, loadInfo, match[1]);
-
- match = /\?css(?:=(.*?))?(&specificonly)?$/.exec(uri.path);
- if (match)
- {
- return new StyleDataChannel(uri, loadInfo,
- match[1] ? decodeURIComponent(match[1]) : null, !!match[2]);
- }
-
- throw Cr.NS_ERROR_FAILURE;
- },
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory, Ci.nsIAboutModule])
-};
-AboutHandler.init();
-
-/**
- * Base class for channel implementations, subclasses usually only need to
- * override BaseChannel._getResponse() method.
- * @constructor
- */
-function BaseChannel(uri, loadInfo)
-{
- this.URI = this.originalURI = uri;
- this.loadInfo = loadInfo;
-}
-BaseChannel.prototype = {
- URI: null,
- originalURI: null,
- contentCharset: "utf-8",
- contentLength: 0,
- contentType: null,
- owner: Utils.systemPrincipal,
- securityInfo: null,
- notificationCallbacks: null,
- loadFlags: 0,
- loadGroup: null,
- name: null,
- status: Cr.NS_OK,
-
- _getResponse: notImplemented,
-
- _checkSecurity: function()
- {
- if (!this.loadInfo.triggeringPrincipal.equals(Utils.systemPrincipal))
- throw Cr.NS_ERROR_FAILURE;
- },
-
- asyncOpen: function(listener, context)
- {
- Promise.resolve(this._getResponse()).then(data =>
- {
- let stream = Cc["@mozilla.org/io/string-input-stream;1"]
- .createInstance(Ci.nsIStringInputStream);
- stream.setData(data, data.length);
-
- try
- {
- listener.onStartRequest(this, context);
- }
- catch(e)
- {
- // Listener failing isn't our problem
- }
-
- try
- {
- listener.onDataAvailable(this, context, stream, 0, stream.available());
- }
- catch(e)
- {
- // Listener failing isn't our problem
- }
-
- try
- {
- listener.onStopRequest(this, context, Cr.NS_OK);
- }
- catch(e)
- {
- // Listener failing isn't our problem
- }
- });
- },
-
- asyncOpen2: function(listener)
- {
- this._checkSecurity();
- this.asyncOpen(listener, null);
- },
-
- open: function()
- {
- let data = this._getResponse();
- if (typeof data.then == "function")
- throw Cr.NS_ERROR_NOT_IMPLEMENTED;
-
- let stream = Cc["@mozilla.org/io/string-input-stream;1"]
- .createInstance(Ci.nsIStringInputStream);
- stream.setData(data, data.length);
- return stream;
- },
-
- open2: function()
- {
- this._checkSecurity();
- return this.open();
- },
-
- isPending: () => false,
- cancel: notImplemented,
- suspend: notImplemented,
- resume: notImplemented,
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIChannel, Ci.nsIRequest])
-};
-
-/**
- * Channel returning CSS data for the global as well as site-specific stylesheet.
- * @constructor
- */
-function StyleDataChannel(uri, loadInfo, domain, specificOnly)
-{
- BaseChannel.call(this, uri, loadInfo);
- this._domain = domain;
- this._specificOnly = specificOnly;
-}
-StyleDataChannel.prototype = {
- __proto__: BaseChannel.prototype,
- contentType: "text/css",
- _domain: null,
-
- _getResponse: function()
- {
- function escapeChar(match)
- {
- return "\\" + match.charCodeAt(0).toString(16) + " ";
- }
-
- // Would be great to avoid sync messaging here but nsIStyleSheetService
- // insists on opening channels synchronously.
- let [selectors, keys] = (this._domain ?
- port.emitSync("getSelectorsForDomain", [this._domain, this._specificOnly]) :
- port.emitSync("getUnconditionalSelectors"));
-
- let cssPrefix = "{-moz-binding: url(about:abp-elemhide?hit";
- let cssSuffix = "#dummy) !important;}\n";
- let result = [];
-
- for (let i = 0; i < selectors.length; i++)
- {
- let selector = selectors[i];
- let key = keys[i];
- result.push(selector.replace(/[^\x01-\x7F]/g, escapeChar),
- cssPrefix, key, cssSuffix);
- }
-
- return result.join("");
- }
-};
-
-/**
- * Channel returning data for element hiding hits.
- * @constructor
- */
-function HitRegistrationChannel(uri, loadInfo, key)
-{
- BaseChannel.call(this, uri, loadInfo);
- this.key = key;
-}
-HitRegistrationChannel.prototype = {
- __proto__: BaseChannel.prototype,
- key: null,
- contentType: "text/xml",
-
- _getResponse: function()
- {
- let window = getRequestWindow(this);
- port.emitWithResponse("registerElemHideHit", {
- key: this.key,
- frames: getFrames(window),
- isPrivate: isPrivate(window)
- }).then(hit =>
- {
- if (hit)
- RequestNotifier.addNodeData(window.document, window.top, hit);
- });
- return "<bindings xmlns='http://www.mozilla.org/xbl'/>";
- }
-};
-
-let observer = {
- QueryInterface: XPCOMUtils.generateQI([
- Ci.nsIObserver, Ci.nsISupportsWeakReference
- ]),
-
- topic: "document-element-inserted",
- styleURL: Utils.makeURI("about:abp-elemhide?css"),
- sheet: null,
-
- init: function()
- {
- Services.obs.addObserver(this, this.topic, true);
- onShutdown.add(() =>
- {
- Services.obs.removeObserver(this, this.topic);
- });
-
- port.on("elemhideupdate", () =>
- {
- this.sheet = null;
- });
- },
-
- observe: function(subject, topic, data)
- {
- if (topic != this.topic)
- return;
-
- let window = subject.defaultView;
- if (!window)
- {
- // This is typically XBL bindings and SVG images, but also real
- // documents occasionally - probably due to speculative loading?
- return;
- }
- let type = window.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebNavigation)
- .QueryInterface(Ci.nsIDocShellTreeItem)
- .itemType;
- if (type != Ci.nsIDocShellTreeItem.typeContent)
- return;
-
- port.emitWithResponse("elemhideEnabled", {
- frames: getFrames(window),
- isPrivate: isPrivate(window)
- }).then(({
- enabled, contentType, docDomain, thirdParty, location, filter,
- filterType
- }) =>
- {
- if (Cu.isDeadWrapper(window))
- {
- // We are too late, the window is gone already.
- return;
- }
-
- if (enabled)
- {
- let utils = window.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindowUtils);
-
- // If we have a filter hit at this point then it must be a $generichide
- // filter - apply only specific element hiding filters.
- let specificOnly = !!filter;
- if (!specificOnly)
- {
- if (!this.sheet)
- {
- this.sheet = Utils.styleService.preloadSheet(this.styleURL,
- Ci.nsIStyleSheetService.USER_SHEET);
- }
-
- try
- {
- utils.addSheet(this.sheet, Ci.nsIStyleSheetService.USER_SHEET);
- }
- catch (e)
- {
- // Ignore NS_ERROR_ILLEGAL_VALUE - it will be thrown if we try to add
- // the stylesheet multiple times to the same document (the observer
- // will be notified twice for some documents).
- if (e.result != Cr.NS_ERROR_ILLEGAL_VALUE)
- throw e;
- }
- }
-
- let host = window.location.hostname;
- if (host)
- {
- try
- {
- let suffix = "=" + encodeURIComponent(host);
- if (specificOnly)
- suffix += "&specificonly";
- utils.loadSheetUsingURIString(this.styleURL.spec + suffix,
- Ci.nsIStyleSheetService.USER_SHEET);
- }
- catch (e)
- {
- // Ignore NS_ERROR_ILLEGAL_VALUE - it will be thrown if we try to add
- // the stylesheet multiple times to the same document (the observer
- // will be notified twice for some documents).
- if (e.result != Cr.NS_ERROR_ILLEGAL_VALUE)
- throw e;
- }
- }
- }
-
- if (filter)
- {
- RequestNotifier.addNodeData(window.document, window.top, {
- contentType, docDomain, thirdParty, location, filter, filterType
- });
- }
- });
- }
-};
-observer.init();
diff --git a/data/extensions/spyblock@gnu.org/lib/child/elemHideEmulation.js b/data/extensions/spyblock@gnu.org/lib/child/elemHideEmulation.js
deleted file mode 100644
index 7c4ee17..0000000
--- a/data/extensions/spyblock@gnu.org/lib/child/elemHideEmulation.js
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-"use strict";
-
-(function()
-{
- let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
- let {port} = require("messaging");
- let {getFrames, isPrivate} = require("child/utils");
- let {RequestNotifier} = require("child/requestNotifier");
-
- function getFilters(window, callback)
- {
- let message = {
- frames: getFrames(window),
- payload: {
- type: "filters.get",
- what: "elemhideemulation"
- }
- };
- port.emitWithResponse("ext_message", message).then(callback);
- }
-
- function addUserCSS(window, cssCode)
- {
- let uri = Services.io.newURI("data:text/css," + encodeURIComponent(cssCode),
- null, null);
- let utils = window.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindowUtils);
- utils.loadSheet(uri, Ci.nsIDOMWindowUtils.USER_SHEET);
- }
-
- function initElemHideEmulation()
- {
- let scope = Object.assign({}, require("common"));
- Services.scriptloader.loadSubScript(
- "chrome://adblockplus/content/elemHideEmulation.js", scope);
-
- let onContentWindow = (subject, topic, data) =>
- {
- if (!(subject instanceof Ci.nsIDOMWindow))
- return;
-
- let onReady = event =>
- {
- subject.removeEventListener("load", onReady);
- let handler = new scope.ElemHideEmulation(
- subject, getFilters.bind(null, subject), (selectors, filters) =>
- {
- if (selectors.length == 0)
- return;
-
- addUserCSS(subject, selectors.map(
- selector => selector + "{display: none !important;}"
- ).join("\n"));
-
- if (!isPrivate(subject))
- port.emit("addHits", filters);
-
- let docDomain = null;
- try
- {
- // We are calling getFrames() here because it will consider
- // "inheritance" for about:blank and data: frames.
- docDomain = new URL(getFrames(subject)[0].location).hostname;
- }
- catch (e)
- {
- // Invalid URL?
- }
-
- for (let i = 0; i < filters.length; i++)
- {
- RequestNotifier.addNodeData(subject.document, subject.top, {
- contentType: "ELEMHIDE",
- docDomain: docDomain,
- thirdParty: false,
- location: "##" + selectors[i],
- filter: filters[i],
- filterType: "elemhideemulation"
- });
- }
- }
- );
-
- handler.apply();
- };
-
- subject.addEventListener("load", onReady);
- };
-
- Services.obs.addObserver(onContentWindow, "content-document-global-created",
- false);
- onShutdown.add(() =>
- {
- Services.obs.removeObserver(onContentWindow,
- "content-document-global-created");
- });
- }
-
- initElemHideEmulation();
-})();
diff --git a/data/extensions/spyblock@gnu.org/lib/child/flasher.js b/data/extensions/spyblock@gnu.org/lib/child/flasher.js
deleted file mode 100644
index 492f4e0..0000000
--- a/data/extensions/spyblock@gnu.org/lib/child/flasher.js
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * @fileOverview Draws a blinking border for a list of matching elements.
- */
-
-function Flasher(elements, scrollToItem)
-{
- if (scrollToItem && elements[0].ownerDocument)
- {
- // Ensure that at least one element is visible when flashing
- elements[0].scrollIntoView();
- }
-
- this.elements = elements;
- this.count = 0;
-
- this.doFlash();
-
-}
-Flasher.prototype =
-{
- elements: null,
- count: 0,
- timer: null,
-
- doFlash: function()
- {
- if (this.count >= 12)
- {
- this.stop();
- return;
- }
-
- if (this.count % 2)
- this.switchOff();
- else
- this.switchOn();
-
- this.count++;
-
- this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
- this.timer.initWithCallback(() => this.doFlash(), 300, Ci.nsITimer.TYPE_ONE_SHOT);
- },
-
- stop: function()
- {
- if (this.timer)
- {
- this.timer.cancel();
- this.timer = null;
- }
-
- if (this.elements)
- {
- this.switchOff();
- this.elements = null;
- }
- },
-
- setOutline: function(outline, offset)
- {
- for (let element of this.elements)
- {
- if (!Cu.isDeadWrapper(element) && "style" in element)
- {
- element.style.outline = outline;
- element.style.outlineOffset = offset;
- }
- }
- },
-
- switchOn: function()
- {
- this.setOutline("#CC0000 dotted 2px", "-2px");
- },
-
- switchOff: function()
- {
- this.setOutline("", "");
- }
-};
-
-exports.Flasher = Flasher;
diff --git a/data/extensions/spyblock@gnu.org/lib/child/main.js b/data/extensions/spyblock@gnu.org/lib/child/main.js
deleted file mode 100644
index bc21e9a..0000000
--- a/data/extensions/spyblock@gnu.org/lib/child/main.js
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-let {port} = require("messaging");
-
-// Only initialize after receiving a "response" to a dummy message - this makes
-// sure that on update the old version has enough time to receive and process
-// the shutdown message.
-port.emitWithResponse("ping").then(() =>
-{
- require("child/elemHide");
- require("child/contentPolicy");
- require("child/contextMenu");
- require("child/dataCollector");
- require("child/elemHideEmulation");
- require("child/subscribeLinks");
-}).catch(e => Cu.reportError(e));
diff --git a/data/extensions/spyblock@gnu.org/lib/child/objectTabs.js b/data/extensions/spyblock@gnu.org/lib/child/objectTabs.js
deleted file mode 100644
index 74e7387..0000000
--- a/data/extensions/spyblock@gnu.org/lib/child/objectTabs.js
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * @fileOverview Code responsible for showing and hiding object tabs.
- */
-
-let {port} = require("messaging");
-
-/**
- * Class responsible for showing and hiding object tabs.
- * @class
- */
-var objTabs =
-{
- /**
- * Number of milliseconds to wait until hiding tab after the mouse moves away.
- * @type Integer
- */
- HIDE_DELAY: 1000,
-
- /**
- * Document element the object tab is currently being displayed for.
- * @type Element
- */
- currentElement: null,
-
- /**
- * Windows that the window event handler is currently registered for.
- * @type Window[]
- */
- windowListeners: null,
-
- /**
- * Panel element currently used as object tab.
- * @type Element
- */
- objtabElement: null,
-
- /**
- * Time of previous position update.
- * @type Integer
- */
- prevPositionUpdate: 0,
-
- /**
- * Timer used to update position of the object tab.
- * @type nsITimer
- */
- positionTimer: null,
-
- /**
- * Timer used to delay hiding of the object tab.
- * @type nsITimer
- */
- hideTimer: null,
-
- /**
- * Used when hideTimer is running, time when the tab should be hidden.
- * @type Integer
- */
- hideTargetTime: 0,
-
- /**
- * Localized texts and class names to be used for the tab. This will be set
- * when showTabFor is called for the first time.
- * @type Object
- */
- texts: null,
-
- /**
- * Called to show object tab for an element.
- */
- showTabFor: function(/**Element*/ element)
- {
- // Object tabs aren't usable in Fennec
- let {application} = require("info");
- if (application == "fennec" || application == "fennec2" ||
- application == "adblockbrowser")
- return;
-
- if (!this.texts)
- this.texts = port.emitWithResponse("getObjectTabsTexts");
- Promise.all([port.emitWithResponse("getObjectTabsStatus"), this.texts])
- .then(([status, texts]) =>
- {
- this.texts = texts;
- if (!status)
- return;
-
- if (this.hideTimer)
- {
- this.hideTimer.cancel();
- this.hideTimer = null;
- }
-
- if (this.objtabElement)
- this.objtabElement.style.setProperty("opacity", "1", "important");
-
- if (this.currentElement != element)
- {
- this._hideTab();
-
- let {RequestNotifier} = require("child/requestNotifier");
- let data = RequestNotifier.getDataForNode(element, true, "OBJECT");
- if (data)
- this._showTab(element, data[1]);
- }
- });
- },
-
- /**
- * Called to hide object tab for an element (actual hiding happens delayed).
- */
- hideTabFor: function(/**Element*/ element)
- {
- if (element != this.currentElement || this.hideTimer)
- return;
-
- this.hideTargetTime = Date.now() + this.HIDE_DELAY;
- this.hideTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
- this.hideTimer.init(this, 40, Ci.nsITimer.TYPE_REPEATING_SLACK);
- },
-
- /**
- * Makes the tab element visible.
- * @param {Element} element
- * @param {RequestEntry} data
- */
- _showTab: function(element, data)
- {
- let doc = element.ownerDocument.defaultView.top.document;
-
- this.objtabElement = doc.createElementNS("http://www.w3.org/1999/xhtml", "a");
- this.objtabElement.textContent = this.texts.label;
- this.objtabElement.setAttribute("title", this.texts.tooltip);
- this.objtabElement.setAttribute("href", data.location);
- this.objtabElement.setAttribute("class", this.texts.classHidden);
- this.objtabElement.style.setProperty("opacity", "1", "important");
- this.objtabElement.nodeData = data;
-
- this.currentElement = element;
-
- // Register paint listeners for the relevant windows
- this.windowListeners = [];
- let wnd = element.ownerDocument.defaultView;
- while (wnd)
- {
- wnd.addEventListener("MozAfterPaint", objectWindowEventHandler, false);
- this.windowListeners.push(wnd);
- wnd = (wnd.parent != wnd ? wnd.parent : null);
- }
-
- // Register mouse listeners on the object tab
- this.objtabElement.addEventListener("mouseover", objectTabEventHander, false);
- this.objtabElement.addEventListener("mouseout", objectTabEventHander, false);
- this.objtabElement.addEventListener("click", objectTabEventHander, true);
-
- // Insert the tab into the document and adjust its position
- doc.documentElement.appendChild(this.objtabElement);
- if (!this.positionTimer)
- {
- this.positionTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
- this.positionTimer.init(this, 200, Ci.nsITimer.TYPE_REPEATING_SLACK);
- }
- this._positionTab();
- },
-
- /**
- * Hides the tab element.
- */
- _hideTab: function()
- {
- if (this.objtabElement)
- {
- // Prevent recursive calls via popuphidden handler
- let objtab = this.objtabElement;
- this.objtabElement = null;
- this.currentElement = null;
-
- if (this.hideTimer)
- {
- this.hideTimer.cancel();
- this.hideTimer = null;
- }
-
- if (this.positionTimer)
- {
- this.positionTimer.cancel();
- this.positionTimer = null;
- }
-
- try {
- objtab.parentNode.removeChild(objtab);
- } catch (e) {}
- objtab.removeEventListener("mouseover", objectTabEventHander, false);
- objtab.removeEventListener("mouseout", objectTabEventHander, false);
- objtab.nodeData = null;
-
- for (let wnd of this.windowListeners)
- wnd.removeEventListener("MozAfterPaint", objectWindowEventHandler, false);
- this.windowListeners = null;
- }
- },
-
- /**
- * Updates position of the tab element.
- */
- _positionTab: function()
- {
- // Test whether element is still in document
- let elementDoc = null;
- try
- {
- elementDoc = this.currentElement.ownerDocument;
- } catch (e) {} // Ignore "can't access dead object" error
- if (!elementDoc || !this.currentElement.offsetWidth || !this.currentElement.offsetHeight ||
- !elementDoc.defaultView || !elementDoc.documentElement)
- {
- this._hideTab();
- return;
- }
-
- let objRect = this._getElementPosition(this.currentElement);
-
- let className = this.texts.classVisibleTop;
- let left = objRect.right - this.objtabElement.offsetWidth;
- let top = objRect.top - this.objtabElement.offsetHeight;
- if (top < 0)
- {
- top = objRect.bottom;
- className = this.texts.classVisibleBottom;
- }
-
- if (this.objtabElement.style.left != left + "px")
- this.objtabElement.style.setProperty("left", left + "px", "important");
- if (this.objtabElement.style.top != top + "px")
- this.objtabElement.style.setProperty("top", top + "px", "important");
-
- if (this.objtabElement.getAttribute("class") != className)
- this.objtabElement.setAttribute("class", className);
-
- this.prevPositionUpdate = Date.now();
- },
-
- /**
- * Calculates element's position relative to the top frame and considering
- * clipping due to scrolling.
- * @return {{left: Number, top: Number, right: Number, bottom: Number}}
- */
- _getElementPosition: function(/**Element*/ element)
- {
- // Restrict rectangle coordinates by the boundaries of a window's client area
- function intersectRect(rect, wnd)
- {
- // Cannot use wnd.innerWidth/Height because they won't account for scrollbars
- let doc = wnd.document;
- let wndWidth = doc.documentElement.clientWidth;
- let wndHeight = doc.documentElement.clientHeight;
- if (doc.compatMode == "BackCompat") // clientHeight will be bogus in quirks mode
- wndHeight = Math.max(doc.documentElement.offsetHeight, doc.body.offsetHeight) - wnd.scrollMaxY - 1;
-
- rect.left = Math.max(rect.left, 0);
- rect.top = Math.max(rect.top, 0);
- rect.right = Math.min(rect.right, wndWidth);
- rect.bottom = Math.min(rect.bottom, wndHeight);
- }
-
- let rect = element.getBoundingClientRect();
- let wnd = element.ownerDocument.defaultView;
-
- let style = wnd.getComputedStyle(element, null);
- let offsets = [
- parseFloat(style.borderLeftWidth) + parseFloat(style.paddingLeft),
- parseFloat(style.borderTopWidth) + parseFloat(style.paddingTop),
- parseFloat(style.borderRightWidth) + parseFloat(style.paddingRight),
- parseFloat(style.borderBottomWidth) + parseFloat(style.paddingBottom)
- ];
-
- rect = {left: rect.left + offsets[0], top: rect.top + offsets[1],
- right: rect.right - offsets[2], bottom: rect.bottom - offsets[3]};
- while (true)
- {
- intersectRect(rect, wnd);
-
- if (!wnd.frameElement)
- break;
-
- // Recalculate coordinates to be relative to frame's parent window
- let frameElement = wnd.frameElement;
- wnd = frameElement.ownerDocument.defaultView;
-
- let frameRect = frameElement.getBoundingClientRect();
- let frameStyle = wnd.getComputedStyle(frameElement, null);
- let relLeft = frameRect.left + parseFloat(frameStyle.borderLeftWidth) + parseFloat(frameStyle.paddingLeft);
- let relTop = frameRect.top + parseFloat(frameStyle.borderTopWidth) + parseFloat(frameStyle.paddingTop);
-
- rect.left += relLeft;
- rect.right += relLeft;
- rect.top += relTop;
- rect.bottom += relTop;
- }
-
- return rect;
- },
-
- doBlock: function()
- {
- let {storeNodes} = require("child/contentPolicy");
- let nodesID = storeNodes([this.currentElement]);
- port.emit("blockItem", {
- request: this.objtabElement.nodeData,
- nodesID
- });
- },
-
- /**
- * Called whenever a timer fires.
- * @param {nsISupport} subject
- * @param {string} topic
- * @param {string} data
- */
- observe: function(subject, topic, data)
- {
- if (subject == this.positionTimer)
- {
- // Don't update position if it was already updated recently (via MozAfterPaint)
- if (Date.now() - this.prevPositionUpdate > 100)
- this._positionTab();
- }
- else if (subject == this.hideTimer)
- {
- let now = Date.now();
- if (now >= this.hideTargetTime)
- this._hideTab();
- else if (this.hideTargetTime - now < this.HIDE_DELAY / 2)
- this.objtabElement.style.setProperty("opacity", (this.hideTargetTime - now) * 2 / this.HIDE_DELAY, "important");
- }
- }
-};
-
-onShutdown.add(objTabs._hideTab.bind(objTabs));
-
-/**
- * Function called whenever the mouse enters or leaves an object.
- */
-function objectMouseEventHander(/**Event*/ event)
-{
- if (!event.isTrusted)
- return;
-
- if (event.type == "mouseover")
- objTabs.showTabFor(event.target);
- else if (event.type == "mouseout")
- objTabs.hideTabFor(event.target);
-}
-
-/**
- * Function called for paint events of the object tab window.
- */
-function objectWindowEventHandler(/**Event*/ event)
-{
- if (!event.isTrusted)
- return;
-
- // Don't trigger update too often, avoid overusing CPU on frequent page updates
- if (event.type == "MozAfterPaint" && Date.now() - objTabs.prevPositionUpdate > 20)
- objTabs._positionTab();
-}
-
-/**
- * Function called whenever the mouse enters or leaves an object tab.
- */
-function objectTabEventHander(/**Event*/ event)
-{
- if (onShutdown.done || !event.isTrusted)
- return;
-
- if (event.type == "click" && event.button == 0)
- {
- event.preventDefault();
- event.stopPropagation();
-
- objTabs.doBlock();
- }
- else if (event.type == "mouseover")
- objTabs.showTabFor(objTabs.currentElement);
- else if (event.type == "mouseout")
- objTabs.hideTabFor(objTabs.currentElement);
-}
-exports.objectMouseEventHander = objectMouseEventHander;
diff --git a/data/extensions/spyblock@gnu.org/lib/child/requestNotifier.js b/data/extensions/spyblock@gnu.org/lib/child/requestNotifier.js
deleted file mode 100644
index fc6d314..0000000
--- a/data/extensions/spyblock@gnu.org/lib/child/requestNotifier.js
+++ /dev/null
@@ -1,444 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * @fileOverview Stores Adblock Plus data to be attached to a window.
- */
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let {port} = require("messaging");
-let {Utils} = require("utils");
-let {Flasher} = require("child/flasher");
-
-let nodeData = new WeakMap();
-let windowStats = new WeakMap();
-let windowData = new WeakMap();
-let requestEntryMaxId = 0;
-
-/**
- * Active RequestNotifier instances by their ID
- * @type Map.<number,RequestNotifier>
- */
-let notifiers = new Map();
-
-port.on("startWindowScan", onStartScan);
-port.on("shutdownNotifier", onNotifierShutdown);
-port.on("flashNodes", onFlashNodes);
-port.on("retrieveNodeSize", onRetrieveNodeSize);
-port.on("storeNodesForEntries", onStoreNodes);
-port.on("retrieveWindowStats", onRetrieveWindowStats);
-port.on("storeWindowData", onStoreWindowData);
-port.on("retrieveWindowData", onRetrieveWindowData);
-
-function onStartScan({notifierID, outerWindowID})
-{
- let window = Services.wm.getOuterWindowWithId(outerWindowID);
- if (window)
- new RequestNotifier(window, notifierID);
-}
-
-function onNotifierShutdown(notifierID)
-{
- let notifier = notifiers.get(notifierID);
- if (notifier)
- notifier.shutdown();
-}
-
-function onFlashNodes({notifierID, requests, scrollToItem})
-{
- let notifier = notifiers.get(notifierID);
- if (notifier)
- notifier.flashNodes(requests, scrollToItem);
-}
-
-function onRetrieveNodeSize({notifierID, requests})
-{
- let notifier = notifiers.get(notifierID);
- if (notifier)
- return notifier.retrieveNodeSize(requests);
-}
-
-function onStoreNodes({notifierID, requests})
-{
- let notifier = notifiers.get(notifierID);
- if (notifier)
- return notifier.storeNodesForEntries(requests);
-}
-
-function onRetrieveWindowStats(outerWindowID)
-{
- let window = Services.wm.getOuterWindowWithId(outerWindowID);
- if (window)
- return RequestNotifier.getWindowStatistics(window);
-}
-
-function onStoreWindowData({outerWindowID, data})
-{
- let window = Services.wm.getOuterWindowWithId(outerWindowID);
- if (window)
- windowData.set(window.document, data);
-};
-
-function onRetrieveWindowData(outerWindowID)
-{
- let window = Services.wm.getOuterWindowWithId(outerWindowID);
- if (window)
- return windowData.get(window.document) || null;
-};
-
-/**
- * Creates a notifier object for a particular window. After creation the window
- * will first be scanned for previously saved requests. Once that scan is
- * complete only new requests for this window will be reported.
- * @param {Window} window window to attach the notifier to
- * @param {Integer} notifierID Parent notifier ID to be messaged
- */
-function RequestNotifier(window, notifierID)
-{
- this.window = window;
- this.id = notifierID;
- notifiers.set(this.id, this);
- this.nodes = new Map();
- this.startScan(window);
-}
-exports.RequestNotifier = RequestNotifier;
-
-RequestNotifier.prototype =
-{
- /**
- * Parent notifier ID to be messaged
- * @type Integer
- */
- id: null,
-
- /**
- * The window this notifier is associated with.
- * @type Window
- */
- window: null,
-
- /**
- * Nodes associated with a particular request ID.
- * @type Map.<number,Node>
- */
- nodes: null,
-
- /**
- * Shuts down the notifier once it is no longer used. The listener
- * will no longer be called after that.
- */
- shutdown: function()
- {
- delete this.window;
- delete this.nodes;
- this.stopFlashing();
- notifiers.delete(this.id);
- },
-
- /**
- * Notifies the parent about a new request.
- * @param {Node} node DOM node that the request is associated with
- * @param {Object} entry
- */
- notifyListener: function(node, entry)
- {
- if (this.nodes)
- this.nodes.set(entry.id, node);
- port.emit("foundNodeData", {
- notifierID: this.id,
- data: entry
- });
- },
-
- onComplete: function()
- {
- port.emit("scanComplete", this.id);
- },
-
- /**
- * Number of currently posted scan events (will be 0 when the scan finishes
- * running).
- */
- eventsPosted: 0,
-
- /**
- * Starts the initial scan of the window (will recurse into frames).
- * @param {Window} wnd the window to be scanned
- */
- startScan: function(wnd)
- {
- let doc = wnd.document;
- let walker = doc.createTreeWalker(doc, Ci.nsIDOMNodeFilter.SHOW_ELEMENT, null, false);
-
- let process = function()
- {
- // Don't do anything if the notifier was shut down already.
- if (!this.window)
- return;
-
- let node = walker.currentNode;
- let data = nodeData.get(node);
- if (typeof data != "undefined")
- for (let k in data)
- this.notifyListener(node, data[k]);
-
- if (walker.nextNode())
- Utils.runAsync(process);
- else
- {
- // Done with the current window, start the scan for its frames
- for (let i = 0; i < wnd.frames.length; i++)
- this.startScan(wnd.frames[i]);
-
- this.eventsPosted--;
- if (!this.eventsPosted)
- {
- this.scanComplete = true;
- this.onComplete();
- }
- }
- }.bind(this);
-
- // Process each node in a separate event to allow other events to process
- this.eventsPosted++;
- Utils.runAsync(process);
- },
-
- /**
- * Makes the nodes associated with the given requests blink.
- * @param {number[]} requests list of request IDs that were previously
- * reported by this notifier.
- * @param {boolean} scrollToItem if true, scroll to first node
- */
- flashNodes: function(requests, scrollToItem)
- {
- this.stopFlashing();
-
- let nodes = [];
- for (let id of requests)
- {
- if (!this.nodes.has(id))
- continue;
-
- let node = this.nodes.get(id);
- if (Cu.isDeadWrapper(node))
- this.nodes.delete(node);
- else if (node.nodeType == Ci.nsIDOMNode.ELEMENT_NODE)
- nodes.push(node);
- }
- if (nodes.length)
- this.flasher = new Flasher(nodes, scrollToItem);
- },
-
- /**
- * Stops flashing nodes after a previous flashNodes() call.
- */
- stopFlashing: function()
- {
- if (this.flasher)
- this.flasher.stop();
- this.flasher = null;
- },
-
- /**
- * Attempts to calculate the size of the nodes associated with the requests.
- * @param {number[]} requests list of request IDs that were previously
- * reported by this notifier.
- * @return {number[]|null} either an array containing width and height or
- * null if the size could not be calculated.
- */
- retrieveNodeSize: function(requests)
- {
- function getNodeSize(node)
- {
- if (node instanceof Ci.nsIDOMHTMLImageElement && (node.naturalWidth || node.naturalHeight))
- return [node.naturalWidth, node.naturalHeight];
- else if (node instanceof Ci.nsIDOMHTMLElement && (node.offsetWidth || node.offsetHeight))
- return [node.offsetWidth, node.offsetHeight];
- else
- return null;
- }
-
- let size = null;
- for (let id of requests)
- {
- if (!this.nodes.has(id))
- continue;
-
- let node = this.nodes.get(id);
- if (Cu.isDeadWrapper(node))
- this.nodes.delete(node);
- else
- {
- size = getNodeSize(node);
- if (size)
- break;
- }
- }
- return size;
- },
-
- /**
- * Stores the nodes associated with the requests and generates a unique ID
- * for them that can be used with Policy.refilterNodes().
- * @param {number[]} requests list of request IDs that were previously
- * reported by this notifier.
- * @return {string} unique identifiers associated with the nodes.
- */
- storeNodesForEntries: function(requests)
- {
- let nodes = [];
- for (let id of requests)
- {
- if (!this.nodes.has(id))
- continue;
-
- let node = this.nodes.get(id);
- if (Cu.isDeadWrapper(node))
- this.nodes.delete(node);
- else
- nodes.push(node);
- }
-
- let {storeNodes} = require("child/contentPolicy");
- return storeNodes(nodes);
- }
-};
-
-/**
- * Attaches request data to a DOM node.
- * @param {Node} node node to attach data to
- * @param {Window} topWnd top-level window the node belongs to
- * @param {Object} hitData
- * @param {String} hitData.contentType request type, e.g. "IMAGE"
- * @param {String} hitData.docDomain domain of the document that initiated the request
- * @param {Boolean} hitData.thirdParty will be true if a third-party server has been requested
- * @param {String} hitData.location the address that has been requested
- * @param {String} hitData.filter filter applied to the request or null if none
- * @param {String} hitData.filterType type of filter applied to the request
- */
-RequestNotifier.addNodeData = function(node, topWnd, {contentType, docDomain, thirdParty, location, filter, filterType})
-{
- let entry = {
- id: ++requestEntryMaxId,
- type: contentType,
- docDomain, thirdParty, location, filter
- };
-
- let existingData = nodeData.get(node);
- if (typeof existingData == "undefined")
- {
- existingData = {};
- nodeData.set(node, existingData);
- }
-
- // Add this request to the node data
- existingData[contentType + " " + location] = entry;
-
- // Update window statistics
- if (!windowStats.has(topWnd.document))
- {
- windowStats.set(topWnd.document, {
- items: 0,
- hidden: 0,
- blocked: 0,
- whitelisted: 0,
- filters: {}
- });
- }
-
- let stats = windowStats.get(topWnd.document);
- if (filterType != "elemhide" && filterType != "elemhideexception" && filterType != "elemhideemulation")
- stats.items++;
- if (filter)
- {
- if (filterType == "blocking")
- stats.blocked++;
- else if (filterType == "whitelist" || filterType == "elemhideexception")
- stats.whitelisted++;
- else if (filterType == "elemhide" || filterType == "elemhideemulation")
- stats.hidden++;
-
- if (filter in stats.filters)
- stats.filters[filter]++;
- else
- stats.filters[filter] = 1;
- }
-
- // Notify listeners
- for (let notifier of notifiers.values())
- if (!notifier.window || notifier.window == topWnd)
- notifier.notifyListener(node, entry);
-}
-
-/**
- * Retrieves the statistics for a window.
- * @return {Object} Object with the properties items, blocked, whitelisted, hidden, filters containing statistics for the window (might be null)
- */
-RequestNotifier.getWindowStatistics = function(/**Window*/ wnd)
-{
- if (windowStats.has(wnd.document))
- return windowStats.get(wnd.document);
- else
- return null;
-}
-
-/**
- * Retrieves the request data associated with a DOM node.
- * @param {Node} node
- * @param {Boolean} noParent if missing or false, the search will extend to the parent nodes until one is found that has data associated with it
- * @param {Integer} [type] request type to be looking for
- * @param {String} [location] request location to be looking for
- * @result {[Node, Object]}
- * @static
- */
-RequestNotifier.getDataForNode = function(node, noParent, type, location)
-{
- while (node)
- {
- let data = nodeData.get(node);
- if (typeof data != "undefined")
- {
- let entry = null;
- // Look for matching entry
- for (let k in data)
- {
- if ((!entry || entry.id < data[k].id) &&
- (typeof type == "undefined" || data[k].type == type) &&
- (typeof location == "undefined" || data[k].location == location))
- {
- entry = data[k];
- }
- }
- if (entry)
- return [node, entry];
- }
-
- // If we don't have any match on this node then maybe its parent will do
- if ((typeof noParent != "boolean" || !noParent) &&
- node.parentNode instanceof Ci.nsIDOMElement)
- {
- node = node.parentNode;
- }
- else
- {
- node = null;
- }
- }
-
- return null;
-};
diff --git a/data/extensions/spyblock@gnu.org/lib/child/subscribeLinks.js b/data/extensions/spyblock@gnu.org/lib/child/subscribeLinks.js
deleted file mode 100644
index a2e729d..0000000
--- a/data/extensions/spyblock@gnu.org/lib/child/subscribeLinks.js
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let {port} = require("messaging");
-
-Services.obs.addObserver(onContentWindow, "content-document-global-created",
- false);
-onShutdown.add(() =>
-{
- Services.obs.removeObserver(onContentWindow,
- "content-document-global-created");
-});
-
-function onContentWindow(subject, topic, data)
-{
- if (subject instanceof Ci.nsIDOMWindow && subject.top == subject)
- {
- let eventTarget = subject.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebNavigation)
- .QueryInterface(Ci.nsIDocShell)
- .chromeEventHandler;
- if (eventTarget)
- eventTarget.addEventListener("click", onClick, true);
- }
-}
-
-function onClick(event)
-{
- if (onShutdown.done)
- return;
-
- // Ignore right-clicks
- if (event.button == 2)
- return;
-
- // Search the link associated with the click
- let link = event.target;
- while (!(link instanceof Ci.nsIDOMHTMLAnchorElement))
- {
- link = link.parentNode;
-
- if (!link)
- return;
- }
-
- let queryString = null;
- if (link.protocol == "http:" || link.protocol == "https:")
- {
- if (link.host == "subscribe.adblockplus.org" && link.pathname == "/")
- queryString = link.search.substr(1);
- }
- else
- {
- // Firefox doesn't populate the "search" property for links with
- // non-standard URL schemes so we need to extract the query string
- // manually
- let match = /^abp:\/*subscribe\/*\?(.*)/i.exec(link.href);
- if (match)
- queryString = match[1];
- }
-
- if (!queryString)
- return;
-
- // This is our link - make sure the browser doesn't handle it
- event.preventDefault();
- event.stopPropagation();
-
- // Decode URL parameters
- let title = null;
- let url = null;
- let mainSubscriptionTitle = null;
- let mainSubscriptionURL = null;
- for (let param of queryString.split("&"))
- {
- let parts = param.split("=", 2);
- if (parts.length != 2 || !/\S/.test(parts[1]))
- continue;
- switch (parts[0])
- {
- case "title":
- title = decodeURIComponent(parts[1]);
- break;
- case "location":
- url = decodeURIComponent(parts[1]);
- break;
- case "requiresTitle":
- mainSubscriptionTitle = decodeURIComponent(parts[1]);
- break;
- case "requiresLocation":
- mainSubscriptionURL = decodeURIComponent(parts[1]);
- break;
- }
- }
-
- port.emit("subscribeLinkClick", {
- title: title,
- url: url,
- mainSubscriptionTitle: mainSubscriptionTitle,
- mainSubscriptionURL: mainSubscriptionURL
- });
-}
diff --git a/data/extensions/spyblock@gnu.org/lib/child/utils.js b/data/extensions/spyblock@gnu.org/lib/child/utils.js
deleted file mode 100644
index fde649f..0000000
--- a/data/extensions/spyblock@gnu.org/lib/child/utils.js
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-"use strict";
-
-let {PrivateBrowsingUtils} = Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm", {});
-
-let {Utils} = require("utils");
-
-/**
- * Retrieves the effective location of a window.
- */
-let getWindowLocation = exports.getWindowLocation = function(/**Window*/ window) /**String*/
-{
- let result = null;
-
- // Crazy Thunderbird stuff
- if ("name" in window && window.name == "messagepane")
- {
- try
- {
- let mailWnd = window.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebNavigation)
- .QueryInterface(Ci.nsIDocShellTreeItem)
- .rootTreeItem
- .QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindow);
-
- // Typically we get a wrapped mail window here, need to unwrap
- try
- {
- mailWnd = mailWnd.wrappedJSObject;
- } catch(e) {}
-
- if ("currentHeaderData" in mailWnd && "content-base" in mailWnd.currentHeaderData)
- {
- result = mailWnd.currentHeaderData["content-base"].headerValue;
- }
- else if ("currentHeaderData" in mailWnd && "from" in mailWnd.currentHeaderData)
- {
- let emailAddress = Utils.headerParser.extractHeaderAddressMailboxes(mailWnd.currentHeaderData.from.headerValue);
- if (emailAddress)
- result = 'mailto:' + emailAddress.replace(/^[\s"]+/, "").replace(/[\s"]+$/, "").replace(/\s/g, '%20');
- }
- } catch(e) {}
- }
-
- // Sane branch
- if (!result)
- result = window.location.href;
-
- // Remove the anchor if any
- let index = result.indexOf("#");
- if (index >= 0)
- result = result.substring(0, index);
-
- return result;
-}
-
-/**
- * Retrieves the frame hierarchy for a window. Returns an array containing
- * the information for all frames, starting with the window itself up to its
- * top-level window. Each entry has a location and a sitekey entry.
- * @return {Array}
- */
-let getFrames = exports.getFrames = function(/**Window*/ window)
-{
- let frames = [];
- while (window)
- {
- let frame = {
- location: getWindowLocation(window),
- sitekey: null
- };
-
- let documentElement = window.document && window.document.documentElement;
- if (documentElement)
- frame.sitekey = documentElement.getAttribute("data-adblockkey")
-
- frames.push(frame);
- window = (window != window.parent ? window.parent : null);
- }
-
- // URLs like about:blank inherit their security context from upper-level
- // frames, resolve their URLs accordingly.
- for (let i = frames.length - 2; i >= 0; i--)
- {
- let frame = frames[i];
- if (frame.location == "about:blank" || frame.location == "moz-safe-about:blank" ||
- frame.location == "about:srcdoc" ||
- Utils.netUtils.URIChainHasFlags(Utils.makeURI(frame.location), Ci.nsIProtocolHandler.URI_INHERITS_SECURITY_CONTEXT))
- {
- frame.location = frames[i + 1].location;
- }
- }
-
- return frames;
-};
-
-/**
- * Checks whether Private Browsing mode is enabled for a content window.
- * @return {Boolean}
- */
-let isPrivate = exports.isPrivate = function(/**Window*/ window)
-{
- return PrivateBrowsingUtils.isContentWindowPrivate(window);
-};
-
-/**
- * Gets the DOM window associated with a particular request (if any).
- */
-let getRequestWindow = exports.getRequestWindow = function(/**nsIChannel*/ channel) /**nsIDOMWindow*/
-{
- try
- {
- if (channel.notificationCallbacks)
- return channel.notificationCallbacks.getInterface(Ci.nsILoadContext).associatedWindow;
- } catch(e) {}
-
- try
- {
- if (channel.loadGroup && channel.loadGroup.notificationCallbacks)
- return channel.loadGroup.notificationCallbacks.getInterface(Ci.nsILoadContext).associatedWindow;
- } catch(e) {}
-
- return null;
-};
diff --git a/data/extensions/spyblock@gnu.org/lib/common.js b/data/extensions/spyblock@gnu.org/lib/common.js
deleted file mode 100644
index e2c2db5..0000000
--- a/data/extensions/spyblock@gnu.org/lib/common.js
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-// We are currently limited to ECMAScript 5 in this file, because it is being
-// used in the browser tests. See https://issues.adblockplus.org/ticket/4796
-
-/**
- * Converts filter text into regular expression string
- * @param {string} text as in Filter()
- * @return {string} regular expression representation of filter text
- */
-function filterToRegExp(text)
-{
- return text
- // remove multiple wildcards
- .replace(/\*+/g, "*")
- // remove anchors following separator placeholder
- .replace(/\^\|$/, "^")
- // escape special symbols
- .replace(/\W/g, "\\$&")
- // replace wildcards by .*
- .replace(/\\\*/g, ".*")
- // process separator placeholders (all ANSI characters but alphanumeric
- // characters and _%.-)
- .replace(/\\\^/g, "(?:[\\x00-\\x24\\x26-\\x2C\\x2F\\x3A-\\x40\\x5B-\\x5E\\x60\\x7B-\\x7F]|$)")
- // process extended anchor at expression start
- .replace(/^\\\|\\\|/, "^[\\w\\-]+:\\/+(?!\\/)(?:[^\\/]+\\.)?")
- // process anchor at expression start
- .replace(/^\\\|/, "^")
- // process anchor at expression end
- .replace(/\\\|$/, "$")
- // remove leading wildcards
- .replace(/^(\.\*)/, "")
- // remove trailing wildcards
- .replace(/(\.\*)$/, "");
-}
-
-if (typeof exports != "undefined")
- exports.filterToRegExp = filterToRegExp;
diff --git a/data/extensions/spyblock@gnu.org/lib/contentPolicy.js b/data/extensions/spyblock@gnu.org/lib/contentPolicy.js
deleted file mode 100644
index ad36655..0000000
--- a/data/extensions/spyblock@gnu.org/lib/contentPolicy.js
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * @fileOverview Content policy implementation, responsible for blocking things.
- */
-
-"use strict";
-
-let {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let {Utils} = require("utils");
-let {port} = require("messaging");
-let {Prefs} = require("prefs");
-let {FilterStorage} = require("filterStorage");
-let {BlockingFilter, WhitelistFilter, RegExpFilter} = require("filterClasses");
-let {defaultMatcher} = require("matcher");
-
-/**
- * Public policy checking functions and auxiliary objects
- * @class
- */
-var Policy = exports.Policy =
-{
- /**
- * Map of content types reported by Firefox to the respecitve content types
- * used by Adblock Plus. Other content types are simply mapped to OTHER.
- * @type Map.<string,string>
- */
- contentTypes: new Map(function* ()
- {
- // Treat navigator.sendBeacon() the same as <a ping>,
- // it's essentially the same concept - merely generalized.
- yield ["BEACON", "PING"];
-
- // Treat <img srcset> and <picture> the same as other images.
- yield ["IMAGESET", "IMAGE"];
-
- // Treat fetch() the same as XMLHttpRequest,
- // it's essentially the same - merely a more modern API.
- yield ["FETCH", "XMLHTTPREQUEST"];
-
- // Everything else is mapped to itself
- for (let contentType of ["OTHER", "SCRIPT", "IMAGE", "STYLESHEET", "OBJECT",
- "SUBDOCUMENT", "DOCUMENT", "XMLHTTPREQUEST",
- "OBJECT_SUBREQUEST", "FONT", "MEDIA", "PING",
- "WEBSOCKET", "ELEMHIDE", "POPUP", "GENERICHIDE",
- "GENERICBLOCK"])
- yield [contentType, contentType];
- }()),
-
- /**
- * Set of content types that aren't associated with a visual document area
- * @type Set.<string>
- */
- nonVisualTypes: new Set([
- "SCRIPT", "STYLESHEET", "XMLHTTPREQUEST", "OBJECT_SUBREQUEST", "FONT",
- "PING", "WEBSOCKET", "ELEMHIDE", "POPUP", "GENERICHIDE", "GENERICBLOCK"
- ]),
-
- /**
- * Map containing all schemes that should be ignored by content policy.
- * @type Set.<string>
- */
- whitelistSchemes: new Set(),
-
- /**
- * Called on module startup, initializes various exported properties.
- */
- init: function()
- {
- // whitelisted URL schemes
- for (let scheme of Prefs.whitelistschemes.toLowerCase().split(" "))
- this.whitelistSchemes.add(scheme);
-
- port.on("shouldAllow", (message, sender) => this.shouldAllow(message));
-
- // Generate class identifier used to collapse nodes and register
- // corresponding stylesheet.
- let collapsedClass = "";
- let offset = "a".charCodeAt(0);
- for (let i = 0; i < 20; i++)
- collapsedClass += String.fromCharCode(offset + Math.random() * 26);
- port.on("getCollapsedClass", (message, sender) => collapsedClass);
-
- let collapseStyle = Services.io.newURI("data:text/css," +
- encodeURIComponent("." + collapsedClass +
- "{-moz-binding: url(chrome://global/content/bindings/general.xml#foobarbazdummy) !important;}"), null, null);
- Utils.styleService.loadAndRegisterSheet(collapseStyle, Ci.nsIStyleSheetService.USER_SHEET);
- onShutdown.add(() =>
- {
- Utils.styleService.unregisterSheet(collapseStyle, Ci.nsIStyleSheetService.USER_SHEET);
- });
- },
-
- /**
- * Checks whether a node should be blocked, hides it if necessary
- * @param {Object} data request data
- * @param {String} data.contentType
- * @param {String} data.location location of the request
- * @param {Object[]} data.frames
- * @param {Boolean} data.isPrivate true if the request belongs to a private browsing window
- * @return {Object} An object containing properties allow, collapse and hits
- * indicating how this request should be handled.
- */
- shouldAllow: function({contentType, location, frames, isPrivate})
- {
- let hits = [];
-
- function addHit(frameIndex, contentType, docDomain, thirdParty, location, filter)
- {
- if (filter && !isPrivate)
- FilterStorage.increaseHitCount(filter);
- hits.push({
- frameIndex, contentType, docDomain, thirdParty, location,
- filter: filter ? filter.text : null,
- filterType: filter ? filter.type : null
- });
- }
-
- function response(allow, collapse)
- {
- return {allow, collapse, hits};
- }
-
- // Ignore whitelisted schemes
- if (contentType != "POPUP" && !this.isBlockableScheme(location))
- return response(true, false);
-
- // Interpret unknown types as "other"
- contentType = this.contentTypes.get(contentType) || "OTHER";
-
- let nogeneric = false;
- if (Prefs.enabled)
- {
- let whitelistHit =
- this.isFrameWhitelisted(frames, false);
- if (whitelistHit)
- {
- let [frameIndex, matchType, docDomain, thirdParty, location, filter] = whitelistHit;
- addHit(frameIndex, matchType, docDomain, thirdParty, location, filter);
- if (matchType == "DOCUMENT")
- return response(true, false);
- else
- nogeneric = true;
- }
- }
-
- let match = null;
- let wndLocation = frames[0].location;
- let docDomain = getHostname(wndLocation);
- let [sitekey, sitekeyFrame] = getSitekey(frames);
-
- let thirdParty = isThirdParty(location, docDomain);
- let collapse = false;
-
- if (!match && Prefs.enabled && RegExpFilter.typeMap.hasOwnProperty(contentType))
- {
- match = defaultMatcher.matchesAny(location, RegExpFilter.typeMap[contentType],
- docDomain, thirdParty, sitekey, nogeneric, isPrivate);
- if (match instanceof BlockingFilter && !this.nonVisualTypes.has(contentType))
- collapse = (match.collapse != null ? match.collapse : !Prefs.fastcollapse);
- }
- addHit(null, contentType, docDomain, thirdParty, location, match);
-
- return response(!match || match instanceof WhitelistFilter, collapse);
- },
-
- /**
- * Checks whether the location's scheme is blockable.
- * @param location {nsIURI|String}
- * @return {Boolean}
- */
- isBlockableScheme: function(location)
- {
- let scheme;
- if (typeof location == "string")
- {
- let match = /^([\w\-]+):/.exec(location);
- scheme = match ? match[1] : null;
- }
- else
- scheme = location.scheme;
- return !this.whitelistSchemes.has(scheme);
- },
-
- /**
- * Checks whether a top-level window is whitelisted.
- * @param {String} url
- * URL of the document loaded into the window
- * @return {?WhitelistFilter}
- * exception rule that matched the URL if any
- */
- isWhitelisted: function(url)
- {
- if (!url)
- return null;
-
- // Do not apply exception rules to schemes on our whitelistschemes list.
- if (!this.isBlockableScheme(url))
- return null;
-
- // Ignore fragment identifier
- let index = url.indexOf("#");
- if (index >= 0)
- url = url.substring(0, index);
-
- let result = defaultMatcher.matchesAny(url, RegExpFilter.typeMap.DOCUMENT,
- getHostname(url), false, null);
- return (result instanceof WhitelistFilter ? result : null);
- },
-
- /**
- * Checks whether a frame is whitelisted.
- * @param {Array} frames
- * frame structure as returned by getFrames() in child/utils module.
- * @param {boolean} isElemHide
- * true if element hiding whitelisting should be considered
- * @return {?Array}
- * An array with the hit parameters: frameIndex, contentType, docDomain,
- * thirdParty, location, filter. Note that the filter could be a
- * genericblock/generichide exception rule. If nothing matched null is
- * returned.
- */
- isFrameWhitelisted: function(frames, isElemHide)
- {
- let [sitekey, sitekeyFrame] = getSitekey(frames);
- let nogenericHit = null;
-
- let typeMap = RegExpFilter.typeMap.DOCUMENT;
- if (isElemHide)
- typeMap = typeMap | RegExpFilter.typeMap.ELEMHIDE;
- let genericType = (isElemHide ? "GENERICHIDE" : "GENERICBLOCK");
-
- for (let i = 0; i < frames.length; i++)
- {
- let frame = frames[i];
- let wndLocation = frame.location;
- let parentWndLocation = frames[Math.min(i + 1, frames.length - 1)].location;
- let parentDocDomain = getHostname(parentWndLocation);
-
- let match = defaultMatcher.matchesAny(wndLocation, typeMap, parentDocDomain, false, sitekey);
- if (match instanceof WhitelistFilter)
- {
- let whitelistType = (match.contentType & RegExpFilter.typeMap.DOCUMENT) ? "DOCUMENT" : "ELEMHIDE";
- return [i, whitelistType, parentDocDomain, false, wndLocation, match];
- }
-
- if (!nogenericHit)
- {
- match = defaultMatcher.matchesAny(wndLocation,
- RegExpFilter.typeMap[genericType], parentDocDomain, false, sitekey);
- if (match instanceof WhitelistFilter)
- nogenericHit = [i, genericType, parentDocDomain, false, wndLocation, match];
- }
-
- if (frame == sitekeyFrame)
- [sitekey, sitekeyFrame] = getSitekey(frames.slice(i + 1));
- }
-
- return nogenericHit;
- },
-
- /**
- * Deletes nodes that were previously stored with a
- * RequestNotifier.storeNodesForEntries() call or similar.
- * @param {string} id unique ID of the nodes
- */
- deleteNodes: function(id)
- {
- port.emit("deleteNodes", id);
- },
-
- /**
- * Asynchronously re-checks filters for nodes given by an ID previously
- * returned by a RequestNotifier.storeNodesForEntries() call or similar.
- * @param {string} id unique ID of the nodes
- * @param {RequestEntry} entry
- */
- refilterNodes: function(id, entry)
- {
- port.emit("refilterNodes", {
- nodesID: id,
- entry: entry
- });
- }
-};
-Policy.init();
-
-/**
- * Extracts the hostname from a URL (might return null).
- */
-function getHostname(/**String*/ url) /**String*/
-{
- try
- {
- return Utils.unwrapURL(url).host;
- }
- catch(e)
- {
- return null;
- }
-}
-
-/**
- * Retrieves and validates the sitekey for a frame structure.
- */
-function getSitekey(frames)
-{
- for (let frame of frames)
- {
- if (frame.sitekey && frame.sitekey.indexOf("_") >= 0)
- {
- let [key, signature] = frame.sitekey.split("_", 2);
- key = key.replace(/=/g, "");
-
- // Website specifies a key but is the signature valid?
- let uri = Services.io.newURI(frame.location, null, null);
- let host = uri.asciiHost;
- if (uri.port > 0)
- host += ":" + uri.port;
- let params = [
- uri.path.replace(/#.*/, ""), // REQUEST_URI
- host, // HTTP_HOST
- Utils.httpProtocol.userAgent // HTTP_USER_AGENT
- ];
- if (Utils.verifySignature(key, signature, params.join("\0")))
- return [key, frame];
- }
- }
-
- return [null, null];
-}
-
-/**
- * Retrieves the location of a window.
- * @param wnd {nsIDOMWindow}
- * @return {String} window location or null on failure
- */
-function getWindowLocation(wnd)
-{
- if ("name" in wnd && wnd.name == "messagepane")
- {
- // Thunderbird branch
- try
- {
- let mailWnd = wnd.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebNavigation)
- .QueryInterface(Ci.nsIDocShellTreeItem)
- .rootTreeItem
- .QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindow);
-
- // Typically we get a wrapped mail window here, need to unwrap
- try
- {
- mailWnd = mailWnd.wrappedJSObject;
- } catch(e) {}
-
- if ("currentHeaderData" in mailWnd && "content-base" in mailWnd.currentHeaderData)
- {
- return mailWnd.currentHeaderData["content-base"].headerValue;
- }
- else if ("currentHeaderData" in mailWnd && "from" in mailWnd.currentHeaderData)
- {
- let emailAddress = Utils.headerParser.extractHeaderAddressMailboxes(mailWnd.currentHeaderData.from.headerValue);
- if (emailAddress)
- return 'mailto:' + emailAddress.replace(/^[\s"]+/, "").replace(/[\s"]+$/, "").replace(/\s/g, '%20');
- }
- } catch(e) {}
- }
-
- // Firefox branch
- return wnd.location.href;
-}
-
-/**
- * Checks whether the location's origin is different from document's origin.
- */
-function isThirdParty(/**String*/location, /**String*/ docDomain) /**Boolean*/
-{
- if (!location || !docDomain)
- return true;
-
- let uri = Utils.makeURI(location);
- try
- {
- return Utils.effectiveTLD.getBaseDomain(uri) != Utils.effectiveTLD.getBaseDomainFromHost(docDomain);
- }
- catch (e)
- {
- // EffectiveTLDService throws on IP addresses, just compare the host name
- let host = "";
- try
- {
- host = uri.host;
- } catch (e) {}
- return host != docDomain;
- }
-}
diff --git a/data/extensions/spyblock@gnu.org/lib/coreUtils.js b/data/extensions/spyblock@gnu.org/lib/coreUtils.js
deleted file mode 100644
index 98a1331..0000000
--- a/data/extensions/spyblock@gnu.org/lib/coreUtils.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-"use strict";
-
-function desc(properties)
-{
- let descriptor = {};
- let keys = Object.keys(properties);
-
- for (let key of keys)
- descriptor[key] = Object.getOwnPropertyDescriptor(properties, key);
-
- return descriptor;
-}
-exports.desc = desc;
-
-function extend(cls, properties)
-{
- return Object.create(cls.prototype, desc(properties));
-}
-exports.extend = extend;
diff --git a/data/extensions/spyblock@gnu.org/lib/customizableUI.js b/data/extensions/spyblock@gnu.org/lib/customizableUI.js
deleted file mode 100644
index 3874256..0000000
--- a/data/extensions/spyblock@gnu.org/lib/customizableUI.js
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * @fileOverview This emulates a subset of the CustomizableUI API from Firefox 28.
- */
-
-let {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", null);
-
-let {Utils} = require("utils");
-
-// UI module has to be referenced lazily to avoid circular references
-XPCOMUtils.defineLazyGetter(this, "UI", () => require("ui").UI);
-
-let widgets = new Map();
-
-function getToolbox(/**Window*/ window, /**Widget*/ widget) /**Element*/
-{
- if (!("defaultArea" in widget) || !widget.defaultArea)
- return null;
-
- let toolbar = UI.findElement(window, widget.defaultArea);
- if (!toolbar)
- return null;
-
- let toolbox = toolbar.toolbox;
- if (toolbox && ("palette" in toolbox) && toolbox.palette)
- return toolbox;
- else
- return null;
-}
-
-function getToolbar(/**Element*/ element) /**Element*/
-{
- for (let parent = element.parentNode; parent; parent = parent.parentNode)
- if (parent.localName == "toolbar")
- return parent;
- return null;
-}
-
-function getPaletteItem(/**Element*/ toolbox, /**String*/ id) /**Element*/
-{
- for (let child of toolbox.palette.children)
- if (child.id == id)
- return child;
-
- return null;
-}
-
-function restoreWidget(/**Element*/ toolbox, /**Widget*/ widget)
-{
- // Create node
- let node = widget.onBuild(toolbox.ownerDocument);
-
- // Insert into the palette first
- toolbox.palette.insertBefore(node, toolbox.palette.firstChild);
-
- // Now find out where we should put it
- let position = toolbox.getAttribute(widget.positionAttribute);
- if (!/^\S*,\S*,\S*$/.test(position))
- position = null;
-
- if (position == null)
- {
- // No explicitly saved position but maybe we can find it in a currentset
- // attribute somewhere.
- let toolbars = toolbox.externalToolbars.slice();
- for (let child of toolbox.children)
- if (child.localName == "toolbar")
- toolbars.push(child);
- for (let toolbar of toolbars)
- {
- let currentSet = toolbar.getAttribute("currentset");
- if (currentSet)
- {
- let items = currentSet.split(",");
- let index = items.indexOf(widget.id);
- if (index >= 0)
- {
- let before = (index + 1 < items.length ? items[index + 1] : "");
- position = "visible," + toolbar.id + "," + before;
- toolbox.setAttribute(widget.positionAttribute, position);
- toolbox.ownerDocument.persist(toolbox.id, widget.positionAttribute);
- break;
- }
- }
- }
- }
-
- showWidget(toolbox, widget, position);
-}
-
-function showWidget(/**Element*/ toolbox, /**Widget*/ widget, /**String*/ position)
-{
- let visible = "visible", parent = null, before = null;
- if (position)
- {
- [visible, parent, before] = position.split(",", 3);
- parent = toolbox.ownerDocument.getElementById(parent);
- if (before == "")
- before = null;
- else
- before = toolbox.ownerDocument.getElementById(before);
- if (before && before.parentNode != parent)
- before = null;
- }
-
- if (visible == "visible" && !parent)
- {
- let insertionPoint = {
- parent: widget.defaultArea
- };
- if (typeof widget.defaultBefore != "undefined")
- insertionPoint.before = widget.defaultBefore;
- if (typeof widget.defaultAfter != "undefined")
- insertionPoint.after = widget.defaultAfter;
-
- [parent, before] = UI.resolveInsertionPoint(toolbox.ownerDocument.defaultView, insertionPoint);
- }
-
- if (parent && parent.localName != "toolbar")
- parent = null;
-
- if (visible != "visible")
- {
- // Move to palette if the item is currently visible
- let node = toolbox.ownerDocument.getElementById(widget.id);
- if (node)
- toolbox.palette.appendChild(node);
- }
- else if (parent)
- {
- // Add the item to the toolbar
- let items = parent.currentSet.split(",");
- let index = (before ? items.indexOf(before.id) : -1);
- if (index < 0)
- before = null;
- parent.insertItem(widget.id, before, null, false);
- }
-
- saveState(toolbox, widget);
-}
-
-function removeWidget(/**Window*/ window, /**Widget*/ widget)
-{
- let element = window.document.getElementById(widget.id);
- if (element)
- element.parentNode.removeChild(element);
-
- let toolbox = getToolbox(window, widget);
- if (toolbox)
- {
- let paletteItem = getPaletteItem(toolbox, widget.id);
- if (paletteItem)
- paletteItem.parentNode.removeChild(paletteItem);
- }
-}
-
-function onToolbarCustomization(/**Event*/ event)
-{
- let toolbox = event.currentTarget;
- for (let [id, widget] of widgets)
- saveState(toolbox, widget);
-}
-
-function saveState(/**Element*/ toolbox, /**Widget*/ widget)
-{
- let node = toolbox.ownerDocument.getElementById(widget.id);
-
- let position = toolbox.getAttribute(widget.positionAttribute) || "hidden,,";
- if (node && node.parentNode.localName != "toolbarpalette")
- {
- if (typeof widget.onAdded == "function")
- widget.onAdded(node)
-
- let toolbar = getToolbar(node);
- position = "visible," + toolbar.id + "," + (node.nextSibling ? node.nextSibling.id : "");
- }
- else
- position = position.replace(/^visible,/, "hidden,")
-
- toolbox.setAttribute(widget.positionAttribute, position);
- toolbox.ownerDocument.persist(toolbox.id, widget.positionAttribute);
-}
-
-let CustomizableUI = exports.CustomizableUI =
-{
- createWidget: function(widget)
- {
- if (typeof widget.id == "undefined" ||
- typeof widget.defaultArea == "undefined" ||
- typeof widget.positionAttribute == "undefined")
- {
- throw new Error("Unexpected: required property missing from the widget data");
- }
- widgets.set(widget.id, widget);
-
- // Show widget in any existing windows
- for (let window of UI.applicationWindows)
- {
- let toolbox = getToolbox(window, widget);
- if (toolbox)
- {
- toolbox.addEventListener("aftercustomization", onToolbarCustomization, false);
- restoreWidget(toolbox, widget);
- }
- }
- },
-
- destroyWidget: function(id)
- {
- // Don't do anything here. This function is called on shutdown,
- // removeFromWindow will take care of cleaning up already.
- },
-
- getPlacementOfWidget: function(id)
- {
- let window = UI.currentWindow;
- if (!window)
- return null;
-
- let widget = window.document.getElementById(id);
- if (!widget)
- return null;
-
- let toolbar = getToolbar(widget);
- if (!toolbar)
- return null;
-
- return {area: toolbar.id};
- },
-
- addWidgetToArea: function(id)
- {
- // Note: the official API function also has area and position parameters.
- // We ignore those here and simply restore the previous position instead.
- let widget = widgets.get(id);
- for (let window of UI.applicationWindows)
- {
- let toolbox = getToolbox(window, widget);
- if (!toolbox)
- continue;
-
- let position = toolbox.getAttribute(widget.positionAttribute);
- if (position)
- position = position.replace(/^hidden,/, "visible,");
- showWidget(toolbox, widget, position);
- }
- },
-
- removeWidgetFromArea: function(id)
- {
- let widget = widgets.get(id);
- for (let window of UI.applicationWindows)
- {
- let toolbox = getToolbox(window, widget);
- if (!toolbox)
- continue;
-
- let position = toolbox.getAttribute(widget.positionAttribute);
- if (position)
- position = position.replace(/^visible,/, "hidden,");
- else
- position = "hidden,,";
- showWidget(toolbox, widget, position);
- }
- }
-};
-
-let {WindowObserver} = require("windowObserver");
-new WindowObserver({
- applyToWindow: function(window)
- {
- let {isKnownWindow} = require("appSupport");
- if (!isKnownWindow(window))
- return;
-
- for (let [id, widget] of widgets)
- {
- let toolbox = getToolbox(window, widget);
- if (toolbox)
- {
- toolbox.addEventListener("aftercustomization", onToolbarCustomization, false);
-
- // Restore widget asynchronously to allow the stylesheet to load
- Utils.runAsync(restoreWidget.bind(null, toolbox, widget));
- }
- }
- },
-
- removeFromWindow: function(window)
- {
- let {isKnownWindow} = require("appSupport");
- if (!isKnownWindow(window))
- return;
-
- for (let [id, widget] of widgets)
- {
- let toolbox = getToolbox(window, widget);
- if (toolbox)
- toolbox.removeEventListener("aftercustomization", onToolbarCustomization, false);
-
- removeWidget(window, widget);
- }
- }
-});
diff --git a/data/extensions/spyblock@gnu.org/lib/downloader.js b/data/extensions/spyblock@gnu.org/lib/downloader.js
deleted file mode 100644
index fd760a7..0000000
--- a/data/extensions/spyblock@gnu.org/lib/downloader.js
+++ /dev/null
@@ -1,421 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-"use strict";
-
-/**
- * @fileOverview Downloads a set of URLs in regular time intervals.
- */
-
-const {Utils} = require("utils");
-
-const MILLIS_IN_SECOND = exports.MILLIS_IN_SECOND = 1000;
-const MILLIS_IN_MINUTE = exports.MILLIS_IN_MINUTE = 60 * MILLIS_IN_SECOND;
-const MILLIS_IN_HOUR = exports.MILLIS_IN_HOUR = 60 * MILLIS_IN_MINUTE;
-const MILLIS_IN_DAY = exports.MILLIS_IN_DAY = 24 * MILLIS_IN_HOUR;
-
-let Downloader =
-/**
- * Creates a new downloader instance.
- * @param {Function} dataSource
- * Function that will yield downloadable objects on each check
- * @param {number} initialDelay
- * Number of milliseconds to wait before the first check
- * @param {number} checkInterval
- * Interval between the checks
- * @constructor
- */
-exports.Downloader = function(dataSource, initialDelay, checkInterval)
-{
- this.dataSource = dataSource;
- this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
- this._timer.initWithCallback(() =>
- {
- this._timer.delay = checkInterval;
- this._doCheck();
- }, initialDelay, Ci.nsITimer.TYPE_REPEATING_SLACK);
- this._downloading = Object.create(null);
-};
-Downloader.prototype =
-{
- /**
- * Timer triggering the downloads.
- * @type {nsITimer}
- */
- _timer: null,
-
- /**
- * Map containing the URLs of objects currently being downloaded as its keys.
- */
- _downloading: null,
-
- /**
- * Function that will yield downloadable objects on each check.
- * @type {Function}
- */
- dataSource: null,
-
- /**
- * Maximal time interval that the checks can be left out until the soft
- * expiration interval increases.
- * @type {number}
- */
- maxAbsenceInterval: 1 * MILLIS_IN_DAY,
-
- /**
- * Minimal time interval before retrying a download after an error.
- * @type {number}
- */
- minRetryInterval: 1 * MILLIS_IN_DAY,
-
- /**
- * Maximal allowed expiration interval, larger expiration intervals will be
- * corrected.
- * @type {number}
- */
- maxExpirationInterval: 14 * MILLIS_IN_DAY,
-
- /**
- * Maximal number of redirects before the download is considered as failed.
- * @type {number}
- */
- maxRedirects: 5,
-
- /**
- * Called whenever expiration intervals for an object need to be adapted.
- * @type {Function}
- */
- onExpirationChange: null,
-
- /**
- * Callback to be triggered whenever a download starts.
- * @type {Function}
- */
- onDownloadStarted: null,
-
- /**
- * Callback to be triggered whenever a download finishes successfully. The
- * callback can return an error code to indicate that the data is wrong.
- * @type {Function}
- */
- onDownloadSuccess: null,
-
- /**
- * Callback to be triggered whenever a download fails.
- * @type {Function}
- */
- onDownloadError: null,
-
- /**
- * Checks whether anything needs downloading.
- */
- _doCheck()
- {
- let now = Date.now();
- for (let downloadable of this.dataSource())
- {
- if (downloadable.lastCheck &&
- now - downloadable.lastCheck > this.maxAbsenceInterval)
- {
- // No checks for a long time interval - user must have been offline,
- // e.g. during a weekend. Increase soft expiration to prevent load
- // peaks on the server.
- downloadable.softExpiration += now - downloadable.lastCheck;
- }
- downloadable.lastCheck = now;
-
- // Sanity check: do expiration times make sense? Make sure people changing
- // system clock don't get stuck with outdated subscriptions.
- if (downloadable.hardExpiration - now > this.maxExpirationInterval)
- downloadable.hardExpiration = now + this.maxExpirationInterval;
- if (downloadable.softExpiration - now > this.maxExpirationInterval)
- downloadable.softExpiration = now + this.maxExpirationInterval;
-
- // Notify the caller about changes to expiration parameters
- if (this.onExpirationChange)
- this.onExpirationChange(downloadable);
-
- // Does that object need downloading?
- if (downloadable.softExpiration > now &&
- downloadable.hardExpiration > now)
- {
- continue;
- }
-
- // Do not retry downloads too often
- if (downloadable.lastError &&
- now - downloadable.lastError < this.minRetryInterval)
- {
- continue;
- }
-
- this._download(downloadable, 0);
- }
- },
-
- /**
- * Stops the periodic checks.
- */
- cancel()
- {
- this._timer.cancel();
- },
-
- /**
- * Checks whether an address is currently being downloaded.
- * @param {string} url
- * @return {boolean}
- */
- isDownloading(url)
- {
- return url in this._downloading;
- },
-
- /**
- * Starts downloading for an object.
- * @param {Downloadable} downloadable
- */
- download(downloadable)
- {
- // Make sure to detach download from the current execution context
- Utils.runAsync(this._download.bind(this, downloadable, 0));
- },
-
- /**
- * Generates the real download URL for an object by appending various
- * parameters.
- * @param {Downloadable} downloadable
- * @return {string}
- */
- getDownloadUrl(downloadable)
- {
- const {addonName, addonVersion, application, applicationVersion,
- platform, platformVersion} = require("info");
- let url = downloadable.redirectURL || downloadable.url;
- if (url.indexOf("?") >= 0)
- url += "&";
- else
- url += "?";
- // We limit the download count to 4+ to keep the request anonymized
- let {downloadCount} = downloadable;
- if (downloadCount > 4)
- downloadCount = "4+";
- url += "addonName=" + encodeURIComponent(addonName) +
- "&addonVersion=" + encodeURIComponent(addonVersion) +
- "&application=" + encodeURIComponent(application) +
- "&applicationVersion=" + encodeURIComponent(applicationVersion) +
- "&platform=" + encodeURIComponent(platform) +
- "&platformVersion=" + encodeURIComponent(platformVersion) +
- "&lastVersion=" + encodeURIComponent(downloadable.lastVersion) +
- "&downloadCount=" + encodeURIComponent(downloadCount);
- return url;
- },
-
- _download(downloadable, redirects)
- {
- if (this.isDownloading(downloadable.url))
- return;
-
- let downloadUrl = this.getDownloadUrl(downloadable);
- let request = null;
-
- let errorCallback = function errorCallback(error)
- {
- let channelStatus = -1;
- try
- {
- channelStatus = request.channel.status;
- }
- catch (e) {}
-
- let responseStatus = request.status;
-
- Cu.reportError("Adblock Plus: Downloading URL " + downloadable.url +
- " failed (" + error + ")\n" +
- "Download address: " + downloadUrl + "\n" +
- "Channel status: " + channelStatus + "\n" +
- "Server response: " + responseStatus);
-
- if (this.onDownloadError)
- {
- // Allow one extra redirect if the error handler gives us a redirect URL
- let redirectCallback = null;
- if (redirects <= this.maxRedirects)
- {
- redirectCallback = url =>
- {
- downloadable.redirectURL = url;
- this._download(downloadable, redirects + 1);
- };
- }
-
- this.onDownloadError(downloadable, downloadUrl, error, channelStatus,
- responseStatus, redirectCallback);
- }
- }.bind(this);
-
- try
- {
- request = new XMLHttpRequest();
- request.mozBackgroundRequest = true;
- request.open("GET", downloadUrl);
- }
- catch (e)
- {
- errorCallback("synchronize_invalid_url");
- return;
- }
-
- try
- {
- request.overrideMimeType("text/plain");
- request.channel.loadFlags = request.channel.loadFlags |
- request.channel.INHIBIT_CACHING |
- request.channel.VALIDATE_ALWAYS;
-
- // Override redirect limit from preferences, user might have set it to 1
- if (request.channel instanceof Ci.nsIHttpChannel)
- request.channel.redirectionLimit = this.maxRedirects;
- }
- catch (e)
- {
- Cu.reportError(e);
- }
-
- request.addEventListener("error", event =>
- {
- if (onShutdown.done)
- return;
-
- delete this._downloading[downloadable.url];
- errorCallback("synchronize_connection_error");
- }, false);
-
- request.addEventListener("load", event =>
- {
- if (onShutdown.done)
- return;
-
- delete this._downloading[downloadable.url];
-
- // Status will be 0 for non-HTTP requests
- if (request.status && request.status != 200)
- {
- errorCallback("synchronize_connection_error");
- return;
- }
-
- downloadable.downloadCount++;
-
- this.onDownloadSuccess(
- downloadable, request.responseText, errorCallback,
- url =>
- {
- if (redirects >= this.maxRedirects)
- errorCallback("synchronize_connection_error");
- else
- {
- downloadable.redirectURL = url;
- this._download(downloadable, redirects + 1);
- }
- }
- );
- });
-
- request.send(null);
-
- this._downloading[downloadable.url] = true;
- if (this.onDownloadStarted)
- this.onDownloadStarted(downloadable);
- },
-
- /**
- * Produces a soft and a hard expiration interval for a given supplied
- * expiration interval.
- * @param {number} interval
- * @return {Array} soft and hard expiration interval
- */
- processExpirationInterval(interval)
- {
- interval = Math.min(Math.max(interval, 0), this.maxExpirationInterval);
- let soft = Math.round(interval * (Math.random() * 0.4 + 0.8));
- let hard = interval * 2;
- let now = Date.now();
- return [now + soft, now + hard];
- }
-};
-
-/**
- * An object that can be downloaded by the downloadable
- * @param {string} url URL that has to be requested for the object
- * @constructor
- */
-let Downloadable = exports.Downloadable = function Downloadable(url)
-{
- this.url = url;
-};
-Downloadable.prototype =
-{
- /**
- * URL that has to be requested for the object.
- * @type {string}
- */
- url: null,
-
- /**
- * URL that the download was redirected to if any.
- * @type {string}
- */
- redirectURL: null,
-
- /**
- * Time of last download error or 0 if the last download was successful.
- * @type {number}
- */
- lastError: 0,
-
- /**
- * Time of last check whether the object needs downloading.
- * @type {number}
- */
- lastCheck: 0,
-
- /**
- * Object version corresponding to the last successful download.
- * @type {number}
- */
- lastVersion: 0,
-
- /**
- * Soft expiration interval, will increase if no checks are performed for a
- * while.
- * @type {number}
- */
- softExpiration: 0,
-
- /**
- * Hard expiration interval, this is fixed.
- * @type {number}
- */
- hardExpiration: 0,
-
- /**
- * Number indicating how often the object was downloaded.
- * @type {number}
- */
- downloadCount: 0
-};
diff --git a/data/extensions/spyblock@gnu.org/lib/elemHide.js b/data/extensions/spyblock@gnu.org/lib/elemHide.js
deleted file mode 100644
index a91f1d4..0000000
--- a/data/extensions/spyblock@gnu.org/lib/elemHide.js
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-"use strict";
-
-/**
- * @fileOverview Element hiding implementation.
- */
-
-const {ElemHideException} = require("filterClasses");
-const {FilterNotifier} = require("filterNotifier");
-
-/**
- * Lookup table, filters by their associated key
- * @type {Object}
- */
-let filterByKey = [];
-
-/**
- * Lookup table, keys of the filters by filter text
- * @type {Object}
- */
-let keyByFilter = Object.create(null);
-
-/**
- * Nested lookup table, filter (or false if inactive) by filter key by domain.
- * (Only contains filters that aren't unconditionally matched for all domains.)
- * @type {Object}
- */
-let filtersByDomain = Object.create(null);
-
-/**
- * Lookup table, filter key by selector. (Only used for selectors that are
- * unconditionally matched for all domains.)
- */
-let filterKeyBySelector = Object.create(null);
-
-/**
- * This array caches the keys of filterKeyBySelector table (selectors which
- * unconditionally apply on all domains). It will be null if the cache needs to
- * be rebuilt.
- */
-let unconditionalSelectors = null;
-
-/**
- * This array caches the values of filterKeyBySelector table (filterIds for
- * selectors which unconditionally apply on all domains). It will be null if the
- * cache needs to be rebuilt.
- */
-let unconditionalFilterKeys = null;
-
-/**
- * Object to be used instead when a filter has a blank domains property.
- */
-let defaultDomains = Object.create(null);
-defaultDomains[""] = true;
-
-/**
- * Lookup table, keys are known element hiding exceptions
- * @type {Object}
- */
-let knownExceptions = Object.create(null);
-
-/**
- * Lookup table, lists of element hiding exceptions by selector
- * @type {Object}
- */
-let exceptions = Object.create(null);
-
-/**
- * Container for element hiding filters
- * @class
- */
-let ElemHide = exports.ElemHide = {
- /**
- * Removes all known filters
- */
- clear()
- {
- filterByKey = [];
- keyByFilter = Object.create(null);
- filtersByDomain = Object.create(null);
- filterKeyBySelector = Object.create(null);
- unconditionalSelectors = unconditionalFilterKeys = null;
- knownExceptions = Object.create(null);
- exceptions = Object.create(null);
- FilterNotifier.emit("elemhideupdate");
- },
-
- _addToFiltersByDomain(key, filter)
- {
- let domains = filter.domains || defaultDomains;
- for (let domain in domains)
- {
- let filters = filtersByDomain[domain];
- if (!filters)
- filters = filtersByDomain[domain] = Object.create(null);
-
- if (domains[domain])
- filters[key] = filter;
- else
- filters[key] = false;
- }
- },
-
- /**
- * Add a new element hiding filter
- * @param {ElemHideFilter} filter
- */
- add(filter)
- {
- if (filter instanceof ElemHideException)
- {
- if (filter.text in knownExceptions)
- return;
-
- let {selector} = filter;
- if (!(selector in exceptions))
- exceptions[selector] = [];
- exceptions[selector].push(filter);
-
- // If this is the first exception for a previously unconditionally
- // applied element hiding selector we need to take care to update the
- // lookups.
- let filterKey = filterKeyBySelector[selector];
- if (typeof filterKey != "undefined")
- {
- this._addToFiltersByDomain(filterKey, filterByKey[filterKey]);
- delete filterKeyBySelector[selector];
- unconditionalSelectors = unconditionalFilterKeys = null;
- }
-
- knownExceptions[filter.text] = true;
- }
- else
- {
- if (filter.text in keyByFilter)
- return;
-
- let key = filterByKey.push(filter) - 1;
- keyByFilter[filter.text] = key;
-
- if (!(filter.domains || filter.selector in exceptions))
- {
- // The new filter's selector is unconditionally applied to all domains
- filterKeyBySelector[filter.selector] = key;
- unconditionalSelectors = unconditionalFilterKeys = null;
- }
- else
- {
- // The new filter's selector only applies to some domains
- this._addToFiltersByDomain(key, filter);
- }
- }
-
- FilterNotifier.emit("elemhideupdate");
- },
-
- _removeFilterKey(key, filter)
- {
- if (filterKeyBySelector[filter.selector] == key)
- {
- delete filterKeyBySelector[filter.selector];
- unconditionalSelectors = unconditionalFilterKeys = null;
- return;
- }
-
- // We haven't found this filter in unconditional filters, look in
- // filtersByDomain.
- let domains = filter.domains || defaultDomains;
- for (let domain in domains)
- {
- let filters = filtersByDomain[domain];
- if (filters)
- delete filters[key];
- }
- },
-
- /**
- * Removes an element hiding filter
- * @param {ElemHideFilter} filter
- */
- remove(filter)
- {
- if (filter instanceof ElemHideException)
- {
- if (!(filter.text in knownExceptions))
- return;
-
- let list = exceptions[filter.selector];
- let index = list.indexOf(filter);
- if (index >= 0)
- list.splice(index, 1);
- delete knownExceptions[filter.text];
- }
- else
- {
- if (!(filter.text in keyByFilter))
- return;
-
- let key = keyByFilter[filter.text];
- delete filterByKey[key];
- delete keyByFilter[filter.text];
- this._removeFilterKey(key, filter);
- }
-
- FilterNotifier.emit("elemhideupdate");
- },
-
- /**
- * Checks whether an exception rule is registered for a filter on a particular
- * domain.
- * @param {Filter} filter
- * @param {string} docDomain
- * @return {ElemHideException}
- */
- getException(filter, docDomain)
- {
- if (!(filter.selector in exceptions))
- return null;
-
- let list = exceptions[filter.selector];
- for (let i = list.length - 1; i >= 0; i--)
- {
- if (list[i].isActiveOnDomain(docDomain))
- return list[i];
- }
-
- return null;
- },
-
- /**
- * Retrieves an element hiding filter by the corresponding protocol key
- * @param {number} key
- * @return {Filter}
- */
- getFilterByKey(key)
- {
- return (key in filterByKey ? filterByKey[key] : null);
- },
-
- /**
- * Returns a list of all selectors as a nested map. On first level, the keys
- * are all values of `ElemHideBase.selectorDomain` (domains on which these
- * selectors should apply, ignoring exceptions). The values are maps again,
- * with the keys being selectors and values the corresponding filter keys.
- * @returns {Map.<String,Map<String,String>>}
- */
- getSelectors()
- {
- let domains = new Map();
- for (let key in filterByKey)
- {
- let filter = filterByKey[key];
- if (!filter.selector)
- continue;
-
- let domain = filter.selectorDomain || "";
-
- if (!domains.has(domain))
- domains.set(domain, new Map());
- domains.get(domain).set(filter.selector, key);
- }
-
- return domains;
- },
-
- /**
- * Returns a list of selectors that apply on each website unconditionally.
- * @returns {string[]}
- */
- getUnconditionalSelectors()
- {
- if (!unconditionalSelectors)
- unconditionalSelectors = Object.keys(filterKeyBySelector);
- return unconditionalSelectors.slice();
- },
-
- /**
- * Returns a list of filter keys for selectors which apply to all websites
- * without exception.
- * @returns {number[]}
- */
- getUnconditionalFilterKeys()
- {
- if (!unconditionalFilterKeys)
- {
- let selectors = this.getUnconditionalSelectors();
- unconditionalFilterKeys = [];
- for (let selector of selectors)
- unconditionalFilterKeys.push(filterKeyBySelector[selector]);
- }
- return unconditionalFilterKeys.slice();
- },
-
-
- /**
- * Constant used by getSelectorsForDomain to return all selectors applying to
- * a particular hostname.
- */
- ALL_MATCHING: 0,
-
- /**
- * Constant used by getSelectorsForDomain to exclude selectors which apply to
- * all websites without exception.
- */
- NO_UNCONDITIONAL: 1,
-
- /**
- * Constant used by getSelectorsForDomain to return only selectors for filters
- * which specifically match the given host name.
- */
- SPECIFIC_ONLY: 2,
-
- /**
- * Determines from the current filter list which selectors should be applied
- * on a particular host name. Optionally returns the corresponding filter
- * keys.
- * @param {string} domain
- * @param {number} [criteria]
- * One of the following: ElemHide.ALL_MATCHING, ElemHide.NO_UNCONDITIONAL or
- * ElemHide.SPECIFIC_ONLY.
- * @param {boolean} [provideFilterKeys]
- * If true, the function will return a list of corresponding filter keys in
- * addition to selectors.
- * @returns {string[]|Array.<string[]>}
- * List of selectors or an array with two elements (list of selectors and
- * list of corresponding keys) if provideFilterKeys is true.
- */
- getSelectorsForDomain(domain, criteria, provideFilterKeys)
- {
- let filterKeys = [];
- let selectors = [];
-
- if (typeof criteria == "undefined")
- criteria = ElemHide.ALL_MATCHING;
- if (criteria < ElemHide.NO_UNCONDITIONAL)
- {
- selectors = this.getUnconditionalSelectors();
- if (provideFilterKeys)
- filterKeys = this.getUnconditionalFilterKeys();
- }
-
- let specificOnly = (criteria >= ElemHide.SPECIFIC_ONLY);
- let seenFilters = Object.create(null);
- let currentDomain = domain ? domain.toUpperCase() : "";
- while (true)
- {
- if (specificOnly && currentDomain == "")
- break;
-
- let filters = filtersByDomain[currentDomain];
- if (filters)
- {
- for (let filterKey in filters)
- {
- if (filterKey in seenFilters)
- continue;
- seenFilters[filterKey] = true;
-
- let filter = filters[filterKey];
- if (filter && !this.getException(filter, domain))
- {
- selectors.push(filter.selector);
- // It is faster to always push the key, even if not required.
- filterKeys.push(filterKey);
- }
- }
- }
-
- if (currentDomain == "")
- break;
-
- let nextDot = currentDomain.indexOf(".");
- currentDomain = nextDot == -1 ? "" : currentDomain.substr(nextDot + 1);
- }
-
- if (provideFilterKeys)
- return [selectors, filterKeys];
- return selectors;
- }
-};
diff --git a/data/extensions/spyblock@gnu.org/lib/elemHideEmulation.js b/data/extensions/spyblock@gnu.org/lib/elemHideEmulation.js
deleted file mode 100644
index edf2082..0000000
--- a/data/extensions/spyblock@gnu.org/lib/elemHideEmulation.js
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-"use strict";
-
-/**
- * @fileOverview Element hiding emulation implementation.
- */
-
-const {ElemHide} = require("elemHide");
-const {Filter} = require("filterClasses");
-
-let filters = Object.create(null);
-
-/**
- * Container for element hiding emulation filters
- * @class
- */
-let ElemHideEmulation = {
- /**
- * Removes all known filters
- */
- clear()
- {
- filters = Object.create(null);
- },
-
- /**
- * Add a new element hiding emulation filter
- * @param {ElemHideEmulationFilter} filter
- */
- add(filter)
- {
- filters[filter.text] = true;
- },
-
- /**
- * Removes an element hiding emulation filter
- * @param {ElemHideEmulationFilter} filter
- */
- remove(filter)
- {
- delete filters[filter.text];
- },
-
- /**
- * Returns a list of all rules active on a particular domain
- * @param {string} domain
- * @return {ElemHideEmulationFilter[]}
- */
- getRulesForDomain(domain)
- {
- let result = [];
- let keys = Object.getOwnPropertyNames(filters);
- for (let key of keys)
- {
- let filter = Filter.fromText(key);
- if (filter.isActiveOnDomain(domain) &&
- !ElemHide.getException(filter, domain))
- {
- result.push(filter);
- }
- }
- return result;
- }
-};
-exports.ElemHideEmulation = ElemHideEmulation;
diff --git a/data/extensions/spyblock@gnu.org/lib/elemHideFF.js b/data/extensions/spyblock@gnu.org/lib/elemHideFF.js
deleted file mode 100644
index fe42e11..0000000
--- a/data/extensions/spyblock@gnu.org/lib/elemHideFF.js
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-"use strict";
-
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-let {port} = require("messaging");
-let {ElemHide} = require("elemHide");
-let {FilterNotifier} = require("filterNotifier");
-let {FilterStorage} = require("filterStorage");
-let {Prefs} = require("prefs");
-let {Policy} = require("contentPolicy");
-let {Utils} = require("utils");
-
-let isDirty = false;
-FilterNotifier.on("elemhideupdate", () =>
-{
- // Notify content process asynchronously, only one message per update batch.
- if (!isDirty)
- {
- isDirty = true;
- Utils.runAsync(() => {
- isDirty = false;
- port.emit("elemhideupdate")
- });
- }
-});
-
-port.on("getUnconditionalSelectors", () =>
-{
- return [
- ElemHide.getUnconditionalSelectors(),
- ElemHide.getUnconditionalFilterKeys()
- ];
-});
-
-port.on("getSelectorsForDomain", ([domain, specificOnly]) =>
-{
- let type = specificOnly ? ElemHide.SPECIFIC_ONLY : ElemHide.NO_UNCONDITIONAL;
- return ElemHide.getSelectorsForDomain(domain, type, true);
-});
-
-port.on("elemhideEnabled", ({frames, isPrivate}) =>
-{
- if (!Prefs.enabled || !Policy.isBlockableScheme(frames[0].location))
- return {enabled: false};
-
- let hit = Policy.isFrameWhitelisted(frames, true);
- if (hit)
- {
- let [frameIndex, contentType, docDomain, thirdParty, location, filter] = hit;
- if (!isPrivate)
- FilterStorage.increaseHitCount(filter);
- return {
- enabled: contentType == "GENERICHIDE",
- contentType, docDomain, thirdParty, location,
- filter: filter.text, filterType: filter.type
- };
- }
-
- return {enabled: true};
-});
-
-port.on("registerElemHideHit", ({key, frames, isPrivate}) =>
-{
- let filter = ElemHide.getFilterByKey(key);
- if (!filter)
- return null;
-
- if (!isPrivate)
- FilterStorage.increaseHitCount(filter);
-
- let docDomain;
- try
- {
- docDomain = Utils.unwrapURL(frames[0].location).host;
- }
- catch(e)
- {
- docDomain = null;
- }
-
- return {
- contentType: "ELEMHIDE",
- docDomain,
- thirdParty: false,
- location: filter.text.replace(/^.*?#/, '#'),
- filter: filter.text,
- filterType: filter.type
- };
-});
diff --git a/data/extensions/spyblock@gnu.org/lib/events.js b/data/extensions/spyblock@gnu.org/lib/events.js
deleted file mode 100644
index 8d11f7c..0000000
--- a/data/extensions/spyblock@gnu.org/lib/events.js
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-"use strict";
-
-/**
- * Registers and emits named events.
- *
- * @constructor
- */
-exports.EventEmitter = function()
-{
- this._listeners = Object.create(null);
-};
-
-exports.EventEmitter.prototype = {
- /**
- * Adds a listener for the specified event name.
- *
- * @param {string} name
- * @param {function} listener
- */
- on(name, listener)
- {
- if (name in this._listeners)
- this._listeners[name].push(listener);
- else
- this._listeners[name] = [listener];
- },
-
- /**
- * Removes a listener for the specified event name.
- *
- * @param {string} name
- * @param {function} listener
- */
- off(name, listener)
- {
- let listeners = this._listeners[name];
- if (listeners)
- {
- let idx = listeners.indexOf(listener);
- if (idx != -1)
- listeners.splice(idx, 1);
- }
- },
-
- /**
- * Adds a one time listener and returns a promise that
- * is resolved the next time the specified event is emitted.
- * @param {string} name
- * @return {Promise}
- */
- once(name)
- {
- return new Promise(resolve =>
- {
- let listener = () =>
- {
- this.off(name, listener);
- resolve();
- };
-
- this.on(name, listener);
- });
- },
-
- /**
- * Returns a copy of the array of listeners for the specified event.
- *
- * @param {string} name
- * @return {function[]}
- */
- listeners(name)
- {
- let listeners = this._listeners[name];
- return listeners ? listeners.slice() : [];
- },
-
- /**
- * Calls all previously added listeners for the given event name.
- *
- * @param {string} name
- * @param {...*} [arg]
- */
- emit(name, ...args)
- {
- let listeners = this.listeners(name);
- for (let listener of listeners)
- listener(...args);
- }
-};
diff --git a/data/extensions/spyblock@gnu.org/lib/ext_background.js b/data/extensions/spyblock@gnu.org/lib/ext_background.js
deleted file mode 100644
index b57f96c..0000000
--- a/data/extensions/spyblock@gnu.org/lib/ext_background.js
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-let {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", null);
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", null);
-
-let {_EventTarget: EventTarget, i18n} = require("ext_common");
-let {port} = require("messaging");
-
-exports.onMessage = new EventTarget(port);
-exports.i18n = i18n;
-
-function Page(windowID)
-{
- this._windowID = windowID;
-}
-Page.prototype = {
- sendMessage: function(payload)
- {
- port.emit("ext_message", {targetID: this._windowID, payload});
- }
-};
-exports.Page = Page;
-
-function PageMap()
-{
- this._map = new Map();
-
- port.on("ext_disconnect", windowID => this._map.delete(windowID));
-}
-PageMap.prototype = {
- keys: function()
- {
- let result = [];
- for (let windowID of this._map.keys())
- result.push(new Page(windowID));
- return result;
- },
-
- get: function(page)
- {
- return this._map.get(page._windowID);
- },
-
- set: function(page, value)
- {
- this._map.set(page._windowID, value);
- },
-
- has: function(page)
- {
- return this._map.has(page._windowID);
- },
-
- delete: function(page)
- {
- return this._map.delete(page._windowID);
- }
-};
-exports.PageMap = PageMap;
-
-exports.showOptions = function()
-{
- require("ui").UI.openFiltersDialog();
-};
diff --git a/data/extensions/spyblock@gnu.org/lib/ext_common.js b/data/extensions/spyblock@gnu.org/lib/ext_common.js
deleted file mode 100644
index 296c00f..0000000
--- a/data/extensions/spyblock@gnu.org/lib/ext_common.js
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-(function(global)
-{
- const Cu = Components.utils;
-
- let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
- if (!global.ext)
- global.ext = {};
-
- var wrapperSymbol = Symbol("ext-wrapper");
-
- function wrapFrames(frames)
- {
- if (!frames.length)
- return null;
-
- // We have frames as an array, non-Firefox code expects url and parent
- // properties however.
- Object.defineProperty(frames, "url", {
- enumerable: true,
- get: () => new URL(frames[0].location)
- });
-
- Object.defineProperty(frames, "parent", {
- enumerable: true,
- get: () => wrapFrames(frames.slice(1))
- });
-
- return frames;
- }
-
- var EventTarget = global.ext._EventTarget = function(port, windowID)
- {
- this._port = port;
- this._windowID = windowID;
- this.addListener((payload, sender, resolve) =>
- {
- if (payload.type)
- {
- let result = this._port._dispatch(payload.type, payload, sender);
- if (typeof result != "undefined")
- resolve(result);
- }
- });
- };
- EventTarget.prototype = {
- addListener: function(listener)
- {
- var wrapper = (message, sender) =>
- {
- if (this._windowID && this._windowID != message.targetID)
- return undefined;
-
- return new Promise((resolve, reject) =>
- {
- var sender = {};
- if (message.senderID)
- {
- // We will only get here on the background side so we can access
- // the Page object.
- const Page = require("ext_background").Page;
- sender.page = new Page(message.senderID);
- }
- if (message.frames)
- sender.frame = wrapFrames(message.frames);
- if (!listener(message.payload, sender, resolve))
- resolve(undefined);
- });
- };
- listener[wrapperSymbol] = wrapper;
- this._port.on("ext_message", wrapper);
- },
-
- removeListener: function(listener)
- {
- if (listener[wrapperSymbol])
- this._port.off("ext_message", listener[wrapperSymbol]);
- }
- };
-
- let pageName = "global";
- if (typeof location !== "undefined")
- pageName = location.pathname.replace(/.*\//, "").replace(/\..*?$/, "");
-
- let stringBundle = Services.strings.createBundle(
- "chrome://adblockplus/locale/" + pageName + ".properties?" + Math.random());
-
- global.ext.i18n = {
- getMessage(key, args)
- {
- try {
- return stringBundle.GetStringFromName(key);
- }
- catch(e)
- {
- // Don't report errors for special strings, these are expected to be
- // missing.
- if (key[0] != "@")
- Cu.reportError(e);
- return "";
- }
- }
- };
-
- if (typeof exports == "object")
- exports = global.ext;
-})(this);
diff --git a/data/extensions/spyblock@gnu.org/lib/filterClasses.js b/data/extensions/spyblock@gnu.org/lib/filterClasses.js
deleted file mode 100644
index 3612728..0000000
--- a/data/extensions/spyblock@gnu.org/lib/filterClasses.js
+++ /dev/null
@@ -1,1061 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-"use strict";
-
-/**
- * @fileOverview Definition of Filter class and its subclasses.
- */
-
-const {FilterNotifier} = require("filterNotifier");
-const {extend} = require("coreUtils");
-const {filterToRegExp} = require("common");
-
-/**
- * Abstract base class for filters
- *
- * @param {string} text string representation of the filter
- * @constructor
- */
-function Filter(text)
-{
- this.text = text;
- this.subscriptions = [];
-}
-exports.Filter = Filter;
-
-Filter.prototype =
-{
- /**
- * String representation of the filter
- * @type {string}
- */
- text: null,
-
- /**
- * Filter subscriptions the filter belongs to
- * @type {Subscription[]}
- */
- subscriptions: null,
-
- /**
- * Filter type as a string, e.g. "blocking".
- * @type {string}
- */
- get type()
- {
- throw new Error("Please define filter type in the subclass");
- },
-
- /**
- * Serializes the filter to an array of strings for writing out on the disk.
- * @param {string[]} buffer buffer to push the serialization results into
- */
- serialize(buffer)
- {
- buffer.push("[Filter]");
- buffer.push("text=" + this.text);
- },
-
- toString()
- {
- return this.text;
- }
-};
-
-/**
- * Cache for known filters, maps string representation to filter objects.
- * @type {Object}
- */
-Filter.knownFilters = Object.create(null);
-
-/**
- * Regular expression that element hiding filters should match
- * @type {RegExp}
- */
-Filter.elemhideRegExp = /^([^/*|@"!]*?)#(@)?(?:([\w-]+|\*)((?:\([\w-]+(?:[$^*]?=[^()"]*)?\))*)|#(.+))$/;
-/**
- * Regular expression that RegExp filters specified as RegExps should match
- * @type {RegExp}
- */
-Filter.regexpRegExp = /^(@@)?\/.*\/(?:\$~?[\w-]+(?:=[^,\s]+)?(?:,~?[\w-]+(?:=[^,\s]+)?)*)?$/;
-/**
- * Regular expression that options on a RegExp filter should match
- * @type {RegExp}
- */
-Filter.optionsRegExp = /\$(~?[\w-]+(?:=[^,\s]+)?(?:,~?[\w-]+(?:=[^,\s]+)?)*)$/;
-
-/**
- * Creates a filter of correct type from its text representation - does the
- * basic parsing and calls the right constructor then.
- *
- * @param {string} text as in Filter()
- * @return {Filter}
- */
-Filter.fromText = function(text)
-{
- if (text in Filter.knownFilters)
- return Filter.knownFilters[text];
-
- let ret;
- let match = (text.includes("#") ? Filter.elemhideRegExp.exec(text) : null);
- if (match)
- {
- ret = ElemHideBase.fromText(
- text, match[1], !!match[2], match[3], match[4], match[5]
- );
- }
- else if (text[0] == "!")
- ret = new CommentFilter(text);
- else
- ret = RegExpFilter.fromText(text);
-
- Filter.knownFilters[ret.text] = ret;
- return ret;
-};
-
-/**
- * Deserializes a filter
- *
- * @param {Object} obj map of serialized properties and their values
- * @return {Filter} filter or null if the filter couldn't be created
- */
-Filter.fromObject = function(obj)
-{
- let ret = Filter.fromText(obj.text);
- if (ret instanceof ActiveFilter)
- {
- if ("disabled" in obj)
- ret._disabled = (obj.disabled == "true");
- if ("hitCount" in obj)
- ret._hitCount = parseInt(obj.hitCount, 10) || 0;
- if ("lastHit" in obj)
- ret._lastHit = parseInt(obj.lastHit, 10) || 0;
- }
- return ret;
-};
-
-/**
- * Removes unnecessary whitespaces from filter text, will only return null if
- * the input parameter is null.
- * @param {string} text
- * @return {string}
- */
-Filter.normalize = function(text)
-{
- if (!text)
- return text;
-
- // Remove line breaks and such
- text = text.replace(/[^\S ]/g, "");
-
- if (/^\s*!/.test(text))
- {
- // Don't remove spaces inside comments
- return text.trim();
- }
- else if (Filter.elemhideRegExp.test(text))
- {
- // Special treatment for element hiding filters, right side is allowed to
- // contain spaces
- let [, domain, separator, selector] = /^(.*?)(#@?#?)(.*)$/.exec(text);
- return domain.replace(/\s/g, "") + separator + selector.trim();
- }
- return text.replace(/\s/g, "");
-};
-
-/**
- * @see filterToRegExp
- */
-Filter.toRegExp = filterToRegExp;
-
-/**
- * Class for invalid filters
- * @param {string} text see Filter()
- * @param {string} reason Reason why this filter is invalid
- * @constructor
- * @augments Filter
- */
-function InvalidFilter(text, reason)
-{
- Filter.call(this, text);
-
- this.reason = reason;
-}
-exports.InvalidFilter = InvalidFilter;
-
-InvalidFilter.prototype = extend(Filter, {
- type: "invalid",
-
- /**
- * Reason why this filter is invalid
- * @type {string}
- */
- reason: null,
-
- /**
- * See Filter.serialize()
- * @inheritdoc
- */
- serialize(buffer) {}
-});
-
-/**
- * Class for comments
- * @param {string} text see Filter()
- * @constructor
- * @augments Filter
- */
-function CommentFilter(text)
-{
- Filter.call(this, text);
-}
-exports.CommentFilter = CommentFilter;
-
-CommentFilter.prototype = extend(Filter, {
- type: "comment",
-
- /**
- * See Filter.serialize()
- * @inheritdoc
- */
- serialize(buffer) {}
-});
-
-/**
- * Abstract base class for filters that can get hits
- * @param {string} text
- * see Filter()
- * @param {string} [domains]
- * Domains that the filter is restricted to separated by domainSeparator
- * e.g. "foo.com|bar.com|~baz.com"
- * @constructor
- * @augments Filter
- */
-function ActiveFilter(text, domains)
-{
- Filter.call(this, text);
-
- this.domainSource = domains;
-}
-exports.ActiveFilter = ActiveFilter;
-
-ActiveFilter.prototype = extend(Filter, {
- _disabled: false,
- _hitCount: 0,
- _lastHit: 0,
-
- /**
- * Defines whether the filter is disabled
- * @type {boolean}
- */
- get disabled()
- {
- return this._disabled;
- },
- set disabled(value)
- {
- if (value != this._disabled)
- {
- let oldValue = this._disabled;
- this._disabled = value;
- FilterNotifier.triggerListeners("filter.disabled", this, value, oldValue);
- }
- return this._disabled;
- },
-
- /**
- * Number of hits on the filter since the last reset
- * @type {number}
- */
- get hitCount()
- {
- return this._hitCount;
- },
- set hitCount(value)
- {
- if (value != this._hitCount)
- {
- let oldValue = this._hitCount;
- this._hitCount = value;
- FilterNotifier.triggerListeners("filter.hitCount", this, value, oldValue);
- }
- return this._hitCount;
- },
-
- /**
- * Last time the filter had a hit (in milliseconds since the beginning of the
- * epoch)
- * @type {number}
- */
- get lastHit()
- {
- return this._lastHit;
- },
- set lastHit(value)
- {
- if (value != this._lastHit)
- {
- let oldValue = this._lastHit;
- this._lastHit = value;
- FilterNotifier.triggerListeners("filter.lastHit", this, value, oldValue);
- }
- return this._lastHit;
- },
-
- /**
- * String that the domains property should be generated from
- * @type {string}
- */
- domainSource: null,
-
- /**
- * Separator character used in domainSource property, must be
- * overridden by subclasses
- * @type {string}
- */
- domainSeparator: null,
-
- /**
- * Determines whether the trailing dot in domain names isn't important and
- * should be ignored, must be overridden by subclasses.
- * @type {boolean}
- */
- ignoreTrailingDot: true,
-
- /**
- * Determines whether domainSource is already upper-case,
- * can be overridden by subclasses.
- * @type {boolean}
- */
- domainSourceIsUpperCase: false,
-
- /**
- * Map containing domains that this filter should match on/not match
- * on or null if the filter should match on all domains
- * @type {Object}
- */
- get domains()
- {
- // Despite this property being cached, the getter is called
- // several times on Safari, due to WebKit bug 132872
- let prop = Object.getOwnPropertyDescriptor(this, "domains");
- if (prop)
- return prop.value;
-
- let domains = null;
-
- if (this.domainSource)
- {
- let source = this.domainSource;
- if (!this.domainSourceIsUpperCase)
- {
- // RegExpFilter already have uppercase domains
- source = source.toUpperCase();
- }
- let list = source.split(this.domainSeparator);
- if (list.length == 1 && list[0][0] != "~")
- {
- // Fast track for the common one-domain scenario
- domains = Object.create(null);
- domains[""] = false;
- if (this.ignoreTrailingDot)
- list[0] = list[0].replace(/\.+$/, "");
- domains[list[0]] = true;
- }
- else
- {
- let hasIncludes = false;
- for (let i = 0; i < list.length; i++)
- {
- let domain = list[i];
- if (this.ignoreTrailingDot)
- domain = domain.replace(/\.+$/, "");
- if (domain == "")
- continue;
-
- let include;
- if (domain[0] == "~")
- {
- include = false;
- domain = domain.substr(1);
- }
- else
- {
- include = true;
- hasIncludes = true;
- }
-
- if (!domains)
- domains = Object.create(null);
-
- domains[domain] = include;
- }
- if (domains)
- domains[""] = !hasIncludes;
- }
-
- this.domainSource = null;
- }
-
- Object.defineProperty(this, "domains", {value: domains, enumerable: true});
- return this.domains;
- },
-
- /**
- * Array containing public keys of websites that this filter should apply to
- * @type {string[]}
- */
- sitekeys: null,
-
- /**
- * Checks whether this filter is active on a domain.
- * @param {string} docDomain domain name of the document that loads the URL
- * @param {string} [sitekey] public key provided by the document
- * @return {boolean} true in case of the filter being active
- */
- isActiveOnDomain(docDomain, sitekey)
- {
- // Sitekeys are case-sensitive so we shouldn't convert them to
- // upper-case to avoid false positives here. Instead we need to
- // change the way filter options are parsed.
- if (this.sitekeys &&
- (!sitekey || this.sitekeys.indexOf(sitekey.toUpperCase()) < 0))
- {
- return false;
- }
-
- // If no domains are set the rule matches everywhere
- if (!this.domains)
- return true;
-
- // If the document has no host name, match only if the filter
- // isn't restricted to specific domains
- if (!docDomain)
- return this.domains[""];
-
- if (this.ignoreTrailingDot)
- docDomain = docDomain.replace(/\.+$/, "");
- docDomain = docDomain.toUpperCase();
-
- while (true)
- {
- if (docDomain in this.domains)
- return this.domains[docDomain];
-
- let nextDot = docDomain.indexOf(".");
- if (nextDot < 0)
- break;
- docDomain = docDomain.substr(nextDot + 1);
- }
- return this.domains[""];
- },
-
- /**
- * Checks whether this filter is active only on a domain and its subdomains.
- * @param {string} docDomain
- * @return {boolean}
- */
- isActiveOnlyOnDomain(docDomain)
- {
- if (!docDomain || !this.domains || this.domains[""])
- return false;
-
- if (this.ignoreTrailingDot)
- docDomain = docDomain.replace(/\.+$/, "");
- docDomain = docDomain.toUpperCase();
-
- for (let domain in this.domains)
- {
- if (this.domains[domain] && domain != docDomain)
- {
- if (domain.length <= docDomain.length)
- return false;
-
- if (!domain.endsWith("." + docDomain))
- return false;
- }
- }
-
- return true;
- },
-
- /**
- * Checks whether this filter is generic or specific
- * @return {boolean}
- */
- isGeneric()
- {
- return !(this.sitekeys && this.sitekeys.length) &&
- (!this.domains || this.domains[""]);
- },
-
- /**
- * See Filter.serialize()
- * @inheritdoc
- */
- serialize(buffer)
- {
- if (this._disabled || this._hitCount || this._lastHit)
- {
- Filter.prototype.serialize.call(this, buffer);
- if (this._disabled)
- buffer.push("disabled=true");
- if (this._hitCount)
- buffer.push("hitCount=" + this._hitCount);
- if (this._lastHit)
- buffer.push("lastHit=" + this._lastHit);
- }
- }
-});
-
-/**
- * Abstract base class for RegExp-based filters
- * @param {string} text see Filter()
- * @param {string} regexpSource
- * filter part that the regular expression should be build from
- * @param {number} [contentType]
- * Content types the filter applies to, combination of values from
- * RegExpFilter.typeMap
- * @param {boolean} [matchCase]
- * Defines whether the filter should distinguish between lower and upper case
- * letters
- * @param {string} [domains]
- * Domains that the filter is restricted to, e.g. "foo.com|bar.com|~baz.com"
- * @param {boolean} [thirdParty]
- * Defines whether the filter should apply to third-party or first-party
- * content only
- * @param {string} [sitekeys]
- * Public keys of websites that this filter should apply to
- * @constructor
- * @augments ActiveFilter
- */
-function RegExpFilter(text, regexpSource, contentType, matchCase, domains,
- thirdParty, sitekeys)
-{
- ActiveFilter.call(this, text, domains, sitekeys);
-
- if (contentType != null)
- this.contentType = contentType;
- if (matchCase)
- this.matchCase = matchCase;
- if (thirdParty != null)
- this.thirdParty = thirdParty;
- if (sitekeys != null)
- this.sitekeySource = sitekeys;
-
- if (regexpSource.length >= 2 &&
- regexpSource[0] == "/" &&
- regexpSource[regexpSource.length - 1] == "/")
- {
- // The filter is a regular expression - convert it immediately to
- // catch syntax errors
- let regexp = new RegExp(regexpSource.substr(1, regexpSource.length - 2),
- this.matchCase ? "" : "i");
- Object.defineProperty(this, "regexp", {value: regexp});
- }
- else
- {
- // No need to convert this filter to regular expression yet, do it on demand
- this.regexpSource = regexpSource;
- }
-}
-exports.RegExpFilter = RegExpFilter;
-
-RegExpFilter.prototype = extend(ActiveFilter, {
- /**
- * @see ActiveFilter.domainSourceIsUpperCase
- */
- domainSourceIsUpperCase: true,
-
- /**
- * Number of filters contained, will always be 1 (required to
- * optimize Matcher).
- * @type {number}
- */
- length: 1,
-
- /**
- * @see ActiveFilter.domainSeparator
- */
- domainSeparator: "|",
-
- /**
- * Expression from which a regular expression should be generated -
- * for delayed creation of the regexp property
- * @type {string}
- */
- regexpSource: null,
- /**
- * Regular expression to be used when testing against this filter
- * @type {RegExp}
- */
- get regexp()
- {
- // Despite this property being cached, the getter is called
- // several times on Safari, due to WebKit bug 132872
- let prop = Object.getOwnPropertyDescriptor(this, "regexp");
- if (prop)
- return prop.value;
-
- let source = Filter.toRegExp(this.regexpSource);
- let regexp = new RegExp(source, this.matchCase ? "" : "i");
- Object.defineProperty(this, "regexp", {value: regexp});
- return regexp;
- },
- /**
- * Content types the filter applies to, combination of values from
- * RegExpFilter.typeMap
- * @type {number}
- */
- contentType: 0x7FFFFFFF,
- /**
- * Defines whether the filter should distinguish between lower and
- * upper case letters
- * @type {boolean}
- */
- matchCase: false,
- /**
- * Defines whether the filter should apply to third-party or
- * first-party content only. Can be null (apply to all content).
- * @type {boolean}
- */
- thirdParty: null,
-
- /**
- * String that the sitekey property should be generated from
- * @type {string}
- */
- sitekeySource: null,
-
- /**
- * Array containing public keys of websites that this filter should apply to
- * @type {string[]}
- */
- get sitekeys()
- {
- // Despite this property being cached, the getter is called
- // several times on Safari, due to WebKit bug 132872
- let prop = Object.getOwnPropertyDescriptor(this, "sitekeys");
- if (prop)
- return prop.value;
-
- let sitekeys = null;
-
- if (this.sitekeySource)
- {
- sitekeys = this.sitekeySource.split("|");
- this.sitekeySource = null;
- }
-
- Object.defineProperty(
- this, "sitekeys", {value: sitekeys, enumerable: true}
- );
- return this.sitekeys;
- },
-
- /**
- * Tests whether the URL matches this filter
- * @param {string} location URL to be tested
- * @param {number} typeMask bitmask of content / request types to match
- * @param {string} docDomain domain name of the document that loads the URL
- * @param {boolean} thirdParty should be true if the URL is a third-party
- * request
- * @param {string} sitekey public key provided by the document
- * @return {boolean} true in case of a match
- */
- matches(location, typeMask, docDomain, thirdParty, sitekey, privatenode)
- {
- if(this.subscriptions[0])
- if (this.subscriptions[0].privateMode)
- if (privatenode==false)
- return false;
-
- if (this.contentType & typeMask &&
- (this.thirdParty == null || this.thirdParty == thirdParty) &&
- this.isActiveOnDomain(docDomain, sitekey) && this.regexp.test(location))
- {
- return true;
- }
- return false;
- }
-});
-
-// Required to optimize Matcher, see also RegExpFilter.prototype.length
-Object.defineProperty(RegExpFilter.prototype, "0", {
- get() { return this; }
-});
-
-/**
- * Creates a RegExp filter from its text representation
- * @param {string} text same as in Filter()
- * @return {Filter}
- */
-RegExpFilter.fromText = function(text)
-{
- let blocking = true;
- let origText = text;
- if (text.indexOf("@@") == 0)
- {
- blocking = false;
- text = text.substr(2);
- }
-
- let contentType = null;
- let matchCase = null;
- let domains = null;
- let sitekeys = null;
- let thirdParty = null;
- let collapse = null;
- let options;
- let match = (text.indexOf("$") >= 0 ? Filter.optionsRegExp.exec(text) : null);
- if (match)
- {
- options = match[1].toUpperCase().split(",");
- text = match.input.substr(0, match.index);
- for (let option of options)
- {
- let value = null;
- let separatorIndex = option.indexOf("=");
- if (separatorIndex >= 0)
- {
- value = option.substr(separatorIndex + 1);
- option = option.substr(0, separatorIndex);
- }
- option = option.replace(/-/, "_");
- if (option in RegExpFilter.typeMap)
- {
- if (contentType == null)
- contentType = 0;
- contentType |= RegExpFilter.typeMap[option];
- }
- else if (option[0] == "~" && option.substr(1) in RegExpFilter.typeMap)
- {
- if (contentType == null)
- ({contentType} = RegExpFilter.prototype);
- contentType &= ~RegExpFilter.typeMap[option.substr(1)];
- }
- else if (option == "MATCH_CASE")
- matchCase = true;
- else if (option == "~MATCH_CASE")
- matchCase = false;
- else if (option == "DOMAIN" && typeof value != "undefined")
- domains = value;
- else if (option == "THIRD_PARTY")
- thirdParty = true;
- else if (option == "~THIRD_PARTY")
- thirdParty = false;
- else if (option == "COLLAPSE")
- collapse = true;
- else if (option == "~COLLAPSE")
- collapse = false;
- else if (option == "SITEKEY" && typeof value != "undefined")
- sitekeys = value;
- else
- return new InvalidFilter(origText, "filter_unknown_option");
- }
- }
-
- try
- {
- if (blocking)
- {
- return new BlockingFilter(origText, text, contentType, matchCase, domains,
- thirdParty, sitekeys, collapse);
- }
- return new WhitelistFilter(origText, text, contentType, matchCase, domains,
- thirdParty, sitekeys);
- }
- catch (e)
- {
- return new InvalidFilter(origText, "filter_invalid_regexp");
- }
-};
-
-/**
- * Maps type strings like "SCRIPT" or "OBJECT" to bit masks
- */
-RegExpFilter.typeMap = {
- OTHER: 1,
- SCRIPT: 2,
- IMAGE: 4,
- STYLESHEET: 8,
- OBJECT: 16,
- SUBDOCUMENT: 32,
- DOCUMENT: 64,
- WEBSOCKET: 128,
- WEBRTC: 256,
- XBL: 1,
- PING: 1024,
- XMLHTTPREQUEST: 2048,
- OBJECT_SUBREQUEST: 4096,
- DTD: 1,
- MEDIA: 16384,
- FONT: 32768,
-
- BACKGROUND: 4, // Backwards compat, same as IMAGE
-
- POPUP: 0x10000000,
- GENERICBLOCK: 0x20000000,
- ELEMHIDE: 0x40000000,
- GENERICHIDE: 0x80000000
-};
-
-// DOCUMENT, ELEMHIDE, POPUP, GENERICHIDE and GENERICBLOCK options shouldn't
-// be there by default
-RegExpFilter.prototype.contentType &= ~(RegExpFilter.typeMap.DOCUMENT |
- RegExpFilter.typeMap.ELEMHIDE |
- RegExpFilter.typeMap.POPUP |
- RegExpFilter.typeMap.GENERICHIDE |
- RegExpFilter.typeMap.GENERICBLOCK);
-
-/**
- * Class for blocking filters
- * @param {string} text see Filter()
- * @param {string} regexpSource see RegExpFilter()
- * @param {number} contentType see RegExpFilter()
- * @param {boolean} matchCase see RegExpFilter()
- * @param {string} domains see RegExpFilter()
- * @param {boolean} thirdParty see RegExpFilter()
- * @param {string} sitekeys see RegExpFilter()
- * @param {boolean} collapse
- * defines whether the filter should collapse blocked content, can be null
- * @constructor
- * @augments RegExpFilter
- */
-function BlockingFilter(text, regexpSource, contentType, matchCase, domains,
- thirdParty, sitekeys, collapse)
-{
- RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains,
- thirdParty, sitekeys);
-
- this.collapse = collapse;
-}
-exports.BlockingFilter = BlockingFilter;
-
-BlockingFilter.prototype = extend(RegExpFilter, {
- type: "blocking",
-
- /**
- * Defines whether the filter should collapse blocked content.
- * Can be null (use the global preference).
- * @type {boolean}
- */
- collapse: null
-});
-
-/**
- * Class for whitelist filters
- * @param {string} text see Filter()
- * @param {string} regexpSource see RegExpFilter()
- * @param {number} contentType see RegExpFilter()
- * @param {boolean} matchCase see RegExpFilter()
- * @param {string} domains see RegExpFilter()
- * @param {boolean} thirdParty see RegExpFilter()
- * @param {string} sitekeys see RegExpFilter()
- * @constructor
- * @augments RegExpFilter
- */
-function WhitelistFilter(text, regexpSource, contentType, matchCase, domains,
- thirdParty, sitekeys)
-{
- RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains,
- thirdParty, sitekeys);
-}
-exports.WhitelistFilter = WhitelistFilter;
-
-WhitelistFilter.prototype = extend(RegExpFilter, {
- type: "whitelist"
-});
-
-/**
- * Base class for element hiding filters
- * @param {string} text see Filter()
- * @param {string} [domains] Host names or domains the filter should be
- * restricted to
- * @param {string} selector CSS selector for the HTML elements that should be
- * hidden
- * @constructor
- * @augments ActiveFilter
- */
-function ElemHideBase(text, domains, selector)
-{
- ActiveFilter.call(this, text, domains || null);
-
- if (domains)
- {
- this.selectorDomain = domains.replace(/,~[^,]+/g, "")
- .replace(/^~[^,]+,?/, "").toLowerCase();
- }
-
- // Braces are being escaped to prevent CSS rule injection.
- this.selector = selector.replace("{", "\\x7B ").replace("}", "\\x7D ");
-}
-exports.ElemHideBase = ElemHideBase;
-
-ElemHideBase.prototype = extend(ActiveFilter, {
- /**
- * @see ActiveFilter.domainSeparator
- */
- domainSeparator: ",",
-
- /**
- * @see ActiveFilter.ignoreTrailingDot
- */
- ignoreTrailingDot: false,
-
- /**
- * Host name or domain the filter should be restricted to (can be null for
- * no restriction)
- * @type {string}
- */
- selectorDomain: null,
- /**
- * CSS selector for the HTML elements that should be hidden
- * @type {string}
- */
- selector: null
-});
-
-/**
- * Creates an element hiding filter from a pre-parsed text representation
- *
- * @param {string} text same as in Filter()
- * @param {string} domain
- * domain part of the text representation (can be empty)
- * @param {boolean} isException exception rule indicator
- * @param {string} tagName tag name part (can be empty)
- * @param {string} attrRules attribute matching rules (can be empty)
- * @param {string} selector raw CSS selector (can be empty)
- * @return {ElemHideFilter|ElemHideException|
- * ElemHideEmulationFilter|InvalidFilter}
- */
-ElemHideBase.fromText = function(text, domain, isException, tagName, attrRules,
- selector)
-{
- if (!selector)
- {
- if (tagName == "*")
- tagName = "";
-
- let id = null;
- let additional = "";
- if (attrRules)
- {
- attrRules = attrRules.match(/\([\w-]+(?:[$^*]?=[^()"]*)?\)/g);
- for (let rule of attrRules)
- {
- rule = rule.substr(1, rule.length - 2);
- let separatorPos = rule.indexOf("=");
- if (separatorPos > 0)
- {
- rule = rule.replace(/=/, '="') + '"';
- additional += "[" + rule + "]";
- }
- else
- {
- if (id)
- return new InvalidFilter(text, "filter_elemhide_duplicate_id");
-
- id = rule;
- }
- }
- }
-
- if (id)
- selector = `${tagName}.${id}${additional},${tagName}#${id}${additional}`;
- else if (tagName || additional)
- selector = tagName + additional;
- else
- return new InvalidFilter(text, "filter_elemhide_nocriteria");
- }
-
- // We don't allow ElemHide filters which have any empty domains.
- // Note: The ElemHide.prototype.domainSeparator is duplicated here, if that
- // changes this must be changed too.
- if (domain && /(^|,)~?(,|$)/.test(domain))
- return new InvalidFilter(text, "filter_invalid_domain");
-
- if (isException)
- return new ElemHideException(text, domain, selector);
-
- if (selector.indexOf("[-abp-properties=") != -1)
- {
- // Element hiding emulation filters are inefficient so we need to make sure
- // that they're only applied if they specify active domains
- if (!/,[^~][^,.]*\.[^,]/.test("," + domain))
- return new InvalidFilter(text, "filter_elemhideemulation_nodomain");
-
- return new ElemHideEmulationFilter(text, domain, selector);
- }
-
- return new ElemHideFilter(text, domain, selector);
-};
-
-/**
- * Class for element hiding filters
- * @param {string} text see Filter()
- * @param {string} domains see ElemHideBase()
- * @param {string} selector see ElemHideBase()
- * @constructor
- * @augments ElemHideBase
- */
-function ElemHideFilter(text, domains, selector)
-{
- ElemHideBase.call(this, text, domains, selector);
-}
-exports.ElemHideFilter = ElemHideFilter;
-
-ElemHideFilter.prototype = extend(ElemHideBase, {
- type: "elemhide"
-});
-
-/**
- * Class for element hiding exceptions
- * @param {string} text see Filter()
- * @param {string} domains see ElemHideBase()
- * @param {string} selector see ElemHideBase()
- * @constructor
- * @augments ElemHideBase
- */
-function ElemHideException(text, domains, selector)
-{
- ElemHideBase.call(this, text, domains, selector);
-}
-exports.ElemHideException = ElemHideException;
-
-ElemHideException.prototype = extend(ElemHideBase, {
- type: "elemhideexception"
-});
-
-/**
- * Class for element hiding emulation filters
- * @param {string} text see Filter()
- * @param {string} domains see ElemHideBase()
- * @param {string} selector see ElemHideBase()
- * @constructor
- * @augments ElemHideBase
- */
-function ElemHideEmulationFilter(text, domains, selector)
-{
- ElemHideBase.call(this, text, domains, selector);
-}
-exports.ElemHideEmulationFilter = ElemHideEmulationFilter;
-
-ElemHideEmulationFilter.prototype = extend(ElemHideBase, {
- type: "elemhideemulation"
-});
diff --git a/data/extensions/spyblock@gnu.org/lib/filterListener.js b/data/extensions/spyblock@gnu.org/lib/filterListener.js
deleted file mode 100644
index 8700602..0000000
--- a/data/extensions/spyblock@gnu.org/lib/filterListener.js
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-"use strict";
-
-/**
- * @fileOverview Component synchronizing filter storage with Matcher
- * instances and ElemHide.
- */
-
-const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-const {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
-
-const {FilterStorage} = require("filterStorage");
-const {FilterNotifier} = require("filterNotifier");
-const {ElemHide} = require("elemHide");
-const {ElemHideEmulation} = require("elemHideEmulation");
-const {defaultMatcher} = require("matcher");
-const {ActiveFilter, RegExpFilter,
- ElemHideBase, ElemHideEmulationFilter} = require("filterClasses");
-const {Prefs} = require("prefs");
-
-/**
- * Increases on filter changes, filters will be saved if it exceeds 1.
- * @type {number}
- */
-let isDirty = 0;
-
-/**
- * This object can be used to change properties of the filter change listeners.
- * @class
- */
-let FilterListener = {
- /**
- * Increases "dirty factor" of the filters and calls
- * FilterStorage.saveToDisk() if it becomes 1 or more. Save is
- * executed delayed to prevent multiple subsequent calls. If the
- * parameter is 0 it forces saving filters if any changes were
- * recorded after the previous save.
- * @param {number} factor
- */
- setDirty(factor)
- {
- if (factor == 0 && isDirty > 0)
- isDirty = 1;
- else
- isDirty += factor;
- if (isDirty >= 1)
- {
- isDirty = 0;
- FilterStorage.saveToDisk();
- }
- }
-};
-
-/**
- * Observer listening to history purge actions.
- * @class
- */
-let HistoryPurgeObserver = {
- observe(subject, topic, data)
- {
- if (topic == "browser:purge-session-history" &&
- Prefs.clearStatsOnHistoryPurge)
- {
- FilterStorage.resetHitCounts();
- FilterListener.setDirty(0); // Force saving to disk
-
- Prefs.recentReports = [];
- }
- },
- QueryInterface: XPCOMUtils.generateQI(
- [Ci.nsISupportsWeakReference, Ci.nsIObserver]
- )
-};
-
-/**
- * Initializes filter listener on startup, registers the necessary hooks.
- */
-function init()
-{
- FilterNotifier.on("filter.hitCount", onFilterHitCount);
- FilterNotifier.on("filter.lastHit", onFilterLastHit);
- FilterNotifier.on("filter.added", onFilterAdded);
- FilterNotifier.on("filter.removed", onFilterRemoved);
- FilterNotifier.on("filter.disabled", onFilterDisabled);
- FilterNotifier.on("filter.moved", onGenericChange);
-
- FilterNotifier.on("subscription.added", onSubscriptionAdded);
- FilterNotifier.on("subscription.removed", onSubscriptionRemoved);
- FilterNotifier.on("subscription.disabled", onSubscriptionDisabled);
- FilterNotifier.on("subscription.updated", onSubscriptionUpdated);
- FilterNotifier.on("subscription.moved", onGenericChange);
- FilterNotifier.on("subscription.title", onGenericChange);
- FilterNotifier.on("subscription.fixedTitle", onGenericChange);
- FilterNotifier.on("subscription.homepage", onGenericChange);
- FilterNotifier.on("subscription.downloadStatus", onGenericChange);
- FilterNotifier.on("subscription.lastCheck", onGenericChange);
- FilterNotifier.on("subscription.errors", onGenericChange);
-
- FilterNotifier.on("load", onLoad);
- FilterNotifier.on("save", onSave);
-
- FilterStorage.loadFromDisk();
-
- Services.obs.addObserver(HistoryPurgeObserver,
- "browser:purge-session-history", true);
- onShutdown.add(() =>
- {
- Services.obs.removeObserver(HistoryPurgeObserver,
- "browser:purge-session-history");
- });
-}
-init();
-
-/**
- * Notifies Matcher instances or ElemHide object about a new filter
- * if necessary.
- * @param {Filter} filter filter that has been added
- */
-function addFilter(filter)
-{
- if (!(filter instanceof ActiveFilter) || filter.disabled)
- return;
-
- let hasEnabled = false;
- for (let i = 0; i < filter.subscriptions.length; i++)
- {
- if (!filter.subscriptions[i].disabled)
- hasEnabled = true;
- }
- if (!hasEnabled)
- return;
-
- if (filter instanceof RegExpFilter)
- defaultMatcher.add(filter);
- else if (filter instanceof ElemHideBase)
- {
- if (filter instanceof ElemHideEmulationFilter)
- ElemHideEmulation.add(filter);
- else
- ElemHide.add(filter);
- }
-}
-
-/**
- * Notifies Matcher instances or ElemHide object about removal of a filter
- * if necessary.
- * @param {Filter} filter filter that has been removed
- */
-function removeFilter(filter)
-{
- if (!(filter instanceof ActiveFilter))
- return;
-
- if (!filter.disabled)
- {
- let hasEnabled = false;
- for (let i = 0; i < filter.subscriptions.length; i++)
- {
- if (!filter.subscriptions[i].disabled)
- hasEnabled = true;
- }
- if (hasEnabled)
- return;
- }
-
- if (filter instanceof RegExpFilter)
- defaultMatcher.remove(filter);
- else if (filter instanceof ElemHideBase)
- {
- if (filter instanceof ElemHideEmulationFilter)
- ElemHideEmulation.remove(filter);
- else
- ElemHide.remove(filter);
- }
-}
-
-const primes = [101, 109, 131, 149, 163, 179, 193, 211, 229, 241];
-
-function addFilters(filters)
-{
- // We add filters using pseudo-random ordering. Reason is that ElemHide will
- // assign consecutive filter IDs that might be visible to the website. The
- // randomization makes sure that no conclusion can be made about the actual
- // filters applying there. We have ten prime numbers to use as iteration step,
- // any of those can be chosen as long as the array length isn't divisible by
- // it.
- let len = filters.length;
- if (!len)
- return;
-
- let current = (Math.random() * len) | 0;
- let step;
- do
- {
- step = primes[(Math.random() * primes.length) | 0];
- } while (len % step == 0);
-
- for (let i = 0; i < len; i++, current = (current + step) % len)
- addFilter(filters[current]);
-}
-
-function onSubscriptionAdded(subscription)
-{
- FilterListener.setDirty(1);
-
- if (!subscription.disabled)
- addFilters(subscription.filters);
-}
-
-function onSubscriptionRemoved(subscription)
-{
- FilterListener.setDirty(1);
-
- if (!subscription.disabled)
- subscription.filters.forEach(removeFilter);
-}
-
-function onSubscriptionDisabled(subscription, newValue)
-{
- FilterListener.setDirty(1);
-
- if (subscription.url in FilterStorage.knownSubscriptions)
- {
- if (newValue == false)
- addFilters(subscription.filters);
- else
- subscription.filters.forEach(removeFilter);
- }
-}
-
-function onSubscriptionUpdated(subscription)
-{
- FilterListener.setDirty(1);
-
- if (subscription.url in FilterStorage.knownSubscriptions &&
- !subscription.disabled)
- {
- subscription.oldFilters.forEach(removeFilter);
- addFilters(subscription.filters);
- }
-}
-
-function onFilterHitCount(filter, newValue)
-{
- if (newValue == 0)
- FilterListener.setDirty(0);
- else
- FilterListener.setDirty(0.002);
-}
-
-function onFilterLastHit()
-{
- FilterListener.setDirty(0.002);
-}
-
-function onFilterAdded(filter)
-{
- FilterListener.setDirty(1);
-
- if (!filter.disabled)
- addFilter(filter);
-}
-
-function onFilterRemoved(filter)
-{
- FilterListener.setDirty(1);
-
- if (!filter.disabled)
- removeFilter(filter);
-}
-
-function onFilterDisabled(filter, newValue)
-{
- FilterListener.setDirty(1);
-
- if (newValue == false)
- addFilter(filter);
- else
- removeFilter(filter);
-}
-
-function onGenericChange()
-{
- FilterListener.setDirty(1);
-}
-
-function onLoad()
-{
- isDirty = 0;
-
- defaultMatcher.clear();
- ElemHide.clear();
- ElemHideEmulation.clear();
- for (let subscription of FilterStorage.subscriptions)
- {
- if (!subscription.disabled)
- addFilters(subscription.filters);
- }
-}
-
-function onSave()
-{
- isDirty = 0;
-}
diff --git a/data/extensions/spyblock@gnu.org/lib/filterNotifier.js b/data/extensions/spyblock@gnu.org/lib/filterNotifier.js
deleted file mode 100644
index 66697cc..0000000
--- a/data/extensions/spyblock@gnu.org/lib/filterNotifier.js
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-"use strict";
-
-/**
- * @fileOverview This component manages listeners and calls them to distributes
- * messages about filter changes.
- */
-
-const {EventEmitter} = require("events");
-const {desc} = require("coreUtils");
-
-const CATCH_ALL = "__all";
-
-/**
- * @callback FilterNotifierCatchAllListener
- * @param {string} action
- * @param {Subscription|Filter} item
- * @param {...*} additionalInfo
- */
-
-/**
- * This class allows registering and triggering listeners for filter events.
- * @class
- */
-exports.FilterNotifier = Object.create(new EventEmitter(), desc({
- /**
- * Adds a listener
- *
- * @deprecated use FilterNotifier.on(action, callback)
- * @param {FilterNotifierCatchAllListener} listener
- */
- addListener(listener)
- {
- let listeners = this._listeners[CATCH_ALL];
- if (!listeners || listeners.indexOf(listener) == -1)
- this.on(CATCH_ALL, listener);
- },
-
- /**
- * Removes a listener that was previosly added via addListener
- *
- * @deprecated use FilterNotifier.off(action, callback)
- * @param {FilterNotifierCatchAllListener} listener
- */
- removeListener(listener)
- {
- this.off(CATCH_ALL, listener);
- },
-
- /**
- * Notifies listeners about an event
- * @param {string} action event code ("load", "save", "elemhideupdate",
- * "subscription.added", "subscription.removed",
- * "subscription.disabled", "subscription.title",
- * "subscription.lastDownload", "subscription.downloadStatus",
- * "subscription.homepage", "subscription.updated",
- * "filter.added", "filter.removed", "filter.moved",
- * "filter.disabled", "filter.hitCount", "filter.lastHit")
- * @param {Subscription|Filter} item item that the change applies to
- * @param {*} param1
- * @param {*} param2
- * @param {*} param3
- * @deprecated use FilterNotifier.emit(action)
- */
- triggerListeners(action, item, param1, param2, param3)
- {
- this.emit(action, item, param1, param2, param3);
- this.emit(CATCH_ALL, action, item, param1, param2, param3);
- }
-}));
diff --git a/data/extensions/spyblock@gnu.org/lib/filterStorage.js b/data/extensions/spyblock@gnu.org/lib/filterStorage.js
deleted file mode 100644
index 5bbf76c..0000000
--- a/data/extensions/spyblock@gnu.org/lib/filterStorage.js
+++ /dev/null
@@ -1,786 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-"use strict";
-
-/**
- * @fileOverview FilterStorage class responsible for managing user's
- * subscriptions and filters.
- */
-
-const {IO} = require("io");
-const {Prefs} = require("prefs");
-const {Filter, ActiveFilter} = require("filterClasses");
-const {Subscription, SpecialSubscription,
- ExternalSubscription} = require("subscriptionClasses");
-const {FilterNotifier} = require("filterNotifier");
-
-/**
- * Version number of the filter storage file format.
- * @type {number}
- */
-let formatVersion = 5;
-
-/**
- * This class reads user's filters from disk, manages them in memory
- * and writes them back.
- * @class
- */
-let FilterStorage = exports.FilterStorage =
-{
- /**
- * Will be set to true after the initial loadFromDisk() call completes.
- * @type {boolean}
- */
- initialized: false,
-
- /**
- * Version number of the patterns.ini format used.
- * @type {number}
- */
- get formatVersion()
- {
- return formatVersion;
- },
-
- /**
- * File containing the filter list
- * @type {string}
- */
- get sourceFile()
- {
- return "patterns.ini";
- },
-
- /**
- * Will be set to true if no patterns.ini file exists.
- * @type {boolean}
- */
- firstRun: false,
-
- /**
- * Map of properties listed in the filter storage file before the sections
- * start. Right now this should be only the format version.
- */
- fileProperties: Object.create(null),
-
- /**
- * List of filter subscriptions containing all filters
- * @type {Subscription[]}
- */
- subscriptions: [],
-
- /**
- * Map of subscriptions already on the list, by their URL/identifier
- * @type {Object}
- */
- knownSubscriptions: Object.create(null),
-
- /**
- * Finds the filter group that a filter should be added to by default. Will
- * return null if this group doesn't exist yet.
- * @param {Filter} filter
- * @return {?SpecialSubscription}
- */
- getGroupForFilter(filter)
- {
- let generalSubscription = null;
- for (let subscription of FilterStorage.subscriptions)
- {
- if (subscription instanceof SpecialSubscription && !subscription.disabled)
- {
- // Always prefer specialized subscriptions
- if (subscription.isDefaultFor(filter))
- return subscription;
-
- // If this is a general subscription - store it as fallback
- if (!generalSubscription &&
- (!subscription.defaults || !subscription.defaults.length))
- {
- generalSubscription = subscription;
- }
- }
- }
- return generalSubscription;
- },
-
- /**
- * Adds a filter subscription to the list
- * @param {Subscription} subscription filter subscription to be added
- */
- addSubscription(subscription)
- {
- if (subscription.url in FilterStorage.knownSubscriptions)
- return;
-
- FilterStorage.subscriptions.push(subscription);
- FilterStorage.knownSubscriptions[subscription.url] = subscription;
- addSubscriptionFilters(subscription);
-
- FilterNotifier.triggerListeners("subscription.added", subscription);
- },
-
- /**
- * Removes a filter subscription from the list
- * @param {Subscription} subscription filter subscription to be removed
- */
- removeSubscription(subscription)
- {
- for (let i = 0; i < FilterStorage.subscriptions.length; i++)
- {
- if (FilterStorage.subscriptions[i].url == subscription.url)
- {
- removeSubscriptionFilters(subscription);
-
- FilterStorage.subscriptions.splice(i--, 1);
- delete FilterStorage.knownSubscriptions[subscription.url];
- FilterNotifier.triggerListeners("subscription.removed", subscription);
- return;
- }
- }
- },
-
- /**
- * Moves a subscription in the list to a new position.
- * @param {Subscription} subscription filter subscription to be moved
- * @param {Subscription} [insertBefore] filter subscription to insert before
- * (if omitted the subscription will be put at the end of the list)
- */
- moveSubscription(subscription, insertBefore)
- {
- let currentPos = FilterStorage.subscriptions.indexOf(subscription);
- if (currentPos < 0)
- return;
-
- let newPos = -1;
- if (insertBefore)
- newPos = FilterStorage.subscriptions.indexOf(insertBefore);
-
- if (newPos < 0)
- newPos = FilterStorage.subscriptions.length;
-
- if (currentPos < newPos)
- newPos--;
- if (currentPos == newPos)
- return;
-
- FilterStorage.subscriptions.splice(currentPos, 1);
- FilterStorage.subscriptions.splice(newPos, 0, subscription);
- FilterNotifier.triggerListeners("subscription.moved", subscription);
- },
-
- /**
- * Replaces the list of filters in a subscription by a new list
- * @param {Subscription} subscription filter subscription to be updated
- * @param {Filter[]} filters new filter list
- */
- updateSubscriptionFilters(subscription, filters)
- {
- removeSubscriptionFilters(subscription);
- subscription.oldFilters = subscription.filters;
- subscription.filters = filters;
- addSubscriptionFilters(subscription);
- FilterNotifier.triggerListeners("subscription.updated", subscription);
- delete subscription.oldFilters;
- },
-
- /**
- * Adds a user-defined filter to the list
- * @param {Filter} filter
- * @param {SpecialSubscription} [subscription]
- * particular group that the filter should be added to
- * @param {number} [position]
- * position within the subscription at which the filter should be added
- */
- addFilter(filter, subscription, position)
- {
- if (!subscription)
- {
- if (filter.subscriptions.some(s => s instanceof SpecialSubscription &&
- !s.disabled))
- {
- return; // No need to add
- }
- subscription = FilterStorage.getGroupForFilter(filter);
- }
- if (!subscription)
- {
- // No group for this filter exists, create one
- subscription = SpecialSubscription.createForFilter(filter);
- this.addSubscription(subscription);
- return;
- }
-
- if (typeof position == "undefined")
- position = subscription.filters.length;
-
- if (filter.subscriptions.indexOf(subscription) < 0)
- filter.subscriptions.push(subscription);
- subscription.filters.splice(position, 0, filter);
- FilterNotifier.triggerListeners("filter.added", filter, subscription,
- position);
- },
-
- /**
- * Removes a user-defined filter from the list
- * @param {Filter} filter
- * @param {SpecialSubscription} [subscription] a particular filter group that
- * the filter should be removed from (if ommited will be removed from all
- * subscriptions)
- * @param {number} [position] position inside the filter group at which the
- * filter should be removed (if ommited all instances will be removed)
- */
- removeFilter(filter, subscription, position)
- {
- let subscriptions = (
- subscription ? [subscription] : filter.subscriptions.slice()
- );
- for (let i = 0; i < subscriptions.length; i++)
- {
- let currentSubscription = subscriptions[i];
- if (currentSubscription instanceof SpecialSubscription)
- {
- let positions = [];
- if (typeof position == "undefined")
- {
- let index = -1;
- do
- {
- index = currentSubscription.filters.indexOf(filter, index + 1);
- if (index >= 0)
- positions.push(index);
- } while (index >= 0);
- }
- else
- positions.push(position);
-
- for (let j = positions.length - 1; j >= 0; j--)
- {
- let currentPosition = positions[j];
- if (currentSubscription.filters[currentPosition] == filter)
- {
- currentSubscription.filters.splice(currentPosition, 1);
- if (currentSubscription.filters.indexOf(filter) < 0)
- {
- let index = filter.subscriptions.indexOf(currentSubscription);
- if (index >= 0)
- filter.subscriptions.splice(index, 1);
- }
- FilterNotifier.triggerListeners(
- "filter.removed", filter, currentSubscription, currentPosition
- );
- }
- }
- }
- }
- },
-
- /**
- * Moves a user-defined filter to a new position
- * @param {Filter} filter
- * @param {SpecialSubscription} subscription filter group where the filter is
- * located
- * @param {number} oldPosition current position of the filter
- * @param {number} newPosition new position of the filter
- */
- moveFilter(filter, subscription, oldPosition, newPosition)
- {
- if (!(subscription instanceof SpecialSubscription) ||
- subscription.filters[oldPosition] != filter)
- {
- return;
- }
-
- newPosition = Math.min(Math.max(newPosition, 0),
- subscription.filters.length - 1);
- if (oldPosition == newPosition)
- return;
-
- subscription.filters.splice(oldPosition, 1);
- subscription.filters.splice(newPosition, 0, filter);
- FilterNotifier.triggerListeners("filter.moved", filter, subscription,
- oldPosition, newPosition);
- },
-
- /**
- * Increases the hit count for a filter by one
- * @param {Filter} filter
- */
- increaseHitCount(filter)
- {
- if (!Prefs.savestats || !(filter instanceof ActiveFilter))
- return;
-
- filter.hitCount++;
- filter.lastHit = Date.now();
- },
-
- /**
- * Resets hit count for some filters
- * @param {Filter[]} filters filters to be reset, if null all filters will
- * be reset
- */
- resetHitCounts(filters)
- {
- if (!filters)
- {
- filters = [];
- for (let text in Filter.knownFilters)
- filters.push(Filter.knownFilters[text]);
- }
- for (let filter of filters)
- {
- filter.hitCount = 0;
- filter.lastHit = 0;
- }
- },
-
- /**
- * @callback TextSink
- * @param {string?} line
- */
-
- /**
- * Allows importing previously serialized filter data.
- * @param {boolean} silent
- * If true, no "load" notification will be sent out.
- * @return {TextSink}
- * Function to be called for each line of data. Calling it with null as
- * parameter finalizes the import and replaces existing data. No changes
- * will be applied before finalization, so import can be "aborted" by
- * forgetting this callback.
- */
- importData(silent)
- {
- let parser = new INIParser();
- return line =>
- {
- parser.process(line);
- if (line === null)
- {
- let knownSubscriptions = Object.create(null);
- for (let subscription of parser.subscriptions)
- knownSubscriptions[subscription.url] = subscription;
-
- this.fileProperties = parser.fileProperties;
- this.subscriptions = parser.subscriptions;
- this.knownSubscriptions = knownSubscriptions;
- Filter.knownFilters = parser.knownFilters;
- Subscription.knownSubscriptions = parser.knownSubscriptions;
-
- if (!silent)
- FilterNotifier.triggerListeners("load");
- }
- };
- },
-
- /**
- * Loads all subscriptions from the disk.
- * @return {Promise} promise resolved or rejected when loading is complete
- */
- loadFromDisk()
- {
- let tryBackup = backupIndex =>
- {
- return this.restoreBackup(backupIndex, true).then(() =>
- {
- if (this.subscriptions.length == 0)
- return tryBackup(backupIndex + 1);
- }).catch(error =>
- {
- // Give up
- });
- };
-
- return IO.statFile(this.sourceFile).then(statData =>
- {
- if (!statData.exists)
- {
- this.firstRun = true;
- return;
- }
-
- let parser = this.importData(true);
- return IO.readFromFile(this.sourceFile, parser).then(() =>
- {
- parser(null);
- if (this.subscriptions.length == 0)
- {
- // No filter subscriptions in the file, this isn't right.
- throw new Error("No data in the file");
- }
- });
- }).catch(error =>
- {
- Cu.reportError(error);
- return tryBackup(1);
- }).then(() =>
- {
- this.initialized = true;
- FilterNotifier.triggerListeners("load");
- });
- },
-
- /**
- * Constructs the file name for a patterns.ini backup.
- * @param {number} backupIndex
- * number of the backup file (1 being the most recent)
- * @return {string} backup file name
- */
- getBackupName(backupIndex)
- {
- let [name, extension] = this.sourceFile.split(".", 2);
- return (name + "-backup" + backupIndex + "." + extension);
- },
-
- /**
- * Restores an automatically created backup.
- * @param {number} backupIndex
- * number of the backup to restore (1 being the most recent)
- * @param {boolean} silent
- * If true, no "load" notification will be sent out.
- * @return {Promise} promise resolved or rejected when restoring is complete
- */
- restoreBackup(backupIndex, silent)
- {
- let backupFile = this.getBackupName(backupIndex);
- let parser = this.importData(silent);
- return IO.readFromFile(backupFile, parser).then(() =>
- {
- parser(null);
- return this.saveToDisk();
- });
- },
-
- /**
- * Generator serializing filter data and yielding it line by line.
- */
- *exportData()
- {
- // Do not persist external subscriptions
- let subscriptions = this.subscriptions.filter(
- s => !(s instanceof ExternalSubscription)
- );
-
- yield "# Adblock Plus preferences";
- yield "version=" + formatVersion;
-
- let saved = new Set();
- let buf = [];
-
- // Save subscriptions
- for (let subscription of subscriptions)
- {
- yield "";
-
- subscription.serialize(buf);
- if (subscription.filters.length)
- {
- buf.push("", "[Subscription filters]");
- subscription.serializeFilters(buf);
- }
- for (let line of buf)
- yield line;
- buf.splice(0);
- }
-
- // Save filter data
- for (let subscription of subscriptions)
- {
- for (let filter of subscription.filters)
- {
- if (!saved.has(filter.text))
- {
- filter.serialize(buf);
- saved.add(filter.text);
- for (let line of buf)
- yield line;
- buf.splice(0);
- }
- }
- }
- },
-
- /**
- * Will be set to true if saveToDisk() is running (reentrance protection).
- * @type {boolean}
- */
- _saving: false,
-
- /**
- * Will be set to true if a saveToDisk() call arrives while saveToDisk() is
- * already running (delayed execution).
- * @type {boolean}
- */
- _needsSave: false,
-
- /**
- * Saves all subscriptions back to disk
- * @return {Promise} promise resolved or rejected when saving is complete
- */
- saveToDisk()
- {
- if (this._saving)
- {
- this._needsSave = true;
- return;
- }
-
- this._saving = true;
-
- return Promise.resolve().then(() =>
- {
- // First check whether we need to create a backup
- if (Prefs.patternsbackups <= 0)
- return false;
-
- return IO.statFile(this.sourceFile).then(statData =>
- {
- if (!statData.exists)
- return false;
-
- return IO.statFile(this.getBackupName(1)).then(backupStatData =>
- {
- if (backupStatData.exists &&
- (Date.now() - backupStatData.lastModified) / 3600000 <
- Prefs.patternsbackupinterval)
- {
- return false;
- }
- return true;
- });
- });
- }).then(backupRequired =>
- {
- if (!backupRequired)
- return;
-
- let ignoreErrors = error =>
- {
- // Expected error, backup file doesn't exist.
- };
-
- let renameBackup = index =>
- {
- if (index > 0)
- {
- return IO.renameFile(this.getBackupName(index),
- this.getBackupName(index + 1))
- .catch(ignoreErrors)
- .then(() => renameBackup(index - 1));
- }
-
- return IO.renameFile(this.sourceFile, this.getBackupName(1))
- .catch(ignoreErrors);
- };
-
- // Rename existing files
- return renameBackup(Prefs.patternsbackups - 1);
- }).catch(error =>
- {
- // Errors during backup creation shouldn't prevent writing filters.
- Cu.reportError(error);
- }).then(() =>
- {
- return IO.writeToFile(this.sourceFile, this.exportData());
- }).then(() =>
- {
- FilterNotifier.triggerListeners("save");
- }).catch(error =>
- {
- // If saving failed, report error but continue - we still have to process
- // flags.
- Cu.reportError(error);
- }).then(() =>
- {
- this._saving = false;
- if (this._needsSave)
- {
- this._needsSave = false;
- this.saveToDisk();
- }
- });
- },
-
- /**
- * @typedef FileInfo
- * @type {object}
- * @property {nsIFile} file
- * @property {number} lastModified
- */
-
- /**
- * Returns a promise resolving in a list of existing backup files.
- * @return {Promise.<FileInfo[]>}
- */
- getBackupFiles()
- {
- let backups = [];
-
- let checkBackupFile = index =>
- {
- return IO.statFile(this.getBackupName(index)).then(statData =>
- {
- if (!statData.exists)
- return backups;
-
- backups.push({
- index,
- lastModified: statData.lastModified
- });
- return checkBackupFile(index + 1);
- }).catch(error =>
- {
- // Something went wrong, return whatever data we got so far.
- Cu.reportError(error);
- return backups;
- });
- };
-
- return checkBackupFile(1);
- }
-};
-
-/**
- * Joins subscription's filters to the subscription without any notifications.
- * @param {Subscription} subscription
- * filter subscription that should be connected to its filters
- */
-function addSubscriptionFilters(subscription)
-{
- if (!(subscription.url in FilterStorage.knownSubscriptions))
- return;
-
- for (let filter of subscription.filters)
- filter.subscriptions.push(subscription);
-}
-
-/**
- * Removes subscription's filters from the subscription without any
- * notifications.
- * @param {Subscription} subscription filter subscription to be removed
- */
-function removeSubscriptionFilters(subscription)
-{
- if (!(subscription.url in FilterStorage.knownSubscriptions))
- return;
-
- for (let filter of subscription.filters)
- {
- let i = filter.subscriptions.indexOf(subscription);
- if (i >= 0)
- filter.subscriptions.splice(i, 1);
- }
-}
-
-/**
- * Listener returned by FilterStorage.importData(), parses filter data.
- * @constructor
- */
-function INIParser()
-{
- this.fileProperties = this.curObj = {};
- this.subscriptions = [];
- this.knownFilters = Object.create(null);
- this.knownSubscriptions = Object.create(null);
-}
-INIParser.prototype =
-{
- linesProcessed: 0,
- subscriptions: null,
- knownFilters: null,
- knownSubscriptions: null,
- wantObj: true,
- fileProperties: null,
- curObj: null,
- curSection: null,
-
- process(val)
- {
- let origKnownFilters = Filter.knownFilters;
- Filter.knownFilters = this.knownFilters;
- let origKnownSubscriptions = Subscription.knownSubscriptions;
- Subscription.knownSubscriptions = this.knownSubscriptions;
- let match;
- try
- {
- if (this.wantObj === true && (match = /^(\w+)=(.*)$/.exec(val)))
- this.curObj[match[1]] = match[2];
- else if (val === null || (match = /^\s*\[(.+)\]\s*$/.exec(val)))
- {
- if (this.curObj)
- {
- // Process current object before going to next section
- switch (this.curSection)
- {
- case "filter":
- if ("text" in this.curObj)
- Filter.fromObject(this.curObj);
- break;
- case "subscription": {
- let subscription = Subscription.fromObject(this.curObj);
- if (subscription)
- this.subscriptions.push(subscription);
- break;
- }
- case "subscription filters":
- if (this.subscriptions.length)
- {
- let subscription = this.subscriptions[
- this.subscriptions.length - 1
- ];
- for (let text of this.curObj)
- {
- let filter = Filter.fromText(text);
- subscription.filters.push(filter);
- filter.subscriptions.push(subscription);
- }
- }
- break;
- }
- }
-
- if (val === null)
- return;
-
- this.curSection = match[1].toLowerCase();
- switch (this.curSection)
- {
- case "filter":
- case "subscription":
- this.wantObj = true;
- this.curObj = {};
- break;
- case "subscription filters":
- this.wantObj = false;
- this.curObj = [];
- break;
- default:
- this.wantObj = undefined;
- this.curObj = null;
- }
- }
- else if (this.wantObj === false && val)
- this.curObj.push(val.replace(/\\\[/g, "["));
- }
- finally
- {
- Filter.knownFilters = origKnownFilters;
- Subscription.knownSubscriptions = origKnownSubscriptions;
- }
- }
-};
diff --git a/data/extensions/spyblock@gnu.org/lib/io.js b/data/extensions/spyblock@gnu.org/lib/io.js
deleted file mode 100644
index 0a22513..0000000
--- a/data/extensions/spyblock@gnu.org/lib/io.js
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-"use strict";
-
-let {IO: LegacyIO} = require("legacyIO");
-let {Utils} = require("utils");
-
-let webextension = require("webextension");
-let messageID = 0;
-let messageCallbacks = new Map();
-
-webextension.then(port =>
-{
- port.onMessage.addListener(message =>
- {
- let {id} = message;
- let callbacks = messageCallbacks.get(id);
- if (callbacks)
- {
- messageCallbacks.delete(id);
-
- if (message.success)
- callbacks.resolve(message.result);
- else
- callbacks.reject(message.result);
- }
- });
-});
-
-function callWebExt(method, ...args)
-{
- return webextension.then(port =>
- {
- return new Promise((resolve, reject) =>
- {
- let id = ++messageID;
- messageCallbacks.set(id, {resolve, reject});
- port.postMessage({id, method, args});
- });
- });
-}
-
-function callLegacy(method, ...args)
-{
- return new Promise((resolve, reject) =>
- {
- LegacyIO[method](...args, (error, result) =>
- {
- if (error)
- reject(error);
- else
- resolve(result);
- });
- });
-}
-
-function legacyFile(fileName)
-{
- let file = LegacyIO.resolveFilePath("adblockplus");
- file.append(fileName);
- return file;
-}
-
-function ensureDirExists(file)
-{
- if (!file.exists())
- {
- ensureDirExists(file.parent);
- file.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
- }
-}
-
-let fallback = {
- readFromFile(fileName, listener)
- {
- let wrapper = {
- process(line)
- {
- if (line !== null)
- listener(line);
- }
- };
- return callLegacy("readFromFile", legacyFile(fileName), wrapper);
- },
-
- writeToFile(fileName, data)
- {
- let file = legacyFile(fileName);
- ensureDirExists(file.parent);
- return callLegacy("writeToFile", file, data);
- },
-
- copyFile(fromFile, toFile)
- {
- return callLegacy("copyFile", legacyFile(fromFile), legacyFile(toFile));
- },
-
- renameFile(fromFile, newName)
- {
- return callLegacy("renameFile", legacyFile(fromFile), newName);
- },
-
- removeFile(fileName)
- {
- return callLegacy("removeFile", legacyFile(fileName));
- },
-
- statFile(fileName)
- {
- return callLegacy("statFile", legacyFile(fileName));
- }
-};
-
-exports.IO =
-{
- /**
- * @callback TextSink
- * @param {string} line
- */
-
- /**
- * Reads text lines from a file.
- * @param {string} fileName
- * Name of the file to be read
- * @param {TextSink} listener
- * Function that will be called for each line in the file
- * @return {Promise}
- * Promise to be resolved or rejected once the operation is completed
- */
- readFromFile(fileName, listener)
- {
- return callWebExt("readFromFile", fileName).then(contents =>
- {
- return new Promise((resolve, reject) =>
- {
- let lineIndex = 0;
-
- function processBatch()
- {
- while (lineIndex < contents.length)
- {
- listener(contents[lineIndex++]);
- if (lineIndex % 1000 == 0)
- {
- Utils.runAsync(processBatch);
- return;
- }
- }
- resolve();
- }
-
- processBatch();
- });
- });
- },
-
- /**
- * Writes text lines to a file.
- * @param {string} fileName
- * Name of the file to be written
- * @param {Iterable.<string>} data
- * An array-like or iterable object containing the lines (without line
- * endings)
- * @return {Promise}
- * Promise to be resolved or rejected once the operation is completed
- */
- writeToFile(fileName, data)
- {
- return callWebExt("writeToFile", fileName, Array.from(data));
- },
-
- /**
- * Copies a file.
- * @param {string} fromFile
- * Name of the file to be copied
- * @param {string} toFile
- * Name of the file to be written, will be overwritten if exists
- * @return {Promise}
- * Promise to be resolved or rejected once the operation is completed
- */
- copyFile(fromFile, toFile)
- {
- return callWebExt("copyFile", fromFile, toFile);
- },
-
- /**
- * Renames a file.
- * @param {string} fromFile
- * Name of the file to be renamed
- * @param {string} newName
- * New file name, will be overwritten if exists
- * @return {Promise}
- * Promise to be resolved or rejected once the operation is completed
- */
- renameFile(fromFile, newName)
- {
- return callWebExt("renameFile", fromFile, newName);
- },
-
- /**
- * Removes a file.
- * @param {string} fileName
- * Name of the file to be removed
- * @return {Promise}
- * Promise to be resolved or rejected once the operation is completed
- */
- removeFile(fileName)
- {
- return callWebExt("removeFile", fileName);
- },
-
- /**
- * @typedef StatData
- * @type {object}
- * @property {boolean} exists
- * true if the file exists
- * @property {number} lastModified
- * file modification time in milliseconds
- */
-
- /**
- * Retrieves file metadata.
- * @param {string} fileName
- * Name of the file to be looked up
- * @return {Promise.<StatData>}
- * Promise to be resolved with file metadata once the operation is
- * completed
- */
- statFile(fileName)
- {
- return callWebExt("statFile", fileName);
- }
-};
-
-let {application} = require("info");
-if (application != "firefox" && application != "fennec2")
-{
- // Currently, only Firefox has a working WebExtensions implementation, other
- // applications should just use the fallback.
- exports.IO = fallback;
-}
-else
-{
- // Add fallbacks to IO methods - fall back to legacy I/O if file wasn't found.
- for (let name of Object.getOwnPropertyNames(exports.IO))
- {
- // No fallback for writeToFile method, new data should always be stored to
- // new storage only.
- if (name == "writeToFile")
- continue;
-
- let method = exports.IO[name];
- let fallbackMethod = fallback[name];
- exports.IO[name] = (...args) =>
- {
- return method(...args).catch(error =>
- {
- if (error == "NoSuchFile")
- return fallbackMethod(...args);
- throw error;
- });
- };
- }
-}
diff --git a/data/extensions/spyblock@gnu.org/lib/keySelector.js b/data/extensions/spyblock@gnu.org/lib/keySelector.js
deleted file mode 100644
index 151f50d..0000000
--- a/data/extensions/spyblock@gnu.org/lib/keySelector.js
+++ /dev/null
@@ -1,227 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-Cu.import("resource://gre/modules/Services.jsm");
-
-let validModifiers = Object.create(null);
-validModifiers.ACCEL = null;
-validModifiers.CTRL = "control";
-validModifiers.CONTROL = "control";
-validModifiers.SHIFT = "shift";
-validModifiers.ALT = "alt";
-validModifiers.META = "meta";
-
-let bindingsKeys = null;
-(function()
-{
- let request = new XMLHttpRequest();
- request.open("GET", "chrome://global/content/platformHTMLBindings.xml");
- request.addEventListener("load", () =>
- {
- bindingsKeys = request.responseXML.getElementsByTagName("handler");
- });
- request.send();
-})();
-
-
-/**
- * Sets the correct value of validModifiers.ACCEL.
- */
-function initAccelKey()
-{
- validModifiers.ACCEL = "control";
- try
- {
- let accelKey = Services.prefs.getIntPref("ui.key.accelKey");
- if (accelKey == Ci.nsIDOMKeyEvent.DOM_VK_CONTROL)
- validModifiers.ACCEL = "control";
- else if (accelKey == Ci.nsIDOMKeyEvent.DOM_VK_ALT)
- validModifiers.ACCEL = "alt";
- else if (accelKey == Ci.nsIDOMKeyEvent.DOM_VK_META)
- validModifiers.ACCEL = "meta";
- }
- catch(e)
- {
- Cu.reportError(e);
- }
-}
-
-exports.KeySelector = KeySelector;
-
-/**
- * This class provides capabilities to find and use available keyboard shortcut
- * keys.
- * @param {ChromeWindow} window the window where to look up existing shortcut
- * keys
- * @constructor
- */
-function KeySelector(window)
-{
- this._initExistingShortcuts(window);
-}
-KeySelector.prototype =
-{
- /**
- * Map listing existing shortcut keys as its keys.
- * @type Object
- */
- _existingShortcuts: null,
-
- /**
- * Sets up _existingShortcuts property for a window.
- */
- _initExistingShortcuts: function(/**ChromeWindow*/ window)
- {
- if (!validModifiers.ACCEL)
- initAccelKey();
-
- this._existingShortcuts = Object.create(null);
-
- let keys = Array.prototype.slice.apply(window.document.getElementsByTagName("key"));
- if (bindingsKeys)
- keys.push.apply(keys, bindingsKeys);
- for (let i = 0; i < keys.length; i++)
- {
- let key = keys[i];
- let keyData =
- {
- shift: false,
- meta: false,
- alt: false,
- control: false,
- char: null,
- code: null
- };
-
- let keyChar = key.getAttribute("key");
- if (keyChar && keyChar.length == 1)
- keyData.char = keyChar.toUpperCase();
-
- let keyCode = key.getAttribute("keycode");
- if (keyCode && "DOM_" + keyCode.toUpperCase() in Ci.nsIDOMKeyEvent)
- keyData.code = Ci.nsIDOMKeyEvent["DOM_" + keyCode.toUpperCase()];
-
- if (!keyData.char && !keyData.code)
- continue;
-
- let keyModifiers = key.getAttribute("modifiers");
- if (keyModifiers)
- for (let modifier of keyModifiers.toUpperCase().match(/\w+/g))
- if (modifier in validModifiers)
- keyData[validModifiers[modifier]] = true;
-
- let canonical = [keyData.shift, keyData.meta, keyData.alt, keyData.control, keyData.char || keyData.code].join(" ");
- this._existingShortcuts[canonical] = true;
- }
- },
-
- /**
- * Selects a keyboard shortcut variant that isn't already taken,
- * parses it into an object.
- */
- selectKey: function(/**String*/ variants) /**Object*/
- {
- for (let variant of variants.split(/\s*,\s*/))
- {
- if (!variant)
- continue;
-
- let keyData =
- {
- shift: false,
- meta: false,
- alt: false,
- control: false,
- char: null,
- code: null,
- codeName: null
- };
- for (let part of variant.toUpperCase().split(/\s+/))
- {
- if (part in validModifiers)
- keyData[validModifiers[part]] = true;
- else if (part.length == 1)
- keyData.char = part;
- else if ("DOM_VK_" + part in Ci.nsIDOMKeyEvent)
- {
- keyData.code = Ci.nsIDOMKeyEvent["DOM_VK_" + part];
- keyData.codeName = "VK_" + part;
- }
- }
-
- if (!keyData.char && !keyData.code)
- continue;
-
- let canonical = [keyData.shift, keyData.meta, keyData.alt, keyData.control, keyData.char || keyData.code].join(" ");
- if (canonical in this._existingShortcuts)
- continue;
-
- return keyData;
- }
-
- return null;
- }
-};
-
-/**
- * Creates the text representation for a key.
- * @static
- */
-KeySelector.getTextForKey = function (/**Object*/ key) /**String*/
-{
- if (!key)
- return null;
-
- if (!("text" in key))
- {
- key.text = null;
- try
- {
- let stringBundle = Services.strings.createBundle("chrome://global-platform/locale/platformKeys.properties");
- let parts = [];
- if (key.control)
- parts.push(stringBundle.GetStringFromName("VK_CONTROL"));
- if (key.alt)
- parts.push(stringBundle.GetStringFromName("VK_ALT"));
- if (key.meta)
- parts.push(stringBundle.GetStringFromName("VK_META"));
- if (key.shift)
- parts.push(stringBundle.GetStringFromName("VK_SHIFT"));
- if (key.char)
- parts.push(key.char.toUpperCase());
- else
- {
- let stringBundle2 = Services.strings.createBundle("chrome://global/locale/keys.properties");
- parts.push(stringBundle2.GetStringFromName(key.codeName));
- }
- key.text = parts.join(stringBundle.GetStringFromName("MODIFIER_SEPARATOR"));
- }
- catch (e)
- {
- Cu.reportError(e);
- return null;
- }
- }
- return key.text;
-};
-
-/**
- * Tests whether a keypress event matches the given key.
- * @static
- */
-KeySelector.matchesKey = function(/**Event*/ event, /**Object*/ key) /**Boolean*/
-{
- if (event.defaultPrevented || !key)
- return false;
- if (key.shift != event.shiftKey || key.alt != event.altKey)
- return false;
- if (key.meta != event.metaKey || key.control != event.ctrlKey)
- return false;
-
- if (key.char && event.charCode && String.fromCharCode(event.charCode).toUpperCase() == key.char)
- return true;
- if (key.code && event.keyCode && event.keyCode == key.code)
- return true;
- return false;
-};
diff --git a/data/extensions/spyblock@gnu.org/lib/legacyIO.js b/data/extensions/spyblock@gnu.org/lib/legacyIO.js
deleted file mode 100644
index 5549d96..0000000
--- a/data/extensions/spyblock@gnu.org/lib/legacyIO.js
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * @fileOverview Module containing file I/O helpers.
- */
-
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", null);
-let {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", null);
-let {OS} = Cu.import("resource://gre/modules/osfile.jsm", null);
-let {Task} = Cu.import("resource://gre/modules/Task.jsm", null);
-
-let {Prefs} = require("prefs");
-let {Utils} = require("utils");
-
-let firstRead = true;
-const BUFFER_SIZE = 0x80000; // 512kB
-
-let IO = exports.IO =
-{
- /**
- * Retrieves the platform-dependent line break string.
- */
- get lineBreak()
- {
- let lineBreak = (Services.appinfo.OS == "WINNT" ? "\r\n" : "\n");
- Object.defineProperty(this, "lineBreak", {value: lineBreak});
- return lineBreak;
- },
-
- /**
- * Tries to interpret a file path as an absolute path or a path relative to
- * user's profile. Returns a file or null on failure.
- */
- resolveFilePath: function(/**String*/ path) /**nsIFile*/
- {
- if (!path)
- return null;
-
- try {
- // Assume an absolute path first
- return new FileUtils.File(path);
- } catch (e) {}
-
- try {
- // Try relative path now
- return FileUtils.getFile("ProfD", path.split("/"));
- } catch (e) {}
-
- return null;
- },
-
- /**
- * Reads strings from a file asynchronously, calls listener.process() with
- * each line read and with a null parameter once the read operation is done.
- * The callback will be called when the operation is done.
- */
- readFromFile: function(/**nsIFile*/ file, /**Object*/ listener, /**Function*/ callback)
- {
- try
- {
- let processing = false;
- let buffer = "";
- let loaded = false;
- let error = null;
-
- let onProgress = function*(data)
- {
- let index = (processing ? -1 : Math.max(data.lastIndexOf("\n"), data.lastIndexOf("\r")));
- if (index >= 0)
- {
- // Protect against reentrance in case the listener processes events.
- processing = true;
- try
- {
- let oldBuffer = buffer;
- buffer = data.substr(index + 1);
- data = data.substr(0, index + 1);
- let lines = data.split(/[\r\n]+/);
- lines.pop();
- lines[0] = oldBuffer + lines[0];
- for (let i = 0; i < lines.length; i++)
- listener.process(lines[i]);
- }
- finally
- {
- processing = false;
- data = buffer;
- buffer = "";
- yield* onProgress(data);
-
- if (loaded)
- {
- loaded = false;
- onSuccess();
- }
-
- if (error)
- {
- let param = error;
- error = null;
- onError(param);
- }
- }
- }
- else
- buffer += data;
- };
-
- let onSuccess = function()
- {
- if (processing)
- {
- // Still processing data, delay processing this event.
- loaded = true;
- return;
- }
-
- // We are ignoring return value of listener.process() here because
- // turning this callback into a generator would be complicated, and
- // delaying isn't really necessary for the last two calls.
- if (buffer !== "")
- listener.process(buffer);
- listener.process(null);
-
- callback(null);
- };
-
- let onError = function(e)
- {
- if (processing)
- {
- // Still processing data, delay processing this event.
- error = e;
- return;
- }
-
- callback(e);
- };
-
- let decoder = new TextDecoder();
- Task.spawn(function*()
- {
- if (firstRead && Services.vc.compare(Utils.platformVersion, "23.0a1") <= 0)
- {
- // See https://issues.adblockplus.org/ticket/530 - the first file
- // opened cannot be closed due to Gecko bug 858723. Make sure that
- // our patterns.ini file doesn't stay locked by opening a dummy file
- // first.
- try
- {
- let dummyPath = IO.resolveFilePath(Prefs.data_directory + "/dummy").path;
- let dummy = yield OS.File.open(dummyPath, {write: true, truncate: true});
- yield dummy.close();
- }
- catch (e)
- {
- // Dummy might be locked already, we don't care
- }
- }
- firstRead = false;
-
- let f = yield OS.File.open(file.path, {read: true});
- while (true)
- {
- let array = yield f.read(BUFFER_SIZE);
- if (!array.length)
- break;
-
- let data = decoder.decode(array, {stream: true});
- yield* onProgress(data);
- }
- yield f.close();
- }.bind(this)).then(onSuccess, onError);
- }
- catch (e)
- {
- callback(e);
- }
- },
-
- /**
- * Writes string data to a file in UTF-8 format asynchronously. The callback
- * will be called when the write operation is done.
- */
- writeToFile: function(/**nsIFile*/ file, /**Iterator*/ data, /**Function*/ callback)
- {
- try
- {
- let encoder = new TextEncoder();
-
- Task.spawn(function*()
- {
- // This mimics OS.File.writeAtomic() but writes in chunks.
- let tmpPath = file.path + ".tmp";
- let f = yield OS.File.open(tmpPath, {write: true, truncate: true});
-
- let buf = [];
- let bufLen = 0;
- let lineBreak = this.lineBreak;
-
- function writeChunk()
- {
- let array = encoder.encode(buf.join(lineBreak) + lineBreak);
- buf = [];
- bufLen = 0;
- return f.write(array);
- }
-
- for (let line of data)
- {
- buf.push(line);
- bufLen += line.length;
- if (bufLen >= BUFFER_SIZE)
- yield writeChunk();
- }
-
- if (bufLen)
- yield writeChunk();
-
- // OS.File.flush() isn't exposed prior to Gecko 27, see bug 912457.
- if (typeof f.flush == "function")
- yield f.flush();
- yield f.close();
- yield OS.File.move(tmpPath, file.path, {noCopy: true});
- }.bind(this)).then(callback.bind(null, null), callback);
- }
- catch (e)
- {
- callback(e);
- }
- },
-
- /**
- * Copies a file asynchronously. The callback will be called when the copy
- * operation is done.
- */
- copyFile: function(/**nsIFile*/ fromFile, /**nsIFile*/ toFile, /**Function*/ callback)
- {
- try
- {
- let promise = OS.File.copy(fromFile.path, toFile.path);
- promise.then(callback.bind(null, null), callback);
- }
- catch (e)
- {
- callback(e);
- }
- },
-
- /**
- * Renames a file within the same directory, will call callback when done.
- */
- renameFile: function(/**nsIFile*/ fromFile, /**String*/ newName, /**Function*/ callback)
- {
- try
- {
- let toFile = fromFile.clone();
- toFile.leafName = newName;
- let promise = OS.File.move(fromFile.path, toFile.path);
- promise.then(callback.bind(null, null), callback);
- }
- catch(e)
- {
- callback(e);
- }
- },
-
- /**
- * Removes a file, will call callback when done.
- */
- removeFile: function(/**nsIFile*/ file, /**Function*/ callback)
- {
- try
- {
- let promise = OS.File.remove(file.path);
- promise.then(callback.bind(null, null), callback);
- }
- catch(e)
- {
- callback(e);
- }
- },
-
- /**
- * Gets file information such as whether the file exists.
- */
- statFile: function(/**nsIFile*/ file, /**Function*/ callback)
- {
- try
- {
- let promise = OS.File.stat(file.path);
- promise.then(function onSuccess(info)
- {
- callback(null, {
- exists: true,
- isDirectory: info.isDir,
- isFile: !info.isDir,
- lastModified: info.lastModificationDate.getTime()
- });
- }, function onError(e)
- {
- if (e.becauseNoSuchFile)
- {
- callback(null, {
- exists: false,
- isDirectory: false,
- isFile: false,
- lastModified: 0
- });
- }
- else
- callback(e);
- });
- }
- catch(e)
- {
- callback(e);
- }
- }
-}
diff --git a/data/extensions/spyblock@gnu.org/lib/main.js b/data/extensions/spyblock@gnu.org/lib/main.js
deleted file mode 100644
index c0d4733..0000000
--- a/data/extensions/spyblock@gnu.org/lib/main.js
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * @fileOverview Starts up Adblock Plus
- */
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-bootstrapChildProcesses();
-registerPublicAPI();
-require("filterListener");
-require("contentPolicy");
-require("synchronizer");
-require("notification");
-require("sync");
-require("messageResponder");
-require("ui");
-require("objectTabs");
-require("elemHideFF");
-require("elemHideEmulation");
-
-function bootstrapChildProcesses()
-{
- let info = require("info");
-
- let processScript = info.addonRoot + "lib/child/bootstrap.js?" +
- Math.random() + "&info=" + encodeURIComponent(JSON.stringify(info));
- let messageManager = Cc["@mozilla.org/parentprocessmessagemanager;1"]
- .getService(Ci.nsIProcessScriptLoader)
- .QueryInterface(Ci.nsIMessageBroadcaster);
- messageManager.loadProcessScript(processScript, true);
-
- onShutdown.add(() => {
- messageManager.broadcastAsyncMessage("AdblockPlus:Shutdown", processScript);
- messageManager.removeDelayedProcessScript(processScript);
- });
-}
-
-function registerPublicAPI()
-{
- let {addonRoot} = require("info");
-
- let uri = Services.io.newURI(addonRoot + "lib/Public.jsm", null, null);
- if (uri instanceof Ci.nsIMutable)
- uri.mutable = false;
-
- let classID = Components.ID("5e447bce-1dd2-11b2-b151-ec21c2b6a135");
- let contractID = "@adblockplus.org/abp/public;1";
- let factory =
- {
- createInstance: function(outer, iid)
- {
- if (outer)
- throw Cr.NS_ERROR_NO_AGGREGATION;
- return uri.QueryInterface(iid);
- },
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory])
- };
-
- let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
- registrar.registerFactory(classID, "Adblock Plus public API URL", contractID, factory);
-
- onShutdown.add(function()
- {
- registrar.unregisterFactory(classID, factory);
- Cu.unload(uri.spec);
- });
-}
diff --git a/data/extensions/spyblock@gnu.org/lib/matcher.js b/data/extensions/spyblock@gnu.org/lib/matcher.js
deleted file mode 100644
index 02573bd..0000000
--- a/data/extensions/spyblock@gnu.org/lib/matcher.js
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-"use strict";
-
-/**
- * @fileOverview Matcher class implementing matching addresses against
- * a list of filters.
- */
-
-const {Filter, WhitelistFilter} = require("filterClasses");
-
-/**
- * Blacklist/whitelist filter matching
- * @constructor
- */
-function Matcher()
-{
- this.clear();
-}
-exports.Matcher = Matcher;
-
-Matcher.prototype = {
- /**
- * Lookup table for filters by their associated keyword
- * @type {Object}
- */
- filterByKeyword: null,
-
- /**
- * Lookup table for keywords by the filter text
- * @type {Object}
- */
- keywordByFilter: null,
-
- /**
- * Removes all known filters
- */
- clear()
- {
- this.filterByKeyword = Object.create(null);
- this.keywordByFilter = Object.create(null);
- },
-
- /**
- * Adds a filter to the matcher
- * @param {RegExpFilter} filter
- */
- add(filter)
- {
- if (filter.text in this.keywordByFilter)
- return;
-
- // Look for a suitable keyword
- let keyword = this.findKeyword(filter);
- let oldEntry = this.filterByKeyword[keyword];
- if (typeof oldEntry == "undefined")
- this.filterByKeyword[keyword] = filter;
- else if (oldEntry.length == 1)
- this.filterByKeyword[keyword] = [oldEntry, filter];
- else
- oldEntry.push(filter);
- this.keywordByFilter[filter.text] = keyword;
- },
-
- /**
- * Removes a filter from the matcher
- * @param {RegExpFilter} filter
- */
- remove(filter)
- {
- if (!(filter.text in this.keywordByFilter))
- return;
-
- let keyword = this.keywordByFilter[filter.text];
- let list = this.filterByKeyword[keyword];
- if (list.length <= 1)
- delete this.filterByKeyword[keyword];
- else
- {
- let index = list.indexOf(filter);
- if (index >= 0)
- {
- list.splice(index, 1);
- if (list.length == 1)
- this.filterByKeyword[keyword] = list[0];
- }
- }
-
- delete this.keywordByFilter[filter.text];
- },
-
- /**
- * Chooses a keyword to be associated with the filter
- * @param {Filter} filter
- * @return {string} keyword or an empty string if no keyword could be found
- */
- findKeyword(filter)
- {
- let result = "";
- let {text} = filter;
- if (Filter.regexpRegExp.test(text))
- return result;
-
- // Remove options
- let match = Filter.optionsRegExp.exec(text);
- if (match)
- text = match.input.substr(0, match.index);
-
- // Remove whitelist marker
- if (text.substr(0, 2) == "@@")
- text = text.substr(2);
-
- let candidates = text.toLowerCase().match(
- /[^a-z0-9%*][a-z0-9%]{3,}(?=[^a-z0-9%*])/g
- );
- if (!candidates)
- return result;
-
- let hash = this.filterByKeyword;
- let resultCount = 0xFFFFFF;
- let resultLength = 0;
- for (let i = 0, l = candidates.length; i < l; i++)
- {
- let candidate = candidates[i].substr(1);
- let count = (candidate in hash ? hash[candidate].length : 0);
- if (count < resultCount ||
- (count == resultCount && candidate.length > resultLength))
- {
- result = candidate;
- resultCount = count;
- resultLength = candidate.length;
- }
- }
- return result;
- },
-
- /**
- * Checks whether a particular filter is being matched against.
- * @param {RegExpFilter} filter
- * @return {boolean}
- */
- hasFilter(filter)
- {
- return (filter.text in this.keywordByFilter);
- },
-
- /**
- * Returns the keyword used for a filter, null for unknown filters.
- * @param {RegExpFilter} filter
- * @return {string}
- */
- getKeywordForFilter(filter)
- {
- if (filter.text in this.keywordByFilter)
- return this.keywordByFilter[filter.text];
- return null;
- },
-
- /**
- * Checks whether the entries for a particular keyword match a URL
- * @param {string} keyword
- * @param {string} location
- * @param {number} typeMask
- * @param {string} docDomain
- * @param {boolean} thirdParty
- * @param {string} sitekey
- * @param {boolean} specificOnly
- * @return {?Filter}
- */
- _checkEntryMatch(keyword, location, typeMask, docDomain, thirdParty, sitekey,
- specificOnly, privatenode)
- {
- let list = this.filterByKeyword[keyword];
- for (let i = 0; i < list.length; i++)
- {
- let filter = list[i];
-
- if (specificOnly && filter.isGeneric() &&
- !(filter instanceof WhitelistFilter))
- continue;
-
- if (filter.matches(location, typeMask, docDomain, thirdParty, sitekey, privatenode))
- return filter;
- }
- return null;
- },
-
- /**
- * Tests whether the URL matches any of the known filters
- * @param {string} location
- * URL to be tested
- * @param {number} typeMask
- * bitmask of content / request types to match
- * @param {string} docDomain
- * domain name of the document that loads the URL
- * @param {boolean} thirdParty
- * should be true if the URL is a third-party request
- * @param {string} sitekey
- * public key provided by the document
- * @param {boolean} specificOnly
- * should be true if generic matches should be ignored
- * @return {?RegExpFilter}
- * matching filter or null
- */
- matchesAny(location, typeMask, docDomain, thirdParty, sitekey, specificOnly)
- {
- let candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g);
- if (candidates === null)
- candidates = [];
- candidates.push("");
- for (let i = 0, l = candidates.length; i < l; i++)
- {
- let substr = candidates[i];
- if (substr in this.filterByKeyword)
- {
- let result = this._checkEntryMatch(substr, location, typeMask,
- docDomain, thirdParty, sitekey,
- specificOnly);
- if (result)
- return result;
- }
- }
-
- return null;
- }
-};
-
-/**
- * Combines a matcher for blocking and exception rules, automatically sorts
- * rules into two Matcher instances.
- * @constructor
- * @augments Matcher
- */
-function CombinedMatcher()
-{
- this.blacklist = new Matcher();
- this.whitelist = new Matcher();
- this.resultCache = Object.create(null);
-}
-exports.CombinedMatcher = CombinedMatcher;
-
-/**
- * Maximal number of matching cache entries to be kept
- * @type {number}
- */
-CombinedMatcher.maxCacheEntries = 1000;
-
-CombinedMatcher.prototype =
-{
- /**
- * Matcher for blocking rules.
- * @type {Matcher}
- */
- blacklist: null,
-
- /**
- * Matcher for exception rules.
- * @type {Matcher}
- */
- whitelist: null,
-
- /**
- * Lookup table of previous matchesAny results
- * @type {Object}
- */
- resultCache: null,
-
- /**
- * Number of entries in resultCache
- * @type {number}
- */
- cacheEntries: 0,
-
- /**
- * @see Matcher#clear
- */
- clear()
- {
- this.blacklist.clear();
- this.whitelist.clear();
- this.resultCache = Object.create(null);
- this.cacheEntries = 0;
- },
-
- /**
- * @see Matcher#add
- * @param {Filter} filter
- */
- add(filter)
- {
- if (filter instanceof WhitelistFilter)
- this.whitelist.add(filter);
- else
- this.blacklist.add(filter);
-
- if (this.cacheEntries > 0)
- {
- this.resultCache = Object.create(null);
- this.cacheEntries = 0;
- }
- },
-
- /**
- * @see Matcher#remove
- * @param {Filter} filter
- */
- remove(filter)
- {
- if (filter instanceof WhitelistFilter)
- this.whitelist.remove(filter);
- else
- this.blacklist.remove(filter);
-
- if (this.cacheEntries > 0)
- {
- this.resultCache = Object.create(null);
- this.cacheEntries = 0;
- }
- },
-
- /**
- * @see Matcher#findKeyword
- * @param {Filter} filter
- * @return {string} keyword
- */
- findKeyword(filter)
- {
- if (filter instanceof WhitelistFilter)
- return this.whitelist.findKeyword(filter);
- return this.blacklist.findKeyword(filter);
- },
-
- /**
- * @see Matcher#hasFilter
- * @param {Filter} filter
- * @return {boolean}
- */
- hasFilter(filter)
- {
- if (filter instanceof WhitelistFilter)
- return this.whitelist.hasFilter(filter);
- return this.blacklist.hasFilter(filter);
- },
-
- /**
- * @see Matcher#getKeywordForFilter
- * @param {Filter} filter
- * @return {string} keyword
- */
- getKeywordForFilter(filter)
- {
- if (filter instanceof WhitelistFilter)
- return this.whitelist.getKeywordForFilter(filter);
- return this.blacklist.getKeywordForFilter(filter);
- },
-
- /**
- * Checks whether a particular filter is slow
- * @param {RegExpFilter} filter
- * @return {boolean}
- */
- isSlowFilter(filter)
- {
- let matcher = (
- filter instanceof WhitelistFilter ? this.whitelist : this.blacklist
- );
- if (matcher.hasFilter(filter))
- return !matcher.getKeywordForFilter(filter);
- return !matcher.findKeyword(filter);
- },
-
- /**
- * Optimized filter matching testing both whitelist and blacklist matchers
- * simultaneously. For parameters see Matcher.matchesAny().
- * @see Matcher#matchesAny
- * @inheritdoc
- */
- matchesAnyInternal(location, typeMask, docDomain, thirdParty, sitekey,
- specificOnly, privatenode)
- {
- let candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g);
- if (candidates === null)
- candidates = [];
- candidates.push("");
-
- let blacklistHit = null;
- for (let i = 0, l = candidates.length; i < l; i++)
- {
- let substr = candidates[i];
- if (substr in this.whitelist.filterByKeyword)
- {
- let result = this.whitelist._checkEntryMatch(
- substr, location, typeMask, docDomain, thirdParty, sitekey, privatenode
- );
- if (result)
- return result;
- }
- if (substr in this.blacklist.filterByKeyword && blacklistHit === null)
- {
- blacklistHit = this.blacklist._checkEntryMatch(
- substr, location, typeMask, docDomain, thirdParty, sitekey,
- specificOnly, privatenode
- );
- }
- }
- return blacklistHit;
- },
-
- /**
- * @see Matcher#matchesAny
- * @inheritdoc
- */
- matchesAny(location, typeMask, docDomain, thirdParty, sitekey, specificOnly, privatenode)
- {
- let key = location + " " + typeMask + " " + docDomain + " " + thirdParty +
- " " + sitekey + " " + specificOnly;
- if (!privatenode)
- if (key in this.resultCache)
- return this.resultCache[key];
-
- let result = this.matchesAnyInternal(location, typeMask, docDomain,
- thirdParty, sitekey, specificOnly, privatenode);
-
- if (this.cacheEntries >= CombinedMatcher.maxCacheEntries)
- {
- this.resultCache = Object.create(null);
- this.cacheEntries = 0;
- }
-
- if (!privatenode){
- this.resultCache[key] = result;
- this.cacheEntries++;
- }
-
- return result;
- }
-};
-
-/**
- * Shared CombinedMatcher instance that should usually be used.
- * @type {CombinedMatcher}
- */
-exports.defaultMatcher = new CombinedMatcher();
diff --git a/data/extensions/spyblock@gnu.org/lib/messageResponder.js b/data/extensions/spyblock@gnu.org/lib/messageResponder.js
deleted file mode 100644
index 5dfc2e9..0000000
--- a/data/extensions/spyblock@gnu.org/lib/messageResponder.js
+++ /dev/null
@@ -1,431 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/* globals require */
-
-"use strict";
-
-(function(global)
-{
- let ext = global.ext || require("ext_background");
-
- const {port} = require("messaging");
- const {Prefs} = require("prefs");
- const {Utils} = require("utils");
- const {FilterStorage} = require("filterStorage");
- const {FilterNotifier} = require("filterNotifier");
- const {defaultMatcher} = require("matcher");
- const {ElemHideEmulation} = require("elemHideEmulation");
- const {Notification: NotificationStorage} = require("notification");
-
- const {Filter, BlockingFilter, RegExpFilter} = require("filterClasses");
- const {Synchronizer} = require("synchronizer");
-
- const info = require("info");
- const {Subscription,
- DownloadableSubscription,
- SpecialSubscription} = require("subscriptionClasses");
-
- // Some modules doesn't exist on Firefox. Moreover,
- // require() throws an exception on Firefox in that case.
- // However, try/catch causes the whole function to to be
- // deoptimized on V8. So we wrap it into another function.
- function tryRequire(module)
- {
- try
- {
- return require(module);
- }
- catch (e)
- {
- return null;
- }
- }
-
- function convertObject(keys, obj)
- {
- let result = {};
- for (let key of keys)
- {
- if (key in obj)
- result[key] = obj[key];
- }
- return result;
- }
-
- function convertSubscription(subscription)
- {
- let obj = convertObject(["disabled", "downloadStatus", "homepage",
- "lastDownload", "title", "url"], subscription);
- obj.isDownloading = Synchronizer.isExecuting(subscription.url);
- return obj;
- }
-
- let convertFilter = convertObject.bind(null, ["text"]);
-
- let changeListeners = new ext.PageMap();
- let listenedPreferences = Object.create(null);
- let listenedFilterChanges = Object.create(null);
- let messageTypes = new Map([
- ["app", "app.respond"],
- ["filter", "filters.respond"],
- ["pref", "prefs.respond"],
- ["subscription", "subscriptions.respond"]
- ]);
-
- function sendMessage(type, action, ...args)
- {
- let pages = changeListeners.keys();
- if (pages.length == 0)
- return;
-
- let convertedArgs = [];
- for (let arg of args)
- {
- if (arg instanceof Subscription)
- convertedArgs.push(convertSubscription(arg));
- else if (arg instanceof Filter)
- convertedArgs.push(convertFilter(arg));
- else
- convertedArgs.push(arg);
- }
-
- for (let page of pages)
- {
- let filters = changeListeners.get(page);
- let actions = filters[type];
- if (actions && actions.indexOf(action) != -1)
- {
- page.sendMessage({
- type: messageTypes.get(type),
- action,
- args: convertedArgs
- });
- }
- }
- }
-
- function addFilterListeners(type, actions)
- {
- for (let action of actions)
- {
- let name;
- if (type == "filter" && action == "loaded")
- name = "load";
- else
- name = type + "." + action;
-
- if (!(name in listenedFilterChanges))
- {
- listenedFilterChanges[name] = null;
- FilterNotifier.on(name, (...args) =>
- {
- sendMessage(type, action, ...args);
- });
- }
- }
- }
-
- function getListenerFilters(page)
- {
- let listenerFilters = changeListeners.get(page);
- if (!listenerFilters)
- {
- listenerFilters = Object.create(null);
- changeListeners.set(page, listenerFilters);
- }
- return listenerFilters;
- }
-
- port.on("app.get", (message, sender) =>
- {
- if (message.what == "issues")
- {
- let subscriptionInit = tryRequire("subscriptionInit");
- let result = subscriptionInit ? subscriptionInit.reinitialized : false;
- return {filterlistsReinitialized: result};
- }
-
- if (message.what == "doclink")
- return Utils.getDocLink(message.link);
-
- if (message.what == "localeInfo")
- {
- let bidiDir;
- if ("chromeRegistry" in Utils)
- {
- let isRtl = Utils.chromeRegistry.isLocaleRTL("adblockplus");
- bidiDir = isRtl ? "rtl" : "ltr";
- }
- else
- bidiDir = ext.i18n.getMessage("@@bidi_dir");
-
- return {locale: Utils.appLocale, bidiDir};
- }
-
- if (message.what == "features")
- {
- return {
- devToolsPanel: info.platform == "chromium"
- };
- }
-
- return info[message.what];
- });
-
- port.on("app.listen", (message, sender) =>
- {
- getListenerFilters(sender.page).app = message.filter;
- });
-
- port.on("app.open", (message, sender) =>
- {
- if (message.what == "options")
- ext.showOptions();
- });
-
- port.on("filters.add", (message, sender) =>
- {
- let result = require("filterValidation").parseFilter(message.text);
- let errors = [];
- if (result.error)
- errors.push(result.error.toString());
- else if (result.filter)
- FilterStorage.addFilter(result.filter);
-
- return errors;
- });
-
- port.on("filters.blocked", (message, sender) =>
- {
- let filter = defaultMatcher.matchesAny(message.url,
- RegExpFilter.typeMap[message.requestType], message.docDomain,
- message.thirdParty);
-
- return filter instanceof BlockingFilter;
- });
-
- port.on("filters.get", (message, sender) =>
- {
- if (message.what == "elemhideemulation")
- {
- let filters = [];
- const {checkWhitelisted} = require("whitelisting");
-
- if (Prefs.enabled && !checkWhitelisted(sender.page, sender.frame,
- RegExpFilter.typeMap.DOCUMENT |
- RegExpFilter.typeMap.ELEMHIDE))
- {
- let {hostname} = sender.frame.url;
- filters = ElemHideEmulation.getRulesForDomain(hostname);
- filters = filters.map((filter) =>
- {
- return {
- selector: filter.selector,
- text: filter.text
- };
- });
- }
- return filters;
- }
-
- let subscription = Subscription.fromURL(message.subscriptionUrl);
- if (!subscription)
- return [];
-
- return subscription.filters.map(convertFilter);
- });
-
- port.on("filters.importRaw", (message, sender) =>
- {
- let result = require("filterValidation").parseFilters(message.text);
- let errors = [];
- for (let error of result.errors)
- {
- if (error.type != "unexpected-filter-list-header")
- errors.push(error.toString());
- }
-
- if (errors.length > 0)
- return errors;
-
- let seenFilter = Object.create(null);
- for (let filter of result.filters)
- {
- FilterStorage.addFilter(filter);
- seenFilter[filter.text] = null;
- }
-
- if (!message.removeExisting)
- return errors;
-
- for (let subscription of FilterStorage.subscriptions)
- {
- if (!(subscription instanceof SpecialSubscription))
- continue;
-
- for (let j = subscription.filters.length - 1; j >= 0; j--)
- {
- let filter = subscription.filters[j];
- if (/^@@\|\|([^/:]+)\^\$document$/.test(filter.text))
- continue;
-
- if (!(filter.text in seenFilter))
- FilterStorage.removeFilter(filter);
- }
- }
-
- return errors;
- });
-
- port.on("filters.listen", (message, sender) =>
- {
- getListenerFilters(sender.page).filter = message.filter;
- addFilterListeners("filter", message.filter);
- });
-
- port.on("filters.remove", (message, sender) =>
- {
- let filter = Filter.fromText(message.text);
- let subscription = null;
- if (message.subscriptionUrl)
- subscription = Subscription.fromURL(message.subscriptionUrl);
-
- if (!subscription)
- FilterStorage.removeFilter(filter);
- else
- FilterStorage.removeFilter(filter, subscription, message.index);
- });
-
- port.on("prefs.get", (message, sender) =>
- {
- return Prefs[message.key];
- });
-
- port.on("prefs.listen", (message, sender) =>
- {
- getListenerFilters(sender.page).pref = message.filter;
- for (let preference of message.filter)
- {
- if (!(preference in listenedPreferences))
- {
- listenedPreferences[preference] = null;
- Prefs.on(preference, () =>
- {
- sendMessage("pref", preference, Prefs[preference]);
- });
- }
- }
- });
-
- port.on("prefs.toggle", (message, sender) =>
- {
- if (message.key == "notifications_ignoredcategories")
- NotificationStorage.toggleIgnoreCategory("*");
- else
- Prefs[message.key] = !Prefs[message.key];
- });
-
- port.on("subscriptions.add", (message, sender) =>
- {
- let subscription = Subscription.fromURL(message.url);
- if ("title" in message)
- subscription.title = message.title;
- if ("homepage" in message)
- subscription.homepage = message.homepage;
-
- if (message.confirm)
- {
- ext.showOptions(() =>
- {
- sendMessage("app", "addSubscription", subscription);
- });
- }
- else
- {
- subscription.disabled = false;
- FilterStorage.addSubscription(subscription);
-
- if (subscription instanceof DownloadableSubscription &&
- !subscription.lastDownload)
- Synchronizer.execute(subscription);
- }
- });
-
- port.on("subscriptions.get", (message, sender) =>
- {
- let subscriptions = FilterStorage.subscriptions.filter((s) =>
- {
- if (message.ignoreDisabled && s.disabled)
- return false;
- if (s instanceof DownloadableSubscription && message.downloadable)
- return true;
- if (s instanceof SpecialSubscription && message.special)
- return true;
- return false;
- });
-
- return subscriptions.map(convertSubscription);
- });
-
- port.on("subscriptions.listen", (message, sender) =>
- {
- getListenerFilters(sender.page).subscription = message.filter;
- addFilterListeners("subscription", message.filter);
- });
-
- port.on("subscriptions.remove", (message, sender) =>
- {
- let subscription = Subscription.fromURL(message.url);
- if (subscription.url in FilterStorage.knownSubscriptions)
- FilterStorage.removeSubscription(subscription);
- });
-
- port.on("subscriptions.toggle", (message, sender) =>
- {
- let subscription = Subscription.fromURL(message.url);
- if (subscription.url in FilterStorage.knownSubscriptions)
- {
- if (subscription.disabled || message.keepInstalled)
- subscription.disabled = !subscription.disabled;
- else
- FilterStorage.removeSubscription(subscription);
- }
- else
- {
- subscription.disabled = false;
- subscription.title = message.title;
- subscription.homepage = message.homepage;
- FilterStorage.addSubscription(subscription);
- if (!subscription.lastDownload)
- Synchronizer.execute(subscription);
- }
- });
-
- port.on("subscriptions.update", (message, sender) =>
- {
- let {subscriptions} = FilterStorage;
- if (message.url)
- subscriptions = [Subscription.fromURL(message.url)];
-
- for (let subscription of subscriptions)
- {
- if (subscription instanceof DownloadableSubscription)
- Synchronizer.execute(subscription, true);
- }
- });
-})(this);
diff --git a/data/extensions/spyblock@gnu.org/lib/messaging.js b/data/extensions/spyblock@gnu.org/lib/messaging.js
deleted file mode 100644
index 63d061e..0000000
--- a/data/extensions/spyblock@gnu.org/lib/messaging.js
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-"use strict";
-
-let {EventEmitter} = require("events");
-
-const MESSAGE_NAME = "AdblockPlus:Message";
-const RESPONSE_NAME = "AdblockPlus:Response";
-
-function isPromise(value)
-{
- // value instanceof Promise won't work - there can be different Promise
- // classes (e.g. in different contexts) and there can also be promise-like
- // classes (e.g. Task).
- return (value && typeof value.then == "function");
-}
-
-function sendMessage(messageManager, messageName, payload, callbackID)
-{
- let request = {messageName, payload, callbackID};
- if (messageManager instanceof Ci.nsIMessageSender)
- {
- messageManager.sendAsyncMessage(MESSAGE_NAME, request);
- return 1;
- }
- else if (messageManager instanceof Ci.nsIMessageBroadcaster)
- {
- messageManager.broadcastAsyncMessage(MESSAGE_NAME, request);
- return messageManager.childCount;
- }
- else
- {
- Cu.reportError("Unexpected message manager, impossible to send message");
- return 0;
- }
-}
-
-function sendSyncMessage(messageManager, messageName, payload)
-{
- let request = {messageName, payload};
- let responses = messageManager.sendRpcMessage(MESSAGE_NAME, request);
- let processor = new ResponseProcessor(messageName);
- for (let response of responses)
- processor.add(response);
- return processor.value;
-}
-
-function ResponseProcessor(messageName)
-{
- this.value = undefined;
- this.add = function(response)
- {
- if (typeof response == "undefined")
- return;
-
- if (typeof this.value == "undefined")
- this.value = response;
- else
- Cu.reportError("Got multiple responses to message '" + messageName + "', only first response was accepted.");
- };
-}
-
-function getSender(origin)
-{
- if (origin instanceof Ci.nsIDOMXULElement)
- origin = origin.messageManager;
-
- if (origin instanceof Ci.nsIMessageSender)
- return new LightWeightPort(origin);
- else
- return null;
-}
-
-/**
- * Lightweight communication port allowing only sending messages.
- * @param {nsIMessageManager} messageManager
- * @constructor
- */
-function LightWeightPort(messageManager)
-{
- this._messageManager = messageManager;
-}
-LightWeightPort.prototype =
-{
- /**
- * @see Port#emit
- */
- emit: function(messageName, payload)
- {
- sendMessage(this._messageManager, messageName, payload);
- },
-
- /**
- * @see Port#emitSync
- */
- emitSync: function(messageName, payload)
- {
- return sendSyncMessage(this._messageManager, messageName, payload);
- }
-};
-
-/**
- * Communication port wrapping the message manager API to send and receive
- * messages.
- * @param {nsIMessageManager} messageManager
- * @constructor
- */
-function Port(messageManager)
-{
- this._messageManager = messageManager;
- this._eventEmitter = new EventEmitter();
-
- this._responseCallbacks = new Map();
- this._responseCallbackCounter = 0;
-
- this._handleRequest = this._handleRequest.bind(this);
- this._handleResponse = this._handleResponse.bind(this);
- this._messageManager.addMessageListener(MESSAGE_NAME, this._handleRequest);
- this._messageManager.addMessageListener(RESPONSE_NAME, this._handleResponse);
-}
-Port.prototype = {
- /**
- * Disables the port and makes it stop listening to incoming messages.
- */
- disconnect: function()
- {
- this._messageManager.removeMessageListener(MESSAGE_NAME, this._handleRequest);
- this._messageManager.removeMessageListener(RESPONSE_NAME, this._handleResponse);
- },
-
- _sendResponse: function(sender, callbackID, payload)
- {
- if (!sender || typeof callbackID == "undefined")
- return;
-
- let response = {callbackID, payload};
- sender._messageManager.sendAsyncMessage(RESPONSE_NAME, response);
- },
-
- _handleRequest: function(message)
- {
- let sender = getSender(message.target);
- let {callbackID, messageName, payload} = message.data;
-
- let result = this._dispatch(messageName, payload, sender);
- if (isPromise(result))
- {
- // This is a promise - asynchronous response
- if (message.sync)
- {
- Cu.reportError("Asynchronous response to the synchronous message '" + messageName + "' is not possible");
- return undefined;
- }
-
- result.then(result =>
- {
- this._sendResponse(sender, callbackID, result)
- }, e =>
- {
- Cu.reportError(e);
- this._sendResponse(sender, callbackID, undefined);
- });
- }
- else
- this._sendResponse(sender, callbackID, result);
-
- return result;
- },
-
- _handleResponse: function(message)
- {
- let {callbackID, payload} = message.data;
- let callbackData = this._responseCallbacks.get(callbackID);
- if (!callbackData)
- return;
-
- let [callback, processor, expectedResponses] = callbackData;
-
- try
- {
- processor.add(payload);
- }
- catch (e)
- {
- Cu.reportError(e);
- }
-
- callbackData[2] = --expectedResponses;
- if (expectedResponses <= 0)
- {
- this._responseCallbacks.delete(callbackID);
- callback(processor.value);
- }
- },
-
- _dispatch: function(messageName, payload, sender)
- {
- let callbacks = this._eventEmitter.listeners(messageName);
- let processor = new ResponseProcessor(messageName);
- for (let callback of callbacks)
- {
- try
- {
- processor.add(callback(payload, sender));
- }
- catch (e)
- {
- Cu.reportError(e);
- }
- }
- return processor.value;
- },
-
- /**
- * Function to be called when a particular message is received
- * @callback Port~messageHandler
- * @param payload data attached to the message if any
- * @param {LightWeightPort} sender object that can be used to communicate with
- * the sender of the message, could be null
- * @return the handler can return undefined (no response), a value (response
- * to be sent to sender immediately) or a promise (asynchronous
- * response).
- */
-
- /**
- * Adds a handler for the specified message.
- * @param {string} messageName message that would trigger the callback
- * @param {Port~messageHandler} callback
- */
- on: function(messageName, callback)
- {
- this._eventEmitter.on(messageName, callback);
- },
-
- /**
- * Removes a handler for the specified message.
- * @param {string} messageName message that would trigger the callback
- * @param {Port~messageHandler} callback
- */
- off: function(messageName, callback)
- {
- this._eventEmitter.off(messageName, callback);
- },
-
- /**
- * Sends a message.
- * @param {string} messageName message identifier
- * @param [payload] data to attach to the message
- */
- emit: function(messageName, payload)
- {
- sendMessage(this._messageManager, messageName, payload, undefined);
- },
-
- /**
- * Sends a message and expects a response.
- * @param {string} messageName message identifier
- * @param [payload] data to attach to the message
- * @return {Promise} promise that will be resolved with the response
- */
- emitWithResponse: function(messageName, payload)
- {
- let callbackID = ++this._responseCallbackCounter;
- let expectedResponses = sendMessage(
- this._messageManager, messageName, payload, callbackID);
- return new Promise((resolve, reject) =>
- {
- this._responseCallbacks.set(callbackID,
- [resolve, new ResponseProcessor(messageName), expectedResponses]);
- });
- },
-
- /**
- * Sends a synchonous message (DO NOT USE unless absolutely unavoidable).
- * @param {string} messageName message identifier
- * @param [payload] data to attach to the message
- * @return response returned by the handler
- */
- emitSync: function(messageName, payload)
- {
- return sendSyncMessage(this._messageManager, messageName, payload);
- }
-};
-exports.Port = Port;
-
-let messageManager;
-try
-{
- // Child
- messageManager = require("messageManager");
-}
-catch (e)
-{
- // Parent
- messageManager = Cc["@mozilla.org/parentprocessmessagemanager;1"]
- .getService(Ci.nsIMessageListenerManager);
-}
-
-let port = new Port(messageManager);
-onShutdown.add(() => port.disconnect());
-exports.port = port;
diff --git a/data/extensions/spyblock@gnu.org/lib/notification.js b/data/extensions/spyblock@gnu.org/lib/notification.js
deleted file mode 100644
index 311e4e8..0000000
--- a/data/extensions/spyblock@gnu.org/lib/notification.js
+++ /dev/null
@@ -1,475 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-"use strict";
-
-/**
- * @fileOverview Handles notifications.
- */
-
-const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-
-const {Prefs} = require("prefs");
-const {Downloader, Downloadable,
- MILLIS_IN_MINUTE, MILLIS_IN_HOUR, MILLIS_IN_DAY} = require("downloader");
-const {Utils} = require("utils");
-const {Matcher, defaultMatcher} = require("matcher");
-const {Filter, RegExpFilter, WhitelistFilter} = require("filterClasses");
-
-const INITIAL_DELAY = 1 * MILLIS_IN_MINUTE;
-const CHECK_INTERVAL = 1 * MILLIS_IN_HOUR;
-const EXPIRATION_INTERVAL = 1 * MILLIS_IN_DAY;
-const TYPE = {
- information: 0,
- question: 1,
- relentless: 2,
- critical: 3
-};
-
-let showListeners = [];
-let questionListeners = {};
-
-function getNumericalSeverity(notification)
-{
- if (notification.type in TYPE)
- return TYPE[notification.type];
- return TYPE.information;
-}
-
-function saveNotificationData()
-{
- // HACK: JSON values aren't saved unless they are assigned a different object.
- Prefs.notificationdata = JSON.parse(JSON.stringify(Prefs.notificationdata));
-}
-
-function localize(translations, locale)
-{
- if (locale in translations)
- return translations[locale];
-
- let languagePart = locale.substring(0, locale.indexOf("-"));
- if (languagePart && languagePart in translations)
- return translations[languagePart];
-
- let defaultLocale = "en-US";
- return translations[defaultLocale];
-}
-
-/**
- * The object providing actual downloading functionality.
- * @type {Downloader}
- */
-let downloader = null;
-let localData = [];
-
-/**
- * Regularly fetches notifications and decides which to show.
- * @class
- */
-let Notification = exports.Notification =
-{
- /**
- * Called on module startup.
- */
- init()
- {
- downloader = new Downloader(this._getDownloadables.bind(this),
- INITIAL_DELAY, CHECK_INTERVAL);
- downloader.onExpirationChange = this._onExpirationChange.bind(this);
- downloader.onDownloadSuccess = this._onDownloadSuccess.bind(this);
- downloader.onDownloadError = this._onDownloadError.bind(this);
- onShutdown.add(() => downloader.cancel());
- },
-
- /**
- * Yields a Downloadable instances for the notifications download.
- */
- *_getDownloadables()
- {
- let downloadable = new Downloadable(Prefs.notificationurl);
- if (typeof Prefs.notificationdata.lastError === "number")
- downloadable.lastError = Prefs.notificationdata.lastError;
- if (typeof Prefs.notificationdata.lastCheck === "number")
- downloadable.lastCheck = Prefs.notificationdata.lastCheck;
- if (typeof Prefs.notificationdata.data === "object" &&
- "version" in Prefs.notificationdata.data)
- {
- downloadable.lastVersion = Prefs.notificationdata.data.version;
- }
- if (typeof Prefs.notificationdata.softExpiration === "number")
- downloadable.softExpiration = Prefs.notificationdata.softExpiration;
- if (typeof Prefs.notificationdata.hardExpiration === "number")
- downloadable.hardExpiration = Prefs.notificationdata.hardExpiration;
- if (typeof Prefs.notificationdata.downloadCount === "number")
- downloadable.downloadCount = Prefs.notificationdata.downloadCount;
- yield downloadable;
- },
-
- _onExpirationChange(downloadable)
- {
- Prefs.notificationdata.lastCheck = downloadable.lastCheck;
- Prefs.notificationdata.softExpiration = downloadable.softExpiration;
- Prefs.notificationdata.hardExpiration = downloadable.hardExpiration;
- saveNotificationData();
- },
-
- _onDownloadSuccess(downloadable, responseText, errorCallback,
- redirectCallback)
- {
- try
- {
- let data = JSON.parse(responseText);
- for (let notification of data.notifications)
- {
- if ("severity" in notification)
- {
- if (!("type" in notification))
- notification.type = notification.severity;
- delete notification.severity;
- }
- }
- Prefs.notificationdata.data = data;
- }
- catch (e)
- {
- Cu.reportError(e);
- errorCallback("synchronize_invalid_data");
- return;
- }
-
- Prefs.notificationdata.lastError = 0;
- Prefs.notificationdata.downloadStatus = "synchronize_ok";
- [
- Prefs.notificationdata.softExpiration,
- Prefs.notificationdata.hardExpiration
- ] = downloader.processExpirationInterval(EXPIRATION_INTERVAL);
- Prefs.notificationdata.downloadCount = downloadable.downloadCount;
- saveNotificationData();
-
- Notification.showNext();
- },
-
- _onDownloadError(downloadable, downloadURL, error, channelStatus,
- responseStatus, redirectCallback)
- {
- Prefs.notificationdata.lastError = Date.now();
- Prefs.notificationdata.downloadStatus = error;
- saveNotificationData();
- },
-
- /**
- * Adds a listener for notifications to be shown.
- * @param {Function} listener Listener to be invoked when a notification is
- * to be shown
- */
- addShowListener(listener)
- {
- if (showListeners.indexOf(listener) == -1)
- showListeners.push(listener);
- },
-
- /**
- * Removes the supplied listener.
- * @param {Function} listener Listener that was added via addShowListener()
- */
- removeShowListener(listener)
- {
- let index = showListeners.indexOf(listener);
- if (index != -1)
- showListeners.splice(index, 1);
- },
-
- /**
- * Determines which notification is to be shown next.
- * @param {string} url URL to match notifications to (optional)
- * @return {Object} notification to be shown, or null if there is none
- */
- _getNextToShow(url)
- {
- function checkTarget(target, parameter, name, version)
- {
- let minVersionKey = parameter + "MinVersion";
- let maxVersionKey = parameter + "MaxVersion";
- return !((parameter in target && target[parameter] != name) ||
- (minVersionKey in target &&
- Services.vc.compare(version, target[minVersionKey]) < 0) ||
- (maxVersionKey in target &&
- Services.vc.compare(version, target[maxVersionKey]) > 0));
- }
-
- let remoteData = [];
- if (typeof Prefs.notificationdata.data == "object" &&
- Prefs.notificationdata.data.notifications instanceof Array)
- {
- remoteData = Prefs.notificationdata.data.notifications;
- }
-
- let notifications = localData.concat(remoteData);
- if (notifications.length === 0)
- return null;
-
- const {addonName, addonVersion, application,
- applicationVersion, platform, platformVersion} = require("info");
- let notificationToShow = null;
- for (let notification of notifications)
- {
- if (typeof notification.type === "undefined" ||
- notification.type !== "critical")
- {
- let shown;
- if (typeof Prefs.notificationdata.shown == "object")
- shown = Prefs.notificationdata.shown[notification.id];
-
- if (typeof shown != "undefined")
- {
- if (typeof notification.interval == "number")
- {
- if (shown + notification.interval > Date.now())
- continue;
- }
- else if (shown)
- continue;
- }
-
- if (notification.type !== "relentless" &&
- Prefs.notifications_ignoredcategories.indexOf("*") != -1)
- {
- continue;
- }
- }
-
- if (typeof url === "string" || notification.urlFilters instanceof Array)
- {
- if (Prefs.enabled && typeof url === "string" &&
- notification.urlFilters instanceof Array)
- {
- let host;
- try
- {
- host = new URL(url).hostname;
- }
- catch (e)
- {
- host = "";
- }
-
- let exception = defaultMatcher.matchesAny(
- url, RegExpFilter.typeMap.DOCUMENT, host, false, null
- );
- if (exception instanceof WhitelistFilter)
- continue;
-
- let matcher = new Matcher();
- for (let urlFilter of notification.urlFilters)
- matcher.add(Filter.fromText(urlFilter));
- if (!matcher.matchesAny(url, RegExpFilter.typeMap.DOCUMENT, host,
- false, null))
- {
- continue;
- }
- }
- else
- continue;
- }
-
- if (notification.targets instanceof Array)
- {
- let match = false;
- for (let target of notification.targets)
- {
- if (checkTarget(target, "extension", addonName, addonVersion) &&
- checkTarget(target, "application", application,
- applicationVersion) &&
- checkTarget(target, "platform", platform, platformVersion))
- {
- match = true;
- break;
- }
- }
- if (!match)
- continue;
- }
-
- if (!notificationToShow ||
- getNumericalSeverity(notification) >
- getNumericalSeverity(notificationToShow))
- notificationToShow = notification;
- }
-
- return notificationToShow;
- },
-
- /**
- * Invokes the listeners added via addShowListener() with the next
- * notification to be shown.
- * @param {string} url URL to match notifications to (optional)
- */
- showNext(url)
- {
- let notification = Notification._getNextToShow(url);
- if (notification)
- {
- for (let showListener of showListeners)
- showListener(notification);
- }
- },
-
- /**
- * Marks a notification as shown.
- * @param {string} id ID of the notification to be marked as shown
- */
- markAsShown(id)
- {
- let now = Date.now();
- let data = Prefs.notificationdata;
-
- if (data.shown instanceof Array)
- {
- let newShown = {};
- for (let oldId of data.shown)
- newShown[oldId] = now;
- data.shown = newShown;
- }
-
- if (typeof data.shown != "object")
- data.shown = {};
-
- data.shown[id] = now;
-
- saveNotificationData();
- },
-
- /**
- * Localizes the texts of the supplied notification.
- * @param {Object} notification notification to translate
- * @param {string} locale the target locale (optional, defaults to the
- * application locale)
- * @return {Object} the translated texts
- */
- getLocalizedTexts(notification, locale)
- {
- locale = locale || Utils.appLocale;
- let textKeys = ["title", "message"];
- let localizedTexts = [];
- for (let key of textKeys)
- {
- if (key in notification)
- {
- if (typeof notification[key] == "string")
- localizedTexts[key] = notification[key];
- else
- localizedTexts[key] = localize(notification[key], locale);
- }
- }
- return localizedTexts;
- },
-
- /**
- * Adds a local notification.
- * @param {Object} notification notification to add
- */
- addNotification(notification)
- {
- if (localData.indexOf(notification) == -1)
- localData.push(notification);
- },
-
- /**
- * Removes an existing local notification.
- * @param {Object} notification notification to remove
- */
- removeNotification(notification)
- {
- let index = localData.indexOf(notification);
- if (index > -1)
- localData.splice(index, 1);
- },
-
- /**
- * A callback function which listens to see if notifications were approved.
- *
- * @callback QuestionListener
- * @param {boolean} approved
- */
-
- /**
- * Adds a listener for question-type notifications
- * @param {string} id
- * @param {QuestionListener} listener
- */
- addQuestionListener(id, listener)
- {
- if (!(id in questionListeners))
- questionListeners[id] = [];
- if (questionListeners[id].indexOf(listener) === -1)
- questionListeners[id].push(listener);
- },
-
- /**
- * Removes a listener that was previously added via addQuestionListener
- * @param {string} id
- * @param {QuestionListener} listener
- */
- removeQuestionListener(id, listener)
- {
- if (!(id in questionListeners))
- return;
- let index = questionListeners[id].indexOf(listener);
- if (index > -1)
- questionListeners[id].splice(index, 1);
- if (questionListeners[id].length === 0)
- delete questionListeners[id];
- },
-
- /**
- * Notifies question listeners about interactions with a notification
- * @param {string} id notification ID
- * @param {boolean} approved indicator whether notification has been approved
- */
- triggerQuestionListeners(id, approved)
- {
- if (!(id in questionListeners))
- return;
- let listeners = questionListeners[id];
- for (let listener of listeners)
- listener(approved);
- },
-
- /**
- * Toggles whether notifications of a specific category should be ignored
- * @param {string} category notification category identifier
- * @param {boolean} [forceValue] force specified value
- */
- toggleIgnoreCategory(category, forceValue)
- {
- let categories = Prefs.notifications_ignoredcategories;
- let index = categories.indexOf(category);
- if (index == -1 && forceValue !== false)
- {
- categories.push(category);
- Prefs.notifications_showui = true;
- }
- else if (index != -1 && forceValue !== true)
- categories.splice(index, 1);
-
- // HACK: JSON values aren't saved unless they are assigned a
- // different object.
- Prefs.notifications_ignoredcategories =
- JSON.parse(JSON.stringify(categories));
- }
-};
-Notification.init();
diff --git a/data/extensions/spyblock@gnu.org/lib/objectTabs.js b/data/extensions/spyblock@gnu.org/lib/objectTabs.js
deleted file mode 100644
index 3ee92bc..0000000
--- a/data/extensions/spyblock@gnu.org/lib/objectTabs.js
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * @fileOverview Code responsible for showing and hiding object tabs.
- */
-
-let {Prefs} = require("prefs");
-let {Utils} = require("utils");
-let {port} = require("messaging");
-
-/**
- * Random element class, to be used for object tabs displayed on top of the
- * plugin content.
- * @type string
- */
-let classVisibleTop = null;
-
-/**
- * Random element class, to be used for object tabs displayed at the bottom of
- * the plugin content.
- * @type string
- */
-let classVisibleBottom = null;
-
-/**
- * Random element class, to be used for object tabs that are hidden.
- * @type string
- */
-let classHidden = null;
-
-port.on("getObjectTabsStatus", function(message, sender)
-{
- let {UI} = require("ui");
-
- return !!(Prefs.enabled && Prefs.frameobjects && UI.overlay && classHidden);
-});
-
-port.on("getObjectTabsTexts", function(message, sender)
-{
- let {UI} = require("ui");
-
- return {
- label: UI.overlay.attributes.objtabtext,
- tooltip: UI.overlay.attributes.objtabtooltip,
- classVisibleTop, classVisibleBottom, classHidden
- };
-});
-
-port.on("blockItem", function({request, nodesID}, sender)
-{
- let {UI} = require("ui");
- UI.blockItem(UI.currentWindow, nodesID, request);
-});
-
-function init()
-{
- function processCSSData(event)
- {
- if (onShutdown.done)
- return;
-
- let data = event.target.responseText;
-
- let rnd = [];
- let offset = "a".charCodeAt(0);
- for (let i = 0; i < 60; i++)
- rnd.push(offset + Math.random() * 26);
-
- classVisibleTop = String.fromCharCode.apply(String, rnd.slice(0, 20));
- classVisibleBottom = String.fromCharCode.apply(String, rnd.slice(20, 40));
- classHidden = String.fromCharCode.apply(String, rnd.slice(40, 60));
-
- let url = Utils.makeURI("data:text/css," + encodeURIComponent(data.replace(/%%CLASSVISIBLETOP%%/g, classVisibleTop)
- .replace(/%%CLASSVISIBLEBOTTOM%%/g, classVisibleBottom)
- .replace(/%%CLASSHIDDEN%%/g, classHidden)));
- Utils.styleService.loadAndRegisterSheet(url, Ci.nsIStyleSheetService.USER_SHEET);
- onShutdown.add(function()
- {
- Utils.styleService.unregisterSheet(url, Ci.nsIStyleSheetService.USER_SHEET);
- });
- }
-
- // Load CSS asynchronously
- try
- {
- let request = new XMLHttpRequest();
- request.mozBackgroundRequest = true;
- request.open("GET", "chrome://adblockplus/content/objtabs.css");
- request.overrideMimeType("text/plain");
- request.addEventListener("load", processCSSData, false);
- request.send(null);
- }
- catch (e)
- {
- Cu.reportError(e);
- }
-}
-init();
diff --git a/data/extensions/spyblock@gnu.org/lib/prefs.js b/data/extensions/spyblock@gnu.org/lib/prefs.js
deleted file mode 100644
index d1ebb95..0000000
--- a/data/extensions/spyblock@gnu.org/lib/prefs.js
+++ /dev/null
@@ -1,197 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
-let {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
-
-let {addonRoot, addonName} = require("info");
-let branchName = "extensions." + addonName + ".";
-let branch = Services.prefs.getBranch(branchName);
-let preconfiguredBranch =
- Services.prefs.getBranch(branchName + "preconfigured.");
-let ignorePrefChanges = false;
-
-function init()
-{
- // Load default preferences and set up properties for them
- let defaultBranch = Services.prefs.getDefaultBranch(branchName);
-
- let prefsData = require("prefs.json");
- let defaults = prefsData.defaults;
- let preconfigurable = new Set(prefsData.preconfigurable);
- for (let pref in defaults)
- {
- let value = defaults[pref];
- let [getter, setter] = typeMap[typeof value];
- if (preconfigurable.has(pref))
- {
- try
- {
- value = getter(preconfiguredBranch, pref);
- }
- catch (e) {}
- }
- setter(defaultBranch, pref, value);
- defineProperty(pref, false, getter, setter);
- }
-
- // Add preference change observer
- try
- {
- branch.QueryInterface(Ci.nsIPrefBranch2).addObserver("", Prefs, true);
- onShutdown.add(() => branch.removeObserver("", Prefs));
- }
- catch (e)
- {
- Cu.reportError(e);
- }
-}
-
-/**
- * Sets up getter/setter on Prefs object for preference.
- */
-function defineProperty(/**String*/ name, defaultValue, /**Function*/ readFunc, /**Function*/ writeFunc)
-{
- let value = defaultValue;
- Prefs["_update_" + name] = () =>
- {
- try
- {
- value = readFunc(branch, name);
- triggerListeners(name);
- }
- catch(e)
- {
- Cu.reportError(e);
- }
- };
- Object.defineProperty(Prefs, name, {
- enumerable: true,
- get: () => value,
- set: (newValue) =>
- {
- if (value == newValue)
- return value;
-
- try
- {
- ignorePrefChanges = true;
- writeFunc(branch, name, newValue);
- value = newValue;
- Services.prefs.savePrefFile(null);
- triggerListeners(name);
- }
- catch(e)
- {
- Cu.reportError(e);
- }
- finally
- {
- ignorePrefChanges = false;
- }
- return value;
- }
- });
- Prefs["_update_" + name]();
-}
-
-let listeners = [];
-function triggerListeners(/**String*/ name)
-{
- for (let i = 0; i < listeners.length; i++)
- {
- try
- {
- listeners[i](name);
- }
- catch(e)
- {
- Cu.reportError(e);
- }
- }
-}
-
-/**
- * Manages the preferences for an extension, object properties corresponding
- * to extension's preferences are added automatically. Setting the property
- * will automatically change the preference, external preference changes are
- * also recognized automatically.
- */
-let Prefs = exports.Prefs =
-{
- /**
- * Migrates an old preference to a new name.
- */
- migrate: function(/**String*/ oldName, /**String*/ newName)
- {
- if (newName in this && Services.prefs.prefHasUserValue(oldName))
- {
- let [getter, setter] = typeMap[typeof this[newName]];
- try
- {
- this[newName] = getter(Services.prefs, oldName);
- } catch(e) {}
- Services.prefs.clearUserPref(oldName);
- }
- },
-
- /**
- * Adds a preferences listener that will be fired whenever a preference
- * changes.
- */
- addListener: function(/**Function*/ listener)
- {
- if (listeners.indexOf(listener) < 0)
- listeners.push(listener);
- },
-
- /**
- * Removes a preferences listener.
- */
- removeListener: function(/**Function*/ listener)
- {
- let index = listeners.indexOf(listener);
- if (index >= 0)
- listeners.splice(index, 1);
- },
-
- observe: function(subject, topic, data)
- {
- if (ignorePrefChanges || topic != "nsPref:changed")
- return;
-
- if ("_update_" + data in this)
- this["_update_" + data]();
- },
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference, Ci.nsIObserver])
-};
-
-let getIntPref = (branch, pref) => branch.getIntPref(pref);
-let setIntPref = (branch, pref, newValue) => branch.setIntPref(pref, newValue);
-
-let getBoolPref = (branch, pref) => branch.getBoolPref(pref);
-let setBoolPref = (branch, pref, newValue) => branch.setBoolPref(pref, newValue);
-
-let getCharPref = (branch, pref) => branch.getComplexValue(pref, Ci.nsISupportsString).data;
-let setCharPref = (branch, pref, newValue) =>
-{
- let str = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
- str.data = newValue;
- branch.setComplexValue(pref, Ci.nsISupportsString, str);
-};
-
-let getJSONPref = (branch, pref) => JSON.parse(getCharPref(branch, pref));
-let setJSONPref = (branch, pref, newValue) => setCharPref(branch, pref, JSON.stringify(newValue));
-
-// Getter/setter functions for difference preference types
-let typeMap =
-{
- boolean: [getBoolPref, setBoolPref],
- number: [getIntPref, setIntPref],
- string: [getCharPref, setCharPref],
- object: [getJSONPref, setJSONPref]
-};
-
-init();
diff --git a/data/extensions/spyblock@gnu.org/lib/requestNotifier.js b/data/extensions/spyblock@gnu.org/lib/requestNotifier.js
deleted file mode 100644
index f42eaac..0000000
--- a/data/extensions/spyblock@gnu.org/lib/requestNotifier.js
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * @fileOverview Stores Adblock Plus data to be attached to a window.
- */
-
-let {port} = require("messaging");
-
-let requestNotifierMaxId = 0;
-
-/**
- * Active RequestNotifier instances by their ID
- * @type Map.<number,RequestNotifier>
- */
-let notifiers = new Map();
-
-port.on("foundNodeData", ({notifierID, data}, sender) =>
-{
- let notifier = notifiers.get(notifierID);
- if (notifier)
- notifier.notifyListener(data);
-});
-
-port.on("scanComplete", (notifierID, sender) =>
-{
- let notifier = notifiers.get(notifierID);
- if (notifier)
- notifier.onComplete();
-});
-
-/**
- * Creates a notifier object for a particular window. After creation the window
- * will first be scanned for previously saved requests. Once that scan is
- * complete only new requests for this window will be reported.
- * @param {Integer} outerWindowID ID of the window to attach the notifier to
- * @param {Function} listener listener to be called whenever a new request is found
- * @param {Object} [listenerObj] "this" pointer to be used when calling the listener
- */
-function RequestNotifier(outerWindowID, listener, listenerObj)
-{
- this.listener = listener;
- this.listenerObj = listenerObj || null;
- this.id = ++requestNotifierMaxId;
- notifiers.set(this.id, this);
-
- port.emit("startWindowScan", {
- notifierID: this.id,
- outerWindowID: outerWindowID
- });
-}
-exports.RequestNotifier = RequestNotifier;
-
-RequestNotifier.prototype =
-{
- /**
- * The unique ID of this notifier.
- * @type Integer
- */
- id: null,
-
- /**
- * The listener to be called when a new request is found.
- * @type Function
- */
- listener: null,
-
- /**
- * "this" pointer to be used when calling the listener.
- * @type Object
- */
- listenerObj: null,
-
- /**
- * Will be set to true once the initial window scan is complete.
- * @type Boolean
- */
- scanComplete: false,
-
- /**
- * Shuts down the notifier once it is no longer used. The listener
- * will no longer be called after that.
- */
- shutdown: function()
- {
- notifiers.delete(this.id);
- port.emit("shutdownNotifier", this.id);
- },
-
- /**
- * Notifies listener about a new request.
- * @param {Object} entry
- */
- notifyListener: function(entry)
- {
- this.listener.call(this.listenerObj, entry, this.scanComplete);
- },
-
- onComplete: function()
- {
- this.scanComplete = true;
- this.notifyListener(null);
- },
-
- /**
- * Makes the nodes associated with the given requests blink.
- * @param {number[]} requests list of request IDs that were previously
- * reported by this notifier.
- * @param {Boolean} scrollToItem if true, scroll to first node
- */
- flashNodes: function(requests, scrollToItem)
- {
- if (!requests)
- requests = [];
-
- port.emit("flashNodes", {
- notifierID: this.id,
- requests,
- scrollToItem
- });
- },
-
- /**
- * Attempts to calculate the size of the nodes associated with the requests.
- * @param {number[]} requests list of request IDs that were previously
- * reported by this notifier.
- * @param {Function} callback function to be called with two parameters (x,y)
- */
- retrieveNodeSize: function(requests, callback)
- {
- if (!requests)
- requests = [];
-
- port.emitWithResponse("retrieveNodeSize", {
- notifierID: this.id,
- requests
- }).then(callback);
- },
-
- /**
- * Stores the nodes associated with the requests and generates a unique ID
- * for them that can be used with Policy.refilterNodes(). Note that
- * Policy.deleteNodes() always has to be called to release the memory.
- * @param {number[]} requests list of request IDs that were previously
- * reported by this notifier.
- * @param {Function} callback function to be called with the nodes ID.
- */
- storeNodesForEntries: function(requests, callback)
- {
- if (!requests)
- requests = [];
-
- port.emitWithResponse("storeNodesForEntries", {
- notifierID: this.id,
- requests
- }).then(callback);
- }
-};
-
-/**
- * Associates a piece of data with a particular window.
- * @param {number} outerWindowID the ID of the window
- * @static
- */
-RequestNotifier.storeWindowData = function(outerWindowID, data)
-{
- port.emit("storeWindowData", {
- outerWindowID,
- data
- });
-};
-
-/**
- * Retrieves a piece of data previously associated with the window by calling
- * storeWindowData.
- * @param {number} outerWindowID the ID of the window
- * @param {Function} callback function to be called with the data.
- * @static
- */
-RequestNotifier.retrieveWindowData = function(outerWindowID, callback)
-{
- port.emitWithResponse("retrieveWindowData", outerWindowID).then(callback);
-};
-
-/**
- * Retrieves the statistics for a window.
- * @param {number} outerWindowID the ID of the window
- * @param {Function} callback the callback to be called with the resulting
- * object (object properties will be items, blocked,
- * whitelisted, hidden, filters) or null.
- */
-RequestNotifier.getWindowStatistics = function(outerWindowID, callback)
-{
- port.emitWithResponse("retrieveWindowStats", outerWindowID).then(callback);
-};
diff --git a/data/extensions/spyblock@gnu.org/lib/subscriptionClasses.js b/data/extensions/spyblock@gnu.org/lib/subscriptionClasses.js
deleted file mode 100644
index 5fe1eb8..0000000
--- a/data/extensions/spyblock@gnu.org/lib/subscriptionClasses.js
+++ /dev/null
@@ -1,584 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-"use strict";
-
-/**
- * @fileOverview Definition of Subscription class and its subclasses.
- */
-
-const {ActiveFilter, BlockingFilter,
- WhitelistFilter, ElemHideBase} = require("filterClasses");
-const {FilterNotifier} = require("filterNotifier");
-const {desc, extend} = require("coreUtils");
-
-/**
- * Abstract base class for filter subscriptions
- *
- * @param {string} url download location of the subscription
- * @param {string} [title] title of the filter subscription
- * @constructor
- */
-function Subscription(url, title)
-{
- this.url = url;
- this.filters = [];
- if (title)
- this._title = title;
- Subscription.knownSubscriptions[url] = this;
-}
-exports.Subscription = Subscription;
-
-Subscription.prototype =
-{
- /**
- * Download location of the subscription
- * @type {string}
- */
- url: null,
-
- /**
- * Filters contained in the filter subscription
- * @type {Filter[]}
- */
- filters: null,
-
- _title: null,
- _fixedTitle: false,
- _disabled: false,
-
- /**
- * Title of the filter subscription
- * @type {string}
- */
- get title()
- {
- return this._title;
- },
- set title(value)
- {
- if (value != this._title)
- {
- let oldValue = this._title;
- this._title = value;
- FilterNotifier.triggerListeners("subscription.title",
- this, value, oldValue);
- }
- return this._title;
- },
-
- /**
- * Determines whether the title should be editable
- * @type {boolean}
- */
- get fixedTitle()
- {
- return this._fixedTitle;
- },
- set fixedTitle(value)
- {
- if (value != this._fixedTitle)
- {
- let oldValue = this._fixedTitle;
- this._fixedTitle = value;
- FilterNotifier.triggerListeners("subscription.fixedTitle",
- this, value, oldValue);
- }
- return this._fixedTitle;
- },
-
- /**
- * Defines whether the filters in the subscription should be disabled
- * @type {boolean}
- */
- get disabled()
- {
- return this._disabled;
- },
- set disabled(value)
- {
- if (value != this._disabled)
- {
- let oldValue = this._disabled;
- this._disabled = value;
- FilterNotifier.triggerListeners("subscription.disabled",
- this, value, oldValue);
- }
- return this._disabled;
- },
-
- /**
- * Serializes the subscription to an array of strings for writing
- * out on the disk.
- * @param {string[]} buffer buffer to push the serialization results into
- */
- serialize(buffer)
- {
- buffer.push("[Subscription]");
- buffer.push("url=" + this.url);
- if (this._title)
- buffer.push("title=" + this._title);
- if (this._fixedTitle)
- buffer.push("fixedTitle=true");
- if (this._disabled)
- buffer.push("disabled=true");
- },
-
- serializeFilters(buffer)
- {
- for (let filter of this.filters)
- buffer.push(filter.text.replace(/\[/g, "\\["));
- },
-
- toString()
- {
- let buffer = [];
- this.serialize(buffer);
- return buffer.join("\n");
- }
-};
-
-/**
- * Cache for known filter subscriptions, maps URL to subscription objects.
- * @type {Object}
- */
-Subscription.knownSubscriptions = Object.create(null);
-
-/**
- * Returns a subscription from its URL, creates a new one if necessary.
- * @param {string} url
- * URL of the subscription
- * @return {Subscription}
- * subscription or null if the subscription couldn't be created
- */
-Subscription.fromURL = function(url)
-{
- if (url in Subscription.knownSubscriptions)
- return Subscription.knownSubscriptions[url];
-
- if (url[0] != "~")
- return new DownloadableSubscription(url, null);
- return new SpecialSubscription(url);
-};
-
-/**
- * Deserializes a subscription
- *
- * @param {Object} obj
- * map of serialized properties and their values
- * @return {Subscription}
- * subscription or null if the subscription couldn't be created
- */
-Subscription.fromObject = function(obj)
-{
- let result;
- if (obj.url[0] != "~")
- {
- // URL is valid - this is a downloadable subscription
- result = new DownloadableSubscription(obj.url, obj.title);
- if ("downloadStatus" in obj)
- result._downloadStatus = obj.downloadStatus;
- if ("lastSuccess" in obj)
- result.lastSuccess = parseInt(obj.lastSuccess, 10) || 0;
- if ("lastCheck" in obj)
- result._lastCheck = parseInt(obj.lastCheck, 10) || 0;
- if ("expires" in obj)
- result.expires = parseInt(obj.expires, 10) || 0;
- if ("softExpiration" in obj)
- result.softExpiration = parseInt(obj.softExpiration, 10) || 0;
- if ("errors" in obj)
- result._errors = parseInt(obj.errors, 10) || 0;
- if ("version" in obj)
- result.version = parseInt(obj.version, 10) || 0;
- if ("requiredVersion" in obj)
- result.requiredVersion = obj.requiredVersion;
- if ("homepage" in obj)
- result._homepage = obj.homepage;
- if ("lastDownload" in obj)
- result._lastDownload = parseInt(obj.lastDownload, 10) || 0;
- if ("downloadCount" in obj)
- result.downloadCount = parseInt(obj.downloadCount, 10) || 0;
- }
- else
- {
- result = new SpecialSubscription(obj.url, obj.title);
- if ("defaults" in obj)
- result.defaults = obj.defaults.split(" ");
- }
- if ("fixedTitle" in obj)
- result._fixedTitle = (obj.fixedTitle == "true");
- if ("privateMode" in obj)
- result.privateMode = (obj.privateMode == "true");
- if ("disabled" in obj)
- result._disabled = (obj.disabled == "true");
-
- return result;
-};
-
-/**
- * Class for special filter subscriptions (user's filters)
- * @param {string} url see Subscription()
- * @param {string} [title] see Subscription()
- * @constructor
- * @augments Subscription
- */
-function SpecialSubscription(url, title)
-{
- Subscription.call(this, url, title);
-}
-exports.SpecialSubscription = SpecialSubscription;
-
-SpecialSubscription.prototype = extend(Subscription, {
- /**
- * Filter types that should be added to this subscription by default
- * (entries should correspond to keys in SpecialSubscription.defaultsMap).
- * @type {string[]}
- */
- defaults: null,
-
- /**
- * Tests whether a filter should be added to this group by default
- * @param {Filter} filter filter to be tested
- * @return {boolean}
- */
- isDefaultFor(filter)
- {
- if (this.defaults && this.defaults.length)
- {
- for (let type of this.defaults)
- {
- if (filter instanceof SpecialSubscription.defaultsMap[type])
- return true;
- if (!(filter instanceof ActiveFilter) && type == "blacklist")
- return true;
- }
- }
-
- return false;
- },
-
- /**
- * See Subscription.serialize()
- * @inheritdoc
- */
- serialize(buffer)
- {
- Subscription.prototype.serialize.call(this, buffer);
- if (this.defaults && this.defaults.length)
- {
- buffer.push("defaults=" +
- this.defaults.filter(
- type => type in SpecialSubscription.defaultsMap
- ).join(" ")
- );
- }
- if (this._lastDownload)
- buffer.push("lastDownload=" + this._lastDownload);
- }
-});
-
-SpecialSubscription.defaultsMap = Object.create(null, desc({
- whitelist: WhitelistFilter,
- blocking: BlockingFilter,
- elemhide: ElemHideBase
-}));
-
-/**
- * Creates a new user-defined filter group.
- * @param {string} [title] title of the new filter group
- * @return {SpecialSubscription}
- */
-SpecialSubscription.create = function(title)
-{
- let url;
- do
- {
- url = "~user~" + Math.round(Math.random() * 1000000);
- } while (url in Subscription.knownSubscriptions);
- return new SpecialSubscription(url, title);
-};
-
-/**
- * Creates a new user-defined filter group and adds the given filter to it.
- * This group will act as the default group for this filter type.
- * @param {Filter} filter
- * @return {SpecialSubscription}
- */
-SpecialSubscription.createForFilter = function(filter)
-{
- let subscription = SpecialSubscription.create();
- subscription.filters.push(filter);
- for (let type in SpecialSubscription.defaultsMap)
- {
- if (filter instanceof SpecialSubscription.defaultsMap[type])
- subscription.defaults = [type];
- }
- if (!subscription.defaults)
- subscription.defaults = ["blocking"];
- return subscription;
-};
-
-/**
- * Abstract base class for regular filter subscriptions (both
- * internally and externally updated)
- * @param {string} url see Subscription()
- * @param {string} [title] see Subscription()
- * @constructor
- * @augments Subscription
- */
-function RegularSubscription(url, title)
-{
- Subscription.call(this, url, title || url);
-}
-exports.RegularSubscription = RegularSubscription;
-
-RegularSubscription.prototype = extend(Subscription, {
- _homepage: null,
- _lastDownload: 0,
-
- /**
- * Filter subscription homepage if known
- * @type {string}
- */
- get homepage()
- {
- return this._homepage;
- },
- set homepage(value)
- {
- if (value != this._homepage)
- {
- let oldValue = this._homepage;
- this._homepage = value;
- FilterNotifier.triggerListeners("subscription.homepage",
- this, value, oldValue);
- }
- return this._homepage;
- },
-
- /**
- * Time of the last subscription download (in seconds since the
- * beginning of the epoch)
- * @type {number}
- */
- get lastDownload()
- {
- return this._lastDownload;
- },
- set lastDownload(value)
- {
- if (value != this._lastDownload)
- {
- let oldValue = this._lastDownload;
- this._lastDownload = value;
- FilterNotifier.triggerListeners("subscription.lastDownload",
- this, value, oldValue);
- }
- return this._lastDownload;
- },
-
- /**
- * See Subscription.serialize()
- * @inheritdoc
- */
- serialize(buffer)
- {
- Subscription.prototype.serialize.call(this, buffer);
- if (this._homepage)
- buffer.push("homepage=" + this._homepage);
- if (this._lastDownload)
- buffer.push("lastDownload=" + this._lastDownload);
- }
-});
-
-/**
- * Class for filter subscriptions updated externally (by other extension)
- * @param {string} url see Subscription()
- * @param {string} [title] see Subscription()
- * @constructor
- * @augments RegularSubscription
- */
-function ExternalSubscription(url, title)
-{
- RegularSubscription.call(this, url, title);
-}
-exports.ExternalSubscription = ExternalSubscription;
-
-ExternalSubscription.prototype = extend(RegularSubscription, {
- /**
- * See Subscription.serialize()
- * @inheritdoc
- */
- serialize(buffer)
- {
- throw new Error(
- "Unexpected call, external subscriptions should not be serialized"
- );
- }
-});
-
-/**
- * Class for filter subscriptions updated externally (by other extension)
- * @param {string} url see Subscription()
- * @param {string} [title] see Subscription()
- * @constructor
- * @augments RegularSubscription
- */
-function DownloadableSubscription(url, title)
-{
- RegularSubscription.call(this, url, title);
-}
-exports.DownloadableSubscription = DownloadableSubscription;
-
-DownloadableSubscription.prototype = extend(RegularSubscription, {
- _downloadStatus: null,
- _lastCheck: 0,
- _errors: 0,
-
- /**
- * Status of the last download (ID of a string)
- * @type {string}
- */
- get downloadStatus()
- {
- return this._downloadStatus;
- },
- set downloadStatus(value)
- {
- let oldValue = this._downloadStatus;
- this._downloadStatus = value;
- FilterNotifier.triggerListeners("subscription.downloadStatus",
- this, value, oldValue);
- return this._downloadStatus;
- },
-
- /**
- * Time of the last successful download (in seconds since the beginning of the
- * epoch).
- */
- lastSuccess: 0,
-
- /**
- * Time when the subscription was considered for an update last time
- * (in seconds since the beginning of the epoch). This will be used
- * to increase softExpiration if the user doesn't use Adblock Plus
- * for some time.
- * @type {number}
- */
- get lastCheck()
- {
- return this._lastCheck;
- },
- set lastCheck(value)
- {
- if (value != this._lastCheck)
- {
- let oldValue = this._lastCheck;
- this._lastCheck = value;
- FilterNotifier.triggerListeners("subscription.lastCheck",
- this, value, oldValue);
- }
- return this._lastCheck;
- },
-
- /**
- * Hard expiration time of the filter subscription (in seconds since
- * the beginning of the epoch)
- * @type {number}
- */
- expires: 0,
-
- /**
- * Soft expiration time of the filter subscription (in seconds since
- * the beginning of the epoch)
- * @type {number}
- */
- softExpiration: 0,
-
- /**
- * Number of download failures since last success
- * @type {number}
- */
- get errors()
- {
- return this._errors;
- },
- set errors(value)
- {
- if (value != this._errors)
- {
- let oldValue = this._errors;
- this._errors = value;
- FilterNotifier.triggerListeners("subscription.errors", this,
- value, oldValue);
- }
- return this._errors;
- },
-
- /**
- * Version of the subscription data retrieved on last successful download
- * @type {number}
- */
- version: 0,
-
- /**
- * Minimal Adblock Plus version required for this subscription
- * @type {string}
- */
- requiredVersion: null,
-
- /**
- * Number indicating how often the object was downloaded.
- * @type {number}
- */
- downloadCount: 0,
-
- /**
- * Should be true if the Privatemode: header is set to true in the subscription
- * @type Boolean
- */
- privateMode: false,
-
- /**
- * See Subscription.serialize()
- * @inheritdoc
- */
- serialize(buffer)
- {
- RegularSubscription.prototype.serialize.call(this, buffer);
- if (this.downloadStatus)
- buffer.push("downloadStatus=" + this.downloadStatus);
- if (this.lastSuccess)
- buffer.push("lastSuccess=" + this.lastSuccess);
- if (this.lastCheck)
- buffer.push("lastCheck=" + this.lastCheck);
- if (this.expires)
- buffer.push("expires=" + this.expires);
- if (this.softExpiration)
- buffer.push("softExpiration=" + this.softExpiration);
- if (this.errors)
- buffer.push("errors=" + this.errors);
- if (this.version)
- buffer.push("version=" + this.version);
- if (this.requiredVersion)
- buffer.push("requiredVersion=" + this.requiredVersion);
- if (this.downloadCount)
- buffer.push("downloadCount=" + this.downloadCount);
- if (this.privateMode)
- buffer.push("privateMode=" + this.privateMode);
- }
-});
diff --git a/data/extensions/spyblock@gnu.org/lib/sync.js b/data/extensions/spyblock@gnu.org/lib/sync.js
deleted file mode 100644
index 3f9d973..0000000
--- a/data/extensions/spyblock@gnu.org/lib/sync.js
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * @fileOverview Firefox Sync integration
- */
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-let {FilterStorage} = require("filterStorage");
-let {FilterNotifier} = require("filterNotifier");
-let {Synchronizer} = require("synchronizer");
-let {Subscription, SpecialSubscription, DownloadableSubscription, ExternalSubscription} = require("subscriptionClasses");
-let {Filter, ActiveFilter} = require("filterClasses");
-
-// Firefox Sync classes are set later in initEngine()
-let Service, Engines, SyncEngine, Store, Tracker;
-
-/**
- * ID of the only record stored
- * @type String
- */
-let filtersRecordID = "6fad6286-8207-46b6-aa39-8e0ce0bd7c49";
-
-let Sync = exports.Sync =
-{
- /**
- * Will be set to true if/when Weave starts up.
- * @type Boolean
- */
- initialized: false,
-
- /**
- * Whether Weave requested us to track changes.
- * @type Boolean
- */
- trackingEnabled: false,
-
- /**
- * Returns Adblock Plus sync engine.
- * @result Engine
- */
- getEngine: function()
- {
- if (this.initialized)
- return Engines.get("adblockplus");
- else
- return null;
- }
-};
-
-/**
- * Listens to notifications from Sync service.
- */
-let SyncServiceObserver =
-{
- init: function()
- {
- try
- {
- let {Status, STATUS_DISABLED, CLIENT_NOT_CONFIGURED} = Cu.import("resource://services-sync/status.js", null);
- Sync.initialized = Status.ready;
- Sync.trackingEnabled = (Status.service != STATUS_DISABLED && Status.service != CLIENT_NOT_CONFIGURED);
- }
- catch (e)
- {
- return;
- }
-
- if (Sync.initialized)
- this.initEngine();
- else
- Services.obs.addObserver(this, "weave:service:ready", true);
- Services.obs.addObserver(this, "weave:engine:start-tracking", true);
- Services.obs.addObserver(this, "weave:engine:stop-tracking", true);
-
- onShutdown.add(function()
- {
- try
- {
- Services.obs.removeObserver(this, "weave:service:ready");
- } catch (e) {}
- Services.obs.removeObserver(this, "weave:engine:start-tracking");
- Services.obs.removeObserver(this, "weave:engine:stop-tracking");
- }.bind(this));
- },
-
- initEngine: function()
- {
- ({Engines, SyncEngine, Store, Tracker} = Cu.import("resource://services-sync/engines.js"));
- if (typeof Engines == "undefined")
- {
- ({Service} = Cu.import("resource://services-sync/service.js"));
- Engines = Service.engineManager;
- }
-
- ABPEngine.prototype.__proto__ = SyncEngine.prototype;
- ABPStore.prototype.__proto__ = Store.prototype;
- ABPTracker.prototype.__proto__ = Tracker.prototype;
-
- Engines.register(ABPEngine);
- onShutdown.add(function()
- {
- Engines.unregister("adblockplus");
- });
- },
-
- observe: function(subject, topic, data)
- {
- switch (topic)
- {
- case "weave:service:ready":
- if (Sync.initialized)
- return;
-
- this.initEngine();
- Sync.initialized = true;
- break;
- case "weave:engine:start-tracking":
- Sync.trackingEnabled = true;
- if (trackerInstance)
- trackerInstance.startTracking();
- break;
- case "weave:engine:stop-tracking":
- Sync.trackingEnabled = false;
- if (trackerInstance)
- trackerInstance.stopTracking();
- break;
- }
- },
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
-};
-
-function ABPEngine()
-{
- SyncEngine.call(this, "AdblockPlus", Service);
-}
-ABPEngine.prototype =
-{
- _storeObj: ABPStore,
- _trackerObj: ABPTracker,
- version: 1,
-
- _reconcile: function(item)
- {
- // Always process server data, we will do the merging ourselves
- return true;
- }
-};
-
-function ABPStore(name, engine)
-{
- Store.call(this, name, engine);
-}
-ABPStore.prototype =
-{
- getAllIDs: function()
- {
- let result = {}
- result[filtersRecordID] = true;
- return result;
- },
-
- changeItemID: function(oldId, newId)
- {
- // This should not be called, our engine doesn't implement _findDupe
- throw Cr.NS_ERROR_UNEXPECTED;
- },
-
- itemExists: function(id)
- {
- // Only one id exists so far
- return (id == filtersRecordID);
- },
-
- createRecord: function(id, collection)
- {
- let record = new ABPEngine.prototype._recordObj(collection, id);
- if (id == filtersRecordID)
- {
- record.cleartext = {
- id: id,
- subscriptions: [],
- };
- for (let subscription of FilterStorage.subscriptions)
- {
- if (subscription instanceof ExternalSubscription)
- continue;
-
- let subscriptionEntry =
- {
- url: subscription.url,
- disabled: subscription.disabled
- };
- if (subscription instanceof SpecialSubscription)
- {
- subscriptionEntry.filters = [];
- for (let filter of subscription.filters)
- {
- let filterEntry = {text: filter.text};
- if (filter instanceof ActiveFilter)
- filterEntry.disabled = filter.disabled;
- subscriptionEntry.filters.push(filterEntry);
- }
- }
- else
- subscriptionEntry.title = subscription.title;
- record.cleartext.subscriptions.push(subscriptionEntry);
- }
-
- // Data sent, forget about local changes now
- trackerInstance.clearPrivateChanges()
- }
- else
- record.deleted = true;
-
- return record;
- },
-
- create: function(record)
- {
- // This should not be called because our record list doesn't change but
- // call update just in case.
- this.update(record);
- },
-
- update: function(record)
- {
- if (record.id != filtersRecordID)
- return;
-
- this._log.trace("Merging in remote data");
-
- let data = record.cleartext.subscriptions;
-
- // First make sure we have the same subscriptions on both sides
- let seenSubscription = Object.create(null);
- for (let remoteSubscription of data)
- {
- seenSubscription[remoteSubscription.url] = true;
- if (remoteSubscription.url in FilterStorage.knownSubscriptions)
- {
- let subscription = FilterStorage.knownSubscriptions[remoteSubscription.url];
- if (!trackerInstance.didSubscriptionChange(remoteSubscription))
- {
- // Only change local subscription if there were no changes, otherwise dismiss remote changes
- subscription.disabled = remoteSubscription.disabled;
- if (subscription instanceof DownloadableSubscription)
- subscription.title = remoteSubscription.title;
- }
- }
- else if (!trackerInstance.didSubscriptionChange(remoteSubscription))
- {
- // Subscription was added remotely, add it locally as well
- let subscription = Subscription.fromURL(remoteSubscription.url);
- if (!subscription)
- continue;
-
- subscription.disabled = remoteSubscription.disabled;
- if (subscription instanceof DownloadableSubscription)
- {
- subscription.title = remoteSubscription.title;
- FilterStorage.addSubscription(subscription);
- Synchronizer.execute(subscription);
- }
- }
- }
-
- for (let subscription of FilterStorage.subscriptions.slice())
- {
- if (!(subscription.url in seenSubscription) && subscription instanceof DownloadableSubscription && !trackerInstance.didSubscriptionChange(subscription))
- {
- // Subscription was removed remotely, remove it locally as well
- FilterStorage.removeSubscription(subscription);
- }
- }
-
- // Now sync the custom filters
- let seenFilter = Object.create(null);
- for (let remoteSubscription of data)
- {
- if (!("filters" in remoteSubscription))
- continue;
-
- for (let remoteFilter of remoteSubscription.filters)
- {
- seenFilter[remoteFilter.text] = true;
-
- let filter = Filter.fromText(remoteFilter.text);
- if (trackerInstance.didFilterChange(filter))
- continue;
-
- if (filter.subscriptions.some((subscription) => subscription instanceof SpecialSubscription))
- {
- // Filter might have been changed remotely
- if (filter instanceof ActiveFilter)
- filter.disabled = remoteFilter.disabled;
- }
- else
- {
- // Filter was added remotely, add it locally as well
- FilterStorage.addFilter(filter);
- }
- }
- }
-
- for (let subscription of FilterStorage.subscriptions)
- {
- if (!(subscription instanceof SpecialSubscription))
- continue;
-
- for (let filter of subscription.filters.slice())
- {
- if (!(filter.text in seenFilter) && !trackerInstance.didFilterChange(filter))
- {
- // Filter was removed remotely, remove it locally as well
- FilterStorage.removeFilter(filter);
- }
- }
- }
-
- // Merge done, forget about local changes now
- trackerInstance.clearPrivateChanges()
- },
-
- remove: function(record)
- {
- // Shouldn't be called but if it is - ignore
- },
-
- wipe: function()
- {
- this._log.trace("Got wipe command, removing all data");
-
- for (let subscription of FilterStorage.subscriptions.slice())
- {
- if (subscription instanceof DownloadableSubscription)
- FilterStorage.removeSubscription(subscription);
- else if (subscription instanceof SpecialSubscription)
- {
- for (let filter of subscription.filters.slice())
- FilterStorage.removeFilter(filter);
- }
- }
-
- // Data wiped, forget about local changes now
- trackerInstance.clearPrivateChanges()
- }
-};
-
-/**
- * Hack to allow store to use the tracker - store tracker pointer globally.
- */
-let trackerInstance = null;
-
-function ABPTracker(name, engine)
-{
- Tracker.call(this, name, engine);
-
- this.privateTracker = new Tracker(name + ".private", engine);
- trackerInstance = this;
-
- this.onChange = this.onChange.bind(this);
-
- if (Sync.trackingEnabled)
- this.startTracking();
-}
-ABPTracker.prototype =
-{
- privateTracker: null,
-
- startTracking: function()
- {
- FilterNotifier.addListener(this.onChange);
- },
-
- stopTracking: function()
- {
- FilterNotifier.removeListener(this.onChange);
- },
-
- clearPrivateChanges: function()
- {
- this.privateTracker.clearChangedIDs();
- },
-
- addPrivateChange: function(id)
- {
- // Ignore changes during syncing
- if (this.ignoreAll)
- return;
-
- this.addChangedID(filtersRecordID);
- this.privateTracker.addChangedID(id);
- this.score += 10;
- },
-
- didSubscriptionChange: function(subscription)
- {
- return ("subscription " + subscription.url) in this.privateTracker.changedIDs;
- },
-
- didFilterChange: function(filter)
- {
- return ("filter " + filter.text) in this.privateTracker.changedIDs;
- },
-
- onChange: function(action, item)
- {
- switch (action)
- {
- case "subscription.updated":
- if ("oldSubscription" in item)
- {
- // Subscription moved to a new address
- this.addPrivateChange("subscription " + item.url);
- this.addPrivateChange("subscription " + item.oldSubscription.url);
- }
- else if (item instanceof SpecialSubscription)
- {
- // User's filters changed via Preferences window
- for (let filter of item.filters)
- this.addPrivateChange("filter " + filter.text);
- for (let filter of item.oldFilters)
- this.addPrivateChange("filter " + filter.text);
- }
- break;
- case "subscription.added":
- case "subscription.removed":
- case "subscription.disabled":
- case "subscription.title":
- this.addPrivateChange("subscription " + item.url);
- break;
- case "filter.added":
- case "filter.removed":
- case "filter.disabled":
- this.addPrivateChange("filter " + item.text);
- break;
- }
- }
-};
-
-SyncServiceObserver.init();
diff --git a/data/extensions/spyblock@gnu.org/lib/synchronizer.js b/data/extensions/spyblock@gnu.org/lib/synchronizer.js
deleted file mode 100644
index b8d14a2..0000000
--- a/data/extensions/spyblock@gnu.org/lib/synchronizer.js
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-"use strict";
-
-/**
- * @fileOverview Manages synchronization of filter subscriptions.
- */
-
-const {Downloader, Downloadable,
- MILLIS_IN_SECOND, MILLIS_IN_MINUTE,
- MILLIS_IN_HOUR, MILLIS_IN_DAY} = require("downloader");
-const {Filter} = require("filterClasses");
-const {FilterStorage} = require("filterStorage");
-const {FilterNotifier} = require("filterNotifier");
-const {Prefs} = require("prefs");
-const {Subscription, DownloadableSubscription} = require("subscriptionClasses");
-const {Utils} = require("utils");
-
-const INITIAL_DELAY = 1 * MILLIS_IN_MINUTE;
-const CHECK_INTERVAL = 1 * MILLIS_IN_HOUR;
-const DEFAULT_EXPIRATION_INTERVAL = 5 * MILLIS_IN_DAY;
-
-/**
- * The object providing actual downloading functionality.
- * @type {Downloader}
- */
-let downloader = null;
-
-/**
- * This object is responsible for downloading filter subscriptions whenever
- * necessary.
- * @class
- */
-let Synchronizer = exports.Synchronizer =
-{
- /**
- * Called on module startup.
- */
- init()
- {
- downloader = new Downloader(this._getDownloadables.bind(this),
- INITIAL_DELAY, CHECK_INTERVAL);
- onShutdown.add(() =>
- {
- downloader.cancel();
- });
-
- downloader.onExpirationChange = this._onExpirationChange.bind(this);
- downloader.onDownloadStarted = this._onDownloadStarted.bind(this);
- downloader.onDownloadSuccess = this._onDownloadSuccess.bind(this);
- downloader.onDownloadError = this._onDownloadError.bind(this);
- },
-
- /**
- * Checks whether a subscription is currently being downloaded.
- * @param {string} url URL of the subscription
- * @return {boolean}
- */
- isExecuting(url)
- {
- return downloader.isDownloading(url);
- },
-
- /**
- * Starts the download of a subscription.
- * @param {DownloadableSubscription} subscription
- * Subscription to be downloaded
- * @param {boolean} manual
- * true for a manually started download (should not trigger fallback
- * requests)
- */
- execute(subscription, manual)
- {
- downloader.download(this._getDownloadable(subscription, manual));
- },
-
- /**
- * Yields Downloadable instances for all subscriptions that can be downloaded.
- */
- *_getDownloadables()
- {
- if (!Prefs.subscriptions_autoupdate)
- return;
-
- for (let subscription of FilterStorage.subscriptions)
- {
- if (subscription instanceof DownloadableSubscription)
- yield this._getDownloadable(subscription, false);
- }
- },
-
- /**
- * Creates a Downloadable instance for a subscription.
- * @param {Subscription} subscription
- * @param {boolean} manual
- * @return {Downloadable}
- */
- _getDownloadable(subscription, manual)
- {
- let result = new Downloadable(subscription.url);
- if (subscription.lastDownload != subscription.lastSuccess)
- result.lastError = subscription.lastDownload * MILLIS_IN_SECOND;
- result.lastCheck = subscription.lastCheck * MILLIS_IN_SECOND;
- result.lastVersion = subscription.version;
- result.softExpiration = subscription.softExpiration * MILLIS_IN_SECOND;
- result.hardExpiration = subscription.expires * MILLIS_IN_SECOND;
- result.manual = manual;
- result.downloadCount = subscription.downloadCount;
- result.privateMode = subscription.privateMode;
- return result;
- },
-
- _onExpirationChange(downloadable)
- {
- let subscription = Subscription.fromURL(downloadable.url);
- subscription.lastCheck = Math.round(
- downloadable.lastCheck / MILLIS_IN_SECOND
- );
- subscription.softExpiration = Math.round(
- downloadable.softExpiration / MILLIS_IN_SECOND
- );
- subscription.expires = Math.round(
- downloadable.hardExpiration / MILLIS_IN_SECOND
- );
- },
-
- _onDownloadStarted(downloadable)
- {
- let subscription = Subscription.fromURL(downloadable.url);
- FilterNotifier.triggerListeners("subscription.downloading", subscription);
- },
-
- _onDownloadSuccess(downloadable, responseText, errorCallback,
- redirectCallback)
- {
- let lines = responseText.split(/[\r\n]+/);
- let headerMatch = /\[Adblock(?:\s*Plus\s*([\d.]+)?)?\]/i.exec(lines[0]);
- if (!headerMatch)
- return errorCallback("synchronize_invalid_data");
- let minVersion = headerMatch[1];
-
- // Don't remove parameter comments immediately but add them to a list first,
- // they need to be considered in the checksum calculation.
- let remove = [];
- let params = {
- redirect: null,
- homepage: null,
- title: null,
- version: null,
- privatemode: null,
- expires: null
- };
- for (let i = 0; i < lines.length; i++)
- {
- let match = /^\s*!\s*(\w+)\s*:\s*(.*)/.exec(lines[i]);
- if (match)
- {
- let keyword = match[1].toLowerCase();
- let value = match[2];
- if (keyword in params)
- {
- params[keyword] = value;
- remove.push(i);
- }
- else if (keyword == "checksum")
- {
- lines.splice(i--, 1);
- let checksum = Utils.generateChecksum(lines);
- if (checksum && checksum != value.replace(/=+$/, ""))
- return errorCallback("synchronize_checksum_mismatch");
- }
- }
- }
-
- if (params.redirect)
- return redirectCallback(params.redirect);
-
- // Handle redirects
- let subscription = Subscription.fromURL(downloadable.redirectURL ||
- downloadable.url);
- if (downloadable.redirectURL &&
- downloadable.redirectURL != downloadable.url)
- {
- let oldSubscription = Subscription.fromURL(downloadable.url);
- subscription.title = oldSubscription.title;
- subscription.disabled = oldSubscription.disabled;
- subscription.lastCheck = oldSubscription.lastCheck;
-
- let listed = (oldSubscription.url in FilterStorage.knownSubscriptions);
- if (listed)
- FilterStorage.removeSubscription(oldSubscription);
-
- delete Subscription.knownSubscriptions[oldSubscription.url];
-
- if (listed)
- FilterStorage.addSubscription(subscription);
- }
-
- // The download actually succeeded
- subscription.lastSuccess = subscription.lastDownload = Math.round(
- Date.now() / MILLIS_IN_SECOND
- );
- subscription.downloadStatus = "synchronize_ok";
- subscription.downloadCount = downloadable.downloadCount;
- subscription.errors = 0;
-
- // Remove lines containing parameters
- for (let i = remove.length - 1; i >= 0; i--)
- lines.splice(remove[i], 1);
-
- // Process parameters
- if (params.homepage)
- {
- let url;
- try
- {
- url = new URL(params.homepage);
- }
- catch (e)
- {
- url = null;
- }
-
- if (url && (url.protocol == "http:" || url.protocol == "https:"))
- subscription.homepage = url.href;
- }
-
- if (params.privatemode)
- {
- subscription.privateMode = (params.privatemode == "true");
- }
-
- if (params.title)
- {
- subscription.title = params.title;
- subscription.fixedTitle = true;
- }
- else
- subscription.fixedTitle = false;
-
- subscription.version = (params.version ? parseInt(params.version, 10) : 0);
-
- let expirationInterval = DEFAULT_EXPIRATION_INTERVAL;
- if (params.expires)
- {
- let match = /^(\d+)\s*(h)?/.exec(params.expires);
- if (match)
- {
- let interval = parseInt(match[1], 10);
- if (match[2])
- expirationInterval = interval * MILLIS_IN_HOUR;
- else
- expirationInterval = interval * MILLIS_IN_DAY;
- }
- }
-
- let [
- softExpiration,
- hardExpiration
- ] = downloader.processExpirationInterval(expirationInterval);
- subscription.softExpiration = Math.round(softExpiration / MILLIS_IN_SECOND);
- subscription.expires = Math.round(hardExpiration / MILLIS_IN_SECOND);
-
- if (minVersion)
- subscription.requiredVersion = minVersion;
- else
- delete subscription.requiredVersion;
-
- // Process filters
- lines.shift();
- let filters = [];
- for (let line of lines)
- {
- line = Filter.normalize(line);
- if (line)
- filters.push(Filter.fromText(line));
- }
-
- FilterStorage.updateSubscriptionFilters(subscription, filters);
-
- return undefined;
- },
-
- _onDownloadError(downloadable, downloadURL, error, channelStatus,
- responseStatus, redirectCallback)
- {
- let subscription = Subscription.fromURL(downloadable.url);
- subscription.lastDownload = Math.round(Date.now() / MILLIS_IN_SECOND);
- subscription.downloadStatus = error;
-
- // Request fallback URL if necessary - for automatic updates only
- if (!downloadable.manual)
- {
- subscription.errors++;
-
- if (redirectCallback &&
- subscription.errors >= Prefs.subscriptions_fallbackerrors &&
- /^https?:\/\//i.test(subscription.url))
- {
- subscription.errors = 0;
-
- let fallbackURL = Prefs.subscriptions_fallbackurl;
- const {addonVersion} = require("info");
- fallbackURL = fallbackURL.replace(/%VERSION%/g,
- encodeURIComponent(addonVersion));
- fallbackURL = fallbackURL.replace(/%SUBSCRIPTION%/g,
- encodeURIComponent(subscription.url));
- fallbackURL = fallbackURL.replace(/%URL%/g,
- encodeURIComponent(downloadURL));
- fallbackURL = fallbackURL.replace(/%ERROR%/g,
- encodeURIComponent(error));
- fallbackURL = fallbackURL.replace(/%CHANNELSTATUS%/g,
- encodeURIComponent(channelStatus));
- fallbackURL = fallbackURL.replace(/%RESPONSESTATUS%/g,
- encodeURIComponent(responseStatus));
-
- let request = new XMLHttpRequest();
- request.mozBackgroundRequest = true;
- request.open("GET", fallbackURL);
- request.overrideMimeType("text/plain");
- request.channel.loadFlags = request.channel.loadFlags |
- request.channel.INHIBIT_CACHING |
- request.channel.VALIDATE_ALWAYS;
- request.addEventListener("load", ev =>
- {
- if (onShutdown.done)
- return;
-
- if (!(subscription.url in FilterStorage.knownSubscriptions))
- return;
-
- let match = /^(\d+)(?:\s+(\S+))?$/.exec(request.responseText);
- if (match && match[1] == "301" && // Moved permanently
- match[2] && /^https?:\/\//i.test(match[2]))
- {
- redirectCallback(match[2]);
- }
- else if (match && match[1] == "410") // Gone
- {
- let data = "[Adblock]\n" +
- subscription.filters.map(f => f.text).join("\n");
- redirectCallback("data:text/plain," + encodeURIComponent(data));
- }
- }, false);
- request.send(null);
- }
- }
- }
-};
-Synchronizer.init();
diff --git a/data/extensions/spyblock@gnu.org/lib/ui.js b/data/extensions/spyblock@gnu.org/lib/ui.js
deleted file mode 100644
index 1941a97..0000000
--- a/data/extensions/spyblock@gnu.org/lib/ui.js
+++ /dev/null
@@ -1,1906 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-let {Utils} = require("utils");
-let {port} = require("messaging");
-let {Prefs} = require("prefs");
-let {Policy} = require("contentPolicy");
-let {FilterStorage} = require("filterStorage");
-let {FilterNotifier} = require("filterNotifier");
-let {RequestNotifier} = require("requestNotifier");
-let {Filter} = require("filterClasses");
-let {Subscription, SpecialSubscription, DownloadableSubscription} = require("subscriptionClasses");
-let {Synchronizer} = require("synchronizer");
-let {KeySelector} = require("keySelector");
-let {Notification} = require("notification");
-let {initAntiAdblockNotification} = require("antiadblockInit");
-
-let CustomizableUI = null;
-
-/**
- * Filter corresponding with "disable on site" menu item (set in fillIconMent()).
- * @type Filter
- */
-let siteWhitelist = null;
-/**
- * Filter corresponding with "disable on site" menu item (set in fillIconMenu()).
- * @type Filter
- */
-let pageWhitelist = null;
-
-/**
- * Window containing the detached list of blockable items.
- * @type Window
- */
-let detachedBottombar = null;
-
-/**
- * Object initializing add-on options, observes add-on manager notifications
- * about add-on options being opened.
- * @type nsIObserver
- */
-let optionsObserver =
-{
- init: function()
- {
- Services.obs.addObserver(this, "addon-options-displayed", true);
- onShutdown.add(function()
- {
- Services.obs.removeObserver(this, "addon-options-displayed");
- }.bind(this));
- },
-
- /**
- * Initializes options in add-on manager when they show up.
- */
- initOptionsDoc: function(/**Document*/ doc)
- {
- function hideElement(id, hide)
- {
- let element = doc.getElementById(id);
- if (element)
- element.collapsed = hide;
- }
- function setChecked(id, checked)
- {
- let element = doc.getElementById(id);
- if (element)
- element.value = checked;
- }
- function addCommandHandler(id, handler)
- {
- let element = doc.getElementById(id);
- if (element)
- element.addEventListener("command", handler, false);
- }
-
- Utils.splitAllLabels(doc);
-
- addCommandHandler("adblockplus-filters", UI.openFiltersDialog.bind(UI));
-
- let {Sync} = require("sync");
- let syncEngine = Sync.getEngine();
- hideElement("adblockplus-sync", !syncEngine);
-
- let {defaultToolbarPosition, statusbarPosition} = require("appSupport");
- let hasToolbar = defaultToolbarPosition;
- let hasStatusBar = statusbarPosition;
-
- hideElement("adblockplus-showintoolbar", !hasToolbar);
- hideElement("adblockplus-showinstatusbar", !hasStatusBar);
-
- let checkbox = doc.querySelector("setting[type=bool]");
- if (checkbox)
- initCheckboxes();
-
- function initCheckboxes()
- {
- if (!("value" in checkbox))
- {
- // XBL bindings didn't apply yet (bug 708397), try later
- Utils.runAsync(initCheckboxes);
- return;
- }
-
- setChecked("adblockplus-savestats", Prefs.savestats);
- addCommandHandler("adblockplus-savestats", function()
- {
- UI.toggleSaveStats(doc.defaultView);
- this.value = Prefs.savestats;
- });
-
- hideElement("adblockplus-shownotifications", !Prefs.notifications_showui);
- setChecked("adblockplus-shownotifications", Prefs.notifications_ignoredcategories.indexOf("*") == -1);
- addCommandHandler("adblockplus-shownotifications", function()
- {
- Notification.toggleIgnoreCategory("*");
- this.value = (Prefs.notifications_ignoredcategories.indexOf("*") == -1);
- });
-
- let hasAcceptableAds = FilterStorage.subscriptions.some((subscription) => subscription instanceof DownloadableSubscription &&
- subscription.url == Prefs.subscriptions_exceptionsurl);
- setChecked("adblockplus-acceptableAds", hasAcceptableAds);
- addCommandHandler("adblockplus-acceptableAds", function()
- {
- this.value = UI.toggleAcceptableAds();
- });
-
- setChecked("adblockplus-sync", syncEngine && syncEngine.enabled);
- addCommandHandler("adblockplus-sync", function()
- {
- this.value = UI.toggleSync();
- });
-
- setChecked("adblockplus-showintoolbar", UI.isToolbarIconVisible());
- addCommandHandler("adblockplus-showintoolbar", function()
- {
- UI.toggleToolbarIcon();
- this.value = UI.isToolbarIconVisible();
- });
-
- let list = doc.getElementById("adblockplus-subscription-list");
- if (list)
- {
- // Load subscriptions data
- let request = new XMLHttpRequest();
- request.mozBackgroundRequest = true;
- request.open("GET", "chrome://adblockplus/content/ui/subscriptions.xml");
- request.addEventListener("load", function()
- {
- if (onShutdown.done)
- return;
-
- let currentSubscription = FilterStorage.subscriptions.filter((subscription) => subscription instanceof DownloadableSubscription &&
- subscription.url != Prefs.subscriptions_exceptionsurl &&
- subscription.url != Prefs.subscriptions_antiadblockurl);
- currentSubscription = (currentSubscription.length ? currentSubscription[0] : null);
-
- let subscriptions =request.responseXML.getElementsByTagName("subscription");
- for (let i = 0; i < subscriptions.length; i++)
- {
- let item = subscriptions[i];
- let url = item.getAttribute("url");
- if (!url)
- continue;
-
- list.appendItem(item.getAttribute("title"), url, null);
- if (currentSubscription && url == currentSubscription.url)
- list.selectedIndex = list.itemCount - 1;
-
- if (currentSubscription && list.selectedIndex < 0)
- {
- list.appendItem(currentSubscription.title, currentSubscription.url, null);
- list.selectedIndex = list.itemCount - 1;
- }
- }
-
- var listener = function()
- {
- if (list.value)
- UI.setSubscription(list.value, list.label);
- }
- list.addEventListener("command", listener, false);
-
- // xul:menulist in Fennec is broken and doesn't trigger any events
- // on selection. Have to detect selectIndex changes instead.
- // See https://bugzilla.mozilla.org/show_bug.cgi?id=891736
- list.watch("selectedIndex", function(prop, oldval, newval)
- {
- Utils.runAsync(listener);
- return newval;
- });
- }, false);
- request.send();
- }
- }
- },
-
- observe: function(subject, topic, data)
- {
- let {addonID} = require("info")
- if (data != addonID)
- return;
-
- this.initOptionsDoc(subject.QueryInterface(Ci.nsIDOMDocument));
- },
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference])
-};
-optionsObserver.init();
-
-/**
- * Session restore observer instance, stored to prevent it from being garbage
- * collected.
- * @type SessionRestoreObserver
- */
-let sessionRestoreObserver = null;
-
-/**
- * Observer waiting for the browsing session to be restored on startup.
- */
-function SessionRestoreObserver(/**function*/ callback)
-{
- sessionRestoreObserver = this;
-
- this.callback = callback;
- Services.obs.addObserver(this, "sessionstore-windows-restored", true);
-
- // Just in case, don't wait longer than 5 seconds
- this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
- this.timer.init(this, 5000, Ci.nsITimer.TYPE_ONE_SHOT);
-}
-SessionRestoreObserver.prototype =
-{
- callback: null,
- timer: null,
- observe: function(subject, topic, data)
- {
- Services.obs.removeObserver(this, "sessionstore-windows-restored");
- sessionRestoreObserver = null;
-
- this.timer.cancel();
- this.timer = null;
-
- if (!onShutdown.done)
- this.callback();
- },
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference])
-}
-
-/**
- * Timer used to delay notification handling.
- * @type nsITimer
- */
-let notificationTimer = null;
-
-let UI = exports.UI =
-{
- /**
- * Gets called on startup, initializes UI integration.
- */
- init: function()
- {
- // We have to wait for multiple events before running start-up actions
- let prerequisites = [];
-
- // Start loading overlay
- prerequisites.push(new Promise((resolve, reject) =>
- {
- let request = new XMLHttpRequest();
- request.mozBackgroundRequest = true;
- request.open("GET", "chrome://adblockplus/content/ui/overlay.xul");
- request.channel.owner = Utils.systemPrincipal;
- request.addEventListener("load", event =>
- {
- if (onShutdown.done)
- return;
-
- this.processOverlay(request.responseXML.documentElement);
-
- // Don't wait for the rest of the startup sequence, add icon already
- this.addToolbarButton();
-
- resolve();
- }, false);
-
- request.addEventListener("error", event =>
- {
- reject(new Error("Unexpected: Failed to load overlay.xul"));
- });
-
- request.send(null);
- }));
-
- // Wait for filters to load
- if (!FilterStorage.initialized)
- prerequisites.push(FilterNotifier.once("load"));
-
- // Wait for session to be restored
- prerequisites.push(new Promise((resolve, reject) =>
- {
- let window = this.currentWindow;
- if (!window && "nsISessionStore" in Ci)
- {
- // No application windows yet, the application must be starting up. Wait
- // for session to be restored before initializing our UI.
- new SessionRestoreObserver(resolve);
- }
- else
- resolve();
- }));
-
- Promise.all(prerequisites).then(() => this.initDone())
- .catch(e => Cu.reportError(e));
- },
-
- /**
- * Provesses overlay document data and initializes overlay property.
- */
- processOverlay: function(/**Element*/ root)
- {
- Utils.splitAllLabels(root);
-
- let specialElements = {"abp-status-popup": true, "abp-status": true, "abp-toolbarbutton": true, "abp-menuitem": true, "abp-bottombar-container": true};
-
- this.overlay = {all: []};
-
- // Remove whitespace text nodes
- let walker = root.ownerDocument.createTreeWalker(
- root, Ci.nsIDOMNodeFilter.SHOW_TEXT,
- (node) => !/\S/.test(node.nodeValue), false
- );
- let whitespaceNodes = [];
- while (walker.nextNode())
- whitespaceNodes.push(walker.currentNode);
-
- for (let i = 0; i < whitespaceNodes.length; i++)
- whitespaceNodes[i].parentNode.removeChild(whitespaceNodes[i]);
-
- // Put overlay elements into appropriate fields
- while (root.firstElementChild)
- {
- let child = root.firstElementChild;
- if (child.getAttribute("id") in specialElements)
- this.overlay[child.getAttribute("id")] = child;
- else
- this.overlay.all.push(child);
- root.removeChild(child);
- }
-
- // Read overlay attributes
- this.overlay.attributes = {};
- for (let i = 0; i < root.attributes.length; i++)
- this.overlay.attributes[root.attributes[i].name] = root.attributes[i].value;
-
- // Copy context menu into the toolbar icon and Tools menu item
- function fixId(element, newId)
- {
- if (element.hasAttribute("id"))
- element.setAttribute("id", element.getAttribute("id").replace("abp-status", newId));
-
- for (let i = 0, len = element.children.length; i < len; i++)
- fixId(element.children[i], newId);
-
- return element;
- }
-
- if ("abp-status-popup" in this.overlay)
- {
- let menuSource = this.overlay["abp-status-popup"];
- delete this.overlay["abp-status-popup"];
-
- if (this.overlay.all.length)
- this.overlay.all[0].appendChild(menuSource);
- if ("abp-toolbarbutton" in this.overlay)
- this.overlay["abp-toolbarbutton"].appendChild(fixId(menuSource.cloneNode(true), "abp-toolbar"));
- if ("abp-menuitem" in this.overlay)
- this.overlay["abp-menuitem"].appendChild(fixId(menuSource.cloneNode(true), "abp-menuitem"));
- }
- },
-
- /**
- * Gets called once the initialization is finished and Adblock Plus elements
- * can be added to the UI.
- */
- initDone: function()
- {
- // The icon might be added already, make sure its state is correct
- this.updateState();
-
- // Listen for pref and filters changes
- Prefs.addListener(name =>
- {
- if (name == "enabled" || name == "defaulttoolbaraction" || name == "defaultstatusbaraction")
- this.updateState();
- else if (name == "showinstatusbar")
- {
- for (let window of this.applicationWindows)
- this.updateStatusbarIcon(window);
- }
- });
-
- for (let eventName of [
- "filter.added", "filter.removed", "filter.disabled",
- "subscription.added", "subscription.removed", "subscription.disabled",
- "subscription.updated", "load"
- ])
- {
- FilterNotifier.on(eventName, () => this.updateState());
- }
-
- Notification.addShowListener(notification =>
- {
- let window = this.currentWindow;
- if (!window)
- return;
-
- let button = window.document.getElementById("abp-toolbarbutton")
- || window.document.getElementById("abp-status");
- if (!button)
- return;
-
- this._showNotification(window, button, notification);
- });
-
- // Add "anti-adblock messages" notification
- initAntiAdblockNotification();
-
- // Initialize subscribe link handling
- port.on("subscribeLinkClick", data => this.subscribeLinkClicked(data));
-
- // Execute first-run actions if a window is open already, otherwise it
- // will happen in applyToWindow() when a window is opened.
- this.firstRunActions(this.currentWindow);
- },
-
- addToolbarButton: function()
- {
- let {WindowObserver} = require("windowObserver");
- new WindowObserver(this);
-
- let {defaultToolbarPosition} = require("appSupport");
- if ("abp-toolbarbutton" in this.overlay && defaultToolbarPosition)
- {
- try
- {
- ({CustomizableUI} = Cu.import("resource:///modules/CustomizableUI.jsm", null));
- }
- catch (e)
- {
- // No built-in CustomizableUI API, use our own implementation.
- ({CustomizableUI} = require("customizableUI"));
- }
-
- CustomizableUI.createWidget({
- id: "abp-toolbarbutton",
- type: "custom",
- positionAttribute: "abp-iconposition", // For emulation only
- defaultArea: defaultToolbarPosition.parent,
- defaultBefore: defaultToolbarPosition.before, // For emulation only
- defaultAfter: defaultToolbarPosition.after, // For emulation only
- removable: true,
- onBuild: function(document)
- {
- let node = document.importNode(this.overlay["abp-toolbarbutton"], true);
- node.addEventListener("click", this.onIconClick, false);
- node.addEventListener("command", this.onIconClick, false);
- this.updateIconState(document.defaultView, node);
- return node;
- }.bind(this),
- onAdded: function(node)
- {
- // For emulation only, this callback isn't part of the official
- // CustomizableUI API.
- this.updateIconState(node.ownerDocument.defaultView, node);
- }.bind(this),
- });
- onShutdown.add(CustomizableUI.destroyWidget.bind(CustomizableUI, "abp-toolbarbutton"));
- }
- },
-
- firstRunActions: function(window)
- {
- if (this.firstRunDone || !window || !FilterStorage.initialized)
- return;
-
- this.firstRunDone = true;
-
- let {addonVersion} = require("info");
- let prevVersion = Prefs.currentVersion;
- if (prevVersion != addonVersion)
- {
- Prefs.currentVersion = addonVersion;
- this.addSubscription(window, prevVersion);
-
- // The "Hide placeholders" option has been removed from the UI in 2.6.6.3881
- // So we reset the option for users updating from older versions.
- if (prevVersion && Services.vc.compare(prevVersion, "2.6.6.3881") < 0)
- Prefs.fastcollapse = false;
- }
- },
-
- /**
- * Will be set to true after the check whether first-run actions should run
- * has been performed.
- * @type Boolean
- */
- firstRunDone: false,
-
- /**
- * Initializes Adblock Plus UI in a window.
- */
- applyToWindow: function(/**Window*/ window, /**Boolean*/ noDelay)
- {
- let {delayInitialization, isKnownWindow, getBrowser, addBrowserLocationListener} = require("appSupport");
- if (window.document.documentElement.id == "CustomizeToolbarWindow" || isKnownWindow(window))
- {
- // Add style processing instruction
- let style = window.document.createProcessingInstruction("xml-stylesheet", 'class="adblockplus-node" href="chrome://adblockplus/skin/overlay.css" type="text/css"');
- window.document.insertBefore(style, window.document.firstChild);
- }
-
- if (!isKnownWindow(window))
- return;
-
- // Thunderbird windows will not be initialized at this point, execute
- // delayed
- if (!noDelay && delayInitialization)
- {
- Utils.runAsync(this.applyToWindow.bind(this, window, true));
- return;
- }
-
- // Add general items to the document
- for (let i = 0; i < this.overlay.all.length; i++)
- window.document.documentElement.appendChild(this.overlay.all[i].cloneNode(true));
-
- // Add status bar icon
- this.updateStatusbarIcon(window);
-
- // Add tools menu item
- if ("abp-menuitem" in this.overlay)
- {
- let {toolsMenu} = require("appSupport");
- let [parent, before] = this.resolveInsertionPoint(window, toolsMenu);
- if (parent)
- parent.insertBefore(this.overlay["abp-menuitem"].cloneNode(true), before);
- }
-
- // Attach event handlers
- for (let i = 0; i < eventHandlers.length; i++)
- {
- let [id, event, handler] = eventHandlers[i];
- let element = window.document.getElementById(id);
- if (element)
- element.addEventListener(event, handler.bind(null, window), false);
- }
- window.addEventListener("popupshowing", this.onPopupShowing, false);
- window.addEventListener("keypress", this.onKeyPress, false);
-
- addBrowserLocationListener(window, function()
- {
- this.updateIconState(window, window.document.getElementById("abp-status"));
- this.updateIconState(window, window.document.getElementById("abp-toolbarbutton"));
-
- Notification.showNext(this.getCurrentLocation(window).spec);
- }.bind(this));
-
- let notificationPanel = window.document.getElementById("abp-notification");
- notificationPanel.addEventListener("command", function(event)
- {
- switch (event.target.id)
- {
- case "abp-notification-close":
- notificationPanel.classList.add("abp-closing");
- break;
- case "abp-notification-optout":
- Notification.toggleIgnoreCategory("*", true);
- /* FALL THROUGH */
- case "abp-notification-hide":
- notificationPanel.hidePopup();
- break;
- }
- }, false);
-
- // First-run actions?
- this.firstRunActions(window);
-
- // Some people actually switch off browser.frames.enabled and are surprised
- // that things stop working...
- window.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebNavigation)
- .QueryInterface(Ci.nsIDocShell)
- .allowSubframes = true;
- },
-
- /**
- * Removes Adblock Plus UI from a window.
- */
- removeFromWindow: function(/**Window*/ window)
- {
- let {isKnownWindow, removeBrowserLocationListeners} = require("appSupport");
- if (window.document.documentElement.id == "CustomizeToolbarWindow" || isKnownWindow(window))
- {
- // Remove style processing instruction
- for (let child = window.document.firstChild; child; child = child.nextSibling)
- if (child.nodeType == child.PROCESSING_INSTRUCTION_NODE && child.data.indexOf("adblockplus-node") >= 0)
- child.parentNode.removeChild(child);
- }
-
- if (!isKnownWindow(window))
- return;
-
- for (let id in this.overlay)
- {
- if (id == "all")
- {
- let list = this.overlay[id];
- for (let i = 0; i < list.length; i++)
- {
- let clone = window.document.getElementById(list[i].getAttribute("id"));
- if (clone)
- clone.parentNode.removeChild(clone);
- }
- }
- else
- {
- let clone = window.document.getElementById(id);
- if (clone)
- clone.parentNode.removeChild(clone);
- }
- }
-
- window.removeEventListener("popupshowing", this.onPopupShowing, false);
- window.removeEventListener("keypress", this.onKeyPress, false);
- removeBrowserLocationListeners(window);
- },
-
- /**
- * The overlay information to be used when adding elements to the UI.
- * @type Object
- */
- overlay: null,
-
- /**
- * Iterator for application windows that Adblock Plus should apply to.
- * @type Iterator
- */
- get applicationWindows()
- {
- let {isKnownWindow} = require("appSupport");
-
- let enumerator = Services.wm.getZOrderDOMWindowEnumerator(null, true);
- if (!enumerator.hasMoreElements())
- {
- // On Linux the list returned will be empty, see bug 156333. Fall back to random order.
- enumerator = Services.wm.getEnumerator(null);
- }
-
- let generate = function*()
- {
- while (enumerator.hasMoreElements())
- {
- let window = enumerator.getNext().QueryInterface(Ci.nsIDOMWindow);
- if (isKnownWindow(window))
- yield window;
- }
- };
-
- return generate();
- },
-
- /**
- * Returns the top-most application window or null if none exists.
- * @type Window
- */
- get currentWindow()
- {
- for (let window of this.applicationWindows)
- return window;
- return null;
- },
-
- /**
- * Opens a URL in the browser window. If browser window isn't passed as parameter,
- * this function attempts to find a browser window. If an event is passed in
- * it should be passed in to the browser if possible (will e.g. open a tab in
- * background depending on modifiers keys).
- */
- loadInBrowser: function(/**String*/ url, /**Window*/ currentWindow, /**Event*/ event)
- {
- if (!currentWindow)
- currentWindow = this.currentWindow;
-
- let {addTab} = require("appSupport");
- if (currentWindow && addTab)
- addTab(currentWindow, url, event);
- else
- {
- let protocolService = Cc["@mozilla.org/uriloader/external-protocol-service;1"].getService(Ci.nsIExternalProtocolService);
- protocolService.loadURI(Services.io.newURI(url, null, null), null);
- }
- },
-
- /**
- * Opens a pre-defined documentation link in the browser window. This will
- * send the UI language to adblockplus.org so that the correct language
- * version of the page can be selected.
- */
- loadDocLink: function(/**String*/ linkID, /**Window*/ window)
- {
- let link = Utils.getDocLink(linkID);
- this.loadInBrowser(link, window);
- },
-
-
- /**
- * Brings up the filter composer dialog to block an item. The optional nodesID
- * parameter must be a unique ID returned by
- * RequestNotifier.storeNodesForEntry() or similar.
- */
- blockItem: function(/**Window*/ window, /**string*/ nodesID, /**RequestEntry*/ item)
- {
- if (!item)
- return;
-
- window.openDialog("chrome://adblockplus/content/ui/composer.xul", "_blank",
- "chrome,centerscreen,resizable,dialog=no,dependent", nodesID, item);
- },
-
- /**
- * Opens filter preferences dialog or focuses an already open dialog.
- * @param {Filter} [filter] filter to be selected
- */
- openFiltersDialog: function(filter)
- {
- let existing = Services.wm.getMostRecentWindow("abp:filters");
- if (existing)
- {
- try
- {
- existing.focus();
- } catch (e) {}
- if (filter)
- existing.SubscriptionActions.selectFilter(filter);
- }
- else
- {
- Services.ww.openWindow(null, "chrome://adblockplus/content/ui/filters.xul", "_blank", "chrome,centerscreen,resizable,dialog=no", {wrappedJSObject: filter});
- }
- },
-
- /**
- * Opens report wizard for the current page.
- */
- openReportDialog: function(/**Window*/ window)
- {
- let wnd = Services.wm.getMostRecentWindow("abp:sendReport");
- if (wnd)
- wnd.focus();
- else
- {
- let uri = this.getCurrentLocation(window);
- if (uri)
- {
- let {getBrowser} = require("appSupport");
- let browser = getBrowser(window);
- if ("selectedBrowser" in browser)
- browser = browser.selectedBrowser;
- window.openDialog("chrome://adblockplus/content/ui/sendReport.xul", "_blank", "chrome,centerscreen,resizable=no", browser.outerWindowID, uri, browser);
- }
- }
- },
-
- /**
- * Opens our contribution page.
- */
- openContributePage: function(/**Window*/ window)
- {
- this.loadDocLink("contribute", window);
- },
-
- /**
- * Executed on first run, adds a filter subscription and notifies that user
- * about that.
- */
- addSubscription: function(/**Window*/ window, /**String*/ prevVersion)
- {
- // Add "acceptable ads" subscription for new users and user updating from old ABP versions.
- // Don't add it for users of privacy subscriptions (use a hardcoded list for now).
- let addAcceptable = (Services.vc.compare(prevVersion, "2.0") < 0);
- let privacySubscriptions = {
- "https://easylist-downloads.adblockplus.org/easyprivacy+easylist.txt": true,
- "https://easylist-downloads.adblockplus.org/easyprivacy.txt": true,
- "https://secure.fanboy.co.nz/fanboy-tracking.txt": true,
- "https://fanboy-adblock-list.googlecode.com/hg/fanboy-adblocklist-stats.txt": true,
- "https://bitbucket.org/fanboy/fanboyadblock/raw/tip/fanboy-adblocklist-stats.txt": true,
- "https://hg01.codeplex.com/fanboyadblock/raw-file/tip/fanboy-adblocklist-stats.txt": true,
- "https://adversity.googlecode.com/hg/Adversity-Tracking.txt": true
- };
- if (FilterStorage.subscriptions.some((subscription) => subscription.url == Prefs.subscriptions_exceptionsurl || subscription.url in privacySubscriptions))
- addAcceptable = false;
-
- // Don't add subscription if the user has a subscription already
- let addSubscription = true;
- //if (FilterStorage.subscriptions.some((subscription) => subscription instanceof DownloadableSubscription && subscription.url != Prefs.subscriptions_exceptionsurl))
- addSubscription = false;
-
- // If this isn't the first run, only add subscription if the user has no custom filters
- if (addSubscription && Services.vc.compare(prevVersion, "0.0") > 0)
- {
- if (FilterStorage.subscriptions.some((subscription) => subscription.url != Prefs.subscriptions_exceptionsurl && subscription.filters.length))
- addSubscription = false;
- }
-
- // Add "acceptable ads" subscription
- if (false)
- {
- let subscription = Subscription.fromURL(Prefs.subscriptions_exceptionsurl);
- if (subscription)
- {
- subscription.title = "Allow non-intrusive advertising";
- FilterStorage.addSubscription(subscription);
- if (subscription instanceof DownloadableSubscription && !subscription.lastDownload)
- Synchronizer.execute(subscription);
- }
- else
- addAcceptable = false;
- }
-
- /* Add "anti-adblock messages" subscription for new users and users updating from old ABP versions
- if (Services.vc.compare(prevVersion, "2.5") < 0)
- {
- let subscription = Subscription.fromURL(Prefs.subscriptions_antiadblockurl);
- if (subscription && !(subscription.url in FilterStorage.knownSubscriptions))
- {
- subscription.disabled = true;
- FilterStorage.addSubscription(subscription);
- if (subscription instanceof DownloadableSubscription && !subscription.lastDownload)
- Synchronizer.execute(subscription);
- }
- }*/
-
- // Extra subsriptions
- let subscription = Subscription.fromURL("http://gnuzilla.gnu.org/filters/blacklist.txt");
- subscription.disabled = false;
- FilterStorage.addSubscription(subscription);
- Synchronizer.execute(subscription);
-
- subscription = Subscription.fromURL("http://gnuzilla.gnu.org/filters/third-party.txt");
- subscription.disabled = false;
- FilterStorage.addSubscription(subscription);
- Synchronizer.execute(subscription);
-
- if (!addSubscription && !addAcceptable)
- return;
-
- function notifyUser()
- {return;
-
- let {addTab} = require("appSupport");
- if (addTab)
- {
- addTab(window, "chrome://adblockplus/content/ui/firstRun.html");
- }
- else
- {
- let dialogSource = '\
- <?xml-stylesheet href="chrome://global/skin/" type="text/css"?>\
- <dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" onload="document.title=content.document.title" buttons="accept" width="500" height="600">\
- <iframe type="content-primary" flex="1" src="chrome://adblockplus/content/ui/firstRun.html"/>\
- </dialog>';
- Services.ww.openWindow(window,
- "data:application/vnd.mozilla.xul+xml," + encodeURIComponent(dialogSource),
- "_blank", "chrome,centerscreen,resizable,dialog=no", null);
- }
- }
-
- if (addSubscription)
- {
- // Load subscriptions data
- let request = new XMLHttpRequest();
- request.mozBackgroundRequest = true;
- request.open("GET", "chrome://adblockplus/content/ui/subscriptions.xml");
- request.addEventListener("load", function()
- {
- if (onShutdown.done)
- return;
-
- let node = Utils.chooseFilterSubscription(request.responseXML.getElementsByTagName("subscription"));
- let subscription = (node ? Subscription.fromURL(node.getAttribute("url")) : null);
- if (subscription)
- {
- FilterStorage.addSubscription(subscription);
- subscription.disabled = false;
- subscription.title = node.getAttribute("title");
- subscription.homepage = node.getAttribute("homepage");
- if (subscription instanceof DownloadableSubscription && !subscription.lastDownload)
- Synchronizer.execute(subscription);
-
- notifyUser();
- }
- }, false);
- request.send();
- }
- else
- notifyUser();
- },
-
- /**
- * Called whenever child/subscribeLinks module intercepts clicks on abp: links
- * as well as links to subscribe.adblockplus.org.
- */
- subscribeLinkClicked: function({title, url,
- mainSubscriptionTitle, mainSubscriptionURL})
- {
- if (!url)
- return;
-
- // Default title to the URL
- if (!title)
- title = url;
-
- // Main subscription needs both title and URL
- if (mainSubscriptionTitle && !mainSubscriptionURL)
- mainSubscriptionTitle = null;
- if (mainSubscriptionURL && !mainSubscriptionTitle)
- mainSubscriptionURL = null;
-
- // Trim spaces in title and URL
- title = title.trim();
- url = url.trim();
- if (mainSubscriptionURL)
- {
- mainSubscriptionTitle = mainSubscriptionTitle.trim();
- mainSubscriptionURL = mainSubscriptionURL.trim();
- }
-
- // Verify that the URL is valid
- url = Utils.makeURI(url);
- if (!url || (url.scheme != "http" && url.scheme != "https" && url.scheme != "ftp"))
- return;
- url = url.spec;
-
- if (mainSubscriptionURL)
- {
- mainSubscriptionURL = Utils.makeURI(mainSubscriptionURL);
- if (!mainSubscriptionURL || (mainSubscriptionURL.scheme != "http" && mainSubscriptionURL.scheme != "https" && mainSubscriptionURL.scheme != "ftp"))
- mainSubscriptionURL = mainSubscriptionTitle = null;
- else
- mainSubscriptionURL = mainSubscriptionURL.spec;
- }
-
- this.openSubscriptionDialog(this.currentWindow, url, title, mainSubscriptionURL, mainSubscriptionTitle);
- },
-
- /**
- * Opens a dialog letting the user confirm/adjust a filter subscription to
- * be added.
- */
- openSubscriptionDialog: function(/**Window*/ window, /**String*/ url, /**String*/ title, /**String*/ mainURL, /**String*/ mainTitle)
- {
- let subscription = {url: url, title: title, disabled: false, external: false,
- mainSubscriptionTitle: mainTitle, mainSubscriptionURL: mainURL};
- window.openDialog("chrome://adblockplus/content/ui/subscriptionSelection.xul", "_blank",
- "chrome,centerscreen,resizable,dialog=no", subscription, null);
- },
-
- /**
- * Retrieves the current location of the browser.
- */
- getCurrentLocation: function(/**Window*/ window) /**nsIURI*/
- {
- let {getCurrentLocation} = require("appSupport");
- let result = getCurrentLocation(window);
- return (result ? Utils.unwrapURL(result) : null);
- },
-
- /**
- * Looks up an element with given ID in the window. If a list of IDs is given
- * will try all of them until an element exists.
- */
- findElement: function(/**Window*/ window, /**String|String[]*/ id) /**Element*/
- {
- if (id instanceof Array)
- {
- for (let candidate of id)
- {
- let result = window.document.getElementById(candidate);
- if (result)
- return result;
- }
- return null;
- }
- else
- return window.document.getElementById(id);
- },
-
- /**
- * Resolves an insertion point as specified in appSupport module. Returns
- * two elements: the parent element and the element to insert before.
- */
- resolveInsertionPoint: function(/**Window*/ window, /**Object*/ insertionPoint) /**Element[]*/
- {
- let parent = null;
- let before = null;
- if (insertionPoint)
- {
- if ("parent" in insertionPoint)
- parent = this.findElement(window, insertionPoint.parent);
-
- if (parent && "before" in insertionPoint)
- before = this.findElement(window, insertionPoint.before);
-
- if (parent && !before && "after" in insertionPoint)
- {
- let after = this.findElement(window, insertionPoint.after);
- if (after)
- before = after.nextElementSibling;
- }
-
- if (before && before.parentNode != parent)
- before = null;
- }
-
- return [parent, before];
- },
-
- /**
- * Toggles visibility state of the toolbar icon.
- */
- toggleToolbarIcon: function()
- {
- if (!CustomizableUI)
- return;
- if (this.isToolbarIconVisible())
- CustomizableUI.removeWidgetFromArea("abp-toolbarbutton");
- else
- {
- let {defaultToolbarPosition} = require("appSupport");
- CustomizableUI.addWidgetToArea("abp-toolbarbutton", defaultToolbarPosition.parent);
- }
- },
-
- /**
- * Updates Adblock Plus icon state for all windows.
- */
- updateState: function()
- {
- for (let window of this.applicationWindows)
- {
- this.updateIconState(window, window.document.getElementById("abp-status"));
- this.updateIconState(window, window.document.getElementById("abp-toolbarbutton"));
- }
- },
-
- /**
- * Updates Adblock Plus icon state for a single application window.
- */
- updateIconState: function(/**Window*/ window, /**Element*/ icon)
- {
- if (!icon)
- return;
-
- let state = (Prefs.enabled ? "active" : "disabled");
- if (state == "active")
- {
- let location = this.getCurrentLocation(window);
- if (location && Policy.isWhitelisted(location.spec))
- state = "whitelisted";
- }
-
- let popupId = "abp-status-popup";
- if (icon.localName == "statusbarpanel")
- {
- if (Prefs.defaultstatusbaraction == 0)
- {
- icon.setAttribute("popup", popupId);
- icon.removeAttribute("context");
- }
- else
- {
- icon.removeAttribute("popup");
- icon.setAttribute("context", popupId);
- }
- }
- else
- {
- if (Prefs.defaulttoolbaraction == 0)
- {
- icon.setAttribute("type", "menu");
- icon.removeAttribute("context");
- }
- else
- {
- icon.setAttribute("type", "menu-button");
- icon.setAttribute("context", popupId);
- }
- }
-
- icon.setAttribute("abpstate", state);
- },
-
- /**
- * Shows or hides status bar icons in all windows, according to pref.
- */
- updateStatusbarIcon: function(/**Window*/ window)
- {
- if (!("abp-status" in this.overlay))
- return;
-
- let {statusbarPosition} = require("appSupport");
- if (!statusbarPosition)
- return;
-
- let icon = window.document.getElementById("abp-status");
- if (Prefs.showinstatusbar && !icon)
- {
- let [parent, before] = this.resolveInsertionPoint(window, statusbarPosition);
- if (!parent)
- return;
-
- parent.insertBefore(this.overlay["abp-status"].cloneNode(true), before);
-
- icon = window.document.getElementById("abp-status");
- this.updateIconState(window, icon);
- icon.addEventListener("click", this.onIconClick, false);
- }
- else if (!Prefs.showinstatusbar && icon)
- icon.parentNode.removeChild(icon);
- },
-
- /**
- * Toggles the value of a boolean preference.
- */
- togglePref: function(/**String*/ pref)
- {
- Prefs[pref] = !Prefs[pref];
- },
-
- /**
- * If the given filter is already in user's list, removes it from the list. Otherwise adds it.
- */
- toggleFilter: function(/**Filter*/ filter)
- {
- if (filter.subscriptions.length)
- {
- if (filter.disabled || filter.subscriptions.some((subscription) => !(subscription instanceof SpecialSubscription)))
- filter.disabled = !filter.disabled;
- else
- FilterStorage.removeFilter(filter);
- }
- else
- {
- filter.disabled = false;
- FilterStorage.addFilter(filter);
- }
- },
-
-
- /**
- * Toggles "Count filter hits" option.
- */
- toggleSaveStats: function(window)
- {
- if (Prefs.savestats)
- {
- if (!Utils.confirm(window, Utils.getString("clearStats_warning")))
- return;
-
- FilterStorage.resetHitCounts();
- Prefs.savestats = false;
- }
- else
- Prefs.savestats = true;
- },
-
- /**
- * Sets the current filter subscription in a single-subscription scenario,
- * all other subscriptions will be removed.
- */
- setSubscription: function(url, title)
- {
- let subscription = Subscription.fromURL(url);
- let currentSubscriptions = FilterStorage.subscriptions.filter(
- ((subscription) => subscription instanceof DownloadableSubscription && subscription.url != Prefs.subscriptions_exceptionsurl)
- );
- if (!subscription || currentSubscriptions.indexOf(subscription) >= 0)
- return;
-
- for (let i = 0; i < currentSubscriptions.length; i++)
- FilterStorage.removeSubscription(currentSubscriptions[i]);
-
- subscription.title = title;
- FilterStorage.addSubscription(subscription);
- if (subscription instanceof DownloadableSubscription && !subscription.lastDownload)
- Synchronizer.execute(subscription);
- },
-
- /**
- * Adds or removes "non-intrisive ads" filter list.
- * @return {Boolean} true if the filter list has been added
- **/
- toggleAcceptableAds: function()
- {
- let subscription = Subscription.fromURL(Prefs.subscriptions_exceptionsurl);
- if (!subscription)
- return false;
-
- subscription.disabled = false;
- subscription.title = "Allow non-intrusive advertising";
- if (subscription.url in FilterStorage.knownSubscriptions)
- FilterStorage.removeSubscription(subscription);
- else
- {
- FilterStorage.addSubscription(subscription);
- if (subscription instanceof DownloadableSubscription && !subscription.lastDownload)
- Synchronizer.execute(subscription);
- }
-
- return (subscription.url in FilterStorage.knownSubscriptions);
- },
-
- /**
- * Toggles the pref for the Adblock Plus sync engine.
- * @return {Boolean} new state of the sync engine
- */
- toggleSync: function()
- {
- let {Sync} = require("sync");
- let syncEngine = Sync.getEngine();
- if (syncEngine)
- {
- syncEngine.enabled = !syncEngine.enabled;
- return syncEngine.enabled;
- }
- else
- return false;
- },
-
- /**
- * Tests whether blockable items list is currently open.
- */
- isBottombarOpen: function(/**Window*/ window) /**Boolean*/
- {
- if (detachedBottombar && !detachedBottombar.closed)
- return true;
-
- return !!window.document.getElementById("abp-bottombar");
- },
-
- /**
- * Called when some pop-up in the application window shows up, initializes
- * pop-ups related to Adblock Plus.
- */
- onPopupShowing: function(/**Event*/ event)
- {
- if (event.defaultPrevented)
- return;
-
- let popup = event.originalTarget;
-
- let {contentContextMenu} = require("appSupport");
- if ((typeof contentContextMenu == "string" && popup.id == contentContextMenu) ||
- (contentContextMenu instanceof Array && contentContextMenu.indexOf(popup.id) >= 0))
- {
- this.fillContentContextMenu(popup);
- }
- else if (popup.id == "abp-tooltip")
- this.fillIconTooltip(event, popup.ownerDocument.defaultView);
- else
- {
- let match = /^(abp-(?:toolbar|status|menuitem)-)popup$/.exec(popup.id);
- if (match)
- this.fillIconMenu(event, popup.ownerDocument.defaultView, match[1]);
- }
- },
-
- /**
- * Handles click on toolbar and status bar icons.
- */
- onIconClick: function(/**Event*/ event)
- {
- if (event.eventPhase != event.AT_TARGET)
- return;
-
- let isToolbar = (event.target.localName != "statusbarpanel");
- let action = 0;
- if ((isToolbar && event.type == "command") || (!isToolbar && event.button == 0))
- action = (isToolbar ? Prefs.defaulttoolbaraction : Prefs.defaultstatusbaraction);
- else if (event.button == 1)
- action = 3;
-
- let window = event.target.ownerDocument.defaultView;
- if (action == 1)
- this.toggleBottombar(window);
- else if (action == 2)
- this.openFiltersDialog();
- else if (action == 3)
- {
- // If there is a whitelisting rule for current page - remove it (reenable).
- // Otherwise flip "enabled" pref.
- if (!this.removeWhitelist(window))
- this.togglePref("enabled");
- }
- },
-
- /**
- * Removes/disables the exception rule applying for the current page.
- */
- removeWhitelist: function(/**Window*/ window)
- {
- let location = this.getCurrentLocation(window);
- let filter = null;
- if (location)
- filter = Policy.isWhitelisted(location.spec);
- if (filter && filter.subscriptions.length && !filter.disabled)
- {
- UI.toggleFilter(filter);
- return true;
- }
- return false;
- },
-
- /**
- * Updates state of the icon tooltip.
- */
- fillIconTooltip: function(/**Event*/ event, /**Window*/ window)
- {
- let E = (id) => window.document.getElementById(id);
-
- let node = window.document.tooltipNode;
- if (!node || !node.hasAttribute("tooltip"))
- {
- event.preventDefault();
- return;
- }
-
- // Prevent tooltip from overlapping menu
- for (let id of ["abp-toolbar-popup", "abp-status-popup"])
- {
- let element = E(id);
- if (element && element.state == "open")
- {
- event.preventDefault();
- return;
- }
- }
-
- let type = (node.id == "abp-toolbarbutton" ? "toolbar" : "statusbar");
- let action = parseInt(Prefs["default" + type + "action"]);
- if (isNaN(action))
- action = -1;
-
- let actionDescr = E("abp-tooltip-action");
- actionDescr.hidden = (action < 0 || action > 3);
- if (!actionDescr.hidden)
- actionDescr.setAttribute("value", Utils.getString("action" + action + "_tooltip"));
-
- let statusDescr = E("abp-tooltip-status");
- let state = node.getAttribute("abpstate");
- let statusStr = Utils.getString(state + "_tooltip");
- if (state == "active")
- {
- let [activeSubscriptions, activeFilters] = FilterStorage.subscriptions.reduce(function([subscriptions, filters], current)
- {
- if (current instanceof SpecialSubscription)
- return [subscriptions, filters + current.filters.filter((filter) => !filter.disabled).length];
- else if (!current.disabled && !(Prefs.subscriptions_exceptionscheckbox && current.url == Prefs.subscriptions_exceptionsurl))
- return [subscriptions + 1, filters];
- else
- return [subscriptions, filters]
- }, [0, 0]);
-
- statusStr = statusStr.replace(/\?1\?/, activeSubscriptions).replace(/\?2\?/, activeFilters);
- }
- statusDescr.setAttribute("value", statusStr);
-
- E("abp-tooltip-blocked-label").hidden = true;
- E("abp-tooltip-blocked").hidden = true;
- E("abp-tooltip-filters-label").hidden = true;
- E("abp-tooltip-filters").hidden = true;
- E("abp-tooltip-more-filters").hidden = true;
-
- if (state == "active")
- {
- let {getBrowser} = require("appSupport");
- let browser = getBrowser(window);
- if ("selectedBrowser" in browser)
- browser = browser.selectedBrowser;
- let outerWindowID = browser.outerWindowID;
- RequestNotifier.getWindowStatistics(outerWindowID, (stats) =>
- {
- E("abp-tooltip-blocked-label").hidden = false;
- E("abp-tooltip-blocked").hidden = false;
-
- let blockedStr = Utils.getString("blocked_count_tooltip");
- blockedStr = blockedStr.replace(/\?1\?/, stats ? stats.blocked : 0).replace(/\?2\?/, stats ? stats.items : 0);
-
- if (stats && stats.whitelisted + stats.hidden)
- {
- blockedStr += " " + Utils.getString("blocked_count_addendum");
- blockedStr = blockedStr.replace(/\?1\?/, stats.whitelisted).replace(/\?2\?/, stats.hidden);
- }
-
- E("abp-tooltip-blocked").setAttribute("value", blockedStr);
-
- let activeFilters = [];
- if (stats)
- {
- let filterSort = function(a, b)
- {
- return stats.filters[b] - stats.filters[a];
- };
- for (let filter in stats.filters)
- activeFilters.push(filter);
- activeFilters = activeFilters.sort(filterSort);
- }
-
- if (activeFilters.length > 0)
- {
- let filtersContainer = E("abp-tooltip-filters");
- while (filtersContainer.firstChild)
- filtersContainer.removeChild(filtersContainer.firstChild);
-
- for (let i = 0; i < activeFilters.length && i < 3; i++)
- {
- let descr = filtersContainer.ownerDocument.createElement("description");
- descr.setAttribute("value", activeFilters[i] + " (" + stats.filters[activeFilters[i]] + ")");
- filtersContainer.appendChild(descr);
- }
- }
-
- E("abp-tooltip-filters-label").hidden = (activeFilters.length == 0);
- E("abp-tooltip-filters").hidden = (activeFilters.length == 0);
- E("abp-tooltip-more-filters").hidden = (activeFilters.length <= 3);
- });
- }
- },
-
- /**
- * Updates state of the icon context menu.
- */
- fillIconMenu: function(/**Event*/ event, /**Window*/ window, /**String*/ prefix)
- {
- function hideElement(id, hide)
- {
- let element = window.document.getElementById(id);
- if (element)
- element.hidden = hide;
- }
- function setChecked(id, checked)
- {
- let element = window.document.getElementById(id);
- if (element)
- element.setAttribute("checked", checked);
- }
- function setDisabled(id, disabled)
- {
- let element = window.document.getElementById(id);
- if (element)
- element.setAttribute("disabled", disabled);
- }
- function setDefault(id, isDefault)
- {
- let element = window.document.getElementById(id);
- if (element)
- element.setAttribute("default", isDefault);
- }
- function generateLabel(id, param)
- {
- let element = window.document.getElementById(id);
- if (element)
- element.setAttribute("label", element.getAttribute("labeltempl").replace(/\?1\?/, param));
- }
-
- let bottombarOpen = this.isBottombarOpen(window);
- hideElement(prefix + "openbottombar", bottombarOpen);
- hideElement(prefix + "closebottombar", !bottombarOpen);
-
- hideElement(prefix + "whitelistsite", true);
- hideElement(prefix + "whitelistpage", true);
-
- let location = this.getCurrentLocation(window);
- if (location && Policy.isBlockableScheme(location))
- {
- let host = null;
- try
- {
- host = location.host.replace(/^www\./, "");
- } catch (e) {}
-
- if (host)
- {
- let ending = "|";
- location = location.clone();
- if (location instanceof Ci.nsIURL)
- location.ref = "";
- if (location instanceof Ci.nsIURL && location.query)
- {
- location.query = "";
- ending = "?";
- }
-
- siteWhitelist = Filter.fromText("@@||" + host + "^$document");
- setChecked(prefix + "whitelistsite", siteWhitelist.subscriptions.length && !siteWhitelist.disabled);
- generateLabel(prefix + "whitelistsite", host);
- hideElement(prefix + "whitelistsite", false);
-
- pageWhitelist = Filter.fromText("@@|" + location.spec + ending + "$document");
- setChecked(prefix + "whitelistpage", pageWhitelist.subscriptions.length && !pageWhitelist.disabled);
- hideElement(prefix + "whitelistpage", false);
- }
- else
- {
- siteWhitelist = Filter.fromText("@@|" + location.spec + "|");
- setChecked(prefix + "whitelistsite", siteWhitelist.subscriptions.length && !siteWhitelist.disabled);
- generateLabel(prefix + "whitelistsite", location.spec.replace(/^mailto:/, ""));
- hideElement(prefix + "whitelistsite", false);
- }
- }
-
- setDisabled("abp-command-sendReport", !location || !Policy.isBlockableScheme(location) || location.scheme == "mailto");
-
- setChecked(prefix + "disabled", !Prefs.enabled);
- setChecked(prefix + "frameobjects", Prefs.frameobjects);
- setChecked(prefix + "savestats", Prefs.savestats);
-
- let {defaultToolbarPosition, statusbarPosition} = require("appSupport");
- let hasToolbar = defaultToolbarPosition;
- let hasStatusBar = statusbarPosition;
- hideElement(prefix + "showintoolbar", !hasToolbar || prefix == "abp-toolbar-");
- hideElement(prefix + "showinstatusbar", !hasStatusBar);
- hideElement(prefix + "shownotifications", !Prefs.notifications_showui);
- hideElement(prefix + "iconSettingsSeparator", (prefix == "abp-toolbar-" || !hasToolbar) && !hasStatusBar);
-
- setChecked(prefix + "showintoolbar", this.isToolbarIconVisible());
- setChecked(prefix + "showinstatusbar", Prefs.showinstatusbar);
- setChecked(prefix + "shownotifications", Prefs.notifications_ignoredcategories.indexOf("*") == -1);
-
- let {Sync} = require("sync");
- let syncEngine = Sync.getEngine();
- hideElement(prefix + "sync", !syncEngine);
- setChecked(prefix + "sync", syncEngine && syncEngine.enabled);
-
- let defAction = (!window.document.popupNode || window.document.popupNode.id == "abp-toolbarbutton" ?
- Prefs.defaulttoolbaraction :
- Prefs.defaultstatusbaraction);
- setDefault(prefix + "openbottombar", defAction == 1);
- setDefault(prefix + "closebottombar", defAction == 1);
- setDefault(prefix + "filters", defAction == 2);
- setDefault(prefix + "disabled", defAction == 3);
-
- let popup = window.document.getElementById(prefix + "popup");
- let items = (popup ? popup.querySelectorAll('menuitem[key]') : []);
- for (let i = 0; i < items.length; i++)
- {
- let item = items[i];
- let match = /^abp-key-/.exec(item.getAttribute("key"));
- if (!match)
- continue;
-
- let name = match.input.substr(match.index + match[0].length);
- if (!this.hotkeys)
- this.configureKeys(window);
- if (name in this.hotkeys)
- {
- let text = KeySelector.getTextForKey(this.hotkeys[name]);
- if (text)
- item.setAttribute("acceltext", text);
- else
- item.removeAttribute("acceltext");
- }
- }
-
- hideElement(prefix + "contributebutton", Prefs.hideContributeButton);
- },
-
- /**
- * Adds Adblock Plus menu items to the content area context menu when it shows
- * up.
- */
- fillContentContextMenu: function(/**Element*/ popup)
- {
- let window = popup.ownerDocument.defaultView;
- let data = window.gContextMenuContentData;
- if (!data)
- {
- // This is SeaMonkey Mail or Thunderbird, they won't get context menu data
- // for us. Send the notification ourselves.
- data = {
- event: {target: popup.triggerNode},
- addonInfo: {},
- get wrappedJSObject() {return this;}
- };
- Services.obs.notifyObservers(data, "AdblockPlus:content-contextmenu", null);
- }
-
- if (typeof data.addonInfo != "object" || typeof data.addonInfo.adblockplus != "object")
- return;
-
- let items = data.addonInfo.adblockplus;
- let clicked = null;
- let menuItems = [];
-
- function menuItemTriggered(id, nodeData)
- {
- clicked = id;
- this.blockItem(window, id, nodeData);
- }
-
- for (let [id, nodeData] of items)
- {
- let type = nodeData.type.toLowerCase();
- let label = this.overlay.attributes[type + "contextlabel"];
- if (!label)
- return;
-
- let item = popup.ownerDocument.createElement("menuitem");
- item.setAttribute("label", label);
- item.setAttribute("class", "abp-contextmenuitem");
- item.addEventListener("command", menuItemTriggered.bind(this, id, nodeData), false);
- popup.appendChild(item);
-
- menuItems.push(item);
- }
-
- // Add "Remove exception" menu item if necessary
- let location = this.getCurrentLocation(window);
- let filter = (location ? Policy.isWhitelisted(location.spec) : null);
- if (filter && filter.subscriptions.length && !filter.disabled)
- {
- let label = this.overlay.attributes.whitelistcontextlabel;
- if (!label)
- return;
-
- let item = popup.ownerDocument.createElement("menuitem");
- item.setAttribute("label", label);
- item.setAttribute("class", "abp-contextmenuitem");
- item.addEventListener("command", this.toggleFilter.bind(this, filter), false);
- popup.appendChild(item);
-
- menuItems.push(item);
- }
-
- // Make sure to clean up everything once the context menu is closed
- let cleanUp = function(event)
- {
- if (event.eventPhase != event.AT_TARGET)
- return;
-
- popup.removeEventListener("popuphidden", cleanUp, false);
- for (let menuItem of menuItems)
- if (menuItem.parentNode)
- menuItem.parentNode.removeChild(menuItem);
-
- for (let [id, nodeData] of items)
- if (id && id != clicked)
- Policy.deleteNodes(id);
- }.bind(this);
- popup.addEventListener("popuphidden", cleanUp, false);
- },
-
- /**
- * Called when the user presses a key in the application window, reacts to our
- * shortcut keys.
- */
- onKeyPress: function(/**Event*/ event)
- {
- if (!this.hotkeys)
- this.configureKeys(event.currentTarget);
-
- for (let key in this.hotkeys)
- {
- if (KeySelector.matchesKey(event, this.hotkeys[key]))
- {
- event.preventDefault();
- let command = event.currentTarget.document.getElementById("abp-command-" + key);
- if (command)
- command.doCommand();
- }
- }
- },
-
- /**
- * Checks whether the toolbar icon is currently displayed.
- */
- isToolbarIconVisible: function() /**Boolean*/
- {
- if (!CustomizableUI)
- return false;
- let placement = CustomizableUI.getPlacementOfWidget("abp-toolbarbutton");
- return !!placement;
- },
-
- /**
- * Stores the selected hotkeys, initialized when the user presses a key.
- */
- hotkeys: null,
-
- /**
- * Chooses shortcut keys that are available in the window according to
- * preferences.
- */
- configureKeys: function(/**Window*/ window)
- {
- let selector = new KeySelector(window);
-
- this.hotkeys = {};
- for (let name in Prefs)
- {
- let match = /_key$/.exec(name);
- if (match && typeof Prefs[name] == "string")
- {
- let keyName = match.input.substr(0, match.index);
- this.hotkeys[keyName] = selector.selectKey(Prefs[name]);
- }
- }
- },
-
- /**
- * Toggles open/closed state of the blockable items list.
- */
- toggleBottombar: function(/**Window*/ window)
- {
- if (detachedBottombar && !detachedBottombar.closed)
- {
- detachedBottombar.close();
- detachedBottombar = null;
- }
- else
- {
- let {addBottomBar, removeBottomBar, getBrowser} = require("appSupport");
- let mustDetach = !addBottomBar || !removeBottomBar || !("abp-bottombar-container" in this.overlay);
- let detach = mustDetach || Prefs.detachsidebar;
- if (!detach && window.document.getElementById("abp-bottombar"))
- {
- removeBottomBar(window);
-
- let browser = (getBrowser ? getBrowser(window) : null);
- if (browser && "selectedBrowser" in browser)
- browser = browser.selectedBrowser;
- if (browser)
- browser.focus();
- }
- else if (!detach)
- {
- addBottomBar(window, this.overlay["abp-bottombar-container"]);
- let element = window.document.getElementById("abp-bottombar");
- if (element)
- {
- element.setAttribute("width", Prefs.blockableItemsSize.width);
- element.setAttribute("height", Prefs.blockableItemsSize.height);
-
- let splitter = window.document.getElementById("abp-bottombar-splitter");
- if (splitter)
- {
- splitter.addEventListener("command", function()
- {
- Prefs.blockableItemsSize = {width: element.width, height: element.height};
- }, false);
- }
- }
- }
- else
- detachedBottombar = window.openDialog("chrome://adblockplus/content/ui/sidebarDetached.xul", "_blank", "chrome,resizable,dependent,dialog=no", mustDetach);
- }
- },
-
- /**
- * Hide contribute button and persist this choice.
- */
- hideContributeButton: function(/**Window*/ window)
- {
- Prefs.hideContributeButton = true;
-
- for (let id of ["abp-status-contributebutton", "abp-toolbar-contributebutton", "abp-menuitem-contributebutton"])
- {
- let button = window.document.getElementById(id);
- if (button)
- button.hidden = true;
- }
- },
-
- _showNotification: function(window, button, notification)
- {
- let panel = window.document.getElementById("abp-notification");
- if (panel.state !== "closed")
- return;
-
- function insertMessage(element, text, links)
- {
- let match = /^(.*?)<(a|strong)>(.*?)<\/\2>(.*)$/.exec(text);
- if (!match)
- {
- element.appendChild(window.document.createTextNode(text));
- return;
- }
-
- let [_, before, tagName, value, after] = match;
-
- insertMessage(element, before, links);
-
- let newElement = window.document.createElementNS("http://www.w3.org/1999/xhtml", tagName);
- if (tagName === "a" && links && links.length)
- newElement.setAttribute("href", links.shift());
- insertMessage(newElement, value, links);
- element.appendChild(newElement);
-
- insertMessage(element, after, links);
- }
-
- let texts = Notification.getLocalizedTexts(notification);
- let titleElement = window.document.getElementById("abp-notification-title");
- titleElement.textContent = texts.title;
- let messageElement = window.document.getElementById("abp-notification-message");
- messageElement.innerHTML = "";
- let docLinks = [];
- if (notification.links)
- for (let link of notification.links)
- docLinks.push(Utils.getDocLink(link));
-
- insertMessage(messageElement, texts.message, docLinks);
-
- messageElement.addEventListener("click", function(event)
- {
- let link = event.target;
- while (link && link !== messageElement && link.localName !== "a")
- link = link.parentNode;
- if (!link || link.localName !== "a")
- return;
- event.preventDefault();
- event.stopPropagation();
- this.loadInBrowser(link.href, window);
- }.bind(this));
-
- if (notification.type === "question")
- {
- function buttonHandler(approved, event)
- {
- event.preventDefault();
- event.stopPropagation();
- panel.hidePopup();
- Notification.triggerQuestionListeners(notification.id, approved)
- Notification.markAsShown(notification.id);
- }
- window.document.getElementById("abp-notification-yes").onclick = buttonHandler.bind(null, true);
- window.document.getElementById("abp-notification-no").onclick = buttonHandler.bind(null, false);
- }
- else
- Notification.markAsShown(notification.id);
-
- panel.setAttribute("class", "abp-" + notification.type);
- panel.setAttribute("noautohide", true);
- panel.openPopup(button, "bottomcenter topcenter", 0, 0, false, false, null);
- }
-};
-UI.onPopupShowing = UI.onPopupShowing.bind(UI);
-UI.onKeyPress = UI.onKeyPress.bind(UI);
-UI.onIconClick = UI.onIconClick.bind(UI);
-UI.init();
-
-/**
- * List of event handers to be registered for each window. For each event
- * handler the element ID, event and the actual event handler are listed.
- * @type Array
- */
-let eventHandlers = [
- ["abp-command-sendReport", "command", UI.openReportDialog.bind(UI)],
- ["abp-command-filters", "command", UI.openFiltersDialog.bind(UI)],
- ["abp-command-sidebar", "command", UI.toggleBottombar.bind(UI)],
- ["abp-command-togglesitewhitelist", "command", function() { UI.toggleFilter(siteWhitelist); }],
- ["abp-command-togglepagewhitelist", "command", function() { UI.toggleFilter(pageWhitelist); }],
- ["abp-command-toggleobjtabs", "command", UI.togglePref.bind(UI, "frameobjects")],
- ["abp-command-togglesavestats", "command", UI.toggleSaveStats.bind(UI)],
- ["abp-command-togglesync", "command", UI.toggleSync.bind(UI)],
- ["abp-command-toggleshowintoolbar", "command", UI.toggleToolbarIcon.bind(UI)],
- ["abp-command-toggleshowinstatusbar", "command", UI.togglePref.bind(UI, "showinstatusbar")],
- ["abp-command-enable", "command", UI.togglePref.bind(UI, "enabled")],
- ["abp-command-contribute", "command", UI.openContributePage.bind(UI)],
- ["abp-command-contribute-hide", "command", UI.hideContributeButton.bind(UI)],
- ["abp-command-toggleshownotifications", "command", Notification.toggleIgnoreCategory.bind(Notification, "*", null)]
-];
-
-onShutdown.add(function()
-{
- for (let window of UI.applicationWindows)
- if (UI.isBottombarOpen(window))
- UI.toggleBottombar(window);
-});
diff --git a/data/extensions/spyblock@gnu.org/lib/utils.js b/data/extensions/spyblock@gnu.org/lib/utils.js
deleted file mode 100644
index 7b07041..0000000
--- a/data/extensions/spyblock@gnu.org/lib/utils.js
+++ /dev/null
@@ -1,751 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * @fileOverview Module containing a bunch of utility functions.
- */
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-let sidebarParams = null;
-
-/**
- * Provides a bunch of utility functions.
- * @class
- */
-let Utils = exports.Utils =
-{
- /**
- * Returns the add-on ID used by Adblock Plus
- */
- get addonID()
- {
- let {addonID} = require("info");
- return addonID;
- },
-
- /**
- * Returns the installed Adblock Plus version
- */
- get addonVersion()
- {
- let {addonVersion} = require("info");
- return addonVersion;
- },
-
- /**
- * Returns whether we are running in Fennec, for Fennec-specific hacks
- * @type Boolean
- */
- get isFennec()
- {
- let {application} = require("info");
- let result = (application == "fennec" || application == "fennec2" || application == "icecatmobile");
- Utils.__defineGetter__("isFennec", () => result);
- return result;
- },
-
- /**
- * Returns the user interface locale selected for adblockplus chrome package.
- */
- get appLocale()
- {
- let locale = "en-US";
- try
- {
- locale = Utils.chromeRegistry.getSelectedLocale("adblockplus");
- }
- catch (e)
- {
- Cu.reportError(e);
- }
- Object.defineProperty(this, "appLocale", {value: locale});
- return locale;
- },
-
- /**
- * Returns version of the Gecko platform
- */
- get platformVersion()
- {
- let platformVersion = Services.appinfo.platformVersion;
- Object.defineProperty(this, "platformVersion", {value: platformVersion});
- return platformVersion;
- },
-
- /**
- * Retrieves a string from global.properties string bundle, will throw if string isn't found.
- *
- * @param {String} name string name
- * @return {String}
- */
- getString: function(name)
- {
- // Randomize URI to work around bug 719376
- let stringBundle = Services.strings.createBundle("chrome://adblockplus/locale/global.properties?" + Math.random());
- Utils.getString = function(name)
- {
- return stringBundle.GetStringFromName(name);
- }
- return Utils.getString(name);
- },
-
- /**
- * Shows an alert message like window.alert() but with a custom title.
- *
- * @param {Window} parentWindow parent window of the dialog (can be null)
- * @param {String} message message to be displayed
- * @param {String} [title] dialog title, default title will be used if omitted
- */
- alert: function(parentWindow, message, title)
- {
- if (!title)
- title = Utils.getString("default_dialog_title");
- Utils.promptService.alert(parentWindow, title, message);
- },
-
- /**
- * Asks the user for a confirmation like window.confirm() but with a custom title.
- *
- * @param {Window} parentWindow parent window of the dialog (can be null)
- * @param {String} message message to be displayed
- * @param {String} [title] dialog title, default title will be used if omitted
- * @return {Bool}
- */
- confirm: function(parentWindow, message, title)
- {
- if (!title)
- title = Utils.getString("default_dialog_title");
- return Utils.promptService.confirm(parentWindow, title, message);
- },
-
- /**
- * Retrieves the window for a document node.
- * @return {Window} will be null if the node isn't associated with a window
- */
- getWindow: function(/**Node*/ node)
- {
- if ("ownerDocument" in node && node.ownerDocument)
- node = node.ownerDocument;
-
- if ("defaultView" in node)
- return node.defaultView;
-
- return null;
- },
-
- /**
- * Retrieves the top-level chrome window for a content window.
- */
- getChromeWindow: function(/**Window*/ window) /**Window*/
- {
- return window.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebNavigation)
- .QueryInterface(Ci.nsIDocShellTreeItem)
- .rootTreeItem
- .QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindow);
- },
-
- /**
- * If the window doesn't have its own security context (e.g. about:blank or
- * data: URL) walks up the parent chain until a window is found that has a
- * security context.
- */
- getOriginWindow: function(/**Window*/ wnd) /**Window*/
- {
- while (wnd != wnd.parent)
- {
- let uri = Utils.makeURI(wnd.location.href);
- if (uri.spec != "about:blank" && uri.spec != "moz-safe-about:blank" &&
- !Utils.netUtils.URIChainHasFlags(uri, Ci.nsIProtocolHandler.URI_INHERITS_SECURITY_CONTEXT))
- {
- break;
- }
- wnd = wnd.parent;
- }
- return wnd;
- },
-
- /**
- * If a protocol using nested URIs like jar: is used - retrieves innermost
- * nested URI.
- */
- unwrapURL: function(/**nsIURI or String*/ url) /**nsIURI*/
- {
- if (!(url instanceof Ci.nsIURI))
- url = Utils.makeURI(url);
-
- if (url instanceof Ci.nsINestedURI)
- return url.innermostURI;
- else
- return url;
- },
-
- /**
- * Translates a string URI into its nsIURI representation, will return null for
- * invalid URIs.
- */
- makeURI: function(/**String*/ url) /**nsIURI*/
- {
- try
- {
- return Utils.ioService.newURI(url, null, null);
- }
- catch (e) {
- return null;
- }
- },
-
- /**
- * Posts an action to the event queue of the current thread to run it
- * asynchronously.
- * @param {function} callback
- */
- runAsync: function(callback)
- {
- Services.tm.currentThread.dispatch(callback, Ci.nsIEventTarget.DISPATCH_NORMAL);
- },
-
- /**
- * Generates filter subscription checksum.
- *
- * @param {string[]} lines filter subscription lines (with checksum line removed)
- * @return {String} checksum or null
- */
- generateChecksum: function(lines)
- {
- let stream = null;
- try
- {
- // Checksum is an MD5 checksum (base64-encoded without the trailing "=") of
- // all lines in UTF-8 without the checksum line, joined with "\n".
-
- let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
- converter.charset = "UTF-8";
- stream = converter.convertToInputStream(lines.join("\n"));
-
- let hashEngine = Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash);
- hashEngine.init(hashEngine.MD5);
- hashEngine.updateFromStream(stream, stream.available());
- return hashEngine.finish(true).replace(/=+$/, "");
- }
- catch (e)
- {
- return null;
- }
- finally
- {
- if (stream)
- stream.close();
- }
- },
-
- /**
- * Formats a unix time according to user's locale.
- * @param {Integer} time unix time in milliseconds
- * @return {String} formatted date and time
- */
- formatTime: function(time)
- {
- try
- {
- let date = new Date(time);
- return Utils.dateFormatter.FormatDateTime("", Ci.nsIScriptableDateFormat.dateFormatShort,
- Ci.nsIScriptableDateFormat.timeFormatNoSeconds,
- date.getFullYear(), date.getMonth() + 1, date.getDate(),
- date.getHours(), date.getMinutes(), date.getSeconds());
- }
- catch(e)
- {
- // Make sure to return even on errors
- Cu.reportError(e);
- return "";
- }
- },
-
- /**
- * Checks whether any of the prefixes listed match the application locale,
- * returns matching prefix if any.
- */
- checkLocalePrefixMatch: function(/**String*/ prefixes) /**String*/
- {
- if (!prefixes)
- return null;
-
- let appLocale = Utils.appLocale;
- for (let prefix of prefixes.split(/,/))
- if (new RegExp("^" + prefix + "\\b").test(appLocale))
- return prefix;
-
- return null;
- },
-
- /**
- * Chooses the best filter subscription for user's language.
- */
- chooseFilterSubscription: function(/**NodeList*/ subscriptions) /**Node*/
- {
- let selectedItem = null;
- let selectedPrefix = null;
- let matchCount = 0;
- for (let i = 0; i < subscriptions.length; i++)
- {
- let subscription = subscriptions[i];
- if (!selectedItem)
- selectedItem = subscription;
-
- let prefix = Utils.checkLocalePrefixMatch(subscription.getAttribute("prefixes"));
- if (prefix)
- {
- if (!selectedPrefix || selectedPrefix.length < prefix.length)
- {
- selectedItem = subscription;
- selectedPrefix = prefix;
- matchCount = 1;
- }
- else if (selectedPrefix && selectedPrefix.length == prefix.length)
- {
- matchCount++;
-
- // If multiple items have a matching prefix of the same length:
- // Select one of the items randomly, probability should be the same
- // for all items. So we replace the previous match here with
- // probability 1/N (N being the number of matches).
- if (Math.random() * matchCount < 1)
- {
- selectedItem = subscription;
- selectedPrefix = prefix;
- }
- }
- }
- }
- return selectedItem;
- },
-
- /**
- * Saves sidebar state before detaching/reattaching
- */
- setParams: function(params)
- {
- sidebarParams = params;
- },
-
- /**
- * Retrieves and removes sidebar state after detaching/reattaching
- */
- getParams: function()
- {
- let ret = sidebarParams;
- sidebarParams = null;
- return ret;
- },
-
- /**
- * Verifies RSA signature. The public key and signature should be base64-encoded.
- * @param {string} key
- * @param {string} signature
- * @param {string} data
- * @return {boolean}
- */
- verifySignature: function(key, signature, data)
- {
- if (!Utils.crypto)
- return false;
-
- // Maybe we did the same check recently, look it up in the cache
- if (!("_cache" in Utils.verifySignature))
- Utils.verifySignature._cache = new Cache(5);
- let cache = Utils.verifySignature._cache;
- let cacheKey = key + " " + signature + " " + data;
- if (cacheKey in cache.data)
- return cache.data[cacheKey];
- else
- cache.add(cacheKey, false);
-
- let keyInfo, pubKey, context;
- try
- {
- let keyItem = Utils.crypto.getSECItem(atob(key));
- keyInfo = Utils.crypto.SECKEY_DecodeDERSubjectPublicKeyInfo(keyItem.address());
- if (keyInfo.isNull())
- throw new Error("SECKEY_DecodeDERSubjectPublicKeyInfo failed");
-
- pubKey = Utils.crypto.SECKEY_ExtractPublicKey(keyInfo);
- if (pubKey.isNull())
- throw new Error("SECKEY_ExtractPublicKey failed");
-
- let signatureItem = Utils.crypto.getSECItem(atob(signature));
-
- context = Utils.crypto.VFY_CreateContext(pubKey, signatureItem.address(), Utils.crypto.SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE, null);
- if (context.isNull())
- return false; // This could happen if the signature is invalid
-
- let error = Utils.crypto.VFY_Begin(context);
- if (error < 0)
- throw new Error("VFY_Begin failed");
-
- error = Utils.crypto.VFY_Update(context, data, data.length);
- if (error < 0)
- throw new Error("VFY_Update failed");
-
- error = Utils.crypto.VFY_End(context);
- if (error < 0)
- return false;
-
- cache.data[cacheKey] = true;
- return true;
- }
- catch (e)
- {
- Cu.reportError(e);
- return false;
- }
- finally
- {
- if (keyInfo && !keyInfo.isNull())
- Utils.crypto.SECKEY_DestroySubjectPublicKeyInfo(keyInfo);
- if (pubKey && !pubKey.isNull())
- Utils.crypto.SECKEY_DestroyPublicKey(pubKey);
- if (context && !context.isNull())
- Utils.crypto.VFY_DestroyContext(context, true);
- }
- },
-
- /**
- * Returns the documentation link from the preferences.
- */
- getDocLink: function(/**String*/ linkID)
- {
- let {Prefs} = require("prefs");
- let docLink = Prefs.documentation_link;
- return docLink.replace(/%LINK%/g, linkID).replace(/%LANG%/g, Utils.appLocale);
- },
-
- /**
- * Splits up a combined label into the label and access key components.
- *
- * @return {Array} An array with two strings: label and access key
- */
- splitLabel: function(/**String*/ label)
- {
- let match = /^(.*)\s*\(&(.)\)\s*(\u2026?)$/.exec(label);
- if (match)
- {
- // Access key not part of the label
- return [match[1] + match[3], match[2]];
- }
- else
- {
- // Access key part of the label
- let pos = label.indexOf("&");
- if (pos >= 0 && pos < label.length - 1)
- return [label.substr(0, pos) + label.substr(pos + 1), label[pos + 1]];
- else
- return [label, ""];
- }
- },
-
- /**
- * Split all labels starting from a particular DOM node.
- */
- splitAllLabels: function(/**DOMNode*/ root)
- {
- let attrMap = {
- __proto__: null,
- "label": "value",
- "setting": "title"
- };
-
- let elements = root.querySelectorAll("*[label], label[value], setting[title]");
- for (let i = 0; i < elements.length; i++)
- {
- let element = elements[i];
- let attr = (element.localName in attrMap ? attrMap[element.localName] : "label");
- let origLabel = element.getAttribute(attr);
-
- let [label, accesskey] = this.splitLabel(origLabel);
- if (label != origLabel)
- element.setAttribute(attr, label);
- if (accesskey != "")
- element.setAttribute("accesskey", accesskey);
-
- // Labels forward changes of the accessKey property to their control, only
- // set it for actual controls.
- if (element.localName != "label")
- element.accessKey = accesskey;
- }
- }
-};
-
-/**
- * A cache with a fixed capacity, newer entries replace entries that have been
- * stored first.
- * @constructor
- */
-function Cache(/**Integer*/ size)
-{
- this._ringBuffer = new Array(size);
- this.data = Object.create(null);
-}
-exports.Cache = Cache;
-
-Cache.prototype =
-{
- /**
- * Ring buffer storing hash keys, allows determining which keys need to be
- * evicted.
- * @type Array
- */
- _ringBuffer: null,
-
- /**
- * Index in the ring buffer to be written next.
- * @type Integer
- */
- _bufferIndex: 0,
-
- /**
- * Cache data, maps values to the keys. Read-only access, for writing use
- * add() method.
- * @type Object
- */
- data: null,
-
- /**
- * Adds a key and the corresponding value to the cache.
- */
- add: function(/**String*/ key, value)
- {
- if (!(key in this.data))
- {
- // This is a new key - we need to add it to the ring buffer and evict
- // another entry instead.
- let oldKey = this._ringBuffer[this._bufferIndex];
- if (typeof oldKey != "undefined")
- delete this.data[oldKey];
- this._ringBuffer[this._bufferIndex] = key;
-
- this._bufferIndex++;
- if (this._bufferIndex >= this._ringBuffer.length)
- this._bufferIndex = 0;
- }
-
- this.data[key] = value;
- },
-
- /**
- * Clears cache contents.
- */
- clear: function()
- {
- this._ringBuffer = new Array(this._ringBuffer.length);
- this.data = Object.create(null);
- }
-}
-
-// Getters for common services, this should be replaced by Services.jsm in future
-
-XPCOMUtils.defineLazyServiceGetter(Utils, "categoryManager", "@mozilla.org/categorymanager;1", "nsICategoryManager");
-XPCOMUtils.defineLazyServiceGetter(Utils, "ioService", "@mozilla.org/network/io-service;1", "nsIIOService");
-XPCOMUtils.defineLazyServiceGetter(Utils, "promptService", "@mozilla.org/embedcomp/prompt-service;1", "nsIPromptService");
-XPCOMUtils.defineLazyServiceGetter(Utils, "effectiveTLD", "@mozilla.org/network/effective-tld-service;1", "nsIEffectiveTLDService");
-XPCOMUtils.defineLazyServiceGetter(Utils, "netUtils", "@mozilla.org/network/util;1", "nsINetUtil");
-XPCOMUtils.defineLazyServiceGetter(Utils, "styleService", "@mozilla.org/content/style-sheet-service;1", "nsIStyleSheetService");
-XPCOMUtils.defineLazyServiceGetter(Utils, "prefService", "@mozilla.org/preferences-service;1", "nsIPrefService");
-XPCOMUtils.defineLazyServiceGetter(Utils, "versionComparator", "@mozilla.org/xpcom/version-comparator;1", "nsIVersionComparator");
-XPCOMUtils.defineLazyServiceGetter(Utils, "windowMediator", "@mozilla.org/appshell/window-mediator;1", "nsIWindowMediator");
-XPCOMUtils.defineLazyServiceGetter(Utils, "windowWatcher", "@mozilla.org/embedcomp/window-watcher;1", "nsIWindowWatcher");
-XPCOMUtils.defineLazyServiceGetter(Utils, "chromeRegistry", "@mozilla.org/chrome/chrome-registry;1", "nsIXULChromeRegistry");
-XPCOMUtils.defineLazyServiceGetter(Utils, "systemPrincipal", "@mozilla.org/systemprincipal;1", "nsIPrincipal");
-XPCOMUtils.defineLazyServiceGetter(Utils, "dateFormatter", "@mozilla.org/intl/scriptabledateformat;1", "nsIScriptableDateFormat");
-XPCOMUtils.defineLazyServiceGetter(Utils, "httpProtocol", "@mozilla.org/network/protocol;1?name=http", "nsIHttpProtocolHandler");
-XPCOMUtils.defineLazyServiceGetter(Utils, "clipboard", "@mozilla.org/widget/clipboard;1", "nsIClipboard");
-XPCOMUtils.defineLazyServiceGetter(Utils, "clipboardHelper", "@mozilla.org/widget/clipboardhelper;1", "nsIClipboardHelper");
-XPCOMUtils.defineLazyGetter(Utils, "crypto", function()
-{
- try
- {
- let ctypes = Cu.import("resource://gre/modules/ctypes.jsm", null).ctypes;
-
- let nsslib;
- try
- {
- nsslib = ctypes.open(ctypes.libraryName("nss3"));
- }
- catch (e)
- {
- // It seems that on Mac OS X the full path name needs to be specified
- let file;
- // Gecko 35 added GreBinD key, see https://bugzilla.mozilla.org/show_bug.cgi?id=1077099
- if (Services.dirsvc.has("GreBinD"))
- file = Services.dirsvc.get("GreBinD", Ci.nsILocalFile);
- else
- file = Services.dirsvc.get("GreD", Ci.nsILocalFile);
- file.append(ctypes.libraryName("nss3"));
- nsslib = ctypes.open(file.path);
- }
-
- let result = {};
-
- // seccomon.h
- result.siUTF8String = 14;
-
- // secoidt.h
- result.SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE = 15;
-
- // The following types are opaque to us
- result.VFYContext = ctypes.void_t;
- result.SECKEYPublicKey = ctypes.void_t;
- result.CERTSubjectPublicKeyInfo = ctypes.void_t;
-
- /*
- * seccomon.h
- * struct SECItemStr {
- * SECItemType type;
- * unsigned char *data;
- * unsigned int len;
- * };
- */
- result.SECItem = ctypes.StructType("SECItem", [
- {type: ctypes.int},
- {data: ctypes.unsigned_char.ptr},
- {len: ctypes.int}
- ]);
-
- /*
- * cryptohi.h
- * extern VFYContext *VFY_CreateContext(SECKEYPublicKey *key, SECItem *sig,
- * SECOidTag sigAlg, void *wincx);
- */
- result.VFY_CreateContext = nsslib.declare(
- "VFY_CreateContext",
- ctypes.default_abi, result.VFYContext.ptr,
- result.SECKEYPublicKey.ptr,
- result.SECItem.ptr,
- ctypes.int,
- ctypes.voidptr_t
- );
-
- /*
- * cryptohi.h
- * extern void VFY_DestroyContext(VFYContext *cx, PRBool freeit);
- */
- result.VFY_DestroyContext = nsslib.declare(
- "VFY_DestroyContext",
- ctypes.default_abi, ctypes.void_t,
- result.VFYContext.ptr,
- ctypes.bool
- );
-
- /*
- * cryptohi.h
- * extern SECStatus VFY_Begin(VFYContext *cx);
- */
- result.VFY_Begin = nsslib.declare("VFY_Begin",
- ctypes.default_abi, ctypes.int,
- result.VFYContext.ptr
- );
-
- /*
- * cryptohi.h
- * extern SECStatus VFY_Update(VFYContext *cx, const unsigned char *input,
- * unsigned int inputLen);
- */
- result.VFY_Update = nsslib.declare(
- "VFY_Update",
- ctypes.default_abi, ctypes.int,
- result.VFYContext.ptr,
- ctypes.unsigned_char.ptr,
- ctypes.int
- );
-
- /*
- * cryptohi.h
- * extern SECStatus VFY_End(VFYContext *cx);
- */
- result.VFY_End = nsslib.declare(
- "VFY_End",
- ctypes.default_abi, ctypes.int,
- result.VFYContext.ptr
- );
-
- /*
- * keyhi.h
- * extern CERTSubjectPublicKeyInfo *
- * SECKEY_DecodeDERSubjectPublicKeyInfo(SECItem *spkider);
- */
- result.SECKEY_DecodeDERSubjectPublicKeyInfo = nsslib.declare(
- "SECKEY_DecodeDERSubjectPublicKeyInfo",
- ctypes.default_abi, result.CERTSubjectPublicKeyInfo.ptr,
- result.SECItem.ptr
- );
-
- /*
- * keyhi.h
- * extern void SECKEY_DestroySubjectPublicKeyInfo(CERTSubjectPublicKeyInfo *spki);
- */
- result.SECKEY_DestroySubjectPublicKeyInfo = nsslib.declare(
- "SECKEY_DestroySubjectPublicKeyInfo",
- ctypes.default_abi, ctypes.void_t,
- result.CERTSubjectPublicKeyInfo.ptr
- );
-
- /*
- * keyhi.h
- * extern SECKEYPublicKey *
- * SECKEY_ExtractPublicKey(CERTSubjectPublicKeyInfo *);
- */
- result.SECKEY_ExtractPublicKey = nsslib.declare(
- "SECKEY_ExtractPublicKey",
- ctypes.default_abi, result.SECKEYPublicKey.ptr,
- result.CERTSubjectPublicKeyInfo.ptr
- );
-
- /*
- * keyhi.h
- * extern void SECKEY_DestroyPublicKey(SECKEYPublicKey *key);
- */
- result.SECKEY_DestroyPublicKey = nsslib.declare(
- "SECKEY_DestroyPublicKey",
- ctypes.default_abi, ctypes.void_t,
- result.SECKEYPublicKey.ptr
- );
-
- // Convenience method
- result.getSECItem = function(data)
- {
- var dataArray = new ctypes.ArrayType(ctypes.unsigned_char, data.length)();
- for (let i = 0; i < data.length; i++)
- dataArray[i] = data.charCodeAt(i) % 256;
- return new result.SECItem(result.siUTF8String, dataArray, dataArray.length);
- };
-
- return result;
- }
- catch (e)
- {
- Cu.reportError(e);
- // Expected, ctypes isn't supported in Gecko 1.9.2
- return null;
- }
-});
-
-if ("@mozilla.org/messenger/headerparser;1" in Cc)
- XPCOMUtils.defineLazyServiceGetter(Utils, "headerParser", "@mozilla.org/messenger/headerparser;1", "nsIMsgHeaderParser");
-else
- Utils.headerParser = null;
diff --git a/data/extensions/spyblock@gnu.org/lib/whitelisting.js b/data/extensions/spyblock@gnu.org/lib/whitelisting.js
deleted file mode 100644
index 1006d26..0000000
--- a/data/extensions/spyblock@gnu.org/lib/whitelisting.js
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2017 eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * @fileOverview This is a dummy to provide a function needed by message
- * responder.
- */
-
-"use strict";
-
-let {Policy} = require("contentPolicy");
-let {RegExpFilter} = require("filterClasses");
-
-// NOTE: The function interface is supposed to be compatible with
-// checkWhitelisted in adblockpluschrome. That's why there is a typeMask
-// parameter here. However, this parameter is only used to decide whether
-// elemhide whitelisting should be considered, so only supported values for this
-// parameter are RegExpFilter.typeMap.DOCUMENT and
-// RegExpFilter.typeMap.DOCUMENT | RegExpFilter.typeMap.ELEMHIDE.
-exports.checkWhitelisted = function(page, frames, typeMask)
-{
- let match =
- Policy.isFrameWhitelisted(frames, typeMask & RegExpFilter.typeMap.ELEMHIDE);
- if (match)
- {
- let [frameIndex, matchType, docDomain, thirdParty, location, filter] = match;
- if (matchType == "DOCUMENT" || matchType == "ELEMHIDE")
- return filter;
- }
-
- return null;
-};
diff --git a/data/extensions/spyblock@gnu.org/lib/windowObserver.js b/data/extensions/spyblock@gnu.org/lib/windowObserver.js
deleted file mode 100644
index 7d34f8a..0000000
--- a/data/extensions/spyblock@gnu.org/lib/windowObserver.js
+++ /dev/null
@@ -1,99 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-exports.WindowObserver = WindowObserver;
-
-/**
- * This class will call listener's method applyToWindow() for all new chrome
- * windows being opened. It will also call listener's method removeFromWindow()
- * for all windows still open when the extension is shut down.
- * @param {Object} listener
- * @param {String} [when] when to execute applyToWindow(). "start" means immediately
- * when the window opens, "ready" when its contents are available
- * and "end" (default) means to wait until the "load" event.
- * @constructor
- */
-function WindowObserver(listener, when)
-{
- this._listener = listener;
- this._when = when;
-
- let windows = [];
- let e = Services.wm.getZOrderDOMWindowEnumerator(null, true);
- while (e.hasMoreElements())
- windows.push(e.getNext());
-
- // Check if there are any windows that we missed
- let eAll = Services.ww.getWindowEnumerator();
- while (eAll.hasMoreElements())
- {
- let element = eAll.getNext();
- if (windows.indexOf(element) < 0)
- windows.push(element);
- }
-
- for (let i = 0; i < windows.length; i++)
- {
- let window = windows[i].QueryInterface(Ci.nsIDOMWindow);
- if (when == "start" || window.document.readyState == "complete")
- this._listener.applyToWindow(window);
- else
- this.observe(window, "chrome-document-global-created", null);
- }
-
- Services.obs.addObserver(this, "chrome-document-global-created", true);
-
- this._shutdownHandler = function()
- {
- let e = Services.ww.getWindowEnumerator();
- while (e.hasMoreElements())
- this._listener.removeFromWindow(e.getNext().QueryInterface(Ci.nsIDOMWindow));
-
- Services.obs.removeObserver(this, "chrome-document-global-created");
- }.bind(this);
- onShutdown.add(this._shutdownHandler);
-}
-WindowObserver.prototype =
-{
- _listener: null,
- _when: null,
- _shutdownHandler: null,
-
- shutdown: function()
- {
- if (!this._shutdownHandler)
- return;
-
- onShutdown.remove(this._shutdownHandler);
- this._shutdownHandler();
- this._shutdownHandler = null;
- },
-
- observe: function(subject, topic, data)
- {
- if (topic == "chrome-document-global-created")
- {
- let window = subject.QueryInterface(Ci.nsIDOMWindow);
- if (this._when == "start")
- {
- this._listener.applyToWindow(window);
- return;
- }
-
- let event = (this._when == "ready" ? "DOMContentLoaded" : "load");
- let listener = function()
- {
- window.removeEventListener(event, listener, false);
- if (this._shutdownHandler)
- this._listener.applyToWindow(window);
- }.bind(this);
- window.addEventListener(event, listener, false);
- }
- },
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference, Ci.nsIObserver])
-};