├── skin
├── icon.png
├── blocked.png
├── toolbar.png
├── spinner16.gif
├── toolbar-large.png
├── kabl-monitor.css
├── kabl-overlay.css
└── kabl-config.css
├── chrome.manifest
├── install.rdf
├── content
├── kabl-overlay.xul
├── kabl-lib.js
├── kabl-config.xul
├── kabl-frame.js
├── kabl-monitor.xul
├── kabl-inserter.js
├── kabl-sync.js
├── kabl-overlay.js
├── kabl-pref.js
├── kabl-config.js
├── kabl-monitor.js
├── kabl-parse.js
└── kabl-policy.js
├── defaults
└── preferences
│ └── kabl.js
├── README.md
└── LICENSE
/skin/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arantius/karma-blocker/HEAD/skin/icon.png
--------------------------------------------------------------------------------
/skin/blocked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arantius/karma-blocker/HEAD/skin/blocked.png
--------------------------------------------------------------------------------
/skin/toolbar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arantius/karma-blocker/HEAD/skin/toolbar.png
--------------------------------------------------------------------------------
/skin/spinner16.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arantius/karma-blocker/HEAD/skin/spinner16.gif
--------------------------------------------------------------------------------
/skin/toolbar-large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arantius/karma-blocker/HEAD/skin/toolbar-large.png
--------------------------------------------------------------------------------
/skin/kabl-monitor.css:
--------------------------------------------------------------------------------
1 | dialog {
2 | min-height: 40em;
3 | min-width: 50em;
4 | }
5 |
6 | treechildren:-moz-tree-cell(blocked) {
7 | background: url('chrome://kabl/skin/blocked.png') 50% 50% no-repeat;
8 | }
9 |
--------------------------------------------------------------------------------
/chrome.manifest:
--------------------------------------------------------------------------------
1 | content kabl content/
2 | skin kabl classic/1.0 skin/
3 |
4 | overlay chrome://browser/content/browser.xul chrome://kabl/content/kabl-overlay.xul
5 | style chrome://browser/content/browser.xul chrome://kabl/skin/kabl-overlay.css
6 | style chrome://global/content/customizeToolbar.xul chrome://kabl/skin/kabl-overlay.css
7 |
--------------------------------------------------------------------------------
/skin/kabl-overlay.css:
--------------------------------------------------------------------------------
1 | #tb-kabl {
2 | list-style-image: url("chrome://kabl/skin/toolbar-large.png");
3 | }
4 | toolbar[iconsize="small"] #tb-kabl {
5 | list-style-image: url("chrome://kabl/skin/toolbar.png");
6 | }
7 |
8 | #tb-kabl[kabl_disabled="yes"] {
9 | opacity: 0.8;
10 | }
11 | #tb-kabl[kabl_disabled="yes"] .toolbarbutton-icon {
12 | opacity: 0.5;
13 | }
14 |
15 | .popup-notification-icon[popupid="kabl-update-conflict"] {
16 | list-style-image: url("chrome://kabl/skin/icon.png");
17 | }
18 |
--------------------------------------------------------------------------------
/skin/kabl-config.css:
--------------------------------------------------------------------------------
1 | #status_box {
2 | padding-top: 7px;
3 | }
4 |
5 | textbox#rules {
6 | margin: 0px 5px;
7 | font-family: monospace;
8 | }
9 |
10 | textbox#status_line {
11 | margin-right: 5px;
12 | padding-left: 8px;
13 | cursor: default;
14 | }
15 | textbox#status_line input {
16 | display: none;
17 | }
18 | textbox#status_line label {
19 | margin-left: 0;
20 | }
21 |
22 | button[dlgtype='extra1'] {
23 | float: left;
24 | }
25 |
26 | button#sync_now image { display: none; }
27 | button#sync_now.loading image { display: block; } /* why not -moz-box ? */
28 |
--------------------------------------------------------------------------------
/install.rdf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | kabl@trac.arantius.com
5 | Karma Blocker
6 | 0.6.2beta2
7 | Block resources based on their karma.
8 | 2
9 |
10 | Anthony Lieuallen
11 |
12 | chrome://kabl/skin/icon.png
13 | http://trac.arantius.com/wiki/Extensions/KarmaBlocker
14 | chrome://kabl/content/kabl-config.xul
15 |
16 |
17 |
18 | {ec8030f7-c20a-464f-9b0e-13a3a9e97384}
19 | 40.0
20 | 45.*
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/content/kabl-overlay.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
13 |
14 |
17 |
20 |
23 |
26 |
27 |
28 |
29 |
30 |
31 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/content/kabl-lib.js:
--------------------------------------------------------------------------------
1 | // ***** BEGIN LICENSE BLOCK *****
2 | // Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 | //
4 | // The contents of this file are subject to the Mozilla Public License Version
5 | // 1.1 (the 'License'); you may not use this file except in compliance with
6 | // the License. You may obtain a copy of the License at
7 | // http://www.mozilla.org/MPL/
8 | //
9 | // Software distributed under the License is distributed on an 'AS IS' basis,
10 | // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 | // for the specific language governing rights and limitations under the
12 | // License.
13 | //
14 | // The Initial Developer of the Original Code is Anthony Lieuallen.
15 | //
16 | // Portions created by the Initial Developer are Copyright (C) 2007
17 | // the Initial Developer. All Rights Reserved.
18 | //
19 | // Alternatively, the contents of this file may be used under the terms of
20 | // either the GNU General Public License Version 2 or later (the 'GPL'), or
21 | // the GNU Lesser General Public License Version 2.1 or later (the 'LGPL'),
22 | // in which case the provisions of the GPL or the LGPL are applicable instead
23 | // of those above. If you wish to allow use of your version of this file only
24 | // under the terms of either the GPL or the LGPL, and not to allow others to
25 | // use your version of this file under the terms of the MPL, indicate your
26 | // decision by deleting the provisions above and replace them with the notice
27 | // and other provisions required by the GPL or the LGPL. If you do not delete
28 | // the provisions above, a recipient may use your version of this file under
29 | // the terms of any one of the MPL, the GPL or the LGPL.
30 | //
31 | // ***** END LICENSE BLOCK *****
32 |
33 | var EXPORTED_SYMBOLS=['gKablActiveWin', 'gKablBrowserWin'];
34 |
35 | function gKablActiveWin() {
36 | var ww=Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
37 | .getService(Components.interfaces.nsIWindowWatcher);
38 | return ww.activeWindow;
39 | }
40 |
41 | function gKablBrowserWin() {
42 | var windowMediator=Components
43 | .classes["@mozilla.org/appshell/window-mediator;1"]
44 | .getService(Components.interfaces.nsIWindowMediator);
45 | return windowMediator.getMostRecentWindow("navigator:browser");
46 | }
47 |
--------------------------------------------------------------------------------
/content/kabl-config.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
59 |
--------------------------------------------------------------------------------
/content/kabl-frame.js:
--------------------------------------------------------------------------------
1 | // ***** BEGIN LICENSE BLOCK *****
2 | // Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 | //
4 | // The contents of this file are subject to the Mozilla Public License Version
5 | // 1.1 (the 'License'); you may not use this file except in compliance with
6 | // the License. You may obtain a copy of the License at
7 | // http://www.mozilla.org/MPL/
8 | //
9 | // Software distributed under the License is distributed on an 'AS IS' basis,
10 | // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 | // for the specific language governing rights and limitations under the
12 | // License.
13 | //
14 | // The Initial Developer of the Original Code is Anthony Lieuallen.
15 | //
16 | // Portions created by the Initial Developer are Copyright (C) 2007
17 | // the Initial Developer. All Rights Reserved.
18 | //
19 | // Alternatively, the contents of this file may be used under the terms of
20 | // either the GNU General Public License Version 2 or later (the 'GPL'), or
21 | // the GNU Lesser General Public License Version 2.1 or later (the 'LGPL'),
22 | // in which case the provisions of the GPL or the LGPL are applicable instead
23 | // of those above. If you wish to allow use of your version of this file only
24 | // under the terms of either the GPL or the LGPL, and not to allow others to
25 | // use your version of this file under the terms of the MPL, indicate your
26 | // decision by deleting the provisions above and replace them with the notice
27 | // and other provisions required by the GPL or the LGPL. If you do not delete
28 | // the provisions above, a recipient may use your version of this file under
29 | // the terms of any one of the MPL, the GPL or the LGPL.
30 | //
31 | // ***** END LICENSE BLOCK *****
32 |
33 | Components.utils.import('chrome://kabl/content/kabl-inserter.js');
34 | Components.utils.import('chrome://kabl/content/kabl-policy.js');
35 | Components.utils.import('chrome://kabl/content/kabl-pref.js');
36 | Components.utils.import('chrome://kabl/content/kabl-sync.js');
37 |
38 | //\\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
39 |
40 | gKablPolicy.startup();
41 | addEventListener('DOMContentLoaded', gKablPolicy.collapse, false);
42 |
43 | gKablInserter.addObserver();
44 | addEventListener('unload', gKablInserter.removeObserver, false);
45 |
--------------------------------------------------------------------------------
/content/kabl-monitor.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
82 |
--------------------------------------------------------------------------------
/content/kabl-inserter.js:
--------------------------------------------------------------------------------
1 | // ***** BEGIN LICENSE BLOCK *****
2 | // Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 | //
4 | // The contents of this file are subject to the Mozilla Public License Version
5 | // 1.1 (the 'License'); you may not use this file except in compliance with
6 | // the License. You may obtain a copy of the License at
7 | // http://www.mozilla.org/MPL/
8 | //
9 | // Software distributed under the License is distributed on an 'AS IS' basis,
10 | // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 | // for the specific language governing rights and limitations under the
12 | // License.
13 | //
14 | // The Initial Developer of the Original Code is Joe Hewitt.
15 | //
16 | // Portions created by the Initial Developer are Copyright (C) 2005
17 | // the Initial Developer. All Rights Reserved.
18 | //
19 | // Contributor(s):
20 | // Anthony Lieuallen, Copyright (C) 2007
21 | //
22 | // Alternatively, the contents of this file may be used under the terms of
23 | // either the GNU General Public License Version 2 or later (the 'GPL'), or
24 | // the GNU Lesser General Public License Version 2.1 or later (the 'LGPL'),
25 | // in which case the provisions of the GPL or the LGPL are applicable instead
26 | // of those above. If you wish to allow use of your version of this file only
27 | // under the terms of either the GPL or the LGPL, and not to allow others to
28 | // use your version of this file under the terms of the MPL, indicate your
29 | // decision by deleting the provisions above and replace them with the notice
30 | // and other provisions required by the GPL or the LGPL. If you do not delete
31 | // the provisions above, a recipient may use your version of this file under
32 | // the terms of any one of the MPL, the GPL or the LGPL.
33 | //
34 | // ***** END LICENSE BLOCK *****
35 |
36 | var EXPORTED_SYMBOLS=['gKablInserter'];
37 |
38 | Components.utils.import('resource://gre/modules/Services.jsm');
39 |
40 | Components.utils.import('chrome://kabl/content/kabl-parse.js');
41 | Components.utils.import('chrome://kabl/content/kabl-pref.js');
42 |
43 | var gKablInserter={};
44 |
45 | gKablInserter.addObserver=function() {
46 | Services.obs.addObserver(
47 | gKablInserter, 'content-document-global-created', false);
48 | };
49 |
50 | gKablInserter.removeObserver=function() {
51 | Services.obs.removeObserver(
52 | gKablInserter, 'content-document-global-created', false);
53 | };
54 |
55 | gKablInserter.observe=function(aSubject, aTopic, aData) {
56 | if ('content-document-global-created' != aTopic) return;
57 | if (!gKablPrefs.enabled) return;
58 | if (0 == gKablRulesObj.injectFunctions.length) return;
59 |
60 | var sandbox = Components.utils.Sandbox(aSubject, {
61 | 'sameZoneAs': aSubject,
62 | 'sandboxPrototype': aSubject,
63 | 'wantXrays': false,
64 | });
65 | Components.utils.evalInSandbox(
66 | gKablInserter.insertStr
67 | + ';insert('+gKablRulesObj.injectFunctionsStr+');',
68 | sandbox);
69 | };
70 |
71 | (function() {
72 | function insert(aFuncs) {
73 | var obj=function(){return arguments.callee;};
74 | obj.__noSuchMethod__=obj;
75 | obj.toString=function(){return '';};
76 |
77 | for (var i=0, func=null; func=aFuncs[i]; i++) {
78 | var subObj=obj;
79 | var name=func.split('.');
80 | var baseName=name.shift(), subName;
81 |
82 | // Don't overwrite, if the page already has this object.
83 | if ('undefined'!=typeof window[baseName]) continue;
84 |
85 | // Create properties, as necessary.
86 | while (subName=name.shift()) {
87 | subObj[subName]=obj;
88 | subObj=subObj[subName];
89 | }
90 |
91 | window[baseName]=obj;
92 | }
93 | };
94 | gKablInserter.insertStr=uneval(insert);
95 | })();
96 |
--------------------------------------------------------------------------------
/defaults/preferences/kabl.js:
--------------------------------------------------------------------------------
1 | pref('extensions.kabl.enabled', true);
2 | pref('extensions.kabl.debug', 0);
3 | pref("extensions.kabl.rules", "# This is a ruleset configuration for Karma Blocker. For more information, see:\n# http://trac.arantius.com/wiki/Extensions/KarmaBlocker\n\n# This default ruleset is intended to be demonstrative: making productive\n# use of all the features that the Karma Blocker rule syntax provides. It\n# should generally work, but it has intentionally not been tweaked to deal\n# with the particulars of any given site. All rules here are intended to\n# explain what can be done, and how it can be done, while remaining as\n# generic as possible, with limited exceptions. You the user are expected\n# to tweak and customize these rules.\n[Settings]\nthreshold=12\ncutoff=12\ncollapse=false\n\n[Inject]\nfunction='DM_tag'\nfunction='OA_show'\nfunction='_gat._getTracker'\nfunction='quantserve'\nfunction='s.t'\nfunction='setOmniturePageName'\nfunction='urchinTracker'\n\n# If any request that a Flash movie makes is blocked, the entire Flash\n# movie will remove itself from the page. So if we let the movie\n# through, we let all requests it makes go through, with this rule.\n[Group]\nname=\"Whitelist: flash sub-request\"\nscore=-13\nrule=$type==object_subrequest\n\n# eBay uses third-party iframes for auction descriptions now, to\n# prevent the XSS hole they left open for a long time.\n[Group]\nname=\"Whitelist: eBay\"\nmatch=any\nscore=-13\nrule=$url.host=='cgi.ebay.com'\nrule=$url.host=='vi.ebaydesc.com'\nrule=$url.host=='srx.main.ebayrtm.com'\n\n[Group]\nname=\"Whitelist: HTTPS\"\nscore=-4\nrule=$url.scheme=='https'\n\n[Group]\nname=\"Whitelist: CDNs\"\nscore=-4\nmatch=any\nrule=$url.host$='.akamai.com'\nrule=$url.host$='.asset-cache.com'\nrule=$url.host$='.cachefly.com'\nrule=$url.host$='.fsdn.com'\nrule=$url.host$='.ggpht.com'\nrule=$url.host$='.gstatic.com'\nrule=$url.host=~'cdn'\n\n[Group]\nname=\"Whitelist: Keywords\"\nscore=-4\nmatch=any\nrule=$url=~'(\\b|_)(downlo|uplo)ads?\\d*(\\b|_)'\n\n[Group]\nname=\"(I)FRAMEs and Scripts\"\nscore=6\nmatch=any\nrule=$type==script\nrule=$type==subdocument\n\n[Group]\nname=\"Feed Trackers\"\nscore=4\nmatch=any\nrule=$url.path=~'^/~.{1,2}/'\nrule=$url^='http://feeds.wordpress.com/1.0/'\n\n[Group]\nname=\"Size: 0x0 & 1x1\"\nscore=4\nmatch=any\nrule=$origin.tag.size=='0x0'\nrule=$origin.tag.size=='1x1'\n\n# See: http://www.iab.net/iab_products_and_industry_services/1421/1443/1452\n[Group]\nname=\"Size: Standard Banner\"\nscore=4\nmatch=any\nrule=$origin.tag.size=='300x250'\nrule=$origin.tag.size=='468x60'\nrule=$origin.tag.size=='234x60'\nrule=$origin.tag.size=='88x31'\nrule=$origin.tag.size=='120x90'\nrule=$origin.tag.size=='120x60'\nrule=$origin.tag.size=='120x240'\nrule=$origin.tag.size=='125x125'\nrule=$origin.tag.size=='728x90'\nrule=$origin.tag.size=='160x600'\nrule=$origin.tag.size=='120x600'\nrule=$origin.tag.size=='300x600'\n\n[Group]\nname=\"Third-party\"\nscore=4\nrule=$thirdParty==true\n\n[Group]\nname=\"Unsavory hosts\"\nscore=4\nmatch=any\nrule=$url.host$='.addtoany.com'\nrule=$url.host$='.blogads.com'\nrule=$url.host$='.imrworldwide.com'\nrule=$url.host$='.kontera.com'\nrule=$url.host$='.scorecardresearch.com'\nrule=$url.host$='.statcounter.com'\n\n[Group]\nname=\"Images\"\nscore=3\nrule=$type==image\n\n[Group]\nname=\"Extra-long URLs\"\nscore=2\nrule=$url.path=~'.{175}'\n\n[Group]\nname=\"Keywords (Full)\"\nscore=2\nrule=$url=~'(\\b|_)ad(frame|sense|server?|sonar)?s?\\d*(\\b|_)'\nrule=$url=~'(\\b|_)banners?\\d*(\\b|_)'\nrule=$url=~'(\\b|_)(analytic|quant|s_code|track|urchin|webtrend)(s|er|ing)?\\d*(\\b|_)'\nrule=$url.host=~'metrics'\n\n[Group]\nname=\"Keywords (Partial)\"\nscore=2\nrule=$url=~'(\\b|_)ads?\\d*|ads?\\d*(\\b|_)'\nrule=$url=~'(\\b|_)track(s|er|ing)?\\d*|track(s|er|ing)?\\d*(\\b|_)'\n\n[Group]\nname=\"Long Querystring\"\nscore=2\nmatch=all\nrule=$url.path=~'\\?(.*&){6,}'\n\n[Group]\nname=\"Objects (Flash)\"\nscore=2\nrule=$type==object\n\n[Group]\nname=\"Querystring\"\nscore=1\nrule=$url.path=~'\\?'");
4 | pref('extensions.kabl.sync_enabled', false);
5 | pref('extensions.kabl.sync_check_interval', 3600000); // ms = 1 hour
6 | pref('extensions.kabl.sync_last_rules', '');
7 | pref('extensions.kabl.sync_last_time', '0');
8 | pref('extensions.kabl.sync_update_interval', 432000000); // ms = 5 days
9 | pref('extensions.kabl.sync_url', 'https://gist.github.com/raw/857951/Karma_Blocker_Default_Rules.ini');
10 |
--------------------------------------------------------------------------------
/content/kabl-sync.js:
--------------------------------------------------------------------------------
1 | // ***** BEGIN LICENSE BLOCK *****
2 | // Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 | //
4 | // The contents of this file are subject to the Mozilla Public License Version
5 | // 1.1 (the 'License'); you may not use this file except in compliance with
6 | // the License. You may obtain a copy of the License at
7 | // http://www.mozilla.org/MPL/
8 | //
9 | // Software distributed under the License is distributed on an 'AS IS' basis,
10 | // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 | // for the specific language governing rights and limitations under the
12 | // License.
13 | //
14 | // The Initial Developer of the Original Code is Anthony Lieuallen.
15 | //
16 | // Portions created by the Initial Developer are Copyright (C) 2007
17 | // the Initial Developer. All Rights Reserved.
18 | //
19 | // Alternatively, the contents of this file may be used under the terms of
20 | // either the GNU General Public License Version 2 or later (the 'GPL'), or
21 | // the GNU Lesser General Public License Version 2.1 or later (the 'LGPL'),
22 | // in which case the provisions of the GPL or the LGPL are applicable instead
23 | // of those above. If you wish to allow use of your version of this file only
24 | // under the terms of either the GPL or the LGPL, and not to allow others to
25 | // use your version of this file under the terms of the MPL, indicate your
26 | // decision by deleting the provisions above and replace them with the notice
27 | // and other provisions required by the GPL or the LGPL. If you do not delete
28 | // the provisions above, a recipient may use your version of this file under
29 | // the terms of any one of the MPL, the GPL or the LGPL.
30 | //
31 | // ***** END LICENSE BLOCK *****
32 |
33 | var EXPORTED_SYMBOLS=['gKablRuleSync'];
34 |
35 | var Cc = Components.classes;
36 | var Ci = Components.interfaces;
37 | var Cu = Components.utils;
38 |
39 | Cu.import('chrome://kabl/content/kabl-lib.js');
40 | Cu.import('chrome://kabl/content/kabl-pref.js');
41 | Cu.import("resource://gre/modules/Services.jsm");
42 | Cu.import("resource://gre/modules/PopupNotifications.jsm");
43 |
44 | // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
45 |
46 | function gKablRuleSync(callback, force, url) {
47 | if (!force && !gKablPrefs.sync_enabled) return;
48 |
49 | gKablSet('sync_last_time', new Date().valueOf());
50 |
51 | var xhr=Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
52 | .createInstance(Ci.nsIXMLHttpRequest);
53 | xhr.open('GET', url || gKablPrefs.sync_url, true);
54 | xhr.onreadystatechange = function() {
55 | if (4!=xhr.readyState) return;
56 | if (200!=xhr.status) return;
57 | gKablRuleSyncApply(force, callback, xhr.responseText);
58 | };
59 | xhr.send(null);
60 | }
61 |
62 | function gKablRuleSyncApply(force, callback, newRules) {
63 | if (!force
64 | && gKablPrefs.rules!=gKablPrefs.sync_last_rules
65 | && gKablPrefs.rules!=newRules) {
66 | var line1='Karma Blocker Sync Confirmation';
67 | var line2='The local ruleset has changed since the last sync.\n'
68 | +'Destroy changes and apply update?';
69 | var win=gKablActiveWin();
70 | if (win && win == gKablBrowserWin()) {
71 | win.PopupNotifications.show(
72 | win.gBrowser.selectedBrowser,
73 | 'kabl-update-conflict',
74 | line1+'. '+line2,
75 | 'tb-kabl',
76 | {
77 | label: 'Apply update',
78 | accessKey: 'a',
79 | callback: function() {
80 | gKablRuleSyncApply(true, callback, newRules);
81 | }
82 | },
83 | null);
84 | } else {
85 | var doSync=Services.prompt.confirm(null, line1, line2);
86 | if (doSync) gKablRuleSyncApply(true, callback, newRules);
87 | }
88 | return;
89 | }
90 |
91 | gKablSet('sync_last_rules', newRules);
92 | gKablSet('rules', newRules);
93 | callback && callback();
94 | }
95 |
96 | var timerCallback={
97 | notify:function(timer) {
98 | var now=new Date().valueOf();
99 | if (now < gKablPrefs.sync_last_time+gKablPrefs.sync_update_interval) {
100 | return;
101 | }
102 | gKablRuleSync();
103 | }
104 | };
105 |
106 | var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
107 | // Once in a few seconds (after load), and ..
108 | timer.initWithCallback(timerCallback, 10000, Ci.nsITimer.TYPE_ONE_shot);
109 | // .. once every hour (check_interval).
110 | timer.initWithCallback(timerCallback, gKablPrefs.sync_check_interval,
111 | Ci.nsITimer.TYPE_REPEATING_SLACK);
112 |
--------------------------------------------------------------------------------
/content/kabl-overlay.js:
--------------------------------------------------------------------------------
1 | // ***** BEGIN LICENSE BLOCK *****
2 | // Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 | //
4 | // The contents of this file are subject to the Mozilla Public License Version
5 | // 1.1 (the 'License'); you may not use this file except in compliance with
6 | // the License. You may obtain a copy of the License at
7 | // http://www.mozilla.org/MPL/
8 | //
9 | // Software distributed under the License is distributed on an 'AS IS' basis,
10 | // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 | // for the specific language governing rights and limitations under the
12 | // License.
13 | //
14 | // The Initial Developer of the Original Code is Anthony Lieuallen.
15 | //
16 | // Portions created by the Initial Developer are Copyright (C) 2007
17 | // the Initial Developer. All Rights Reserved.
18 | //
19 | // Alternatively, the contents of this file may be used under the terms of
20 | // either the GNU General Public License Version 2 or later (the 'GPL'), or
21 | // the GNU Lesser General Public License Version 2.1 or later (the 'LGPL'),
22 | // in which case the provisions of the GPL or the LGPL are applicable instead
23 | // of those above. If you wish to allow use of your version of this file only
24 | // under the terms of either the GPL or the LGPL, and not to allow others to
25 | // use your version of this file under the terms of the MPL, indicate your
26 | // decision by deleting the provisions above and replace them with the notice
27 | // and other provisions required by the GPL or the LGPL. If you do not delete
28 | // the provisions above, a recipient may use your version of this file under
29 | // the terms of any one of the MPL, the GPL or the LGPL.
30 | //
31 | // ***** END LICENSE BLOCK *****
32 |
33 | Components.utils.import('chrome://kabl/content/kabl-pref.js');
34 |
35 | var gKabl={
36 | menuitemToggle: null,
37 | menuitemReload: null,
38 |
39 | isReloading: false,
40 | reloadTimer: null,
41 |
42 | finishReload:function() {
43 | if (!gKabl.isReloading) return;
44 | dump("Finishing disabled reload ...\n");
45 | gKabl.isReloading = false;
46 | if (gKabl.reloadTimer) {
47 | clearTimeout(gKabl.reloadTimer);
48 | gKabl.reloadTimer = null;
49 | }
50 | gKablSet('enabled', true);
51 | },
52 |
53 | openConfig:function() {
54 | var windowWatcher=Components
55 | .classes['@mozilla.org/embedcomp/window-watcher;1']
56 | .getService(Components.interfaces.nsIWindowWatcher);
57 | windowWatcher.openWindow(
58 | window, 'chrome://kabl/content/kabl-config.xul', null,
59 | 'chrome,dependent,centerscreen,resizable,dialog', null);
60 | },
61 |
62 | openMonitorWindow:function(parentWin) {
63 | if (gKabl.monitorWin && false===gKabl.monitorWin.closed) {
64 | return gKabl.monitorWin;
65 | }
66 |
67 | return gKabl.monitorWin=parentWin.open(
68 | 'chrome://kabl/content/kabl-monitor.xul', null,
69 | 'chrome,close=no,dependent,dialog,resizable'
70 | );
71 | },
72 |
73 | popupshowing:function() {
74 | gKabl.menuitemToggle.style.fontWeight
75 | = gKablPrefs.enabled ? 'normal' : 'bold';
76 | gKabl.menuitemReload.style.fontWeight
77 | = gKablPrefs.enabled ? 'bold' : 'normal';
78 | },
79 |
80 | toggle:function() {
81 | gKablSet('enabled', !gKablPrefs.enabled);
82 | },
83 |
84 | toolbarButtonDefault:function() {
85 | dump('>>> toolbarButtonDefault ...\n');
86 | if (gKablPrefs.enabled) {
87 | dump("Reloading, disabled ...\n");
88 | gKabl.isReloading = true;
89 | gKablSet('enabled', false);
90 | gKabl.reloadTimer = setTimeout(gKabl.finishReload, 30000);
91 | try {
92 | gBrowser.reloadTab(gBrowser.mCurrentTab);
93 | } catch (e) {
94 | dump('could not reload tab!\n'+e+'\n');
95 | }
96 | } else {
97 | gKablSet('enabled', true);
98 | }
99 | },
100 |
101 | setToolbarButtonState:function() {
102 | var tb=document.getElementById('tb-kabl');
103 | if (tb) {
104 | // Standard is disabled=true -- but that disables the button, so
105 | // clicking it fires no command and won't re-enable us. Use our
106 | // own yes/no styled to be similar.
107 | tb.setAttribute('kabl_disabled', gKablPrefs.enabled ? 'no' : 'yes');
108 | }
109 | },
110 |
111 | onContentLoad:function(event) {
112 | gKabl.finishReload();
113 | },
114 |
115 | onChromeLoad:function() {
116 | gKabl.setToolbarButtonState();
117 |
118 | gKabl.menuitemToggle
119 | = document.querySelector('#tb-kabl menuitem[label=Toggle]');
120 | gKabl.menuitemReload
121 | = document.querySelector('#tb-kabl menuitem[label=Reload]');
122 |
123 | window.removeEventListener('load', gKabl.onLoad, false);
124 | gBrowser.addEventListener('load', gKabl.onContentLoad, true);
125 |
126 | Components
127 | .classes['@mozilla.org/globalmessagemanager;1']
128 | .getService(Ci.nsIMessageListenerManager)
129 | .loadFrameScript('chrome://kabl/content/kabl-frame.js', true);
130 | }
131 | };
132 |
133 | window.addEventListener('load', gKabl.onChromeLoad, false);
134 |
--------------------------------------------------------------------------------
/content/kabl-pref.js:
--------------------------------------------------------------------------------
1 | // ***** BEGIN LICENSE BLOCK *****
2 | // Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 | //
4 | // The contents of this file are subject to the Mozilla Public License Version
5 | // 1.1 (the 'License'); you may not use this file except in compliance with
6 | // the License. You may obtain a copy of the License at
7 | // http://www.mozilla.org/MPL/
8 | //
9 | // Software distributed under the License is distributed on an 'AS IS' basis,
10 | // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 | // for the specific language governing rights and limitations under the
12 | // License.
13 | //
14 | // The Initial Developer of the Original Code is Anthony Lieuallen.
15 | //
16 | // Portions created by the Initial Developer are Copyright (C) 2007
17 | // the Initial Developer. All Rights Reserved.
18 | //
19 | // Alternatively, the contents of this file may be used under the terms of
20 | // either the GNU General Public License Version 2 or later (the 'GPL'), or
21 | // the GNU Lesser General Public License Version 2.1 or later (the 'LGPL'),
22 | // in which case the provisions of the GPL or the LGPL are applicable instead
23 | // of those above. If you wish to allow use of your version of this file only
24 | // under the terms of either the GPL or the LGPL, and not to allow others to
25 | // use your version of this file under the terms of the MPL, indicate your
26 | // decision by deleting the provisions above and replace them with the notice
27 | // and other provisions required by the GPL or the LGPL. If you do not delete
28 | // the provisions above, a recipient may use your version of this file under
29 | // the terms of any one of the MPL, the GPL or the LGPL.
30 | //
31 | // ***** END LICENSE BLOCK *****
32 |
33 | var EXPORTED_SYMBOLS=[
34 | 'gKablLoad', 'gKablPrefs', 'gKablSet', 'gKablSave'];
35 |
36 | Components.utils.import('chrome://kabl/content/kabl-parse.js');
37 |
38 | // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
39 |
40 | var prefBranch=Components.classes['@mozilla.org/preferences-service;1']
41 | .getService(Components.interfaces.nsIPrefService)
42 | .getBranch('extensions.kabl.');
43 |
44 | // globals that hold the settings
45 | var gKablPrefs={
46 | 'debug':null,
47 | 'enabled':null,
48 | 'rules':null,
49 | 'sync_enabled':null,
50 | 'sync_check_interval':null,
51 | 'sync_last_rules':null,
52 | 'sync_last_time':null,
53 | 'sync_update_interval':null,
54 | 'sync_url':null};
55 |
56 | function gKablLoad() {
57 | gKablPrefs.debug=prefBranch.getIntPref('debug');
58 | gKablPrefs.enabled=prefBranch.getBoolPref('enabled');
59 | gKablPrefs.rules=prefBranch.getCharPref('rules');
60 | gKablPrefs.sync_enabled=prefBranch.getBoolPref('sync_enabled');
61 | gKablPrefs.sync_check_interval=prefBranch.getIntPref('sync_check_interval');
62 | gKablPrefs.sync_last_rules=prefBranch.getCharPref('sync_last_rules');
63 | gKablPrefs.sync_last_time=parseFloat(prefBranch.getCharPref('sync_last_time'));
64 | gKablPrefs.sync_update_interval=prefBranch.getIntPref('sync_update_interval');
65 | gKablPrefs.sync_url=prefBranch.getCharPref('sync_url');
66 | }
67 |
68 | function gKablSave() {
69 | prefBranch.setIntPref('debug', gKablPrefs.debug);
70 | prefBranch.setBoolPref('enabled', gKablPrefs.enabled);
71 | prefBranch.setCharPref('rules', gKablPrefs.rules);
72 | prefBranch.setBoolPref('sync_enabled', gKablPrefs.sync_enabled);
73 | prefBranch.setIntPref('sync_check_interval', gKablPrefs.sync_check_interval);
74 | prefBranch.setCharPref('sync_last_rules', gKablPrefs.sync_last_rules);
75 | prefBranch.setCharPref('sync_last_time', String(gKablPrefs.sync_last_time));
76 | prefBranch.setIntPref('sync_update_interval', gKablPrefs.sync_update_interval);
77 | prefBranch.setCharPref('sync_url', gKablPrefs.sync_url);
78 | }
79 |
80 | function gKablSet(name, value) {
81 | gKablPrefs[name]=value;
82 | gKablSave();
83 | }
84 |
85 | // run the passed function on all navigator windows
86 | function withAllChrome(func) {
87 | var mediator=Components.classes['@mozilla.org/appshell/window-mediator;1']
88 | .getService(Components.interfaces.nsIWindowMediator);
89 | var winEnum=mediator.getEnumerator('navigator:browser');
90 | while (winEnum.hasMoreElements()){
91 | func(winEnum.getNext());
92 | }
93 | }
94 |
95 | var gKablPrefObserver={
96 | _branch:null,
97 |
98 | register:function() {
99 | prefBranch.QueryInterface(Components.interfaces.nsIPrefBranch2);
100 | prefBranch.addObserver('', this, false);
101 | },
102 |
103 | observe:function(aSubject, aTopic, aData) {
104 | if('nsPref:changed'!=aTopic) return;
105 | // aSubject is the nsIPrefBranch we're observing (after appropriate QI)
106 | // aData is the name of the pref that's been changed (relative to aSubject)
107 | gKablLoad();
108 | switch (aData) {
109 | case 'enabled':
110 | withAllChrome(function(win) { win.gKabl.setToolbarButtonState(); });
111 | break;
112 | case 'rules':
113 | gKablRulesObj.parse(prefBranch.getCharPref('rules'));
114 | break;
115 | }
116 | }
117 | };
118 |
119 | gKablPrefObserver.register();
120 | gKablLoad();
121 |
--------------------------------------------------------------------------------
/content/kabl-config.js:
--------------------------------------------------------------------------------
1 | // ***** BEGIN LICENSE BLOCK *****
2 | // Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 | //
4 | // The contents of this file are subject to the Mozilla Public License Version
5 | // 1.1 (the 'License'); you may not use this file except in compliance with
6 | // the License. You may obtain a copy of the License at
7 | // http://www.mozilla.org/MPL/
8 | //
9 | // Software distributed under the License is distributed on an 'AS IS' basis,
10 | // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 | // for the specific language governing rights and limitations under the
12 | // License.
13 | //
14 | // The Initial Developer of the Original Code is Anthony Lieuallen.
15 | //
16 | // Portions created by the Initial Developer are Copyright (C) 2007
17 | // the Initial Developer. All Rights Reserved.
18 | //
19 | //
20 | // Alternatively, the contents of this file may be used under the terms of
21 | // either the GNU General Public License Version 2 or later (the 'GPL'), or
22 | // the GNU Lesser General Public License Version 2.1 or later (the 'LGPL'),
23 | // in which case the provisions of the GPL or the LGPL are applicable instead
24 | // of those above. If you wish to allow use of your version of this file only
25 | // under the terms of either the GPL or the LGPL, and not to allow others to
26 | // use your version of this file under the terms of the MPL, indicate your
27 | // decision by deleting the provisions above and replace them with the notice
28 | // and other provisions required by the GPL or the LGPL. If you do not delete
29 | // the provisions above, a recipient may use your version of this file under
30 | // the terms of any one of the MPL, the GPL or the LGPL.
31 | //
32 | // ***** END LICENSE BLOCK *****
33 |
34 | Components.utils.import('chrome://kabl/content/kabl-lib.js');
35 | Components.utils.import('chrome://kabl/content/kabl-parse.js');
36 | Components.utils.import('chrome://kabl/content/kabl-pref.js');
37 | Components.utils.import('chrome://kabl/content/kabl-sync.js');
38 |
39 | // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
40 |
41 | function gKablConfigOpen() {
42 | document.getElementById('enabled')
43 | .setAttribute('checked', gKablPrefs.enabled);
44 | document.getElementById('sync_enabled')
45 | .setAttribute('checked', gKablPrefs.sync_enabled);
46 | document.getElementById('sync_url')
47 | .setAttribute('value', gKablPrefs.sync_url);
48 |
49 | var rules=document.getElementById('rules');
50 | rules.value=gKablPrefs.rules;
51 | rules.selectionStart=0;
52 | rules.selectionEnd=0;
53 | rules.focus();
54 |
55 | gKablSetSyncTime();
56 |
57 | document.getElementById('sync_enabled').addEventListener(
58 | 'click', gKablSyncEnabledChange, true);
59 | document.getElementById('sync_enabled').addEventListener(
60 | 'keypress', gKablSyncEnabledChange, true);
61 | gKablSyncEnabledChange();
62 | }
63 |
64 | function gKablConfigAccept() {
65 | var parseOk=gKablCheckConfig();
66 | if (!parseOk) {
67 | if (!confirm('Parse error.\nReally save rules?')) return;
68 | }
69 |
70 | // extract pref vals
71 | gKablPrefs.enabled=document.getElementById('enabled').checked;
72 | gKablPrefs.rules=document.getElementById('rules').value;
73 | gKablPrefs.sync_enabled=document.getElementById('sync_enabled').checked;
74 | gKablPrefs.sync_url=document.getElementById('sync_url').value;
75 |
76 | gKablSave();
77 |
78 | return true;
79 | }
80 |
81 | function gKablCheckConfig() {
82 | var textbox=document.getElementById('rules');
83 |
84 | try {
85 | gKablRulesObj.parse(textbox.value);
86 | } catch (e) {
87 | if (e instanceof KablParseException) {
88 | gKablSetStatusLabel('err', e.message);
89 | textbox.selectionStart=parseInt(e.start);
90 | textbox.selectionEnd=parseInt(e.end);
91 | textbox.focus();
92 | return false;
93 | }
94 | dump("ERROR in gKablCheckConfig():\n");
95 | for (var i in e) dump(i+' '+e[i]+'\n');
96 | return false;
97 | }
98 |
99 | gKablSetStatusLabel('ok');
100 |
101 | textbox.focus();
102 | return true;
103 | }
104 |
105 | function gKablSetStatusLabel(type, msg) {
106 | for (label in {'unk':1, 'ok':1, 'err':1}) {
107 | document.getElementById('status_'+label).setAttribute(
108 | 'hidden', (label!=type)
109 | );
110 | }
111 |
112 | var errmsg=document.getElementById('status_errmsg');
113 | if ('err'==type) {
114 | errmsg.setAttribute('value', msg);
115 | errmsg.setAttribute('hidden', false);
116 | } else {
117 | errmsg.setAttribute('hidden', true);
118 | }
119 | }
120 |
121 | // This function originates from AdBlock Plus, reused under MPL.
122 | function gKablLoadInBrowser(url) {
123 | var currentWindow=gKablBrowserWin();
124 | if (currentWindow) {
125 | try {
126 | currentWindow.delayedOpenTab(url);
127 | }
128 | catch(e) {
129 | currentWindow.loadURI(url);
130 | }
131 | } else {
132 | var protocolService=Components
133 | .classes['@mozilla.org/uriloader/external-protocol-service;1']
134 | .getService(Components.interfaces.nsIExternalProtocolService);
135 | protocolService.loadUrl(url);
136 | }
137 | }
138 |
139 | function gKablResetConfig() {
140 | if (!confirm('Really throw away current rules and reset to defaults?')) {
141 | return;
142 | }
143 |
144 | var defaultPref=Components.classes['@mozilla.org/preferences-service;1']
145 | .getService(Components.interfaces.nsIPrefService)
146 | .getDefaultBranch('extensions.kabl.');
147 |
148 | document.getElementById('enabled').checked=defaultPref.getBoolPref('enabled');;
149 | document.getElementById('rules').value=defaultPref.getCharPref('rules');
150 | document.getElementById('sync_enabled').value=defaultPref.getBoolPref('sync_enabled');
151 | document.getElementById('sync_url').value=defaultPref.getCharPref('sync_url');
152 | }
153 |
154 | function gKablSyncEnabledChange(aEvent) {
155 | var syncEnabled=document.getElementById('sync_enabled').checked;
156 | document.getElementById('sync_now').disabled=!syncEnabled;
157 | document.getElementById('sync_url').disabled=!syncEnabled;
158 | }
159 |
160 | function gKablSyncNow() {
161 | var btn = document.getElementById('sync_now');
162 | btn.className += ' loading';
163 | btn.disabled = true;
164 |
165 | gKablRuleSync(gKablSyncNowCallback,
166 | document.getElementById('sync_enabled').checked,
167 | document.getElementById('sync_url').value);
168 | }
169 |
170 | function gKablSyncNowCallback() {
171 | var btn = document.getElementById('sync_now');
172 | btn.className = btn.className.replace(' loading', '');
173 | btn.disabled = false;
174 |
175 | var rules=document.getElementById('rules');
176 | rules.value=gKablPrefs.rules;
177 | gKablSetSyncTime();
178 | }
179 |
180 | function gKablSetSyncTime() {
181 | var lastSync='Never';
182 | if (gKablPrefs.sync_last_time) {
183 | lastSync=new Date(gKablPrefs.sync_last_time).toLocaleString();
184 | }
185 | document.getElementById('sync_time').value='Last sync: '+lastSync;
186 | }
187 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Documentation
2 |
3 | Karma Blocker is an ad/nuisance blocker and privacy enhancer for technical people.
4 | It uses a simplistic definition language to assign "karma" points to every resource that Firefox loads when rendering pages. If any resource gathers enough points, it is blocked. It sports the following features:
5 |
6 | * Request-time blocking of any resource.
7 | (Blocked objects never load, never use bandwidth, never set cookies.)
8 | * Karma (or score) based weighting of objects, similar to popular spam filtering solutions like [SpamAssasin](http://spamassassin.apache.org/).
9 | * A flexible expression language for powerful filtering, on a richer set of data than simply "the URL".
10 | * Global function injection; if a script is blocked, yet functions in it are still called, injecting a blank function of the same name will eliminate any errors.
11 |
12 | ## Operation
13 |
14 | Every time Firefox begins to load any resource (page, image, style sheet, javascript file, etc.) Karma Blocker will first check it against the rules it is configured to use.
15 | If the rules match that request, it will be denied and never load.
16 | There are certain exceptions:
17 |
18 | * When Karma Blocker is disabled (and the status bar icon is greyed out), all requests will be allowed.
19 | * When the resource is not from one of the schemes `http`, `https`, `ftp`, `chrome`, all requests will be allowed.
20 | * Three different checks are made to ensure that resources that form part of the browser itself (i.e. the back/forward buttons, icons, etc.) are never blocked.
21 |
22 | Click the icon in the status bar to globally enable/disable Karma Blocker.
23 |
24 | ## Configuration
25 |
26 | See [Configuration wiki page](https://github.com/arantius/karma-blocker/wiki/Configuration).
27 |
28 | # Changelog
29 |
30 | * Version 0.6.2 (Pending)
31 | * Inject functions which do not break the page when called.
32 | * Version 0.6.1 (September 8, 2015)
33 | * Minor bug fix to new monitor window.
34 | * Version 0.6 (September 3, 2015)
35 | * Bug fix: Allow literal 'false' values.
36 | * Toolbar button's default click action is to disable only while reloading the page.
37 | * Add request type 'xmlhttprequest'.
38 | * Allow semicolon for comments.
39 | * Richer options in the monitor window.
40 | * Version 0.5 (March 27, 2015)
41 | * Compatibility with multi-process Firefox.
42 | * Version 0.4.8 (October 17, 2013)
43 | * Performance Enhancements
44 | * Version 0.4.7 (September 1, 2013)
45 | * Small bug fixes for compatibility with modern Firefox versions.
46 | * Version 0.4.6 (August 16, 2011)
47 | * Do not warn when local and to-sync rules match. (#529)
48 | * Fix warning about internal Firefox API change. (#530)
49 | * Support up to Firefox 7. (#532)
50 | * Version 0.4.5 (June 27, 2011)
51 | * Fix changing the rules w/out requiring a browser restart. (#499)
52 | * Tweaks to default rule set. (#513, #518)
53 | * Display a spinner in the config dialog's sync button while loading the remote resource.
54 | * Compatibility with Firefox 5.0.
55 | * Version 0.4.4 (March 15, 2011)
56 | * Detect invalid regular expressions. (#487)
57 | * Fix early DOM access bug (forced visibility of tab scroll buttons). (#488)
58 | * New icons.
59 | * Version 0.4.3 (March 7, 2011)
60 | * Firefox 4 compatibility. (#482)
61 | * Properly handle resources loaded from pretty-printed feeds. (#372)
62 | * Check for undefined property accesses. (#412)
63 | * Fix syntax in default rules. (#415)
64 | * Indicate in the monitor dialog when the cutoff score halts processing. (#416)
65 | * When a rule was not checked, display 'Skipped' for match rather than 'No'. (#417)
66 | * Do not reset the 'Scores' box of the monitor window when resources are added. (#419)
67 | * Add less than and greater than operators. (#421)
68 | * Version 0.4.2 (Jan 11, 2010)
69 | * Fix typo in default preferences, causing the rules to be just "undefined". (#392)
70 | * New button in configuration dialog, to reset to default rules. (#389)
71 | * Version 0.4.1 (Dec 31, 2009)
72 | * Firefox 3.6 compatibility flag.
73 | * Avoid spurious "function anonymous() { }" text in page. (#306)
74 | * Add an optional toolbar button. (#285)
75 | * Monitor dialog displays types correctly. (#370)
76 | * Add `origin.size` property, for compact size rules. (#371)
77 | * New default rules to demonstrate new features, cause less false positives. (#265)
78 | * Version 0.4 (Jun 26, 2009)
79 | * Mark Firefox compatibility with 3.0 through 3.5.
80 | * Add option for the monitor window to gather only blocked resources. (#221)
81 | * Add configuration setting to enable/disable the element collapsing feature (now ''off'' by default), and make it less aggressive when it is enabled. (#209)
82 | * Allow functions with properties to be injected, i.e. `inject='_gat._getTracker'` will eat undefined function errors from blocked Google Analytics scripts. (#253)
83 | * Disable wrapping when editing rules, so long lines display on one line (with a horizontal scroll bar).
84 | * Never block core parts of the browser itself. (#222)
85 | * In the monitor window, you can copy data, remove items, open URLs, and expand/collapse rows via a context menu. (#266)
86 | * New default rules which are highly functional. (#265)
87 | * Version 0.3.2 (Sep 27, 2008)
88 | * Bug fix, certain rule sets can cause Firefox to freeze. (#182)
89 | * Version 0.3.1 (Jul 15, 2008)
90 | * Enhanced element collapsing. (When an ad is blocked, if it is inside an otherwise empty, fixed size container, that container will be removed from the page.)
91 | * Version 0.3 (Feb 9, 2008)
92 | * Bug fix: allow rules to block chrome (#93).
93 | * Compatibility with Firefox 3.0.
94 | * Feature: Monitor window, which displays the score, and blocked status of all resources, plus the match status and score contribution of each group, for each resource.
95 | * Add the "name" field for "Group" sections, to allow meaningful group display in the monitor window.
96 | * Version 0.2.1 (Jun 28, 2007)
97 | * Add debugging output detailing where functions are being injected to.
98 | * Fix home page address.
99 | * Remove stability/security disclaimer, a few months of testing have gone well.
100 | * Version 0.2 (Feb 17, 2007)
101 | * Initial release of Karma Blocker with full feature set:
102 | * Karma based scoring system.
103 | * Flexible rules language for matching.
104 | * Function injection.
105 | * Version 0.1 (Jan 3, 2007)
106 | * Initial release of grandfather project, Third Party Script Stopper.
107 |
108 | # Credits
109 |
110 | * [Using the RegExp Object for Lexical Analysis in Javascript](http://cc.usu.edu/~amcinnes/js-regexp-lexing.html) - Lexical analysis algorithm
111 | * [FireBug](http://www.getfirebug.com/) - Content page function injection
112 | * [Fast Icon](http://www.fasticon.com/) iSimple System set - Main Icon
113 | * [famfamfam.com](http://www.famfamfam.com/lab/icons/silk/) Silk icons set - Blocked Icon
114 | * Previously: [Everaldo Coelho](http://everaldo.com/) Crystal Clear Actions icons set - Main Icon
115 | * [AdBlock](http://adblock.mozdev.org/) and [AdBlock Plus](http://adblockplus.org/) - Ideas, some code sections
116 |
117 | # License
118 |
119 | Karma Blocker is released under the GPLv2 license.
120 |
--------------------------------------------------------------------------------
/content/kabl-monitor.js:
--------------------------------------------------------------------------------
1 | // ***** BEGIN LICENSE BLOCK *****
2 | // Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 | //
4 | // The contents of this file are subject to the Mozilla Public License Version
5 | // 1.1 (the 'License'); you may not use this file except in compliance with
6 | // the License. You may obtain a copy of the License at
7 | // http://www.mozilla.org/MPL/
8 | //
9 | // Software distributed under the License is distributed on an 'AS IS' basis,
10 | // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 | // for the specific language governing rights and limitations under the
12 | // License.
13 | //
14 | // The Initial Developer of the Original Code is Anthony Lieuallen.
15 | //
16 | // Portions created by the Initial Developer are Copyright (C) 2007
17 | // the Initial Developer. All Rights Reserved.
18 | //
19 | // Alternatively, the contents of this file may be used under the terms of
20 | // either the GNU General Public License Version 2 or later (the 'GPL'), or
21 | // the GNU Lesser General Public License Version 2.1 or later (the 'LGPL'),
22 | // in which case the provisions of the GPL or the LGPL are applicable instead
23 | // of those above. If you wish to allow use of your version of this file only
24 | // under the terms of either the GPL or the LGPL, and not to allow others to
25 | // use your version of this file under the terms of the MPL, indicate your
26 | // decision by deleting the provisions above and replace them with the notice
27 | // and other provisions required by the GPL or the LGPL. If you do not delete
28 | // the provisions above, a recipient may use your version of this file under
29 | // the terms of any one of the MPL, the GPL or the LGPL.
30 | //
31 | // ***** END LICENSE BLOCK *****
32 |
33 | Components.utils.import('chrome://kabl/content/kabl-policy.js');
34 |
35 | //\\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
36 |
37 | var Cc = Components.classes;
38 | var Ci = Components.interfaces;
39 | var Cu = Components.utils;
40 |
41 | var LENGTH_LIMIT = 4000;
42 |
43 | var gPreviousSelectedItem=null;
44 | var $=function(x){ return document.getElementById(x); }
45 |
46 | var gKablMonitor={
47 | typeMap:{
48 | '1':'other',
49 | '2':'script',
50 | '3':'image',
51 | '4':'stylesheet',
52 | '5':'object',
53 | '6':'document',
54 | '7':'subdocument',
55 | '8':'refresh',
56 | '9':'xbl',
57 | '10':'ping',
58 | '11':'xmlhttprequest',
59 | '12':'object_subrequest'
60 | },
61 |
62 | treeRes:null,
63 | treeScore:null,
64 | changing:false,
65 |
66 | onLoad:function() {
67 | window.removeEventListener('DOMContentLoaded', gKablMonitor.onLoad, false);
68 | gKablMonitor.treeRes=$('treeRes');
69 | gKablMonitor.treeScore=$('treeScore');
70 |
71 | Cc['@mozilla.org/parentprocessmessagemanager;1']
72 | .getService(Ci.nsIMessageBroadcaster)
73 | .broadcastAsyncMessage('kabl:monitor-opened');
74 | Cc['@mozilla.org/parentprocessmessagemanager;1']
75 | .getService(Ci.nsIMessageListenerManager)
76 | .addMessageListener('kabl:monitor', gKablMonitor.add);
77 |
78 | $('filterForm').addEventListener('click', function(event) {
79 | // After timeout so that .checked/.selected matches new state.
80 | setTimeout(gKablMonitor.changeShowing, 0, event);
81 | }, true);
82 | },
83 |
84 | onUnload:function() {
85 | Cc['@mozilla.org/parentprocessmessagemanager;1']
86 | .getService(Ci.nsIMessageBroadcaster)
87 | .broadcastAsyncMessage('kabl:monitor-closed');
88 | Cc['@mozilla.org/parentprocessmessagemanager;1']
89 | .getService(Ci.nsIMessageListenerManager)
90 | .removeMessageListener('kabl:monitor', gKablMonitor.add);
91 | },
92 |
93 | changeShowing:function(event) {
94 | var checkedShowAll = $('showTypeAll').checked;
95 | var checkedAllOther =
96 | $('showTypeXhr').checked &&
97 | $('showTypeCss').checked &&
98 | $('showTypeImg').checked &&
99 | $('showTypeScr').checked &&
100 | $('showTypeOth').checked;
101 |
102 | if ('showTypeAll' == event.target.id) {
103 | $('showTypeXhr').checked =
104 | $('showTypeCss').checked =
105 | $('showTypeImg').checked =
106 | $('showTypeScr').checked =
107 | $('showTypeOth').checked =
108 | $('showTypeAll').checked;
109 | } else if (checkedAllOther) {
110 | $('showTypeAll').checked = true;
111 | } else {
112 | $('showTypeAll').checked = false;
113 | }
114 |
115 | gKablMonitor.changing = true;
116 | for (var i = 0, row = null; row = gKablMonitor.treeRes.childNodes[i]; i++) {
117 | row.hidden = !gKablMonitor.showRow(row);
118 | }
119 | gKablMonitor.changing = false;
120 | },
121 |
122 | clear:function() {
123 | gKablMonitor.changing=true;
124 | while (gKablMonitor.treeScore.firstChild) {
125 | gKablMonitor.treeScore.removeChild(gKablMonitor.treeScore.firstChild);
126 | }
127 | while (gKablMonitor.treeRes.firstChild) {
128 | gKablMonitor.treeRes.removeChild(gKablMonitor.treeRes.firstChild);
129 | }
130 | gKablMonitor.changing=false;
131 | },
132 |
133 | resSelect:function(event) {
134 | if (gKablMonitor.changing) return;
135 |
136 | while (gKablMonitor.treeScore.firstChild) {
137 | gKablMonitor.treeScore.removeChild(gKablMonitor.treeScore.firstChild);
138 | }
139 |
140 | var tree = event.target;
141 | var item = tree.contentView.getItemAtIndex(tree.currentIndex);
142 | if (!item) return;
143 | if (item && item==gPreviousSelectedItem) return;
144 | gPreviousSelectedItem=item;
145 |
146 | for (i in item.groups) {
147 | gKablMonitor.treeScore.appendChild(
148 | gKablMonitor.groupItem(item.groups[i]));
149 | }
150 | },
151 |
152 | showRow:function(row) {
153 | if ($('showBlockedNo').selected && row.blocked) return false;
154 | if ($('showBlockedYes').selected && !row.blocked) return false;
155 |
156 | if ($('showTypeAll').checked) return true;
157 |
158 | if (row.fields.$type == 2) return $('showTypeScr').checked;
159 | else if (row.fields.$type == 3) return $('showTypeImg').checked;
160 | else if (row.fields.$type == 4) return $('showTypeCss').checked;
161 | else if (row.fields.$type == 11) return $('showTypeXhr').checked;
162 | else return $('showTypeOth').checked;
163 | },
164 |
165 | add:function(message) {
166 | fields = message.data.fields;
167 | groups = message.data.groups;
168 | score = message.data.score;
169 | blocked = message.data.blocked;
170 |
171 | var item=gKablMonitor.fieldItem('$url', fields.$url, score, blocked);
172 | item.blocked=blocked;
173 | item.fields=fields;
174 | item.groups=groups;
175 |
176 | item.hidden = !gKablMonitor.showRow(item);
177 |
178 | var children=document.createElement('treechildren');
179 | item.appendChild(children);
180 |
181 | var subItem;
182 | for (i in fields) {
183 | if ('$url'==i) continue;
184 | if ('node'==i) continue;
185 | if ('undefined'==typeof fields[i]) continue;
186 |
187 | subItem=gKablMonitor.fieldItem(i, fields[i]);
188 | children.appendChild(subItem);
189 | }
190 |
191 | gKablMonitor.treeRes.insertBefore(item, gKablMonitor.treeRes.firstChild);
192 | while (gKablMonitor.treeRes.childNodes.length > LENGTH_LIMIT) {
193 | gKablMonitor.treeRes.removeChild(gKablMonitor.treeRes.lastChild);
194 | }
195 | },
196 |
197 | fieldItem:function(name, value, score, blocked) {
198 | if ('$type'==name) {
199 | value=gKablMonitor.typeMap[value];
200 | }
201 |
202 | var cell, row, item=document.createElement('treeitem');
203 |
204 | row=document.createElement('treerow');
205 | item.appendChild(row);
206 |
207 | cell=document.createElement('treecell');
208 | cell.setAttribute('label', name+': '+value);
209 | row.appendChild(cell);
210 |
211 | if ('undefined'!=typeof score) {
212 | item.setAttribute('container', 'true');
213 |
214 | cell=document.createElement('treecell');
215 | cell.setAttribute('label', score);
216 | row.appendChild(cell);
217 |
218 | cell=document.createElement('treecell');
219 | if (blocked) cell.setAttribute('properties', 'blocked');
220 | row.appendChild(cell);
221 | }
222 |
223 | return item;
224 | },
225 |
226 | groupItem:function(group) {
227 | var cell, row, item=document.createElement('treeitem');
228 | if (group.rules) item.setAttribute('container', 'true');
229 |
230 | row=document.createElement('treerow');
231 | item.appendChild(row);
232 |
233 | cell=document.createElement('treecell');
234 | cell.setAttribute('label', group.name);
235 | row.appendChild(cell);
236 |
237 | cell=document.createElement('treecell');
238 | cell.setAttribute('label', group.score);
239 | row.appendChild(cell);
240 |
241 | if (!group.rules) return item;
242 |
243 | var children=document.createElement('treechildren');
244 | item.appendChild(children);
245 |
246 | var rule;
247 | for (i in group.rules) {
248 | rule=group.rules[i];
249 |
250 | var subItem=document.createElement('treeitem');
251 |
252 | row=document.createElement('treerow');
253 | subItem.appendChild(row);
254 | children.appendChild(subItem);
255 |
256 | cell=document.createElement('treecell');
257 | var val=rule.val;
258 | if ('$type'==rule.field) val=this.typeMap[val];
259 | cell.setAttribute('label', rule.field+' '+rule.op+' '+val);
260 | row.appendChild(cell);
261 |
262 | cell=document.createElement('treecell');
263 | var match='';
264 | if (null===rule.match) {
265 | match='Skipped';
266 | } else {
267 | match=rule.match?'Yes':'No';
268 | }
269 | cell.setAttribute('label', match);
270 | row.appendChild(cell);
271 | }
272 |
273 | return item;
274 | },
275 |
276 | labelForResourceItem:function(item) {
277 | // row cell
278 | return item.firstChild.firstChild.getAttribute('label');
279 | },
280 |
281 | withSelectedResources:function(callbackRow, callbackDetail) {
282 | var treeView=gKablMonitor.treeRes.parentNode.view;
283 | var start=new Object(), end=new Object();
284 | for (var i=0; i)';
68 | gKablTokens['inieq']='=';
69 |
70 | // etc
71 | gKablTokens['comment']='^[;#].*';
72 | gKablTokens['whitespace']='[ \t\\n\\r]';
73 |
74 | var gKablIdxTokMap=[];
75 | for (key in gKablTokens) {
76 | gKablIdxTokMap[gKablIdxTokMap.length]=key;
77 | }
78 |
79 | // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
80 |
81 | function KablToken(type, val, cstart, cend) {
82 | this.type=type;
83 | this.val=val;
84 | this.cstart=cstart;
85 | this.cend=cend;
86 | }
87 | KablToken.prototype.toString = function() {
88 | return "{ " + this.type + ", \"" + this.val + "\" }";
89 | };
90 |
91 | function KablParseException(start, end, errMsg, token) {
92 | if (token) {
93 | errMsg=errMsg.replace('%%', token.val);
94 | }
95 |
96 | this.start=start;
97 | this.end=end;
98 | this.message=errMsg;
99 |
100 | this.toString=function() {
101 | return '[KablParseException '+start+';'+end+' '+errMsg+']';
102 | };
103 | }
104 |
105 | var untitledGroupNum=0;
106 | function defaultGroup() {
107 | this.score=1;
108 | this.match='any';
109 | this.rules=[];
110 | this.name='Untitled Group '+(++untitledGroupNum);
111 | };
112 |
113 | // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
114 |
115 | var gKablRulesObj={
116 | ///////////////////////////////// DATA /////////////////////////////////////
117 |
118 | // string rules turn into tokens, stored here
119 | rulesTok:[],
120 |
121 | // the actual rules data
122 | threshold:null,
123 | cutoff:null,
124 | collapse:null,
125 | groups:null,
126 | injectFunctions:null,
127 | injectFunctionsStr:'[]',
128 |
129 | /////////////////////////////// METHODS ////////////////////////////////////
130 |
131 | expect:function(expectTok, errMsg) {
132 | var tok=this.rulesTok.shift();
133 |
134 | if (!tok) {
135 | throw new KablParseException(0, 0, 'Unexpected end of file');
136 | } else if (expectTok!=tok.type) {
137 | throw new KablParseException(tok.cstart, tok.cend, errMsg, tok);
138 | }
139 |
140 | return tok;
141 | },
142 |
143 | lex:function(rules) {
144 | // special case
145 | if (rules.match(/^\s*$/)) return true;
146 |
147 | // collapse defined tokens into a giant regex
148 | var tokRegex='', i=0, parens='';
149 | for (key in gKablTokens) {
150 | tokRegex+=gKablTokens[key]+parens+'|';
151 | parens+='()';
152 | i++;
153 | }
154 | tokRegex=tokRegex.substring(0, tokRegex.length-1);
155 | tokRegex=new RegExp(tokRegex, 'gim');
156 |
157 | // init empty, in case this isn't the first run
158 | this.rulesTok=[];
159 |
160 | // use the giant regex to tokenize the string
161 | var prev_lastIndex=0;
162 | while (true) {
163 | var match=tokRegex.exec(rules);
164 |
165 | if (null==match) {
166 | throw new KablParseException(
167 | prev_lastIndex, tokRegex.lastIndex, 'Syntax error');
168 | } else if (match.index!=prev_lastIndex) {
169 | // start of this isn't end of last
170 | throw new KablParseException(
171 | prev_lastIndex, match.index, 'Syntax error: illegal character(s)');
172 | } else {
173 | var tokIdx=0;
174 | for (var i=0; i=rules.length) {
193 | // lexed the whole string, no errors thrown, we're done!
194 | break;
195 | } else {
196 | prev_lastIndex=tokRegex.lastIndex;
197 | }
198 | }
199 | },
200 |
201 | parse:function(rules) {
202 | // this giant try lets us more cleanly terminate parsing at any point
203 | // by throwing a custom exception, even from subroutines
204 | try {
205 | // init default values
206 | this.threshold=10;
207 | this.cutoff=Number.MAX_VALUE;
208 | this.collapse=false;
209 | this.groups=[];
210 | this.injectFunctions=[];
211 |
212 | this.lex(rules);
213 |
214 | untitledGroupNum=0;
215 |
216 | // State:
217 | // 00 - started
218 | // 10 - in settings section
219 | // 20 - in group section
220 | // 30 - in inject section
221 | var tok=null, tok2=null, state=0, group=null;
222 |
223 | // parse the rules, by examining the tokens in order
224 | while (this.rulesTok.length>0) {
225 | tok=this.rulesTok.shift();
226 |
227 | switch (tok.type) {
228 | ////////////////////////////////////////////////////////////////
229 | case 'settings':
230 | state=10;
231 | break;
232 | case 'settings_cmd':
233 | if (10!=state) {
234 | throw new KablParseException(
235 | tok.cstart, tok.cend,
236 | 'Unexpected '+tok.type+' outside of [Settings] section');
237 | }
238 |
239 | switch (tok.val) {
240 | case 'threshold':
241 | case 'cutoff':
242 | this.expect('inieq', 'Unexpected "%%" expected: "="');
243 | tok2=this.expect('number', 'Unexpected "%%" expected: number');
244 | this[tok.val]=parseFloat(tok2.val);
245 | break;
246 | case 'collapse':
247 | this.expect('inieq', 'Unexpected "%%" expected: "="');
248 | tok2=this.expect('bool', 'Unexpected "%%" expected: bool');
249 | this.collapse='true'==tok2.val;
250 | break;
251 | }
252 | break;
253 | ////////////////////////////////////////////////////////////////
254 | case 'inject':
255 | state=30;
256 | break;
257 | case 'inject_cmd':
258 | if (30!=state) {
259 | throw new KablParseException(
260 | tok.cstart, tok.cend,
261 | 'Unexpected '+tok.type+' outside of [Inject] section');
262 | }
263 |
264 | switch (tok.val) {
265 | case 'function':
266 | this.expect('inieq', 'Unexpected "%%" expected: "="');
267 | tok2=this.expect('string', 'Unexpected "%%" expected: string');
268 | this.injectFunctions.push(
269 | // strip off the quote marks
270 | tok2.val.substr(0, tok2.val.length-1).substr(1));
271 | this.injectFunctionsStr=JSON.stringify(this.injectFunctions);
272 | break;
273 | }
274 | break;
275 | ////////////////////////////////////////////////////////////////
276 | case 'group':
277 | state=20;
278 | if (group) this.groups.push(group);
279 | group=new defaultGroup;
280 | break;
281 | case 'group_cmd':
282 | if (20!=state) {
283 | throw new KablParseException(
284 | tok.cstart, tok.cend,
285 | 'Unexpected "%%" outside of [Group] section', tok);
286 | }
287 |
288 | switch (tok.val) {
289 | case 'match':
290 | this.expect('inieq', 'Unexpected "%%" expected: "="');
291 | tok2=this.expect('group_match_val', 'Unexpected "%%" expected: "any", "all"');
292 | group.match=tok2.val;
293 | break;
294 | case 'score':
295 | this.expect('inieq', 'Unexpected "%%" expected: "="');
296 | tok2=this.expect('number', 'Unexpected "%%" expected: number');
297 | group.score=parseFloat(tok2.val);
298 | break;
299 | case 'rule':
300 | this.expect('inieq', 'Unexpected "%%" expected: "="');
301 | group.rules.push(this.parseRule());
302 | break;
303 | case 'name':
304 | this.expect('inieq', 'Unexpected "%%" expected: "="');
305 | tok2=this.expect('string', 'Unexpected "%%" expected: string');
306 | group.name=tok2.val.substring(1, tok2.val.length-1);
307 | untitledGroupNum--;
308 | break;
309 | }
310 | break;
311 | ////////////////////////////////////////////////////////////////
312 | default:
313 | throw new KablParseException(
314 | tok.cstart, tok.cend, 'Unexpected "%%"', tok);
315 | }
316 | }
317 | } catch (e) {
318 | // Used to do special handling here. Now just re-raise, so as to not
319 | // cause a whitespace diff for the whole body of the try.
320 | throw e;
321 | }
322 |
323 | // if the last parsed section was a group with rules, add it
324 | if (group && group.rules.length) this.groups.push(group);
325 | },
326 |
327 | parseRule:function() {
328 | var fieldTok=this.expect('field', 'Unexpected "%%" expected: field');
329 | var opTok=this.expect('field_op', 'Unexpected "%%" expected: field operator');
330 |
331 | var valTok=null, val=null;
332 |
333 | switch (true) {
334 | case '$thirdParty'==fieldTok.val:
335 | valTok=this.expect('bool', 'Unexpected "%%" expected: true, false');
336 | val='true'===valTok.val?true:false;
337 | break;
338 | case '$type'==fieldTok.val:
339 | valTok=this.expect('field_type_val', 'Unexpected "%%" expected: type');
340 | // ensure type
341 | val=Components.interfaces.nsIContentPolicy[
342 | 'TYPE_'+valTok.val.toUpperCase()
343 | ];
344 | break;
345 | case '$origin'==fieldTok.val.substring(0, 7):
346 | case '$url'==fieldTok.val.substring(0, 4):
347 | if ('<'==opTok.val || '>'==opTok.val) {
348 | valTok=this.expect('number', 'Unexpected "%%" expected: number');
349 | val=parseFloat(valTok.val); // ensure type
350 | } else {
351 | valTok=this.expect('string', 'Unexpected "%%" expected: string');
352 | val=valTok.val.toLowerCase(); // ensure type, case insensitivity
353 | val=val.substr(0, val.length-1).substr(1); // strip off the quote marks
354 | }
355 | break;
356 | default:
357 | throw new KablParseException(
358 | fieldTok.cstart, fieldTok.cend,
359 | 'Unexpected "%%", expected: field', field
360 | );
361 | }
362 |
363 | var regexVal = null;
364 | if ('=~' == opTok.val || '!~' == opTok.val) {
365 | try {
366 | regexVal=new RegExp(val);
367 | } catch (e) {
368 | throw new KablParseException(
369 | valTok.cstart, valTok.cend,
370 | 'Invalid regular expression: %%', {val: e}
371 | );
372 | }
373 | }
374 |
375 | if (typeof val != 'null') {
376 | return {
377 | field:fieldTok.val,
378 | op:opTok.val,
379 | val:val,
380 | regexVal:regexVal,
381 | match:null
382 | };
383 | } else {
384 | return null;
385 | }
386 | }
387 | };
388 |
--------------------------------------------------------------------------------
/content/kabl-policy.js:
--------------------------------------------------------------------------------
1 | // ***** BEGIN LICENSE BLOCK *****
2 | // Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 | //
4 | // The contents of this file are subject to the Mozilla Public License Version
5 | // 1.1 (the 'License'); you may not use this file except in compliance with
6 | // the License. You may obtain a copy of the License at
7 | // http://www.mozilla.org/MPL/
8 | //
9 | // Software distributed under the License is distributed on an 'AS IS' basis,
10 | // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 | // for the specific language governing rights and limitations under the
12 | // License.
13 | //
14 | // The Initial Developer of the Original Code is Anthony Lieuallen.
15 | //
16 | // Portions created by the Initial Developer are Copyright (C) 2007
17 | // the Initial Developer. All Rights Reserved.
18 | //
19 | // Alternatively, the contents of this file may be used under the terms of
20 | // either the GNU General Public License Version 2 or later (the 'GPL'), or
21 | // the GNU Lesser General Public License Version 2.1 or later (the 'LGPL'),
22 | // in which case the provisions of the GPL or the LGPL are applicable instead
23 | // of those above. If you wish to allow use of your version of this file only
24 | // under the terms of either the GPL or the LGPL, and not to allow others to
25 | // use your version of this file under the terms of the MPL, indicate your
26 | // decision by deleting the provisions above and replace them with the notice
27 | // and other provisions required by the GPL or the LGPL. If you do not delete
28 | // the provisions above, a recipient may use your version of this file under
29 | // the terms of any one of the MPL, the GPL or the LGPL.
30 | //
31 | // ***** END LICENSE BLOCK *****
32 |
33 | var EXPORTED_SYMBOLS = ['gKablPolicy'];
34 |
35 | var Cc = Components.classes;
36 | var Ci = Components.interfaces;
37 | var Cu = Components.utils;
38 |
39 | Cu.import('chrome://kabl/content/kabl-parse.js');
40 | Cu.import('chrome://kabl/content/kabl-pref.js');
41 | Cu.import("resource://gre/modules/XPCOMUtils.jsm");
42 |
43 | var gKablCollapseMarker=String(Math.floor(Math.random()*100000));
44 | var UNORDERED_NODE_SNAPSHOT_TYPE=6;
45 | var COLLAPSE_TEXT_LENGTH=25;
46 |
47 | var gMessageSender = Cc['@mozilla.org/childprocessmessagemanager;1']
48 | .getService(Ci.nsIMessageSender);
49 |
50 | //\\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
51 |
52 | // constructor for details of the request
53 | function Fields(type, loc, org, node) {
54 | this['$type']=type;
55 |
56 | this['$url']=loc.spec;
57 | this['$url.host']=loc.host;
58 | this['$url.path']=loc.path;
59 | this['$url.scheme']=loc.scheme;
60 |
61 | // Set base values.
62 | this['$thirdParty']=false;
63 | this['$origin']=undefined;
64 | this['$origin.host']=undefined;
65 | this['$origin.path']=undefined;
66 | this['$origin.scheme']=undefined;
67 | this['$origin.tag']=undefined;
68 |
69 | if ('about:feeds' == org.spec) {
70 | var ioService = Cc["@mozilla.org/network/io-service;1"]
71 | .getService(Ci.nsIIOService);
72 | org = ioService.newURI(node.ownerDocument.location.href, null, null);
73 | }
74 |
75 | // Conditionally override them based on scheme.
76 | switch (org.scheme) {
77 | case 'about':
78 | this['$origin']=org.spec;
79 | setOriginTag(this, node);
80 |
81 | break;
82 | case 'file':
83 | case 'chrome':
84 | this['$origin']=org.spec;
85 | this['$origin.path']=org.path;
86 | this['$origin.scheme']=org.scheme;
87 |
88 | setOriginTag(this, node);
89 |
90 | break;
91 | case 'ftp':
92 | case 'http':
93 | case 'https':
94 | var lHost=loc.host;
95 | var oHost=org.host;
96 | if (!lHost.match(/^[0-9.]+$/)) {
97 | lHost=hostToTld(lHost);
98 | oHost=hostToTld(oHost);
99 | }
100 | this['$thirdParty']=(lHost!=oHost);
101 |
102 | this['$origin']=org.spec;
103 | this['$origin.host']=org.host;
104 | this['$origin.path']=org.path;
105 | this['$origin.scheme']=org.scheme;
106 |
107 | setOriginTag(this, node);
108 |
109 | break;
110 | default:
111 | if (gKablPrefs.debug) {
112 | dump('kabl error condition, unknown origin scheme for\n\t'+org.spec+'\n');
113 | }
114 | break;
115 | }
116 |
117 | for (var i=0, key=null; key=fieldNames[i]; i++) {
118 | if ('string'==typeof this[key]) this[key]=this[key].toLowerCase();
119 | }
120 |
121 | this.node=node;
122 | }
123 |
124 | function cloneObject(obj) {
125 | if (null==obj || 'object'!=typeof obj) {
126 | return obj;
127 | }
128 |
129 | var out=new obj.constructor();
130 | for (var key in obj) {
131 | if (key=="regexVal") {
132 | // would have preferred to check "instanceof RegExp", but it fails when called from extensions
133 | //special case to avoid destroying the cached regex
134 | out[key]=obj[key];
135 | } else {
136 | out[key]=cloneObject(obj[key]);
137 | }
138 | }
139 |
140 | return out;
141 | }
142 |
143 | // true if group matches
144 | function evalGroup(group, fields) {
145 | var flag=null;
146 |
147 | for (var j=0, rule=null; rule=group.rules[j]; j++) {
148 | flag=false;
149 |
150 | if (!(rule.field in fields)) continue;
151 | var fieldVal=fields[rule.field];
152 | switch (rule.op) {
153 | case '==':
154 | flag=fieldVal==rule.val;
155 | break;
156 | case '!=':
157 | flag=fieldVal!=rule.val;
158 | break;
159 | case '=~':
160 | flag=rule.regexVal.test(fieldVal);
161 | break;
162 | case '!~':
163 | flag=!rule.regexVal.test(fieldVal);
164 | break;
165 | case '^=':
166 | flag=fieldVal.substr(0, rule.val.length)==rule.val;
167 | break;
168 | case '$=':
169 | flag=fieldVal.substr(fieldVal.length-rule.val.length)==rule.val;
170 | break;
171 | case '<':
172 | fieldVal=parseFloat(fieldVal);
173 | flag=(!isNaN(fieldVal)) && fieldVal':
176 | fieldVal=parseFloat(fieldVal);
177 | flag=(!isNaN(fieldVal)) && fieldVal>rule.val;
178 | break;
179 | }
180 |
181 | if (monitoring) rule.match=flag;
182 |
183 | if (flag && 'any'==group.match) {
184 | return true;
185 | } else if (!flag && 'all'==group.match) {
186 | return false;
187 | }
188 | }
189 |
190 | if (flag && 'all'==group.match) {
191 | return true;
192 | }
193 | }
194 |
195 | function hostToTld(host) {
196 | // this terribly simple method seems to work well enough
197 | return host.replace(/.*\.(.*......)/, '$1');
198 | }
199 |
200 | // evaluate if/how we should handle this type of score
201 | function evalScore(type, score, fields) {
202 | if (('threshold'==type && score>=gKablRulesObj.threshold) ||
203 | ('cutoff'==type && score>=gKablRulesObj.cutoff)
204 | ) {
205 | try {
206 | var el=fields.node
207 | .QueryInterface(Components.interfaces.nsIDOMNode);
208 | } catch (e) {
209 | if (gKablPrefs.debug) dump('Error in evalScore: '+e+'\n');
210 | return;
211 | }
212 |
213 | // Attempt to hide the node, i.e. if a non-loaded image will
214 | // result in an alt tag showing.
215 | try {
216 | el.setAttribute('style', 'display: none !important');
217 | } catch (e) {
218 | if (gKablPrefs.debug) dump('Error in evalScore: '+e+'\n');
219 | }
220 |
221 | // Mark the node for collapsing.
222 | try {
223 | if ('STYLE'!=el.tagName) {
224 | el.setAttribute('kabl', gKablCollapseMarker);
225 | }
226 | } catch (e) {
227 | if (gKablPrefs.debug) dump('Error in evalScore: '+e+'\n');
228 | }
229 |
230 | return REJECT;
231 | } else if ('threshold'==type ||
232 | ('cutoff'==type && Math.abs(score)>=gKablRulesObj.cutoff)
233 | ) {
234 | return ACCEPT;
235 | } else {
236 | return undefined;
237 | }
238 | }
239 |
240 | function monitorAdd(fields, groups, score, flag) {
241 | if (!monitoring) return;
242 |
243 | var blocked=REJECT==flag;
244 |
245 | try {
246 | var filteredFields = {};
247 | for (i in fields) {
248 | var t = typeof fields[i];
249 | if (t == 'string' || t == 'number') filteredFields[i] = fields[i]
250 | }
251 | gMessageSender.sendAsyncMessage('kabl:monitor', {
252 | 'fields': filteredFields,
253 | 'groups': groups,
254 | 'score': score,
255 | 'blocked': blocked,
256 | });
257 | } catch (e) {
258 | dump('ERROR in monitorAdd: ' + e + '\n\n');
259 | }
260 | }
261 |
262 | function setOriginTag(obj, node) {
263 | obj['$origin.tag']=node.tagName;
264 |
265 | if (!node.attributes) return;
266 | for (var i=0, attr=null; attr=node.attributes.item(i); i++) {
267 | obj['$origin.tag.'+attr.nodeName]=attr.value.toLowerCase();
268 | }
269 |
270 | if (obj['$origin.tag.width'] && obj['$origin.tag.height']) {
271 | obj['$origin.tag.size']=obj['$origin.tag.width']
272 | +'x'+obj['$origin.tag.height'];
273 | }
274 | }
275 |
276 | function strippedTextContent(el) {
277 | var text=el.innerHTML || el.textContent;
278 | if (!text) return '';
279 |
280 | text=text.replace(/[\s]+/g, ' '); //collapse whitespace
281 | text=text.replace(/^\s+|\s+$/g, ''); //strip leading/trailing whitespace
282 | text=text.replace(//gi, ''); //strip js
283 | text=text.replace(//gi, ''); //strip no-js
284 | text=text.replace(//gi, ''); // iframe, alternate content
285 | text=text.replace(//gi, ''); //strip comments
286 | text=text.replace(/<\/?[^>]+>/gi, ''); //strip tags
287 |
288 | return text;
289 | }
290 |
291 | //Inherited from AdBlock Plus, utils.js
292 | function windowForNode(node) {
293 | if (node && node.nodeType!=Components.interfaces.nsIDOMNode.DOCUMENT_NODE) {
294 | node = node.ownerDocument;
295 | }
296 |
297 | if (!node || node.nodeType!=Components.interfaces.nsIDOMNode.DOCUMENT_NODE) {
298 | return null;
299 | }
300 |
301 | return node.defaultView;
302 | }
303 |
304 | //\\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
305 |
306 | var ACCEPT=Components.interfaces.nsIContentPolicy.ACCEPT;
307 | var REJECT=Components.interfaces.nsIContentPolicy.REJECT_REQUEST;
308 |
309 | var fieldNames=['$type', '$thirdParty',
310 | '$url', '$url.host', '$url.path', '$url.scheme',
311 | '$origin', '$origin.host', '$origin.path', '$origin.scheme', '$origin.tag'];
312 |
313 | var monitoring=false;
314 |
315 | //\\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
316 |
317 | var startupDone=false;
318 |
319 | var gKablPolicy={
320 | classDescription: 'Karma Blocker content policy',
321 | classID: Components.ID('cabe6b3f-578c-480f-a2f0-68bc4b7a1142'),
322 | contractID: '@arantius.com/kabl-policy;1',
323 |
324 | QueryInterface: XPCOMUtils.generateQI(
325 | [Ci.nsIContentPolicy, Ci.nsIFactory, Ci.nsISupportsWeakReference]),
326 |
327 | // nsIFactory
328 | createInstance:function(outer, iid) {
329 | if (outer) throw Cr.NS_ERROR_NO_AGGREGATION;
330 | return this.QueryInterface(iid);
331 | },
332 |
333 | // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
334 |
335 | startup:function(outer, iid) {
336 | if (startupDone) return;
337 | startupDone=true;
338 |
339 | // set up initial parsed rules object
340 | gKablRulesObj.parse(gKablPrefs.rules);
341 |
342 | try {
343 | var registrar = Components.manager.QueryInterface(
344 | Ci.nsIComponentRegistrar);
345 | registrar.registerFactory(
346 | gKablPolicy.classID, gKablPolicy.classDescription,
347 | gKablPolicy.contractID, gKablPolicy);
348 | } catch (e) {
349 | dump('KABL registration error: '+e+'\n');
350 | }
351 |
352 | var categoryManager = Cc['@mozilla.org/categorymanager;1']
353 | .getService(Ci.nsICategoryManager);
354 | categoryManager.addCategoryEntry(
355 | 'content-policy', gKablPolicy.classDescription,
356 | gKablPolicy.contractID, false, true);
357 |
358 | var cpmm = Cc['@mozilla.org/childprocessmessagemanager;1']
359 | .getService(Ci.nsIMessageListenerManager);
360 | cpmm.addMessageListener('kabl:monitor-opened', function() {
361 | monitoring=true;
362 | });
363 | cpmm.addMessageListener('kabl:monitor-closed', function() {
364 | monitoring=false;
365 | });
366 | },
367 |
368 | collapse:function(event) {
369 | // Don't continue if we're configured not to do collapsing.
370 | if (!gKablRulesObj.collapse) return;
371 |
372 | // called when a content page loads, this looks for elements that were
373 | // marked as blocked, and looks for a parent node that should be
374 | // collapsed down (because it's probably just a wrapper around the ad)
375 |
376 | var doc=event.target;
377 | var xpr=doc.evaluate(
378 | '//*[@kabl="'+gKablCollapseMarker+'"]',
379 | doc, null, UNORDERED_NODE_SNAPSHOT_TYPE, null);
380 | for (var i=0, item=null; item=xpr.snapshotItem(i); i++) {
381 | // Climb the DOM, from this item, to find a container to collapse.
382 | var el=null;
383 | while (item=item.parentNode) {
384 | // Before we pick this as a collapsing candidate, check for
385 | // stop conditions.
386 | if ('BODY'==item.tagName) break;
387 | if ('HTML'==item.tagName) break;
388 | if (0!=item.getElementsByTagName('form').length) break;
389 | if (strippedTextContent(item).length>COLLAPSE_TEXT_LENGTH) break;
390 |
391 | el=item;
392 | }
393 |
394 | // If we selected an item, collapse it.
395 | // try block just in case, attempt to hide the node, i.e.
396 | // if a non-loaded image will result in an alt tag showing
397 | try {
398 | if (el) {
399 | el=el.QueryInterface(Components.interfaces.nsIDOMNode);
400 | el.setAttribute('style', 'display: none !important');
401 | el.setAttribute('kablcollapse', '1');
402 | }
403 | } catch (e) {
404 | if (gKablPrefs.debug) dump('Error in collapse: '+e+'\n');
405 | }
406 | }
407 | },
408 |
409 | // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
410 |
411 | // nsIContentPolicy
412 | shouldLoad:function(contentType, contentLocation, requestOrigin,
413 | requestingNode, mimeTypeGuess, extra) {
414 | try {
415 |
416 | // when not enabled, let it through
417 | if (!gKablPrefs.enabled) {
418 | return ACCEPT;
419 | }
420 |
421 | // it's not a remote scheme, definitely let it through
422 | if (!contentLocation.schemeIs('http') &&
423 | !contentLocation.schemeIs('https') &&
424 | !contentLocation.schemeIs('chrome') &&
425 | !contentLocation.schemeIs('ftp')
426 | ) {
427 | return ACCEPT;
428 | }
429 |
430 | // never block core parts of the browser
431 | if ('chrome://global/'==contentLocation.spec.substr(0, 16)
432 | || 'chrome://browser/'==contentLocation.spec.substr(0, 17)
433 | ) {
434 | return ACCEPT;
435 | }
436 |
437 | // if it is chrome, and so is the origin, let it through
438 | if (contentLocation.schemeIs('chrome') &&
439 | requestOrigin && requestOrigin.schemeIs('chrome')
440 | ) {
441 | return ACCEPT;
442 | }
443 |
444 | // Only block in content windows (this from AdBlock Plus)
445 | var win=windowForNode(requestingNode);
446 | if (!win) return ACCEPT;
447 | var winType=win
448 | .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
449 | .getInterface(Components.interfaces.nsIWebNavigation)
450 | .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
451 | .itemType;
452 | if (winType!=Components.interfaces.nsIDocShellTreeItem.typeContent) {
453 | return ACCEPT;
454 | }
455 |
456 | // Start checking for whether we should block!
457 | var fields=new Fields(
458 | contentType, contentLocation, requestOrigin, requestingNode);
459 | var monitorGroups=[];
460 |
461 | var score=0, flag=false;
462 | for (var i=0, group=null; group=gKablRulesObj.groups[i]; i++) {
463 | if (monitoring) {
464 | group=cloneObject(group);
465 | monitorGroups.push(group);
466 | }
467 |
468 | if (evalGroup(group, fields, monitoring)) {
469 | score+=group.score;
470 | flag=evalScore('cutoff', score, fields);
471 | if (flag) {
472 | if (monitoring) {
473 | monitorGroups.push({
474 | 'name': 'Cutoff score reached, processing halted.',
475 | 'score': null, 'match': null, 'rules': null});
476 | }
477 | break;
478 | }
479 | } else {
480 | if (monitoring) group.score=0;
481 | }
482 | }
483 |
484 | if (!flag) {
485 | flag=evalScore('threshold', score, fields);
486 | }
487 |
488 | if (!flag) flag=ACCEPT;
489 |
490 | if (monitoring) monitorAdd(fields, monitorGroups, score, flag);
491 | return flag;
492 |
493 | } catch (e) {
494 | dump('ERROR IN kabl policy: ' + e + '\n');
495 | for (var i in e) dump(i+' '+e[i]+'\n');
496 | return ACCEPT;
497 | }
498 | },
499 |
500 | shouldProcess:function(contentType, contentLocation, requestOrigin,
501 | requestingNode, mimeType, extra) {
502 | return ACCEPT;
503 | }
504 | };
505 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU General Public License
2 | **************************
3 |
4 | GNU GENERAL PUBLIC LICENSE
5 | Version 2, June 1991
6 |
7 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.
8 | 675 Mass Ave, Cambridge, MA 02139, USA
9 | Everyone is permitted to copy and distribute verbatim copies
10 | of this license document, but changing it is not allowed.
11 |
12 | Preamble
13 |
14 | The licenses for most software are designed to take away your
15 | freedom to share and change it. By contrast, the GNU General Public
16 | License is intended to guarantee your freedom to share and change free
17 | software--to make sure the software is free for all its users. This
18 | General Public License applies to most of the Free Software
19 | Foundation's software and to any other program whose authors commit to
20 | using it. (Some other Free Software Foundation software is covered by
21 | the GNU Library General Public License instead.) You can apply it to
22 | your programs, too.
23 |
24 | When we speak of free software, we are referring to freedom, not
25 | price. Our General Public Licenses are designed to make sure that you
26 | have the freedom to distribute copies of free software (and charge for
27 | this service if you wish), that you receive source code or can get it
28 | if you want it, that you can change the software or use pieces of it
29 | in new free programs; and that you know you can do these things.
30 |
31 | To protect your rights, we need to make restrictions that forbid
32 | anyone to deny you these rights or to ask you to surrender the rights.
33 | These restrictions translate to certain responsibilities for you if you
34 | distribute copies of the software, or if you modify it.
35 |
36 | For example, if you distribute copies of such a program, whether
37 | gratis or for a fee, you must give the recipients all the rights that
38 | you have. You must make sure that they, too, receive or can get the
39 | source code. And you must show them these terms so they know their
40 | rights.
41 |
42 | We protect your rights with two steps: (1) copyright the software, and
43 | (2) offer you this license which gives you legal permission to copy,
44 | distribute and/or modify the software.
45 |
46 | Also, for each author's protection and ours, we want to make certain
47 | that everyone understands that there is no warranty for this free
48 | software. If the software is modified by someone else and passed on, we
49 | want its recipients to know that what they have is not the original, so
50 | that any problems introduced by others will not reflect on the original
51 | authors' reputations.
52 |
53 | Finally, any free program is threatened constantly by software
54 | patents. We wish to avoid the danger that redistributors of a free
55 | program will individually obtain patent licenses, in effect making the
56 | program proprietary. To prevent this, we have made it clear that any
57 | patent must be licensed for everyone's free use or not licensed at all.
58 |
59 | The precise terms and conditions for copying, distribution and
60 | modification follow.
61 |
62 | GNU GENERAL PUBLIC LICENSE
63 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
64 |
65 | 0. This License applies to any program or other work which contains
66 | a notice placed by the copyright holder saying it may be distributed
67 | under the terms of this General Public License. The "Program", below,
68 | refers to any such program or work, and a "work based on the Program"
69 | means either the Program or any derivative work under copyright law:
70 | that is to say, a work containing the Program or a portion of it,
71 | either verbatim or with modifications and/or translated into another
72 | language. (Hereinafter, translation is included without limitation in
73 | the term "modification".) Each licensee is addressed as "you".
74 |
75 | Activities other than copying, distribution and modification are not
76 | covered by this License; they are outside its scope. The act of
77 | running the Program is not restricted, and the output from the Program
78 | is covered only if its contents constitute a work based on the
79 | Program (independent of having been made by running the Program).
80 | Whether that is true depends on what the Program does.
81 |
82 | 1. You may copy and distribute verbatim copies of the Program's
83 | source code as you receive it, in any medium, provided that you
84 | conspicuously and appropriately publish on each copy an appropriate
85 | copyright notice and disclaimer of warranty; keep intact all the
86 | notices that refer to this License and to the absence of any warranty;
87 | and give any other recipients of the Program a copy of this License
88 | along with the Program.
89 |
90 | You may charge a fee for the physical act of transferring a copy, and
91 | you may at your option offer warranty protection in exchange for a fee.
92 |
93 | 2. You may modify your copy or copies of the Program or any portion
94 | of it, thus forming a work based on the Program, and copy and
95 | distribute such modifications or work under the terms of Section 1
96 | above, provided that you also meet all of these conditions:
97 |
98 | a) You must cause the modified files to carry prominent notices
99 | stating that you changed the files and the date of any change.
100 |
101 | b) You must cause any work that you distribute or publish, that in
102 | whole or in part contains or is derived from the Program or any
103 | part thereof, to be licensed as a whole at no charge to all third
104 | parties under the terms of this License.
105 |
106 | c) If the modified program normally reads commands interactively
107 | when run, you must cause it, when started running for such
108 | interactive use in the most ordinary way, to print or display an
109 | announcement including an appropriate copyright notice and a
110 | notice that there is no warranty (or else, saying that you provide
111 | a warranty) and that users may redistribute the program under
112 | these conditions, and telling the user how to view a copy of this
113 | License. (Exception: if the Program itself is interactive but
114 | does not normally print such an announcement, your work based on
115 | the Program is not required to print an announcement.)
116 |
117 | These requirements apply to the modified work as a whole. If
118 | identifiable sections of that work are not derived from the Program,
119 | and can be reasonably considered independent and separate works in
120 | themselves, then this License, and its terms, do not apply to those
121 | sections when you distribute them as separate works. But when you
122 | distribute the same sections as part of a whole which is a work based
123 | on the Program, the distribution of the whole must be on the terms of
124 | this License, whose permissions for other licensees extend to the
125 | entire whole, and thus to each and every part regardless of who wrote it.
126 |
127 | Thus, it is not the intent of this section to claim rights or contest
128 | your rights to work written entirely by you; rather, the intent is to
129 | exercise the right to control the distribution of derivative or
130 | collective works based on the Program.
131 |
132 | In addition, mere aggregation of another work not based on the Program
133 | with the Program (or with a work based on the Program) on a volume of
134 | a storage or distribution medium does not bring the other work under
135 | the scope of this License.
136 |
137 | 3. You may copy and distribute the Program (or a work based on it,
138 | under Section 2) in object code or executable form under the terms of
139 | Sections 1 and 2 above provided that you also do one of the following:
140 |
141 | a) Accompany it with the complete corresponding machine-readable
142 | source code, which must be distributed under the terms of Sections
143 | 1 and 2 above on a medium customarily used for software interchange; or,
144 |
145 | b) Accompany it with a written offer, valid for at least three
146 | years, to give any third party, for a charge no more than your
147 | cost of physically performing source distribution, a complete
148 | machine-readable copy of the corresponding source code, to be
149 | distributed under the terms of Sections 1 and 2 above on a medium
150 | customarily used for software interchange; or,
151 |
152 | c) Accompany it with the information you received as to the offer
153 | to distribute corresponding source code. (This alternative is
154 | allowed only for noncommercial distribution and only if you
155 | received the program in object code or executable form with such
156 | an offer, in accord with Subsection b above.)
157 |
158 | The source code for a work means the preferred form of the work for
159 | making modifications to it. For an executable work, complete source
160 | code means all the source code for all modules it contains, plus any
161 | associated interface definition files, plus the scripts used to
162 | control compilation and installation of the executable. However, as a
163 | special exception, the source code distributed need not include
164 | anything that is normally distributed (in either source or binary
165 | form) with the major components (compiler, kernel, and so on) of the
166 | operating system on which the executable runs, unless that component
167 | itself accompanies the executable.
168 |
169 | If distribution of executable or object code is made by offering
170 | access to copy from a designated place, then offering equivalent
171 | access to copy the source code from the same place counts as
172 | distribution of the source code, even though third parties are not
173 | compelled to copy the source along with the object code.
174 |
175 | 4. You may not copy, modify, sublicense, or distribute the Program
176 | except as expressly provided under this License. Any attempt
177 | otherwise to copy, modify, sublicense or distribute the Program is
178 | void, and will automatically terminate your rights under this License.
179 | However, parties who have received copies, or rights, from you under
180 | this License will not have their licenses terminated so long as such
181 | parties remain in full compliance.
182 |
183 | 5. You are not required to accept this License, since you have not
184 | signed it. However, nothing else grants you permission to modify or
185 | distribute the Program or its derivative works. These actions are
186 | prohibited by law if you do not accept this License. Therefore, by
187 | modifying or distributing the Program (or any work based on the
188 | Program), you indicate your acceptance of this License to do so, and
189 | all its terms and conditions for copying, distributing or modifying
190 | the Program or works based on it.
191 |
192 | 6. Each time you redistribute the Program (or any work based on the
193 | Program), the recipient automatically receives a license from the
194 | original licensor to copy, distribute or modify the Program subject to
195 | these terms and conditions. You may not impose any further
196 | restrictions on the recipients' exercise of the rights granted herein.
197 | You are not responsible for enforcing compliance by third parties to
198 | this License.
199 |
200 | 7. If, as a consequence of a court judgment or allegation of patent
201 | infringement or for any other reason (not limited to patent issues),
202 | conditions are imposed on you (whether by court order, agreement or
203 | otherwise) that contradict the conditions of this License, they do not
204 | excuse you from the conditions of this License. If you cannot
205 | distribute so as to satisfy simultaneously your obligations under this
206 | License and any other pertinent obligations, then as a consequence you
207 | may not distribute the Program at all. For example, if a patent
208 | license would not permit royalty-free redistribution of the Program by
209 | all those who receive copies directly or indirectly through you, then
210 | the only way you could satisfy both it and this License would be to
211 | refrain entirely from distribution of the Program.
212 |
213 | If any portion of this section is held invalid or unenforceable under
214 | any particular circumstance, the balance of the section is intended to
215 | apply and the section as a whole is intended to apply in other
216 | circumstances.
217 |
218 | It is not the purpose of this section to induce you to infringe any
219 | patents or other property right claims or to contest validity of any
220 | such claims; this section has the sole purpose of protecting the
221 | integrity of the free software distribution system, which is
222 | implemented by public license practices. Many people have made
223 | generous contributions to the wide range of software distributed
224 | through that system in reliance on consistent application of that
225 | system; it is up to the author/donor to decide if he or she is willing
226 | to distribute software through any other system and a licensee cannot
227 | impose that choice.
228 |
229 | This section is intended to make thoroughly clear what is believed to
230 | be a consequence of the rest of this License.
231 |
232 | 8. If the distribution and/or use of the Program is restricted in
233 | certain countries either by patents or by copyrighted interfaces, the
234 | original copyright holder who places the Program under this License
235 | may add an explicit geographical distribution limitation excluding
236 | those countries, so that distribution is permitted only in or among
237 | countries not thus excluded. In such case, this License incorporates
238 | the limitation as if written in the body of this License.
239 |
240 | 9. The Free Software Foundation may publish revised and/or new versions
241 | of the General Public License from time to time. Such new versions will
242 | be similar in spirit to the present version, but may differ in detail to
243 | address new problems or concerns.
244 |
245 | Each version is given a distinguishing version number. If the Program
246 | specifies a version number of this License which applies to it and "any
247 | later version", you have the option of following the terms and conditions
248 | either of that version or of any later version published by the Free
249 | Software Foundation. If the Program does not specify a version number of
250 | this License, you may choose any version ever published by the Free Software
251 | Foundation.
252 |
253 | 10. If you wish to incorporate parts of the Program into other free
254 | programs whose distribution conditions are different, write to the author
255 | to ask for permission. For software which is copyrighted by the Free
256 | Software Foundation, write to the Free Software Foundation; we sometimes
257 | make exceptions for this. Our decision will be guided by the two goals
258 | of preserving the free status of all derivatives of our free software and
259 | of promoting the sharing and reuse of software generally.
260 |
261 | NO WARRANTY
262 |
263 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
264 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
265 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
266 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
267 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
268 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
269 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
270 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
271 | REPAIR OR CORRECTION.
272 |
273 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
274 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
275 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
276 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
277 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
278 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
279 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
280 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
281 | POSSIBILITY OF SUCH DAMAGES.
282 |
283 | END OF TERMS AND CONDITIONS
284 |
285 | Appendix: How to Apply These Terms to Your New Programs
286 |
287 | If you develop a new program, and you want it to be of the greatest
288 | possible use to the public, the best way to achieve this is to make it
289 | free software which everyone can redistribute and change under these terms.
290 |
291 | To do so, attach the following notices to the program. It is safest
292 | to attach them to the start of each source file to most effectively
293 | convey the exclusion of warranty; and each file should have at least
294 | the "copyright" line and a pointer to where the full notice is found.
295 |
296 |
297 | Copyright (C) 19yy
298 |
299 | This program is free software; you can redistribute it and/or modify
300 | it under the terms of the GNU General Public License as published by
301 | the Free Software Foundation; either version 2 of the License, or
302 | (at your option) any later version.
303 |
304 | This program is distributed in the hope that it will be useful,
305 | but WITHOUT ANY WARRANTY; without even the implied warranty of
306 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
307 | GNU General Public License for more details.
308 |
309 | You should have received a copy of the GNU General Public License
310 | along with this program; if not, write to the Free Software
311 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
312 |
313 | Also add information on how to contact you by electronic and paper mail.
314 |
315 | If the program is interactive, make it output a short notice like this
316 | when it starts in an interactive mode:
317 |
318 | Gnomovision version 69, Copyright (C) 19yy name of author
319 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
320 | This is free software, and you are welcome to redistribute it
321 | under certain conditions; type `show c' for details.
322 |
323 | The hypothetical commands `show w' and `show c' should show the appropriate
324 | parts of the General Public License. Of course, the commands you use may
325 | be called something other than `show w' and `show c'; they could even be
326 | mouse-clicks or menu items--whatever suits your program.
327 |
328 | You should also get your employer (if you work as a programmer) or your
329 | school, if any, to sign a "copyright disclaimer" for the program, if
330 | necessary. Here is a sample; alter the names:
331 |
332 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
333 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
334 |
335 | , 1 April 1989
336 | Ty Coon, President of Vice
337 |
338 | This General Public License does not permit incorporating your program into
339 | proprietary programs. If your program is a subroutine library, you may
340 | consider it more useful to permit linking proprietary applications with the
341 | library. If this is what you want to do, use the GNU Library General
342 | Public License instead of this License.
343 |
--------------------------------------------------------------------------------