LEFT | RIGHT |
1 /* This Source Code Form is subject to the terms of the Mozilla Public | 1 /* This Source Code Form is subject to the terms of the Mozilla Public |
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, | 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ | 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | 4 |
5 Cu.import("resource://gre/modules/Services.jsm"); | 5 Cu.import("resource://gre/modules/Services.jsm"); |
6 Cu.import("resource://gre/modules/FileUtils.jsm"); | 6 Cu.import("resource://gre/modules/FileUtils.jsm"); |
7 | 7 |
8 let {Prefs} = require("prefs"); | 8 let {Prefs} = require("prefs"); |
9 | 9 |
10 let RULES_VERSION = 2; | 10 let RULES_VERSION = 2; |
| 11 |
| 12 let CUSTOM_RULE_PRIORITY = 0x7FFFFFFF; |
11 | 13 |
12 let rules = {expressions: []}; | 14 let rules = {expressions: []}; |
13 | 15 |
14 loadRules(); | 16 loadRules(); |
15 | 17 |
16 // Make first attempt to update rules after five minutes | 18 // Make first attempt to update rules after five minutes |
17 let updateTimer = null; | 19 let updateTimer = null; |
18 updateTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); | 20 updateTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); |
19 updateTimer.initWithCallback(onTimer, 1000 * 60 * 5, Ci.nsITimer.TYPE_REPEATING_
SLACK); | 21 updateTimer.initWithCallback(onTimer, 1000 * 60 * 5, Ci.nsITimer.TYPE_REPEATING_
SLACK); |
20 onShutdown.add(function() updateTimer.cancel()); | 22 onShutdown.add(function() updateTimer.cancel()); |
(...skipping 18 matching lines...) Expand all Loading... |
39 request.addEventListener("load", function() | 41 request.addEventListener("load", function() |
40 { | 42 { |
41 try | 43 try |
42 { | 44 { |
43 // Remove comments from the file if any | 45 // Remove comments from the file if any |
44 let data = JSON.parse(request.responseText.replace(/^\s*\/\/.*/mg, "")); | 46 let data = JSON.parse(request.responseText.replace(/^\s*\/\/.*/mg, "")); |
45 if (ignoreVersion || data.version == RULES_VERSION) | 47 if (ignoreVersion || data.version == RULES_VERSION) |
46 { | 48 { |
47 rules = data; | 49 rules = data; |
48 callback(true); | 50 callback(true); |
| 51 |
| 52 // Add user-defined rules after calling the callback - if the callback |
| 53 // saves the rules then the custom rules won't be included. |
| 54 addCustomRules(); |
49 } | 55 } |
50 else | 56 else |
51 callback(false); | 57 callback(false); |
52 } | 58 } |
53 catch (e) | 59 catch (e) |
54 { | 60 { |
55 Cu.reportError(e); | 61 Cu.reportError(e); |
56 callback(false); | 62 callback(false); |
57 } | 63 } |
58 }, false); | 64 }, false); |
(...skipping 13 matching lines...) Expand all Loading... |
72 callback(false); | 78 callback(false); |
73 } | 79 } |
74 } | 80 } |
75 | 81 |
76 function getRuleFile() | 82 function getRuleFile() |
77 { | 83 { |
78 let result = FileUtils.getFile("ProfD", ["url-fixer-rules.json"]); | 84 let result = FileUtils.getFile("ProfD", ["url-fixer-rules.json"]); |
79 | 85 |
80 getRuleFile = function() result; | 86 getRuleFile = function() result; |
81 return getRuleFile(); | 87 return getRuleFile(); |
| 88 } |
| 89 |
| 90 function addCustomRules() |
| 91 { |
| 92 for (let domain in Prefs.whitelist) |
| 93 onWhitelistEntryAdded(domain); |
| 94 } |
| 95 |
| 96 function onWhitelistEntryAdded(domain) |
| 97 { |
| 98 let reverse = domain.split("").reverse().join(""); |
| 99 addSuffix(rules.domain, reverse, CUSTOM_RULE_PRIORITY); |
| 100 } |
| 101 exports.onWhitelistEntryAdded = onWhitelistEntryAdded; |
| 102 |
| 103 function onWhitelistEntryRemoved(domain) |
| 104 { |
| 105 let reverse = domain.split("").reverse().join(""); |
| 106 removeSuffix(rules.domain, reverse, CUSTOM_RULE_PRIORITY); |
| 107 } |
| 108 exports.onWhitelistEntryRemoved = onWhitelistEntryRemoved; |
| 109 |
| 110 function addSuffix(tree, suffix, priority) |
| 111 { |
| 112 if (suffix.length == 0) |
| 113 { |
| 114 // We are at the last character, just put our priority here |
| 115 tree[""] = " " + priority; |
| 116 return; |
| 117 } |
| 118 |
| 119 let c = suffix[0]; |
| 120 if (c in tree) |
| 121 { |
| 122 let existing = tree[c]; |
| 123 if (typeof existing == "string") |
| 124 { |
| 125 // Single choice for this suffix, maybe the same entry? |
| 126 if (existing.substr(0, suffix.length - 1) == suffix.substr(1) && existing[
suffix.length - 1] == " ") |
| 127 { |
| 128 // Same entry, simply replace it by new priority |
| 129 tree[c] = suffix.substr(1) + " " + priority; |
| 130 } |
| 131 else |
| 132 { |
| 133 // Different entry, need to add a new branching point and go deeper |
| 134 if (existing[0] == " ") |
| 135 tree[c] = {"": existing}; |
| 136 else |
| 137 { |
| 138 tree[c] = {}; |
| 139 tree[c][existing[0]] = existing.substr(1); |
| 140 } |
| 141 addSuffix(tree[c], suffix.substr(1), priority); |
| 142 } |
| 143 } |
| 144 else |
| 145 { |
| 146 // Multiple choices for this suffix - go deeper |
| 147 addSuffix(existing, suffix.substr(1), priority); |
| 148 } |
| 149 } |
| 150 else |
| 151 { |
| 152 // No existing entry yet, just add ours |
| 153 tree[c] = suffix.substr(1) + " " + priority; |
| 154 } |
| 155 } |
| 156 |
| 157 function removeSuffix(tree, suffix, priority) |
| 158 { |
| 159 if (suffix.length == 0) |
| 160 { |
| 161 // We are at the last character, check whether there is an entry with |
| 162 // matching priority |
| 163 if ("" in tree && tree[""] == " " + priority) |
| 164 delete tree[""]; |
| 165 return; |
| 166 } |
| 167 |
| 168 let c = suffix[0]; |
| 169 if (!(c in tree)) |
| 170 return; |
| 171 |
| 172 if (typeof tree[c] == "string") |
| 173 { |
| 174 // Single entry - check whether it is the right one |
| 175 if (tree[c] == suffix.substr(1) + " " + priority) |
| 176 delete tree[c]; |
| 177 } |
| 178 else |
| 179 { |
| 180 // Multiple entries, need to go deeper |
| 181 removeSuffix(tree[c], suffix.substr(1), priority); |
| 182 } |
82 } | 183 } |
83 | 184 |
84 function onTimer() | 185 function onTimer() |
85 { | 186 { |
86 // Next check in 1 hour | 187 // Next check in 1 hour |
87 updateTimer.delay = 1000 * 60 * 60; | 188 updateTimer.delay = 1000 * 60 * 60; |
88 | 189 |
89 // Only download rules every three days | 190 // Only download rules every three days |
90 let nextUpdate = Prefs.lastRuleUpdate + 60 * 60 * 24 * 3; | 191 let nextUpdate = Prefs.lastRuleUpdate + 60 * 60 * 24 * 3; |
91 if (nextUpdate > Date.now() / 1000) | 192 if (nextUpdate > Date.now() / 1000) |
92 return; | 193 return; |
93 | 194 |
94 loadRulesFrom("http://urlfixer.org/download/rules.json?version=" + RULES_VERSI
ON, false, function(success) | 195 loadRulesFrom("http://urlfixer.org/download/rules.json?version=" + RULES_VERSI
ON, false, function(success) |
95 { | 196 { |
96 if (success) | 197 if (success) |
97 { | 198 { |
98 rules.timestamp = Date.now(); | 199 rules.timestamp = Date.now(); |
99 | |
100 var dynRules = require("updateRules").updateRules(); | |
101 for(var i in dynRules) | |
102 { | |
103 rules[i] = dynRules[i]; | |
104 } | |
105 | 200 |
106 try | 201 try |
107 { | 202 { |
108 // Save the rules to file. | 203 // Save the rules to file. |
109 let rulesText = JSON.stringify(rules); | 204 let rulesText = JSON.stringify(rules); |
110 let fileStream = FileUtils.openSafeFileOutputStream(getRuleFile()); | 205 let fileStream = FileUtils.openSafeFileOutputStream(getRuleFile()); |
111 let stream = Cc["@mozilla.org/intl/converter-output-stream;1"].createIns
tance(Ci.nsIConverterOutputStream); | 206 let stream = Cc["@mozilla.org/intl/converter-output-stream;1"].createIns
tance(Ci.nsIConverterOutputStream); |
112 stream.init(fileStream, "UTF-8", 16384, Ci.nsIConverterInputStream.DEFAU
LT_REPLACEMENT_CHARACTER); | 207 stream.init(fileStream, "UTF-8", 16384, Ci.nsIConverterInputStream.DEFAU
LT_REPLACEMENT_CHARACTER); |
113 stream.writeString(rulesText); | 208 stream.writeString(rulesText); |
114 stream.flush(); | 209 stream.flush(); |
(...skipping 27 matching lines...) Expand all Loading... |
142 // Apply user's custom changes first | 237 // Apply user's custom changes first |
143 let customRules = Prefs.custom_replace; | 238 let customRules = Prefs.custom_replace; |
144 for (let searchString in customRules) | 239 for (let searchString in customRules) |
145 { | 240 { |
146 let replacement = customRules[searchString]; | 241 let replacement = customRules[searchString]; |
147 searchString = searchString.toLowerCase(); | 242 searchString = searchString.toLowerCase(); |
148 if (/^re:+/.test(searchString)) | 243 if (/^re:+/.test(searchString)) |
149 domain = domain.replace(new RegExp(RegExp.rightContext, "g"), replacement)
; | 244 domain = domain.replace(new RegExp(RegExp.rightContext, "g"), replacement)
; |
150 else | 245 else |
151 domain = domain.replace(searchString, replacement); | 246 domain = domain.replace(searchString, replacement); |
152 } | |
153 | |
154 // Apply user's whitelist | |
155 let whitelist = Prefs.whitelist; | |
156 if (whitelist.hasOwnProperty(domain) || /^www\./.test(domain) && whitelist.has
OwnProperty(domain.substr(4))) | |
157 { | |
158 return domain; | |
159 } | 247 } |
160 | 248 |
161 // Now apply our rules on the domain name | 249 // Now apply our rules on the domain name |
162 for (let i = 0, l = rules.expressions.length; i < l; i++) | 250 for (let i = 0, l = rules.expressions.length; i < l; i++) |
163 domain = applyExpression(domain, rules.expressions[i]); | 251 domain = applyExpression(domain, rules.expressions[i]); |
164 | 252 |
165 // Find similar known domains, test domains without the www. prefix | 253 // Find similar known domains, test domains without the www. prefix |
166 if (domain.substr(0, 4) == "www.") | 254 if (domain.substr(0, 4) == "www.") |
167 domain = "www." + getBestMatch(domain.substr(4), rules.domain, 1, "."); | 255 domain = "www." + getBestMatch(domain.substr(4), rules.domain, 1, "."); |
168 else | 256 else |
169 domain = getBestMatch(domain, rules.domain, 1, "."); | 257 domain = getBestMatch(domain, rules.domain, 1, "."); |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
312 bestSuggestionDistance = distance; | 400 bestSuggestionDistance = distance; |
313 bestSuggestionMatched = matchedLen; | 401 bestSuggestionMatched = matchedLen; |
314 bestSuggestionPriority = priority; | 402 bestSuggestionPriority = priority; |
315 } | 403 } |
316 } | 404 } |
317 if (bestSuggestion) | 405 if (bestSuggestion) |
318 return input.substr(0, input.length - bestSuggestionMatched) + bestSuggestio
n; | 406 return input.substr(0, input.length - bestSuggestionMatched) + bestSuggestio
n; |
319 else | 407 else |
320 return input; | 408 return input; |
321 } | 409 } |
LEFT | RIGHT |