| Index: lib/rules.js |
| =================================================================== |
| --- a/lib/rules.js |
| +++ b/lib/rules.js |
| @@ -4,16 +4,18 @@ |
| Cu.import("resource://gre/modules/Services.jsm"); |
| Cu.import("resource://gre/modules/FileUtils.jsm"); |
| let {Prefs} = require("prefs"); |
| let RULES_VERSION = 2; |
| +let CUSTOM_RULE_PRIORITY = 0x7FFFFFFF; |
| + |
| let rules = {expressions: []}; |
| loadRules(); |
| // Make first attempt to update rules after five minutes |
| let updateTimer = null; |
| updateTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); |
| updateTimer.initWithCallback(onTimer, 1000 * 60 * 5, Ci.nsITimer.TYPE_REPEATING_SLACK); |
| @@ -41,16 +43,20 @@ function loadRulesFrom(url, ignoreVersio |
| try |
| { |
| // Remove comments from the file if any |
| let data = JSON.parse(request.responseText.replace(/^\s*\/\/.*/mg, "")); |
| if (ignoreVersion || data.version == RULES_VERSION) |
| { |
| rules = data; |
| callback(true); |
| + |
| + // Add user-defined rules after calling the callback - if the callback |
| + // saves the rules then the custom rules won't be included. |
| + addCustomRules(); |
| } |
| else |
| callback(false); |
| } |
| catch (e) |
| { |
| Cu.reportError(e); |
| callback(false); |
| @@ -76,38 +82,127 @@ function loadRulesFrom(url, ignoreVersio |
| function getRuleFile() |
| { |
| let result = FileUtils.getFile("ProfD", ["url-fixer-rules.json"]); |
| getRuleFile = function() result; |
| return getRuleFile(); |
| } |
| +function addCustomRules() |
| +{ |
| + for (let domain in Prefs.whitelist) |
| + onWhitelistEntryAdded(domain); |
| +} |
| + |
| +function onWhitelistEntryAdded(domain) |
| +{ |
| + let reverse = Array.prototype.slice.call(domain).reverse().join(""); |
|
Thomas Greiner
2012/09/26 15:59:35
also in onWhitelistEntryAdded function
|
| + addSuffix(rules.domain, reverse, CUSTOM_RULE_PRIORITY); |
| +} |
| +exports.onWhitelistEntryAdded = onWhitelistEntryAdded; |
| + |
| +function onWhitelistEntryRemoved(domain) |
| +{ |
| + let reverse = Array.prototype.slice.call(domain).reverse().join(""); |
|
Thomas Greiner
2012/09/26 15:49:13
It looks less confusing if you do it this way:
le
Wladimir Palant
2012/09/27 14:55:06
domain is a string - string.slice() returns anothe
|
| + removeSuffix(rules.domain, reverse, CUSTOM_RULE_PRIORITY); |
| +} |
| +exports.onWhitelistEntryRemoved = onWhitelistEntryRemoved; |
| + |
| +function addSuffix(tree, suffix, priority) |
| +{ |
| + if (suffix.length == 0) |
| + { |
| + // We are at the last character, just put our priority here |
| + tree[""] = " " + priority; |
| + return; |
| + } |
| + |
| + let c = suffix[0]; |
| + if (c in tree) |
| + { |
| + let existing = tree[c]; |
| + if (typeof existing == "string") |
| + { |
| + // Single choice for this suffix, maybe the same entry? |
| + if (existing.substr(0, suffix.length - 1) == suffix.substr(1) && existing[suffix.length - 1] == " ") |
| + { |
| + // Same entry, simply replace it by new priority |
| + tree[c] = suffix.substr(1) + " " + priority; |
| + } |
| + else |
| + { |
| + // Different entry, need to add a new branching point and go deeper |
| + if (existing[0] == " ") |
| + tree[c] = {"": existing}; |
| + else |
| + { |
| + tree[c] = {}; |
| + tree[c][existing[0]] = existing.substr(1); |
| + } |
| + addSuffix(tree[c], suffix.substr(1), priority); |
| + } |
| + } |
| + else |
| + { |
| + // Multiple choices for this suffix - go deeper |
| + addSuffix(existing, suffix.substr(1), priority); |
| + } |
| + } |
| + else |
| + { |
| + // No existing entry yet, just add ours |
| + tree[c] = suffix.substr(1) + " " + priority; |
| + } |
| +} |
| + |
| +function removeSuffix(tree, suffix, priority) |
| +{ |
| + if (suffix.length == 0) |
| + { |
| + // We are at the last character, check whether there is an entry with |
| + // matching priority |
| + if ("" in tree && tree[""] == " " + priority) |
| + delete tree[""]; |
| + return; |
| + } |
| + |
| + let c = suffix[0]; |
| + if (!(c in tree)) |
| + return; |
| + |
| + if (typeof tree[c] == "string") |
| + { |
| + // Single entry - check whether it is the right one |
| + if (tree[c] == suffix.substr(1) + " " + priority) |
| + delete tree[c]; |
| + } |
| + else |
| + { |
| + // Multiple entries, need to go deeper |
| + removeSuffix(tree[c], suffix.substr(1), priority); |
| + } |
| +} |
| + |
| function onTimer() |
| { |
| // Next check in 1 hour |
| updateTimer.delay = 1000 * 60 * 60; |
| // Only download rules every three days |
| let nextUpdate = Prefs.lastRuleUpdate + 60 * 60 * 24 * 3; |
| if (nextUpdate > Date.now() / 1000) |
| return; |
| loadRulesFrom("http://urlfixer.org/download/rules.json?version=" + RULES_VERSION, false, function(success) |
| { |
| if (success) |
| { |
| rules.timestamp = Date.now(); |
| - var dynRules = require("updateRules").updateRules(); |
| - for(var i in dynRules) |
| - { |
| - rules[i] = dynRules[i]; |
| - } |
| - |
| try |
| { |
| // Save the rules to file. |
| let rulesText = JSON.stringify(rules); |
| let fileStream = FileUtils.openSafeFileOutputStream(getRuleFile()); |
| let stream = Cc["@mozilla.org/intl/converter-output-stream;1"].createInstance(Ci.nsIConverterOutputStream); |
| stream.init(fileStream, "UTF-8", 16384, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); |
| stream.writeString(rulesText); |
| @@ -145,23 +240,16 @@ function getDomainCorrection(domain) |
| { |
| let replacement = customRules[searchString]; |
| searchString = searchString.toLowerCase(); |
| if (/^re:+/.test(searchString)) |
| domain = domain.replace(new RegExp(RegExp.rightContext, "g"), replacement); |
| else |
| domain = domain.replace(searchString, replacement); |
| } |
| - |
| - // Apply user's whitelist |
| - let whitelist = Prefs.whitelist; |
| - if (whitelist.hasOwnProperty(domain) || /^www\./.test(domain) && whitelist.hasOwnProperty(domain.substr(4))) |
| - { |
| - return domain; |
| - } |
| // Now apply our rules on the domain name |
| for (let i = 0, l = rules.expressions.length; i < l; i++) |
| domain = applyExpression(domain, rules.expressions[i]); |
| // Find similar known domains, test domains without the www. prefix |
| if (domain.substr(0, 4) == "www.") |
| domain = "www." + getBestMatch(domain.substr(4), rules.domain, 1, "."); |