URI: 
       tFixed merged conflict and added folder creation on first load - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 23ffbc3e4874d8496fec25fd4ada5dfe24733a8b
   DIR parent c486c6d55f65b0e2cfb82aaca994ae74f9f9bc80
  HTML Author: Maran <maran.hidskes@gmail.com>
       Date:   Fri, 21 Sep 2012 16:57:54 +0200
       
       Fixed merged conflict and added folder creation on first load
       
       Diffstat:
         M electrum                            |       9 ++++++---
         M lib/__init__.py                     |       2 +-
         M lib/gui_lite.py                     |      13 +++++++++++++
         M lib/gui_qt.py                       |      38 +++++++++++++++++++++++++++----
         M lib/interface.py                    |      50 +++++++++++++++++++++++++-------
         M lib/simple_config.py                |      28 ++++++++++++++++++++++------
         A lib/socks.py                        |     382 +++++++++++++++++++++++++++++++
         M lib/wallet.py                       |       5 +++--
         M setup.py                            |       1 +
       
       9 files changed, 502 insertions(+), 26 deletions(-)
       ---
   DIR diff --git a/electrum b/electrum
       t@@ -37,9 +37,9 @@ except ImportError:
            sys.exit("Error: AES does not seem to be installed. Try 'sudo pip install slowaes'")
        
        try:
       -    from lib import Wallet, WalletSynchronizer, format_satoshis, mnemonic, prompt_password, SimpleConfig
       +    from lib import Wallet, WalletSynchronizer, format_satoshis, mnemonic, prompt_password, parse_proxy_options, SimpleConfig
        except ImportError:
       -    from electrum import Wallet, WalletSynchronizer, format_satoshis, mnemonic, prompt_password, SimpleConfig
       +    from electrum import Wallet, WalletSynchronizer, format_satoshis, mnemonic, prompt_password, parse_proxy_options, SimpleConfig
        
        from decimal import Decimal
        
       t@@ -116,8 +116,11 @@ if __name__ == '__main__':
            parser.add_option("-s", "--fromaddr", dest="from_addr", default=None, help="set source address for payto/mktx. if it isn't in the wallet, it will ask for the private key unless supplied in the format public_key:private_key. It's not saved in the wallet.")
            parser.add_option("-c", "--changeaddr", dest="change_addr", default=None, help="set the change address for payto/mktx. default is a spare address, or the source address if it's not in the wallet")
            parser.add_option("-r", "--remote", dest="remote_url", default=None, help="URL of a remote wallet")
       +    parser.add_option("-p", "--proxy", dest="proxy", default=simple_config.config["proxy"], help="set proxy [type:]host[:port], where type is socks4,socks5 or http")
            options, args = parser.parse_args()
        
       +    if type(options.proxy) == type(''):
       +                options.proxy = parse_proxy_options(options.proxy)
        
            wallet = Wallet()
            wallet.set_path(options.wallet_path)
       t@@ -179,7 +182,7 @@ if __name__ == '__main__':
                    sys.exit("Error: Unknown GUI: " + options.gui)
        
                gui = gui.ElectrumGui(wallet)
       -        interface = WalletSynchronizer(wallet, True, gui.server_list_changed)
       +        interface = WalletSynchronizer(wallet, True, gui.server_list_changed, options.proxy)
                interface.start()
        
                try:
   DIR diff --git a/lib/__init__.py b/lib/__init__.py
       t@@ -1,4 +1,4 @@
        from wallet import Wallet, format_satoshis, prompt_password
       -from interface import WalletSynchronizer
       +from interface import WalletSynchronizer, parse_proxy_options
        from interface import TcpStratumInterface
        from simple_config import SimpleConfig
   DIR diff --git a/lib/gui_lite.py b/lib/gui_lite.py
       t@@ -5,6 +5,7 @@ from PyQt4.QtGui import *
        
        from decimal import Decimal as D
        from interface import DEFAULT_SERVERS
       +from simple_config import SimpleConfig
        from util import get_resource_path as rsrc
        from i18n import _
        import decimal
       t@@ -231,6 +232,12 @@ class MiniWindow(QDialog):
                close_shortcut = QShortcut(QKeySequence("Ctrl+W"), self)
                close_shortcut.activated.connect(self.close)
        
       +        cfg = SimpleConfig()
       +        g = cfg.config["winpos-lite"]
       +        self.setGeometry(g[0], g[1], g[2], g[3])
       +        show_history.setChecked(cfg.config["history"])
       +        self.show_history(cfg.config["history"])
       +        
                self.setWindowIcon(QIcon(":electrum.png"))
                self.setWindowTitle("Electrum")
                self.setWindowFlags(Qt.Window|Qt.MSWindowsFixedSizeDialogHint)
       t@@ -247,6 +254,12 @@ class MiniWindow(QDialog):
                QDir.setCurrent(old_path)
        
            def closeEvent(self, event):
       +        cfg = SimpleConfig()
       +        g = self.geometry()
       +        cfg.set_key("winpos-lite", [g.left(),g.top(),g.width(),g.height()])
       +        cfg.set_key("history", self.history_list.isVisible())
       +        cfg.save_config()
       +        
                super(MiniWindow, self).closeEvent(event)
                qApp.quit()
        
   DIR diff --git a/lib/gui_qt.py b/lib/gui_qt.py
       t@@ -37,6 +37,7 @@ except:
            sys.exit("Error: Could not import icons_rc.py, please generate it with: 'pyrcc4 icons.qrc -o lib/icons_rc.py'")
        
        from wallet import format_satoshis
       +from simple_config import SimpleConfig
        import bmp, mnemonic, pyqrnative, qrscanner
        from simple_config import SimpleConfig
        
       t@@ -203,7 +204,9 @@ class ElectrumWindow(QMainWindow):
                tabs.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
                self.setCentralWidget(tabs)
                self.create_status_bar()
       -        self.setGeometry(100,100,840,400)
       +        cfg = SimpleConfig()
       +        g = cfg.config["winpos-qt"]
       +        self.setGeometry(g[0], g[1], g[2], g[3])
                title = 'Electrum ' + self.wallet.electrum_version + '  -  ' + self.wallet.path
                if not self.wallet.seed: title += ' [seedless]'
                self.setWindowTitle( title )
       t@@ -1392,6 +1395,24 @@ class ElectrumWindow(QMainWindow):
                hbox.addWidget(radio2)
        
                vbox.addLayout(hbox)
       +        
       +        hbox = QHBoxLayout()
       +        proxy_mode = QComboBox()
       +        proxy_host = QLineEdit()
       +        proxy_host.setFixedWidth(200)
       +        proxy_port = QLineEdit()
       +        proxy_port.setFixedWidth(50)
       +        proxy_mode.addItems(['NONE', 'SOCKS4', 'SOCKS5', 'HTTP'])
       +        proxy_mode.setCurrentIndex(proxy_mode.findText(str(interface.proxy["mode"]).upper()))
       +        proxy_host.setText(interface.proxy["host"])
       +        proxy_port.setText(interface.proxy["port"])
       +        hbox.addWidget(QLabel(_('Proxy') + ':'))
       +        hbox.addWidget(proxy_mode)
       +        hbox.addWidget(proxy_host)
       +        hbox.addWidget(proxy_port)
       +        vbox.addLayout(hbox)
       +
       +        hbox = QHBoxLayout()
        
                if wallet.interface.servers:
                    label = _('Active Servers')
       t@@ -1425,9 +1446,12 @@ class ElectrumWindow(QMainWindow):
                server = unicode( host_line.text() )
        
                try:
       -            wallet.set_server(server)
       -        except:
       -            QMessageBox.information(None, _('Error'), 'error', _('OK'))
       +            cfg = SimpleConfig()
       +            cfg.set_key("proxy", { u'mode':unicode(proxy_mode.currentText()).lower(), u'host':unicode(proxy_host.text()), u'port':unicode(proxy_port.text()) })
       +            cfg.save_config()
       +            wallet.set_server(server, cfg.config["proxy"])
       +        except Exception as err:
       +            QMessageBox.information(None, _('Error'), str(err), _('OK'))
                    if parent == None:
                        sys.exit(1)
                    else:
       t@@ -1435,6 +1459,12 @@ class ElectrumWindow(QMainWindow):
        
                return True
        
       +    def closeEvent(self, event):
       +        cfg = SimpleConfig()
       +        g = self.geometry()
       +        cfg.set_key("winpos-qt", [g.left(),g.top(),g.width(),g.height()])
       +        cfg.save_config()
       +        event.accept()
        
        
        class ElectrumGui:
   DIR diff --git a/lib/interface.py b/lib/interface.py
       t@@ -28,6 +28,7 @@ DEFAULT_SERVERS = [ 'ecdsa.org:50001:t',
                            'electrum.novit.ro:50001:t', 
                            'electrum.bytesized-hosting.com:50001:t']  # list of default servers
        
       +proxy_modes = ['none', 'socks4', 'socks5', 'http' ]
        
        def replace_keys(obj, old_key, new_key):
            if isinstance(obj, dict):
       t@@ -47,13 +48,29 @@ def old_to_new(d):
            replace_keys(d, 'is_in', 'is_input')
            replace_keys(d, 'raw_scriptPubKey', 'raw_output_script')
        
       +def parse_proxy_options(s):
       +    proxy = { "mode":"socks5", "host":"localhost" }
       +    args = s.split(':')
       +    n = 0
       +    if proxy_modes.count(args[n]) == 1:
       +        proxy["mode"] = args[n]
       +        n += 1
       +    if len(args) > n:
       +        proxy["host"] = args[n]
       +        n += 1
       +    if len(args) > n:
       +        proxy["port"] = args[n]
       +    else:
       +        proxy["port"] = "8080" if proxy["mode"] == "http" else "1080"
       +    return proxy
        
        class Interface(threading.Thread):
       -    def __init__(self, host, port, debug_server):
       +    def __init__(self, host, port, debug_server, proxy):
                threading.Thread.__init__(self)
                self.daemon = True
                self.host = host
                self.port = port
       +        self.proxy = proxy
        
                self.servers = [] # actual list from IRC
                self.rtime = 0
       t@@ -121,8 +138,8 @@ class Interface(threading.Thread):
        class PollingInterface(Interface):
            """ non-persistent connection. synchronous calls"""
        
       -    def __init__(self, host, port, debug_server):
       -        Interface.__init__(self, host, port, debug_server)
       +    def __init__(self, host, port, debug_server, proxy):
       +        Interface.__init__(self, host, port, debug_server, proxy)
                self.session_id = None
                self.debug_server = debug_server
        
       t@@ -173,7 +190,11 @@ class HttpStratumInterface(PollingInterface):
        
            def send(self, messages):
                import urllib2, json, time, cookielib
       -
       +        
       +        if self.proxy["mode"] != "none":
       +            import socks
       +            socks.setdefaultproxy(proxy_modes.index(self.proxy["mode"]), self.proxy["host"], int(self.proxy["port"]) )
       +            socks.wrapmodule(urllib2)
                cj = cookielib.CookieJar()
                opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
                urllib2.install_opener(opener)
       t@@ -232,16 +253,23 @@ class HttpStratumInterface(PollingInterface):
        class TcpStratumInterface(Interface):
            """json-rpc over persistent TCP connection, asynchronous"""
        
       -    def __init__(self, host, port, debug_server):
       -        Interface.__init__(self, host, port, debug_server)
       +    def __init__(self, host, port, debug_server, proxy):
       +        Interface.__init__(self, host, port, debug_server, proxy)
                self.debug_server = debug_server
        
            def init_socket(self):
       -        self.s = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
       +        global proxy_modes
       +        if self.proxy["mode"] == "none":
       +            self.s = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
       +        else:
       +            import socks
       +            self.s = socks.socksocket()
       +            print "Using Proxy", self.proxy
       +            self.s.setproxy(proxy_modes.index(self.proxy["mode"]), self.proxy["host"], int(self.proxy["port"]) )
                self.s.settimeout(60)
                self.s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
                try:
       -            self.s.connect(( self.host, self.port))
       +            self.s.connect(( self.host.encode('ascii'), int(self.port)))
                    self.is_connected = True
                    self.send([('server.version', [ELECTRUM_VERSION])])
                    print "Connected to %s:%d"%(self.host,self.port)
       t@@ -305,11 +333,12 @@ class TcpStratumInterface(Interface):
        
        class WalletSynchronizer(threading.Thread):
        
       -    def __init__(self, wallet, loop=False, servers_loaded_callback=None):
       +    def __init__(self, wallet, loop=False, servers_loaded_callback=None, proxy=None):
                threading.Thread.__init__(self)
                self.daemon = True
                self.wallet = wallet
                self.loop = loop
       +        self.proxy = proxy
                self.init_interface()
                self.servers_loaded_callback = servers_loaded_callback
        
       t@@ -331,7 +360,7 @@ class WalletSynchronizer(threading.Thread):
                    print_error("Error: Unknown protocol")
                    InterfaceClass = TcpStratumInterface
        
       -        self.interface = InterfaceClass(host, port, self.wallet.debug_server)
       +        self.interface = InterfaceClass(host, port, self.wallet.debug_server, self.proxy)
                self.wallet.interface = self.interface
        
            def handle_response(self, r):
       t@@ -429,6 +458,7 @@ class WalletSynchronizer(threading.Thread):
                    if self.loop:
                        time.sleep(5)
                        # Server has been changed. Copy callback for new interface.
       +                self.proxy = self.interface.proxy
                        self.init_interface()
                        self.start_interface()
                        continue
   DIR diff --git a/lib/simple_config.py b/lib/simple_config.py
       t@@ -4,7 +4,9 @@ from util import user_dir
        
        class SimpleConfig:
        
       -    default_options = {"gui": "lite"}
       +
       +    default_options = {"gui": "lite", "proxy": { "mode": "none", "host":"localhost", "port":"8080" },
       +    "winpos-qt": [100, 100, 840, 400], "winpos-lite": [4, 25, 351, 149], "history": False }
            
            def __init__(self):
                # Find electrum data folder
       t@@ -18,25 +20,39 @@ class SimpleConfig:
                    if not os.path.exists(self.config_folder):
                        os.mkdir(self.config_folder)
                    self.save_config()
       -        
       +
            def set_key(self, key, value, save = True):
                self.config[key] = value
                if save == True:
                    self.save_config()
       -    
       +
            def save_config(self):
       +        if not os.path.exists(self.config_folder):
       +            os.mkdir(self.config_folder)
                f = open(self.config_file_path(), "w+")
                f.write(json.dumps(self.config))
       -    
       +
            def load_config(self):
                f = open(self.config_file_path(), "r")
                file_contents = f.read()
                if file_contents:
       -            self.config = json.loads(file_contents)
       +            user_config = json.loads(file_contents)
       +            for i in user_config:
       +                self.config[i] = user_config[i]
                else:
                    self.config = self.default_options
                    self.save_config()
       -    
       +  
            def config_file_path(self):
                return "%s" % (self.config_folder + "/config.json")
        
       +    def __init__(self):
       +        # Find electrum data folder
       +        self.config_folder = user_dir()
       +        self.config = self.default_options
       +        # Read the file
       +        if os.path.exists(self.config_file_path()):
       +            self.load_config()
       +        self.save_config()
       +
       +
   DIR diff --git a/lib/socks.py b/lib/socks.py
       t@@ -0,0 +1,382 @@
       +"""SocksiPy - Python SOCKS module.
       +Version 1.00
       +
       +Copyright 2006 Dan-Haim. All rights reserved.
       +
       +Redistribution and use in source and binary forms, with or without modification,
       +are permitted provided that the following conditions are met:
       +1. Redistributions of source code must retain the above copyright notice, this
       +   list of conditions and the following disclaimer.
       +2. Redistributions in binary form must reproduce the above copyright notice,
       +   this list of conditions and the following disclaimer in the documentation
       +   and/or other materials provided with the distribution.
       +3. Neither the name of Dan Haim nor the names of his contributors may be used
       +   to endorse or promote products derived from this software without specific
       +   prior written permission.
       +   
       +THIS SOFTWARE IS PROVIDED BY DAN HAIM "AS IS" AND ANY EXPRESS OR IMPLIED
       +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
       +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
       +EVENT SHALL DAN HAIM OR HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
       +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
       +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA
       +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
       +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
       +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMANGE.
       +
       +
       +This module provides a standard socket-like interface for Python
       +for tunneling connections through SOCKS proxies.
       +
       +"""
       +
       +"""
       +
       +Minor modifications made by Christopher Gilbert (http://motomastyle.com/)
       +for use in PyLoris (http://pyloris.sourceforge.net/)
       +
       +Minor modifications made by Mario Vilas (http://breakingcode.wordpress.com/)
       +mainly to merge bug fixes found in Sourceforge
       +
       +"""
       +
       +import socket
       +import struct
       +import sys
       +
       +PROXY_TYPE_SOCKS4 = 1
       +PROXY_TYPE_SOCKS5 = 2
       +PROXY_TYPE_HTTP = 3
       +
       +_defaultproxy = None
       +_orgsocket = socket.socket
       +
       +class ProxyError(Exception): pass
       +class GeneralProxyError(ProxyError): pass
       +class Socks5AuthError(ProxyError): pass
       +class Socks5Error(ProxyError): pass
       +class Socks4Error(ProxyError): pass
       +class HTTPError(ProxyError): pass
       +
       +_generalerrors = ("success",
       +    "invalid data",
       +    "not connected",
       +    "not available",
       +    "bad proxy type",
       +    "bad input")
       +
       +_socks5errors = ("succeeded",
       +    "general SOCKS server failure",
       +    "connection not allowed by ruleset",
       +    "Network unreachable",
       +    "Host unreachable",
       +    "Connection refused",
       +    "TTL expired",
       +    "Command not supported",
       +    "Address type not supported",
       +    "Unknown error")
       +
       +_socks5autherrors = ("succeeded",
       +    "authentication is required",
       +    "all offered authentication methods were rejected",
       +    "unknown username or invalid password",
       +    "unknown error")
       +
       +_socks4errors = ("request granted",
       +    "request rejected or failed",
       +    "request rejected because SOCKS server cannot connect to identd on the client",
       +    "request rejected because the client program and identd report different user-ids",
       +    "unknown error")
       +
       +def setdefaultproxy(proxytype=None, addr=None, port=None, rdns=True, username=None, password=None):
       +    """setdefaultproxy(proxytype, addr[, port[, rdns[, username[, password]]]])
       +    Sets a default proxy which all further socksocket objects will use,
       +    unless explicitly changed.
       +    """
       +    global _defaultproxy
       +    _defaultproxy = (proxytype, addr, port, rdns, username, password)
       +
       +def wrapmodule(module):
       +    """wrapmodule(module)
       +    Attempts to replace a module's socket library with a SOCKS socket. Must set
       +    a default proxy using setdefaultproxy(...) first.
       +    This will only work on modules that import socket directly into the namespace;
       +    most of the Python Standard Library falls into this category.
       +    """
       +    if _defaultproxy != None:
       +        module.socket.socket = socksocket
       +    else:
       +        raise GeneralProxyError((4, "no proxy specified"))
       +
       +class socksocket(socket.socket):
       +    """socksocket([family[, type[, proto]]]) -> socket object
       +    Open a SOCKS enabled socket. The parameters are the same as
       +    those of the standard socket init. In order for SOCKS to work,
       +    you must specify family=AF_INET, type=SOCK_STREAM and proto=0.
       +    """
       +
       +    def __init__(self, family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, _sock=None):
       +        _orgsocket.__init__(self, family, type, proto, _sock)
       +        if _defaultproxy != None:
       +            self.__proxy = _defaultproxy
       +        else:
       +            self.__proxy = (None, None, None, None, None, None)
       +        self.__proxysockname = None
       +        self.__proxypeername = None
       +
       +    def __recvall(self, count):
       +        """__recvall(count) -> data
       +        Receive EXACTLY the number of bytes requested from the socket.
       +        Blocks until the required number of bytes have been received.
       +        """
       +        data = self.recv(count)
       +        while len(data) < count:
       +            d = self.recv(count-len(data))
       +            if not d: raise GeneralProxyError((0, "connection closed unexpectedly"))
       +            data = data + d
       +        return data
       +
       +    def setproxy(self, proxytype=None, addr=None, port=None, rdns=True, username=None, password=None):
       +        """setproxy(proxytype, addr[, port[, rdns[, username[, password]]]])
       +        Sets the proxy to be used.
       +        proxytype -    The type of the proxy to be used. Three types
       +                are supported: PROXY_TYPE_SOCKS4 (including socks4a),
       +                PROXY_TYPE_SOCKS5 and PROXY_TYPE_HTTP
       +        addr -        The address of the server (IP or DNS).
       +        port -        The port of the server. Defaults to 1080 for SOCKS
       +                servers and 8080 for HTTP proxy servers.
       +        rdns -        Should DNS queries be preformed on the remote side
       +                (rather than the local side). The default is True.
       +                Note: This has no effect with SOCKS4 servers.
       +        username -    Username to authenticate with to the server.
       +                The default is no authentication.
       +        password -    Password to authenticate with to the server.
       +                Only relevant when username is also provided.
       +        """
       +        self.__proxy = (proxytype, addr, port, rdns, username, password)
       +
       +    def __negotiatesocks5(self, destaddr, destport):
       +        """__negotiatesocks5(self,destaddr,destport)
       +        Negotiates a connection through a SOCKS5 server.
       +        """
       +        # First we'll send the authentication packages we support.
       +        if (self.__proxy[4]!=None) and (self.__proxy[5]!=None):
       +            # The username/password details were supplied to the
       +            # setproxy method so we support the USERNAME/PASSWORD
       +            # authentication (in addition to the standard none).
       +            self.sendall(struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02))
       +        else:
       +            # No username/password were entered, therefore we
       +            # only support connections with no authentication.
       +            self.sendall(struct.pack('BBB', 0x05, 0x01, 0x00))
       +        # We'll receive the server's response to determine which
       +        # method was selected
       +        chosenauth = self.__recvall(2)
       +        if chosenauth[0:1] != chr(0x05).encode():
       +            self.close()
       +            raise GeneralProxyError((1, _generalerrors[1]))
       +        # Check the chosen authentication method
       +        if chosenauth[1:2] == chr(0x00).encode():
       +            # No authentication is required
       +            pass
       +        elif chosenauth[1:2] == chr(0x02).encode():
       +            # Okay, we need to perform a basic username/password
       +            # authentication.
       +            self.sendall(chr(0x01).encode() + chr(len(self.__proxy[4])) + self.__proxy[4] + chr(len(self.__proxy[5])) + self.__proxy[5])
       +            authstat = self.__recvall(2)
       +            if authstat[0:1] != chr(0x01).encode():
       +                # Bad response
       +                self.close()
       +                raise GeneralProxyError((1, _generalerrors[1]))
       +            if authstat[1:2] != chr(0x00).encode():
       +                # Authentication failed
       +                self.close()
       +                raise Socks5AuthError((3, _socks5autherrors[3]))
       +            # Authentication succeeded
       +        else:
       +            # Reaching here is always bad
       +            self.close()
       +            if chosenauth[1] == chr(0xFF).encode():
       +                raise Socks5AuthError((2, _socks5autherrors[2]))
       +            else:
       +                raise GeneralProxyError((1, _generalerrors[1]))
       +        # Now we can request the actual connection
       +        req = struct.pack('BBB', 0x05, 0x01, 0x00)
       +        # If the given destination address is an IP address, we'll
       +        # use the IPv4 address request even if remote resolving was specified.
       +        try:
       +            ipaddr = socket.inet_aton(destaddr)
       +            req = req + chr(0x01).encode() + ipaddr
       +        except socket.error:
       +            # Well it's not an IP number,  so it's probably a DNS name.
       +            if self.__proxy[3]:
       +                # Resolve remotely
       +                ipaddr = None
       +                req = req + chr(0x03).encode() + chr(len(destaddr)).encode() + destaddr
       +            else:
       +                # Resolve locally
       +                ipaddr = socket.inet_aton(socket.gethostbyname(destaddr))
       +                req = req + chr(0x01).encode() + ipaddr
       +        req = req + struct.pack(">H", destport)
       +        self.sendall(req)
       +        # Get the response
       +        resp = self.__recvall(4)
       +        if resp[0:1] != chr(0x05).encode():
       +            self.close()
       +            raise GeneralProxyError((1, _generalerrors[1]))
       +        elif resp[1:2] != chr(0x00).encode():
       +            # Connection failed
       +            self.close()
       +            if ord(resp[1:2])<=8:
       +                raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])]))
       +            else:
       +                raise Socks5Error((9, _socks5errors[9]))
       +        # Get the bound address/port
       +        elif resp[3:4] == chr(0x01).encode():
       +            boundaddr = self.__recvall(4)
       +        elif resp[3:4] == chr(0x03).encode():
       +            resp = resp + self.recv(1)
       +            boundaddr = self.__recvall(ord(resp[4:5]))
       +        else:
       +            self.close()
       +            raise GeneralProxyError((1,_generalerrors[1]))
       +        boundport = struct.unpack(">H", self.__recvall(2))[0]
       +        self.__proxysockname = (boundaddr, boundport)
       +        if ipaddr != None:
       +            self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
       +        else:
       +            self.__proxypeername = (destaddr, destport)
       +
       +    def getproxysockname(self):
       +        """getsockname() -> address info
       +        Returns the bound IP address and port number at the proxy.
       +        """
       +        return self.__proxysockname
       +
       +    def getproxypeername(self):
       +        """getproxypeername() -> address info
       +        Returns the IP and port number of the proxy.
       +        """
       +        return _orgsocket.getpeername(self)
       +
       +    def getpeername(self):
       +        """getpeername() -> address info
       +        Returns the IP address and port number of the destination
       +        machine (note: getproxypeername returns the proxy)
       +        """
       +        return self.__proxypeername
       +
       +    def __negotiatesocks4(self,destaddr,destport):
       +        """__negotiatesocks4(self,destaddr,destport)
       +        Negotiates a connection through a SOCKS4 server.
       +        """
       +        # Check if the destination address provided is an IP address
       +        rmtrslv = False
       +        try:
       +            ipaddr = socket.inet_aton(destaddr)
       +        except socket.error:
       +            # It's a DNS name. Check where it should be resolved.
       +            if self.__proxy[3]:
       +                ipaddr = struct.pack("BBBB", 0x00, 0x00, 0x00, 0x01)
       +                rmtrslv = True
       +            else:
       +                ipaddr = socket.inet_aton(socket.gethostbyname(destaddr))
       +        # Construct the request packet
       +        req = struct.pack(">BBH", 0x04, 0x01, destport) + ipaddr
       +        # The username parameter is considered userid for SOCKS4
       +        if self.__proxy[4] != None:
       +            req = req + self.__proxy[4]
       +        req = req + chr(0x00).encode()
       +        # DNS name if remote resolving is required
       +        # NOTE: This is actually an extension to the SOCKS4 protocol
       +        # called SOCKS4A and may not be supported in all cases.
       +        if rmtrslv:
       +            req = req + destaddr + chr(0x00).encode()
       +        self.sendall(req)
       +        # Get the response from the server
       +        resp = self.__recvall(8)
       +        if resp[0:1] != chr(0x00).encode():
       +            # Bad data
       +            self.close()
       +            raise GeneralProxyError((1,_generalerrors[1]))
       +        if resp[1:2] != chr(0x5A).encode():
       +            # Server returned an error
       +            self.close()
       +            if ord(resp[1:2]) in (91, 92, 93):
       +                self.close()
       +                raise Socks4Error((ord(resp[1:2]), _socks4errors[ord(resp[1:2]) - 90]))
       +            else:
       +                raise Socks4Error((94, _socks4errors[4]))
       +        # Get the bound address/port
       +        self.__proxysockname = (socket.inet_ntoa(resp[4:]), struct.unpack(">H", resp[2:4])[0])
       +        if rmtrslv != None:
       +            self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
       +        else:
       +            self.__proxypeername = (destaddr, destport)
       +
       +    def __negotiatehttp(self, destaddr, destport):
       +        """__negotiatehttp(self,destaddr,destport)
       +        Negotiates a connection through an HTTP server.
       +        """
       +        # If we need to resolve locally, we do this now
       +        if not self.__proxy[3]:
       +            addr = socket.gethostbyname(destaddr)
       +        else:
       +            addr = destaddr
       +        self.sendall(("CONNECT " + addr + ":" + str(destport) + " HTTP/1.1\r\n" + "Host: " + destaddr + "\r\n\r\n").encode())
       +        # We read the response until we get the string "\r\n\r\n"
       +        resp = self.recv(1)
       +        while resp.find("\r\n\r\n".encode()) == -1:
       +            resp = resp + self.recv(1)
       +        # We just need the first line to check if the connection
       +        # was successful
       +        statusline = resp.splitlines()[0].split(" ".encode(), 2)
       +        if statusline[0] not in ("HTTP/1.0".encode(), "HTTP/1.1".encode()):
       +            self.close()
       +            raise GeneralProxyError((1, _generalerrors[1]))
       +        try:
       +            statuscode = int(statusline[1])
       +        except ValueError:
       +            self.close()
       +            raise GeneralProxyError((1, _generalerrors[1]))
       +        if statuscode != 200:
       +            self.close()
       +            raise HTTPError((statuscode, statusline[2]))
       +        self.__proxysockname = ("0.0.0.0", 0)
       +        self.__proxypeername = (addr, destport)
       +
       +    def connect(self, destpair):
       +        """connect(self, despair)
       +        Connects to the specified destination through a proxy.
       +        destpar - A tuple of the IP/DNS address and the port number.
       +        (identical to socket's connect).
       +        To select the proxy server use setproxy().
       +        """
       +        # Do a minimal input check first
       +        if (not type(destpair) in (list,tuple)) or (len(destpair) < 2) or (type(destpair[0]) != type('')) or (type(destpair[1]) != int):
       +            raise GeneralProxyError((5, _generalerrors[5]))
       +        if self.__proxy[0] == PROXY_TYPE_SOCKS5:
       +            if self.__proxy[2] != None:
       +                portnum = self.__proxy[2]
       +            else:
       +                portnum = 1080
       +            _orgsocket.connect(self, (self.__proxy[1], portnum))
       +            self.__negotiatesocks5(destpair[0], destpair[1])
       +        elif self.__proxy[0] == PROXY_TYPE_SOCKS4:
       +            if self.__proxy[2] != None:
       +                portnum = self.__proxy[2]
       +            else:
       +                portnum = 1080
       +            _orgsocket.connect(self,(self.__proxy[1], portnum))
       +            self.__negotiatesocks4(destpair[0], destpair[1])
       +        elif self.__proxy[0] == PROXY_TYPE_HTTP:
       +            if self.__proxy[2] != None:
       +                portnum = self.__proxy[2]
       +            else:
       +                portnum = 8080
       +            _orgsocket.connect(self,(self.__proxy[1], portnum))
       +            self.__negotiatehttp(destpair[0], destpair[1])
       +        elif self.__proxy[0] == None:
       +            _orgsocket.connect(self, (destpair[0], destpair[1]))
       +        else:
       +            raise GeneralProxyError((4, _generalerrors[4]))
   DIR diff --git a/lib/wallet.py b/lib/wallet.py
       t@@ -347,15 +347,16 @@ class Wallet:
            def is_up_to_date(self):
                return self.interface.responses.empty() and not self.interface.unanswered_requests
        
       -    def set_server(self, server):
       +    def set_server(self, server, proxy):
                # raise an error if the format isnt correct
                a,b,c = server.split(':')
                b = int(b)
                assert c in ['t', 'h', 'n']
                # set the server
       -        if server != self.server:
       +        if server != self.server or proxy != self.interface.proxy:
                    self.server = server
                    self.save()
       +            self.interface.proxy = proxy
                    self.interface.is_connected = False  # this exits the polling loop
                    self.interface.poke()
        
   DIR diff --git a/setup.py b/setup.py
       t@@ -55,6 +55,7 @@ setup(name = "Electrum",
                          'electrum.qrscanner',
                          'electrum.history_widget',
                          'electrum.simple_config',
       +                  'electrum.socks',
                          'electrum.bmp',
                          'electrum.msqr',
                          'electrum.util',