Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: lib/adblockplus.js

Issue 9846017: Make JavaScript sources compile into the library; convert JavaScript files on the fly (Closed)
Patch Set: Review comments addressed Created March 15, 2013, 3:59 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « include/AdblockPlus/JsEngine.h ('k') | lib/compat.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * This file is part of the Adblock Plus extension,
3 * Copyright (C) 2006-2012 Eyeo GmbH
4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation.
8 *
9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 //
19 // This file has been generated automatically from Adblock Plus for Firefox
20 // source code. DO NOT MODIFY, change the original source code instead.
21 //
22 // Relevant repositories:
23 // * https://hg.adblockplus.org/adblockplus/
24 // * https://hg.adblockplus.org/jshydra/
25 //
26
27 require.scopes["filterNotifier"] = (function()
28 {
29 var exports = {};
30 var listeners = [];
31 var FilterNotifier = exports.FilterNotifier =
32 {
33 addListener: function(listener)
34 {
35 if (listeners.indexOf(listener) >= 0)
36 {
37 return;
38 }
39 listeners.push(listener);
40 },
41 removeListener: function(listener)
42 {
43 var index = listeners.indexOf(listener);
44 if (index >= 0)
45 {
46 listeners.splice(index, 1);
47 }
48 },
49 triggerListeners: function(action, item, param1, param2, param3)
50 {
51 for (var _loopIndex0 = 0; _loopIndex0 < listeners.length; ++_loopIndex0)
52 {
53 var listener = listeners[_loopIndex0];
54 listener(action, item, param1, param2, param3);
55 }
56 }
57 };
58 return exports;
59 })();
60 require.scopes["filterClasses"] = (function()
61 {
62 var exports = {};
63 var FilterNotifier = require("filterNotifier").FilterNotifier;
64
65 function Filter(text)
66 {
67 this.text = text;
68 this.subscriptions = [];
69 }
70 exports.Filter = Filter;
71 Filter.prototype =
72 {
73 text: null,
74 subscriptions: null,
75 serialize: function(buffer)
76 {
77 buffer.push("[Filter]");
78 buffer.push("text=" + this.text);
79 },
80 toString: function()
81 {
82 return this.text;
83 }
84 };
85 Filter.knownFilters =
86 {
87 __proto__: null
88 };
89 Filter.elemhideRegExp = /^([^\/\*\|\@"!]*?)#(\@)?(?:([\w\-]+|\*)((?:\([\w\-]+( ?:[$^*]?=[^\(\)"]*)?\))*)|#([^{}]+))$/;
90 Filter.regexpRegExp = /^(@@)?\/.*\/(?:\$~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?: =[^,\s]+)?)*)?$/;
91 Filter.optionsRegExp = /\$(~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[^,\s]+)?)*) $/;
92 Filter.fromText = function(text)
93 {
94 if (text in Filter.knownFilters)
95 {
96 return Filter.knownFilters[text];
97 }
98 var ret;
99 var match = text.indexOf("#") >= 0 ? Filter.elemhideRegExp.exec(text) : null ;
100 if (match)
101 {
102 ret = ElemHideBase.fromText(text, match[1], match[2], match[3], match[4], match[5]);
103 }
104 else if (text[0] == "!")
105 {
106 ret = new CommentFilter(text);
107 }
108 else
109 {
110 ret = RegExpFilter.fromText(text);
111 }
112 Filter.knownFilters[ret.text] = ret;
113 return ret;
114 };
115 Filter.fromObject = function(obj)
116 {
117 var ret = Filter.fromText(obj.text);
118 if (ret instanceof ActiveFilter)
119 {
120 if ("disabled" in obj)
121 {
122 ret._disabled = obj.disabled == "true";
123 }
124 if ("hitCount" in obj)
125 {
126 ret._hitCount = parseInt(obj.hitCount) || 0;
127 }
128 if ("lastHit" in obj)
129 {
130 ret._lastHit = parseInt(obj.lastHit) || 0;
131 }
132 }
133 return ret;
134 };
135 Filter.normalize = function(text)
136 {
137 if (!text)
138 {
139 return text;
140 }
141 text = text.replace(/[^\S ]/g, "");
142 if (/^\s*!/.test(text))
143 {
144 return text.replace(/^\s+/, "").replace(/\s+$/, "");
145 }
146 else if (Filter.elemhideRegExp.test(text))
147 {
148 var _tempVar1 = /^(.*?)(#\@?#?)(.*)$/.exec(text);
149 var domain = _tempVar1[1];
150 var separator = _tempVar1[2];
151 var selector = _tempVar1[3];
152 return domain.replace(/\s/g, "") + separator + selector.replace(/^\s+/, "" ).replace(/\s+$/, "");
153 }
154 else
155 {
156 return text.replace(/\s/g, "");
157 }
158 };
159
160 function InvalidFilter(text, reason)
161 {
162 Filter.call(this, text);
163 this.reason = reason;
164 }
165 exports.InvalidFilter = InvalidFilter;
166 InvalidFilter.prototype =
167 {
168 __proto__: Filter.prototype,
169 reason: null,
170 serialize: function(buffer){}
171 };
172
173 function CommentFilter(text)
174 {
175 Filter.call(this, text);
176 }
177 exports.CommentFilter = CommentFilter;
178 CommentFilter.prototype =
179 {
180 __proto__: Filter.prototype,
181 serialize: function(buffer){}
182 };
183
184 function ActiveFilter(text, domains)
185 {
186 Filter.call(this, text);
187 this.domainSource = domains;
188 }
189 exports.ActiveFilter = ActiveFilter;
190 ActiveFilter.prototype =
191 {
192 __proto__: Filter.prototype,
193 _disabled: false,
194 _hitCount: 0,
195 _lastHit: 0,
196 get disabled()
197 {
198 return this._disabled;
199 },
200 set disabled(value)
201 {
202 if (value != this._disabled)
203 {
204 var oldValue = this._disabled;
205 this._disabled = value;
206 FilterNotifier.triggerListeners("filter.disabled", this, value, oldValue );
207 }
208 return this._disabled;
209 },
210 get hitCount()
211 {
212 return this._hitCount;
213 },
214 set hitCount(value)
215 {
216 if (value != this._hitCount)
217 {
218 var oldValue = this._hitCount;
219 this._hitCount = value;
220 FilterNotifier.triggerListeners("filter.hitCount", this, value, oldValue );
221 }
222 return this._hitCount;
223 },
224 get lastHit()
225 {
226 return this._lastHit;
227 },
228 set lastHit(value)
229 {
230 if (value != this._lastHit)
231 {
232 var oldValue = this._lastHit;
233 this._lastHit = value;
234 FilterNotifier.triggerListeners("filter.lastHit", this, value, oldValue) ;
235 }
236 return this._lastHit;
237 },
238 domainSource: null,
239 domainSeparator: null,
240 ignoreTrailingDot: true,
241 get domains()
242 {
243 var domains = null;
244 if (this.domainSource)
245 {
246 var list = this.domainSource.split(this.domainSeparator);
247 if (list.length == 1 && list[0][0] != "~")
248 {
249 domains =
250 {
251 __proto__: null,
252 "": false
253 };
254 if (this.ignoreTrailingDot)
255 {
256 list[0] = list[0].replace(/\.+$/, "");
257 }
258 domains[list[0]] = true;
259 }
260 else
261 {
262 var hasIncludes = false;
263 for (var i = 0; i < list.length; i++)
264 {
265 var domain = list[i];
266 if (this.ignoreTrailingDot)
267 {
268 domain = domain.replace(/\.+$/, "");
269 }
270 if (domain == "")
271 {
272 continue;
273 }
274 var include;
275 if (domain[0] == "~")
276 {
277 include = false;
278 domain = domain.substr(1);
279 }
280 else
281 {
282 include = true;
283 hasIncludes = true;
284 }
285 if (!domains)
286 {
287 domains =
288 {
289 __proto__: null
290 };
291 }
292 domains[domain] = include;
293 }
294 domains[""] = !hasIncludes;
295 }
296 delete this.domainSource;
297 }
298 this.__defineGetter__("domains", function()
299 {
300 return domains;
301 });
302 return this.domains;
303 },
304 isActiveOnDomain: function(docDomain)
305 {
306 if (!this.domains)
307 {
308 return true;
309 }
310 if (!docDomain)
311 {
312 return this.domains[""];
313 }
314 if (this.ignoreTrailingDot)
315 {
316 docDomain = docDomain.replace(/\.+$/, "");
317 }
318 docDomain = docDomain.toUpperCase();
319 while (true)
320 {
321 if (docDomain in this.domains)
322 {
323 return this.domains[docDomain];
324 }
325 var nextDot = docDomain.indexOf(".");
326 if (nextDot < 0)
327 {
328 break;
329 }
330 docDomain = docDomain.substr(nextDot + 1);
331 }
332 return this.domains[""];
333 },
334 isActiveOnlyOnDomain: function(docDomain)
335 {
336 if (!docDomain || !this.domains || this.domains[""])
337 {
338 return false;
339 }
340 if (this.ignoreTrailingDot)
341 {
342 docDomain = docDomain.replace(/\.+$/, "");
343 }
344 docDomain = docDomain.toUpperCase();
345 for (var domain in this.domains)
346 {
347 if (this.domains[domain] && domain != docDomain && (domain.length <= doc Domain.length || domain.indexOf("." + docDomain) != domain.length - docDomain.le ngth - 1))
348 {
349 return false;
350 }
351 }
352 return true;
353 },
354 serialize: function(buffer)
355 {
356 if (this._disabled || this._hitCount || this._lastHit)
357 {
358 Filter.prototype.serialize.call(this, buffer);
359 if (this._disabled)
360 {
361 buffer.push("disabled=true");
362 }
363 if (this._hitCount)
364 {
365 buffer.push("hitCount=" + this._hitCount);
366 }
367 if (this._lastHit)
368 {
369 buffer.push("lastHit=" + this._lastHit);
370 }
371 }
372 }
373 };
374
375 function RegExpFilter(text, regexpSource, contentType, matchCase, domains, thi rdParty)
376 {
377 ActiveFilter.call(this, text, domains);
378 if (contentType != null)
379 {
380 this.contentType = contentType;
381 }
382 if (matchCase)
383 {
384 this.matchCase = matchCase;
385 }
386 if (thirdParty != null)
387 {
388 this.thirdParty = thirdParty;
389 }
390 if (regexpSource.length >= 2 && regexpSource[0] == "/" && regexpSource[regex pSource.length - 1] == "/")
391 {
392 var regexp = new RegExp(regexpSource.substr(1, regexpSource.length - 2), t his.matchCase ? "" : "i");
393 this.__defineGetter__("regexp", function()
394 {
395 return regexp;
396 });
397 }
398 else
399 {
400 this.regexpSource = regexpSource;
401 }
402 }
403 exports.RegExpFilter = RegExpFilter;
404 RegExpFilter.prototype =
405 {
406 __proto__: ActiveFilter.prototype,
407 length: 1,
408 domainSeparator: "|",
409 regexpSource: null,
410 get regexp()
411 {
412 var source = this.regexpSource.replace(/\*+/g, "*");
413 if (source[0] == "*")
414 {
415 source = source.substr(1);
416 }
417 var pos = source.length - 1;
418 if (pos >= 0 && source[pos] == "*")
419 {
420 source = source.substr(0, pos);
421 }
422 source = source.replace(/\^\|$/, "^").replace(/\W/g, "\\$&").replace(/\\\* /g, ".*").replace(/\\\^/g, "(?:[\\x00-\\x24\\x26-\\x2C\\x2F\\x3A-\\x40\\x5B-\\x5 E\\x60\\x7B-\\x80]|$)").replace(/^\\\|\\\|/, "^[\\w\\-]+:\\/+(?!\\/)(?:[^.\\/]+\ \.)*?").replace(/^\\\|/, "^").replace(/\\\|$/, "$");
423 var regexp = new RegExp(source, this.matchCase ? "" : "i");
424 delete this.regexpSource;
425 this.__defineGetter__("regexp", function()
426 {
427 return regexp;
428 });
429 return this.regexp;
430 },
431 contentType: 2147483647,
432 matchCase: false,
433 thirdParty: null,
434 matches: function(location, contentType, docDomain, thirdParty)
435 {
436 if (this.regexp.test(location) && (RegExpFilter.typeMap[contentType] & thi s.contentType) != 0 && (this.thirdParty == null || this.thirdParty == thirdParty ) && this.isActiveOnDomain(docDomain))
437 {
438 return true;
439 }
440 return false;
441 }
442 };
443 RegExpFilter.prototype.__defineGetter__("0", function()
444 {
445 return this;
446 });
447 RegExpFilter.fromText = function(text)
448 {
449 var blocking = true;
450 var origText = text;
451 if (text.indexOf("@@") == 0)
452 {
453 blocking = false;
454 text = text.substr(2);
455 }
456 var contentType = null;
457 var matchCase = null;
458 var domains = null;
459 var siteKeys = null;
460 var thirdParty = null;
461 var collapse = null;
462 var options;
463 var match = text.indexOf("$") >= 0 ? Filter.optionsRegExp.exec(text) : null;
464 if (match)
465 {
466 options = match[1].toUpperCase().split(",");
467 text = match.input.substr(0, match.index);
468 for (var _loopIndex2 = 0; _loopIndex2 < options.length; ++_loopIndex2)
469 {
470 var option = options[_loopIndex2];
471 var value = null;
472 var separatorIndex = option.indexOf("=");
473 if (separatorIndex >= 0)
474 {
475 value = option.substr(separatorIndex + 1);
476 option = option.substr(0, separatorIndex);
477 }
478 option = option.replace(/-/, "_");
479 if (option in RegExpFilter.typeMap)
480 {
481 if (contentType == null)
482 {
483 contentType = 0;
484 }
485 contentType |= RegExpFilter.typeMap[option];
486 }
487 else if (option[0] == "~" && option.substr(1) in RegExpFilter.typeMap)
488 {
489 if (contentType == null)
490 {
491 contentType = RegExpFilter.prototype.contentType;
492 }
493 contentType &= ~RegExpFilter.typeMap[option.substr(1)];
494 }
495 else if (option == "MATCH_CASE")
496 {
497 matchCase = true;
498 }
499 else if (option == "DOMAIN" && typeof value != "undefined")
500 {
501 domains = value;
502 }
503 else if (option == "THIRD_PARTY")
504 {
505 thirdParty = true;
506 }
507 else if (option == "~THIRD_PARTY")
508 {
509 thirdParty = false;
510 }
511 else if (option == "COLLAPSE")
512 {
513 collapse = true;
514 }
515 else if (option == "~COLLAPSE")
516 {
517 collapse = false;
518 }
519 else if (option == "SITEKEY" && typeof value != "undefined")
520 {
521 siteKeys = value.split(/\|/);
522 }
523 }
524 }
525 if (!blocking && (contentType == null || contentType & RegExpFilter.typeMap. DOCUMENT) && (!options || options.indexOf("DOCUMENT") < 0) && !/^\|?[\w\-]+:/.te st(text))
526 {
527 if (contentType == null)
528 {
529 contentType = RegExpFilter.prototype.contentType;
530 }
531 contentType &= ~RegExpFilter.typeMap.DOCUMENT;
532 }
533 if (!blocking && siteKeys)
534 {
535 contentType = RegExpFilter.typeMap.DOCUMENT;
536 }
537 try
538 {
539 if (blocking)
540 {
541 return new BlockingFilter(origText, text, contentType, matchCase, domain s, thirdParty, collapse);
542 }
543 else
544 {
545 return new WhitelistFilter(origText, text, contentType, matchCase, domai ns, thirdParty, siteKeys);
546 }
547 }
548 catch (e)
549 {
550 return new InvalidFilter(text, e);
551 }
552 };
553 RegExpFilter.typeMap =
554 {
555 OTHER: 1,
556 SCRIPT: 2,
557 IMAGE: 4,
558 STYLESHEET: 8,
559 OBJECT: 16,
560 SUBDOCUMENT: 32,
561 DOCUMENT: 64,
562 XBL: 1,
563 PING: 1,
564 XMLHTTPREQUEST: 2048,
565 OBJECT_SUBREQUEST: 4096,
566 DTD: 1,
567 MEDIA: 16384,
568 FONT: 32768,
569 BACKGROUND: 4,
570 POPUP: 268435456,
571 DONOTTRACK: 536870912,
572 ELEMHIDE: 1073741824
573 };
574 RegExpFilter.prototype.contentType &= ~ (RegExpFilter.typeMap.ELEMHIDE | RegEx pFilter.typeMap.DONOTTRACK | RegExpFilter.typeMap.POPUP);
575
576 function BlockingFilter(text, regexpSource, contentType, matchCase, domains, t hirdParty, collapse)
577 {
578 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, thirdParty);
579 this.collapse = collapse;
580 }
581 exports.BlockingFilter = BlockingFilter;
582 BlockingFilter.prototype =
583 {
584 __proto__: RegExpFilter.prototype,
585 collapse: null
586 };
587
588 function WhitelistFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, siteKeys)
589 {
590 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, thirdParty);
591 if (siteKeys != null)
592 {
593 this.siteKeys = siteKeys;
594 }
595 }
596 exports.WhitelistFilter = WhitelistFilter;
597 WhitelistFilter.prototype =
598 {
599 __proto__: RegExpFilter.prototype,
600 siteKeys: null
601 };
602
603 function ElemHideBase(text, domains, selector)
604 {
605 ActiveFilter.call(this, text, domains ? domains.toUpperCase() : null);
606 if (domains)
607 {
608 this.selectorDomain = domains.replace(/,~[^,]+/g, "").replace(/^~[^,]+,?/, "").toLowerCase();
609 }
610 this.selector = selector;
611 }
612 exports.ElemHideBase = ElemHideBase;
613 ElemHideBase.prototype =
614 {
615 __proto__: ActiveFilter.prototype,
616 domainSeparator: ",",
617 ignoreTrailingDot: false,
618 selectorDomain: null,
619 selector: null
620 };
621 ElemHideBase.fromText = function(text, domain, isException, tagName, attrRules , selector)
622 {
623 if (!selector)
624 {
625 if (tagName == "*")
626 {
627 tagName = "";
628 }
629 var id = null;
630 var additional = "";
631 if (attrRules)
632 {
633 attrRules = attrRules.match(/\([\w\-]+(?:[$^*]?=[^\(\)"]*)?\)/g);
634 for (var _loopIndex3 = 0; _loopIndex3 < attrRules.length; ++_loopIndex3)
635 {
636 var rule = attrRules[_loopIndex3];
637 rule = rule.substr(1, rule.length - 2);
638 var separatorPos = rule.indexOf("=");
639 if (separatorPos > 0)
640 {
641 rule = rule.replace(/=/, "=\"") + "\"";
642 additional += "[" + rule + "]";
643 }
644 else
645 {
646 if (id)
647 {
648 var Utils = require("utils").Utils;
649 return new InvalidFilter(text, Utils.getString("filter_elemhide_du plicate_id"));
650 }
651 else
652 {
653 id = rule;
654 }
655 }
656 }
657 }
658 if (id)
659 {
660 selector = tagName + "." + id + additional + "," + tagName + "#" + id + additional;
661 }
662 else if (tagName || additional)
663 {
664 selector = tagName + additional;
665 }
666 else
667 {
668 var Utils = require("utils").Utils;
669 return new InvalidFilter(text, Utils.getString("filter_elemhide_nocriter ia"));
670 }
671 }
672 if (isException)
673 {
674 return new ElemHideException(text, domain, selector);
675 }
676 else
677 {
678 return new ElemHideFilter(text, domain, selector);
679 }
680 };
681
682 function ElemHideFilter(text, domains, selector)
683 {
684 ElemHideBase.call(this, text, domains, selector);
685 }
686 exports.ElemHideFilter = ElemHideFilter;
687 ElemHideFilter.prototype =
688 {
689 __proto__: ElemHideBase.prototype
690 };
691
692 function ElemHideException(text, domains, selector)
693 {
694 ElemHideBase.call(this, text, domains, selector);
695 }
696 exports.ElemHideException = ElemHideException;
697 ElemHideException.prototype =
698 {
699 __proto__: ElemHideBase.prototype
700 };
701 return exports;
702 })();
703 require.scopes["subscriptionClasses"] = (function()
704 {
705 var exports = {};
706 var _tempVar4 = require("filterClasses");
707 var ActiveFilter = _tempVar4.ActiveFilter;
708 var BlockingFilter = _tempVar4.BlockingFilter;
709 var WhitelistFilter = _tempVar4.WhitelistFilter;
710 var ElemHideBase = _tempVar4.ElemHideBase;
711 var FilterNotifier = require("filterNotifier").FilterNotifier;
712
713 function Subscription(url, title)
714 {
715 this.url = url;
716 this.filters = [];
717 if (title)
718 {
719 this._title = title;
720 }
721 else
722 {
723 var Utils = require("utils").Utils;
724 this._title = Utils.getString("newGroup_title");
725 }
726 Subscription.knownSubscriptions[url] = this;
727 }
728 exports.Subscription = Subscription;
729 Subscription.prototype =
730 {
731 url: null,
732 filters: null,
733 _title: null,
734 _fixedTitle: false,
735 _disabled: false,
736 get title()
737 {
738 return this._title;
739 },
740 set title(value)
741 {
742 if (value != this._title)
743 {
744 var oldValue = this._title;
745 this._title = value;
746 FilterNotifier.triggerListeners("subscription.title", this, value, oldVa lue);
747 }
748 return this._title;
749 },
750 get fixedTitle()
751 {
752 return this._fixedTitle;
753 },
754 set fixedTitle(value)
755 {
756 if (value != this._fixedTitle)
757 {
758 var oldValue = this._fixedTitle;
759 this._fixedTitle = value;
760 FilterNotifier.triggerListeners("subscription.fixedTitle", this, value, oldValue);
761 }
762 return this._fixedTitle;
763 },
764 get disabled()
765 {
766 return this._disabled;
767 },
768 set disabled(value)
769 {
770 if (value != this._disabled)
771 {
772 var oldValue = this._disabled;
773 this._disabled = value;
774 FilterNotifier.triggerListeners("subscription.disabled", this, value, ol dValue);
775 }
776 return this._disabled;
777 },
778 serialize: function(buffer)
779 {
780 buffer.push("[Subscription]");
781 buffer.push("url=" + this.url);
782 buffer.push("title=" + this._title);
783 if (this._fixedTitle)
784 {
785 buffer.push("fixedTitle=true");
786 }
787 if (this._disabled)
788 {
789 buffer.push("disabled=true");
790 }
791 },
792 serializeFilters: function(buffer)
793 {
794 for (var _loopIndex5 = 0; _loopIndex5 < this.filters.length; ++_loopIndex5 )
795 {
796 var filter = this.filters[_loopIndex5];
797 buffer.push(filter.text.replace(/\[/g, "\\["));
798 }
799 },
800 toString: function()
801 {
802 var buffer = [];
803 this.serialize(buffer);
804 return buffer.join("\n");
805 }
806 };
807 Subscription.knownSubscriptions =
808 {
809 __proto__: null
810 };
811 Subscription.fromURL = function(url)
812 {
813 if (url in Subscription.knownSubscriptions)
814 {
815 return Subscription.knownSubscriptions[url];
816 }
817 try
818 {
819 url = Services.io.newURI(url, null, null).spec;
820 return new DownloadableSubscription(url, null);
821 }
822 catch (e)
823 {
824 return new SpecialSubscription(url);
825 }
826 };
827 Subscription.fromObject = function(obj)
828 {
829 var result;
830 try
831 {
832 obj.url = Services.io.newURI(obj.url, null, null).spec;
833 result = new DownloadableSubscription(obj.url, obj.title);
834 if ("nextURL" in obj)
835 {
836 result.nextURL = obj.nextURL;
837 }
838 if ("downloadStatus" in obj)
839 {
840 result._downloadStatus = obj.downloadStatus;
841 }
842 if ("lastModified" in obj)
843 {
844 result.lastModified = obj.lastModified;
845 }
846 if ("lastSuccess" in obj)
847 {
848 result.lastSuccess = parseInt(obj.lastSuccess) || 0;
849 }
850 if ("lastCheck" in obj)
851 {
852 result._lastCheck = parseInt(obj.lastCheck) || 0;
853 }
854 if ("expires" in obj)
855 {
856 result.expires = parseInt(obj.expires) || 0;
857 }
858 if ("softExpiration" in obj)
859 {
860 result.softExpiration = parseInt(obj.softExpiration) || 0;
861 }
862 if ("errors" in obj)
863 {
864 result._errors = parseInt(obj.errors) || 0;
865 }
866 if ("requiredVersion" in obj)
867 {
868 var addonVersion = require("info").addonVersion;
869 result.requiredVersion = obj.requiredVersion;
870 if (Services.vc.compare(result.requiredVersion, addonVersion) > 0)
871 {
872 result.upgradeRequired = true;
873 }
874 }
875 if ("alternativeLocations" in obj)
876 {
877 result.alternativeLocations = obj.alternativeLocations;
878 }
879 if ("homepage" in obj)
880 {
881 result._homepage = obj.homepage;
882 }
883 if ("lastDownload" in obj)
884 {
885 result._lastDownload = parseInt(obj.lastDownload) || 0;
886 }
887 }
888 catch (e)
889 {
890 if (!("title" in obj))
891 {
892 if (obj.url == "~wl~")
893 {
894 obj.defaults = "whitelist";
895 }
896 else if (obj.url == "~fl~")
897 {
898 obj.defaults = "blocking";
899 }
900 else if (obj.url == "~eh~")
901 {
902 obj.defaults = "elemhide";
903 }
904 if ("defaults" in obj)
905 {
906 var Utils = require("utils").Utils;
907 obj.title = Utils.getString(obj.defaults + "Group_title");
908 }
909 }
910 result = new SpecialSubscription(obj.url, obj.title);
911 if ("defaults" in obj)
912 {
913 result.defaults = obj.defaults.split(" ");
914 }
915 }
916 if ("fixedTitle" in obj)
917 {
918 result._fixedTitle = obj.fixedTitle == "true";
919 }
920 if ("disabled" in obj)
921 {
922 result._disabled = obj.disabled == "true";
923 }
924 return result;
925 };
926
927 function SpecialSubscription(url, title)
928 {
929 Subscription.call(this, url, title);
930 }
931 exports.SpecialSubscription = SpecialSubscription;
932 SpecialSubscription.prototype =
933 {
934 __proto__: Subscription.prototype,
935 defaults: null,
936 isDefaultFor: function(filter)
937 {
938 if (this.defaults && this.defaults.length)
939 {
940 for (var _loopIndex6 = 0; _loopIndex6 < this.defaults.length; ++_loopInd ex6)
941 {
942 var type = this.defaults[_loopIndex6];
943 if (filter instanceof SpecialSubscription.defaultsMap[type])
944 {
945 return true;
946 }
947 if (!(filter instanceof ActiveFilter) && type == "blacklist")
948 {
949 return true;
950 }
951 }
952 }
953 return false;
954 },
955 serialize: function(buffer)
956 {
957 Subscription.prototype.serialize.call(this, buffer);
958 if (this.defaults && this.defaults.length)
959 {
960 buffer.push("defaults=" + this.defaults.filter(function(type)
961 {
962 return type in SpecialSubscription.defaultsMap;
963 }).join(" "));
964 }
965 if (this._lastDownload)
966 {
967 buffer.push("lastDownload=" + this._lastDownload);
968 }
969 }
970 };
971 SpecialSubscription.defaultsMap =
972 {
973 __proto__: null,
974 "whitelist": WhitelistFilter,
975 "blocking": BlockingFilter,
976 "elemhide": ElemHideBase
977 };
978 SpecialSubscription.create = function(title)
979 {
980 var url;
981 do
982 {
983 url = "~user~" + Math.round(Math.random() * 1000000);
984 }
985 while (url in Subscription.knownSubscriptions);
986 return new SpecialSubscription(url, title);
987 };
988 SpecialSubscription.createForFilter = function(filter)
989 {
990 var subscription = SpecialSubscription.create();
991 subscription.filters.push(filter);
992 for (var type in SpecialSubscription.defaultsMap)
993 {
994 if (filter instanceof SpecialSubscription.defaultsMap[type])
995 {
996 subscription.defaults = [type];
997 }
998 }
999 if (!subscription.defaults)
1000 {
1001 subscription.defaults = ["blocking"];
1002 }
1003 var Utils = require("utils").Utils;
1004 subscription.title = Utils.getString(subscription.defaults[0] + "Group_title ");
1005 return subscription;
1006 };
1007
1008 function RegularSubscription(url, title)
1009 {
1010 Subscription.call(this, url, title || url);
1011 }
1012 exports.RegularSubscription = RegularSubscription;
1013 RegularSubscription.prototype =
1014 {
1015 __proto__: Subscription.prototype,
1016 _homepage: null,
1017 _lastDownload: 0,
1018 get homepage()
1019 {
1020 return this._homepage;
1021 },
1022 set homepage(value)
1023 {
1024 if (value != this._homepage)
1025 {
1026 var oldValue = this._homepage;
1027 this._homepage = value;
1028 FilterNotifier.triggerListeners("subscription.homepage", this, value, ol dValue);
1029 }
1030 return this._homepage;
1031 },
1032 get lastDownload()
1033 {
1034 return this._lastDownload;
1035 },
1036 set lastDownload(value)
1037 {
1038 if (value != this._lastDownload)
1039 {
1040 var oldValue = this._lastDownload;
1041 this._lastDownload = value;
1042 FilterNotifier.triggerListeners("subscription.lastDownload", this, value , oldValue);
1043 }
1044 return this._lastDownload;
1045 },
1046 serialize: function(buffer)
1047 {
1048 Subscription.prototype.serialize.call(this, buffer);
1049 if (this._homepage)
1050 {
1051 buffer.push("homepage=" + this._homepage);
1052 }
1053 if (this._lastDownload)
1054 {
1055 buffer.push("lastDownload=" + this._lastDownload);
1056 }
1057 }
1058 };
1059
1060 function ExternalSubscription(url, title)
1061 {
1062 RegularSubscription.call(this, url, title);
1063 }
1064 exports.ExternalSubscription = ExternalSubscription;
1065 ExternalSubscription.prototype =
1066 {
1067 __proto__: RegularSubscription.prototype,
1068 serialize: function(buffer)
1069 {
1070 throw new Error("Unexpected call, external subscriptions should not be ser ialized");
1071 }
1072 };
1073
1074 function DownloadableSubscription(url, title)
1075 {
1076 RegularSubscription.call(this, url, title);
1077 }
1078 exports.DownloadableSubscription = DownloadableSubscription;
1079 DownloadableSubscription.prototype =
1080 {
1081 __proto__: RegularSubscription.prototype,
1082 _downloadStatus: null,
1083 _lastCheck: 0,
1084 _errors: 0,
1085 nextURL: null,
1086 get downloadStatus()
1087 {
1088 return this._downloadStatus;
1089 },
1090 set downloadStatus(value)
1091 {
1092 var oldValue = this._downloadStatus;
1093 this._downloadStatus = value;
1094 FilterNotifier.triggerListeners("subscription.downloadStatus", this, value , oldValue);
1095 return this._downloadStatus;
1096 },
1097 lastModified: null,
1098 lastSuccess: 0,
1099 get lastCheck()
1100 {
1101 return this._lastCheck;
1102 },
1103 set lastCheck(value)
1104 {
1105 if (value != this._lastCheck)
1106 {
1107 var oldValue = this._lastCheck;
1108 this._lastCheck = value;
1109 FilterNotifier.triggerListeners("subscription.lastCheck", this, value, o ldValue);
1110 }
1111 return this._lastCheck;
1112 },
1113 expires: 0,
1114 softExpiration: 0,
1115 get errors()
1116 {
1117 return this._errors;
1118 },
1119 set errors(value)
1120 {
1121 if (value != this._errors)
1122 {
1123 var oldValue = this._errors;
1124 this._errors = value;
1125 FilterNotifier.triggerListeners("subscription.errors", this, value, oldV alue);
1126 }
1127 return this._errors;
1128 },
1129 requiredVersion: null,
1130 upgradeRequired: false,
1131 alternativeLocations: null,
1132 serialize: function(buffer)
1133 {
1134 RegularSubscription.prototype.serialize.call(this, buffer);
1135 if (this.nextURL)
1136 {
1137 buffer.push("nextURL=" + this.nextURL);
1138 }
1139 if (this.downloadStatus)
1140 {
1141 buffer.push("downloadStatus=" + this.downloadStatus);
1142 }
1143 if (this.lastModified)
1144 {
1145 buffer.push("lastModified=" + this.lastModified);
1146 }
1147 if (this.lastSuccess)
1148 {
1149 buffer.push("lastSuccess=" + this.lastSuccess);
1150 }
1151 if (this.lastCheck)
1152 {
1153 buffer.push("lastCheck=" + this.lastCheck);
1154 }
1155 if (this.expires)
1156 {
1157 buffer.push("expires=" + this.expires);
1158 }
1159 if (this.softExpiration)
1160 {
1161 buffer.push("softExpiration=" + this.softExpiration);
1162 }
1163 if (this.errors)
1164 {
1165 buffer.push("errors=" + this.errors);
1166 }
1167 if (this.requiredVersion)
1168 {
1169 buffer.push("requiredVersion=" + this.requiredVersion);
1170 }
1171 if (this.alternativeLocations)
1172 {
1173 buffer.push("alternativeLocations=" + this.alternativeLocations);
1174 }
1175 }
1176 };
1177 return exports;
1178 })();
1179 require.scopes["filterStorage"] = (function()
1180 {
1181 var exports = {};
1182 var IO = require("io").IO;
1183 var Prefs = require("prefs").Prefs;
1184 var _tempVar7 = require("filterClasses");
1185 var Filter = _tempVar7.Filter;
1186 var ActiveFilter = _tempVar7.ActiveFilter;
1187 var _tempVar8 = require("subscriptionClasses");
1188 var Subscription = _tempVar8.Subscription;
1189 var SpecialSubscription = _tempVar8.SpecialSubscription;
1190 var ExternalSubscription = _tempVar8.ExternalSubscription;
1191 var FilterNotifier = require("filterNotifier").FilterNotifier;
1192 var formatVersion = 4;
1193 var FilterStorage = exports.FilterStorage =
1194 {
1195 get formatVersion()
1196 {
1197 return formatVersion;
1198 },
1199 get sourceFile()
1200 {
1201 var file = null;
1202 if (Prefs.patternsfile)
1203 {
1204 file = IO.resolveFilePath(Prefs.patternsfile);
1205 }
1206 if (!file)
1207 {
1208 file = IO.resolveFilePath(Prefs.data_directory);
1209 if (file)
1210 {
1211 file.append("patterns.ini");
1212 }
1213 }
1214 if (!file)
1215 {
1216 try
1217 {
1218 file = IO.resolveFilePath(Services.prefs.getDefaultBranch("extensions. adblockplus.").getCharPref("data_directory"));
1219 if (file)
1220 {
1221 file.append("patterns.ini");
1222 }
1223 }
1224 catch (e){}
1225 }
1226 if (!file)
1227 {
1228 Cu.reportError("Adblock Plus: Failed to resolve filter file location fro m extensions.adblockplus.patternsfile preference");
1229 }
1230 this.__defineGetter__("sourceFile", function()
1231 {
1232 return file;
1233 });
1234 return this.sourceFile;
1235 },
1236 fileProperties:
1237 {
1238 __proto__: null
1239 },
1240 subscriptions: [],
1241 knownSubscriptions:
1242 {
1243 __proto__: null
1244 },
1245 getGroupForFilter: function(filter)
1246 {
1247 var generalSubscription = null;
1248 for (var _loopIndex9 = 0; _loopIndex9 < FilterStorage.subscriptions.length ; ++_loopIndex9)
1249 {
1250 var subscription = FilterStorage.subscriptions[_loopIndex9];
1251 if (subscription instanceof SpecialSubscription && !subscription.disable d)
1252 {
1253 if (subscription.isDefaultFor(filter))
1254 {
1255 return subscription;
1256 }
1257 if (!generalSubscription && (!subscription.defaults || !subscription.d efaults.length))
1258 {
1259 generalSubscription = subscription;
1260 }
1261 }
1262 }
1263 return generalSubscription;
1264 },
1265 addSubscription: function(subscription, silent)
1266 {
1267 if (subscription.url in FilterStorage.knownSubscriptions)
1268 {
1269 return;
1270 }
1271 FilterStorage.subscriptions.push(subscription);
1272 FilterStorage.knownSubscriptions[subscription.url] = subscription;
1273 addSubscriptionFilters(subscription);
1274 if (!silent)
1275 {
1276 FilterNotifier.triggerListeners("subscription.added", subscription);
1277 }
1278 },
1279 removeSubscription: function(subscription, silent)
1280 {
1281 for (var i = 0; i < FilterStorage.subscriptions.length; i++)
1282 {
1283 if (FilterStorage.subscriptions[i].url == subscription.url)
1284 {
1285 removeSubscriptionFilters(subscription);
1286 FilterStorage.subscriptions.splice(i--, 1);
1287 delete FilterStorage.knownSubscriptions[subscription.url];
1288 if (!silent)
1289 {
1290 FilterNotifier.triggerListeners("subscription.removed", subscription );
1291 }
1292 return;
1293 }
1294 }
1295 },
1296 moveSubscription: function(subscription, insertBefore)
1297 {
1298 var currentPos = FilterStorage.subscriptions.indexOf(subscription);
1299 if (currentPos < 0)
1300 {
1301 return;
1302 }
1303 var newPos = insertBefore ? FilterStorage.subscriptions.indexOf(insertBefo re) : -1;
1304 if (newPos < 0)
1305 {
1306 newPos = FilterStorage.subscriptions.length;
1307 }
1308 if (currentPos < newPos)
1309 {
1310 newPos--;
1311 }
1312 if (currentPos == newPos)
1313 {
1314 return;
1315 }
1316 FilterStorage.subscriptions.splice(currentPos, 1);
1317 FilterStorage.subscriptions.splice(newPos, 0, subscription);
1318 FilterNotifier.triggerListeners("subscription.moved", subscription);
1319 },
1320 updateSubscriptionFilters: function(subscription, filters)
1321 {
1322 removeSubscriptionFilters(subscription);
1323 subscription.oldFilters = subscription.filters;
1324 subscription.filters = filters;
1325 addSubscriptionFilters(subscription);
1326 FilterNotifier.triggerListeners("subscription.updated", subscription);
1327 delete subscription.oldFilters;
1328 },
1329 addFilter: function(filter, subscription, position, silent)
1330 {
1331 if (!subscription)
1332 {
1333 if (filter.subscriptions.some(function(s)
1334 {
1335 return s instanceof SpecialSubscription && !s.disabled;
1336 }))
1337 {
1338 return;
1339 }
1340 subscription = FilterStorage.getGroupForFilter(filter);
1341 }
1342 if (!subscription)
1343 {
1344 subscription = SpecialSubscription.createForFilter(filter);
1345 this.addSubscription(subscription);
1346 return;
1347 }
1348 if (typeof position == "undefined")
1349 {
1350 position = subscription.filters.length;
1351 }
1352 if (filter.subscriptions.indexOf(subscription) < 0)
1353 {
1354 filter.subscriptions.push(subscription);
1355 }
1356 subscription.filters.splice(position, 0, filter);
1357 if (!silent)
1358 {
1359 FilterNotifier.triggerListeners("filter.added", filter, subscription, po sition);
1360 }
1361 },
1362 removeFilter: function(filter, subscription, position)
1363 {
1364 var subscriptions = subscription ? [subscription] : filter.subscriptions.s lice();
1365 for (var i = 0; i < subscriptions.length; i++)
1366 {
1367 var subscription = subscriptions[i];
1368 if (subscription instanceof SpecialSubscription)
1369 {
1370 var positions = [];
1371 if (typeof position == "undefined")
1372 {
1373 var index = -1;
1374 do
1375 {
1376 index = subscription.filters.indexOf(filter, index + 1);
1377 if (index >= 0)
1378 {
1379 positions.push(index);
1380 }
1381 }
1382 while (index >= 0);
1383 }
1384 else
1385 {
1386 positions.push(position);
1387 }
1388 for (var j = positions.length - 1; j >= 0; j--)
1389 {
1390 var position = positions[j];
1391 if (subscription.filters[position] == filter)
1392 {
1393 subscription.filters.splice(position, 1);
1394 if (subscription.filters.indexOf(filter) < 0)
1395 {
1396 var index = filter.subscriptions.indexOf(subscription);
1397 if (index >= 0)
1398 {
1399 filter.subscriptions.splice(index, 1);
1400 }
1401 }
1402 FilterNotifier.triggerListeners("filter.removed", filter, subscrip tion, position);
1403 }
1404 }
1405 }
1406 }
1407 },
1408 moveFilter: function(filter, subscription, oldPosition, newPosition)
1409 {
1410 if (!(subscription instanceof SpecialSubscription) || subscription.filters [oldPosition] != filter)
1411 {
1412 return;
1413 }
1414 newPosition = Math.min(Math.max(newPosition, 0), subscription.filters.leng th - 1);
1415 if (oldPosition == newPosition)
1416 {
1417 return;
1418 }
1419 subscription.filters.splice(oldPosition, 1);
1420 subscription.filters.splice(newPosition, 0, filter);
1421 FilterNotifier.triggerListeners("filter.moved", filter, subscription, oldP osition, newPosition);
1422 },
1423 increaseHitCount: function(filter, wnd)
1424 {
1425 if (!Prefs.savestats || PrivateBrowsing.enabledForWindow(wnd) || PrivateBr owsing.enabled || !(filter instanceof ActiveFilter))
1426 {
1427 return;
1428 }
1429 filter.hitCount++;
1430 filter.lastHit = Date.now();
1431 },
1432 resetHitCounts: function(filters)
1433 {
1434 if (!filters)
1435 {
1436 filters = [];
1437 for (var text in Filter.knownFilters)
1438 {
1439 filters.push(Filter.knownFilters[text]);
1440 }
1441 }
1442 for (var _loopIndex10 = 0; _loopIndex10 < filters.length; ++_loopIndex10)
1443 {
1444 var filter = filters[_loopIndex10];
1445 filter.hitCount = 0;
1446 filter.lastHit = 0;
1447 }
1448 },
1449 _loading: false,
1450 loadFromDisk: function(sourceFile)
1451 {
1452 if (this._loading)
1453 {
1454 return;
1455 }
1456 var readFile = function(sourceFile, backupIndex)
1457 {
1458 var parser = new INIParser();
1459 IO.readFromFile(sourceFile, true, parser, function(e)
1460 {
1461 if (!e && parser.subscriptions.length == 0)
1462 {
1463 e = new Error("No data in the file");
1464 }
1465 if (e)
1466 {
1467 Cu.reportError(e);
1468 }
1469 if (e && !explicitFile)
1470 {
1471 sourceFile = this.sourceFile;
1472 if (sourceFile)
1473 {
1474 var _tempVar11 = /^(.*)(\.\w+)$/.exec(sourceFile.leafName) || [nul l, sourceFile.leafName, ""];
1475 var part1 = _tempVar11[1];
1476 var part2 = _tempVar11[2];
1477 sourceFile = sourceFile.clone();
1478 sourceFile.leafName = part1 + "-backup" + ++backupIndex + part2;
1479 IO.statFile(sourceFile, function(e, statData)
1480 {
1481 if (!e && statData.exists)
1482 {
1483 readFile(sourceFile, backupIndex);
1484 }
1485 else
1486 {
1487 doneReading(parser);
1488 }
1489 });
1490 return;
1491 }
1492 }
1493 doneReading(parser);
1494 }.bind(this), "FilterStorageRead");
1495 }.bind(this);
1496 var doneReading = function(parser)
1497 {
1498 var specialMap =
1499 {
1500 "~il~": true,
1501 "~wl~": true,
1502 "~fl~": true,
1503 "~eh~": true
1504 };
1505 var knownSubscriptions =
1506 {
1507 __proto__: null
1508 };
1509 for (var i = 0; i < parser.subscriptions.length; i++)
1510 {
1511 var subscription = parser.subscriptions[i];
1512 if (subscription instanceof SpecialSubscription && subscription.filter s.length == 0 && subscription.url in specialMap)
1513 {
1514 parser.subscriptions.splice(i--, 1);
1515 }
1516 else
1517 {
1518 knownSubscriptions[subscription.url] = subscription;
1519 }
1520 }
1521 this.fileProperties = parser.fileProperties;
1522 this.subscriptions = parser.subscriptions;
1523 this.knownSubscriptions = knownSubscriptions;
1524 Filter.knownFilters = parser.knownFilters;
1525 Subscription.knownSubscriptions = parser.knownSubscriptions;
1526 if (parser.userFilters)
1527 {
1528 for (var i = 0; i < parser.userFilters.length; i++)
1529 {
1530 var filter = Filter.fromText(parser.userFilters[i]);
1531 this.addFilter(filter, null, undefined, true);
1532 }
1533 }
1534 this._loading = false;
1535 FilterNotifier.triggerListeners("load");
1536 if (sourceFile != this.sourceFile)
1537 {
1538 this.saveToDisk();
1539 }
1540 }.bind(this);
1541 var startRead = function(file)
1542 {
1543 this._loading = true;
1544 readFile(file, 0);
1545 }.bind(this);
1546 var explicitFile;
1547 if (sourceFile)
1548 {
1549 explicitFile = true;
1550 startRead(sourceFile);
1551 }
1552 else
1553 {
1554 explicitFile = false;
1555 sourceFile = FilterStorage.sourceFile;
1556 var callback = function(e, statData)
1557 {
1558 if (e || !statData.exists)
1559 {
1560 var addonRoot = require("info").addonRoot;
1561 sourceFile = Services.io.newURI(addonRoot + "defaults/patterns.ini", null, null);
1562 }
1563 startRead(sourceFile);
1564 };
1565 if (sourceFile)
1566 {
1567 IO.statFile(sourceFile, callback);
1568 }
1569 else
1570 {
1571 callback(true);
1572 }
1573 }
1574 },
1575 _generateFilterData: function(subscriptions)
1576 {
1577 var _generatorResult12 = [];
1578 _generatorResult12.push("# Adblock Plus preferences");
1579 _generatorResult12.push("version=" + formatVersion);
1580 var saved =
1581 {
1582 __proto__: null
1583 };
1584 var buf = [];
1585 for (var i = 0; i < subscriptions.length; i++)
1586 {
1587 var subscription = subscriptions[i];
1588 for (var j = 0; j < subscription.filters.length; j++)
1589 {
1590 var filter = subscription.filters[j];
1591 if (!(filter.text in saved))
1592 {
1593 filter.serialize(buf);
1594 saved[filter.text] = filter;
1595 for (var k = 0; k < buf.length; k++)
1596 {
1597 _generatorResult12.push(buf[k]);
1598 }
1599 buf.splice(0);
1600 }
1601 }
1602 }
1603 for (var i = 0; i < subscriptions.length; i++)
1604 {
1605 var subscription = subscriptions[i];
1606 _generatorResult12.push("");
1607 subscription.serialize(buf);
1608 if (subscription.filters.length)
1609 {
1610 buf.push("", "[Subscription filters]");
1611 subscription.serializeFilters(buf);
1612 }
1613 for (var k = 0; k < buf.length; k++)
1614 {
1615 _generatorResult12.push(buf[k]);
1616 }
1617 buf.splice(0);
1618 }
1619 return _generatorResult12;
1620 },
1621 _saving: false,
1622 _needsSave: false,
1623 saveToDisk: function(targetFile)
1624 {
1625 var explicitFile = true;
1626 if (!targetFile)
1627 {
1628 targetFile = FilterStorage.sourceFile;
1629 explicitFile = false;
1630 }
1631 if (!targetFile)
1632 {
1633 return;
1634 }
1635 if (!explicitFile && this._saving)
1636 {
1637 this._needsSave = true;
1638 return;
1639 }
1640 try
1641 {
1642 targetFile.parent.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRE CTORY);
1643 }
1644 catch (e){}
1645 var writeFilters = function()
1646 {
1647 IO.writeToFile(targetFile, true, this._generateFilterData(subscriptions) , function(e)
1648 {
1649 if (!explicitFile)
1650 {
1651 this._saving = false;
1652 }
1653 if (e)
1654 {
1655 Cu.reportError(e);
1656 }
1657 if (!explicitFile && this._needsSave)
1658 {
1659 this._needsSave = false;
1660 this.saveToDisk();
1661 }
1662 else
1663 {
1664 FilterNotifier.triggerListeners("save");
1665 }
1666 }.bind(this), "FilterStorageWrite");
1667 }.bind(this);
1668 var checkBackupRequired = function(callbackNotRequired, callbackRequired)
1669 {
1670 if (explicitFile || Prefs.patternsbackups <= 0)
1671 {
1672 callbackNotRequired();
1673 }
1674 else
1675 {
1676 IO.statFile(targetFile, function(e, statData)
1677 {
1678 if (e || !statData.exists)
1679 {
1680 callbackNotRequired();
1681 }
1682 else
1683 {
1684 var _tempVar13 = /^(.*)(\.\w+)$/.exec(targetFile.leafName) || [nul l, targetFile.leafName, ""];
1685 var part1 = _tempVar13[1];
1686 var part2 = _tempVar13[2];
1687 var newestBackup = targetFile.clone();
1688 newestBackup.leafName = part1 + "-backup1" + part2;
1689 IO.statFile(newestBackup, function(e, statData)
1690 {
1691 if (!e && (!statData.exists || (Date.now() - statData.lastModifi ed) / 3600000 >= Prefs.patternsbackupinterval))
1692 {
1693 callbackRequired(part1, part2);
1694 }
1695 else
1696 {
1697 callbackNotRequired();
1698 }
1699 });
1700 }
1701 });
1702 }
1703 }.bind(this);
1704 var removeLastBackup = function(part1, part2)
1705 {
1706 var file = targetFile.clone();
1707 file.leafName = part1 + "-backup" + Prefs.patternsbackups + part2;
1708 IO.removeFile(file, function(e)
1709 {
1710 return renameBackup(part1, part2, Prefs.patternsbackups - 1);
1711 });
1712 }.bind(this);
1713 var renameBackup = function(part1, part2, index)
1714 {
1715 if (index > 0)
1716 {
1717 var fromFile = targetFile.clone();
1718 fromFile.leafName = part1 + "-backup" + index + part2;
1719 var toName = part1 + "-backup" + (index + 1) + part2;
1720 IO.renameFile(fromFile, toName, function(e)
1721 {
1722 return renameBackup(part1, part2, index - 1);
1723 });
1724 }
1725 else
1726 {
1727 var toFile = targetFile.clone();
1728 toFile.leafName = part1 + "-backup" + (index + 1) + part2;
1729 IO.copyFile(targetFile, toFile, writeFilters);
1730 }
1731 }.bind(this);
1732 var subscriptions = this.subscriptions.filter(function(s)
1733 {
1734 return !(s instanceof ExternalSubscription);
1735 });
1736 if (!explicitFile)
1737 {
1738 this._saving = true;
1739 }
1740 checkBackupRequired(writeFilters, removeLastBackup);
1741 },
1742 getBackupFiles: function()
1743 {
1744 var result = [];
1745 var _tempVar14 = /^(.*)(\.\w+)$/.exec(FilterStorage.sourceFile.leafName) | | [null, FilterStorage.sourceFile.leafName, ""];
1746 var part1 = _tempVar14[1];
1747 var part2 = _tempVar14[2];
1748 for (var i = 1;; i++)
1749 {
1750 var file = FilterStorage.sourceFile.clone();
1751 file.leafName = part1 + "-backup" + i + part2;
1752 if (file.exists())
1753 {
1754 result.push(file);
1755 }
1756 else
1757 {
1758 break;
1759 }
1760 }
1761 return result;
1762 }
1763 };
1764
1765 function addSubscriptionFilters(subscription)
1766 {
1767 if (!(subscription.url in FilterStorage.knownSubscriptions))
1768 {
1769 return;
1770 }
1771 for (var _loopIndex15 = 0; _loopIndex15 < subscription.filters.length; ++_lo opIndex15)
1772 {
1773 var filter = subscription.filters[_loopIndex15];
1774 filter.subscriptions.push(subscription);
1775 }
1776 }
1777
1778 function removeSubscriptionFilters(subscription)
1779 {
1780 if (!(subscription.url in FilterStorage.knownSubscriptions))
1781 {
1782 return;
1783 }
1784 for (var _loopIndex16 = 0; _loopIndex16 < subscription.filters.length; ++_lo opIndex16)
1785 {
1786 var filter = subscription.filters[_loopIndex16];
1787 var i = filter.subscriptions.indexOf(subscription);
1788 if (i >= 0)
1789 {
1790 filter.subscriptions.splice(i, 1);
1791 }
1792 }
1793 }
1794 var PrivateBrowsing = exports.PrivateBrowsing =
1795 {
1796 enabled: false,
1797 enabledForWindow: function(wnd)
1798 {
1799 try
1800 {
1801 return wnd.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIL oadContext).usePrivateBrowsing;
1802 }
1803 catch (e)
1804 {
1805 if (e.result != Cr.NS_NOINTERFACE)
1806 {
1807 Cu.reportError(e);
1808 }
1809 return false;
1810 }
1811 },
1812 init: function()
1813 {
1814 if ("@mozilla.org/privatebrowsing;1" in Cc)
1815 {
1816 try
1817 {
1818 this.enabled = Cc["@mozilla.org/privatebrowsing;1"].getService(Ci.nsIP rivateBrowsingService).privateBrowsingEnabled;
1819 Services.obs.addObserver(this, "private-browsing", true);
1820 onShutdown.add(function()
1821 {
1822 Services.obs.removeObserver(this, "private-browsing");
1823 }.bind(this));
1824 }
1825 catch (e)
1826 {
1827 Cu.reportError(e);
1828 }
1829 }
1830 },
1831 observe: function(subject, topic, data)
1832 {
1833 if (topic == "private-browsing")
1834 {
1835 if (data == "enter")
1836 {
1837 this.enabled = true;
1838 }
1839 else if (data == "exit")
1840 {
1841 this.enabled = false;
1842 }
1843 }
1844 },
1845 QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference, Ci.nsIOb server])
1846 };
1847 PrivateBrowsing.init();
1848
1849 function INIParser()
1850 {
1851 this.fileProperties = this.curObj = {};
1852 this.subscriptions = [];
1853 this.knownFilters =
1854 {
1855 __proto__: null
1856 };
1857 this.knownSubscriptions =
1858 {
1859 __proto__: null
1860 };
1861 }
1862 INIParser.prototype =
1863 {
1864 subscriptions: null,
1865 knownFilters: null,
1866 knownSubscrptions: null,
1867 wantObj: true,
1868 fileProperties: null,
1869 curObj: null,
1870 curSection: null,
1871 userFilters: null,
1872 process: function(val)
1873 {
1874 var origKnownFilters = Filter.knownFilters;
1875 Filter.knownFilters = this.knownFilters;
1876 var origKnownSubscriptions = Subscription.knownSubscriptions;
1877 Subscription.knownSubscriptions = this.knownSubscriptions;
1878 var match;
1879 try
1880 {
1881 if (this.wantObj === true && (match = /^(\w+)=(.*)$/.exec(val)))
1882 {
1883 this.curObj[match[1]] = match[2];
1884 }
1885 else if (val === null || (match = /^\s*\[(.+)\]\s*$/.exec(val)))
1886 {
1887 if (this.curObj)
1888 {
1889 switch (this.curSection)
1890 {
1891 case "filter":
1892 case "pattern":
1893 if ("text" in this.curObj)
1894 {
1895 Filter.fromObject(this.curObj);
1896 }
1897 break;
1898 case "subscription":
1899 var subscription = Subscription.fromObject(this.curObj);
1900 if (subscription)
1901 {
1902 this.subscriptions.push(subscription);
1903 }
1904 break;
1905 case "subscription filters":
1906 case "subscription patterns":
1907 if (this.subscriptions.length)
1908 {
1909 var subscription = this.subscriptions[this.subscriptions.length - 1];
1910 for (var _loopIndex17 = 0; _loopIndex17 < this.curObj.length; ++ _loopIndex17)
1911 {
1912 var text = this.curObj[_loopIndex17];
1913 var filter = Filter.fromText(text);
1914 subscription.filters.push(filter);
1915 filter.subscriptions.push(subscription);
1916 }
1917 }
1918 break;
1919 case "user patterns":
1920 this.userFilters = this.curObj;
1921 break;
1922 }
1923 }
1924 if (val === null)
1925 {
1926 return;
1927 }
1928 this.curSection = match[1].toLowerCase();
1929 switch (this.curSection)
1930 {
1931 case "filter":
1932 case "pattern":
1933 case "subscription":
1934 this.wantObj = true;
1935 this.curObj = {};
1936 break;
1937 case "subscription filters":
1938 case "subscription patterns":
1939 case "user patterns":
1940 this.wantObj = false;
1941 this.curObj = [];
1942 break;
1943 default:
1944 this.wantObj = undefined;
1945 this.curObj = null;
1946 }
1947 }
1948 else if (this.wantObj === false && val)
1949 {
1950 this.curObj.push(val.replace(/\\\[/g, "["));
1951 }
1952 }
1953 finally
1954 {
1955 Filter.knownFilters = origKnownFilters;
1956 Subscription.knownSubscriptions = origKnownSubscriptions;
1957 }
1958 }
1959 };
1960 return exports;
1961 })();
1962 require.scopes["elemHide"] = (function()
1963 {
1964 var exports = {};
1965 var Utils = require("utils").Utils;
1966 var IO = require("io").IO;
1967 var Prefs = require("prefs").Prefs;
1968 var ElemHideException = require("filterClasses").ElemHideException;
1969 var FilterNotifier = require("filterNotifier").FilterNotifier;
1970 var AboutHandler = require("elemHideHitRegistration").AboutHandler;
1971 var filterByKey =
1972 {
1973 __proto__: null
1974 };
1975 var keyByFilter =
1976 {
1977 __proto__: null
1978 };
1979 var knownExceptions =
1980 {
1981 __proto__: null
1982 };
1983 var exceptions =
1984 {
1985 __proto__: null
1986 };
1987 var styleURL = null;
1988 var ElemHide = exports.ElemHide =
1989 {
1990 isDirty: false,
1991 applied: false,
1992 init: function()
1993 {
1994 Prefs.addListener(function(name)
1995 {
1996 if (name == "enabled")
1997 {
1998 ElemHide.apply();
1999 }
2000 });
2001 onShutdown.add(function()
2002 {
2003 ElemHide.unapply();
2004 });
2005 var styleFile = IO.resolveFilePath(Prefs.data_directory);
2006 styleFile.append("elemhide.css");
2007 styleURL = Services.io.newFileURI(styleFile).QueryInterface(Ci.nsIFileURL) ;
2008 },
2009 clear: function()
2010 {
2011 filterByKey =
2012 {
2013 __proto__: null
2014 };
2015 keyByFilter =
2016 {
2017 __proto__: null
2018 };
2019 knownExceptions =
2020 {
2021 __proto__: null
2022 };
2023 exceptions =
2024 {
2025 __proto__: null
2026 };
2027 ElemHide.isDirty = false;
2028 ElemHide.unapply();
2029 },
2030 add: function(filter)
2031 {
2032 if (filter instanceof ElemHideException)
2033 {
2034 if (filter.text in knownExceptions)
2035 {
2036 return;
2037 }
2038 var selector = filter.selector;
2039 if (!(selector in exceptions))
2040 {
2041 exceptions[selector] = [];
2042 }
2043 exceptions[selector].push(filter);
2044 knownExceptions[filter.text] = true;
2045 }
2046 else
2047 {
2048 if (filter.text in keyByFilter)
2049 {
2050 return;
2051 }
2052 var key;
2053 do
2054 {
2055 key = Math.random().toFixed(15).substr(5);
2056 }
2057 while (key in filterByKey);
2058 filterByKey[key] = filter;
2059 keyByFilter[filter.text] = key;
2060 ElemHide.isDirty = true;
2061 }
2062 },
2063 remove: function(filter)
2064 {
2065 if (filter instanceof ElemHideException)
2066 {
2067 if (!(filter.text in knownExceptions))
2068 {
2069 return;
2070 }
2071 var list = exceptions[filter.selector];
2072 var index = list.indexOf(filter);
2073 if (index >= 0)
2074 {
2075 list.splice(index, 1);
2076 }
2077 delete knownExceptions[filter.text];
2078 }
2079 else
2080 {
2081 if (!(filter.text in keyByFilter))
2082 {
2083 return;
2084 }
2085 var key = keyByFilter[filter.text];
2086 delete filterByKey[key];
2087 delete keyByFilter[filter.text];
2088 ElemHide.isDirty = true;
2089 }
2090 },
2091 getException: function(filter, docDomain)
2092 {
2093 var selector = filter.selector;
2094 if (!(filter.selector in exceptions))
2095 {
2096 return null;
2097 }
2098 var list = exceptions[filter.selector];
2099 for (var i = list.length - 1; i >= 0; i--)
2100 {
2101 if (list[i].isActiveOnDomain(docDomain))
2102 {
2103 return list[i];
2104 }
2105 }
2106 return null;
2107 },
2108 _applying: false,
2109 _needsApply: false,
2110 apply: function()
2111 {
2112 if (this._applying)
2113 {
2114 this._needsApply = true;
2115 return;
2116 }
2117 if (!ElemHide.isDirty || !Prefs.enabled)
2118 {
2119 if (Prefs.enabled && !ElemHide.applied)
2120 {
2121 try
2122 {
2123 Utils.styleService.loadAndRegisterSheet(styleURL, Ci.nsIStyleSheetSe rvice.USER_SHEET);
2124 ElemHide.applied = true;
2125 }
2126 catch (e)
2127 {
2128 Cu.reportError(e);
2129 }
2130 }
2131 else if (!Prefs.enabled && ElemHide.applied)
2132 {
2133 ElemHide.unapply();
2134 }
2135 return;
2136 }
2137 IO.writeToFile(styleURL.file, false, this._generateCSSContent(), function( e)
2138 {
2139 this._applying = false;
2140 if (e && e.result == Cr.NS_ERROR_NOT_AVAILABLE)
2141 {
2142 IO.removeFile(styleURL.file, function(e2){});
2143 }
2144 else if (e)
2145 {
2146 Cu.reportError(e);
2147 }
2148 if (this._needsApply)
2149 {
2150 this._needsApply = false;
2151 this.apply();
2152 }
2153 else if (!e || e.result == Cr.NS_ERROR_NOT_AVAILABLE)
2154 {
2155 ElemHide.isDirty = false;
2156 ElemHide.unapply();
2157 if (!e)
2158 {
2159 try
2160 {
2161 Utils.styleService.loadAndRegisterSheet(styleURL, Ci.nsIStyleSheet Service.USER_SHEET);
2162 ElemHide.applied = true;
2163 }
2164 catch (e)
2165 {
2166 Cu.reportError(e);
2167 }
2168 }
2169 FilterNotifier.triggerListeners("elemhideupdate");
2170 }
2171 }.bind(this), "ElemHideWrite");
2172 this._applying = true;
2173 },
2174 _generateCSSContent: function()
2175 {
2176 var _generatorResult12 = [];
2177 var domains =
2178 {
2179 __proto__: null
2180 };
2181 var hasFilters = false;
2182 for (var key in filterByKey)
2183 {
2184 var filter = filterByKey[key];
2185 var domain = filter.selectorDomain || "";
2186 var list;
2187 if (domain in domains)
2188 {
2189 list = domains[domain];
2190 }
2191 else
2192 {
2193 list =
2194 {
2195 __proto__: null
2196 };
2197 domains[domain] = list;
2198 }
2199 list[filter.selector] = key;
2200 hasFilters = true;
2201 }
2202 if (!hasFilters)
2203 {
2204 throw Cr.NS_ERROR_NOT_AVAILABLE;
2205 }
2206
2207 function escapeChar(match)
2208 {
2209 return "\\" + match.charCodeAt(0).toString(16) + " ";
2210 }
2211 var cssTemplate = "-moz-binding: url(about:" + AboutHandler.aboutPrefix + "?%ID%#dummy) !important;";
2212 for (var domain in domains)
2213 {
2214 var rules = [];
2215 var list = domains[domain];
2216 if (domain)
2217 {
2218 _generatorResult12.push(("@-moz-document domain(\"" + domain.split("," ).join("\"),domain(\"") + "\"){").replace(/[^\x01-\x7F]/g, escapeChar));
2219 }
2220 else
2221 {
2222 _generatorResult12.push("@-moz-document url-prefix(\"http://\"),url-pr efix(\"https://\")," + "url-prefix(\"mailbox://\"),url-prefix(\"imap://\")," + " url-prefix(\"news://\"),url-prefix(\"snews://\"){");
2223 }
2224 for (var selector in list)
2225 {
2226 _generatorResult12.push(selector.replace(/[^\x01-\x7F]/g, escapeChar) + "{" + cssTemplate.replace("%ID%", list[selector]) + "}");
2227 }
2228 _generatorResult12.push("}");
2229 }
2230 return _generatorResult12;
2231 },
2232 unapply: function()
2233 {
2234 if (ElemHide.applied)
2235 {
2236 try
2237 {
2238 Utils.styleService.unregisterSheet(styleURL, Ci.nsIStyleSheetService.U SER_SHEET);
2239 }
2240 catch (e)
2241 {
2242 Cu.reportError(e);
2243 }
2244 ElemHide.applied = false;
2245 }
2246 },
2247 get styleURL()
2248 {
2249 return ElemHide.applied ? styleURL.spec : null;
2250 },
2251 getFilterByKey: function(key)
2252 {
2253 return key in filterByKey ? filterByKey[key] : null;
2254 },
2255 getSelectorsForDomain: function(domain, specificOnly)
2256 {
2257 var result = [];
2258 for (var key in filterByKey)
2259 {
2260 var filter = filterByKey[key];
2261 if (specificOnly && (!filter.domains || filter.domains[""]))
2262 {
2263 continue;
2264 }
2265 if (filter.isActiveOnDomain(domain) && !this.getException(filter, domain ))
2266 {
2267 result.push(filter.selector);
2268 }
2269 }
2270 return result;
2271 }
2272 };
2273 return exports;
2274 })();
2275 require.scopes["matcher"] = (function()
2276 {
2277 var exports = {};
2278 var _tempVar18 = require("filterClasses");
2279 var Filter = _tempVar18.Filter;
2280 var RegExpFilter = _tempVar18.RegExpFilter;
2281 var WhitelistFilter = _tempVar18.WhitelistFilter;
2282
2283 function Matcher()
2284 {
2285 this.clear();
2286 }
2287 exports.Matcher = Matcher;
2288 Matcher.prototype =
2289 {
2290 filterByKeyword: null,
2291 keywordByFilter: null,
2292 clear: function()
2293 {
2294 this.filterByKeyword =
2295 {
2296 __proto__: null
2297 };
2298 this.keywordByFilter =
2299 {
2300 __proto__: null
2301 };
2302 },
2303 add: function(filter)
2304 {
2305 if (filter.text in this.keywordByFilter)
2306 {
2307 return;
2308 }
2309 var keyword = this.findKeyword(filter);
2310 var oldEntry = this.filterByKeyword[keyword];
2311 if (typeof oldEntry == "undefined")
2312 {
2313 this.filterByKeyword[keyword] = filter;
2314 }
2315 else if (oldEntry.length == 1)
2316 {
2317 this.filterByKeyword[keyword] = [oldEntry, filter];
2318 }
2319 else
2320 {
2321 oldEntry.push(filter);
2322 }
2323 this.keywordByFilter[filter.text] = keyword;
2324 },
2325 remove: function(filter)
2326 {
2327 if (!(filter.text in this.keywordByFilter))
2328 {
2329 return;
2330 }
2331 var keyword = this.keywordByFilter[filter.text];
2332 var list = this.filterByKeyword[keyword];
2333 if (list.length <= 1)
2334 {
2335 delete this.filterByKeyword[keyword];
2336 }
2337 else
2338 {
2339 var index = list.indexOf(filter);
2340 if (index >= 0)
2341 {
2342 list.splice(index, 1);
2343 if (list.length == 1)
2344 {
2345 this.filterByKeyword[keyword] = list[0];
2346 }
2347 }
2348 }
2349 delete this.keywordByFilter[filter.text];
2350 },
2351 findKeyword: function(filter)
2352 {
2353 var result = "";
2354 var text = filter.text;
2355 if (Filter.regexpRegExp.test(text))
2356 {
2357 return result;
2358 }
2359 var match = Filter.optionsRegExp.exec(text);
2360 if (match)
2361 {
2362 text = match.input.substr(0, match.index);
2363 }
2364 if (text.substr(0, 2) == "@@")
2365 {
2366 text = text.substr(2);
2367 }
2368 var candidates = text.toLowerCase().match(/[^a-z0-9%*][a-z0-9%]{3,}(?=[^a- z0-9%*])/g);
2369 if (!candidates)
2370 {
2371 return result;
2372 }
2373 var hash = this.filterByKeyword;
2374 var resultCount = 16777215;
2375 var resultLength = 0;
2376 for (var i = 0, l = candidates.length; i < l; i++)
2377 {
2378 var candidate = candidates[i].substr(1);
2379 var count = candidate in hash ? hash[candidate].length : 0;
2380 if (count < resultCount || count == resultCount && candidate.length > re sultLength)
2381 {
2382 result = candidate;
2383 resultCount = count;
2384 resultLength = candidate.length;
2385 }
2386 }
2387 return result;
2388 },
2389 hasFilter: function(filter)
2390 {
2391 return filter.text in this.keywordByFilter;
2392 },
2393 getKeywordForFilter: function(filter)
2394 {
2395 if (filter.text in this.keywordByFilter)
2396 {
2397 return this.keywordByFilter[filter.text];
2398 }
2399 else
2400 {
2401 return null;
2402 }
2403 },
2404 _checkEntryMatch: function(keyword, location, contentType, docDomain, thirdP arty)
2405 {
2406 var list = this.filterByKeyword[keyword];
2407 for (var i = 0; i < list.length; i++)
2408 {
2409 var filter = list[i];
2410 if (filter.matches(location, contentType, docDomain, thirdParty))
2411 {
2412 return filter;
2413 }
2414 }
2415 return null;
2416 },
2417 matchesAny: function(location, contentType, docDomain, thirdParty)
2418 {
2419 var candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g);
2420 if (candidates === null)
2421 {
2422 candidates = [];
2423 }
2424 candidates.push("");
2425 for (var i = 0, l = candidates.length; i < l; i++)
2426 {
2427 var substr = candidates[i];
2428 if (substr in this.filterByKeyword)
2429 {
2430 var result = this._checkEntryMatch(substr, location, contentType, docD omain, thirdParty);
2431 if (result)
2432 {
2433 return result;
2434 }
2435 }
2436 }
2437 return null;
2438 }
2439 };
2440
2441 function CombinedMatcher()
2442 {
2443 this.blacklist = new Matcher();
2444 this.whitelist = new Matcher();
2445 this.keys =
2446 {
2447 __proto__: null
2448 };
2449 this.resultCache =
2450 {
2451 __proto__: null
2452 };
2453 }
2454 exports.CombinedMatcher = CombinedMatcher;
2455 CombinedMatcher.maxCacheEntries = 1000;
2456 CombinedMatcher.prototype =
2457 {
2458 blacklist: null,
2459 whitelist: null,
2460 keys: null,
2461 resultCache: null,
2462 cacheEntries: 0,
2463 clear: function()
2464 {
2465 this.blacklist.clear();
2466 this.whitelist.clear();
2467 this.keys =
2468 {
2469 __proto__: null
2470 };
2471 this.resultCache =
2472 {
2473 __proto__: null
2474 };
2475 this.cacheEntries = 0;
2476 },
2477 add: function(filter)
2478 {
2479 if (filter instanceof WhitelistFilter)
2480 {
2481 if (filter.siteKeys)
2482 {
2483 for (var i = 0; i < filter.siteKeys.length; i++)
2484 {
2485 this.keys[filter.siteKeys[i]] = filter.text;
2486 }
2487 }
2488 else
2489 {
2490 this.whitelist.add(filter);
2491 }
2492 }
2493 else
2494 {
2495 this.blacklist.add(filter);
2496 }
2497 if (this.cacheEntries > 0)
2498 {
2499 this.resultCache =
2500 {
2501 __proto__: null
2502 };
2503 this.cacheEntries = 0;
2504 }
2505 },
2506 remove: function(filter)
2507 {
2508 if (filter instanceof WhitelistFilter)
2509 {
2510 if (filter.siteKeys)
2511 {
2512 for (var i = 0; i < filter.siteKeys.length; i++)
2513 {
2514 delete this.keys[filter.siteKeys[i]];
2515 }
2516 }
2517 else
2518 {
2519 this.whitelist.remove(filter);
2520 }
2521 }
2522 else
2523 {
2524 this.blacklist.remove(filter);
2525 }
2526 if (this.cacheEntries > 0)
2527 {
2528 this.resultCache =
2529 {
2530 __proto__: null
2531 };
2532 this.cacheEntries = 0;
2533 }
2534 },
2535 findKeyword: function(filter)
2536 {
2537 if (filter instanceof WhitelistFilter)
2538 {
2539 return this.whitelist.findKeyword(filter);
2540 }
2541 else
2542 {
2543 return this.blacklist.findKeyword(filter);
2544 }
2545 },
2546 hasFilter: function(filter)
2547 {
2548 if (filter instanceof WhitelistFilter)
2549 {
2550 return this.whitelist.hasFilter(filter);
2551 }
2552 else
2553 {
2554 return this.blacklist.hasFilter(filter);
2555 }
2556 },
2557 getKeywordForFilter: function(filter)
2558 {
2559 if (filter instanceof WhitelistFilter)
2560 {
2561 return this.whitelist.getKeywordForFilter(filter);
2562 }
2563 else
2564 {
2565 return this.blacklist.getKeywordForFilter(filter);
2566 }
2567 },
2568 isSlowFilter: function(filter)
2569 {
2570 var matcher = filter instanceof WhitelistFilter ? this.whitelist : this.bl acklist;
2571 if (matcher.hasFilter(filter))
2572 {
2573 return !matcher.getKeywordForFilter(filter);
2574 }
2575 else
2576 {
2577 return !matcher.findKeyword(filter);
2578 }
2579 },
2580 matchesAnyInternal: function(location, contentType, docDomain, thirdParty)
2581 {
2582 var candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g);
2583 if (candidates === null)
2584 {
2585 candidates = [];
2586 }
2587 candidates.push("");
2588 var blacklistHit = null;
2589 for (var i = 0, l = candidates.length; i < l; i++)
2590 {
2591 var substr = candidates[i];
2592 if (substr in this.whitelist.filterByKeyword)
2593 {
2594 var result = this.whitelist._checkEntryMatch(substr, location, content Type, docDomain, thirdParty);
2595 if (result)
2596 {
2597 return result;
2598 }
2599 }
2600 if (substr in this.blacklist.filterByKeyword && blacklistHit === null)
2601 {
2602 blacklistHit = this.blacklist._checkEntryMatch(substr, location, conte ntType, docDomain, thirdParty);
2603 }
2604 }
2605 return blacklistHit;
2606 },
2607 matchesAny: function(location, contentType, docDomain, thirdParty)
2608 {
2609 var key = location + " " + contentType + " " + docDomain + " " + thirdPart y;
2610 if (key in this.resultCache)
2611 {
2612 return this.resultCache[key];
2613 }
2614 var result = this.matchesAnyInternal(location, contentType, docDomain, thi rdParty);
2615 if (this.cacheEntries >= CombinedMatcher.maxCacheEntries)
2616 {
2617 this.resultCache =
2618 {
2619 __proto__: null
2620 };
2621 this.cacheEntries = 0;
2622 }
2623 this.resultCache[key] = result;
2624 this.cacheEntries++;
2625 return result;
2626 },
2627 matchesByKey: function(location, key, docDomain)
2628 {
2629 key = key.toUpperCase();
2630 if (key in this.keys)
2631 {
2632 var filter = Filter.knownFilters[this.keys[key]];
2633 if (filter && filter.matches(location, "DOCUMENT", docDomain, false))
2634 {
2635 return filter;
2636 }
2637 else
2638 {
2639 return null;
2640 }
2641 }
2642 else
2643 {
2644 return null;
2645 }
2646 }
2647 };
2648 var defaultMatcher = exports.defaultMatcher = new CombinedMatcher();
2649 return exports;
2650 })();
2651 require.scopes["filterListener"] = (function()
2652 {
2653 var exports = {};
2654 var FilterStorage = require("filterStorage").FilterStorage;
2655 var FilterNotifier = require("filterNotifier").FilterNotifier;
2656 var ElemHide = require("elemHide").ElemHide;
2657 var defaultMatcher = require("matcher").defaultMatcher;
2658 var _tempVar19 = require("filterClasses");
2659 var ActiveFilter = _tempVar19.ActiveFilter;
2660 var RegExpFilter = _tempVar19.RegExpFilter;
2661 var ElemHideBase = _tempVar19.ElemHideBase;
2662 var Prefs = require("prefs").Prefs;
2663 var batchMode = false;
2664 var isDirty = 0;
2665 var FilterListener = exports.FilterListener =
2666 {
2667 get batchMode()
2668 {
2669 return batchMode;
2670 },
2671 set batchMode(value)
2672 {
2673 batchMode = value;
2674 flushElemHide();
2675 },
2676 setDirty: function(factor)
2677 {
2678 if (factor == 0 && isDirty > 0)
2679 {
2680 isDirty = 1;
2681 }
2682 else
2683 {
2684 isDirty += factor;
2685 }
2686 if (isDirty >= 1)
2687 {
2688 FilterStorage.saveToDisk();
2689 }
2690 }
2691 };
2692 var HistoryPurgeObserver =
2693 {
2694 observe: function(subject, topic, data)
2695 {
2696 if (topic == "browser:purge-session-history" && Prefs.clearStatsOnHistoryP urge)
2697 {
2698 FilterStorage.resetHitCounts();
2699 FilterListener.setDirty(0);
2700 Prefs.recentReports = [];
2701 }
2702 },
2703 QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference, Ci.nsIOb server])
2704 };
2705
2706 function init()
2707 {
2708 FilterNotifier.addListener(function(action, item, newValue, oldValue)
2709 {
2710 var match = /^(\w+)\.(.*)/.exec(action);
2711 if (match && match[1] == "filter")
2712 {
2713 onFilterChange(match[2], item, newValue, oldValue);
2714 }
2715 else if (match && match[1] == "subscription")
2716 {
2717 onSubscriptionChange(match[2], item, newValue, oldValue);
2718 }
2719 else
2720 {
2721 onGenericChange(action, item);
2722 }
2723 });
2724 var application = require("info").application;
2725 if (application == "chrome")
2726 {
2727 flushElemHide = function(){};
2728 }
2729 else
2730 {
2731 ElemHide.init();
2732 }
2733 FilterStorage.loadFromDisk();
2734 Services.obs.addObserver(HistoryPurgeObserver, "browser:purge-session-histor y", true);
2735 onShutdown.add(function()
2736 {
2737 Services.obs.removeObserver(HistoryPurgeObserver, "browser:purge-session-h istory");
2738 });
2739 }
2740 init();
2741
2742 function flushElemHide()
2743 {
2744 if (!batchMode && ElemHide.isDirty)
2745 {
2746 ElemHide.apply();
2747 }
2748 }
2749
2750 function addFilter(filter)
2751 {
2752 if (!(filter instanceof ActiveFilter) || filter.disabled)
2753 {
2754 return;
2755 }
2756 var hasEnabled = false;
2757 for (var i = 0; i < filter.subscriptions.length; i++)
2758 {
2759 if (!filter.subscriptions[i].disabled)
2760 {
2761 hasEnabled = true;
2762 }
2763 }
2764 if (!hasEnabled)
2765 {
2766 return;
2767 }
2768 if (filter instanceof RegExpFilter)
2769 {
2770 defaultMatcher.add(filter);
2771 }
2772 else if (filter instanceof ElemHideBase)
2773 {
2774 ElemHide.add(filter);
2775 }
2776 }
2777
2778 function removeFilter(filter)
2779 {
2780 if (!(filter instanceof ActiveFilter))
2781 {
2782 return;
2783 }
2784 if (!filter.disabled)
2785 {
2786 var hasEnabled = false;
2787 for (var i = 0; i < filter.subscriptions.length; i++)
2788 {
2789 if (!filter.subscriptions[i].disabled)
2790 {
2791 hasEnabled = true;
2792 }
2793 }
2794 if (hasEnabled)
2795 {
2796 return;
2797 }
2798 }
2799 if (filter instanceof RegExpFilter)
2800 {
2801 defaultMatcher.remove(filter);
2802 }
2803 else if (filter instanceof ElemHideBase)
2804 {
2805 ElemHide.remove(filter);
2806 }
2807 }
2808
2809 function onSubscriptionChange(action, subscription, newValue, oldValue)
2810 {
2811 FilterListener.setDirty(1);
2812 if (action != "added" && action != "removed" && action != "disabled" && acti on != "updated")
2813 {
2814 return;
2815 }
2816 if (action != "removed" && !(subscription.url in FilterStorage.knownSubscrip tions))
2817 {
2818 return;
2819 }
2820 if ((action == "added" || action == "removed" || action == "updated") && sub scription.disabled)
2821 {
2822 return;
2823 }
2824 if (action == "added" || action == "removed" || action == "disabled")
2825 {
2826 var method = action == "added" || action == "disabled" && newValue == fals e ? addFilter : removeFilter;
2827 if (subscription.filters)
2828 {
2829 subscription.filters.forEach(method);
2830 }
2831 }
2832 else if (action == "updated")
2833 {
2834 subscription.oldFilters.forEach(removeFilter);
2835 subscription.filters.forEach(addFilter);
2836 }
2837 flushElemHide();
2838 }
2839
2840 function onFilterChange(action, filter, newValue, oldValue)
2841 {
2842 if (action == "hitCount" || action == "lastHit")
2843 {
2844 FilterListener.setDirty(0.002);
2845 }
2846 else
2847 {
2848 FilterListener.setDirty(1);
2849 }
2850 if (action != "added" && action != "removed" && action != "disabled")
2851 {
2852 return;
2853 }
2854 if ((action == "added" || action == "removed") && filter.disabled)
2855 {
2856 return;
2857 }
2858 if (action == "added" || action == "disabled" && newValue == false)
2859 {
2860 addFilter(filter);
2861 }
2862 else
2863 {
2864 removeFilter(filter);
2865 }
2866 flushElemHide();
2867 }
2868
2869 function onGenericChange(action)
2870 {
2871 if (action == "load")
2872 {
2873 isDirty = 0;
2874 defaultMatcher.clear();
2875 ElemHide.clear();
2876 for (var _loopIndex20 = 0; _loopIndex20 < FilterStorage.subscriptions.leng th; ++_loopIndex20)
2877 {
2878 var subscription = FilterStorage.subscriptions[_loopIndex20];
2879 if (!subscription.disabled)
2880 {
2881 subscription.filters.forEach(addFilter);
2882 }
2883 }
2884 flushElemHide();
2885 }
2886 else if (action == "save")
2887 {
2888 isDirty = 0;
2889 }
2890 }
2891 return exports;
2892 })();
2893 require.scopes["synchronizer"] = (function()
2894 {
2895 var exports = {};
2896 var Utils = require("utils").Utils;
2897 var FilterStorage = require("filterStorage").FilterStorage;
2898 var FilterNotifier = require("filterNotifier").FilterNotifier;
2899 var Prefs = require("prefs").Prefs;
2900 var _tempVar21 = require("filterClasses");
2901 var Filter = _tempVar21.Filter;
2902 var CommentFilter = _tempVar21.CommentFilter;
2903 var _tempVar22 = require("subscriptionClasses");
2904 var Subscription = _tempVar22.Subscription;
2905 var DownloadableSubscription = _tempVar22.DownloadableSubscription;
2906 var MILLISECONDS_IN_SECOND = 1000;
2907 var SECONDS_IN_MINUTE = 60;
2908 var SECONDS_IN_HOUR = 60 * SECONDS_IN_MINUTE;
2909 var SECONDS_IN_DAY = 24 * SECONDS_IN_HOUR;
2910 var INITIAL_DELAY = 6 * SECONDS_IN_MINUTE;
2911 var CHECK_INTERVAL = SECONDS_IN_HOUR;
2912 var MIN_EXPIRATION_INTERVAL = 1 * SECONDS_IN_DAY;
2913 var MAX_EXPIRATION_INTERVAL = 14 * SECONDS_IN_DAY;
2914 var MAX_ABSENSE_INTERVAL = 1 * SECONDS_IN_DAY;
2915 var timer = null;
2916 var executing =
2917 {
2918 __proto__: null
2919 };
2920 var Synchronizer = exports.Synchronizer =
2921 {
2922 init: function()
2923 {
2924 var callback = function()
2925 {
2926 timer.delay = CHECK_INTERVAL * MILLISECONDS_IN_SECOND;
2927 checkSubscriptions();
2928 };
2929 timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
2930 timer.initWithCallback(callback, INITIAL_DELAY * MILLISECONDS_IN_SECOND, C i.nsITimer.TYPE_REPEATING_SLACK);
2931 onShutdown.add(function()
2932 {
2933 timer.cancel();
2934 });
2935 },
2936 isExecuting: function(url)
2937 {
2938 return url in executing;
2939 },
2940 execute: function(subscription, manual, forceDownload)
2941 {
2942 Utils.runAsync(this.executeInternal, this, subscription, manual, forceDown load);
2943 },
2944 executeInternal: function(subscription, manual, forceDownload)
2945 {
2946 var url = subscription.url;
2947 if (url in executing)
2948 {
2949 return;
2950 }
2951 var newURL = subscription.nextURL;
2952 var hadTemporaryRedirect = false;
2953 subscription.nextURL = null;
2954 var loadFrom = newURL;
2955 var isBaseLocation = true;
2956 if (!loadFrom)
2957 {
2958 loadFrom = url;
2959 }
2960 if (loadFrom == url)
2961 {
2962 if (subscription.alternativeLocations)
2963 {
2964 var options = [
2965 [1, url]
2966 ];
2967 var totalWeight = 1;
2968 for (var _loopIndex23 = 0; _loopIndex23 < subscription.alternativeLoca tions.split(",").length; ++_loopIndex23)
2969 {
2970 var alternative = subscription.alternativeLocations.split(",")[_loop Index23];
2971 if (!/^https?:\/\//.test(alternative))
2972 {
2973 continue;
2974 }
2975 var weight = 1;
2976 var match = /;q=([\d\.]+)$/.exec(alternative);
2977 if (match)
2978 {
2979 weight = parseFloat(match[1]);
2980 if (isNaN(weight) || !isFinite(weight) || weight < 0)
2981 {
2982 weight = 1;
2983 }
2984 if (weight > 10)
2985 {
2986 weight = 10;
2987 }
2988 alternative = alternative.substr(0, match.index);
2989 }
2990 options.push([weight, alternative]);
2991 totalWeight += weight;
2992 }
2993 var choice = Math.random() * totalWeight;
2994 for (var _loopIndex24 = 0; _loopIndex24 < options.length; ++_loopIndex 24)
2995 {
2996 var _tempVar25 = options[_loopIndex24];
2997 var weight = _tempVar25[0];
2998 var alternative = _tempVar25[1];
2999 choice -= weight;
3000 if (choice < 0)
3001 {
3002 loadFrom = alternative;
3003 break;
3004 }
3005 }
3006 isBaseLocation = loadFrom == url;
3007 }
3008 }
3009 else
3010 {
3011 forceDownload = true;
3012 }
3013 var addonVersion = require("info").addonVersion;
3014 loadFrom = loadFrom.replace(/%VERSION%/, "ABP" + addonVersion);
3015 var request = null;
3016
3017 function errorCallback(error)
3018 {
3019 var channelStatus = -1;
3020 try
3021 {
3022 channelStatus = request.channel.status;
3023 }
3024 catch (e){}
3025 var responseStatus = "";
3026 try
3027 {
3028 responseStatus = request.channel.QueryInterface(Ci.nsIHttpChannel).res ponseStatus;
3029 }
3030 catch (e){}
3031 setError(subscription, error, channelStatus, responseStatus, loadFrom, i sBaseLocation, manual);
3032 }
3033 try
3034 {
3035 request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(C i.nsIXMLHttpRequest);
3036 request.mozBackgroundRequest = true;
3037 request.open("GET", loadFrom);
3038 }
3039 catch (e)
3040 {
3041 errorCallback("synchronize_invalid_url");
3042 return;
3043 }
3044 try
3045 {
3046 request.overrideMimeType("text/plain");
3047 request.channel.loadFlags = request.channel.loadFlags | request.channel. INHIBIT_CACHING | request.channel.VALIDATE_ALWAYS;
3048 if (request.channel instanceof Ci.nsIHttpChannel)
3049 {
3050 request.channel.redirectionLimit = 5;
3051 }
3052 var oldNotifications = request.channel.notificationCallbacks;
3053 var oldEventSink = null;
3054 request.channel.notificationCallbacks =
3055 {
3056 QueryInterface: XPCOMUtils.generateQI([Ci.nsIInterfaceRequestor, Ci.ns IChannelEventSink]),
3057 getInterface: function(iid)
3058 {
3059 if (iid.equals(Ci.nsIChannelEventSink))
3060 {
3061 try
3062 {
3063 oldEventSink = oldNotifications.QueryInterface(iid);
3064 }
3065 catch (e){}
3066 return this;
3067 }
3068 if (oldNotifications)
3069 {
3070 return oldNotifications.QueryInterface(iid);
3071 }
3072 else
3073 {
3074 throw Cr.NS_ERROR_NO_INTERFACE;
3075 }
3076 },
3077 asyncOnChannelRedirect: function(oldChannel, newChannel, flags, callba ck)
3078 {
3079 if (isBaseLocation && !hadTemporaryRedirect && oldChannel instanceof Ci.nsIHttpChannel)
3080 {
3081 try
3082 {
3083 subscription.alternativeLocations = oldChannel.getResponseHeader ("X-Alternative-Locations");
3084 }
3085 catch (e)
3086 {
3087 subscription.alternativeLocations = null;
3088 }
3089 }
3090 if (flags & Ci.nsIChannelEventSink.REDIRECT_TEMPORARY)
3091 {
3092 hadTemporaryRedirect = true;
3093 }
3094 else if (!hadTemporaryRedirect)
3095 {
3096 newURL = newChannel.URI.spec;
3097 }
3098 if (oldEventSink)
3099 {
3100 oldEventSink.asyncOnChannelRedirect(oldChannel, newChannel, flags, callback);
3101 }
3102 else
3103 {
3104 callback.onRedirectVerifyCallback(Cr.NS_OK);
3105 }
3106 }
3107 };
3108 }
3109 catch (e)
3110 {
3111 Cu.reportError(e);
3112 }
3113 if (subscription.lastModified && !forceDownload)
3114 {
3115 request.setRequestHeader("If-Modified-Since", subscription.lastModified) ;
3116 }
3117 request.addEventListener("error", function(ev)
3118 {
3119 if (onShutdown.done)
3120 {
3121 return;
3122 }
3123 delete executing[url];
3124 try
3125 {
3126 request.channel.notificationCallbacks = null;
3127 }
3128 catch (e){}
3129 errorCallback("synchronize_connection_error");
3130 }, false);
3131 request.addEventListener("load", function(ev)
3132 {
3133 if (onShutdown.done)
3134 {
3135 return;
3136 }
3137 delete executing[url];
3138 try
3139 {
3140 request.channel.notificationCallbacks = null;
3141 }
3142 catch (e){}
3143 if (request.status && request.status != 200 && request.status != 304)
3144 {
3145 errorCallback("synchronize_connection_error");
3146 return;
3147 }
3148 var newFilters = null;
3149 if (request.status != 304)
3150 {
3151 newFilters = readFilters(subscription, request.responseText, errorCall back);
3152 if (!newFilters)
3153 {
3154 return;
3155 }
3156 subscription.lastModified = request.getResponseHeader("Last-Modified") ;
3157 }
3158 if (isBaseLocation && !hadTemporaryRedirect)
3159 {
3160 subscription.alternativeLocations = request.getResponseHeader("X-Alter native-Locations");
3161 }
3162 subscription.lastSuccess = subscription.lastDownload = Math.round(Date.n ow() / MILLISECONDS_IN_SECOND);
3163 subscription.downloadStatus = "synchronize_ok";
3164 subscription.errors = 0;
3165 var now = Math.round(((new Date(request.getResponseHeader("Date"))).getT ime() || Date.now()) / MILLISECONDS_IN_SECOND);
3166 var expires = Math.round((new Date(request.getResponseHeader("Expires")) ).getTime() / MILLISECONDS_IN_SECOND) || 0;
3167 var expirationInterval = expires ? expires - now : 0;
3168 for (var _loopIndex26 = 0; _loopIndex26 < (newFilters || subscription.fi lters).length; ++_loopIndex26)
3169 {
3170 var filter = (newFilters || subscription.filters)[_loopIndex26];
3171 if (!(filter instanceof CommentFilter))
3172 {
3173 continue;
3174 }
3175 var match = /\bExpires\s*(?::|after)\s*(\d+)\s*(h)?/i.exec(filter.text );
3176 if (match)
3177 {
3178 var interval = parseInt(match[1], 10);
3179 if (match[2])
3180 {
3181 interval *= SECONDS_IN_HOUR;
3182 }
3183 else
3184 {
3185 interval *= SECONDS_IN_DAY;
3186 }
3187 if (interval > expirationInterval)
3188 {
3189 expirationInterval = interval;
3190 }
3191 }
3192 }
3193 expirationInterval = Math.min(Math.max(expirationInterval, MIN_EXPIRATIO N_INTERVAL), MAX_EXPIRATION_INTERVAL);
3194 subscription.expires = subscription.lastDownload + expirationInterval * 2;
3195 subscription.softExpiration = subscription.lastDownload + Math.round(exp irationInterval * (Math.random() * 0.4 + 0.8));
3196 if (newFilters)
3197 {
3198 var fixedTitle = false;
3199 for (var i = 0; i < newFilters.length; i++)
3200 {
3201 var filter = newFilters[i];
3202 if (!(filter instanceof CommentFilter))
3203 {
3204 continue;
3205 }
3206 var match = /^!\s*(\w+)\s*:\s*(.*)/.exec(filter.text);
3207 if (match)
3208 {
3209 var keyword = match[1].toLowerCase();
3210 var value = match[2];
3211 var known = true;
3212 if (keyword == "redirect")
3213 {
3214 if (isBaseLocation && value != url)
3215 {
3216 subscription.nextURL = value;
3217 }
3218 }
3219 else if (keyword == "homepage")
3220 {
3221 var uri = Utils.makeURI(value);
3222 if (uri && (uri.scheme == "http" || uri.scheme == "https"))
3223 {
3224 subscription.homepage = uri.spec;
3225 }
3226 }
3227 else if (keyword == "title")
3228 {
3229 if (value)
3230 {
3231 subscription.title = value;
3232 fixedTitle = true;
3233 }
3234 }
3235 else
3236 {
3237 known = false;
3238 }
3239 if (known)
3240 {
3241 newFilters.splice(i--, 1);
3242 }
3243 }
3244 }
3245 subscription.fixedTitle = fixedTitle;
3246 }
3247 if (isBaseLocation && newURL && newURL != url)
3248 {
3249 var listed = subscription.url in FilterStorage.knownSubscriptions;
3250 if (listed)
3251 {
3252 FilterStorage.removeSubscription(subscription);
3253 }
3254 url = newURL;
3255 var newSubscription = Subscription.fromURL(url);
3256 for (var key in newSubscription)
3257 {
3258 delete newSubscription[key];
3259 }
3260 for (var key in subscription)
3261 {
3262 newSubscription[key] = subscription[key];
3263 }
3264 delete Subscription.knownSubscriptions[subscription.url];
3265 newSubscription.oldSubscription = subscription;
3266 subscription = newSubscription;
3267 subscription.url = url;
3268 if (!(subscription.url in FilterStorage.knownSubscriptions) && listed)
3269 {
3270 FilterStorage.addSubscription(subscription);
3271 }
3272 }
3273 if (newFilters)
3274 {
3275 FilterStorage.updateSubscriptionFilters(subscription, newFilters);
3276 }
3277 delete subscription.oldSubscription;
3278 }, false);
3279 executing[url] = true;
3280 FilterNotifier.triggerListeners("subscription.downloadStatus", subscriptio n);
3281 try
3282 {
3283 request.send(null);
3284 }
3285 catch (e)
3286 {
3287 delete executing[url];
3288 errorCallback("synchronize_connection_error");
3289 return;
3290 }
3291 }
3292 };
3293 Synchronizer.init();
3294
3295 function checkSubscriptions()
3296 {
3297 if (!Prefs.subscriptions_autoupdate)
3298 {
3299 return;
3300 }
3301 var time = Math.round(Date.now() / MILLISECONDS_IN_SECOND);
3302 for (var _loopIndex27 = 0; _loopIndex27 < FilterStorage.subscriptions.length ; ++_loopIndex27)
3303 {
3304 var subscription = FilterStorage.subscriptions[_loopIndex27];
3305 if (!(subscription instanceof DownloadableSubscription))
3306 {
3307 continue;
3308 }
3309 if (subscription.lastCheck && time - subscription.lastCheck > MAX_ABSENSE_ INTERVAL)
3310 {
3311 subscription.softExpiration += time - subscription.lastCheck;
3312 }
3313 subscription.lastCheck = time;
3314 if (subscription.expires - time > MAX_EXPIRATION_INTERVAL)
3315 {
3316 subscription.expires = time + MAX_EXPIRATION_INTERVAL;
3317 }
3318 if (subscription.softExpiration - time > MAX_EXPIRATION_INTERVAL)
3319 {
3320 subscription.softExpiration = time + MAX_EXPIRATION_INTERVAL;
3321 }
3322 if (subscription.softExpiration > time && subscription.expires > time)
3323 {
3324 continue;
3325 }
3326 if (time - subscription.lastDownload >= MIN_EXPIRATION_INTERVAL)
3327 {
3328 Synchronizer.execute(subscription, false);
3329 }
3330 }
3331 }
3332
3333 function readFilters(subscription, text, errorCallback)
3334 {
3335 var lines = text.split(/[\r\n]+/);
3336 var match = /\[Adblock(?:\s*Plus\s*([\d\.]+)?)?\]/i.exec(lines[0]);
3337 if (!match)
3338 {
3339 errorCallback("synchronize_invalid_data");
3340 return null;
3341 }
3342 var minVersion = match[1];
3343 for (var i = 0; i < lines.length; i++)
3344 {
3345 var match = /!\s*checksum[\s\-:]+([\w\+\/]+)/i.exec(lines[i]);
3346 if (match)
3347 {
3348 lines.splice(i, 1);
3349 var checksum = Utils.generateChecksum(lines);
3350 if (checksum && checksum != match[1])
3351 {
3352 errorCallback("synchronize_checksum_mismatch");
3353 return null;
3354 }
3355 break;
3356 }
3357 }
3358 delete subscription.requiredVersion;
3359 delete subscription.upgradeRequired;
3360 if (minVersion)
3361 {
3362 var addonVersion = require("info").addonVersion;
3363 subscription.requiredVersion = minVersion;
3364 if (Services.vc.compare(minVersion, addonVersion) > 0)
3365 {
3366 subscription.upgradeRequired = true;
3367 }
3368 }
3369 lines.shift();
3370 var result = [];
3371 for (var _loopIndex28 = 0; _loopIndex28 < lines.length; ++_loopIndex28)
3372 {
3373 var line = lines[_loopIndex28];
3374 line = Filter.normalize(line);
3375 if (line)
3376 {
3377 result.push(Filter.fromText(line));
3378 }
3379 }
3380 return result;
3381 }
3382
3383 function setError(subscription, error, channelStatus, responseStatus, download URL, isBaseLocation, manual)
3384 {
3385 if (!isBaseLocation)
3386 {
3387 subscription.alternativeLocations = null;
3388 }
3389 try
3390 {
3391 Cu.reportError("Adblock Plus: Downloading filter subscription " + subscrip tion.title + " failed (" + Utils.getString(error) + ")\n" + "Download address: " + downloadURL + "\n" + "Channel status: " + channelStatus + "\n" + "Server resp onse: " + responseStatus);
3392 }
3393 catch (e){}
3394 subscription.lastDownload = Math.round(Date.now() / MILLISECONDS_IN_SECOND);
3395 subscription.downloadStatus = error;
3396 if (!manual)
3397 {
3398 if (error == "synchronize_checksum_mismatch")
3399 {
3400 subscription.errors = 0;
3401 }
3402 else
3403 {
3404 subscription.errors++;
3405 }
3406 if (subscription.errors >= Prefs.subscriptions_fallbackerrors && /^https?: \/\//i.test(subscription.url))
3407 {
3408 subscription.errors = 0;
3409 var fallbackURL = Prefs.subscriptions_fallbackurl;
3410 var addonVersion = require("info").addonVersion;
3411 fallbackURL = fallbackURL.replace(/%VERSION%/g, encodeURIComponent(addon Version));
3412 fallbackURL = fallbackURL.replace(/%SUBSCRIPTION%/g, encodeURIComponent( subscription.url));
3413 fallbackURL = fallbackURL.replace(/%URL%/g, encodeURIComponent(downloadU RL));
3414 fallbackURL = fallbackURL.replace(/%ERROR%/g, encodeURIComponent(error)) ;
3415 fallbackURL = fallbackURL.replace(/%CHANNELSTATUS%/g, encodeURIComponent (channelStatus));
3416 fallbackURL = fallbackURL.replace(/%RESPONSESTATUS%/g, encodeURIComponen t(responseStatus));
3417 var request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstan ce(Ci.nsIXMLHttpRequest);
3418 request.mozBackgroundRequest = true;
3419 request.open("GET", fallbackURL);
3420 request.overrideMimeType("text/plain");
3421 request.channel.loadFlags = request.channel.loadFlags | request.channel. INHIBIT_CACHING | request.channel.VALIDATE_ALWAYS;
3422 request.addEventListener("load", function(ev)
3423 {
3424 if (onShutdown.done)
3425 {
3426 return;
3427 }
3428 if (!(subscription.url in FilterStorage.knownSubscriptions))
3429 {
3430 return;
3431 }
3432 var match = /^(\d+)(?:\s+(\S+))?$/.exec(request.responseText);
3433 if (match && match[1] == "301" && match[2])
3434 {
3435 subscription.nextURL = match[2];
3436 }
3437 else if (match && match[1] == "410")
3438 {
3439 var data = "[Adblock]\n" + subscription.filters.map(function(f)
3440 {
3441 return f.text;
3442 }).join("\n");
3443 var url = "data:text/plain," + encodeURIComponent(data);
3444 var newSubscription = Subscription.fromURL(url);
3445 newSubscription.title = subscription.title;
3446 newSubscription.disabled = subscription.disabled;
3447 FilterStorage.removeSubscription(subscription);
3448 FilterStorage.addSubscription(newSubscription);
3449 Synchronizer.execute(newSubscription);
3450 }
3451 }, false);
3452 request.send(null);
3453 }
3454 }
3455 }
3456 return exports;
3457 })();
OLDNEW
« no previous file with comments | « include/AdblockPlus/JsEngine.h ('k') | lib/compat.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld