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

Side by Side Diff: lib/adblockplus.js

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

Powered by Google App Engine
This is Rietveld