All patches and comments are welcome. Please squash your changes to logical
commits before using git-format-patch and git-send-email to
patches@git.madduck.net.
If you'd read over the Git project's submission guidelines and adhered to them,
I'd be especially grateful.
4 * Vimperator plugin to easily switch between
5 * preconfigured proxy settings
6 * @author Tim Hammerquist <penryu@gmail.com>
9 * Copyright 2008 Tim Hammerquist <penryu@gmail.com>
10 * Compatible with Vimperator 1.2pre or higher. Requires Firefox 3.
13 /*****************************************************************************
17 :proxyadd myhttp 192.168.0.2:3128
18 :proxyadd mytor 192.168.0.3:9050 -type=socks -version=4
19 :proxyadd myssh 127.0.0.1:1080 -type=socks -remote_dns=on
30 Displays summary of the currently defined proxies.
35 Adds a new proxy configuratino to the list of available
39 :proxyadd[!] name host:port [options]
44 Type of proxy. E.g., http, socks, etc.
47 Indicate whether DNS lookups should be performed via
48 the proxy. If not set, Firefox default (off) is used.
49 See 'network.proxy.socks_remote_dns'.
52 Version of SOCKS protocol to use. If not set, Firefox
53 default (5) is used. See 'network.proxy.socks_version'.
57 Attempting to add a proxy with the same name as one already in the
58 list using :proxyadd will fail. Use :proxyadd! to replace the currently
59 defined proxy with the new configuration.
61 If proxy type is not specified, http is used and all other options are
64 -version and -remote_dns options only apply to SOCKS proxies.
66 SOCKS proxies must be defined using the -type/-t option. It is not
67 inferred from use of the -version/-remote_dns options.
72 Remove a proxy from the list of available configurations.
80 This plugin was written to replace the many proxy-switching plugins. It
81 does not yet offer per-URL settings, but much of this functionality may be
82 available using the Vimperator's LocationChange event.
84 While currently functional as a plugin for the user's ~/.vimperator/plugin/
85 directory, this code was written to closely resemble Vimperator's own
86 modules and should work with muttator with little or no modification.
91 * Effects of switching between 2 different SOCKS proxies are not seen
92 immediately. New settings will (eventually) take effect after 1 or 2
93 minutes. Tips/suggestions/patches welcome.
95 * Configured proxies are saved in JSON format in the user's prefs.js file
96 under the id 'extensions.vimperator.proxies' whenever any proxy is
97 added/removed/changed. Be aware, however, that Mozilla's nsIJSON service
98 is very picky about its quotes. It does not interpret single-quotes (')
104 * The current proxy configuration is displayed next to progress bar. I plan
105 to make this configurable. Comments/suggestions on the best way are
108 * Expand :proxyinfo to display socks-specific settings for proxies.
111 :echo proxies.get('proxyname')
115 *****************************************************************************/
118 const jsonService = Components.classes["@mozilla.org/dom/json;1"]
119 .createInstance(Components.interfaces.nsIJSON);
121 Proxy = function() //{{{
123 if (arguments[0].constructor == Array)
124 arguments = arguments[0];
126 var [name, type, host, port, flags] = arguments;
128 var ver = flags.version, rdns = flags.remote_dns;
130 if (!(name && type && host && port))
133 const supportedTypes = ['ftp','gopher','http','socks','ssl'];
135 var data = {}; // this holds our internal data
137 this.__defineGetter__('name', function() { return data.name; });
138 this.__defineSetter__('name', function(v){ });
140 this.__defineGetter__('type', function() { return data.type; });
141 this.__defineSetter__('type', function(v){
143 if (supportedTypes.some(function(t){return t == v}))
146 this.__defineGetter__('host', function() { return data.host; });
147 this.__defineSetter__('host', function(v){ data.host = v; });
148 this.__defineGetter__('port', function() { return data.port; });
149 this.__defineSetter__('port', function(v){ data.port = parseInt(v); });
150 this.__defineGetter__('remote_dns', function() { return data.rdns; });
151 this.__defineSetter__('remote_dns',
152 function(v){ data.rdns = (v ? true : false); });
153 this.__defineGetter__('version', function() { return data.ver; });
154 this.__defineSetter__('version', function(v){
155 data.ver = ({4:4,5:5}[parseInt(v)]); });
157 data.name = name; // this is set once
162 // apply SOCKS-specific settings
165 this.remote_dns = rdns;
172 Proxy.prototype = { //{{{
173 // so we can store our data
174 export: function () {
175 var fields = [this.name, this.type, this.host, this.port];
176 if (this.type == 'socks')
179 ['remote_dns','version'].forEach(function(attr){
180 if (this[attr] != undefined)
181 flags.push([attr,this[attr]]);
183 if (flags.length > 0)
186 flags.forEach(function(f){ obj[f[0]] = f[1]; });
192 toString: function () {
193 return this.name + ": " + this.host + ":" + this.port
194 + " (" + this.type.toUpperCase() + ")";
198 Proxies = function () //{{{
200 ////////////////////////////////////////////////////////////////////////////////
201 ////////////////////// PRIVATE SECTION /////////////////////////////////////////
202 /////////////////////////////////////////////////////////////////////////////{{{
206 PROXY_URL_DETECT = 2;
207 PROXY_NET_DETECT = 4;
209 const proxyStatusId = 'liberator-statusline-field-proxystatus'
210 const proxyPrefId = 'extensions.vimperator.proxies';
213 "network.proxy.ftp_port",
214 "network.proxy.gopher",
215 "network.proxy.gopher_port",
216 "network.proxy.http",
217 "network.proxy.http_port",
218 "network.proxy.socks",
219 "network.proxy.socks_port",
220 "network.proxy.socks_remote_dns",
221 "network.proxy.socks_version",
223 "network.proxy.ssl_port",
224 "network.proxy.type",
227 var _proxies; // private delegate object
229 var proxyStatusContainer, proxyStatusText; // DOM objects for status
231 function createProxyStatusWidget ()
233 if (proxyStatusContainer && proxyStatusText)
236 // create our text node
237 proxyStatusContainer = document.createElement('span');
238 proxyStatusText = document.createTextNode('');
239 proxyStatusContainer.setAttribute('id',proxyStatusId);
240 proxyStatusContainer.style.display = 'none';
241 proxyStatusContainer.appendChild(proxyStatusText);
243 // insert text node into the statusline, next to progress bar
244 var progressBar = document.getElementById(
245 'liberator-statusline-field-progress');
246 progressBar.parentNode.insertBefore(
247 proxyStatusContainer, progressBar.nextSibling);
250 function setProxyStatusText (str)
252 if (!proxyStatusContainer)
253 createProxyStatusWidget();
255 proxyStatusText.data = str;
257 if (str && (str.length > 0))
263 function showProxyStatus ()
265 if (!proxyStatusContainer)
266 createProxyStatusWidget();
268 proxyStatusContainer.style.display = '';
271 function hideProxyStatus ()
273 if (!proxyStatusContainer)
274 createProxyStatusWidget();
276 proxyStatusContainer.style.display = 'none';
279 function sortProxies()
281 _proxies.sort(function(a,b){return (a.name > b.name);});
284 function loadProxies()
286 var prefValue = liberator.options.getPref(proxyPrefId);
289 if (prefValue.length == 0)
293 jsonService.decode(prefValue).forEach(function(a){
294 _proxies.push(new Proxy(a)); });
298 liberator.log("proxy loading failed: " + err, 3);
305 function storeProxies()
307 const setP = liberator.options.setPref;
309 var data = _proxies.map(function(p){return p.export();});
310 var prefValue = jsonService.encode(data);
311 liberator.options.setPref(proxyPrefId, prefValue);
315 function getProxyByName (name)
317 for (var i=0; i < _proxies.length; i++)
318 if (_proxies[i].name == name)
323 function clearProxyPrefs()
325 proxyPrefs.forEach(function(n){
326 try { execute("set! "+n+"&"); }
327 catch (e) { liberator.log('ignored "'+e+'"',3); }
331 function activateProxy(name)
333 const np = "network.proxy.";
334 const setP = liberator.options.setPref;
335 var proxy = getProxyByName(name);
341 setP(np + 'type', PROXY_MANUAL);
342 setP(np + proxy.type, proxy.host);
343 setP(np + proxy.type + "_port", proxy.port);
345 if (proxy.type == 'socks')
347 setP(np + 'socks_remote_dns', proxy.remote_dns || false );
348 setP(np + 'socks_version', proxy.version || 5 );
352 setProxyStatusText("(" + proxy.name + ")");
353 liberator.echo("Now using proxy: " + proxy.name);
357 setProxyStatusText("");
358 liberator.echo("Proxy disabled.");
362 createProxyStatusWidget();
365 /////////////////////////////////////////////////////////////////////////////}}}
366 ////////////////////// OPTIONS /////////////////////////////////////////////////
367 /////////////////////////////////////////////////////////////////////////////{{{
369 liberator.options.add(["proxy"],
370 "Set the active proxy configuration",
373 setter: function (name)
377 validator: function (value)
379 return (getProxyByName(value) || (value == ""));
381 completer: function (filter)
383 return [["", "Direct Connection"]]
384 .concat(_proxies.map(function(p){return [p.name, p];}));
388 /////////////////////////////////////////////////////////////////////////////}}}
389 ////////////////////// COMMANDS ////////////////////////////////////////////////
390 /////////////////////////////////////////////////////////////////////////////{{{
392 liberator.commands.add(["proxyi[nfo]","pxi"],
393 "Display proxy configuration",
394 function (args, special) { liberator.proxies.list(special) });
396 liberator.commands.add(["proxya[dd]","pxa[dd]"],
398 function (args, special)
400 if (args.arguments.length < 2)
402 liberator.echoerr("Insufficient arguments; 2 required.");
406 var name, type, host, port, rdns, ver;
408 name = args.arguments[0];
409 if (liberator.proxies.get(name) && !special)
411 liberator.echoerr("Proxy '"+name+"' already exists."
412 + " Use ! to override.");
416 [host, port] = args.arguments[1].split(':');
418 type = args["-type"] || 'http';
422 rdns = args["-remote_dns"];
423 ver = args["-version"];
426 var proxy = liberator.proxies.add(
427 name, host, port, type, rdns, ver);
430 liberator.echo("Added proxy: " + proxy);
432 liberator.echoerr("Exxx: Could not add proxy `" + name + "'",
433 liberator.commandline.FORCE_SINGLELINE);
436 options: [[["-type","-t"], liberator.commands.OPTION_STRING],
437 [["-remote_dns","-r"], liberator.commands.OPTION_BOOL],
438 [["-version","-v"], liberator.commands.OPTION_INT]],
441 liberator.commands.add(["proxyd[el]","pxrm"],
442 "Remove a proxy from the list",
443 function (args, special)
445 if (args.arguments.length < 1)
447 liberator.echoerr("Insufficient arguments; 1 required.");
451 var name = args.arguments[0];
452 if (!liberator.proxies.get(name))
455 "Can't delete nonexistent proxy '" + name + "'");
459 liberator.echo(liberator.util.objectToString(args.arguments));
461 var proxy = liberator.proxies.destroy(name);
464 liberator.echo("Removed proxy: " + proxy.name);
466 liberator.echoerr("Exxx: Could not remove proxy `" + name + "'",
467 liberator.commandline.FORCE_SINGLELINE);
470 /////////////////////////////////////////////////////////////////////////////}}}
471 ////////////////////// PUBLIC SECTION //////////////////////////////////////////
472 /////////////////////////////////////////////////////////////////////////////{{{
478 return getProxyByName(name);
483 liberator.commandline.echo(_proxies.length + " proxies defined:",
484 null, liberator.commandline.FORCE_MULTILINE);
485 _proxies.forEach(function(p){
486 var prefix = (p.name == liberator.options.proxy) ? "*" : " ";
487 liberator.commandline.echo(prefix + p, null,
488 liberator.commandline.FORCE_MULTILINE);
492 add: function (n, h, p, t, rdns, ver)
496 var new_proxy = new Proxy(n, t, h, p,
497 {remote_dns:rdns, version:ver});
499 // if a proxy of this name already exists, remove it
500 _proxies = _proxies.filter(function(p){
501 return (p.name != n);
503 _proxies.push(new_proxy);
510 destroy: function (name)
512 var proxyCount = _proxies.length;
514 _proxies = _proxies.filter(function(p){
526 return storeProxies();
531 return loadProxies();
537 liberator.proxies = new Proxies();
538 liberator.log("Loading proxy plugin", 0);
540 // vim: set fdm=marker sw=4 ts=4 sts=4 et: