| Index: lib/adblockplus.js |
| =================================================================== |
| new file mode 100644 |
| --- /dev/null |
| +++ b/lib/adblockplus.js |
| @@ -0,0 +1,3047 @@ |
| +/* |
| + * This Source Code is subject to the terms of the Mozilla Public License |
| + * version 2.0 (the "License"). You can obtain a copy of the License at |
| + * http://mozilla.org/MPL/2.0/. |
| + */ |
| + |
| +// |
| +// This file has been generated automatically from Adblock Plus for Firefox |
| +// source code. DO NOT MODIFY, change the original source code instead. |
| +// |
| +// Relevant repositories: |
| +// * https://hg.adblockplus.org/adblockplus/ |
| +// * https://hg.adblockplus.org/jshydra/ |
| +// |
| + |
| +require.scopes["filterNotifier"] = (function() |
| +{ |
| + var exports = {}; |
| + var listeners = []; |
| + var FilterNotifier = exports.FilterNotifier = |
| + { |
| + addListener: function(listener) |
| + { |
| + if (listeners.indexOf(listener) >= 0) |
| + { |
| + return; |
| + } |
| + listeners.push(listener); |
| + }, |
| + removeListener: function(listener) |
| + { |
| + var index = listeners.indexOf(listener); |
| + if (index >= 0) |
| + { |
| + listeners.splice(index, 1); |
| + } |
| + }, |
| + triggerListeners: function(action, item, param1, param2, param3) |
| + { |
| + for (var _loopIndex0 = 0; _loopIndex0 < listeners.length; ++_loopIndex0) |
| + { |
| + var listener = listeners[_loopIndex0]; |
| + listener(action, item, param1, param2, param3); |
| + } |
| + } |
| + }; |
| + return exports; |
| +})(); |
| +require.scopes["filterClasses"] = (function() |
| +{ |
| + var exports = {}; |
| + var FilterNotifier = require("filterNotifier").FilterNotifier; |
| + |
| + function Filter(text) |
| + { |
| + this.text = text; |
| + this.subscriptions = []; |
| + } |
| + exports.Filter = Filter; |
| + Filter.prototype = |
| + { |
| + text: null, |
| + subscriptions: null, |
| + serialize: function(buffer) |
| + { |
| + buffer.push("[Filter]"); |
| + buffer.push("text=" + this.text); |
| + }, |
| + toString: function() |
| + { |
| + return this.text; |
| + } |
| + }; |
| + Filter.knownFilters = |
| + { |
| + __proto__: null |
| + }; |
| + Filter.elemhideRegExp = /^([^\/\*\|\@"!]*?)#(\@)?(?:([\w\-]+|\*)((?:\([\w\-]+(?:[$^*]?=[^\(\)"]*)?\))*)|#([^{}]+))$/; |
| + Filter.regexpRegExp = /^(@@)?\/.*\/(?:\$~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[^,\s]+)?)*)?$/; |
| + Filter.optionsRegExp = /\$(~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[^,\s]+)?)*)$/; |
| + Filter.fromText = function(text) |
| + { |
| + if (text in Filter.knownFilters) |
| + { |
| + return Filter.knownFilters[text]; |
| + } |
| + var ret; |
| + var match = text.indexOf("#") >= 0 ? 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; |
| + }; |
| + Filter.fromObject = function(obj) |
| + { |
| + var 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) || 0; |
| + } |
| + if ("lastHit" in obj) |
| + { |
| + ret._lastHit = parseInt(obj.lastHit) || 0; |
| + } |
| + } |
| + return ret; |
| + }; |
| + Filter.normalize = function(text) |
| + { |
| + if (!text) |
| + { |
| + return text; |
| + } |
| + text = text.replace(/[^\S ]/g, ""); |
| + if (/^\s*!/.test(text)) |
| + { |
| + return text.replace(/^\s+/, "").replace(/\s+$/, ""); |
| + } |
| + else if (Filter.elemhideRegExp.test(text)) |
| + { |
| + var _tempVar1 = /^(.*?)(#\@?#?)(.*)$/.exec(text); |
| + var domain = _tempVar1[1]; |
| + var separator = _tempVar1[2]; |
| + var selector = _tempVar1[3]; |
| + return domain.replace(/\s/g, "") + separator + selector.replace(/^\s+/, "").replace(/\s+$/, ""); |
| + } |
| + else |
| + { |
| + return text.replace(/\s/g, ""); |
| + } |
| + }; |
| + |
| + function InvalidFilter(text, reason) |
| + { |
| + Filter.call(this, text); |
| + this.reason = reason; |
| + } |
| + exports.InvalidFilter = InvalidFilter; |
| + InvalidFilter.prototype = |
| + { |
| + __proto__: Filter.prototype, |
| + reason: null, |
| + serialize: function(buffer){} |
| + }; |
| + |
| + function CommentFilter(text) |
| + { |
| + Filter.call(this, text); |
| + } |
| + exports.CommentFilter = CommentFilter; |
| + CommentFilter.prototype = |
| + { |
| + __proto__: Filter.prototype, |
| + serialize: function(buffer){} |
| + }; |
| + |
| + function ActiveFilter(text, domains) |
| + { |
| + Filter.call(this, text); |
| + this.domainSource = domains; |
| + } |
| + exports.ActiveFilter = ActiveFilter; |
| + ActiveFilter.prototype = |
| + { |
| + __proto__: Filter.prototype, |
| + _disabled: false, |
| + _hitCount: 0, |
| + _lastHit: 0, |
| + get disabled() |
| + { |
| + return this._disabled; |
| + }, |
| + set disabled(value) |
| + { |
| + if (value != this._disabled) |
| + { |
| + var oldValue = this._disabled; |
| + this._disabled = value; |
| + FilterNotifier.triggerListeners("filter.disabled", this, value, oldValue); |
| + } |
| + return this._disabled; |
| + }, |
| + get hitCount() |
| + { |
| + return this._hitCount; |
| + }, |
| + set hitCount(value) |
| + { |
| + if (value != this._hitCount) |
| + { |
| + var oldValue = this._hitCount; |
| + this._hitCount = value; |
| + FilterNotifier.triggerListeners("filter.hitCount", this, value, oldValue); |
| + } |
| + return this._hitCount; |
| + }, |
| + get lastHit() |
| + { |
| + return this._lastHit; |
| + }, |
| + set lastHit(value) |
| + { |
| + if (value != this._lastHit) |
| + { |
| + var oldValue = this._lastHit; |
| + this._lastHit = value; |
| + FilterNotifier.triggerListeners("filter.lastHit", this, value, oldValue); |
| + } |
| + return this._lastHit; |
| + }, |
| + domainSource: null, |
| + domainSeparator: null, |
| + ignoreTrailingDot: true, |
| + get domains() |
| + { |
| + var domains = null; |
| + if (this.domainSource) |
| + { |
| + var list = this.domainSource.split(this.domainSeparator); |
| + if (list.length == 1 && list[0][0] != "~") |
| + { |
| + domains = |
| + { |
| + __proto__: null, |
| + "": false |
| + }; |
| + if (this.ignoreTrailingDot) |
| + { |
| + list[0] = list[0].replace(/\.+$/, ""); |
| + } |
| + domains[list[0]] = true; |
| + } |
| + else |
| + { |
| + var hasIncludes = false; |
| + for (var i = 0; i < list.length; i++) |
| + { |
| + var domain = list[i]; |
| + if (this.ignoreTrailingDot) |
| + { |
| + domain = domain.replace(/\.+$/, ""); |
| + } |
| + if (domain == "") |
| + { |
| + continue; |
| + } |
| + var include; |
| + if (domain[0] == "~") |
| + { |
| + include = false; |
| + domain = domain.substr(1); |
| + } |
| + else |
| + { |
| + include = true; |
| + hasIncludes = true; |
| + } |
| + if (!domains) |
| + { |
| + domains = |
| + { |
| + __proto__: null |
| + }; |
| + } |
| + domains[domain] = include; |
| + } |
| + domains[""] = !hasIncludes; |
| + } |
| + delete this.domainSource; |
| + } |
| + this.__defineGetter__("domains", function() |
| + { |
| + return domains; |
| + }); |
| + return this.domains; |
| + }, |
| + isActiveOnDomain: function(docDomain) |
| + { |
| + if (!this.domains) |
| + { |
| + return true; |
| + } |
| + 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]; |
| + } |
| + var nextDot = docDomain.indexOf("."); |
| + if (nextDot < 0) |
| + { |
| + break; |
| + } |
| + docDomain = docDomain.substr(nextDot + 1); |
| + } |
| + return this.domains[""]; |
| + }, |
| + isActiveOnlyOnDomain: function(docDomain) |
| + { |
| + if (!docDomain || !this.domains || this.domains[""]) |
| + { |
| + return false; |
| + } |
| + if (this.ignoreTrailingDot) |
| + { |
| + docDomain = docDomain.replace(/\.+$/, ""); |
| + } |
| + docDomain = docDomain.toUpperCase(); |
| + for (var domain in this.domains) |
| + { |
| + if (this.domains[domain] && domain != docDomain && (domain.length <= docDomain.length || domain.indexOf("." + docDomain) != domain.length - docDomain.length - 1)) |
| + { |
| + return false; |
| + } |
| + } |
| + return true; |
| + }, |
| + serialize: function(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); |
| + } |
| + } |
| + } |
| + }; |
| + |
| + function RegExpFilter(text, regexpSource, contentType, matchCase, domains, thirdParty) |
| + { |
| + ActiveFilter.call(this, text, domains); |
| + if (contentType != null) |
| + { |
| + this.contentType = contentType; |
| + } |
| + if (matchCase) |
| + { |
| + this.matchCase = matchCase; |
| + } |
| + if (thirdParty != null) |
| + { |
| + this.thirdParty = thirdParty; |
| + } |
| + if (regexpSource.length >= 2 && regexpSource[0] == "/" && regexpSource[regexpSource.length - 1] == "/") |
| + { |
| + var regexp = new RegExp(regexpSource.substr(1, regexpSource.length - 2), this.matchCase ? "" : "i"); |
| + this.__defineGetter__("regexp", function() |
| + { |
| + return regexp; |
| + }); |
| + } |
| + else |
| + { |
| + this.regexpSource = regexpSource; |
| + } |
| + } |
| + exports.RegExpFilter = RegExpFilter; |
| + RegExpFilter.prototype = |
| + { |
| + __proto__: ActiveFilter.prototype, |
| + length: 1, |
| + domainSeparator: "|", |
| + regexpSource: null, |
| + get regexp() |
| + { |
| + var source = this.regexpSource.replace(/\*+/g, "*"); |
| + if (source[0] == "*") |
| + { |
| + source = source.substr(1); |
| + } |
| + var pos = source.length - 1; |
| + if (pos >= 0 && source[pos] == "*") |
| + { |
| + source = source.substr(0, pos); |
| + } |
| + source = source.replace(/\^\|$/, "^").replace(/\W/g, "\\$&").replace(/\\\*/g, ".*").replace(/\\\^/g, "(?:[\\x00-\\x24\\x26-\\x2C\\x2F\\x3A-\\x40\\x5B-\\x5E\\x60\\x7B-\\x80]|$)").replace(/^\\\|\\\|/, "^[\\w\\-]+:\\/+(?!\\/)(?:[^.\\/]+\\.)*?").replace(/^\\\|/, "^").replace(/\\\|$/, "$"); |
| + var regexp = new RegExp(source, this.matchCase ? "" : "i"); |
| + delete this.regexpSource; |
| + this.__defineGetter__("regexp", function() |
| + { |
| + return regexp; |
| + }); |
| + return this.regexp; |
| + }, |
| + contentType: 2147483647, |
| + matchCase: false, |
| + thirdParty: null, |
| + matches: function(location, contentType, docDomain, thirdParty) |
| + { |
| + if (this.regexp.test(location) && (RegExpFilter.typeMap[contentType] & this.contentType) != 0 && (this.thirdParty == null || this.thirdParty == thirdParty) && this.isActiveOnDomain(docDomain)) |
| + { |
| + return true; |
| + } |
| + return false; |
| + } |
| + }; |
| + RegExpFilter.prototype.__defineGetter__("0", function() |
| + { |
| + return this; |
| + }); |
| + RegExpFilter.fromText = function(text) |
| + { |
| + var blocking = true; |
| + var origText = text; |
| + if (text.indexOf("@@") == 0) |
| + { |
| + blocking = false; |
| + text = text.substr(2); |
| + } |
| + var contentType = null; |
| + var matchCase = null; |
| + var domains = null; |
| + var siteKeys = null; |
| + var thirdParty = null; |
| + var collapse = null; |
| + var options; |
| + var match = text.indexOf("$") >= 0 ? Filter.optionsRegExp.exec(text) : null; |
| + if (match) |
| + { |
| + options = match[1].toUpperCase().split(","); |
| + text = match.input.substr(0, match.index); |
| + for (var _loopIndex2 = 0; _loopIndex2 < options.length; ++_loopIndex2) |
| + { |
| + var option = options[_loopIndex2]; |
| + var value = null; |
| + var 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; |
| + } |
| + contentType &= ~RegExpFilter.typeMap[option.substr(1)]; |
| + } |
| + else if (option == "MATCH_CASE") |
| + { |
| + matchCase = true; |
| + } |
| + 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.split(/\|/); |
| + } |
| + } |
| + } |
| + if (!blocking && (contentType == null || contentType & RegExpFilter.typeMap.DOCUMENT) && (!options || options.indexOf("DOCUMENT") < 0) && !/^\|?[\w\-]+:/.test(text)) |
| + { |
| + if (contentType == null) |
| + { |
| + contentType = RegExpFilter.prototype.contentType; |
| + } |
| + contentType &= ~RegExpFilter.typeMap.DOCUMENT; |
| + } |
| + if (!blocking && siteKeys) |
| + { |
| + contentType = RegExpFilter.typeMap.DOCUMENT; |
| + } |
| + try |
| + { |
| + if (blocking) |
| + { |
| + return new BlockingFilter(origText, text, contentType, matchCase, domains, thirdParty, collapse); |
| + } |
| + else |
| + { |
| + return new WhitelistFilter(origText, text, contentType, matchCase, domains, thirdParty, siteKeys); |
| + } |
| + } |
| + catch (e) |
| + { |
| + return new InvalidFilter(text, e); |
| + } |
| + }; |
| + RegExpFilter.typeMap = |
| + { |
| + OTHER: 1, |
| + SCRIPT: 2, |
| + IMAGE: 4, |
| + STYLESHEET: 8, |
| + OBJECT: 16, |
| + SUBDOCUMENT: 32, |
| + DOCUMENT: 64, |
| + XBL: 1, |
| + PING: 1, |
| + XMLHTTPREQUEST: 2048, |
| + OBJECT_SUBREQUEST: 4096, |
| + DTD: 1, |
| + MEDIA: 16384, |
| + FONT: 32768, |
| + BACKGROUND: 4, |
| + POPUP: 268435456, |
| + DONOTTRACK: 536870912, |
| + ELEMHIDE: 1073741824 |
| + }; |
| + RegExpFilter.prototype.contentType &= ~ (RegExpFilter.typeMap.ELEMHIDE | RegExpFilter.typeMap.DONOTTRACK | RegExpFilter.typeMap.POPUP); |
| + |
| + function BlockingFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, collapse) |
| + { |
| + RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, thirdParty); |
| + this.collapse = collapse; |
| + } |
| + exports.BlockingFilter = BlockingFilter; |
| + BlockingFilter.prototype = |
| + { |
| + __proto__: RegExpFilter.prototype, |
| + collapse: null |
| + }; |
| + |
| + function WhitelistFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, siteKeys) |
| + { |
| + RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, thirdParty); |
| + if (siteKeys != null) |
| + { |
| + this.siteKeys = siteKeys; |
| + } |
| + } |
| + exports.WhitelistFilter = WhitelistFilter; |
| + WhitelistFilter.prototype = |
| + { |
| + __proto__: RegExpFilter.prototype, |
| + siteKeys: null |
| + }; |
| + |
| + function ElemHideBase(text, domains, selector) |
| + { |
| + ActiveFilter.call(this, text, domains ? domains.toUpperCase() : null); |
| + if (domains) |
| + { |
| + this.selectorDomain = domains.replace(/,~[^,]+/g, "").replace(/^~[^,]+,?/, "").toLowerCase(); |
| + } |
| + this.selector = selector; |
| + } |
| + exports.ElemHideBase = ElemHideBase; |
| + ElemHideBase.prototype = |
| + { |
| + __proto__: ActiveFilter.prototype, |
| + domainSeparator: ",", |
| + ignoreTrailingDot: false, |
| + selectorDomain: null, |
| + selector: null |
| + }; |
| + ElemHideBase.fromText = function(text, domain, isException, tagName, attrRules, selector) |
| + { |
| + if (!selector) |
| + { |
| + if (tagName == "*") |
| + { |
| + tagName = ""; |
| + } |
| + var id = null; |
| + var additional = ""; |
| + if (attrRules) |
| + { |
| + attrRules = attrRules.match(/\([\w\-]+(?:[$^*]?=[^\(\)"]*)?\)/g); |
| + for (var _loopIndex3 = 0; _loopIndex3 < attrRules.length; ++_loopIndex3) |
| + { |
| + var rule = attrRules[_loopIndex3]; |
| + rule = rule.substr(1, rule.length - 2); |
| + var separatorPos = rule.indexOf("="); |
| + if (separatorPos > 0) |
| + { |
| + rule = rule.replace(/=/, "=\"") + "\""; |
| + additional += "[" + rule + "]"; |
| + } |
| + else |
| + { |
| + if (id) |
| + { |
| + var Utils = require("utils").Utils; |
| + return new InvalidFilter(text, Utils.getString("filter_elemhide_duplicate_id")); |
| + } |
| + else |
| + { |
| + id = rule; |
| + } |
| + } |
| + } |
| + } |
| + if (id) |
| + { |
| + selector = tagName + "." + id + additional + "," + tagName + "#" + id + additional; |
| + } |
| + else if (tagName || additional) |
| + { |
| + selector = tagName + additional; |
| + } |
| + else |
| + { |
| + var Utils = require("utils").Utils; |
| + return new InvalidFilter(text, Utils.getString("filter_elemhide_nocriteria")); |
| + } |
| + } |
| + if (isException) |
| + { |
| + return new ElemHideException(text, domain, selector); |
| + } |
| + else |
| + { |
| + return new ElemHideFilter(text, domain, selector); |
| + } |
| + }; |
| + |
| + function ElemHideFilter(text, domains, selector) |
| + { |
| + ElemHideBase.call(this, text, domains, selector); |
| + } |
| + exports.ElemHideFilter = ElemHideFilter; |
| + ElemHideFilter.prototype = |
| + { |
| + __proto__: ElemHideBase.prototype |
| + }; |
| + |
| + function ElemHideException(text, domains, selector) |
| + { |
| + ElemHideBase.call(this, text, domains, selector); |
| + } |
| + exports.ElemHideException = ElemHideException; |
| + ElemHideException.prototype = |
| + { |
| + __proto__: ElemHideBase.prototype |
| + }; |
| + return exports; |
| +})(); |
| +require.scopes["subscriptionClasses"] = (function() |
| +{ |
| + var exports = {}; |
| + var _tempVar4 = require("filterClasses"); |
| + var ActiveFilter = _tempVar4.ActiveFilter; |
| + var BlockingFilter = _tempVar4.BlockingFilter; |
| + var WhitelistFilter = _tempVar4.WhitelistFilter; |
| + var ElemHideBase = _tempVar4.ElemHideBase; |
| + var FilterNotifier = require("filterNotifier").FilterNotifier; |
| + |
| + function Subscription(url, title) |
| + { |
| + this.url = url; |
| + this.filters = []; |
| + if (title) |
| + { |
| + this._title = title; |
| + } |
| + else |
| + { |
| + var Utils = require("utils").Utils; |
| + this._title = Utils.getString("newGroup_title"); |
| + } |
| + Subscription.knownSubscriptions[url] = this; |
| + } |
| + exports.Subscription = Subscription; |
| + Subscription.prototype = |
| + { |
| + url: null, |
| + filters: null, |
| + _title: null, |
| + _fixedTitle: false, |
| + _disabled: false, |
| + get title() |
| + { |
| + return this._title; |
| + }, |
| + set title(value) |
| + { |
| + if (value != this._title) |
| + { |
| + var oldValue = this._title; |
| + this._title = value; |
| + FilterNotifier.triggerListeners("subscription.title", this, value, oldValue); |
| + } |
| + return this._title; |
| + }, |
| + get fixedTitle() |
| + { |
| + return this._fixedTitle; |
| + }, |
| + set fixedTitle(value) |
| + { |
| + if (value != this._fixedTitle) |
| + { |
| + var oldValue = this._fixedTitle; |
| + this._fixedTitle = value; |
| + FilterNotifier.triggerListeners("subscription.fixedTitle", this, value, oldValue); |
| + } |
| + return this._fixedTitle; |
| + }, |
| + get disabled() |
| + { |
| + return this._disabled; |
| + }, |
| + set disabled(value) |
| + { |
| + if (value != this._disabled) |
| + { |
| + var oldValue = this._disabled; |
| + this._disabled = value; |
| + FilterNotifier.triggerListeners("subscription.disabled", this, value, oldValue); |
| + } |
| + return this._disabled; |
| + }, |
| + 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 (var _loopIndex5 = 0; _loopIndex5 < this.filters.length; ++_loopIndex5) |
| + { |
| + var filter = this.filters[_loopIndex5]; |
| + buffer.push(filter.text.replace(/\[/g, "\\[")); |
| + } |
| + }, |
| + toString: function() |
| + { |
| + var buffer = []; |
| + this.serialize(buffer); |
| + return buffer.join("\n"); |
| + } |
| + }; |
| + Subscription.knownSubscriptions = |
| + { |
| + __proto__: null |
| + }; |
| + Subscription.fromURL = function(url) |
| + { |
| + if (url in Subscription.knownSubscriptions) |
| + { |
| + return Subscription.knownSubscriptions[url]; |
| + } |
| + try |
| + { |
| + url = Services.io.newURI(url, null, null).spec; |
| + return new DownloadableSubscription(url, null); |
| + } |
| + catch (e) |
| + { |
| + return new SpecialSubscription(url); |
| + } |
| + }; |
| + Subscription.fromObject = function(obj) |
| + { |
| + var result; |
| + try |
| + { |
| + obj.url = Services.io.newURI(obj.url, null, null).spec; |
| + result = new DownloadableSubscription(obj.url, obj.title); |
| + if ("nextURL" in obj) |
| + { |
| + result.nextURL = obj.nextURL; |
| + } |
| + if ("downloadStatus" in obj) |
| + { |
| + result._downloadStatus = obj.downloadStatus; |
| + } |
| + if ("lastModified" in obj) |
| + { |
| + result.lastModified = obj.lastModified; |
| + } |
| + 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 ("requiredVersion" in obj) |
| + { |
| + var addonVersion = require("info").addonVersion; |
| + result.requiredVersion = obj.requiredVersion; |
| + if (Services.vc.compare(result.requiredVersion, addonVersion) > 0) |
| + { |
| + result.upgradeRequired = true; |
| + } |
| + } |
| + if ("alternativeLocations" in obj) |
| + { |
| + result.alternativeLocations = obj.alternativeLocations; |
| + } |
| + if ("homepage" in obj) |
| + { |
| + result._homepage = obj.homepage; |
| + } |
| + if ("lastDownload" in obj) |
| + { |
| + result._lastDownload = parseInt(obj.lastDownload) || 0; |
| + } |
| + } |
| + catch (e) |
| + { |
| + if (!("title" in obj)) |
| + { |
| + 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) |
| + { |
| + var Utils = require("utils").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 ("disabled" in obj) |
| + { |
| + result._disabled = obj.disabled == "true"; |
| + } |
| + return result; |
| + }; |
| + |
| + function SpecialSubscription(url, title) |
| + { |
| + Subscription.call(this, url, title); |
| + } |
| + exports.SpecialSubscription = SpecialSubscription; |
| + SpecialSubscription.prototype = |
| + { |
| + __proto__: Subscription.prototype, |
| + defaults: null, |
| + isDefaultFor: function(filter) |
| + { |
| + if (this.defaults && this.defaults.length) |
| + { |
| + for (var _loopIndex6 = 0; _loopIndex6 < this.defaults.length; ++_loopIndex6) |
| + { |
| + var type = this.defaults[_loopIndex6]; |
| + if (filter instanceof SpecialSubscription.defaultsMap[type]) |
| + { |
| + return true; |
| + } |
| + if (!(filter instanceof ActiveFilter) && type == "blacklist") |
| + { |
| + return true; |
| + } |
| + } |
| + } |
| + return false; |
| + }, |
| + serialize: function(buffer) |
| + { |
| + Subscription.prototype.serialize.call(this, buffer); |
| + if (this.defaults && this.defaults.length) |
| + { |
| + buffer.push("defaults=" + this.defaults.filter(function(type) |
| + { |
| + return type in SpecialSubscription.defaultsMap; |
| + }).join(" ")); |
| + } |
| + if (this._lastDownload) |
| + { |
| + buffer.push("lastDownload=" + this._lastDownload); |
| + } |
| + } |
| + }; |
| + SpecialSubscription.defaultsMap = |
| + { |
| + __proto__: null, |
| + "whitelist": WhitelistFilter, |
| + "blocking": BlockingFilter, |
| + "elemhide": ElemHideBase |
| + }; |
| + SpecialSubscription.create = function(title) |
| + { |
| + var url; |
| + do |
| + { |
| + url = "~user~" + Math.round(Math.random() * 1000000); |
| + } |
| + while (url in Subscription.knownSubscriptions); |
| + return new SpecialSubscription(url, title); |
| + }; |
| + SpecialSubscription.createForFilter = function(filter) |
| + { |
| + var subscription = SpecialSubscription.create(); |
| + subscription.filters.push(filter); |
| + for (var type in SpecialSubscription.defaultsMap) |
| + { |
| + if (filter instanceof SpecialSubscription.defaultsMap[type]) |
| + { |
| + subscription.defaults = [type]; |
| + } |
| + } |
| + if (!subscription.defaults) |
| + { |
| + subscription.defaults = ["blocking"]; |
| + } |
| + var Utils = require("utils").Utils; |
| + subscription.title = Utils.getString(subscription.defaults[0] + "Group_title"); |
| + return subscription; |
| + }; |
| + |
| + function RegularSubscription(url, title) |
| + { |
| + Subscription.call(this, url, title || url); |
| + } |
| + exports.RegularSubscription = RegularSubscription; |
| + RegularSubscription.prototype = |
| + { |
| + __proto__: Subscription.prototype, |
| + _homepage: null, |
| + _lastDownload: 0, |
| + get homepage() |
| + { |
| + return this._homepage; |
| + }, |
| + set homepage(value) |
| + { |
| + if (value != this._homepage) |
| + { |
| + var oldValue = this._homepage; |
| + this._homepage = value; |
| + FilterNotifier.triggerListeners("subscription.homepage", this, value, oldValue); |
| + } |
| + return this._homepage; |
| + }, |
| + get lastDownload() |
| + { |
| + return this._lastDownload; |
| + }, |
| + set lastDownload(value) |
| + { |
| + if (value != this._lastDownload) |
| + { |
| + var oldValue = this._lastDownload; |
| + this._lastDownload = value; |
| + FilterNotifier.triggerListeners("subscription.lastDownload", this, value, oldValue); |
| + } |
| + return this._lastDownload; |
| + }, |
| + 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); |
| + } |
| + } |
| + }; |
| + |
| + function ExternalSubscription(url, title) |
| + { |
| + RegularSubscription.call(this, url, title); |
| + } |
| + exports.ExternalSubscription = ExternalSubscription; |
| + ExternalSubscription.prototype = |
| + { |
| + __proto__: RegularSubscription.prototype, |
| + serialize: function(buffer) |
| + { |
| + throw new Error("Unexpected call, external subscriptions should not be serialized"); |
| + } |
| + }; |
| + |
| + function DownloadableSubscription(url, title) |
| + { |
| + RegularSubscription.call(this, url, title); |
| + } |
| + exports.DownloadableSubscription = DownloadableSubscription; |
| + DownloadableSubscription.prototype = |
| + { |
| + __proto__: RegularSubscription.prototype, |
| + _downloadStatus: null, |
| + _lastCheck: 0, |
| + _errors: 0, |
| + nextURL: null, |
| + get downloadStatus() |
| + { |
| + return this._downloadStatus; |
| + }, |
| + set downloadStatus(value) |
| + { |
| + var oldValue = this._downloadStatus; |
| + this._downloadStatus = value; |
| + FilterNotifier.triggerListeners("subscription.downloadStatus", this, value, oldValue); |
| + return this._downloadStatus; |
| + }, |
| + lastModified: null, |
| + lastSuccess: 0, |
| + get lastCheck() |
| + { |
| + return this._lastCheck; |
| + }, |
| + set lastCheck(value) |
| + { |
| + if (value != this._lastCheck) |
| + { |
| + var oldValue = this._lastCheck; |
| + this._lastCheck = value; |
| + FilterNotifier.triggerListeners("subscription.lastCheck", this, value, oldValue); |
| + } |
| + return this._lastCheck; |
| + }, |
| + expires: 0, |
| + softExpiration: 0, |
| + get errors() |
| + { |
| + return this._errors; |
| + }, |
| + set errors(value) |
| + { |
| + if (value != this._errors) |
| + { |
| + var oldValue = this._errors; |
| + this._errors = value; |
| + FilterNotifier.triggerListeners("subscription.errors", this, value, oldValue); |
| + } |
| + return this._errors; |
| + }, |
| + requiredVersion: null, |
| + upgradeRequired: false, |
| + alternativeLocations: null, |
| + serialize: function(buffer) |
| + { |
| + RegularSubscription.prototype.serialize.call(this, buffer); |
| + if (this.nextURL) |
| + { |
| + buffer.push("nextURL=" + this.nextURL); |
| + } |
| + if (this.downloadStatus) |
| + { |
| + buffer.push("downloadStatus=" + this.downloadStatus); |
| + } |
| + if (this.lastModified) |
| + { |
| + buffer.push("lastModified=" + this.lastModified); |
| + } |
| + 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.requiredVersion) |
| + { |
| + buffer.push("requiredVersion=" + this.requiredVersion); |
| + } |
| + if (this.alternativeLocations) |
| + { |
| + buffer.push("alternativeLocations=" + this.alternativeLocations); |
| + } |
| + } |
| + }; |
| + return exports; |
| +})(); |
| +require.scopes["filterStorage"] = (function() |
| +{ |
| + var exports = {}; |
| + var IO = require("io").IO; |
| + var Prefs = require("prefs").Prefs; |
| + var _tempVar7 = require("filterClasses"); |
| + var Filter = _tempVar7.Filter; |
| + var ActiveFilter = _tempVar7.ActiveFilter; |
| + var _tempVar8 = require("subscriptionClasses"); |
| + var Subscription = _tempVar8.Subscription; |
| + var SpecialSubscription = _tempVar8.SpecialSubscription; |
| + var ExternalSubscription = _tempVar8.ExternalSubscription; |
| + var FilterNotifier = require("filterNotifier").FilterNotifier; |
| + var formatVersion = 4; |
| + var FilterStorage = exports.FilterStorage = |
| + { |
| + get formatVersion() |
| + { |
| + return formatVersion; |
| + }, |
| + get sourceFile() |
| + { |
| + var file = null; |
| + if (Prefs.patternsfile) |
| + { |
| + file = IO.resolveFilePath(Prefs.patternsfile); |
| + } |
| + if (!file) |
| + { |
| + file = IO.resolveFilePath(Prefs.data_directory); |
| + if (file) |
| + { |
| + file.append("patterns.ini"); |
| + } |
| + } |
| + if (!file) |
| + { |
| + try |
| + { |
| + file = IO.resolveFilePath(Services.prefs.getDefaultBranch("extensions.adblockplus.").getCharPref("data_directory")); |
| + if (file) |
| + { |
| + file.append("patterns.ini"); |
| + } |
| + } |
| + catch (e){} |
| + } |
| + if (!file) |
| + { |
| + Cu.reportError("Adblock Plus: Failed to resolve filter file location from extensions.adblockplus.patternsfile preference"); |
| + } |
| + this.__defineGetter__("sourceFile", function() |
| + { |
| + return file; |
| + }); |
| + return this.sourceFile; |
| + }, |
| + fileProperties: |
| + { |
| + __proto__: null |
| + }, |
| + subscriptions: [], |
| + knownSubscriptions: |
| + { |
| + __proto__: null |
| + }, |
| + getGroupForFilter: function(filter) |
| + { |
| + var generalSubscription = null; |
| + for (var _loopIndex9 = 0; _loopIndex9 < FilterStorage.subscriptions.length; ++_loopIndex9) |
| + { |
| + var subscription = FilterStorage.subscriptions[_loopIndex9]; |
| + if (subscription instanceof SpecialSubscription && !subscription.disabled) |
| + { |
| + if (subscription.isDefaultFor(filter)) |
| + { |
| + return subscription; |
| + } |
| + if (!generalSubscription && (!subscription.defaults || !subscription.defaults.length)) |
| + { |
| + generalSubscription = subscription; |
| + } |
| + } |
| + } |
| + return generalSubscription; |
| + }, |
| + addSubscription: function(subscription, silent) |
| + { |
| + if (subscription.url in FilterStorage.knownSubscriptions) |
| + { |
| + return; |
| + } |
| + FilterStorage.subscriptions.push(subscription); |
| + FilterStorage.knownSubscriptions[subscription.url] = subscription; |
| + addSubscriptionFilters(subscription); |
| + if (!silent) |
| + { |
| + FilterNotifier.triggerListeners("subscription.added", subscription); |
| + } |
| + }, |
| + removeSubscription: function(subscription, silent) |
| + { |
| + for (var 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]; |
| + if (!silent) |
| + { |
| + FilterNotifier.triggerListeners("subscription.removed", subscription); |
| + } |
| + return; |
| + } |
| + } |
| + }, |
| + moveSubscription: function(subscription, insertBefore) |
| + { |
| + var currentPos = FilterStorage.subscriptions.indexOf(subscription); |
| + if (currentPos < 0) |
| + { |
| + return; |
| + } |
| + var newPos = insertBefore ? FilterStorage.subscriptions.indexOf(insertBefore) : -1; |
| + 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); |
| + }, |
| + updateSubscriptionFilters: function(subscription, filters) |
| + { |
| + removeSubscriptionFilters(subscription); |
| + subscription.oldFilters = subscription.filters; |
| + subscription.filters = filters; |
| + addSubscriptionFilters(subscription); |
| + FilterNotifier.triggerListeners("subscription.updated", subscription); |
| + delete subscription.oldFilters; |
| + }, |
| + addFilter: function(filter, subscription, position, silent) |
| + { |
| + if (!subscription) |
| + { |
| + if (filter.subscriptions.some(function(s) |
| + { |
| + return s instanceof SpecialSubscription && !s.disabled; |
| + })) |
| + { |
| + return; |
| + } |
| + subscription = FilterStorage.getGroupForFilter(filter); |
| + } |
| + if (!subscription) |
| + { |
| + 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); |
| + if (!silent) |
| + { |
| + FilterNotifier.triggerListeners("filter.added", filter, subscription, position); |
| + } |
| + }, |
| + removeFilter: function(filter, subscription, position) |
| + { |
| + var subscriptions = subscription ? [subscription] : filter.subscriptions.slice(); |
| + for (var i = 0; i < subscriptions.length; i++) |
| + { |
| + var subscription = subscriptions[i]; |
| + if (subscription instanceof SpecialSubscription) |
| + { |
| + var positions = []; |
| + if (typeof position == "undefined") |
| + { |
| + var index = -1; |
| + do |
| + { |
| + index = subscription.filters.indexOf(filter, index + 1); |
| + if (index >= 0) |
| + { |
| + positions.push(index); |
| + } |
| + } |
| + while (index >= 0); |
| + } |
| + else |
| + { |
| + positions.push(position); |
| + } |
| + for (var j = positions.length - 1; j >= 0; j--) |
| + { |
| + var position = positions[j]; |
| + if (subscription.filters[position] == filter) |
| + { |
| + subscription.filters.splice(position, 1); |
| + if (subscription.filters.indexOf(filter) < 0) |
| + { |
| + var index = filter.subscriptions.indexOf(subscription); |
| + if (index >= 0) |
| + { |
| + filter.subscriptions.splice(index, 1); |
| + } |
| + } |
| + FilterNotifier.triggerListeners("filter.removed", filter, subscription, position); |
| + } |
| + } |
| + } |
| + } |
| + }, |
| + moveFilter: function(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); |
| + }, |
| + increaseHitCount: function(filter) |
| + { |
| + if (!Prefs.savestats || PrivateBrowsing.enabled || !(filter instanceof ActiveFilter)) |
| + { |
| + return; |
| + } |
| + filter.hitCount++; |
| + filter.lastHit = Date.now(); |
| + }, |
| + resetHitCounts: function(filters) |
| + { |
| + if (!filters) |
| + { |
| + filters = []; |
| + for (var text in Filter.knownFilters) |
| + { |
| + filters.push(Filter.knownFilters[text]); |
| + } |
| + } |
| + for (var _loopIndex10 = 0; _loopIndex10 < filters.length; ++_loopIndex10) |
| + { |
| + var filter = filters[_loopIndex10]; |
| + filter.hitCount = 0; |
| + filter.lastHit = 0; |
| + } |
| + }, |
| + _loading: false, |
| + loadFromDisk: function(sourceFile) |
| + { |
| + if (this._loading) |
| + { |
| + return; |
| + } |
| + var readFile = function(sourceFile, backupIndex) |
| + { |
| + var parser = new INIParser(); |
| + IO.readFromFile(sourceFile, true, parser, function(e) |
| + { |
| + if (!e && parser.subscriptions.length == 0) |
| + { |
| + e = new Error("No data in the file"); |
| + } |
| + if (e) |
| + { |
| + Cu.reportError(e); |
| + } |
| + if (e && !explicitFile) |
| + { |
| + sourceFile = this.sourceFile; |
| + if (sourceFile) |
| + { |
| + var _tempVar11 = /^(.*)(\.\w+)$/.exec(sourceFile.leafName) || [null, sourceFile.leafName, ""]; |
| + var part1 = _tempVar11[1]; |
| + var part2 = _tempVar11[2]; |
| + sourceFile = sourceFile.clone(); |
| + sourceFile.leafName = part1 + "-backup" + ++backupIndex + part2; |
| + IO.statFile(sourceFile, function(e, statData) |
| + { |
| + if (!e && statData.exists) |
| + { |
| + readFile(sourceFile, backupIndex); |
| + } |
| + }); |
| + return; |
| + } |
| + } |
| + var specialMap = |
| + { |
| + "~il~": true, |
| + "~wl~": true, |
| + "~fl~": true, |
| + "~eh~": true |
| + }; |
| + var knownSubscriptions = |
| + { |
| + __proto__: null |
| + }; |
| + for (var i = 0; i < parser.subscriptions.length; i++) |
| + { |
| + var subscription = parser.subscriptions[i]; |
| + if (subscription instanceof SpecialSubscription && subscription.filters.length == 0 && subscription.url in specialMap) |
| + { |
| + parser.subscriptions.splice(i--, 1); |
| + } |
| + else |
| + { |
| + knownSubscriptions[subscription.url] = subscription; |
| + } |
| + } |
| + this.fileProperties = parser.fileProperties; |
| + this.subscriptions = parser.subscriptions; |
| + this.knownSubscriptions = knownSubscriptions; |
| + Filter.knownFilters = parser.knownFilters; |
| + Subscription.knownSubscriptions = parser.knownSubscriptions; |
| + if (parser.userFilters) |
| + { |
| + for (var i = 0; i < parser.userFilters.length; i++) |
| + { |
| + var filter = Filter.fromText(parser.userFilters[i]); |
| + this.addFilter(filter, null, undefined, true); |
| + } |
| + } |
| + this._loading = false; |
| + FilterNotifier.triggerListeners("load"); |
| + if (sourceFile != this.sourceFile) |
| + { |
| + this.saveToDisk(); |
| + } |
| + }.bind(this), "FilterStorageRead"); |
| + }.bind(this); |
| + var startRead = function(file) |
| + { |
| + this._loading = true; |
| + readFile(file, 0); |
| + }.bind(this); |
| + var explicitFile; |
| + if (sourceFile) |
| + { |
| + explicitFile = true; |
| + startRead(sourceFile); |
| + } |
| + else |
| + { |
| + explicitFile = false; |
| + sourceFile = FilterStorage.sourceFile; |
| + var callback = function(e, statData) |
| + { |
| + if (e || !statData.exists) |
| + { |
| + var addonRoot = require("info").addonRoot; |
| + sourceFile = Services.io.newURI(addonRoot + "defaults/patterns.ini", null, null); |
| + } |
| + startRead(sourceFile); |
| + }; |
| + if (sourceFile) |
| + { |
| + IO.statFile(sourceFile, callback); |
| + } |
| + else |
| + { |
| + callback(true); |
| + } |
| + } |
| + }, |
| + _generateFilterData: function(subscriptions) |
| + { |
| + var _generatorResult12 = []; |
| + _generatorResult12.push("# Adblock Plus preferences"); |
| + _generatorResult12.push("version=" + formatVersion); |
| + var saved = |
| + { |
| + __proto__: null |
| + }; |
| + var buf = []; |
| + for (var i = 0; i < subscriptions.length; i++) |
| + { |
| + var subscription = subscriptions[i]; |
| + for (var j = 0; j < subscription.filters.length; j++) |
| + { |
| + var filter = subscription.filters[j]; |
| + if (!(filter.text in saved)) |
| + { |
| + filter.serialize(buf); |
| + saved[filter.text] = filter; |
| + for (var k = 0; k < buf.length; k++) |
| + { |
| + _generatorResult12.push(buf[k]); |
| + } |
| + buf.splice(0); |
| + } |
| + } |
| + } |
| + for (var i = 0; i < subscriptions.length; i++) |
| + { |
| + var subscription = subscriptions[i]; |
| + _generatorResult12.push(""); |
| + subscription.serialize(buf); |
| + if (subscription.filters.length) |
| + { |
| + buf.push("", "[Subscription filters]"); |
| + subscription.serializeFilters(buf); |
| + } |
| + for (var k = 0; k < buf.length; k++) |
| + { |
| + _generatorResult12.push(buf[k]); |
| + } |
| + buf.splice(0); |
| + } |
| + return _generatorResult12; |
| + }, |
| + _saving: false, |
| + _needsSave: false, |
| + saveToDisk: function(targetFile) |
| + { |
| + var explicitFile = true; |
| + if (!targetFile) |
| + { |
| + targetFile = FilterStorage.sourceFile; |
| + explicitFile = false; |
| + } |
| + if (!targetFile) |
| + { |
| + return; |
| + } |
| + if (!explicitFile && this._saving) |
| + { |
| + this._needsSave = true; |
| + return; |
| + } |
| + try |
| + { |
| + targetFile.parent.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); |
| + } |
| + catch (e){} |
| + var writeFilters = function() |
| + { |
| + IO.writeToFile(targetFile, true, this._generateFilterData(subscriptions), function(e) |
| + { |
| + if (!explicitFile) |
| + { |
| + this._saving = false; |
| + } |
| + if (e) |
| + { |
| + Cu.reportError(e); |
| + } |
| + if (!explicitFile && this._needsSave) |
| + { |
| + this._needsSave = false; |
| + this.saveToDisk(); |
| + } |
| + else |
| + { |
| + FilterNotifier.triggerListeners("save"); |
| + } |
| + }.bind(this), "FilterStorageWrite"); |
| + }.bind(this); |
| + var checkBackupRequired = function(callbackNotRequired, callbackRequired) |
| + { |
| + if (explicitFile || Prefs.patternsbackups <= 0) |
| + { |
| + callbackNotRequired(); |
| + } |
| + else |
| + { |
| + IO.statFile(targetFile, function(e, statData) |
| + { |
| + if (e || !statData.exists) |
| + { |
| + callbackNotRequired(); |
| + } |
| + else |
| + { |
| + var _tempVar13 = /^(.*)(\.\w+)$/.exec(targetFile.leafName) || [null, targetFile.leafName, ""]; |
| + var part1 = _tempVar13[1]; |
| + var part2 = _tempVar13[2]; |
| + var newestBackup = targetFile.clone(); |
| + newestBackup.leafName = part1 + "-backup1" + part2; |
| + IO.statFile(newestBackup, function(e, statData) |
| + { |
| + if (!e && (!statData.exists || (Date.now() - statData.lastModified) / 3600000 >= Prefs.patternsbackupinterval)) |
| + { |
| + callbackRequired(part1, part2); |
| + } |
| + else |
| + { |
| + callbackNotRequired(); |
| + } |
| + }); |
| + } |
| + }); |
| + } |
| + }.bind(this); |
| + var removeLastBackup = function(part1, part2) |
| + { |
| + var file = targetFile.clone(); |
| + file.leafName = part1 + "-backup" + Prefs.patternsbackups + part2; |
| + IO.removeFile(file, function(e) |
| + { |
| + return renameBackup(part1, part2, Prefs.patternsbackups - 1); |
| + }); |
| + }.bind(this); |
| + var renameBackup = function(part1, part2, index) |
| + { |
| + if (index > 0) |
| + { |
| + var fromFile = targetFile.clone(); |
| + fromFile.leafName = part1 + "-backup" + index + part2; |
| + var toName = part1 + "-backup" + (index + 1) + part2; |
| + IO.renameFile(fromFile, toName, function(e) |
| + { |
| + return renameBackup(part1, part2, index - 1); |
| + }); |
| + } |
| + else |
| + { |
| + var toFile = targetFile.clone(); |
| + toFile.leafName = part1 + "-backup" + (index + 1) + part2; |
| + IO.copyFile(targetFile, toFile, writeFilters); |
| + } |
| + }.bind(this); |
| + var subscriptions = this.subscriptions.filter(function(s) |
| + { |
| + return !(s instanceof ExternalSubscription); |
| + }); |
| + if (!explicitFile) |
| + { |
| + this._saving = true; |
| + } |
| + checkBackupRequired(writeFilters, removeLastBackup); |
| + }, |
| + getBackupFiles: function() |
| + { |
| + var result = []; |
| + var _tempVar14 = /^(.*)(\.\w+)$/.exec(FilterStorage.sourceFile.leafName) || [null, FilterStorage.sourceFile.leafName, ""]; |
| + var part1 = _tempVar14[1]; |
| + var part2 = _tempVar14[2]; |
| + for (var i = 1;; i++) |
| + { |
| + var file = FilterStorage.sourceFile.clone(); |
| + file.leafName = part1 + "-backup" + i + part2; |
| + if (file.exists()) |
| + { |
| + result.push(file); |
| + } |
| + else |
| + { |
| + break; |
| + } |
| + } |
| + return result; |
| + } |
| + }; |
| + |
| + function addSubscriptionFilters(subscription) |
| + { |
| + if (!(subscription.url in FilterStorage.knownSubscriptions)) |
| + { |
| + return; |
| + } |
| + for (var _loopIndex15 = 0; _loopIndex15 < subscription.filters.length; ++_loopIndex15) |
| + { |
| + var filter = subscription.filters[_loopIndex15]; |
| + filter.subscriptions.push(subscription); |
| + } |
| + } |
| + |
| + function removeSubscriptionFilters(subscription) |
| + { |
| + if (!(subscription.url in FilterStorage.knownSubscriptions)) |
| + { |
| + return; |
| + } |
| + for (var _loopIndex16 = 0; _loopIndex16 < subscription.filters.length; ++_loopIndex16) |
| + { |
| + var filter = subscription.filters[_loopIndex16]; |
| + var i = filter.subscriptions.indexOf(subscription); |
| + if (i >= 0) |
| + { |
| + filter.subscriptions.splice(i, 1); |
| + } |
| + } |
| + } |
| + var PrivateBrowsing = exports.PrivateBrowsing = |
| + { |
| + enabled: false, |
| + init: function() |
| + { |
| + if ("@mozilla.org/privatebrowsing;1" in Cc) |
| + { |
| + try |
| + { |
| + this.enabled = Cc["@mozilla.org/privatebrowsing;1"].getService(Ci.nsIPrivateBrowsingService).privateBrowsingEnabled; |
| + Services.obs.addObserver(this, "private-browsing", true); |
| + onShutdown.add(function() |
| + { |
| + Services.obs.removeObserver(this, "private-browsing"); |
| + }.bind(this)); |
| + } |
| + catch (e) |
| + { |
| + Cu.reportError(e); |
| + } |
| + } |
| + }, |
| + observe: function(subject, topic, data) |
| + { |
| + if (topic == "private-browsing") |
| + { |
| + if (data == "enter") |
| + { |
| + this.enabled = true; |
| + } |
| + else if (data == "exit") |
| + { |
| + this.enabled = false; |
| + } |
| + } |
| + }, |
| + QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference, Ci.nsIObserver]) |
| + }; |
| + PrivateBrowsing.init(); |
| + |
| + function INIParser() |
| + { |
| + this.fileProperties = this.curObj = {}; |
| + this.subscriptions = []; |
| + this.knownFilters = |
| + { |
| + __proto__: null |
| + }; |
| + this.knownSubscriptions = |
| + { |
| + __proto__: null |
| + }; |
| + } |
| + INIParser.prototype = |
| + { |
| + subscriptions: null, |
| + knownFilters: null, |
| + knownSubscrptions: null, |
| + wantObj: true, |
| + fileProperties: null, |
| + curObj: null, |
| + curSection: null, |
| + userFilters: null, |
| + process: function(val) |
| + { |
| + var origKnownFilters = Filter.knownFilters; |
| + Filter.knownFilters = this.knownFilters; |
| + var origKnownSubscriptions = Subscription.knownSubscriptions; |
| + Subscription.knownSubscriptions = this.knownSubscriptions; |
| + var 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) |
| + { |
| + switch (this.curSection) |
| + { |
| + case "filter": |
| + case "pattern": |
| + if ("text" in this.curObj) |
| + { |
| + Filter.fromObject(this.curObj); |
| + } |
| + break; |
| + case "subscription": |
| + var subscription = Subscription.fromObject(this.curObj); |
| + if (subscription) |
| + { |
| + this.subscriptions.push(subscription); |
| + } |
| + break; |
| + case "subscription filters": |
| + case "subscription patterns": |
| + if (this.subscriptions.length) |
| + { |
| + var subscription = this.subscriptions[this.subscriptions.length - 1]; |
| + for (var _loopIndex17 = 0; _loopIndex17 < this.curObj.length; ++_loopIndex17) |
| + { |
| + var text = this.curObj[_loopIndex17]; |
| + var filter = Filter.fromText(text); |
| + subscription.filters.push(filter); |
| + filter.subscriptions.push(subscription); |
| + } |
| + } |
| + break; |
| + case "user patterns": |
| + this.userFilters = this.curObj; |
| + break; |
| + } |
| + } |
| + if (val === null) |
| + { |
| + return; |
| + } |
| + this.curSection = match[1].toLowerCase(); |
| + switch (this.curSection) |
| + { |
| + case "filter": |
| + case "pattern": |
| + case "subscription": |
| + this.wantObj = true; |
| + this.curObj = {}; |
| + break; |
| + case "subscription filters": |
| + case "subscription patterns": |
| + case "user patterns": |
| + 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; |
| + } |
| + } |
| + }; |
| + return exports; |
| +})(); |
| +require.scopes["elemHide"] = (function() |
| +{ |
| + var exports = {}; |
| + var Utils = require("utils").Utils; |
| + var IO = require("io").IO; |
| + var Prefs = require("prefs").Prefs; |
| + var ElemHideException = require("filterClasses").ElemHideException; |
| + var FilterNotifier = require("filterNotifier").FilterNotifier; |
| + var AboutHandler = require("elemHideHitRegistration").AboutHandler; |
| + var filterByKey = |
| + { |
| + __proto__: null |
| + }; |
| + var keyByFilter = |
| + { |
| + __proto__: null |
| + }; |
| + var knownExceptions = |
| + { |
| + __proto__: null |
| + }; |
| + var exceptions = |
| + { |
| + __proto__: null |
| + }; |
| + var styleURL = null; |
| + var ElemHide = exports.ElemHide = |
| + { |
| + isDirty: false, |
| + applied: false, |
| + init: function() |
| + { |
| + Prefs.addListener(function(name) |
| + { |
| + if (name == "enabled") |
| + { |
| + ElemHide.apply(); |
| + } |
| + }); |
| + onShutdown.add(function() |
| + { |
| + ElemHide.unapply(); |
| + }); |
| + var styleFile = IO.resolveFilePath(Prefs.data_directory); |
| + styleFile.append("elemhide.css"); |
| + styleURL = Services.io.newFileURI(styleFile).QueryInterface(Ci.nsIFileURL); |
| + }, |
| + clear: function() |
| + { |
| + filterByKey = |
| + { |
| + __proto__: null |
| + }; |
| + keyByFilter = |
| + { |
| + __proto__: null |
| + }; |
| + knownExceptions = |
| + { |
| + __proto__: null |
| + }; |
| + exceptions = |
| + { |
| + __proto__: null |
| + }; |
| + ElemHide.isDirty = false; |
| + ElemHide.unapply(); |
| + }, |
| + add: function(filter) |
| + { |
| + if (filter instanceof ElemHideException) |
| + { |
| + if (filter.text in knownExceptions) |
| + { |
| + return; |
| + } |
| + var selector = filter.selector; |
| + if (!(selector in exceptions)) |
| + { |
| + exceptions[selector] = []; |
| + } |
| + exceptions[selector].push(filter); |
| + knownExceptions[filter.text] = true; |
| + } |
| + else |
| + { |
| + if (filter.text in keyByFilter) |
| + { |
| + return; |
| + } |
| + var key; |
| + do |
| + { |
| + key = Math.random().toFixed(15).substr(5); |
| + } |
| + while (key in filterByKey); |
| + filterByKey[key] = filter; |
| + keyByFilter[filter.text] = key; |
| + ElemHide.isDirty = true; |
| + } |
| + }, |
| + remove: function(filter) |
| + { |
| + if (filter instanceof ElemHideException) |
| + { |
| + if (!(filter.text in knownExceptions)) |
| + { |
| + return; |
| + } |
| + var list = exceptions[filter.selector]; |
| + var index = list.indexOf(filter); |
| + if (index >= 0) |
| + { |
| + list.splice(index, 1); |
| + } |
| + delete knownExceptions[filter.text]; |
| + } |
| + else |
| + { |
| + if (!(filter.text in keyByFilter)) |
| + { |
| + return; |
| + } |
| + var key = keyByFilter[filter.text]; |
| + delete filterByKey[key]; |
| + delete keyByFilter[filter.text]; |
| + ElemHide.isDirty = true; |
| + } |
| + }, |
| + getException: function(filter, docDomain) |
| + { |
| + var selector = filter.selector; |
| + if (!(filter.selector in exceptions)) |
| + { |
| + return null; |
| + } |
| + var list = exceptions[filter.selector]; |
| + for (var i = list.length - 1; i >= 0; i--) |
| + { |
| + if (list[i].isActiveOnDomain(docDomain)) |
| + { |
| + return list[i]; |
| + } |
| + } |
| + return null; |
| + }, |
| + _applying: false, |
| + _needsApply: false, |
| + apply: function() |
| + { |
| + if (this._applying) |
| + { |
| + this._needsApply = true; |
| + return; |
| + } |
| + if (!ElemHide.isDirty || !Prefs.enabled) |
| + { |
| + if (Prefs.enabled && !ElemHide.applied) |
| + { |
| + try |
| + { |
| + Utils.styleService.loadAndRegisterSheet(styleURL, Ci.nsIStyleSheetService.USER_SHEET); |
| + ElemHide.applied = true; |
| + } |
| + catch (e) |
| + { |
| + Cu.reportError(e); |
| + } |
| + } |
| + else if (!Prefs.enabled && ElemHide.applied) |
| + { |
| + ElemHide.unapply(); |
| + } |
| + return; |
| + } |
| + IO.writeToFile(styleURL.file, false, this._generateCSSContent(), function(e) |
| + { |
| + this._applying = false; |
| + if (e && e.result == Cr.NS_ERROR_NOT_AVAILABLE) |
| + { |
| + IO.removeFile(styleURL.file, function(e2){}); |
| + } |
| + else if (e) |
| + { |
| + Cu.reportError(e); |
| + } |
| + if (this._needsApply) |
| + { |
| + this._needsApply = false; |
| + this.apply(); |
| + } |
| + else if (!e || e.result == Cr.NS_ERROR_NOT_AVAILABLE) |
| + { |
| + ElemHide.isDirty = false; |
| + ElemHide.unapply(); |
| + if (!e) |
| + { |
| + try |
| + { |
| + Utils.styleService.loadAndRegisterSheet(styleURL, Ci.nsIStyleSheetService.USER_SHEET); |
| + ElemHide.applied = true; |
| + } |
| + catch (e) |
| + { |
| + Cu.reportError(e); |
| + } |
| + } |
| + FilterNotifier.triggerListeners("elemhideupdate"); |
| + } |
| + }.bind(this), "ElemHideWrite"); |
| + this._applying = true; |
| + }, |
| + _generateCSSContent: function() |
| + { |
| + var _generatorResult12 = []; |
| + var domains = |
| + { |
| + __proto__: null |
| + }; |
| + var hasFilters = false; |
| + for (var key in filterByKey) |
| + { |
| + var filter = filterByKey[key]; |
| + var domain = filter.selectorDomain || ""; |
| + var list; |
| + if (domain in domains) |
| + { |
| + list = domains[domain]; |
| + } |
| + else |
| + { |
| + list = |
| + { |
| + __proto__: null |
| + }; |
| + domains[domain] = list; |
| + } |
| + list[filter.selector] = key; |
| + hasFilters = true; |
| + } |
| + if (!hasFilters) |
| + { |
| + throw Cr.NS_ERROR_NOT_AVAILABLE; |
| + } |
| + |
| + function escapeChar(match) |
| + { |
| + return "\\" + match.charCodeAt(0).toString(16) + " "; |
| + } |
| + var cssTemplate = "-moz-binding: url(about:" + AboutHandler.aboutPrefix + "?%ID%#dummy) !important;"; |
| + for (var domain in domains) |
| + { |
| + var rules = []; |
| + var list = domains[domain]; |
| + if (domain) |
| + { |
| + _generatorResult12.push(("@-moz-document domain(\"" + domain.split(",").join("\"),domain(\"") + "\"){").replace(/[^\x01-\x7F]/g, escapeChar)); |
| + } |
| + else |
| + { |
| + _generatorResult12.push("@-moz-document url-prefix(\"http://\"),url-prefix(\"https://\"),url-prefix(\"mailbox://\"),url-prefix(\"imap://\"),url-prefix(\"news://\"),url-prefix(\"snews://\"){"); |
| + } |
| + for (var selector in list) |
| + { |
| + _generatorResult12.push(selector.replace(/[^\x01-\x7F]/g, escapeChar) + "{" + cssTemplate.replace("%ID%", list[selector]) + "}"); |
| + } |
| + _generatorResult12.push("}"); |
| + } |
| + return _generatorResult12; |
| + }, |
| + unapply: function() |
| + { |
| + if (ElemHide.applied) |
| + { |
| + try |
| + { |
| + Utils.styleService.unregisterSheet(styleURL, Ci.nsIStyleSheetService.USER_SHEET); |
| + } |
| + catch (e) |
| + { |
| + Cu.reportError(e); |
| + } |
| + ElemHide.applied = false; |
| + } |
| + }, |
| + get styleURL() |
| + { |
| + return ElemHide.applied ? styleURL.spec : null; |
| + }, |
| + getFilterByKey: function(key) |
| + { |
| + return key in filterByKey ? filterByKey[key] : null; |
| + }, |
| + getSelectorsForDomain: function(domain, specificOnly) |
| + { |
| + var result = []; |
| + for (var key in filterByKey) |
| + { |
| + var filter = filterByKey[key]; |
| + if (specificOnly && (!filter.domains || filter.domains[""])) |
| + { |
| + continue; |
| + } |
| + if (filter.isActiveOnDomain(domain) && !this.getException(filter, domain)) |
| + { |
| + result.push(filter.selector); |
| + } |
| + } |
| + return result; |
| + } |
| + }; |
| + return exports; |
| +})(); |
| +require.scopes["filterListener"] = (function() |
| +{ |
| + var exports = {}; |
| + var FilterStorage = require("filterStorage").FilterStorage; |
| + var FilterNotifier = require("filterNotifier").FilterNotifier; |
| + var ElemHide = require("elemHide").ElemHide; |
| + var defaultMatcher = require("matcher").defaultMatcher; |
| + var _tempVar18 = require("filterClasses"); |
| + var ActiveFilter = _tempVar18.ActiveFilter; |
| + var RegExpFilter = _tempVar18.RegExpFilter; |
| + var ElemHideBase = _tempVar18.ElemHideBase; |
| + var Prefs = require("prefs").Prefs; |
| + var batchMode = false; |
| + var isDirty = 0; |
| + var FilterListener = exports.FilterListener = |
| + { |
| + get batchMode() |
| + { |
| + return batchMode; |
| + }, |
| + set batchMode(value) |
| + { |
| + batchMode = value; |
| + flushElemHide(); |
| + }, |
| + setDirty: function(factor) |
| + { |
| + if (factor == 0 && isDirty > 0) |
| + { |
| + isDirty = 1; |
| + } |
| + else |
| + { |
| + isDirty += factor; |
| + } |
| + if (isDirty >= 1) |
| + { |
| + FilterStorage.saveToDisk(); |
| + } |
| + } |
| + }; |
| + var HistoryPurgeObserver = |
| + { |
| + observe: function(subject, topic, data) |
| + { |
| + if (topic == "browser:purge-session-history" && Prefs.clearStatsOnHistoryPurge) |
| + { |
| + FilterStorage.resetHitCounts(); |
| + FilterListener.setDirty(0); |
| + Prefs.recentReports = []; |
| + } |
| + }, |
| + QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference, Ci.nsIObserver]) |
| + }; |
| + |
| + function init() |
| + { |
| + FilterNotifier.addListener(function(action, item, newValue, oldValue) |
| + { |
| + var match = /^(\w+)\.(.*)/.exec(action); |
| + if (match && match[1] == "filter") |
| + { |
| + onFilterChange(match[2], item, newValue, oldValue); |
| + } |
| + else if (match && match[1] == "subscription") |
| + { |
| + onSubscriptionChange(match[2], item, newValue, oldValue); |
| + } |
| + else |
| + { |
| + onGenericChange(action, item); |
| + } |
| + }); |
| + var application = require("info").application; |
| + if (application == "chrome" || application == "opera") |
| + { |
| + flushElemHide = function(){}; |
| + } |
| + else |
| + { |
| + ElemHide.init(); |
| + } |
| + FilterStorage.loadFromDisk(); |
| + Services.obs.addObserver(HistoryPurgeObserver, "browser:purge-session-history", true); |
| + onShutdown.add(function() |
| + { |
| + Services.obs.removeObserver(HistoryPurgeObserver, "browser:purge-session-history"); |
| + }); |
| + } |
| + init(); |
| + |
| + function flushElemHide() |
| + { |
| + if (!batchMode && ElemHide.isDirty) |
| + { |
| + ElemHide.apply(); |
| + } |
| + } |
| + |
| + function addFilter(filter) |
| + { |
| + if (!(filter instanceof ActiveFilter) || filter.disabled) |
| + { |
| + return; |
| + } |
| + var hasEnabled = false; |
| + for (var 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) |
| + { |
| + ElemHide.add(filter); |
| + } |
| + } |
| + |
| + function removeFilter(filter) |
| + { |
| + if (!(filter instanceof ActiveFilter)) |
| + { |
| + return; |
| + } |
| + if (!filter.disabled) |
| + { |
| + var hasEnabled = false; |
| + for (var 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) |
| + { |
| + ElemHide.remove(filter); |
| + } |
| + } |
| + |
| + function onSubscriptionChange(action, subscription, newValue, oldValue) |
| + { |
| + FilterListener.setDirty(1); |
| + if (action != "added" && action != "removed" && action != "disabled" && action != "updated") |
| + { |
| + return; |
| + } |
| + if (action != "removed" && !(subscription.url in FilterStorage.knownSubscriptions)) |
| + { |
| + return; |
| + } |
| + if ((action == "added" || action == "removed" || action == "updated") && subscription.disabled) |
| + { |
| + return; |
| + } |
| + if (action == "added" || action == "removed" || action == "disabled") |
| + { |
| + var method = action == "added" || action == "disabled" && newValue == false ? addFilter : removeFilter; |
| + if (subscription.filters) |
| + { |
| + subscription.filters.forEach(method); |
| + } |
| + } |
| + else if (action == "updated") |
| + { |
| + subscription.oldFilters.forEach(removeFilter); |
| + subscription.filters.forEach(addFilter); |
| + } |
| + flushElemHide(); |
| + } |
| + |
| + function onFilterChange(action, filter, newValue, oldValue) |
| + { |
| + if (action == "hitCount" || action == "lastHit") |
| + { |
| + FilterListener.setDirty(0.002); |
| + } |
| + else |
| + { |
| + FilterListener.setDirty(1); |
| + } |
| + if (action != "added" && action != "removed" && action != "disabled") |
| + { |
| + return; |
| + } |
| + if ((action == "added" || action == "removed") && filter.disabled) |
| + { |
| + return; |
| + } |
| + if (action == "added" || action == "disabled" && newValue == false) |
| + { |
| + addFilter(filter); |
| + } |
| + else |
| + { |
| + removeFilter(filter); |
| + } |
| + flushElemHide(); |
| + } |
| + |
| + function onGenericChange(action) |
| + { |
| + if (action == "load") |
| + { |
| + isDirty = 0; |
| + defaultMatcher.clear(); |
| + ElemHide.clear(); |
| + for (var _loopIndex19 = 0; _loopIndex19 < FilterStorage.subscriptions.length; ++_loopIndex19) |
| + { |
| + var subscription = FilterStorage.subscriptions[_loopIndex19]; |
| + if (!subscription.disabled) |
| + { |
| + subscription.filters.forEach(addFilter); |
| + } |
| + } |
| + flushElemHide(); |
| + } |
| + else if (action == "save") |
| + { |
| + isDirty = 0; |
| + } |
| + } |
| + return exports; |
| +})(); |
| +require.scopes["synchronizer"] = (function() |
| +{ |
| + var exports = {}; |
| + var Utils = require("utils").Utils; |
| + var FilterStorage = require("filterStorage").FilterStorage; |
| + var FilterNotifier = require("filterNotifier").FilterNotifier; |
| + var Prefs = require("prefs").Prefs; |
| + var _tempVar20 = require("filterClasses"); |
| + var Filter = _tempVar20.Filter; |
| + var CommentFilter = _tempVar20.CommentFilter; |
| + var _tempVar21 = require("subscriptionClasses"); |
| + var Subscription = _tempVar21.Subscription; |
| + var DownloadableSubscription = _tempVar21.DownloadableSubscription; |
| + var MILLISECONDS_IN_SECOND = 1000; |
| + var SECONDS_IN_MINUTE = 60; |
| + var SECONDS_IN_HOUR = 60 * SECONDS_IN_MINUTE; |
| + var SECONDS_IN_DAY = 24 * SECONDS_IN_HOUR; |
| + var INITIAL_DELAY = 6 * SECONDS_IN_MINUTE; |
| + var CHECK_INTERVAL = SECONDS_IN_HOUR; |
| + var MIN_EXPIRATION_INTERVAL = 1 * SECONDS_IN_DAY; |
| + var MAX_EXPIRATION_INTERVAL = 14 * SECONDS_IN_DAY; |
| + var MAX_ABSENSE_INTERVAL = 1 * SECONDS_IN_DAY; |
| + var timer = null; |
| + var executing = |
| + { |
| + __proto__: null |
| + }; |
| + var Synchronizer = exports.Synchronizer = |
| + { |
| + init: function() |
| + { |
| + var callback = function() |
| + { |
| + timer.delay = CHECK_INTERVAL * MILLISECONDS_IN_SECOND; |
| + checkSubscriptions(); |
| + }; |
| + timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); |
| + timer.initWithCallback(callback, INITIAL_DELAY * MILLISECONDS_IN_SECOND, Ci.nsITimer.TYPE_REPEATING_SLACK); |
| + onShutdown.add(function() |
| + { |
| + timer.cancel(); |
| + }); |
| + }, |
| + isExecuting: function(url) |
| + { |
| + return url in executing; |
| + }, |
| + execute: function(subscription, manual, forceDownload) |
| + { |
| + Utils.runAsync(this.executeInternal, this, subscription, manual, forceDownload); |
| + }, |
| + executeInternal: function(subscription, manual, forceDownload) |
| + { |
| + var url = subscription.url; |
| + if (url in executing) |
| + { |
| + return; |
| + } |
| + var newURL = subscription.nextURL; |
| + var hadTemporaryRedirect = false; |
| + subscription.nextURL = null; |
| + var loadFrom = newURL; |
| + var isBaseLocation = true; |
| + if (!loadFrom) |
| + { |
| + loadFrom = url; |
| + } |
| + if (loadFrom == url) |
| + { |
| + if (subscription.alternativeLocations) |
| + { |
| + var options = [ |
| + [1, url] |
| + ]; |
| + var totalWeight = 1; |
| + for (var _loopIndex22 = 0; _loopIndex22 < subscription.alternativeLocations.split(",").length; ++_loopIndex22) |
| + { |
| + var alternative = subscription.alternativeLocations.split(",")[_loopIndex22]; |
| + if (!/^https?:\/\//.test(alternative)) |
| + { |
| + continue; |
| + } |
| + var weight = 1; |
| + var match = /;q=([\d\.]+)$/.exec(alternative); |
| + if (match) |
| + { |
| + weight = parseFloat(match[1]); |
| + if (isNaN(weight) || !isFinite(weight) || weight < 0) |
| + { |
| + weight = 1; |
| + } |
| + if (weight > 10) |
| + { |
| + weight = 10; |
| + } |
| + alternative = alternative.substr(0, match.index); |
| + } |
| + options.push([weight, alternative]); |
| + totalWeight += weight; |
| + } |
| + var choice = Math.random() * totalWeight; |
| + for (var _loopIndex23 = 0; _loopIndex23 < options.length; ++_loopIndex23) |
| + { |
| + var _tempVar24 = options[_loopIndex23]; |
| + var weight = _tempVar24[0]; |
| + var alternative = _tempVar24[1]; |
| + choice -= weight; |
| + if (choice < 0) |
| + { |
| + loadFrom = alternative; |
| + break; |
| + } |
| + } |
| + isBaseLocation = loadFrom == url; |
| + } |
| + } |
| + else |
| + { |
| + forceDownload = true; |
| + } |
| + var addonVersion = require("info").addonVersion; |
| + loadFrom = loadFrom.replace(/%VERSION%/, "ABP" + addonVersion); |
| + var request = null; |
| + |
| + function errorCallback(error) |
| + { |
| + var channelStatus = -1; |
| + try |
| + { |
| + channelStatus = request.channel.status; |
| + } |
| + catch (e){} |
| + var responseStatus = ""; |
| + try |
| + { |
| + responseStatus = request.channel.QueryInterface(Ci.nsIHttpChannel).responseStatus; |
| + } |
| + catch (e){} |
| + setError(subscription, error, channelStatus, responseStatus, loadFrom, isBaseLocation, manual); |
| + } |
| + try |
| + { |
| + request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest); |
| + request.mozBackgroundRequest = true; |
| + request.open("GET", loadFrom); |
| + } |
| + 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; |
| + if (request.channel instanceof Ci.nsIHttpChannel) |
| + { |
| + request.channel.redirectionLimit = 5; |
| + } |
| + var oldNotifications = request.channel.notificationCallbacks; |
| + var oldEventSink = null; |
| + request.channel.notificationCallbacks = |
| + { |
| + QueryInterface: XPCOMUtils.generateQI([Ci.nsIInterfaceRequestor, Ci.nsIChannelEventSink]), |
| + getInterface: function(iid) |
| + { |
| + if (iid.equals(Ci.nsIChannelEventSink)) |
| + { |
| + try |
| + { |
| + oldEventSink = oldNotifications.QueryInterface(iid); |
| + } |
| + catch (e){} |
| + return this; |
| + } |
| + if (oldNotifications) |
| + { |
| + return oldNotifications.QueryInterface(iid); |
| + } |
| + else |
| + { |
| + throw Cr.NS_ERROR_NO_INTERFACE; |
| + } |
| + }, |
| + asyncOnChannelRedirect: function(oldChannel, newChannel, flags, callback) |
| + { |
| + if (isBaseLocation && !hadTemporaryRedirect && oldChannel instanceof Ci.nsIHttpChannel) |
| + { |
| + try |
| + { |
| + subscription.alternativeLocations = oldChannel.getResponseHeader("X-Alternative-Locations"); |
| + } |
| + catch (e) |
| + { |
| + subscription.alternativeLocations = null; |
| + } |
| + } |
| + if (flags & Ci.nsIChannelEventSink.REDIRECT_TEMPORARY) |
| + { |
| + hadTemporaryRedirect = true; |
| + } |
| + else if (!hadTemporaryRedirect) |
| + { |
| + newURL = newChannel.URI.spec; |
| + } |
| + if (oldEventSink) |
| + { |
| + oldEventSink.asyncOnChannelRedirect(oldChannel, newChannel, flags, callback); |
| + } |
| + else |
| + { |
| + callback.onRedirectVerifyCallback(Cr.NS_OK); |
| + } |
| + } |
| + }; |
| + } |
| + catch (e) |
| + { |
| + Cu.reportError(e); |
| + } |
| + if (subscription.lastModified && !forceDownload) |
| + { |
| + request.setRequestHeader("If-Modified-Since", subscription.lastModified); |
| + } |
| + request.addEventListener("error", function(ev) |
| + { |
| + if (onShutdown.done) |
| + { |
| + return; |
| + } |
| + delete executing[url]; |
| + try |
| + { |
| + request.channel.notificationCallbacks = null; |
| + } |
| + catch (e){} |
| + errorCallback("synchronize_connection_error"); |
| + }, false); |
| + request.addEventListener("load", function(ev) |
| + { |
| + if (onShutdown.done) |
| + { |
| + return; |
| + } |
| + delete executing[url]; |
| + try |
| + { |
| + request.channel.notificationCallbacks = null; |
| + } |
| + catch (e){} |
| + if (request.status && request.status != 200 && request.status != 304) |
| + { |
| + errorCallback("synchronize_connection_error"); |
| + return; |
| + } |
| + var newFilters = null; |
| + if (request.status != 304) |
| + { |
| + newFilters = readFilters(subscription, request.responseText, errorCallback); |
| + if (!newFilters) |
| + { |
| + return; |
| + } |
| + subscription.lastModified = request.getResponseHeader("Last-Modified"); |
| + } |
| + if (isBaseLocation && !hadTemporaryRedirect) |
| + { |
| + subscription.alternativeLocations = request.getResponseHeader("X-Alternative-Locations"); |
| + } |
| + subscription.lastSuccess = subscription.lastDownload = Math.round(Date.now() / MILLISECONDS_IN_SECOND); |
| + subscription.downloadStatus = "synchronize_ok"; |
| + subscription.errors = 0; |
| + var now = Math.round(((new Date(request.getResponseHeader("Date"))).getTime() || Date.now()) / MILLISECONDS_IN_SECOND); |
| + var expires = Math.round((new Date(request.getResponseHeader("Expires"))).getTime() / MILLISECONDS_IN_SECOND) || 0; |
| + var expirationInterval = expires ? expires - now : 0; |
| + for (var _loopIndex25 = 0; _loopIndex25 < (newFilters || subscription.filters).length; ++_loopIndex25) |
| + { |
| + var filter = (newFilters || subscription.filters)[_loopIndex25]; |
| + if (!(filter instanceof CommentFilter)) |
| + { |
| + continue; |
| + } |
| + var match = /\bExpires\s*(?::|after)\s*(\d+)\s*(h)?/i.exec(filter.text); |
| + if (match) |
| + { |
| + var interval = parseInt(match[1], 10); |
| + if (match[2]) |
| + { |
| + interval *= SECONDS_IN_HOUR; |
| + } |
| + else |
| + { |
| + interval *= SECONDS_IN_DAY; |
| + } |
| + if (interval > expirationInterval) |
| + { |
| + expirationInterval = interval; |
| + } |
| + } |
| + } |
| + expirationInterval = Math.min(Math.max(expirationInterval, MIN_EXPIRATION_INTERVAL), MAX_EXPIRATION_INTERVAL); |
| + subscription.expires = subscription.lastDownload + expirationInterval * 2; |
| + subscription.softExpiration = subscription.lastDownload + Math.round(expirationInterval * (Math.random() * 0.4 + 0.8)); |
| + if (newFilters) |
| + { |
| + var fixedTitle = false; |
| + for (var i = 0; i < newFilters.length; i++) |
| + { |
| + var filter = newFilters[i]; |
| + if (!(filter instanceof CommentFilter)) |
| + { |
| + continue; |
| + } |
| + var match = /^!\s*(\w+)\s*:\s*(.*)/.exec(filter.text); |
| + if (match) |
| + { |
| + var keyword = match[1].toLowerCase(); |
| + var value = match[2]; |
| + var known = true; |
| + if (keyword == "redirect") |
| + { |
| + if (isBaseLocation && value != url) |
| + { |
| + subscription.nextURL = value; |
| + } |
| + } |
| + else if (keyword == "homepage") |
| + { |
| + var uri = Utils.makeURI(value); |
| + if (uri && (uri.scheme == "http" || uri.scheme == "https")) |
| + { |
| + subscription.homepage = uri.spec; |
| + } |
| + } |
| + else if (keyword == "title") |
| + { |
| + if (value) |
| + { |
| + subscription.title = value; |
| + fixedTitle = true; |
| + } |
| + } |
| + else |
| + { |
| + known = false; |
| + } |
| + if (known) |
| + { |
| + newFilters.splice(i--, 1); |
| + } |
| + } |
| + } |
| + subscription.fixedTitle = fixedTitle; |
| + } |
| + if (isBaseLocation && newURL && newURL != url) |
| + { |
| + var listed = subscription.url in FilterStorage.knownSubscriptions; |
| + if (listed) |
| + { |
| + FilterStorage.removeSubscription(subscription); |
| + } |
| + url = newURL; |
| + var newSubscription = Subscription.fromURL(url); |
| + for (var key in newSubscription) |
| + { |
| + delete newSubscription[key]; |
| + } |
| + for (var key in subscription) |
| + { |
| + newSubscription[key] = subscription[key]; |
| + } |
| + delete Subscription.knownSubscriptions[subscription.url]; |
| + newSubscription.oldSubscription = subscription; |
| + subscription = newSubscription; |
| + subscription.url = url; |
| + if (!(subscription.url in FilterStorage.knownSubscriptions) && listed) |
| + { |
| + FilterStorage.addSubscription(subscription); |
| + } |
| + } |
| + if (newFilters) |
| + { |
| + FilterStorage.updateSubscriptionFilters(subscription, newFilters); |
| + } |
| + delete subscription.oldSubscription; |
| + }, false); |
| + executing[url] = true; |
| + FilterNotifier.triggerListeners("subscription.downloadStatus", subscription); |
| + try |
| + { |
| + request.send(null); |
| + } |
| + catch (e) |
| + { |
| + delete executing[url]; |
| + errorCallback("synchronize_connection_error"); |
| + return; |
| + } |
| + } |
| + }; |
| + Synchronizer.init(); |
| + |
| + function checkSubscriptions() |
| + { |
| + if (!Prefs.subscriptions_autoupdate) |
| + { |
| + return; |
| + } |
| + var time = Math.round(Date.now() / MILLISECONDS_IN_SECOND); |
| + for (var _loopIndex26 = 0; _loopIndex26 < FilterStorage.subscriptions.length; ++_loopIndex26) |
| + { |
| + var subscription = FilterStorage.subscriptions[_loopIndex26]; |
| + if (!(subscription instanceof DownloadableSubscription)) |
| + { |
| + continue; |
| + } |
| + if (subscription.lastCheck && time - subscription.lastCheck > MAX_ABSENSE_INTERVAL) |
| + { |
| + subscription.softExpiration += time - subscription.lastCheck; |
| + } |
| + subscription.lastCheck = time; |
| + if (subscription.expires - time > MAX_EXPIRATION_INTERVAL) |
| + { |
| + subscription.expires = time + MAX_EXPIRATION_INTERVAL; |
| + } |
| + if (subscription.softExpiration - time > MAX_EXPIRATION_INTERVAL) |
| + { |
| + subscription.softExpiration = time + MAX_EXPIRATION_INTERVAL; |
| + } |
| + if (subscription.softExpiration > time && subscription.expires > time) |
| + { |
| + continue; |
| + } |
| + if (time - subscription.lastDownload >= MIN_EXPIRATION_INTERVAL) |
| + { |
| + Synchronizer.execute(subscription, false); |
| + } |
| + } |
| + } |
| + |
| + function readFilters(subscription, text, errorCallback) |
| + { |
| + var lines = text.split(/[\r\n]+/); |
| + var match = /\[Adblock(?:\s*Plus\s*([\d\.]+)?)?\]/i.exec(lines[0]); |
| + if (!match) |
| + { |
| + errorCallback("synchronize_invalid_data"); |
| + return null; |
| + } |
| + var minVersion = match[1]; |
| + for (var i = 0; i < lines.length; i++) |
| + { |
| + var match = /!\s*checksum[\s\-:]+([\w\+\/]+)/i.exec(lines[i]); |
| + if (match) |
| + { |
| + lines.splice(i, 1); |
| + var checksum = Utils.generateChecksum(lines); |
| + if (checksum && checksum != match[1]) |
| + { |
| + errorCallback("synchronize_checksum_mismatch"); |
| + return null; |
| + } |
| + break; |
| + } |
| + } |
| + delete subscription.requiredVersion; |
| + delete subscription.upgradeRequired; |
| + if (minVersion) |
| + { |
| + var addonVersion = require("info").addonVersion; |
| + subscription.requiredVersion = minVersion; |
| + if (Services.vc.compare(minVersion, addonVersion) > 0) |
| + { |
| + subscription.upgradeRequired = true; |
| + } |
| + } |
| + lines.shift(); |
| + var result = []; |
| + for (var _loopIndex27 = 0; _loopIndex27 < lines.length; ++_loopIndex27) |
| + { |
| + var line = lines[_loopIndex27]; |
| + line = Filter.normalize(line); |
| + if (line) |
| + { |
| + result.push(Filter.fromText(line)); |
| + } |
| + } |
| + return result; |
| + } |
| + |
| + function setError(subscription, error, channelStatus, responseStatus, downloadURL, isBaseLocation, manual) |
| + { |
| + if (!isBaseLocation) |
| + { |
| + subscription.alternativeLocations = null; |
| + } |
| + try |
| + { |
| + Cu.reportError("Adblock Plus: Downloading filter subscription " + subscription.title + " failed (" + Utils.getString(error) + ")\n" + "Download address: " + downloadURL + "\n" + "Channel status: " + channelStatus + "\n" + "Server response: " + responseStatus); |
| + } |
| + catch (e){} |
| + subscription.lastDownload = Math.round(Date.now() / MILLISECONDS_IN_SECOND); |
| + subscription.downloadStatus = error; |
| + if (!manual) |
| + { |
| + if (error == "synchronize_checksum_mismatch") |
| + { |
| + subscription.errors = 0; |
| + } |
| + else |
| + { |
| + subscription.errors++; |
| + } |
| + if (subscription.errors >= Prefs.subscriptions_fallbackerrors && /^https?:\/\//i.test(subscription.url)) |
| + { |
| + subscription.errors = 0; |
| + var fallbackURL = Prefs.subscriptions_fallbackurl; |
| + var addonVersion = require("info").addonVersion; |
| + 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)); |
| + var request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest); |
| + 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", function(ev) |
| + { |
| + if (onShutdown.done) |
| + { |
| + return; |
| + } |
| + if (!(subscription.url in FilterStorage.knownSubscriptions)) |
| + { |
| + return; |
| + } |
| + var match = /^(\d+)(?:\s+(\S+))?$/.exec(request.responseText); |
| + if (match && match[1] == "301" && match[2]) |
| + { |
| + subscription.nextURL = match[2]; |
| + } |
| + else if (match && match[1] == "410") |
| + { |
| + var data = "[Adblock]\n" + subscription.filters.map(function(f) |
| + { |
| + return f.text; |
| + }).join("\n"); |
| + var url = "data:text/plain," + encodeURIComponent(data); |
| + var newSubscription = Subscription.fromURL(url); |
| + newSubscription.title = subscription.title; |
| + newSubscription.disabled = subscription.disabled; |
| + FilterStorage.removeSubscription(subscription); |
| + FilterStorage.addSubscription(newSubscription); |
| + Synchronizer.execute(newSubscription); |
| + } |
| + }, false); |
| + request.send(null); |
| + } |
| + } |
| + } |
| + return exports; |
| +})(); |