]> git.madduck.net Git - etc/vimperator.git/blob - .vimperator/plugins/proxy.js

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

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.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

initial checkin
[etc/vimperator.git] / .vimperator / plugins / proxy.js
1 /*
2  * proxy.js
3  *
4  *  Vimperator plugin to easily switch between
5  *  preconfigured proxy settings
6  *  @author Tim Hammerquist <penryu@gmail.com>
7  *  @version 0.3
8  *
9  *    Copyright 2008 Tim Hammerquist <penryu@gmail.com>
10  *    Compatible with Vimperator 1.2pre or higher.  Requires Firefox 3.
11  */
12
13 /*****************************************************************************
14
15 USAGE
16
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
20     :proxyinfo
21     :set proxy=myssh
22     :pxrm myhttp
23
24
25 COMMANDS
26
27 :proxyinfo
28 :pxi
29
30     Displays summary of the currently defined proxies.
31
32 :proxyadd
33 :pxadd
34
35     Adds a new proxy configuratino to the list of available
36     configurations.
37
38     Syntax:
39         :proxyadd[!] name host:port [options]
40
41     Available options:
42
43         -type/-t
44                 Type of proxy. E.g., http, socks, etc.
45
46         -remote_dns/-r
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'.
50
51         -version/-v
52                 Version of SOCKS protocol to use. If not set, Firefox
53                 default (5) is used.  See 'network.proxy.socks_version'.
54
55     Notes:
56
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.
60
61         If proxy type is not specified, http is used and all other options are
62         ignored.
63
64         -version and -remote_dns options only apply to SOCKS proxies.
65
66         SOCKS proxies must be defined using the -type/-t option.  It is not
67         inferred from use of the -version/-remote_dns options.
68
69 :proxydel
70 :pxrm
71
72     Remove a proxy from the list of available configurations.
73
74     Syntax:
75         :pxrm name
76
77
78 BACKGROUND
79
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.
83
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.
87
88
89 KNOWN ISSUES
90
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.
94
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 (')
99     correctly.
100
101
102 TODO
103
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
106     welcome.
107
108   * Expand :proxyinfo to display socks-specific settings for proxies.
109     For now, use
110
111         :echo proxies.get('proxyname')
112
113
114
115 *****************************************************************************/
116
117
118 const jsonService = Components.classes["@mozilla.org/dom/json;1"]
119                      .createInstance(Components.interfaces.nsIJSON);
120
121 Proxy = function() //{{{
122 {
123     if (arguments[0].constructor == Array)
124         arguments = arguments[0];
125
126     var [name, type, host, port, flags] = arguments;
127     if (flags)
128         var ver = flags.version, rdns = flags.remote_dns;
129
130     if (!(name && type && host && port))
131         return null;
132
133     const supportedTypes = ['ftp','gopher','http','socks','ssl'];
134
135     var data = {};        // this holds our internal data
136
137     this.__defineGetter__('name', function() { return data.name; });
138     this.__defineSetter__('name', function(v){ });
139
140     this.__defineGetter__('type', function() { return data.type; });
141     this.__defineSetter__('type', function(v){
142         v = v.toLowerCase();
143         if (supportedTypes.some(function(t){return t == v}))
144             data.type = v;
145     });
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)]); });
156
157     data.name = name;     // this is set once
158     this.type = type;
159     this.host = host;
160     this.port = port;
161
162     // apply SOCKS-specific settings
163     if (type == 'socks')
164     {
165         this.remote_dns = rdns;
166         this.version = ver;
167     }
168
169     return this;
170 }; //}}}
171
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')
177         {
178             var flags = [];
179             ['remote_dns','version'].forEach(function(attr){
180                 if (this[attr] != undefined)
181                 flags.push([attr,this[attr]]);
182             });
183             if (flags.length > 0)
184             {
185                 var obj = {};
186                 flags.forEach(function(f){ obj[f[0]] = f[1]; });
187                 fields.push(obj);
188             }
189         }
190         return fields;
191     },
192     toString: function () {
193         return this.name + ": " + this.host + ":" + this.port
194             + " (" + this.type.toUpperCase() + ")";
195     },
196 }; //}}}
197
198 Proxies = function () //{{{
199 {
200     ////////////////////////////////////////////////////////////////////////////////
201     ////////////////////// PRIVATE SECTION /////////////////////////////////////////
202     /////////////////////////////////////////////////////////////////////////////{{{
203
204     PROXY_NONE = 0;
205     PROXY_MANUAL = 1;
206     PROXY_URL_DETECT = 2;
207     PROXY_NET_DETECT = 4;
208
209     const proxyStatusId = 'liberator-statusline-field-proxystatus'
210     const proxyPrefId = 'extensions.vimperator.proxies';
211     const proxyPrefs = [
212         "network.proxy.ftp",
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",
222         "network.proxy.ssl",
223         "network.proxy.ssl_port",
224         "network.proxy.type",
225     ];
226
227     var _proxies;                               // private delegate object
228
229     var proxyStatusContainer, proxyStatusText;  // DOM objects for status
230
231     function createProxyStatusWidget ()
232     {
233         if (proxyStatusContainer && proxyStatusText)
234             return;
235
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);
242
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);
248     }
249
250     function setProxyStatusText (str)
251     {
252         if (!proxyStatusContainer)
253             createProxyStatusWidget();
254
255         proxyStatusText.data = str;
256
257         if (str && (str.length > 0))
258             showProxyStatus();
259         else
260             hideProxyStatus();
261     }
262
263     function showProxyStatus ()
264     {
265         if (!proxyStatusContainer)
266             createProxyStatusWidget();
267
268         proxyStatusContainer.style.display = '';
269     }
270
271     function hideProxyStatus ()
272     {
273         if (!proxyStatusContainer)
274             createProxyStatusWidget();
275
276         proxyStatusContainer.style.display = 'none';
277     }
278
279     function sortProxies()
280     {
281         _proxies.sort(function(a,b){return (a.name > b.name);});
282     }
283
284     function loadProxies()
285     {
286         var prefValue = liberator.options.getPref(proxyPrefId);
287         _proxies = [];
288
289         if (prefValue.length == 0)
290             return;
291
292         try {
293             jsonService.decode(prefValue).forEach(function(a){
294                 _proxies.push(new Proxy(a)); });
295         }
296         catch (err)
297         {
298             liberator.log("proxy loading failed: " + err, 3);
299             return false;
300         }
301
302         sortProxies();
303     }
304
305     function storeProxies()
306     {
307         const setP = liberator.options.setPref;
308         sortProxies();
309         var data = _proxies.map(function(p){return p.export();});
310         var prefValue = jsonService.encode(data);
311         liberator.options.setPref(proxyPrefId, prefValue);
312         return true;
313     }
314
315     function getProxyByName (name)
316     {
317         for (var i=0; i < _proxies.length; i++)
318             if (_proxies[i].name == name)
319                 return _proxies[i];
320         return null;
321     }
322
323     function clearProxyPrefs()
324     {
325         proxyPrefs.forEach(function(n){
326             try       { execute("set! "+n+"&"); }
327             catch (e) { liberator.log('ignored "'+e+'"',3); }
328         });
329     }
330
331     function activateProxy(name)
332     {
333         const np = "network.proxy.";
334         const setP = liberator.options.setPref;
335         var proxy = getProxyByName(name);
336
337         clearProxyPrefs();
338
339         if (proxy)
340         {
341             setP(np + 'type', PROXY_MANUAL);
342             setP(np + proxy.type, proxy.host);
343             setP(np + proxy.type + "_port", proxy.port);
344
345             if (proxy.type == 'socks')
346             {
347                 setP(np + 'socks_remote_dns', proxy.remote_dns || false );
348                 setP(np + 'socks_version', proxy.version || 5 );
349             }
350
351             // update the ui
352             setProxyStatusText("(" + proxy.name + ")");
353             liberator.echo("Now using proxy: " + proxy.name);
354         }
355         else
356         {
357             setProxyStatusText("");
358             liberator.echo("Proxy disabled.");
359         }
360     }
361
362     createProxyStatusWidget();
363     loadProxies();
364
365     /////////////////////////////////////////////////////////////////////////////}}}
366     ////////////////////// OPTIONS /////////////////////////////////////////////////
367     /////////////////////////////////////////////////////////////////////////////{{{
368
369     liberator.options.add(["proxy"],
370         "Set the active proxy configuration",
371         "string", "",
372         {
373             setter: function (name)
374             {
375                 activateProxy(name);
376             },
377             validator: function (value)
378             {
379                 return (getProxyByName(value) || (value == ""));
380             },
381             completer: function (filter)
382             {
383                 return [["", "Direct Connection"]]
384                     .concat(_proxies.map(function(p){return [p.name, p];}));
385             },
386         });
387
388     /////////////////////////////////////////////////////////////////////////////}}}
389     ////////////////////// COMMANDS ////////////////////////////////////////////////
390     /////////////////////////////////////////////////////////////////////////////{{{
391
392     liberator.commands.add(["proxyi[nfo]","pxi"],
393         "Display proxy configuration",
394         function (args, special) { liberator.proxies.list(special) });
395
396     liberator.commands.add(["proxya[dd]","pxa[dd]"],
397         "Add a new proxy",
398         function (args, special)
399         {
400             if (args.arguments.length < 2)
401             {
402                 liberator.echoerr("Insufficient arguments; 2 required.");
403                 return;
404             }
405
406             var name, type, host, port, rdns, ver;
407
408             name = args.arguments[0];
409             if (liberator.proxies.get(name) && !special)
410             {
411                 liberator.echoerr("Proxy '"+name+"' already exists."
412                     + " Use ! to override.");
413                 return;
414             }
415
416             [host, port] = args.arguments[1].split(':');
417
418             type = args["-type"] || 'http';
419
420             if (type == 'socks')
421             {
422                 rdns = args["-remote_dns"];
423                 ver = args["-version"];
424             }
425
426             var proxy = liberator.proxies.add(
427                 name, host, port, type, rdns, ver);
428
429             if (proxy)
430                 liberator.echo("Added proxy: " + proxy);
431             else
432                 liberator.echoerr("Exxx: Could not add proxy `" + name + "'",
433                     liberator.commandline.FORCE_SINGLELINE);
434         },
435         {
436             options: [[["-type","-t"],       liberator.commands.OPTION_STRING],
437                       [["-remote_dns","-r"], liberator.commands.OPTION_BOOL],
438                       [["-version","-v"],    liberator.commands.OPTION_INT]],
439         });
440
441     liberator.commands.add(["proxyd[el]","pxrm"],
442         "Remove a proxy from the list",
443         function (args, special)
444         {
445             if (args.arguments.length < 1)
446             {
447                 liberator.echoerr("Insufficient arguments; 1 required.");
448                 return;
449             }
450
451             var name = args.arguments[0];
452             if (!liberator.proxies.get(name))
453             {
454                 liberator.echoerr(
455                     "Can't delete nonexistent proxy '" + name + "'");
456                 return;
457             }
458
459             liberator.echo(liberator.util.objectToString(args.arguments));
460
461             var proxy = liberator.proxies.destroy(name);
462
463             if (proxy)
464                 liberator.echo("Removed proxy: " + proxy.name);
465             else
466                 liberator.echoerr("Exxx: Could not remove proxy `" + name + "'",
467                     liberator.commandline.FORCE_SINGLELINE);
468         });
469
470     /////////////////////////////////////////////////////////////////////////////}}}
471     ////////////////////// PUBLIC SECTION //////////////////////////////////////////
472     /////////////////////////////////////////////////////////////////////////////{{{
473
474     return {
475
476         get: function (name)
477         {
478             return getProxyByName(name);
479         },
480
481         list: function ()
482         {
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);
489             });
490         },
491
492         add: function (n, h, p, t, rdns, ver)
493         {
494             if (!t) t = 'http';
495
496             var new_proxy = new Proxy(n, t, h, p,
497                 {remote_dns:rdns, version:ver});
498
499             // if a proxy of this name already exists, remove it
500             _proxies = _proxies.filter(function(p){
501                 return (p.name != n);
502             });
503             _proxies.push(new_proxy);
504
505             storeProxies();
506
507             return this.get(n);
508         },
509
510         destroy: function (name)
511         {
512             var proxyCount = _proxies.length;
513             var destruct;
514             _proxies = _proxies.filter(function(p){
515                 if (p.name != name)
516                     return true;
517                 destruct = p;
518                 return false;
519             });
520             storeProxies();
521             return destruct;
522         },
523
524         save: function ()
525         {
526             return storeProxies();
527         },
528
529         load: function ()
530         {
531             return loadProxies();
532         },
533     };
534     //}}}
535 }; //}}}
536
537 liberator.proxies = new Proxies();
538 liberator.log("Loading proxy plugin", 0);
539
540 // vim: set fdm=marker sw=4 ts=4 sts=4 et: