summaryrefslogtreecommitdiff
path: root/data/extensions/spyblock@gnu.org/lib/subscriptionClasses.js
diff options
context:
space:
mode:
Diffstat (limited to 'data/extensions/spyblock@gnu.org/lib/subscriptionClasses.js')
-rw-r--r--data/extensions/spyblock@gnu.org/lib/subscriptionClasses.js597
1 files changed, 597 insertions, 0 deletions
diff --git a/data/extensions/spyblock@gnu.org/lib/subscriptionClasses.js b/data/extensions/spyblock@gnu.org/lib/subscriptionClasses.js
new file mode 100644
index 0000000..13dceaf
--- /dev/null
+++ b/data/extensions/spyblock@gnu.org/lib/subscriptionClasses.js
@@ -0,0 +1,597 @@
+/*
+ * This file is part of Adblock Plus <http://adblockplus.org/>,
+ * Copyright (C) 2006-2014 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 Definition of Subscription class and its subclasses.
+ */
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+let {ActiveFilter, BlockingFilter, WhitelistFilter, ElemHideBase} = require("filterClasses");
+let {FilterNotifier} = require("filterNotifier");
+
+/**
+ * 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;
+ else
+ {
+ let {Utils} = require("utils");
+ this._title = Utils.getString("newGroup_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 Array of 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 filter to an array of strings for writing out on the disk.
+ * @param {Array of String} buffer buffer to push the serialization results into
+ */
+ serialize: function(buffer)
+ {
+ buffer.push("[Subscription]");
+ buffer.push("url=" + this.url);
+ buffer.push("title=" + this._title);
+ if (this._fixedTitle)
+ buffer.push("fixedTitle=true");
+ if (this._disabled)
+ buffer.push("disabled=true");
+ },
+
+ serializeFilters: function(buffer)
+ {
+ for (let filter of this.filters)
+ buffer.push(filter.text.replace(/\[/g, "\\["));
+ },
+
+ toString: function()
+ {
+ let buffer = [];
+ this.serialize(buffer);
+ return buffer.join("\n");
+ }
+};
+
+/**
+ * Cache for known filter subscriptions, maps URL to subscription objects.
+ * @type Object
+ */
+Subscription.knownSubscriptions = {__proto__: 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];
+
+ try
+ {
+ // Test URL for validity
+ url = Services.io.newURI(url, null, null).spec;
+ return new DownloadableSubscription(url, null);
+ }
+ catch (e)
+ {
+ 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;
+ try
+ {
+ obj.url = Services.io.newURI(obj.url, null, null).spec;
+
+ // 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) || 0;
+ if ("lastCheck" in obj)
+ result._lastCheck = parseInt(obj.lastCheck) || 0;
+ if ("expires" in obj)
+ result.expires = parseInt(obj.expires) || 0;
+ if ("softExpiration" in obj)
+ result.softExpiration = parseInt(obj.softExpiration) || 0;
+ if ("errors" in obj)
+ result._errors = parseInt(obj.errors) || 0;
+ if ("version" in obj)
+ result.version = parseInt(obj.version) || 0;
+ if ("requiredVersion" in obj)
+ {
+ let {addonVersion} = require("info");
+ result.requiredVersion = obj.requiredVersion;
+ if (Services.vc.compare(result.requiredVersion, addonVersion) > 0)
+ result.upgradeRequired = true;
+ }
+ if ("homepage" in obj)
+ result._homepage = obj.homepage;
+ if ("lastDownload" in obj)
+ result._lastDownload = parseInt(obj.lastDownload) || 0;
+ }
+ catch (e)
+ {
+ // Invalid URL - custom filter group
+ if (!("title" in obj))
+ {
+ // Backwards compatibility - titles and filter types were originally
+ // determined by group identifier.
+ if (obj.url == "~wl~")
+ obj.defaults = "whitelist";
+ else if (obj.url == "~fl~")
+ obj.defaults = "blocking";
+ else if (obj.url == "~eh~")
+ obj.defaults = "elemhide";
+ if ("defaults" in obj)
+ {
+ let {Utils} = require("utils");
+ obj.title = Utils.getString(obj.defaults + "Group_title");
+ }
+ }
+ 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 =
+{
+ __proto__: Subscription.prototype,
+
+ /**
+ * Filter types that should be added to this subscription by default
+ * (entries should correspond to keys in SpecialSubscription.defaultsMap).
+ * @type Array of 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: function(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()
+ */
+ serialize: function(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 = {
+ __proto__: null,
+ "whitelist": WhitelistFilter,
+ "blocking": BlockingFilter,
+ "elemhide": ElemHideBase
+};
+
+/**
+ * Creates a new user-defined filter group.
+ * @param {String} [title] title of the new filter group
+ * @result {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.
+ */
+SpecialSubscription.createForFilter = function(/**Filter*/ filter) /**SpecialSubscription*/
+{
+ 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"];
+
+ let {Utils} = require("utils");
+ subscription.title = Utils.getString(subscription.defaults[0] + "Group_title");
+ 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 =
+{
+ __proto__: Subscription.prototype,
+
+ _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()
+ */
+ serialize: function(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 by 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 =
+{
+ __proto__: RegularSubscription.prototype,
+
+ /**
+ * See Subscription.serialize()
+ */
+ serialize: function(buffer)
+ {
+ throw new Error("Unexpected call, external subscriptions should not be serialized");
+ }
+};
+
+/**
+ * Class for filter subscriptions updated by 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 =
+{
+ __proto__: RegularSubscription.prototype,
+
+ _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,
+
+ /**
+ * Should be true if requiredVersion is higher than current Adblock Plus version
+ * @type Boolean
+ */
+ upgradeRequired: false,
+
+ /**
+ * Should be true if the Privatemode: header is set to true in the subscription
+ * @type Boolean
+ */
+ privateMode: false,
+
+ /**
+ * See Subscription.serialize()
+ */
+ serialize: function(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.privateMode)
+ buffer.push("privateMode=" + this.privateMode);
+ }
+};