// ==UserScript==
// @name SmartProxyForChina.uc.js
// @description 类似AutoProxy的UC脚本
// @author dannylee
// @namespace lidanny2012/smartproxy@gmail.com
// @include main
// @license MIT License
// @compatibility Firefox 13-21
// @charset UTF-8
// @version 1.2.1.9
// @note 2014/07/25 完善可移动按钮,不支持放在 panelUI 里面。
// @note 1.2.1 2014/04/26 findbar is back, bugs is fixed by ABP2.6
// @note 1.2.0 2014/04/11 Modify for FF29's AddonbarforUC.uc.js
// @note 1.1.0 2014/02/14 Fixed for FF27 ,cancel finderbar
// @note 1.0.9 2014/01/15 更新订阅后自动载入并保存,全局代理不再匹配规则
// @note 1.0.8.5 2013/9/16 修复bug
// @note 1.0.8 2013/9/7 修复个别含重定向地址的proxy bugs, 最小分辨率支持1024X768
// @note 1.0.8 2013/9/7 修改按钮动作, 左键点击弹出菜单,中键点击切换代理模式,右键点击打开系统规则和设置
// @note 1.0.7 2013/5/13 Fixed screen 1360X768 bugs
// @note 1.0.6 2013/5/09 Fixed treeview bug in FF22
// @note 1.0.5 2013/4/30 Fixed bug and change icon
// @note 1.0.4 2013/4/29 Fixed bug and url Unicode's view
// @note 1.0.3 2013/4/28 ADD gfwlist download and update
// @note 1.0.2 2013/4/26 Update For Use ABP 2.2.3 Matcher and Filter Class
// @note 1.0.1 2013/4/11 Remove E4X
// @note 1.0.0 2012/3/16 add UI for rule and import gfwlist file
// @note 0.0.5 2011/10/21 limit proxy server numbers
// @note 0.0.4 2011/8/19 update for nsIProtocolProxyService
// @note 0.0.3 2011/8/18 update filter json file
// @note 0.0.2 2011/8/15 update for abp filter class and match
// @note 0.0.1 2011/8/13 Create Project
// @note 与AutoProxy或其它代理脚本同时使用会冲突
// @note 不依赖ABP, 不安装ABP也可以使用, 也可以与ABP同时使用。
// @note Firefox代理设置为无,最好打开Firefox远程DNS解析
// @note 附加组件栏按钮, 左键点击切换代理模式,右键点击打开系统规则和设置。
// @note 下拉菜单切换代理模式和智能化的对当前站点的代理规则进行操作
// @note report bug and linkurl: https://g.mozest.com/thread-43513-1-1
// @updateURL https://j.mozest.com/ucscript/script/104.meta.js
// @screenshot http://j.mozest.com/images/uploads/previews/000/00/01/c8e11c00-f2fd-eb7f-cc32-cad6a55ae316.jpg http://j.mozest.com/images/uploads/previews/000/00/01/thumb-c8e11c00-f2fd-eb7f-cc32-cad6a55ae316.jpg
// ==/UserScript==
(function(css){
if (window.SmartProxy) {
window.SmartProxy.uninit();
delete window.SmartProxy;
}
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils;
if (!window.Services)
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const ProxySrv = Cc['@mozilla.org/network/protocol-proxy-service;1'].getService(Ci.nsIProtocolProxyService);
const dirService = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
const ioService = Components.classes['@mozilla.org/network/io-service;1'].getService(Ci.nsIIOService);
const _eTLDService = Cc["@mozilla.org/network/effective-tld-service;1"].getService(Ci.nsIEffectiveTLDService);
const _idnService = Cc["@mozilla.org/network/idn-service;1"].getService(Ci.nsIIDNService);
const promptService = Cc["@mozilla.org/embedcomp/prompt-service;1"].getService(Ci.nsIPromptService);
const clipboard = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
const clipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
const FileInputStream = Components.Constructor("@mozilla.org/network/file-input-stream;1", "nsIFileInputStream", "init");
const ConverterInputStream = Components.Constructor("@mozilla.org/intl/converter-input-stream;1", "nsIConverterInputStream", "init");
const FileOutputStream = Components.Constructor("@mozilla.org/network/file-output-stream;1", "nsIFileOutputStream", "init");
const ConverterOutputStream = Components.Constructor("@mozilla.org/intl/converter-output-stream;1", "nsIConverterOutputStream", "init");
const IPREG = /^(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])$/;
const PORTREG = /^\+?[1-9][0-9]*$/;
const SUBSCRIPTION_UPDATE_SUCCESS = 'DOWNLOAD SUCCESS';
var windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
var EXPORTED_SYMBOLS = ["SmartProxy"];
window.SmartProxy = {
QueryInterface: function(uuid) {
if (!uuid.equals(Ci.nsISupports)) {
throw Cr.NS_ERROR_NO_INTERFACE;
}
return this;
},
_ps: Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefService).
getBranch("userChromeJS.SmartProxy.").
QueryInterface(Components.interfaces.nsIPrefBranch2),
Prefs: {},
SPfile: null,
SPfilters: [],
icon: null,
popupid: null,
MsgBox: null,
SVRROWS: null,
modebtn: null,
noproxy: null,
autoproxy: null,
globalproxy: null,
siteProxyOn: null,
reportgfwlist: null,
Treevisible: false,
SPfilterActionMenu: null,
_isready: false,
_FilterIsReady: false,
mode: ['disabled', 'auto', 'global'],
init: function(){
this._isready = false;
this._FilterIsReady = false;
this.loadSPoverloay();
},
uninit: function(){
if (SmartProxy.Proxy.isRegisted)
ProxySrv.uninit();
SPdefaultMatcher.clear();
this.SPfilters = null;
this._ps.removeObserver("", this, false);
this.popupid.parentNode.removeChild(this.popupid);
this.icon.parentNode.removeChild(this.icon);
var e = E("sp-mains");
if (e) e.parentNode.removeChild(e);
var e = E("SP-splitter");
if (e) e.parentNode.removeChild(e);
this.Prefs = {};
},
loadSPjson: function(){
this.SPfile = this._getSmartProxyfile(this.Prefs.patternsfile);
var afile = this._getSmartProxyfile("SPpatterns.json");
if (afile.exists())
this._importpatternsfile(afile);
else {
if (this.SPfile.exists()) {
var subrec = this._importSUBpatternsfile(this.SPfile);
if (subrec > 0)
SmartProxy.saveAllFilter();
} else {
this.showMsg("没有任何代理规则!");
this._ps.setCharPref("proxyMode", "disabled");
}
}
},
loadSPoverloay: function() {//urlbar-icons
// Search for widget toolbar by reading toolbar's currentset attribute
let container = null;
let toolbars = document.getElementsByTagName('toolbar');
let id = 'SmartProxy-button';
for (let i = 0; i < toolbars.length; i += 1) {
let toolbar = toolbars[i];
if (toolbar.getAttribute('currentset').indexOf(id) !== -1) {
container = toolbar;
}
}
if (!container) {
// console.log('111', '不存在 SmartProxy-button')
} else {
let nextNode = null;
let currentSet = container.getAttribute('currentset');
let ids = (currentSet === '__empty') ? [] : currentSet.split(',');
let idx = ids.indexOf(id);
if (idx !== -1) {
for (let i = idx; i < ids.length; i += 1) {
nextNode = document.getElementById(ids[i]);
if (nextNode) {
break;
}
}
}
// console.log('111', 'nextNode is', nextNode);
this.fixButton = function() {
container.insertItem(id, nextNode, null, false);
};
}
var overlay = '\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
';
if (getFoxVer() >= 29) {
if (window.UCADDONBAR)
overlay.replace('', '');
else
overlay.replace('', '');
}
overlay = "data:application/vnd.mozilla.xul+xml;charset=utf-8," + encodeURI(overlay);
window.userChrome_js.loadOverlay(overlay, SmartProxy);
SmartProxy.style = addStyle(css);
},
observe: function(aSubject, aTopic, aData){
if (aTopic == "xul-overlay-merged") {
if (!this._isready) {
if (this.fixButton) {
this.fixButton();
delete this.fixButton;
}
this.refreshPrefs();
this._ps.addObserver("", this, false);
Application.console.log("SmartProxy界面加载完毕!");
this.icon = E("SmartProxy-button");
this.popupid = E("sp-popup");
this.MsgBox = E("SPMESSAGE");
this._isready = true;
this.updateUI();
this._addSVRlist();
this.loadSPjson();
SmartProxy.FilterActions.init();
SmartProxy.FilterSearch.init();
if (!SmartProxy.Proxy.isRegisted)
SmartProxy.Proxy.init();
}
}
if (aTopic == "nsPref:changed") {
switch (aData) {
case 'default_proxy':
this.Prefs.default_proxy = this._ps.getIntPref("default_proxy");
this.updatetips();
SmartProxy.Proxy.setdefaultProxy();
break;
case 'knownProxy':
this.Prefs.knownProxy = this._ps.getCharPref("knownProxy");
if (SmartProxy.Proxy.isRegisted)
SmartProxy.Proxy.uninit();
this._setproxyConfig();
this._addSVRlist();
this.updatetips();
if (!SmartProxy.Proxy.isRegisted)
SmartProxy.Proxy.init();
break;
case 'proxyMode':
this.Prefs.proxyMode = this._ps.getCharPref("proxyMode");
this.updateSHOWMODE();
this.updatetips();
break;
}
}
},
updateUI: function() {
this.SVRROWS = E("SROWS");
this.modebtn = E("proxymode");
this.noproxy = E("noproxy");
this.autoproxy = E("autoproxy");
this.globalproxy = E("globalproxy");
this.siteProxyOn = E("siteProxyOn");
this.reportgfwlist = E("reportgfwlist");
this.SPfilterActionMenu = E("SPfilterActionMenu");
this.updateSHOWMODE();
this.updatetips();
},
updateSHOWMODE: function() {
this.modebtn.value = this.Prefs.proxyMode;
if (this.Prefs.proxyMode == this.mode[0])
this.modebtn.selectedItem = this.noproxy;
else if (this.Prefs.proxyMode == this.mode[1])
this.modebtn.selectedItem = this.autoproxy;
else if (this.Prefs.proxyMode == this.mode[2])
this.modebtn.selectedItem = this.globalproxy;
},
_addSVRlist: function(){
var pmenu = null;
while (this.SVRROWS.lastChild) {
if (this.SVRROWS.lastChild.id != "discription")
this.SVRROWS.removeChild(this.SVRROWS.lastChild);
else
break;
}
while (this.popupid.firstChild) {
this.popupid.removeChild(this.popupid.firstChild);
}
for (var i=0; i < this.proxyConfigs.length; i++) {
this._createServerList(i, this.proxyConfigs[i]);
pmenu = document.createElement("menuitem");
pmenu.setAttribute("id", "POPUP_" + i.toString());
pmenu.setAttribute("type", "radio");
pmenu.setAttribute("name", "SVRDEF");
pmenu.setAttribute("label", this.proxyConfigs[i].name + " " + this.proxyConfigs[i].host + ":" + this.proxyConfigs[i].port);
if (i == this.Prefs.default_proxy)
pmenu.setAttribute("checked", true);
pmenu.setAttribute("oncommand", "SmartProxy.popdefaultproxy(event);");
this.popupid.appendChild(pmenu);
}
},
updatetips: function(){
this.updateicon(this.Prefs.proxyMode);
if (this.Prefs.proxyMode == this.mode[0])
this.icon.setAttribute("tooltiptext", "代理状态: 无");
else if (this.Prefs.proxyMode == this.mode[1])
this.icon.setAttribute("tooltiptext", "代理状态: 自动代理 \n " + this.formattiptext());
else if (this.Prefs.proxyMode == this.mode[2])
this.icon.setAttribute("tooltiptext", "代理状态: 全局代理 \n " + this.formattiptext());
//this.showMsg(this.icon.getAttribute("tooltiptext") + " " + this.formattiptext());
this.showMsg(this.icon.getAttribute("tooltiptext"));
},
updateicon: function(proxyMode){
switch (proxyMode) {
case "disabled" :
this.icon.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACxElEQVQ4jY3RTUiTARgHcClCUwfT2d5NOygsETIPLTMonZvOTW225dT8wnSY22rzY9jM+fGaWqgZghCIhFF6CUqd+urUuVz5gS3nNqeFNDp0meQxqEj+HUSlw8r/+fn/eHgePz8fsdksYS6Xi/B4PITX6yG8Xi/h9XoJj8dDeFwuwrW8TJAkecxX3+/FQP92d2c7ujvb8aijDR0PWnCfrEe9vgbVlWo8bGuGxTQe6xN43Nm+XaVVoVKjxG1VOcoVJSgqzIVUKoFQmApFWTFmJkbO+QTaWxu3CwtyUJAvR17udUilEqSni8Dn83Gey4VMlvVvoMmg3xamCSEUpkIgEOBiQgLOxsaCw+Eg4nQEJFcz9gCrdYptX1lQO+zL6nWHTb31aV39eWtD3dPdsdPSXP9dX1v1Mzv7GlhsFpgEE2GnwsBghCIjQ7wHTFNGXq1OiyqtCto7FVApFSgrLUL+DTkkkkykpKagUqMEjUZDcHAwgoICERh4EmKx6BCo1CihUipQcasUirJiFBXmQibLgkiUhsSkJDQ36NFkuAtDnQ5kYx3Ixjr09nQdAmWlRcjOvgaZLAsSSSbEYhEEAgEuxMeDw+Gg4Z5uZ2ZydHdwoH/INPYqz2ZbjLFYTDF9fX0n/KYpI08ulyKZn4zLiVcQFxeH6OhoREZFgh3OBovNQitpwOCzfsxOGWE1U7sD/U8uHVx7mjLyxGIROGc4YIezwSSYYDBCERIaAjqdDjqdjnp99deh509vmqgReW9vV9Rf75qmjLwkHu+gQKPRDg4VEBAAf39/6Go0bp//njMNc62WSefK4hunc+29c9Nt//Jxw/Ft073mXLUtOhets06rmRr2CexndnaUmJ+huqxmyrG8YPllNo29nrdMlvy3eLjJONftWrWvfVj6PT8zsbv0bu6Hbent0JGB/bzMyTneR5KBR53/A0SneonKm1KCAAAAAElFTkSuQmCC");
break;
case "auto" :
this.icon.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACwElEQVQ4jY3RW0iTcRgG8D9FaIowNfycXaSxxIvyIhOK0plWE2KWqB2NUjG3pVPTiixxZSW1DoJgmckqlCLyNO1z8zSdOmVO3b45XR6+tlrJt6iLrrpIni5MpYuVz/X7/Hh5X0I8xGTSbbJarRTLshTHsRTHcRTHcRTLshRrtVLWkRFKoVCs89Qnj9uM7uLGDyhucqCw0Ym8tx+R/cqBUy9YJD2dQUG9GTpt+3aPQEmD0S1SLeCgagHCZwvYWf0FWytdIHc/gSic2PPQgq53LTs8AgWqYfeWShc2P3KBPPhTLHeClDpAiucRcnPs34C0dshNbjhBFE6QMgfI5XkQ+RyIZAYk0w5SZloC9HoNf8I4JLNMjMgmLSbZ7PtJ2fzslKzi9ch38RM7xNU2hN5hQLJnQaRzIBfmQeQOkHvMEtBJq4WXiuQokEshz82BVJKFzIx0nDyRCrH4MBIOJECiUIKUfAZRLIDc4kAqvoLUza0C+XkSSCVZyDmfgazMM0g/fQzJyUkQiQ4hJjYWpeW3kdvCQNpsRn7HFPI1dtzXjq4CmRnpSEk5guTkJIjFh5GYKEJ8fDx2RUdDIBDg+tWib10drYv1qtoGbVvjcZPJEKHTaSNqamo2kE5aLUxNPYq4/XHYG7MPkZGRCA8PR2hYKPghfATzg1GuuIb657Xo1qih76EXVbXVu1eu3UmrhYmJIgi2CcAP4SOICkJgYAD8A/zB4/HA4/FQcqXQ1fCy7pyWbkmtqlKG/fWuTlotjBUKVwp+fn7w9fWBj89GeHt7w8vLC0UX82we/92rbY7S6zoYo6GPYcyjzLRtwmG3WZzTNjMzbjIwBn03o++hmz0Cy+nubqX6u2ilvoe2GAZ7f/Ro25r6dR1n/1tc3aQ9ymYdnzCPDf8a6NMsDg/2/jQNDzSsGVjOm7S09Uql0net878BWaGbdwSdS90AAAAASUVORK5CYII=");
break;
case "global" :
this.icon.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACk0lEQVQ4jY2RW0hTcRzHfxQ99RodtIeoJx+SICGMgr0UQkEvJkEvhWa5ZV5AQ0bltFB0eQFLXUvXxVFE3qZOt+nWZm1jHnM7x8uuZ2dubpyV1WMPybeHadLDqu/z//Phz+dHlGUsazvA8zwjCAIjSQIjSRIjSRIjCAIj8DzDu92MSqXak42nvglPum44iroREbXDMdx+t47y1yKuvBBw8WkQNUNe2EyTx7IKlHpPukiXwjldCrJnKZzoTeJodwLUFgepYjjV6YNlaiw/q6BG50of7k7gUFcC1LENPoiB7omgughymxf/LpBrP6apKQZSxUCNIuhOBFQVBlUEQaV+UCObETgcMzks61Es+ZYUy8vLikAopIiIoqLpjWezeCCA831ryG3hQOUhkDwMuhUBVYmgdi4jMBsNsuLBCIp0KZwdTOGMJon8xxs42JkAta6DVCKK+1mQcgOkSoEeSqDWz6CB8K7gQn8Ap7VJFPYncfzJRiZWexzUHAMpo5APulA5xkE+6kX19CqqZ/x4ZFrYFZzsWgWp4xmodX03Vn0EVBHEjV7rpmV6fGtIp9WbJoYvs6wzz2Yz5Wk0mn1kNhpkOS086K4IUkZBNWGQPAS67geV+UFlQdQMODD0XIvZGQMcc8Ytnba38Hdts9Ego/tcBioPZkJVRkG1MVB9HNSQwM1XroT+5cA1k3HsUk+P+sgf5zIbDTJqWssADQlQ43aoti+gjq+g7u8oHfGuZL231TRaYLfbOPeCh/PxHLcS8ouBUCCxFg5wrM/LOd1O7r3NMppVsLPZ2XHGbjGqHXNGn3Pe+m3ONDFit01f/Se4+5PJghX+05J30fXTbpnacn2w/mBd8/r/FuzsbUnJXrVavf9/3/8CMPjCugYKVA0AAAAASUVORK5CYII=");
break;
default:
this.icon.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACvElEQVQ4jY3RW0iTARQH8EPRQyoGaX6KvRQ+CClBggoFori8lDHzRloYmqXLayYOr/MyRZcmmKIMNVJ7CEqdOt2mTmc40ZVun6bzMqdO5ZOMnuol+fcwTHpY+X8+/x+Hc4hsRKdTO7Msy5hMJobjTAzHcQzHcYzJZGJMLMuw09OMSCQ6ZatPnR3S/bpaMepqxXhRU4maqjKUiwpQkP8MOVkCVFeWQq0Y8LIJ1NeK97Mz05CVkYqnaSlISU7E/YRY8PkR4PGCkZz0AKrBXm+bgLiieD8hPgbx96IRF3sXfH4EwsJCEBgYiGs+PoiMvPNvoKQwf593kwceLxhBQUHw9fPDFS8veHh4wP2iOyJuh1sBjWbYTaebEczp5wQLCwsC4+qqYN1sFjTUSw6e52YjM0OAqCg+XN1c4cK4wPmCM5ycziM8PNQKKOWygKj2dYR07CG4fQ83Wnfh/WoHLvUWUPUWSGRGYtVbOJ5zhIODA+zt7WBndxahoSHHwK0WI65Ld+HfsourTTu43GAB1W6DyjdBBRtIbxpGaVE+CoW5EBULISoWorFBcgz4vvwCkmxbS9VboIpNULEZlLcOSl3B4+axA9VQ32FXh7Rb0f8+Tqeb8lSrFZ6tra1nSCmXBbhVsaAiM6hgA5S9BkpbBT1aBiUvg5JXkN2mQddrKUaGZdCMyg87pM3+f66tlMsCqMRgLaWsgNLWQOkboJxNUN42SGjBk06tpftN20OFvDe6sVFy6a93KeWyACpbshaEFlDpHqiSA9V8BdV9AzV8R9KH+UWb/x5T9PhMTKgN07MzBj1rMCyuLpuX14y7S2tGg04/b5ianjKMq1U9NoGjjIz0MRMquUQzKtdPfRz7MabsH5xQDyX+t3i8yYDPIvt5bv6T9tfk+PDhrFbzU6ed7D4xcJR3MTGnJRKJ/UnnfwPOTqHPv5QmxQAAAABJRU5ErkJggg==");
}
},
formattiptext: function(){
var tips = this.proxyConfigs[this.Prefs.default_proxy].name + " " + this.proxyConfigs[this.Prefs.default_proxy].host + ":" + this.proxyConfigs[this.Prefs.default_proxy].port;
return tips;
},
savePrefs: function() {
var svrstr = "";
for (let row=this.SVRROWS.firstChild.nextSibling; row; row=row.nextSibling) {
var setstr = "";
var aELM = row.firstChild;
if (aELM.value.trim() == "")
setstr = "未命名";
else
setstr = aELM.value.trim();
aELM = aELM.nextSibling;
if (aELM.value.trim() == "")
setstr = setstr + ";" + "127.0.0.1";
else if (IPREG.test(aELM.value.trim())) {
setstr = setstr + ";" + aELM.value.trim();
} else {
alert("你输入的是神马主机?");
return;
}
aELM = aELM.nextSibling;
if (aELM.value.trim() == "")
setstr = setstr + ";" + "80";
else if (PORTREG.test(aELM.value.trim())) {
setstr = setstr + ";" + aELM.value.trim();
} else {
alert("你输入的是神马端口号?");
return;
}
aELM = aELM.nextSibling;
setstr = setstr + ";" + aELM.value;
if (svrstr == "")
svrstr = setstr;
else
svrstr = svrstr+ "$" + setstr;
}
this._ps.setCharPref("knownProxy", svrstr);
this.showMsg("服务器配置保存成功!");
},
refreshPrefs: function() {
if (!this._ps.prefHasUserValue("knownProxy")) {
this._ps.setCharPref("knownProxy","Free Gate;;8580;$Puff;;1984;$ssh -D;;7070;socks$Toonel;;8080;$Tor;;9050;socks$Wu Jie;;9666;$Your Freedom;;8080;");
}
if (!this._ps.prefHasUserValue("default_proxy")) {
this._ps.setIntPref("default_proxy", 5);
}
if (!this._ps.prefHasUserValue("proxyMode")) {
this._ps.setCharPref("proxyMode", "auto");
}
if (!this._ps.prefHasUserValue("curVersion")) {
this._ps.setCharPref("curVersion", "0.4b2.2011041023");
}
if (!this._ps.prefHasUserValue("patternsfile")) {
this._ps.setCharPref("patternsfile", "SPpatterns.ini");
}
if (!this._ps.prefHasUserValue("url")) {
this._ps.setCharPref("url", "https://autoproxy-gfwlist.googlecode.com/svn/trunk/gfwlist.txt");
}
this.Prefs = {
default_proxy : this._ps.getIntPref("default_proxy"),
knownProxy : this._ps.getCharPref("knownProxy"),
proxyMode : this._ps.getCharPref("proxyMode"),
curVersion : this._ps.getCharPref("curVersion"),
patternsfile : this._ps.getCharPref("patternsfile"),
url : this._ps.getCharPref("url")
}
this._setproxyConfig();
},
_setproxyConfig: function(){
this.proxyConfigs = [];
this.proxyConfigs = this.Prefs.knownProxy.split("$").map(
function(str) {
var entry = str.split(";");
var SRV = {};
SRV.name = entry[0];
SRV.host = entry[1] == '' ? '127.0.0.1' : entry[1];
SRV.port = entry[2];
SRV.type = /^socks4?$/i.test(entry[3]) ? entry[3] : 'http';
return(SRV);
}
);
},
_createServerList: function(aid, aProxy) {
var proxyRow = document.createElement("row");
proxyRow.setAttribute("id", "PROXY_" + aid.toString());
var proxyName = document.createElement("textbox");
var proxyHost = document.createElement("textbox");
var proxyPort = document.createElement("textbox");
var proxyType = document.createElement("radiogroup");
var proxySel = document.createElement("checkbox");
proxySel.setAttribute("checked", (this.Prefs.default_proxy == aid) ? true : false);
proxySel.setAttribute("oncommand", "SmartProxy.setdefaultproxy(event);");
proxyName.setAttribute("class", "proxyName");
proxyHost.setAttribute("class", "proxyHost");
proxyPort.setAttribute("class", "proxyPort");
proxySel.setAttribute("class", "selBox");
proxyType.setAttribute("orient", "horizontal");
var http = document.createElement("radio");
var socks = document.createElement("radio");
var socks4 = document.createElement("radio");
http.setAttribute("class", "proxyHttp");
http.setAttribute("value", "http");
socks.setAttribute("class", "proxySocks5");
socks.setAttribute("value", "socks");
socks4.setAttribute("class", "proxySocks4");
socks4.setAttribute("value", "socks4");
http.setAttribute("selected", aProxy && aProxy.type == "http" );
socks.setAttribute("selected", aProxy && aProxy.type == "socks" );
socks4.setAttribute("selected", aProxy && aProxy.type == "socks4");
if (aProxy) {
proxyName.setAttribute("value", aProxy.name);
proxyHost.setAttribute("value", aProxy.host);
proxyPort.setAttribute("value", aProxy.port);
}
proxyType.appendChild(http);
proxyType.appendChild(socks4);
proxyType.appendChild(socks);
proxyRow.appendChild(proxyName);
proxyRow.appendChild(proxyHost);
proxyRow.appendChild(proxyPort);
proxyRow.appendChild(proxyType);
proxyRow.appendChild(proxySel);
this.SVRROWS.appendChild(proxyRow);
},
setdefaultproxy: function(evt) {
if (!evt.target.checked)
evt.target.setAttribute("checked", true);
else {
var evp = evt.target.parentNode;
var oevp;
for (var i=0; i < this.proxyConfigs.length; i++){
oevp = E("PROXY_" + i.toString());
if (oevp != evp) {
oevp.getElementsByTagName("checkbox")[0].setAttribute("checked", false);
}else {
this._ps.setIntPref("default_proxy", i);
E("POPUP_" + i.toString()).setAttribute("checked", true);
}
}
}
},
popdefaultproxy: function(evt) {
var evp = evt.target.id;
evp = evp.substring(6);
var oevp;
for (var i=0; i < this.proxyConfigs.length; i++){
oevp = E("PROXY_" + i.toString());
if (i.toString() != evp) {
oevp.getElementsByTagName("checkbox")[0].setAttribute("checked", false);
}else {
this._ps.setIntPref("default_proxy", i);
oevp.getElementsByTagName("checkbox")[0].setAttribute("checked", true);
}
}
},
setMode: function() {
this._ps.setCharPref("proxyMode", this.modebtn.value);
},
iconclick: function(evt) {
if (evt.target != this.icon) return;
if (evt.button == 1){
if (this.Prefs.proxyMode == this.mode[0]) {
this._ps.setCharPref("proxyMode", this.mode[1]);
return;
}else if (this.Prefs.proxyMode == this.mode[1]){
this._ps.setCharPref("proxyMode", this.mode[2]);
return;
}else if (this.Prefs.proxyMode == this.mode[2]) {
this._ps.setCharPref("proxyMode", this.mode[0]);
return;
}
}else if (evt.button == 2) {
evt.preventDefault();
var QW1 = E("sp-mains");
var QW2 = E("SP-splitter");
if (QW1.hidden) {
QW1.hidden = QW2.hidden = false;
this.Treevisible = true;
//SmartProxy.FilterView.updateData();
} else {
QW1.hidden = QW2.hidden = true;
this.Treevisible = false;
}
}
},
showMsg: function(Msg){
this.MsgBox.value = Msg;
},
closeslitterbar: function(){
var QW1 = E("sp-mains");
var QW2 = E("SP-splitter");
QW1.hidden = QW2.hidden = true;
this.Treevisible = false;
},
commandreport: function() {
var crurl= getFocusedWindow().content.document.location;
crurl = makeURI(crurl);
if (crurl.scheme != "http" && crurl.scheme != "https" && crurl.scheme != "ftp") return;
crurl = "https://gfwlist.autoproxy.org/report/?url=" + crurl.spec;
let protocolService = Cc["@mozilla.org/uriloader/external-protocol-service;1"].getService(Ci.nsIExternalProtocolService);
protocolService.loadURI(makeURI(crurl), null);
},
setpopupenabled: function(evt) {
var crurl= getFocusedWindow().content.document.location.href;
//Application.console.log(crurl);
var srurl = makeURI(crurl);
if ((srurl.scheme != "http" && srurl.scheme != "https" && srurl.scheme != "ftp") || this.Prefs.proxyMode == "disabled") {
this.siteProxyOn.setAttribute("hidden", true);
this.reportgfwlist.setAttribute("hidden", true);
return;
} else {
//var docDomain = getHostname(crurl);
var topDomain = getDomain(crurl);
var matchs = SPdefaultMatcher.matchesAny(crurl, topDomain);
if (matchs && matchs instanceof SPWhitelistFilter) {
this.siteProxyOn.setAttribute("hidden", true);
this.reportgfwlist.setAttribute("hidden", true);
return;
} else if (matchs && matchs instanceof SPBlockingFilter) {
this.siteProxyOn.setAttribute("value", true);
this.siteProxyOn.filter = matchs;
this.siteProxyOn.setAttribute("label", "禁用" + topDomain + "的代理规则");
return;
}
this.siteProxyOn.setAttribute("hidden", false);
this.siteProxyOn.setAttribute("value", "blocked");
this.siteProxyOn.newfilter = [crurl, topDomain];
this.siteProxyOn.setAttribute("label", "对" + topDomain + "使用代理");
this.reportgfwlist.setAttribute("hidden", false);
}
},
setUrlproxy: function(evt){
if (evt.button != 0) return;
if (evt.target.value != "blocked") {
if (evt.target.filter) {
for (let i = 0; i < this.SPfilters.length; i++) {
if (this.SPfilters[i] == evt.target.filter) {
this.SPfilters[i].disabled = evt.target.value;
SmartProxy.FilterView.updateFilter(this.SPfilters[i]);
if (this.SPfilters[i].disabled && this.SPfilters[i] instanceof SPRegExpFilter && SPdefaultMatcher.hasFilter(this.SPfilters[i]))
SPdefaultMatcher.remove(this.SPfilters[i]);
var afile = this._getSmartProxyfile("SPpatterns.json");
this._exportpatternsfile(afile);
break;
}
}
}
} else {
if (evt.target.value == "blocked" && evt.target.newfilter && evt.target.newfilter.length == 2) {
var val = [];
val = evt.target.newfilter;
var ishave = false;
for (let i = 0; i < this.SPfilters.length; i++) {
if (this.SPfilters[i].matches(val[0], val[1])) {
if (this.SPfilters[i] instanceof SPWhitelistFilter) {
ishave = true;
break;
}else if (this.SPfilters[i].disabled) {
this.SPfilters[i].disabled = false;
SmartProxy.FilterView.updateFilter(this.SPfilters[i]);
if (this.SPfilters[i] instanceof SPRegExpFilter && !SPdefaultMatcher.hasFilter(this.SPfilters[i]))
SPdefaultMatcher.add(this.SPfilters[i]);
ishave = true;
SmartProxy.FilterView.updateData();
var afile = this._getSmartProxyfile("SPpatterns.json");
this._exportpatternsfile(afile);
break;
}
}
}
if (!ishave) {
let filter = SPFilter.fromText(SPFilter.normalize(val[1]));
if (filter && filter instanceof SPRegExpFilter) {
this.SPfilters.push(filter);
var position = SmartProxy.FilterView.data.length;
SmartProxy.FilterView.addFilterAt(position++, filter);
if (!SPdefaultMatcher.hasFilter(filter))
SPdefaultMatcher.add(filter);
var afile = this._getSmartProxyfile("SPpatterns.json");
this._exportpatternsfile(afile);
}
}
}
}
},
loadGFWurl: function() {
window.openNewTabWith("https://autoproxy.org/zh-CN/Subscriptions", null, null, null, false);
},
_getSmartProxyfile : function(afile) {
var profileDir = dirService.get("UChrm", Ci.nsIFile);
var filedir = profileDir.clone().QueryInterface(Ci.nsILocalFile);
filedir.appendRelativePath("UCProfileDir");
filedir.appendRelativePath("SmartProxy");
if(!filedir.exists()) {
filedir.create(Ci.nsIFile.DIRECTORY_TYPE, 0700);
}
filedir.appendRelativePath(afile);
return filedir;
},
stringToFile : function(str, file) {
var stream = new FileOutputStream(file, 0x02 | 0x08 | 0x10 | 0x20, -1, 0);
var cos = new ConverterOutputStream(stream, "UTF-8", 16384, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
cos.writeString(str);
cos.close();
stream.close();
},
_exportpatternsfile : function(file) {
const PR_WRONLY = 0x02;
const PR_CREATE_FILE = 0x08;
const PR_TRUNCATE = 0x20;
var rjson = { createdBy : 'SmartProxy', createdAt : new Date(), SPfilters : [], DisbledFilter : [] };
for (var i = 0; i < this.SPfilters.length; i++) {
rjson.SPfilters.push(this.SPfilters[i].text);
if (this.SPfilters[i].disabled)
rjson.DisbledFilter.push(this.SPfilters[i].text);
}
var fileStream = new FileOutputStream(file, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0644, 0);
var stream = new ConverterOutputStream(fileStream, "UTF-8", 16384, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
stream.writeString(JSON.stringify(rjson, null, 4));
stream.close();
},
_importpatternsfile : function(file) {
var fileStream = new FileInputStream(file, 0x01, 0444, 0);
var stream = new ConverterInputStream(fileStream, "UTF-8", 16384, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
var str = {};
var rjson = '';
while (stream.readString(0xffffffff, str) != 0) {
rjson += str.value;
}
stream.close();
rjson = JSON.parse(rjson);
this._FilterIsReady = false;
this.SPfilters = [];
SPdefaultMatcher.clear();
for (var i = 0; i < rjson.SPfilters.length; i++) {
let filter = SPFilter.fromText(SPFilter.normalize(rjson.SPfilters[i]));
if (filter && filter instanceof SPRegExpFilter && !SPdefaultMatcher.hasFilter(filter)) {
SPdefaultMatcher.add(filter);
this.SPfilters.push(filter);
}
}
for (var i = 0; i < rjson.DisbledFilter.length; i++) {
let filter = SPFilter.fromObject(SPFilter.normalize(rjson.DisbledFilter[i]));
continue;
}
this._FilterIsReady = true;
this.showMsg("共:" + this.SPfilters.length +"个规则!");
},
_importSUBpatternsfile : function(file) {
var fileStream = new FileInputStream(file, 0x01, 0444, 0);
var stream = new ConverterInputStream(fileStream, "UTF-8", 16384, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
stream = stream.QueryInterface(Ci.nsIUnicharLineInputStream);
var line = {};
this._FilterIsReady = false;
var val = "";
var cont;
var newcow = 0;
do {
cont = stream.readLine(line);
val = line.value;
val = val.trim();
if (val != "" && val[0] != "[" && val[0] != "!") {
let filter = SPFilter.fromText(SPFilter.normalize(val));
if (filter && filter instanceof SPRegExpFilter && !SPdefaultMatcher.hasFilter(filter)) {
SPdefaultMatcher.add(filter);
this.SPfilters.push(filter);
if (this.Treevisible) {
var position = SmartProxy.FilterView.data.length;
SmartProxy.FilterView.addFilterAt(position++, filter);
}
newcow = newcow + 1;
}
}
} while (cont);
stream.close();
this._FilterIsReady = true;
this.showMsg("共新增了:" + newcow.toString() +"个规则!");
return newcow;
},
updatesubUrl: function(){
var nUrl = window.prompt('设置新的下载地址:',this.Prefs.url);
if(!nUrl) return;
nUrl = nUrl.trim();
var anew = makeURI(nUrl);
if (anew && (anew.scheme == "http" || anew.scheme == "https")) {
this._ps.setCharPref("url", nUrl);
this.Prefs.url = nUrl;
} else
alert("非法的地址!");
},
updatesubFilter: function(){
function errorCallback(result) {
SmartProxy.showMsg(result);
if (result == SUBSCRIPTION_UPDATE_SUCCESS) {
SmartProxy.showMsg("订阅规则更新成功!");
SmartProxy.addsubFilter();
}
}
SmartProxy.showMsg("请等待,正在更新...");
let url = this.Prefs.url;
var request = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Components.interfaces.nsIXMLHttpRequest);
let me = this;
request.onerror = function (event) {
setTimeout(function () { errorCallback(request.statusText); }, 0);
var error = request.statusText;
return error;
};
request.onload = function (event) {
try {
self._rawData = request.responseText;
if (!self._rawData) {
var error = '返回了一个空文件!';
setTimeout(function () { errorCallback(error); }, 0);
return;
}
self._rawData = self._rawData.replace(/[\r\n]/g, '');
self._rawData = windowMediator.getMostRecentWindow("").atob(self._rawData);
SmartProxy.stringToFile(self._rawData, SmartProxy.SPfile);
setTimeout(function () {
errorCallback(SUBSCRIPTION_UPDATE_SUCCESS);
}, 0);
} catch (e) {
setTimeout(function () { errorCallback(e.toString()); }, 0);
}
};
request.open("GET", url);
request.send(null);
},
addsubFilter: function() {
if (this.SPfile.exists()) {
var newrec = this._importSUBpatternsfile(this.SPfile);
if (!SmartProxy.Proxy.isRegisted)
SmartProxy.Proxy.init();
if (newrec > 0)
SmartProxy.saveAllFilter();
} else {
this.showMsg("没有找到订阅规则文件!");
}
},
saveAllFilter: function() {
var afile = this._getSmartProxyfile("SPpatterns.json");
this._exportpatternsfile(afile);
this.showMsg("规则文件保存成功!");
},
EID: function(id){
return document.getElementById(id);
},
};
SmartProxy.Proxy = {
proxyserver: null,
defaultProxy: null,
proxyConfigs: [],
DirectProxy: null,
isRegisted: false,
init: function() {
if (!SmartProxy._FilterIsReady) return;
SmartProxy.Proxy.proxyserver = [];
SmartProxy.Proxy.DirectProxy = null;
SmartProxy.Proxy.defaultProxy = null;
for (let aproxy of SmartProxy.proxyConfigs) {
SmartProxy.Proxy.proxyserver.push(ProxySrv.newProxyInfo(aproxy.type, aproxy.host, aproxy.port, 1, 0, null));
}
SmartProxy.Proxy.DirectProxy = ProxySrv.newProxyInfo('direct', '', -1, 0, 0, null);
SmartProxy.Proxy.defaultProxy = SmartProxy.Proxy.proxyserver[SmartProxy.Prefs.default_proxy];
if (!SmartProxy.Proxy.defaultProxy) {
SmartProxy.showMsg("无效的默认代理!");
return;
}
ProxySrv.registerFilter(SmartProxy.Proxy, 0);
SmartProxy.Proxy.isRegisted = true;
},
uninit: function() {
ProxySrv.unregisterFilter(SmartProxy.Proxy);
SmartProxy.Proxy.isRegisted = false;
},
setdefaultProxy: function() {
SmartProxy.Proxy.defaultProxy = SmartProxy.Proxy.proxyserver[SmartProxy.Prefs.default_proxy];
},
applyFilter: function(ProxySrv, uri, aProxy) {
if (SmartProxy.Prefs.proxyMode == 'disabled' || uri.schemeIs('feed'))
return SmartProxy.Proxy.DirectProxy;
if (SmartProxy.Prefs.proxyMode == 'global') {
return SmartProxy.Proxy.defaultProxy;
}
if (SmartProxy.Prefs.proxyMode == 'auto')
SmartProxy.updateicon(SmartProxy.Prefs.proxyMode);
var splttag = uri.spec.indexOf("?");
if (splttag > 20)
var match = SPdefaultMatcher.matchesAny(uri.spec.substring(0, splttag), uri.host);
else {
splttag = uri.spec.indexOf("=");
if (splttag > 20)
var match = SPdefaultMatcher.matchesAny(uri.spec.substring(0, splttag), uri.host);
else
var match = SPdefaultMatcher.matchesAny(uri.spec, uri.host);
}
if (match) {
if (SmartProxy.Proxy.CanNotProxy(match))
return SmartProxy.Proxy.DirectProxy;
else {
if (SmartProxy.Prefs.proxyMode == 'auto')
SmartProxy.updateicon("auto-on");
return SmartProxy.Proxy.defaultProxy;
}
}else{
if (SmartProxy.Prefs.proxyMode == 'auto')
return SmartProxy.Proxy.DirectProxy;
else
return SmartProxy.Proxy.defaultProxy;
}
},
CanNotProxy: function(amatch) {
if (amatch.disabled)
return true;
else if (amatch instanceof SPWhitelistFilter)
return true;
else
return false;
},
};
SmartProxy.FilterActions = {
init: function() {
let me = this;
this.treeElement.parentNode.addEventListener("keypress", function(event) {
me.keyPress(event);
}, true);
SmartProxy.FilterView.filters = SmartProxy.SPfilters;
this.treeElement.view = SmartProxy.FilterView;
this.treeElement.inputField.addEventListener("keypress", function(event) {
if (event.keyCode >= event.DOM_VK_PAGE_UP && event.keyCode <= event.DOM_VK_DOWN)
event.stopPropagation();
}, false);
},
get treeElement() E("SPfiltersTree"),
get visible() {
return !this.treeElement.parentNode.collapsed;
},
get focused() {
let focused = document.commandDispatcher.focusedElement;
while (focused)
{
if ("treeBoxObject" in focused && focused.treeBoxObject == SmartProxy.FilterView.boxObject)
return true;
focused = focused.parentNode;
}
return false;
},
setSortOrder: function(sortOrder) {
let col = (SmartProxy.FilterView.sortColumn ? SmartProxy.FilterView.sortColumn.id : "col-filter");
SmartProxy.FilterView.sortBy(col, sortOrder);
},
selectionToggleDisabled: function() {
if (this.treeElement.editingColumn)
return;
let items = SmartProxy.FilterView.selectedItems.filter(function(i) i.filter instanceof SPActiveFilter);
if (items.length) {
SmartProxy.FilterView.boxObject.beginUpdateBatch();
let newValue = !items[0].filter.disabled;
for (let i = 0; i < items.length; i++) {
items[i].filter.disabled = newValue;
SmartProxy.FilterView.updateFilter(items[i].filter);
if (newValue) {
if (items[i].filter instanceof SPRegExpFilter && SPdefaultMatcher.hasFilter(items[i].filter))
SPdefaultMatcher.remove(items[i].filter);
} else {
if (items[i].filter instanceof SPRegExpFilter && !SPdefaultMatcher.hasFilter(items[i].filter))
SPdefaultMatcher.add(items[i].filter);
}
}
SmartProxy.FilterView.boxObject.endUpdateBatch();
}
},
startEditing: function() {
if (this.treeElement.editingColumn)
return;
this.treeElement.startEditing(SmartProxy.FilterView.selection.currentIndex, SmartProxy.FilterView.boxObject.columns.getNamedColumn("col-filter"));
},
insertFilter: function() {
if (!SmartProxy.FilterView.editable || this.treeElement.editingColumn)
return;
SmartProxy.FilterView.insertEditDummy();
this.startEditing();
let tree = this.treeElement;
let listener = function(event) {
if (event.attrName == "editing" && tree.editingRow < 0) {
tree.removeEventListener("DOMAttrModified", listener, false);
SmartProxy.FilterView.removeEditDummy();
}
}
tree.addEventListener("DOMAttrModified", listener, false);
},
deleteItems: function(/**Array*/ items) {
let oldIndex = SmartProxy.FilterView.selection.currentIndex;
items.sort(function(entry1, entry2) entry2.index - entry1.index);
for (let i = 0; i < items.length; i++) {
if (SmartProxy.FilterView.filters[items[i].index] == items[i].filter) {
SmartProxy.FilterView.filters.splice(items[i].index, 1);
SmartProxy.FilterView.removeFilterAt(items[i].index);
if (items[i].filter instanceof SPRegExpFilter && SPdefaultMatcher.hasFilter(items[i].filter))
SPdefaultMatcher.remove(items[i].filter);
}
}
SmartProxy.FilterView.selectRow(oldIndex);
},
deleteSelected: function() {
if (!SmartProxy.FilterView.editable || this.treeElement.editingColumn)
return;
let items = SmartProxy.FilterView.selectedItems;
if (items.length == 0 || (items.length >= 2 && !promptService.confirm(window, "确认删除吗?", "SmartProxy")))
return;
this.deleteItems(items)
},
keyPress: function(/**Event*/ event) {
if (event.target != E("SPfiltersTree"))
return;
let modifiers = 0;
if (event.charCode == " ".charCodeAt(0) && modifiers == 0 && !E("col-enabled").hidden)
this.selectionToggleDisabled();
},
fillActionsPopup: function() {
let editable = SmartProxy.FilterView.editable;
let items = SmartProxy.FilterView.selectedItems.filter(function(i) !i.filter.dummy);
items.sort(function(entry1, entry2) entry1.index - entry2.index);
E("SPfilters-edit-command").setAttribute("disabled", !editable || !items.length);
E("SPfilters-delete-command").setAttribute("disabled", !editable || !items.length);
E("SPfilters-copy-command").setAttribute("disabled", !items.length);
E("SPfilters-Unicode-command").setAttribute("disabled", !editable || !items.length);
let canopentag = false;
if (items.length == 1) {
let atext = items[0].filter.text;
if (editable && (atext.indexOf("%") == -1 || (atext.indexOf("%") != -1 && atext.indexOf("zh.wikipedia.org") == 0)) &&
(atext.indexOf("*") == -1 || (atext.indexOf("*") != -1 && atext.indexOf("zh.wikipedia.org") == 0)) &&
(atext.indexOf("^") == -1) && (atext.indexOf("[") == -1) && (atext.indexOf("\\") == -1) && (atext.substring(0,1) != "/"))
canopentag = true;
}
E("SPfilters-Opentab-command").setAttribute("disabled", !canopentag);
},
copySelected: function(/**Boolean*/ keep) {
let items = SmartProxy.FilterView.selectedItems;
if (!items.length)
return;
items.sort(function(entry1, entry2) entry1.index - entry2.index);
let text = items.map(function(i) i.filter.text).join("\n");
clipboardHelper.copyString(text);
if (!keep && SmartProxy.FilterView.editable && !this.treeElement.editingColumn)
this.deleteItems(items);
},
ConvertUnicode: function() {
let items = SmartProxy.FilterView.selectedItems;
if (!items.length)
return;
items.sort(function(entry1, entry2) entry1.index - entry2.index);
let text = items.map(function(i) i.filter.text).join("\n");
clipboardHelper.copyString(text);
alert("已复制到剪切板: \n" + convertpEnc2Char(text));
},
Openfilterintab: function() {
let items = SmartProxy.FilterView.selectedItems;
if (!items.length || items.length != 1)
return;
let atext = items[0].filter.text;
if ((atext.indexOf("%") != -1 && atext.indexOf("zh.wikipedia.org") != 0) || (atext.indexOf("*") != -1 && atext.indexOf("zh.wikipedia.org") != 0) ||
(atext.indexOf("^") != -1) || (atext.indexOf("[") != -1) ||
(atext.indexOf("\\") != -1) || (atext.substring(0,1) == "/"))
return;
atext = atext.replace(/@|\|/gi, "");
if (atext.substring(0,1) == ".")
atext = "http://www" + atext;
else if (atext.substring(0,1) == "/")
return;
else if (atext.indexOf("zh.wikipedia.org") == 0) {
atext = atext.replace("*", "/wiki/");
atext = "https://" + atext;
} else if (atext.substring(0,4) == "www.")
atext = "http://" + atext;
else if (atext.substring(0,4) == "http")
atext = "" + atext;
else
atext = "http://www." + atext;
window.openNewTabWith(atext, window.gBrowser.contentDocument, null, null, false);
}
};
SmartProxy.FilterView = {
init: function() {
if (this.sortProcs)
return;
function compareText(/**Filter*/ filter1, /**Filter*/ filter2) {
if (filter1.text < filter2.text)
return -1;
else if (filter1.text > filter2.text)
return 1;
else
return 0;
}
function compareSlow(/**Filter*/ filter1, /**Filter*/ filter2) {
let isSlow1 = filter1 instanceof SPRegExpFilter && SPdefaultMatcher.isSlowFilter(filter1);
let isSlow2 = filter2 instanceof SPRegExpFilter && SPdefaultMatcher.isSlowFilter(filter2);
return isSlow1 - isSlow2;
}
function compareEnabled(/**Filter*/ filter1, /**Filter*/ filter2) {
let hasEnabled1 = (filter1 instanceof SPActiveFilter ? 1 : 0);
let hasEnabled2 = (filter2 instanceof SPActiveFilter ? 1 : 0);
if (hasEnabled1 != hasEnabled2)
return hasEnabled1 - hasEnabled2;
else if (hasEnabled1)
return (filter2.disabled - filter1.disabled);
else
return 0;
}
function createSortFunction(cmpFunc, fallbackFunc, desc) {
let factor = (desc ? -1 : 1);
return function(entry1, entry2) {
let isLast1 = ("origFilter" in entry1 && entry1.filter == null);
let isLast2 = ("origFilter" in entry2 && entry2.filter == null);
if (isLast1)
return (isLast2 ? 0 : 1)
else if (isLast2)
return -1;
let ret = cmpFunc(entry1.filter, entry2.filter);
if (ret == 0 && fallbackFunc)
return fallbackFunc(entry1.filter, entry2.filter);
else
return factor * ret;
}
}
this.sortProcs = {
filter: createSortFunction(compareText, null, false),
filterDesc: createSortFunction(compareText, null, true),
slow: createSortFunction(compareSlow, compareText, true),
slowDesc: createSortFunction(compareSlow, compareText, false),
enabled: createSortFunction(compareEnabled, compareText, false),
enabledDesc: createSortFunction(compareEnabled, compareText, true)
};
},
boxObject: null,
atoms: null,
noFiltersDummy: null,
editDummy: null,
data: [],
get treeElement() this.boxObject ? this.boxObject.treeBody.parentNode : null,
get isEmpty() {
return !this.filters.length;
},
get editable() {
return true;
},
get currentItem() {
let index = this.selection.currentIndex;
if (index >= 0 && index < this.data.length)
return this.data[index];
return null;
},
get selectedItems() {
let items = []
for (let i = 0; i < this.selection.getRangeCount(); i++)
{
let min = {};
let max = {};
this.selection.getRangeAt(i, min, max);
for (let j = min.value; j <= max.value; j++)
if (j >= 0 && j < this.data.length)
items.push(this.data[j]);
}
return items;
},
getItemAt: function(x, y) {
let row = this.boxObject.getRowAt(x, y);
if (row >= 0 && row < this.data.length)
return this.data[row];
else
return null;
},
_filters: 0,
get filters() this._filters,
set filters(value) {
if (value == this._filters)
return;
if (this.treeElement)
this.treeElement.stopEditing(true);
this._filters = value;
this.refresh(true);
},
_dirty: false,
refresh: function(force) {
if (SmartProxy.Treevisible) {
if (!force && !this._dirty)
return;
this._dirty = false;
this.updateData();
this.selectRow(0);
}
else
this._dirty = true;
},
sortProcs: null,
sortColumn: null,
sortProc: null,
sortBy: function(col, direction) {
let newSortColumn = null;
if (col) {
newSortColumn = this.boxObject.columns.getNamedColumn(col).element;
if (!direction) {
if (this.sortColumn == newSortColumn)
direction = (newSortColumn.getAttribute("sortDirection") == "ascending" ? "descending" : "ascending");
else
direction = "ascending";
}
}
if (this.sortColumn && this.sortColumn != newSortColumn)
this.sortColumn.removeAttribute("sortDirection");
this.sortColumn = newSortColumn;
if (this.sortColumn) {
this.sortColumn.setAttribute("sortDirection", direction);
this.sortProc = this.sortProcs[col.replace(/^col-/, "") + (direction == "descending" ? "Desc" : "")];
} else
this.sortProc = null;
if (this.data.length > 1) {
this.updateData();
this.boxObject.invalidate();
}
},
addDummyRow: function() {
if (this.boxObject && this.data.length == 0)
{
//if (this._subscription)
this.data.splice(0, 0, this.noFiltersDummy);
this.boxObject.rowCountChanged(0, 1);
}
},
removeDummyRow: function() {
if (this.boxObject && this.isEmpty && this.data.length)
{
this.data.splice(0, 1);
this.boxObject.rowCountChanged(0, -1);
}
},
insertEditDummy: function() {
SmartProxy.FilterView.removeDummyRow();
let position = this.selection.currentIndex;
if (position >= this.data.length)
position = this.data.length - 1;
if (position < 0)
position = 0;
this.editDummy.index = (position < this.data.length ? this.data[position].index : this.data.length);
this.editDummy.position = position;
this.data.splice(position, 0, this.editDummy);
this.boxObject.rowCountChanged(position, 1);
this.selectRow(position);
},
removeEditDummy: function() {
let position = this.editDummy.position;
if (typeof position != "undefined" && position < this.data.length && this.data[position] == this.editDummy)
{
this.data.splice(position, 1);
this.boxObject.rowCountChanged(position, -1);
SmartProxy.FilterView.addDummyRow();
this.selectRow(position);
}
},
selectRow: function(row) {
if (this.selection)
{
row = Math.min(Math.max(row, 0), this.data.length - 1);
this.selection.select(row);
this.boxObject.ensureRowIsVisible(row);
}
},
selectFilter: function(/**Filter*/ filter) {
let index = -1;
for (let i = 0; i < this.data.length; i++)
{
if (this.data[i].filter == filter)
{
index = i;
break;
}
}
if (index >= 0)
{
SmartProxy.FilterView.selectRow(index);
SmartProxy.FilterView.treeElement.focus();
}
},
updateData: function() {
let oldCount = this.rowCount;
if (this.filters && this.filters.length) {
this.data = this.filters.map(function(f, i) ({index: i, filter: f}));
if (this.sortProc) {
let followingFilter = null;
for (let i = this.data.length - 1; i >= 0; i--) {
followingFilter = this.data[i].filter;
}
this.data.sort(this.sortProc);
for (let i = 0; i < this.data.length; i++) {
if ("origFilter" in this.data[i]) {
this.data[i].filter = this.data[i].origFilter;
delete this.data[i].origFilter;
}
}
}
}
else
this.data = [];
if (this.boxObject) {
this.boxObject.rowCountChanged(0, -oldCount);
this.boxObject.rowCountChanged(0, this.rowCount);
}
this.addDummyRow();
},
updateFilter: function(/**Filter*/ filter) {
for (let i = 0; i < this.data.length; i++)
if (this.data[i].filter == filter) {
if (SmartProxy.Treevisible)
this.boxObject.invalidateRow(i);
}
},
addFilterAt: function(/**Integer*/ position, /**Filter*/ filter) {
if (this.data.length == 1 && this.data[0].filter.dummy) {
this.data.splice(0, 1);
this.boxObject.rowCountChanged(0, -1);
}
if (this.sortProc) {
this.updateData();
for (let i = 0; i < this.data.length; i++) {
if (this.data[i].index == position) {
position = i;
break;
}
}
} else {
for (let i = 0; i < this.data.length; i++)
if (this.data[i].index >= position)
this.data[i].index++;
this.data.splice(position, 0, {index: position, filter: filter});
}
if (SmartProxy.Treevisible)
this.boxObject.rowCountChanged(position, 1);
this.selectRow(position);
},
removeFilterAt: function(/**Integer*/ position) {
for (let i = 0; i < this.data.length; i++) {
if (this.data[i].index == position) {
this.data.splice(i, 1);
this.boxObject.rowCountChanged(i, -1);
i--;
}
else if (this.data[i].index > position)
this.data[i].index--;
}
this.addDummyRow();
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsITreeView]),
setTree: function(boxObject) {
this.init();
this.boxObject = boxObject;
if (this.boxObject) {
this.noFiltersDummy = {index: 0, filter: {text: this.boxObject.treeBody.getAttribute("noFiltersText"), dummy: true}};
this.editDummy = {filter: {text: ""}};
let atomService = Cc["@mozilla.org/atom-service;1"].getService(Ci.nsIAtomService);
let stringAtoms = ["col-filter", "col-enabled", "type-filterlist", "type-whitelist"];
let boolAtoms = ["selected", "dummy", "slow", "disabled"];
this.atoms = {};
for (let atom of stringAtoms)
this.atoms[atom] = atomService.getAtom(atom);
for (let atom of boolAtoms) {
this.atoms[atom + "-true"] = atomService.getAtom(atom + "-true");
this.atoms[atom + "-false"] = atomService.getAtom(atom + "-false");
}
let columns = this.boxObject.columns;
for (let i = 0; i < columns.length; i++)
if (columns[i].element.hasAttribute("sortDirection"))
this.sortBy(columns[i].id, columns[i].element.getAttribute("sortDirection"));
this.refresh(true);
}
},
selection: null,
get rowCount() this.data.length,
getCellText: function(row, col) {
if (row < 0 || row >= this.data.length)
return null;
col = col.id;
if (col != "col-filter" && col != "col-slow")
return null;
let filter = this.data[row].filter;
if (col == "col-filter")
return filter.text;
else if (col == "col-slow")
return (filter instanceof SPRegExpFilter && SPdefaultMatcher.isSlowFilter(filter) ? "!" : null);
return null;
},
generateProperties: function(list, properties) {
if (properties)
{
// Gecko 21 and below: we have an nsISupportsArray parameter, add atoms
// to that.
for (let i = 0; i < list.length; i++)
if (list[i] in this.atoms)
properties.AppendElement(this.atoms[list[i]]);
return null;
}
else
{
// Gecko 22+: no parameter, just return a string
return list.join(" ");
}
},
getColumnProperties: function(col, properties) {
return this.generateProperties(["col-" + col.id], properties);
},
getRowProperties: function(row, properties) {
if (row < 0 || row >= this.data.length)
return "";
let list = [];
let filter = this.data[row].filter;
list.push("selected-" + this.selection.isSelected(row));
list.push("slow-" + (filter instanceof SPRegExpFilter && SPdefaultMatcher.isSlowFilter(filter)));
if (filter instanceof SPActiveFilter)
list.push("disabled-" + filter.disabled);
list.push("dummy-" + ("dummy" in filter));
if (filter instanceof SPBlockingFilter)
list.push("type-filterlist");
else if (filter instanceof SPWhitelistFilter)
list.push("type-whitelist");
return this.generateProperties(list, properties);
},
getCellProperties: function(row, col, properties) {
return this.getRowProperties(row, properties) + " " + this.getColumnProperties(col, properties);
},
cycleHeader: function(col) {
let oldDirection = col.element.getAttribute("sortDirection");
if (oldDirection == "ascending")
this.sortBy(col.id, "descending");
else if (oldDirection == "descending")
this.sortBy(null, null);
else
this.sortBy(col.id, "ascending");
},
isSorted: function() {
return (this.sortProc != null);
},
isEditable: function(row, col) {
if (row < 0 || row >= this.data.length)
return false;
let filter = this.data[row].filter;
if (col.id == "col-filter")
return !("dummy" in filter);
else
return false;
},
setCellText: function(row, col, value) {
if (row < 0 || row >= this.data.length || col.id != "col-filter")
return;
let oldFilter = this.data[row].filter;
let position = this.data[row].index;
value = SPFilter.normalize(value);
if (!value || value == oldFilter.text)
return;
this.treeElement.stopEditing();
let newFilter = SPFilter.fromText(value);
if (this.data[row] == this.editDummy)
this.removeEditDummy();
else {
if (this.filters[position] == oldFilter) {
this.filters.splice(position, 1);
if (oldFilter instanceof SPRegExpFilter && SPdefaultMatcher.hasFilter(oldFilter))
SPdefaultMatcher.remove(oldFilter);
}
}
this.filters.splice(position, 0, newFilter);
if (newFilter instanceof SPRegExpFilter && !SPdefaultMatcher.hasFilter(newFilter))
SPdefaultMatcher.add(newFilter);
},
cycleCell: function(row, col) {
if (row < 0 || row >= this.data.length || col.id != "col-enabled")
return;
let filter = this.data[row].filter;
if (filter instanceof SPActiveFilter)
filter.disabled = !filter.disabled;
},
isContainer: function(row) false,
isContainerOpen: function(row) false,
isContainerEmpty: function(row) true,
getLevel: function(row) 0,
getParentIndex: function(row) -1,
hasNextSibling: function(row, afterRow) false,
toggleOpenState: function(row) {},
getProgressMode: function() null,
getImageSrc: function() null,
isSeparator: function() false,
performAction: function() {},
performActionOnRow: function() {},
performActionOnCell: function() {},
getCellValue: function() null,
setCellValue: function() {},
selectionChanged: function() {},
};
SmartProxy.FilterSearch = {
init: function() {
let findbar = E("findbar");
findbar.browser = SmartProxy.FilterSearch.fakeBrowser;
findbar.addEventListener("keypress", function(event){
if (event.keyCode == KeyEvent.DOM_VK_RETURN)
event.preventDefault();
}, false);
findbar.toggleHighlight = function() {};
},
search: function(text, direction, caseSensitive) {
function normalizeString(string) caseSensitive ? string : string.toLowerCase();
function findText(text, direction, startIndex) {
let list = E("SPfiltersTree");
let col = list.columns.getNamedColumn("col-filter");
let count = list.view.rowCount;
for (let i = startIndex + direction; i >= 0 && i < count; i += (direction || 1)) {
let filter = normalizeString(list.view.getCellText(i, col));
if (filter.indexOf(text) >= 0) {
SmartProxy.FilterView.selectRow(i);
return true;
}
}
return false;
}
text = normalizeString(text);
if (findText(text, direction, E("SPfiltersTree").currentIndex))
return Ci.nsITypeAheadFind.FIND_FOUND;
return Ci.nsITypeAheadFind.FIND_NOTFOUND;
}
};
SmartProxy.FilterSearch.fakeBrowser = {
finder: {
_resultListeners: [],
searchString: null,
caseSensitive: false,
lastResult: null,
_notifyResultListeners: function(result, findBackwards) {
this.lastResult = result;
for each (let listener in this._resultListeners)
listener.onFindResult(result, findBackwards);
},
fastFind: function(searchString, linksOnly, drawOutline) {
this.searchString = searchString;
let result = SmartProxy.FilterSearch.search(this.searchString, 0,
this.caseSensitive);
this._notifyResultListeners(result, false);
},
findAgain: function(findBackwards, linksOnly, drawOutline) {
let result = SmartProxy.FilterSearch.search(this.searchString,
findBackwards ? -1 : 1,
this.caseSensitive);
this._notifyResultListeners(result, findBackwards);
},
addResultListener: function(listener) {
if (this._resultListeners.indexOf(listener) === -1)
this._resultListeners.push(listener);
},
removeResultListener: function(listener) {
let index = this._resultListeners.indexOf(listener);
if (index !== -1)
this._resultListeners.splice(index, 1);
},
// Irrelevant for us
highlight: function(highlight, word) {},
enableSelection: function() {},
removeSelection: function() {},
focusContent: function() {},
keyPress: function() {}
},
get _lastSearchString() {
return this.finder.searchString;
},
fastFind: {
get searchString() {
return SmartProxy.FilterSearch.fakeBrowser.finder.searchString;
},
set searchString(searchString) {
SmartProxy.FilterSearch.fakeBrowser.finder.searchString = searchString;
},
foundLink: null,
foundEditable: null,
get caseSensitive() {
return SmartProxy.FilterSearch.fakeBrowser.finder.caseSensitive;
},
set caseSensitive(caseSensitive) {
SmartProxy.FilterSearch.fakeBrowser.finder.caseSensitive = caseSensitive;
},
get currentWindow() SmartProxy.FilterSearch.fakeBrowser.contentWindow,
find: function(searchString, linksOnly) {
SmartProxy.FilterSearch.fakeBrowser.finder.fastFind(searchString, linksOnly);
return SmartProxy.FilterSearch.fakeBrowser.finder.lastResult;
},
findAgain: function(findBackwards, linksOnly) {
SmartProxy.FilterSearch.fakeBrowser.finder.findAgain(findBackwards, linksOnly);
return SmartProxy.FilterSearch.fakeBrowser.finder.lastResult;
},
init: function() {},
setDocShell: function() {},
setSelectionModeAndRepaint: function() {},
collapseSelection: function() {}
},
currentURI: makeURI("http://example.com/"),
contentWindow: {
focus: function() {
E("SPfiltersTree").focus();
},
scrollByLines: function(num) {
E("SPfiltersTree").boxObject.scrollByLines(num);
},
scrollByPages: function(num) {
E("SPfiltersTree").boxObject.scrollByPages(num);
},
},
addEventListener: function(event, handler, capture) {
E("SPfiltersTree").addEventListener(event, handler, capture);
},
removeEventListener: function(event, handler, capture) {
E("SPfiltersTree").addEventListener(event, handler, capture);
},
};
function SPFilter(text) {
this.text = text;
}
SPFilter.prototype = {
text: null,
serialize: function(buffer) {
buffer.push("[Filter]");
buffer.push("text=" + this.text);
},
toString: function() {
return this.text;
}
};
SPFilter.knownFilters = {__proto__: null};
SPFilter.regexpRegExp = /^(@@)?\/.*\/(?:\$~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[^,\s]+)?)*)?$/;
SPFilter.optionsRegExp = /\$(~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[^,\s]+)?)*)$/;
SPFilter.fromText = function(text) {
if (text in SPFilter.knownFilters)
return SPFilter.knownFilters[text];
let ret;
if (text[0] == "!")
ret = null;
else
ret = SPRegExpFilter.fromText(text);
SPFilter.knownFilters[ret.text] = ret;
return ret;
}
SPFilter.fromObject = function(text) {
let ret = SPFilter.fromText(text);
if (ret instanceof SPActiveFilter)
{
ret._disabled = true;
}
return ret;
}
SPFilter.normalize = function(text) {
if (!text)
return text;
text = text.replace(/[^\S ]/g, "");
if (/^\s*!/.test(text)) {
return text.replace(/^\s+/, "").replace(/\s+$/, "");
} else
return text.replace(/\s/g, "");
}
function SPActiveFilter(text, domains)
{
SPFilter.call(this, text);
this.domainSource = domains;
}
SPActiveFilter.prototype = {
__proto__: SPFilter.prototype,
_disabled: false,
get disabled() this._disabled,
set disabled(value) {
if (value != this._disabled)
{
let oldValue = this._disabled;
this._disabled = value;
}
return this._disabled;
},
domainSource: null,
domainSeparator: null,
ignoreTrailingDot: true,
domainSourceIsUpperCase: false,
get domains() {
let domains = null;
if (this.domainSource) {
let source = this.domainSource;
if (!this.domainSourceIsUpperCase) {
// RegExpFilter already have uppercase domains
source = source.toUpperCase();
}
let list = source.split(this.domainSeparator);
if (list.length == 1 && list[0][0] != "~") {
domains = {__proto__: null, "": false};
if (this.ignoreTrailingDot)
list[0] = list[0].replace(/\.+$/, "");
domains[list[0]] = true;
} else {
let hasIncludes = false;
for (let i = 0; i < list.length; i++) {
let domain = list[i];
if (this.ignoreTrailingDot)
domain = domain.replace(/\.+$/, "");
if (domain == "")
continue;
let include;
if (domain[0] == "~") {
include = false;
domain = domain.substr(1);
} else {
include = true;
hasIncludes = true;
}
if (!domains)
domains = {__proto__: null};
domains[domain] = include;
}
domains[""] = !hasIncludes;
}
this.domainSource = null;
}
this.__defineGetter__("domains", function() domains);
return this.domains;
},
isActiveOnDomain: function(/**String*/ docDomain) /**Boolean*/ {
if (!this.domains)
return true;
if (!docDomain)
return this.domains[""];
if (this.ignoreTrailingDot)
docDomain = docDomain.replace(/\.+$/, "");
docDomain = docDomain.toUpperCase();
while (true) {
if (docDomain in this.domains)
return this.domains[docDomain];
let nextDot = docDomain.indexOf(".");
if (nextDot < 0)
break;
docDomain = docDomain.substr(nextDot + 1);
}
return this.domains[""];
},
isActiveOnlyOnDomain: function(/**String*/ docDomain) /**Boolean*/ {
if (!docDomain || !this.domains || this.domains[""])
return false;
if (this.ignoreTrailingDot)
docDomain = docDomain.replace(/\.+$/, "");
docDomain = docDomain.toUpperCase();
for (let domain of this.domains)
if (this.domains[domain] && domain != docDomain && (domain.length <= docDomain.length || domain.indexOf("." + docDomain) != domain.length - docDomain.length - 1))
return false;
return true;
},
serialize: function(buffer) {
if (this._disabled) {
SPFilter.prototype.serialize.call(this, buffer);
if (this._disabled)
buffer.push("disabled=true");
}
}
};
function SPRegExpFilter(text, regexpSource, domains) {
SPActiveFilter.call(this, text, domains);
if (regexpSource.length >= 2 && regexpSource[0] == "/" && regexpSource[regexpSource.length - 1] == "/") {
let regexp = new RegExp(regexpSource.substr(1, regexpSource.length - 2), "i");
this.__defineGetter__("regexp", function() regexp);
} else {
this.regexpSource = regexpSource;
}
}
SPRegExpFilter.prototype = {
__proto__: SPActiveFilter.prototype,
domainSourceIsUpperCase: true,
length: 1,
domainSeparator: "|",
regexpSource: null,
get regexp() {
let source = this.regexpSource
.replace(/\*+/g, "*") // remove multiple wildcards
.replace(/\^\|$/, "^") // remove anchors following separator placeholder
.replace(/\W/g, "\\$&") // escape special symbols
.replace(/\\\*/g, ".*") // replace wildcards by .*
// process separator placeholders (all ANSI characters but alphanumeric characters and _%.-)
.replace(/\\\^/g, "(?:[\\x00-\\x24\\x26-\\x2C\\x2F\\x3A-\\x40\\x5B-\\x5E\\x60\\x7B-\\x7F]|$)")
.replace(/^\\\|\\\|/, "^[\\w\\-]+:\\/+(?!\\/)(?:[^\\/]+\\.)?") // process extended anchor at expression start
.replace(/^\\\|/, "^") // process anchor at expression start
.replace(/\\\|$/, "$") // process anchor at expression end
.replace(/^(\.\*)/, "") // remove leading wildcards
.replace(/(\.\*)$/, ""); // remove trailing wildcards
let regexp = new RegExp(source, "i");
delete this.regexpSource;
this.__defineGetter__("regexp", function() regexp);
return this.regexp;
},
matches: function(location, docDomain) {
if (this.regexp.test(location) && this.isActiveOnDomain(docDomain)) {
return true;
}
return false;
}
};
SPRegExpFilter.prototype.__defineGetter__("0", function() {
return this;
});
SPRegExpFilter.fromText = function(text) {
let blocking = true;
let origText = text;
if (text.indexOf("@@") == 0) {
blocking = false;
text = text.substr(2);
}
let domains = null;
try {
if (blocking)
return new SPBlockingFilter(origText, text, domains);
else
return new SPWhitelistFilter(origText, text, domains);
} catch (e) {
return null;
}
}
function SPBlockingFilter(text, regexpSource, domains) {
SPRegExpFilter.call(this, text, regexpSource, domains);
}
SPBlockingFilter.prototype = {
__proto__: SPRegExpFilter.prototype,
};
function SPWhitelistFilter(text, regexpSource, domains) {
SPRegExpFilter.call(this, text, regexpSource, domains);
}
SPWhitelistFilter.prototype = {
__proto__: SPRegExpFilter.prototype,
}
function SPMatcher() {
this.clear();
}
SPMatcher.prototype = {
filterByKeyword: null,
keywordByFilter: null,
clear: function() {
this.filterByKeyword = {__proto__: null};
this.keywordByFilter = {__proto__: null};
},
add: function(filter) {
if (filter.text in this.keywordByFilter)
return;
let keyword = this.findKeyword(filter);
let oldEntry = this.filterByKeyword[keyword];
if (typeof oldEntry == "undefined")
this.filterByKeyword[keyword] = filter;
else if (oldEntry.length == 1)
this.filterByKeyword[keyword] = [oldEntry, filter];
else
oldEntry.push(filter);
this.keywordByFilter[filter.text] = keyword;
},
remove: function(filter) {
if (!(filter.text in this.keywordByFilter))
return;
let keyword = this.keywordByFilter[filter.text];
let list = this.filterByKeyword[keyword];
if (list.length <= 1)
delete this.filterByKeyword[keyword];
else {
let index = list.indexOf(filter);
if (index >= 0)
{
list.splice(index, 1);
if (list.length == 1)
this.filterByKeyword[keyword] = list[0];
}
}
delete this.keywordByFilter[filter.text];
},
findKeyword: function(filter) {
let result = "";
let text = filter.text;
if (SPFilter.regexpRegExp.test(text))
return result;
let match = SPFilter.optionsRegExp.exec(text);
if (match)
text = match.input.substr(0, match.index);
if (text.substr(0, 2) == "@@")
text = text.substr(2);
let candidates = text.toLowerCase().match(/[^a-z0-9%*][a-z0-9%]{3,}(?=[^a-z0-9%*])/g);
if (!candidates)
return result;
let hash = this.filterByKeyword;
let resultCount = 0xFFFFFF;
let resultLength = 0;
for (let i = 0, l = candidates.length; i < l; i++) {
let candidate = candidates[i].substr(1);
let count = (candidate in hash ? hash[candidate].length : 0);
if (count < resultCount || (count == resultCount && candidate.length > resultLength))
{
result = candidate;
resultCount = count;
resultLength = candidate.length;
}
}
return result;
},
hasFilter: function(/**RegExpFilter*/ filter) /**Boolean*/ {
return (filter.text in this.keywordByFilter);
},
getKeywordForFilter: function(/**RegExpFilter*/ filter) /**String*/ {
if (filter.text in this.keywordByFilter)
return this.keywordByFilter[filter.text];
else
return null;
},
_checkEntryMatch: function(keyword, location, docDomain) {
let list = this.filterByKeyword[keyword];
for (let i = 0; i < list.length; i++)
{
let filter = list[i];
if (filter.matches(location, docDomain))
return filter;
}
return null;
},
matchesAny: function(location, docDomain) {
let candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g);
if (candidates === null)
candidates = [];
candidates.push("");
for (let i = 0, l = candidates.length; i < l; i++) {
let substr = candidates[i];
if (substr in this.filterByKeyword) {
let result = this._checkEntryMatch(substr, location, docDomain);
if (result)
return result;
}
}
return null;
}
};
function SPCombinedMatcher() {
this.blacklist = new SPMatcher();
this.whitelist = new SPMatcher();
this.keys = {__proto__: null};
this.resultCache = {__proto__: null};
}
SPCombinedMatcher.maxCacheEntries = 1000;
SPCombinedMatcher.prototype = {
blacklist: null,
whitelist: null,
keys: null,
resultCache: null,
cacheEntries: 0,
clear: function()
{
this.blacklist.clear();
this.whitelist.clear();
this.keys = {__proto__: null};
this.resultCache = {__proto__: null};
this.cacheEntries = 0;
},
add: function(filter) {
if (filter instanceof SPWhitelistFilter)
this.whitelist.add(filter);
else
this.blacklist.add(filter);
if (this.cacheEntries > 0) {
this.resultCache = {__proto__: null};
this.cacheEntries = 0;
}
},
remove: function(filter) {
if (filter instanceof SPWhitelistFilter)
this.whitelist.remove(filter);
else
this.blacklist.remove(filter);
if (this.cacheEntries > 0) {
this.resultCache = {__proto__: null};
this.cacheEntries = 0;
}
},
findKeyword: function(filter) {
if (filter instanceof SPWhitelistFilter)
return this.whitelist.findKeyword(filter);
else
return this.blacklist.findKeyword(filter);
},
hasFilter: function(filter) {
if (filter instanceof SPWhitelistFilter)
return this.whitelist.hasFilter(filter);
else
return this.blacklist.hasFilter(filter);
},
getKeywordForFilter: function(filter) {
if (filter instanceof SPWhitelistFilter)
return this.whitelist.getKeywordForFilter(filter);
else
return this.blacklist.getKeywordForFilter(filter);
},
isSlowFilter: function(/**RegExpFilter*/ filter) /**Boolean*/ {
let matcher = (filter instanceof SPWhitelistFilter ? this.whitelist : this.blacklist);
if (matcher.hasFilter(filter))
return !matcher.getKeywordForFilter(filter);
else
return !matcher.findKeyword(filter);
},
matchesAnyInternal: function(location, docDomain) {
let candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g);
if (candidates === null)
candidates = [];
candidates.push("");
let blacklistHit = null;
for (let i = 0, l = candidates.length; i < l; i++) {
let substr = candidates[i];
if (substr in this.whitelist.filterByKeyword) {
let result = this.whitelist._checkEntryMatch(substr, location, docDomain);
if (result)
return result;
}
if (substr in this.blacklist.filterByKeyword && blacklistHit === null)
blacklistHit = this.blacklist._checkEntryMatch(substr, location, docDomain);
}
return blacklistHit;
},
matchesAny: function(location, docDomain) {
let key = location + " " + docDomain;
if (key in this.resultCache)
return this.resultCache[key];
let result = this.matchesAnyInternal(location, docDomain);
if (this.cacheEntries >= SPCombinedMatcher.maxCacheEntries) {
this.resultCache = {__proto__: null};
this.cacheEntries = 0;
}
this.resultCache[key] = result;
this.cacheEntries++;
return result;
},
matchesByKey: function(/**String*/ location, /**String*/ key, /**String*/ docDomain) {
key = key.toUpperCase();
if (key in this.keys)
{
let filter = SPFilter.knownFilters[this.keys[key]];
if (filter && filter.matches(location, "DOCUMENT", docDomain, false))
return filter;
else
return null;
}
else
return null;
}
}
let SPdefaultMatcher = new SPCombinedMatcher();
SmartProxy.init();
window.SmartProxy = SmartProxy;
function getFoxVer(){
var info = Components.classes["@mozilla.org/xre/app-info;1"]
.getService(Components.interfaces.nsIXULAppInfo);
var ver = parseInt(info.version.substr(0,3) * 10,10) / 10;
return ver;
}
function addStyle(css) {
var pi = document.createProcessingInstruction(
'xml-stylesheet',
'type="text/css" href="data:text/css;utf-8,' + encodeURIComponent(css) + '"'
);
return document.insertBefore(pi, document.documentElement);
}
function getFocusedWindow(){
var focusedWindow = document.commandDispatcher.focusedWindow;
if (!focusedWindow || focusedWindow == window)
return window.content;
else
return focusedWindow;
}
function getDomain(uri) {
var host = getHostname(uri);
try {
var baseDomain = _eTLDService.getBaseDomainFromHost(host, 0);
return _idnService.convertToDisplayIDN(baseDomain, {});
} catch (e) {
if (e.name == "NS_ERROR_HOST_IS_IP_ADDRESS") {
return host;
} else if (e.name == "NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS") {
return host;
} else {
throw e;
}
}
}
function getHostname(url) {
try {
return unwrapURL(url).host;
} catch(e) {
return null;
}
}
function unwrapURL(url) {
if (!(url instanceof Ci.nsIURI))
url = makeURI(url);
if (url instanceof Ci.nsINestedURI)
return url.innermostURI;
else
return url;
}
function makeURI(url) {
try
{
return ioService.newURI(url, null, null);
}
catch (e) {
return null;
}
}
function E(id) {
return document.getElementById(id);
}
function convertpEnc2Char(str) {
str = str.replace(/((%[A-Fa-f0-9]{2})+)/g,
function(matchstr, parens) {
return convertpEsc2Char(parens);
});
return str;
}
function convertpEsc2Char( str ) {
var outputString = "";
var counter = 0;
var n = 0;
var listArray = str.split('%');
for ( var i = 1; i < listArray.length; i++ ) {
var b = parseInt(listArray[i], 16);
switch (counter) {
case 0:
if (0 <= b && b <= 0x7F) {
outputString += dec2char(b); }
else if (0xC0 <= b && b <= 0xDF) {
counter = 1;
n = b & 0x1F; }
else if (0xE0 <= b && b <= 0xEF) {
counter = 2;
n = b & 0xF; }
else if (0xF0 <= b && b <= 0xF7) {
counter = 3;
n = b & 0x7; }
else {
outputString += 'convertpEsc2Char: error!';
}
break;
case 1:
if (b < 0x80 || b > 0xBF) {
outputString += 'convertpEsc2Char: error!';
}
counter--;
outputString += dec2char((n << 6) | (b-0x80));
n = 0;
break;
case 2: case 3:
if (b < 0x80 || b > 0xBF) {
outputString += 'convertpEsc2Char: error!';
}
n = (n << 6) | (b-0x80);
counter--;
break;
}
}
return outputString;
}
function dec2char(n) {
var result = '';
if (n <= 0xFFFF) {
result += String.fromCharCode(n);
} else if (n <= 0x10FFFF) {
n -= 0x10000
result += String.fromCharCode(0xD800 | (n >> 10)) + String.fromCharCode(0xDC00 | (n & 0x3FF));
} else {
result += 'dec2char error!';
}
return result;
}
})('\
textbox.proxyName{ width: 60px; } .proxyHost{ width: 80px; } .proxyPort{ width: 40px; } radiogroup > .proxyHttp{ margin-left: 10px; } radiogroup > .proxySocks4, radiogroup > .proxySocks5{ margin-left: 21px;} .selBox{ margin-left: 10px; }\
#sp-contents {list-style-image: none; font-size: 14px; padding: 0; margin: 0; }\
.actionbtn { list-style-image: none; color: #484; font-size: 14px; }\
.actionbtn:hover { list-style-image: none; color: #555; text-decoration: underline; cursor: pointer; }\
.actiontoolbtn { list-style-image: none; font-size: 13px; font-weight:bold; margin: 0 5px 0 5px; }\
.actiontoolbtn:hover { list-style-image: none; color: #484; font-weight:bold; text-decoration: underline; margin: 0 5px 0 5px; }\
#closesliderbar { list-style-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABj0lEQVQ4jaXRsUsCYRjHcf8YNcQg1CGUAk1RvJOLaIlAJKPBQVzMIVu8amlNCQQbDqIhwqGlocWzwUMknByEONH5kIIav03dS4mg9MBveH4872d5HZ/mG6NqjY6yu1BG1Rqf5hs/4zCvqryrFbjTFsq7WsG8qgqgLe+A1mBSLvGSTfOSTTMpl0BrzO3b8o4AWtI21Gu003t22S+XGBcLjIsF+uWS3bfTe1Cv0ZK2BfCcUODygnHuiH6xIJBiYWYf547g8oLnhCKAp7gMJ8dwcswos89rPsffec3nGGX27bunuCyAx5iEtbZmx3C50eWkfaDLSQyX+9fNY0wSQDOSmPt4HtKMJARwH45j+fwY7hX0lJD1lDSzG+4VLJ+f+3BcALebMabBEA9OlzhWUnS9q3S9q+hKyu4fnC6mwRC3mzEBaKEtPqJRev4ATY+HpsdDzx/gIxqd22uhLQHcrEf4kqWlcrMeEYBxfoZ5eACV04ViHh5gnJ8JwBoO6Kgq14GNhdJRVazhQAAzf7bk/Bv4Bv7RCf77/Pb2AAAAAElFTkSuQmCC) !important;}\
tree { margin: 0px; } #col-slow { text-align: center; } #col-enabled { min-width: 48px; } #col-slow { min-width: 30px; }\
treechildren:-moz-locale-dir(rtl)::-moz-tree-cell(col-filter, type-whitelist),\
treechildren:-moz-locale-dir(rtl)::-moz-tree-cell(col-filter, type-filterlist) { direction: ltr; text-align: end; }\
treechildren::-moz-tree-cell-text(col-filter, type-whitelist, selected-false) { color: #008000; }\
treechildren::-moz-tree-cell-text(col-filter, dummy-true) { font-style: italic; }\
treechildren::-moz-tree-cell-text(col-filter, type-whitelist, selected-false),\
treechildren::-moz-tree-cell-text(col-slow) { font-size: 12px; }\
treechildren::-moz-tree-cell-text(col-filter, disabled-true, selected-false) { color: #808080; }\
treechildren::-moz-tree-image(col-enabled, disabled-true) { list-style-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAaCAYAAABsONZfAAABD0lEQVQ4je2TMa5FQBSGrUIURiURhVJH3BXYgg1IprYGHa1FCGtheslf0UgkFMZ51ZUn3rvkJvdVr/iLKb4z55z5Ronj+ME5p7uJ4/ihcM5pmiYQ0a9ZlgVEhGmawDknhXNOr4BxHBFFEYQQIKJraBgG+L4PxhjSNIWU8git6woiwrZteJ7DMISqqsiybC90gNq2RV3XO1gUBRhjSJJkL3SCgiCAYRioqgp938OyLLiui3meDy0foKZp4DgOGGPwPA+6rqMsy9Ocp0U0TQPbtqFpGhhj+5wvISKCEAKmaSLPc0gp70FSSggh0HXdj8+wQ1dGPLMb8ZZ7HxP21N6VsLe29w+9C33/bJ+56U+E/QKpA0b/pEOBQAAAAABJRU5ErkJggg==); -moz-image-region: rect(13px 13px 26px 0px); }\
treechildren::-moz-tree-image(col-enabled, disabled-false) { list-style-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAaCAYAAABsONZfAAABD0lEQVQ4je2TMa5FQBSGrUIURiURhVJH3BXYgg1IprYGHa1FCGtheslf0UgkFMZ51ZUn3rvkJvdVr/iLKb4z55z5Ronj+ME5p7uJ4/ihcM5pmiYQ0a9ZlgVEhGmawDknhXNOr4BxHBFFEYQQIKJraBgG+L4PxhjSNIWU8git6woiwrZteJ7DMISqqsiybC90gNq2RV3XO1gUBRhjSJJkL3SCgiCAYRioqgp938OyLLiui3meDy0foKZp4DgOGGPwPA+6rqMsy9Ocp0U0TQPbtqFpGhhj+5wvISKCEAKmaSLPc0gp70FSSggh0HXdj8+wQ1dGPLMb8ZZ7HxP21N6VsLe29w+9C33/bJ+56U+E/QKpA0b/pEOBQAAAAABJRU5ErkJggg==); -moz-image-region: rect(0px 13px 13px 0px); }\
treechildren::-moz-tree-image(col-slow, slow-true) { list-style-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAQCAYAAAAI0W+oAAACIklEQVQ4jZWUXWsTQRSG35sQFe/ygSwmNQlVDBqKSsS2QtGLRNIWaqUMfiDRNH6UBlSKVPBrbUrUK4ObRPSmf8BLCSIEvMsvmCsv/CWvF5PdnWxmiz1w2Jkze95nzp6ZBcJtEQBD/FVITmW0rhsBfA6DfHFF60vg0zXljdUx2K+QXAJ4FNjscdOLXwFwS4B722Zv1T3Yb0P+T62qqqFCAMAdAHx9NxziervhweyAxuwoHgfwB8AnY9n1JV+sWQMXZsDlOfDq+UnYu3sezPT57NFzI7j4GPBFXtxWIkcOgRsrYCqp5vOFcVg8Hg822wZAIQTz+by7kWkd9FIHAeDcGXNvLpzyY7lcjgC+aZVwMBhQSkkppQt6q4O2XNCzNdCKmXvTeaLE3HmhUPBOYiqV4nA49CAa6IOxIlesseoLbl4HPz5U4xPHwHMnwRsL6j3bttnv98cAUkr2ej0XNK+D1vWdPr/p90RcUeNWXa3lp9Q8nU7TcZwJQK1Wo2VZLmQveBj+AuDpKR+2cx9cvAQuz4Lbt1Ts2kUF6XQ6EwApJR3HcQHvg4AfsViMlmVRSslSqcRIJMKZaXWfdtfB1gNw5TJ49LCCdLtdI0TryfcgxDspyWSSzWbTlEQAzGQyrFaroQApJYvFYti9GrNdAIxGoxRC7CsY9Ha7rZ++A9mmEIKVSsWrKJFIMJvNTvzJ3Vi5XD4wZD87C2AH6gK+GY1z/5P4D/B9/dnqz8gaAAAAAElFTkSuQmCC); }\
'.replace(/[\r\n\t]/g, ''));