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, "."); |