--- /dev/null
+/*
+ * proxy.js
+ *
+ *  Vimperator plugin to easily switch between
+ *  preconfigured proxy settings
+ *  @author Tim Hammerquist <penryu@gmail.com>
+ *  @version 0.3
+ *
+ *    Copyright 2008 Tim Hammerquist <penryu@gmail.com>
+ *    Compatible with Vimperator 1.2pre or higher.  Requires Firefox 3.
+ */
+
+/*****************************************************************************
+
+USAGE
+
+    :proxyadd myhttp 192.168.0.2:3128
+    :proxyadd mytor 192.168.0.3:9050 -type=socks -version=4
+    :proxyadd myssh 127.0.0.1:1080 -type=socks -remote_dns=on
+    :proxyinfo
+    :set proxy=myssh
+    :pxrm myhttp
+
+
+COMMANDS
+
+:proxyinfo
+:pxi
+
+    Displays summary of the currently defined proxies.
+
+:proxyadd
+:pxadd
+
+    Adds a new proxy configuratino to the list of available
+    configurations.
+
+    Syntax:
+        :proxyadd[!] name host:port [options]
+
+    Available options:
+
+        -type/-t
+                Type of proxy. E.g., http, socks, etc.
+
+        -remote_dns/-r
+                Indicate whether DNS lookups should be performed via
+                the proxy. If not set, Firefox default (off) is used.
+                See 'network.proxy.socks_remote_dns'.
+
+        -version/-v
+                Version of SOCKS protocol to use. If not set, Firefox
+                default (5) is used.  See 'network.proxy.socks_version'.
+
+    Notes:
+
+        Attempting to add a proxy with the same name as one already in the
+        list using :proxyadd will fail.  Use :proxyadd! to replace the currently
+        defined proxy with the new configuration.
+
+        If proxy type is not specified, http is used and all other options are
+        ignored.
+
+        -version and -remote_dns options only apply to SOCKS proxies.
+
+        SOCKS proxies must be defined using the -type/-t option.  It is not
+        inferred from use of the -version/-remote_dns options.
+
+:proxydel
+:pxrm
+
+    Remove a proxy from the list of available configurations.
+
+    Syntax:
+        :pxrm name
+
+
+BACKGROUND
+
+  This plugin was written to replace the many proxy-switching plugins.  It
+  does not yet offer per-URL settings, but much of this functionality may be
+  available using the Vimperator's LocationChange event.
+
+  While currently functional as a plugin for the user's ~/.vimperator/plugin/
+  directory, this code was written to closely resemble Vimperator's own
+  modules and should work with muttator with little or no modification.
+
+
+KNOWN ISSUES
+
+  * Effects of switching between 2 different SOCKS proxies are not seen
+    immediately.  New settings will (eventually) take effect after 1 or 2
+    minutes.  Tips/suggestions/patches welcome.
+
+  * Configured proxies are saved in JSON format in the user's prefs.js file
+    under the id 'extensions.vimperator.proxies' whenever any proxy is
+    added/removed/changed.  Be aware, however, that Mozilla's nsIJSON service
+    is very picky about its quotes.  It does not interpret single-quotes (')
+    correctly.
+
+
+TODO
+
+  * The current proxy configuration is displayed next to progress bar.  I plan
+    to make this configurable.  Comments/suggestions on the best way are
+    welcome.
+
+  * Expand :proxyinfo to display socks-specific settings for proxies.
+    For now, use
+
+        :echo proxies.get('proxyname')
+
+
+
+*****************************************************************************/
+
+
+const jsonService = Components.classes["@mozilla.org/dom/json;1"]
+                     .createInstance(Components.interfaces.nsIJSON);
+
+Proxy = function() //{{{
+{
+    if (arguments[0].constructor == Array)
+        arguments = arguments[0];
+
+    var [name, type, host, port, flags] = arguments;
+    if (flags)
+        var ver = flags.version, rdns = flags.remote_dns;
+
+    if (!(name && type && host && port))
+        return null;
+
+    const supportedTypes = ['ftp','gopher','http','socks','ssl'];
+
+    var data = {};        // this holds our internal data
+
+    this.__defineGetter__('name', function() { return data.name; });
+    this.__defineSetter__('name', function(v){ });
+
+    this.__defineGetter__('type', function() { return data.type; });
+    this.__defineSetter__('type', function(v){
+        v = v.toLowerCase();
+        if (supportedTypes.some(function(t){return t == v}))
+            data.type = v;
+    });
+    this.__defineGetter__('host', function() { return data.host; });
+    this.__defineSetter__('host', function(v){ data.host = v; });
+    this.__defineGetter__('port', function() { return data.port; });
+    this.__defineSetter__('port', function(v){ data.port = parseInt(v); });
+    this.__defineGetter__('remote_dns', function() { return data.rdns; });
+    this.__defineSetter__('remote_dns',
+        function(v){ data.rdns = (v ? true : false); });
+    this.__defineGetter__('version', function() { return data.ver; });
+    this.__defineSetter__('version', function(v){
+            data.ver = ({4:4,5:5}[parseInt(v)]); });
+
+    data.name = name;     // this is set once
+    this.type = type;
+    this.host = host;
+    this.port = port;
+
+    // apply SOCKS-specific settings
+    if (type == 'socks')
+    {
+        this.remote_dns = rdns;
+        this.version = ver;
+    }
+
+    return this;
+}; //}}}
+
+Proxy.prototype = { //{{{
+    // so we can store our data
+    export: function () {
+        var fields = [this.name, this.type, this.host, this.port];
+        if (this.type == 'socks')
+        {
+            var flags = [];
+            ['remote_dns','version'].forEach(function(attr){
+                if (this[attr] != undefined)
+                flags.push([attr,this[attr]]);
+            });
+            if (flags.length > 0)
+            {
+                var obj = {};
+                flags.forEach(function(f){ obj[f[0]] = f[1]; });
+                fields.push(obj);
+            }
+        }
+        return fields;
+    },
+    toString: function () {
+        return this.name + ": " + this.host + ":" + this.port
+            + " (" + this.type.toUpperCase() + ")";
+    },
+}; //}}}
+
+Proxies = function () //{{{
+{
+    ////////////////////////////////////////////////////////////////////////////////
+    ////////////////////// PRIVATE SECTION /////////////////////////////////////////
+    /////////////////////////////////////////////////////////////////////////////{{{
+
+    PROXY_NONE = 0;
+    PROXY_MANUAL = 1;
+    PROXY_URL_DETECT = 2;
+    PROXY_NET_DETECT = 4;
+
+    const proxyStatusId = 'liberator-statusline-field-proxystatus'
+    const proxyPrefId = 'extensions.vimperator.proxies';
+    const proxyPrefs = [
+        "network.proxy.ftp",
+        "network.proxy.ftp_port",
+        "network.proxy.gopher",
+        "network.proxy.gopher_port",
+        "network.proxy.http",
+        "network.proxy.http_port",
+        "network.proxy.socks",
+        "network.proxy.socks_port",
+        "network.proxy.socks_remote_dns",
+        "network.proxy.socks_version",
+        "network.proxy.ssl",
+        "network.proxy.ssl_port",
+        "network.proxy.type",
+    ];
+
+    var _proxies;                               // private delegate object
+
+    var proxyStatusContainer, proxyStatusText;  // DOM objects for status
+
+    function createProxyStatusWidget ()
+    {
+        if (proxyStatusContainer && proxyStatusText)
+            return;
+
+        // create our text node
+        proxyStatusContainer = document.createElement('span');
+        proxyStatusText      = document.createTextNode('');
+        proxyStatusContainer.setAttribute('id',proxyStatusId);
+        proxyStatusContainer.style.display = 'none';
+        proxyStatusContainer.appendChild(proxyStatusText);
+
+        // insert text node into the statusline, next to progress bar
+        var progressBar = document.getElementById(
+            'liberator-statusline-field-progress');
+        progressBar.parentNode.insertBefore(
+            proxyStatusContainer, progressBar.nextSibling);
+    }
+
+    function setProxyStatusText (str)
+    {
+        if (!proxyStatusContainer)
+            createProxyStatusWidget();
+
+        proxyStatusText.data = str;
+
+        if (str && (str.length > 0))
+            showProxyStatus();
+        else
+            hideProxyStatus();
+    }
+
+    function showProxyStatus ()
+    {
+        if (!proxyStatusContainer)
+            createProxyStatusWidget();
+
+        proxyStatusContainer.style.display = '';
+    }
+
+    function hideProxyStatus ()
+    {
+        if (!proxyStatusContainer)
+            createProxyStatusWidget();
+
+        proxyStatusContainer.style.display = 'none';
+    }
+
+    function sortProxies()
+    {
+        _proxies.sort(function(a,b){return (a.name > b.name);});
+    }
+
+    function loadProxies()
+    {
+        var prefValue = liberator.options.getPref(proxyPrefId);
+        _proxies = [];
+
+        if (prefValue.length == 0)
+            return;
+
+        try {
+            jsonService.decode(prefValue).forEach(function(a){
+                _proxies.push(new Proxy(a)); });
+        }
+        catch (err)
+        {
+            liberator.log("proxy loading failed: " + err, 3);
+            return false;
+        }
+
+        sortProxies();
+    }
+
+    function storeProxies()
+    {
+        const setP = liberator.options.setPref;
+        sortProxies();
+        var data = _proxies.map(function(p){return p.export();});
+        var prefValue = jsonService.encode(data);
+        liberator.options.setPref(proxyPrefId, prefValue);
+        return true;
+    }
+
+    function getProxyByName (name)
+    {
+        for (var i=0; i < _proxies.length; i++)
+            if (_proxies[i].name == name)
+                return _proxies[i];
+        return null;
+    }
+
+    function clearProxyPrefs()
+    {
+        proxyPrefs.forEach(function(n){
+            try       { execute("set! "+n+"&"); }
+            catch (e) { liberator.log('ignored "'+e+'"',3); }
+        });
+    }
+
+    function activateProxy(name)
+    {
+        const np = "network.proxy.";
+        const setP = liberator.options.setPref;
+        var proxy = getProxyByName(name);
+
+        clearProxyPrefs();
+
+        if (proxy)
+        {
+            setP(np + 'type', PROXY_MANUAL);
+            setP(np + proxy.type, proxy.host);
+            setP(np + proxy.type + "_port", proxy.port);
+
+            if (proxy.type == 'socks')
+            {
+                setP(np + 'socks_remote_dns', proxy.remote_dns || false );
+                setP(np + 'socks_version', proxy.version || 5 );
+            }
+
+            // update the ui
+            setProxyStatusText("(" + proxy.name + ")");
+            liberator.echo("Now using proxy: " + proxy.name);
+        }
+        else
+        {
+            setProxyStatusText("");
+            liberator.echo("Proxy disabled.");
+        }
+    }
+
+    createProxyStatusWidget();
+    loadProxies();
+
+    /////////////////////////////////////////////////////////////////////////////}}}
+    ////////////////////// OPTIONS /////////////////////////////////////////////////
+    /////////////////////////////////////////////////////////////////////////////{{{
+
+    liberator.options.add(["proxy"],
+        "Set the active proxy configuration",
+        "string", "",
+        {
+            setter: function (name)
+            {
+                activateProxy(name);
+            },
+            validator: function (value)
+            {
+                return (getProxyByName(value) || (value == ""));
+            },
+            completer: function (filter)
+            {
+                return [["", "Direct Connection"]]
+                    .concat(_proxies.map(function(p){return [p.name, p];}));
+            },
+        });
+
+    /////////////////////////////////////////////////////////////////////////////}}}
+    ////////////////////// COMMANDS ////////////////////////////////////////////////
+    /////////////////////////////////////////////////////////////////////////////{{{
+
+    liberator.commands.add(["proxyi[nfo]","pxi"],
+        "Display proxy configuration",
+        function (args, special) { liberator.proxies.list(special) });
+
+    liberator.commands.add(["proxya[dd]","pxa[dd]"],
+        "Add a new proxy",
+        function (args, special)
+        {
+            if (args.arguments.length < 2)
+            {
+                liberator.echoerr("Insufficient arguments; 2 required.");
+                return;
+            }
+
+            var name, type, host, port, rdns, ver;
+
+            name = args.arguments[0];
+            if (liberator.proxies.get(name) && !special)
+            {
+                liberator.echoerr("Proxy '"+name+"' already exists."
+                    + " Use ! to override.");
+                return;
+            }
+
+            [host, port] = args.arguments[1].split(':');
+
+            type = args["-type"] || 'http';
+
+            if (type == 'socks')
+            {
+                rdns = args["-remote_dns"];
+                ver = args["-version"];
+            }
+
+            var proxy = liberator.proxies.add(
+                name, host, port, type, rdns, ver);
+
+            if (proxy)
+                liberator.echo("Added proxy: " + proxy);
+            else
+                liberator.echoerr("Exxx: Could not add proxy `" + name + "'",
+                    liberator.commandline.FORCE_SINGLELINE);
+        },
+        {
+            options: [[["-type","-t"],       liberator.commands.OPTION_STRING],
+                      [["-remote_dns","-r"], liberator.commands.OPTION_BOOL],
+                      [["-version","-v"],    liberator.commands.OPTION_INT]],
+        });
+
+    liberator.commands.add(["proxyd[el]","pxrm"],
+        "Remove a proxy from the list",
+        function (args, special)
+        {
+            if (args.arguments.length < 1)
+            {
+                liberator.echoerr("Insufficient arguments; 1 required.");
+                return;
+            }
+
+            var name = args.arguments[0];
+            if (!liberator.proxies.get(name))
+            {
+                liberator.echoerr(
+                    "Can't delete nonexistent proxy '" + name + "'");
+                return;
+            }
+
+            liberator.echo(liberator.util.objectToString(args.arguments));
+
+            var proxy = liberator.proxies.destroy(name);
+
+            if (proxy)
+                liberator.echo("Removed proxy: " + proxy.name);
+            else
+                liberator.echoerr("Exxx: Could not remove proxy `" + name + "'",
+                    liberator.commandline.FORCE_SINGLELINE);
+        });
+
+    /////////////////////////////////////////////////////////////////////////////}}}
+    ////////////////////// PUBLIC SECTION //////////////////////////////////////////
+    /////////////////////////////////////////////////////////////////////////////{{{
+
+    return {
+
+        get: function (name)
+        {
+            return getProxyByName(name);
+        },
+
+        list: function ()
+        {
+            liberator.commandline.echo(_proxies.length + " proxies defined:",
+                null, liberator.commandline.FORCE_MULTILINE);
+            _proxies.forEach(function(p){
+                var prefix = (p.name == liberator.options.proxy) ? "*" : " ";
+                liberator.commandline.echo(prefix + p, null,
+                    liberator.commandline.FORCE_MULTILINE);
+            });
+        },
+
+        add: function (n, h, p, t, rdns, ver)
+        {
+            if (!t) t = 'http';
+
+            var new_proxy = new Proxy(n, t, h, p,
+                {remote_dns:rdns, version:ver});
+
+            // if a proxy of this name already exists, remove it
+            _proxies = _proxies.filter(function(p){
+                return (p.name != n);
+            });
+            _proxies.push(new_proxy);
+
+            storeProxies();
+
+            return this.get(n);
+        },
+
+        destroy: function (name)
+        {
+            var proxyCount = _proxies.length;
+            var destruct;
+            _proxies = _proxies.filter(function(p){
+                if (p.name != name)
+                    return true;
+                destruct = p;
+                return false;
+            });
+            storeProxies();
+            return destruct;
+        },
+
+        save: function ()
+        {
+            return storeProxies();
+        },
+
+        load: function ()
+        {
+            return loadProxies();
+        },
+    };
+    //}}}
+}; //}}}
+
+liberator.proxies = new Proxies();
+liberator.log("Loading proxy plugin", 0);
+
+// vim: set fdm=marker sw=4 ts=4 sts=4 et: