URI: 
       tMerge branch 'master' of git://github.com/spesmilo/electrum - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 3f919e193b15a6096d120828fd742188b6578497
   DIR parent 2959a29134f87298a64a66536e7b4bb4601774b3
  HTML Author: slush0 <info@bitcoin.cz>
       Date:   Fri, 18 Jan 2013 13:10:02 +0000
       
       Merge branch 'master' of git://github.com/spesmilo/electrum
       
       Diffstat:
         M README                              |       6 +++---
         M RELEASE-NOTES                       |      52 +++++++++++++++++++++++++++++++
         A TODOLIST                            |      23 +++++++++++++++++++++++
         M app.fil                             |       1 +
         M contrib/build-wine/README           |       2 +-
         M contrib/build-wine/build-electrum-… |       2 +-
         M contrib/build-wine/build-electrum.… |       6 +++---
         M contrib/build-wine/prepare-wine.sh  |       2 +-
         M data/cleanlook/style.css            |      53 ++++---------------------------
         A data/sahara/name.cfg                |       1 +
         A data/sahara/style.css               |     102 +++++++++++++++++++++++++++++++
         M electrum                            |      75 +++++++++++++++++++------------
         M icons.qrc                           |       1 +
         A icons/switchgui.png                 |       0 
         M lib/__init__.py                     |       4 +++-
         M lib/bitcoin.py                      |      87 +++++++++++++++++++++++++++++--
         M lib/exchange_rate.py                |      23 ++++++++++++-----------
         M lib/gui.py                          |       9 +++------
         M lib/gui_android.py                  |      10 ++++++----
         M lib/gui_lite.py                     |     203 +++++++++++++++++--------------
         M lib/gui_qt.py                       |     737 +++++++++++++++++++++++--------
         M lib/history_widget.py               |       2 ++
         M lib/i18n.py                         |      36 +++++++++++++++++++++++++++----
         M lib/interface.py                    |      43 ++++++++++++++++++++++++-------
         M lib/simple_config.py                |       2 +-
         M lib/verifier.py                     |       3 ++-
         M lib/version.py                      |       8 ++++----
         M lib/wallet.py                       |     126 ++++++++++++++++++++-----------
         A lib/wallet_bitkey.py                |      28 ++++++++++++++++++++++++++++
         A lib/wallet_factory.py               |      11 +++++++++++
         M setup-release.py                    |       2 +-
         M setup.py                            |       6 ++++++
       
       32 files changed, 1211 insertions(+), 455 deletions(-)
       ---
   DIR diff --git a/README b/README
       t@@ -1,9 +1,9 @@
        Electrum - lightweight Bitcoin client
        
        Licence: GNU GPL v3
       -Author: thomasv@gitorious
       +Author: thomasv@bitcointalk.org
        Language: Python
       -Homepage: http://electrum.ecdsa.org/
       +Homepage: http://electrum.org/
        
        
        == INSTALL ==
       t@@ -42,4 +42,4 @@ On Mac OS X:
        
        == BROWSER CONFIGURATION ==
        
       -see http://ecdsa.org/bitcoin_URIs.html
       +See http://electrum.org/bitcoin_URIs.html
   DIR diff --git a/RELEASE-NOTES b/RELEASE-NOTES
       t@@ -1,3 +1,55 @@
       +# Release 1.6.2 (Not released)
       +
       +== Classic GUI
       +* Added new version notification
       +
       +# Release 1.6.1 (11-01-2013)
       +
       +== Core
       +* It is now possible to restore a wallet from MPK (this will create a watching-only wallet)
       +* A switch button allows to easily switch between Lite and Classic GUI.
       +
       +== Classic GUI
       +* Seed and MPK help dialogs were rewritten
       +* Point of Sale: requested amounts can be expressed in other currencies and are converted to bitcoin.
       +
       +== Lite GUI
       +* The receiving button was removed in favor of a menu item to keep it consistent with the history toggle.
       +
       +# Release 1.6.0 (07-01-2013)
       +
       +== Core
       +* (Feature) Add support for importing, signing and verifiying compressed keys
       +* (Feature) Auto reconnect to random server on disconnect
       +* (Feature) Ultimate fallback to HTTP port 80 if TCP doesn't work on any server
       +* (Bug) Under rare circumstances changing password with incorrect password could damage wallet
       +
       +== Lite GUI
       +* (Chore) Use blockchain.info for exchange rate data 
       +* (Feature) added currency conversion for BRL, CNY, RUB
       +* (Feature) Saraha theme
       +* (Feature) csv import/export for transactions including labels 
       +
       +== Classic GUI
       +* (Chore) pruning servers now called "p", full servers "f" to avoid confusion with terms
       +* (Feature) Debits in history shown in red
       +* (Feature) csv import/export for transactions including labels 
       +
       +# Release 1.5.8 (02-01-2013)
       +
       +== Core
       +* (Bug) Fix pending address balance on received coins for pruning servers 
       +* (Bug) Fix history command line option to show output again (regression by SPV)
       +* (Chore) Add timeout to blockchain headers file download by HTTP
       +* (Feature) new option: -L, --language: default language used in GUI. 
       +
       +== Lite GUI
       +* (Bug) Sending to auto-completed contacts works again
       +* (Chore) Added version number to title bar
       +
       +== Classic GUI
       +* (Feature) Language selector in options.
       +
        # Release 1.5.7 (18-12-2012)
        
        == Core
   DIR diff --git a/TODOLIST b/TODOLIST
       t@@ -0,0 +1,23 @@
       +
       +security:
       + - check that we are on the longest chain after a reorg
       + - check SSL cerfificates of servers
       +
       +
       +wallet, transactions : 
       + - dust sweeping
       + - transactions with multiple outputs
       + - BIP 32 
       +
       +
       +code improvements:
       + - qrcode and bmp patches are on github (they are incompatible with android)
       +
       +
       +android: 
       + - kivy-based gui
       +
       +
       +protocol:
       + - add client authentication, to make paying servers possible
       +
   DIR diff --git a/app.fil b/app.fil
       t@@ -1,2 +1,3 @@
        lib/gui_qt.py
        lib/gui.py
       +lib/gui_lite.py
   DIR diff --git a/contrib/build-wine/README b/contrib/build-wine/README
       t@@ -1,7 +1,7 @@
        These scripts can be used for cross-compilation of Windows Electrum executables from Linux/Wine.
        
        Usage:
       -1. Copy content of this directory to /electrum-wine.
       +1. Copy content of this directory to /build-wine.
        2. Install Wine (version 1.4 or 1.5+ works fine, 1.4.1 has bug).
        3. Run "./prepare-wine.sh", it will download all dependencies. When you'll be asked, always leave default settings and press "Next >".
        4. By running "./build-electrum.sh", sources will be packed into three separate versions to dist/ directory:
   DIR diff --git a/contrib/build-wine/build-electrum-git.sh b/contrib/build-wine/build-electrum-git.sh
       t@@ -6,7 +6,7 @@ BRANCH=master
        NAME_ROOT=electrum
        
        # These settings probably don't need any change
       -export WINEPREFIX=~/.wine-electrum
       +export WINEPREFIX=/opt/wine-electrum
        PYHOME=c:/python26
        PYTHON="wine $PYHOME/python.exe -OO -B"
        
   DIR diff --git a/contrib/build-wine/build-electrum.sh b/contrib/build-wine/build-electrum.sh
       t@@ -1,11 +1,11 @@
        #!/bin/bash
        
        # You probably need to update only this link
       -ELECTRUM_URL=https://github.com/downloads/spesmilo/electrum/Electrum-1.5.6.tar.gz
       -NAME_ROOT=electrum-1.5.6
       +ELECTRUM_URL=https://github.com/downloads/spesmilo/electrum/Electrum-1.6.1.tar.gz
       +NAME_ROOT=electrum-1.6.1
        
        # These settings probably don't need any change
       -export WINEPREFIX=~/.wine-electrum
       +export WINEPREFIX=/opt/wine-electrum
        PYHOME=c:/python26
        PYTHON="wine $PYHOME/python.exe -OO -B"
        
   DIR diff --git a/contrib/build-wine/prepare-wine.sh b/contrib/build-wine/prepare-wine.sh
       t@@ -9,7 +9,7 @@ NSIS_URL=http://prdownloads.sourceforge.net/nsis/nsis-2.46-setup.exe?download
        #ZBAR_URL=http://sourceforge.net/projects/zbar/files/zbar/0.10/zbar-0.10-setup.exe/download
        
        # These settings probably don't need change
       -export WINEPREFIX=~/.wine-electrum
       +export WINEPREFIX=/opt/wine-electrum
        PYHOME=c:/python26
        PYTHON="wine $PYHOME/python.exe -OO -B"
        
   DIR diff --git a/data/cleanlook/style.css b/data/cleanlook/style.css
       t@@ -9,19 +9,18 @@ MiniWindow QPushButton {
          border-radius: 0px;
          background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
          stop: 0 white, stop: 1 #E6E6E6);
       -  min-height: 25px;
       +  min-height: 30px;
          min-width: 30px;
        }
        
        #send_button{
       -  color: #E5F2FF;
       +  color: #FFF;
          border: 1px solid #3786E6;
          border-radius: 4px;
          background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
          stop: 0 #72B2F8, stop: 1 #3484E6);
       -  min-width: 80px;
       -  min-height: 23px;
          padding: 2px;
       +  width: 20px;
        }
        
        #send_button:disabled{
       t@@ -30,71 +29,33 @@ MiniWindow QPushButton {
          border-radius: 4px;
          background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
          stop: 0 #A5CFFA, stop: 1 #72B2F8);
       -  min-width: 80px;
       -  min-height: 23px;
       -  padding: 2px;
        }
       -#receive_button
       -{
       -  color: #777;
       -  border: 1px solid #CCC;
       -  border-radius: 0px;
       -  background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
       -  stop: 0 white, stop: 1 #E6E6E6);
       -  min-height: 25px;
       -  min-width: 30px;
       -}          
       -#receive_button[isActive=true]
       -{
       -  color: #575757;
       -  background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
       -  stop: 0 white, stop: 1 #D1D1D1);
       -}          
       -
        #address_input, #amount_input, #label_input
        {
            color: #000;
            padding: 5px;
       -    border-radius: 4px;
       +    border-radius: 5px;
       +    min-height: 23px;
            border: 1px solid #AAA9A9;
       -    width: 225px;
       +    width: 200px;
        }
        
        #address_input[isValid=true]
        {
          color: #4D9948;
       -  padding: 5px;
       -  border-radius: 4px;
       -  border: 1px solid #AAA9A9;
       -  width: 225px;
       -  margin-top: 4px;
        }
        
        #address_input[isValid=false]
        {
          color: #CE4141;
       -  padding: 5px;
       -  border-radius: 4px;
       -  border: 1px solid #AAA9A9;
       -  width: 225px;
       -  margin-top: 4px;
        }
        
       -#address_input[isValid=placeholder]
       -{
       -  color: blue;
       -  padding: 5px;
       -  border-radius: 4px;
       -  border: 1px solid #AAA9A9;
       -  width: 225px;
       -  margin-top: 4px;
       -}
        #balance_label
        {
            color: #333;
        }
        
       -#history::item
       +#history
        {
            color: #888;
        }
   DIR diff --git a/data/sahara/name.cfg b/data/sahara/name.cfg
       t@@ -0,0 +1 @@
       +Sahara
   DIR diff --git a/data/sahara/style.css b/data/sahara/style.css
       t@@ -0,0 +1,102 @@
       +#main_window
       +{
       +  background: qlineargradient(x1: 0, y1: 0, x2:0,y2:1, stop: 0 white , stop: 1 #F2E3BE);
       +}
       +
       +MiniWindow QPushButton {
       +  color: #C1A76D;
       +  border: 1px solid #A7811C;
       +  border-radius: 0px;
       +  background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
       +  stop: 0 white, stop: 1 #F2E3BE);
       +  min-height: 25px;
       +  min-width: 30px;
       +}
       +
       +#send_button{
       +  color: #FEEBA7;
       +  border: 1px solid #AD8B35;
       +  border-radius: 4px;
       +  background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
       +  stop: 0 #E0A035, stop: 1 #AD8B35);
       +  min-width: 80px;
       +  min-height: 23px;
       +  padding: 2px;
       +}
       +
       +#send_button:disabled{
       +  color: #FEEDD3;
       +  border: 1px solid #F7D46D;
       +  border-radius: 4px;
       +  background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
       +  stop: 0 #FAEEA5, stop: 1 #DBC050);
       +  min-width: 80px;
       +  min-height: 23px;
       +  padding: 2px;
       +}
       +
       +#receive_button
       +{
       +  color: #FEEBA7;
       +  border: 1px solid #AD8B35;
       +  border-radius: 4px;
       +  background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
       +  stop: 0 #E0A035, stop: 1 #AD8B35);
       +  min-height: 25px;
       +  min-width: 30px;
       +}          
       +#receive_button[isActive=true]
       +{
       +  color: #FEEBA7;
       +  background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
       +  stop: 0 #E0A035, stop: 1 #987620);
       +} 
       +
       +#address_input, #amount_input
       +{
       +    color: #000;
       +    padding: 5px;
       +    border-radius: 4px;
       +    border: 1px solid #CBAE69;
       +    width: 225px;
       +}
       +
       +#address_input[isValid=true]
       +{
       +  color: #4D9948;
       +  padding: 5px;
       +  border-radius: 4px;
       +  border: 1px solid #CBAE69;
       +  width: 225px;
       +  margin-top: 4px;
       +}
       +
       +#address_input[isValid=false]
       +{
       +  color: #CE4141;
       +  padding: 5px;
       +  border-radius: 4px;
       +  border: 1px solid #CBAE69;
       +  width: 225px;
       +  margin-top: 4px;
       +}
       +
       +#address_input[isValid=placeholder]
       +{
       +  color: #DEC58D;
       +  padding: 5px;
       +  border-radius: 4px;
       +  border: 1px solid #CBAE69;
       +  width: 225px;
       +  margin-top: 4px;
       +}
       +#balance_label
       +{
       +    color: #7E5907;
       +}
       +
       +#history
       +{
       +    color: #8B6914;
       +}
       +
   DIR diff --git a/electrum b/electrum
       t@@ -70,8 +70,8 @@ options:\n  --fee, -f: set transaction fee\n  --fromaddr, -s: send from address 
            'signtx':"Sign an unsigned transaction created by a deseeded wallet\nSyntax: signtx <filename>",
            'seed':
                    "Print the generation seed of your wallet.",
       -    'import': 
       -            'Imports a key pair\nSyntax: import <address>:<privatekey>',
       +    'importprivkey': 
       +            'Import a private key\nSyntax: importprivkey <privatekey>',
            'signmessage':
                    'Signs a message with a key\nSyntax: signmessage <address> <message>\nIf you want to lead or end a message with spaces, or want double spaces inside the message make sure you quote the string. I.e. " Hello  This is a weird String "',
            'verifymessage':
       t@@ -99,13 +99,13 @@ offline_commands = [ 'password', 'mktx', 'signtx',
                             'help', 'validateaddress',
                             'signmessage', 'verifymessage',
                             'eval', 'set', 'get', 'create', 'addresses',
       -                     'import', 'seed',
       +                     'importprivkey', 'seed',
                             'deseed','reseed',
                             'freeze','unfreeze',
                             'prioritize','unprioritize']
        
        
       -protected_commands = ['payto', 'password', 'mktx', 'signtx', 'seed', 'import','signmessage' ]
       +protected_commands = ['payto', 'password', 'mktx', 'signtx', 'seed', 'importprivkey','signmessage' ]
        
        # get password routine
        def prompt_password(prompt, confirm=True):
       t@@ -138,6 +138,8 @@ def arg_parser():
            parser.add_option("-p", "--proxy", dest="proxy", default=None, help="set proxy [type:]host[:port], where type is socks4,socks5 or http")
            parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False, help="show debugging information")
            parser.add_option("-P", "--portable", action="store_true", dest="portable", default=False, help="portable wallet")
       +    parser.add_option("-L", "--lang", dest="language", default=None, help="defaut language used in GUI")
       +    parser.add_option("-u", "--usb", dest="bitkey", action="store_true", help="Turn on support for hardware wallets (EXPERIMENTAL)")
            return parser
        
        
       t@@ -204,8 +206,10 @@ if __name__ == '__main__':
                interface = Interface(config, True)
                wallet.interface = interface
                interface.start()
       -        interface.send([('server.peers.subscribe',[])])
       +        if interface.is_connected:
       +            interface.send([('server.peers.subscribe',[])])
        
       +        set_language(config.get('language'))
                gui = gui.ElectrumGui(wallet, config)
        
                found = config.wallet_file_exists
       t@@ -220,8 +224,18 @@ if __name__ == '__main__':
                        wallet.init_mpk( wallet.seed )
                    else:
                        # ask for seed and gap.
       -                if not gui.seed_dialog(): exit()
       -                wallet.init_mpk( wallet.seed )
       +                sg = gui.seed_dialog()
       +                if not sg: exit()
       +                seed, gap = sg
       +                if not seed: exit()
       +                wallet.gap_limit = gap
       +                if len(seed) == 128:
       +                    wallet.seed = None
       +                    wallet.master_public_key = seed
       +                else:
       +                    wallet.seed = str(seed)
       +                    wallet.init_mpk( wallet.seed )
       +            
        
                    # generate the first addresses, in case we are offline
                    if s is None or a == 'create':
       t@@ -301,10 +315,14 @@ if __name__ == '__main__':
                    if not seed:
                        sys.exit("Error: No seed")
        
       -            wallet.seed = str(seed)
       -            wallet.init_mpk( wallet.seed )
       -            if not options.offline:
       +            if len(seed) == 128:
       +                wallet.seed = None
       +                wallet.master_public_key = seed
       +            else:
       +                wallet.seed = str(seed)
       +                wallet.init_mpk( wallet.seed )
        
       +            if not options.offline:
                        interface = Interface(config)
                        interface.start()
                        wallet.interface = interface
       t@@ -378,24 +396,31 @@ if __name__ == '__main__':
        
            # commands needing password
            if cmd in protected_commands or ( cmd=='addresses' and options.show_keys):
       -        password = prompt_password('Password:', False) if wallet.use_encryption and not is_temporary else None
       -        # check password
       -        try:
       -            wallet.pw_decode( wallet.seed, password)
       -        except:
       -            print_msg("Error: This password does not decode this wallet.")
       -            exit(1)
       +        if wallet.use_encryption and not is_temporary:
       +            password = prompt_password('Password:', False)
       +            if not password:
       +                print_msg("Error: Password required")
       +                exit(1)
       +            # check password
       +            try:
       +                seed = wallet.decode_seed(password)
       +            except:
       +                print_msg("Error: This password does not decode this wallet.")
       +                exit(1)
       +        else:
       +            password = None
       +            seed = wallet.seed
        
       -    if cmd == 'import':
       +    if cmd == 'importprivkey':
                # See if they specificed a key on the cmd line, if not prompt
                if len(args) > 1:
       -            keypair = args[1]
       +            sec = args[1]
                else:
       -            keypair = prompt_password('Enter Address:PrivateKey (will not echo):', False)
       +            sec = prompt_password('Enter PrivateKey (will not echo):', False)
                try:
       -            wallet.import_key(keypair,password)
       +            addr = wallet.import_key(sec,password)
                    wallet.save()
       -            print_msg("Keypair imported")
       +            print_msg("Keypair imported: ", addr)
                except BaseException as e:
                    print_msg("Error: Keypair import failed: " + str(e))
        
       t@@ -410,7 +435,6 @@ if __name__ == '__main__':
                    print_msg(known_commands[cmd2])
        
            elif cmd == 'seed':
       -        seed = wallet.pw_decode( wallet.seed, password)
                print_msg(seed + ' "' + ' '.join(mnemonic_encode(seed)) + '"')
        
            elif cmd == 'deseed':
       t@@ -613,11 +637,6 @@ if __name__ == '__main__':
                print_msg(h)
        
            elif cmd == 'password':
       -        try:
       -            seed = wallet.pw_decode( wallet.seed, password)
       -        except ValueError:
       -            sys.exit("Error: Password does not decrypt this wallet.")
       -
                new_password = prompt_password('New password:')
                wallet.update_password(seed, password, new_password)
        
   DIR diff --git a/icons.qrc b/icons.qrc
       t@@ -13,6 +13,7 @@
            <file>icons/status_connected.png</file>
            <file>icons/status_disconnected.png</file>
            <file>icons/status_waiting.png</file>
       +    <file>icons/switchgui.png</file>
            <file>icons/unconfirmed.png</file>
            <file>icons/network.png</file>
          </qresource>
   DIR diff --git a/icons/switchgui.png b/icons/switchgui.png
       Binary files differ.
   DIR diff --git a/lib/__init__.py b/lib/__init__.py
       t@@ -1,6 +1,8 @@
        from version import ELECTRUM_VERSION
        from util import format_satoshis, print_msg, print_error, set_verbosity
       -from wallet import Wallet, WalletSynchronizer
       +from i18n import set_language
       +from wallet import WalletSynchronizer
       +from wallet_factory import WalletFactory as Wallet
        from verifier import WalletVerifier
        from interface import Interface, pick_random_server, DEFAULT_SERVERS
        from simple_config import SimpleConfig
   DIR diff --git a/lib/bitcoin.py b/lib/bitcoin.py
       t@@ -43,8 +43,57 @@ Hash = lambda x: hashlib.sha256(hashlib.sha256(x).digest()).digest()
        hash_encode = lambda x: x[::-1].encode('hex')
        hash_decode = lambda x: x.decode('hex')[::-1]
        
       -############ functions from pywallet ##################### 
        
       +# pywallet openssl private key implementation
       +
       +def i2d_ECPrivateKey(pkey, compressed=False):
       +    if compressed:
       +        key = '3081d30201010420' + \
       +              '%064x' % pkey.secret + \
       +              'a081a53081a2020101302c06072a8648ce3d0101022100' + \
       +              '%064x' % _p + \
       +              '3006040100040107042102' + \
       +              '%064x' % _Gx + \
       +              '022100' + \
       +              '%064x' % _r + \
       +              '020101a124032200'
       +    else:
       +        key = '308201130201010420' + \
       +              '%064x' % pkey.secret + \
       +              'a081a53081a2020101302c06072a8648ce3d0101022100' + \
       +              '%064x' % _p + \
       +              '3006040100040107044104' + \
       +              '%064x' % _Gx + \
       +              '%064x' % _Gy + \
       +              '022100' + \
       +              '%064x' % _r + \
       +              '020101a144034200'
       +        
       +    return key.decode('hex') + i2o_ECPublicKey(pkey, compressed)
       +    
       +def i2o_ECPublicKey(pkey, compressed=False):
       +    # public keys are 65 bytes long (520 bits)
       +    # 0x04 + 32-byte X-coordinate + 32-byte Y-coordinate
       +    # 0x00 = point at infinity, 0x02 and 0x03 = compressed, 0x04 = uncompressed
       +    # compressed keys: <sign> <x> where <sign> is 0x02 if y is even and 0x03 if y is odd
       +    if compressed:
       +        if pkey.pubkey.point.y() & 1:
       +            key = '03' + '%064x' % pkey.pubkey.point.x()
       +        else:
       +            key = '02' + '%064x' % pkey.pubkey.point.x()
       +    else:
       +        key = '04' + \
       +              '%064x' % pkey.pubkey.point.x() + \
       +              '%064x' % pkey.pubkey.point.y()
       +            
       +    return key.decode('hex')
       +            
       +# end pywallet openssl private key implementation
       +
       +                                                
       +            
       +############ functions from pywallet ##################### 
       +            
        addrtype = 0
        
        def hash_160(public_key):
       t@@ -151,17 +200,39 @@ def DecodeBase58Check(psz):
        def PrivKeyToSecret(privkey):
            return privkey[9:9+32]
        
       -def SecretToASecret(secret):
       -    vchIn = chr(addrtype+128) + secret
       +def SecretToASecret(secret, compressed=False):
       +    vchIn = chr((addrtype+128)&255) + secret
       +    if compressed: vchIn += '\01'
            return EncodeBase58Check(vchIn)
        
        def ASecretToSecret(key):
            vch = DecodeBase58Check(key)
       -    if vch and vch[0] == chr(addrtype+128):
       +    if vch and vch[0] == chr((addrtype+128)&255):
                return vch[1:]
            else:
                return False
        
       +def regenerate_key(sec):
       +    b = ASecretToSecret(sec)
       +    if not b:
       +        return False
       +    b = b[0:32]
       +    secret = int('0x' + b.encode('hex'), 16)
       +    return EC_KEY(secret)
       +
       +def GetPubKey(pkey, compressed=False):
       +    return i2o_ECPublicKey(pkey, compressed)
       +
       +def GetPrivKey(pkey, compressed=False):
       +    return i2d_ECPrivateKey(pkey, compressed)
       +
       +def GetSecret(pkey):
       +    return ('%064x' % pkey.secret).decode('hex')
       +
       +def is_compressed(sec):
       +    b = ASecretToSecret(sec)
       +    return len(b) == 33
       +
        ########### end pywallet functions #######################
        
        # secp256k1, http://www.oid-info.com/get/1.3.132.0.10
       t@@ -176,6 +247,13 @@ generator_secp256k1 = ecdsa.ellipticcurve.Point( curve_secp256k1, _Gx, _Gy, _r )
        oid_secp256k1 = (1,3,132,0,10)
        SECP256k1 = ecdsa.curves.Curve("SECP256k1", curve_secp256k1, generator_secp256k1, oid_secp256k1 ) 
        
       +class EC_KEY(object):
       +    def __init__( self, secret ):
       +        self.pubkey = ecdsa.ecdsa.Public_key( generator_secp256k1, generator_secp256k1 * secret )
       +        self.privkey = ecdsa.ecdsa.Private_key( self.pubkey, secret )
       +        self.secret = secret
       +        
       +
        
        def filter(s): 
            out = re.sub('( [^\n]*|)\n','',s)
       t@@ -195,7 +273,6 @@ def raw_tx( inputs, outputs, for_sig = None ):
                    sig = sig + chr(1)                               # hashtype
                    script  = int_to_hex( len(sig))                  +  '     push %d bytes\n'%len(sig)
                    script += sig.encode('hex')                      +  '     sig\n'
       -            pubkey = chr(4) + pubkey
                    script += int_to_hex( len(pubkey))               +  '     push %d bytes\n'%len(pubkey)
                    script += pubkey.encode('hex')                   +  '     pubkey\n'
                elif for_sig==i:
   DIR diff --git a/lib/exchange_rate.py b/lib/exchange_rate.py
       t@@ -28,31 +28,32 @@ class Exchanger(threading.Thread):
                self.discovery()
        
            def discovery(self):
       -        connection = httplib.HTTPSConnection('intersango.com')
       -        connection.request("GET", "/api/ticker.php")
       +        try:
       +            connection = httplib.HTTPSConnection('blockchain.info')
       +            connection.request("GET", "/ticker")
       +        except:
       +            return
                response = connection.getresponse()
                if response.reason == httplib.responses[httplib.NOT_FOUND]:
                    return
                response = json.loads(response.read())
       -        # 1 = BTC:GBP
       -        # 2 = BTC:EUR
       -        # 3 = BTC:USD
       -        # 4 = BTC:PLN
                quote_currencies = {}
                try:
       -            quote_currencies["GBP"] = self._lookup_rate(response, 1)
       -            quote_currencies["EUR"] = self._lookup_rate(response, 2)
       -            quote_currencies["USD"] = self._lookup_rate(response, 3)
       +            for r in response:
       +                quote_currencies[r] = self._lookup_rate(response, r)
                    with self.lock:
                        self.quote_currencies = quote_currencies
                    self.parent.emit(SIGNAL("refresh_balance()"))
                except KeyError:
                    pass
       +            
       +    def get_currencies(self):
       +        return [] if self.quote_currencies == None else sorted(self.quote_currencies.keys())
        
            def _lookup_rate(self, response, quote_id):
       -        return decimal.Decimal(response[str(quote_id)]["last"])
       +        return decimal.Decimal(str(response[str(quote_id)]["15m"]))
        
        if __name__ == "__main__":
       -    exch = Exchanger(("EUR", "USD", "GBP"))
       +    exch = Exchanger(("BRL", "CNY", "EUR", "GBP", "RUB", "USD"))
            print exch.exchange(1, "EUR")
        
   DIR diff --git a/lib/gui.py b/lib/gui.py
       t@@ -65,7 +65,7 @@ def show_seed_dialog(wallet, password, parent):
                show_message("No seed")
                return
            try:
       -        seed = wallet.pw_decode( wallet.seed, password)
       +        seed = wallet.decode_seed(password)
            except:
                show_message("Incorrect password")
                return
       t@@ -164,10 +164,7 @@ def run_recovery_dialog(wallet):
                show_message("no seed")
                return False
                
       -    wallet.seed = seed
       -    wallet.gap_limit = gap
       -    wallet.save()
       -    return True
       +    return seed, gap
        
        
        
       t@@ -477,7 +474,7 @@ def change_password_dialog(wallet, parent, icon):
                return
        
            try:
       -        seed = wallet.pw_decode( wallet.seed, password)
       +        seed = wallet.decode_seed(password)
            except:
                show_message("Incorrect password")
                return
   DIR diff --git a/lib/gui_android.py b/lib/gui_android.py
       t@@ -709,7 +709,7 @@ def seed_dialog():
                password = None
            
            try:
       -        seed = wallet.pw_decode( wallet.seed, password)
       +        seed = wallet.decode_seed(password)
            except:
                modal_dialog('error','incorrect password')
                return
       t@@ -725,7 +725,7 @@ def change_password_dialog():
                password = None
        
            try:
       -        seed = wallet.pw_decode( wallet.seed, password)
       +        seed = wallet.decode_seed(password)
            except:
                modal_dialog('error','incorrect password')
                return
       t@@ -956,8 +956,10 @@ class ElectrumGui:
                    except:
                        modal_dialog('error: could not decode this seed')
                        return
       -        wallet.seed = str(seed)
       -        return True
       +
       +        gap = 5   # default
       +
       +        return str(seed), gap
        
        
            def network_dialog(self):
   DIR diff --git a/lib/gui_lite.py b/lib/gui_lite.py
       t@@ -31,6 +31,7 @@ import util
        import csv 
        import datetime
        
       +from version import ELECTRUM_VERSION as electrum_version
        from wallet import format_satoshis
        import gui_qt
        import shutil
       t@@ -85,16 +86,62 @@ def load_theme_paths():
            return theme_paths
        
        
       +def csv_transaction(wallet):
       +    try:
       +        fileName = QFileDialog.getSaveFileName(QWidget(), 'Select file to export your wallet transactions to', os.path.expanduser('~/electrum-history.csv'), "*.csv")
       +        if fileName:
       +            with open(fileName, "w+") as csvfile:
       +                transaction = csv.writer(csvfile)
       +                transaction.writerow(["transaction_hash","label", "confirmations", "value", "fee", "balance", "timestamp"])
       +                for item in wallet.get_tx_history():
       +                    tx_hash, confirmations, is_mine, value, fee, balance, timestamp = item
       +                    if confirmations:
       +                        if timestamp is not None:
       +                            try:
       +                                time_string = datetime.datetime.fromtimestamp(timestamp).isoformat(' ')[:-3]
       +                            except [RuntimeError, TypeError, NameError] as reason:
       +                                time_string = "unknown"
       +                                pass
       +                        else:
       +                          time_string = "unknown"
       +                    else:
       +                        time_string = "pending"
       +
       +                    if value is not None:
       +                        value_string = format_satoshis(value, True, wallet.num_zeros)
       +                    else:
       +                        value_string = '--'
       +
       +                    if fee is not None:
       +                        fee_string = format_satoshis(fee, True, wallet.num_zeros)
       +                    else:
       +                        fee_string = '0'
       +
       +                    if tx_hash:
       +                        label, is_default_label = wallet.get_label(tx_hash)
       +                    else:
       +                      label = ""
       +
       +                    balance_string = format_satoshis(balance, False, wallet.num_zeros)
       +                    transaction.writerow([tx_hash, label, confirmations, value_string, fee_string, balance_string, time_string])
       +                QMessageBox.information(None,"CSV Export created", "Your CSV export has been successfully created.")
       +    except (IOError, os.error), reason:
       +        QMessageBox.critical(None,"Unable to create csv", "Electrum was unable to produce a transaction export.\n" + str(reason))
       +
       +
        class ElectrumGui(QObject):
        
       -    def __init__(self, wallet, config):
       +    def __init__(self, wallet, config, expert=None):
                super(QObject, self).__init__()
        
                self.wallet = wallet
                self.config = config
                self.check_qt_version()
       -        self.app = QApplication(sys.argv)
       -
       +        self.expert = expert
       +        if self.expert != None:
       +            self.app = self.expert.app
       +        else:
       +            self.app = QApplication(sys.argv)
        
            def check_qt_version(self):
                qtVersion = qVersion()
       t@@ -121,17 +168,19 @@ class ElectrumGui(QObject):
        
                if url:
                    self.set_url(url)
       -
       -        timer = Timer()
       -        timer.start()
       -        self.expert = gui_qt.ElectrumWindow(self.wallet, self.config)
       -        self.expert.app = self.app
       -        self.expert.connect_slots(timer)
       -        self.expert.update_wallet()
       -        self.app.exec_()
       +            
       +        if self.expert == None:
       +            timer = Timer()
       +            timer.start()
       +            self.expert = gui_qt.ElectrumWindow(self.wallet, self.config)
       +            self.expert.app = self.app
       +            self.expert.connect_slots(timer)
       +            self.expert.update_wallet()
       +            self.app.exec_()
        
            def expand(self):
                """Hide the lite mode window and show pro-mode."""
       +        self.config.set_key('gui', 'classic', True)
                self.mini.hide()
                self.expert.show()
        
       t@@ -196,7 +245,7 @@ class MiniWindow(QDialog):
                self.actuator = actuator
                self.config = config
                self.btc_balance = None
       -        self.quote_currencies = ["EUR", "USD", "GBP"]
       +        self.quote_currencies = ["BRL", "CNY", "EUR", "GBP", "RUB", "USD"]
                self.actuator.set_configured_currency(self.set_quote_currency)
                self.exchanger = exchange_rate.Exchanger(self)
                # Needed because price discovery is done in a different thread
       t@@ -209,12 +258,12 @@ class MiniWindow(QDialog):
        
                # Bitcoin address code
                self.address_input = QLineEdit()
       -        self.address_input.setPlaceholderText(_("Enter a Bitcoin address..."))
       +        self.address_input.setPlaceholderText(_("Enter a Bitcoin address or contact"))
                self.address_input.setObjectName("address_input")
        
                self.address_input.setFocusPolicy(Qt.ClickFocus)
        
       -        self.address_input.textEdited.connect(self.address_field_changed)
       +        self.address_input.textChanged.connect(self.address_field_changed)
                resize_line_edit_width(self.address_input,
                                       "1BtaFUr3qVvAmwrsuDuu5zk6e4s2rxd2Gy")
        
       t@@ -249,27 +298,28 @@ class MiniWindow(QDialog):
                self.send_button.clicked.connect(self.send)
        
                # Creating the receive button
       -        self.receive_button = QPushButton(_("&Receive"))
       -        self.receive_button.setObjectName("receive_button")
       -        self.receive_button.setDefault(True)
       +        self.switch_button = QPushButton( QIcon(":icons/switchgui.png"),'' )
       +        self.switch_button.setMaximumWidth(25)
       +        self.switch_button.setFlat(True)
       +        self.switch_button.clicked.connect(expand_callback)
        
                main_layout = QGridLayout(self)
        
       -        main_layout.addWidget(self.balance_label, 0, 0)
       -        main_layout.addWidget(self.receive_button, 0, 1)
       +        main_layout.addWidget(self.balance_label, 0, 0, 1, 3)
       +        main_layout.addWidget(self.switch_button, 0, 3)
        
       -        main_layout.addWidget(self.address_input, 1, 0)
       +        main_layout.addWidget(self.address_input, 1, 0, 1, 4)
       +        main_layout.addWidget(self.amount_input, 2, 0, 1, 2)
       +        main_layout.addWidget(self.send_button, 2, 2, 1, 2)
        
       -        main_layout.addWidget(self.amount_input, 2, 0)
       -        main_layout.addWidget(self.send_button, 2, 1)
       +        self.send_button.setMaximumWidth(125)
        
                self.history_list = history_widget.HistoryWidget()
                self.history_list.setObjectName("history")
                self.history_list.hide()
                self.history_list.setAlternatingRowColors(True)
        
       -        main_layout.addWidget(self.history_list, 3, 0, 1, 2)
       -        
       +        main_layout.addWidget(self.history_list, 3, 0, 1, 4)
        
                self.receiving = receiving_widget.ReceivingWidget(self)
                self.receiving.setObjectName("receiving")
       t@@ -288,6 +338,7 @@ class MiniWindow(QDialog):
                self.receiving.itemDoubleClicked.connect(self.receiving.edit_label)
                self.receiving.itemChanged.connect(self.receiving.update_label)
        
       +
                # Label
                extra_layout.addWidget( QLabel(_('Selecting an address will copy it to the clipboard.\nDouble clicking the label will allow you to edit it.') ),0,0)
        
       t@@ -296,18 +347,15 @@ class MiniWindow(QDialog):
                extra_layout.setColumnMinimumWidth(0,200)
        
                self.receiving_box.setLayout(extra_layout)
       -        main_layout.addWidget(self.receiving_box,0,3,-1,3)
       +        main_layout.addWidget(self.receiving_box,0,4,-1,3)
                self.receiving_box.hide()
        
       -        self.receive_button.clicked.connect(self.toggle_receiving_layout)
       -
                # Creating the menu bar
                menubar = QMenuBar()
       -        electrum_menu = menubar.addMenu(_("&Bitcoin"))
       +        electrum_menu = menubar.addMenu(_("&Electrum"))
        
       -        electrum_menu.addSeparator()
       +        quit_option = electrum_menu.addAction(_("&Close"))
        
       -        quit_option = electrum_menu.addAction(_("&Quit"))
                quit_option.triggered.connect(self.close)
        
                view_menu = menubar.addMenu(_("&View"))
       t@@ -317,7 +365,7 @@ class MiniWindow(QDialog):
                backup_wallet.triggered.connect(self.backup_wallet)
        
                export_csv = extra_menu.addAction( _("&Export transactions to CSV") )
       -        export_csv.triggered.connect(self.actuator.csv_transaction)
       +        export_csv.triggered.connect(lambda: csv_transaction(self.actuator.wallet))
                
                master_key = extra_menu.addAction( _("Copy master public key to clipboard") ) 
                master_key.triggered.connect(self.actuator.copy_master_public_key)
       t@@ -343,6 +391,18 @@ class MiniWindow(QDialog):
                    theme_action.toggled.connect(delegate)
                    theme_group.addAction(theme_action)
                view_menu.addSeparator()
       +
       +        show_receiving = view_menu.addAction(_("Show Receiving addresses"))
       +        show_receiving.setCheckable(True)
       +        show_receiving.toggled.connect(self.toggle_receiving_layout)
       +
       +        show_receiving_toggle = self.config.get("gui_show_receiving",False)
       +        show_receiving.setChecked(show_receiving_toggle)
       +        self.show_receiving = show_receiving
       +
       +        self.toggle_receiving_layout(show_receiving_toggle)
       +
       +
                show_history = view_menu.addAction(_("Show History"))
                show_history.setCheckable(True)
                show_history.toggled.connect(self.show_history)
       t@@ -377,19 +437,6 @@ class MiniWindow(QDialog):
                self.setObjectName("main_window")
                self.show()
        
       -    def toggle_receiving_layout(self):
       -        if self.receiving_box.isVisible():
       -            self.receiving_box.hide()
       -            self.receive_button.setProperty("isActive", False)
       -
       -            qApp.style().unpolish(self.receive_button)
       -            qApp.style().polish(self.receive_button)
       -        else:
       -            self.receiving_box.show()
       -            self.receive_button.setProperty("isActive", 'true')
       -
       -            qApp.style().unpolish(self.receive_button)
       -            qApp.style().polish(self.receive_button)
        
            def toggle_theme(self, theme_name):
                old_path = QDir.currentPath()
       t@@ -403,6 +450,7 @@ class MiniWindow(QDialog):
                g = self.geometry()
                self.config.set_key("winpos-lite", [g.left(),g.top(),g.width(),g.height()],True)
                self.config.set_key("gui_show_history", self.history_list.isVisible(),True)
       +        self.config.set_key("gui_show_receiving", self.receiving_box.isVisible(),True)
                
                super(MiniWindow, self).closeEvent(event)
                qApp.quit()
       t@@ -447,7 +495,7 @@ class MiniWindow(QDialog):
                    quote_text = "(%s)" % quote_text
                btc_balance = "%.2f" % (btc_balance / bitcoin(1))
                self.balance_label.set_balance_text(btc_balance, quote_text)
       -        self.setWindowTitle("Electrum - %s BTC" % btc_balance)
       +        self.setWindowTitle("Electrum %s - %s BTC" % (electrum_version, btc_balance))
        
            def amount_input_changed(self, amount_text):
                """Update the number of bitcoins displayed."""
       t@@ -499,6 +547,13 @@ class MiniWindow(QDialog):
                    self.send_button.setDisabled(True)
        
            def address_field_changed(self, address):
       +        # label or alias, with address in brackets
       +        match2 = re.match("(.*?)\s*\<([1-9A-HJ-NP-Za-km-z]{26,})\>",
       +                          address)
       +        if match2:
       +          address = match2.group(2)
       +          self.address_input.setText(address)
       +
                if self.actuator.is_valid(address):
                    self.check_button_status()
                    self.address_input.setProperty("isValid", True)
       t@@ -540,15 +595,21 @@ class MiniWindow(QDialog):
                self.actuator.acceptbit(self.quote_currencies[0])
        
            def the_website(self):
       -        webbrowser.open("http://electrum-desktop.com")
       +        webbrowser.open("http://electrum.org")
        
            def show_about(self):
                QMessageBox.about(self, "Electrum",
       -            _("Electrum's focus is speed, with low resource usage and simplifying Bitcoin. You do not need to perform regular backups, because your wallet can be recovered from a secret phrase that you can memorize or write on paper. Startup times are instant because it operates in conjuction with high-performance servers that handle the most complicated parts of the Bitcoin system.\n\nSend donations to 1JwTMv4GWaPdf931N6LNPJeZBfZgZJ3zX1"))
       +            _("Electrum's focus is speed, with low resource usage and simplifying Bitcoin. You do not need to perform regular backups, because your wallet can be recovered from a secret phrase that you can memorize or write on paper. Startup times are instant because it operates in conjunction with high-performance servers that handle the most complicated parts of the Bitcoin system."))
        
            def show_report_bug(self):
                QMessageBox.information(self, "Electrum - " + _("Reporting Bugs"),
       -            _("Please report any bugs as issues on github: https://github.com/spesmilo/electrum/issues"))
       +            _("Please report any bugs as issues on github: <a href=\"https://github.com/spesmilo/electrum/issues\">https://github.com/spesmilo/electrum/issues</a>"))
       +
       +    def toggle_receiving_layout(self, toggle_state):
       +        if toggle_state:
       +          self.receiving_box.show()
       +        else:
       +          self.receiving_box.hide()
        
            def show_history(self, toggle_state):
                if toggle_state:
       t@@ -684,7 +745,7 @@ class ReceivePopup(QDialog):
        
        class MiniActuator:
            """Initialize the definitions relating to themes and 
       -    sending/recieving bitcoins."""
       +    sending/receiving bitcoins."""
            
            
            def __init__(self, wallet):
       t@@ -761,47 +822,6 @@ class MiniActuator:
                w.exec_()
                w.destroy()
        
       -    def csv_transaction(self):
       -        try:
       -          fileName = QFileDialog.getSaveFileName(QWidget(), 'Select file to export your wallet transactions to', os.path.expanduser('~/'), "*.csv")
       -          if fileName:
       -            with open(fileName, "w+") as csvfile:
       -                transaction = csv.writer(csvfile)
       -                transaction.writerow(["transaction_hash","label", "confirmations", "value", "fee", "balance", "timestamp"])
       -                for item in self.wallet.get_tx_history():
       -                    tx_hash, confirmations, is_mine, value, fee, balance, timestamp = item
       -                    if confirmations:
       -                        if timestamp is not None:
       -                            try:
       -                                time_string = datetime.datetime.fromtimestamp(timestamp).isoformat(' ')[:-3]
       -                            except [RuntimeError, TypeError, NameError] as reason:
       -                                time_string = "unknown"
       -                                pass
       -                        else:
       -                          time_string = "unknown"
       -                    else:
       -                        time_string = "pending"
       -
       -                    if value is not None:
       -                        value_string = format_satoshis(value, True, self.wallet.num_zeros)
       -                    else:
       -                        value_string = '--'
       -
       -                    if fee is not None:
       -                        fee_string = format_satoshis(fee, True, self.wallet.num_zeros)
       -                    else:
       -                        fee_string = '0'
       -
       -                    if tx_hash:
       -                        label, is_default_label = self.wallet.get_label(tx_hash)
       -                    else:
       -                      label = ""
       -
       -                    balance_string = format_satoshis(balance, False, self.wallet.num_zeros)
       -                    transaction.writerow([tx_hash, label, confirmations, value_string, fee_string, balance_string, time_string])
       -                QMessageBox.information(None,"CSV Export created", "Your CSV export has been succesfully created.")
       -        except (IOError, os.error), reason:
       -          QMessageBox.critical(None,"Unable to create csv", "Electrum was unable to produce a transaction export.\n" + str(reason))
        
            def send(self, address, amount, parent_window):
                """Send bitcoins to the target address."""
       t@@ -879,12 +899,13 @@ class MiniActuator:
        
            def is_valid(self, address):
                """Check if bitcoin address is valid."""
       +
                return self.wallet.is_valid(address)
        
            def copy_master_public_key(self):
                master_pubkey = self.wallet.master_public_key
                qApp.clipboard().setText(master_pubkey)
       -        QMessageBox.information(None,"Copy succesful", "Your public master key has been copied to your clipboard.")
       +        QMessageBox.information(None,"Copy successful", "Your master public key has been copied to your clipboard.")
                
        
            def acceptbit(self, currency):
   DIR diff --git a/lib/gui_qt.py b/lib/gui_qt.py
       t@@ -19,6 +19,7 @@
        import sys, time, datetime, re
        from i18n import _
        from util import print_error
       +import os.path, json, util
        
        try:
            import PyQt4
       t@@ -38,10 +39,14 @@ except:
        
        from wallet import format_satoshis
        import bmp, mnemonic, pyqrnative, qrscanner
       +import exchange_rate
        
        from decimal import Decimal
        
        import platform
       +import httplib
       +import socket
       +import webbrowser
        
        if platform.system() == 'Windows':
            MONOSPACE_FONT = 'Lucida Console'
       t@@ -52,6 +57,81 @@ else:
        
        ALIAS_REGEXP = '^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$'    
        
       +from version import ELECTRUM_VERSION
       +import re
       +
       +class UpdateLabel(QtGui.QLabel):
       +    def __init__(self, config, parent=None):
       +        QtGui.QLabel.__init__(self, parent)
       +
       +        try:
       +            con = httplib.HTTPConnection('electrum.org', 80, timeout=5)
       +            con.request("GET", "/version")
       +            res = con.getresponse()
       +        except socket.error as msg:
       +            print_error("Could not retrieve version information")
       +            return
       +            
       +        if res.status == 200:
       +            self.latest_version = res.read()
       +            self.latest_version = self.latest_version.replace("\n","")
       +            if(re.match('^\d+(\.\d+)*$', self.latest_version)):
       +                self.config = config
       +                self.current_version = ELECTRUM_VERSION
       +                if(self.compare_versions(self.latest_version, self.current_version) == 1):
       +                    latest_seen = self.config.get("last_seen_version",ELECTRUM_VERSION)
       +                    if(self.compare_versions(self.latest_version, latest_seen) == 1):
       +                        self.setText(_("New version available") + ": " + self.latest_version)
       +
       +
       +    def compare_versions(self, version1, version2):
       +        def normalize(v):
       +            return [int(x) for x in re.sub(r'(\.0+)*$','', v).split(".")]
       +        return cmp(normalize(version1), normalize(version2))
       +
       +    def ignore_this_version(self):
       +        self.setText("")
       +        self.config.set_key("last_seen_version", self.latest_version, True)
       +        QMessageBox.information(self, _("Preference saved"), _("Notifications about this update will not be shown again."))
       +        self.dialog.done(0)
       +
       +    def ignore_all_version(self):
       +        self.setText("")
       +        self.config.set_key("last_seen_version", "9.9.9", True)
       +        QMessageBox.information(self, _("Preference saved"), _("No more notifications about version updates will be shown."))
       +        self.dialog.done(0)
       +  
       +    def open_website(self):
       +        webbrowser.open("http://electrum.org/download.html")
       +        self.dialog.done(0)
       +
       +    def mouseReleaseEvent(self, event):
       +        dialog = QDialog(self)
       +        dialog.setWindowTitle(_('Electrum update'))
       +        dialog.setModal(1)
       +
       +        main_layout = QGridLayout()
       +        main_layout.addWidget(QLabel("A new version of Electrum is available: " + self.latest_version), 0,0,1,3)
       +        
       +        ignore_version = QPushButton(_("Ignore this version"))
       +        ignore_version.clicked.connect(self.ignore_this_version)
       +
       +        ignore_all_versions = QPushButton(_("Ignore all versions"))
       +        ignore_all_versions.clicked.connect(self.ignore_all_version)
       +
       +        open_website = QPushButton(_("Goto download page"))
       +        open_website.clicked.connect(self.open_website)
       +
       +        main_layout.addWidget(ignore_version, 1, 0)
       +        main_layout.addWidget(ignore_all_versions, 1, 1)
       +        main_layout.addWidget(open_website, 1, 2)
       +
       +        dialog.setLayout(main_layout)
       +
       +        self.dialog = dialog
       +        
       +        if not dialog.exec_(): return
       +
        def numbify(entry, is_int = False):
            text = unicode(entry.text()).strip()
            pos = entry.cursorPosition()
       t@@ -137,11 +217,12 @@ class StatusBarButton(QPushButton):
        
        class QRCodeWidget(QWidget):
        
       -    def __init__(self, data = None):
       +    def __init__(self, data = None, size=4):
                QWidget.__init__(self)
                self.setMinimumSize(210, 210)
                self.addr = None
                self.qr = None
       +        self.size = size
                if data:
                    self.set_addr(data)
                    self.update_qr()
       t@@ -154,7 +235,7 @@ class QRCodeWidget(QWidget):
        
            def update_qr(self):
                if self.addr and not self.qr:
       -            self.qr = pyqrnative.QRCode(4, pyqrnative.QRErrorCorrectLevel.L)
       +            self.qr = pyqrnative.QRCode(self.size, pyqrnative.QRErrorCorrectLevel.L)
                    self.qr.addData(self.addr)
                    self.qr.make()
                    self.update()
       t@@ -166,7 +247,6 @@ class QRCodeWidget(QWidget):
        
                black = QColor(0, 0, 0, 255)
                white = QColor(255, 255, 255, 255)
       -        boxsize = 6
        
                if not self.qr:
                    qp = QtGui.QPainter()
       t@@ -176,11 +256,16 @@ class QRCodeWidget(QWidget):
                    qp.drawRect(0, 0, 198, 198)
                    qp.end()
                    return
       -        
       -        size = self.qr.getModuleCount()*boxsize
       + 
                k = self.qr.getModuleCount()
                qp = QtGui.QPainter()
                qp.begin(self)
       +        r = qp.viewport()
       +        boxsize = min(r.width(), r.height())*0.8/k
       +        size = k*boxsize
       +        left = (r.width() - size)/2
       +        top = (r.height() - size)/2         
       +
                for r in range(k):
                    for c in range(k):
                        if self.qr.isDark(r, c):
       t@@ -189,15 +274,16 @@ class QRCodeWidget(QWidget):
                        else:
                            qp.setBrush(white)
                            qp.setPen(white)
       -                qp.drawRect(c*boxsize, r*boxsize, boxsize, boxsize)
       +                qp.drawRect(left+c*boxsize, top+r*boxsize, boxsize, boxsize)
                qp.end()
                
        
        
        class QR_Window(QWidget):
        
       -    def __init__(self):
       +    def __init__(self, exchanger):
                QWidget.__init__(self)
       +        self.exchanger = exchanger
                self.setWindowTitle('Electrum - Invoice')
                self.setMinimumSize(800, 250)
                self.address = ''
       t@@ -208,13 +294,11 @@ class QR_Window(QWidget):
                main_box = QHBoxLayout()
                
                self.qrw = QRCodeWidget()
       -        main_box.addWidget(self.qrw)
       +        main_box.addWidget(self.qrw, 1)
        
                vbox = QVBoxLayout()
                main_box.addLayout(vbox)
        
       -        main_box.addStretch(1)
       -
                self.address_label = QLabel("")
                self.address_label.setFont(QFont(MONOSPACE_FONT))
                vbox.addWidget(self.address_label)
       t@@ -229,13 +313,23 @@ class QR_Window(QWidget):
                self.setLayout(main_box)
        
        
       -    def set_content(self, addr, label, amount):
       +    def set_content(self, addr, label, amount, currency):
                self.address = addr
                address_text = "<span style='font-size: 18pt'>%s</span>" % addr if addr else ""
                self.address_label.setText(address_text)
        
       -        self.amount = amount
       -        amount_text = "<span style='font-size: 21pt'>%s</span> <span style='font-size: 16pt'>BTC</span> " % format_satoshis(amount) if amount else ""
       +        if currency == 'BTC': currency = None
       +        amount_text = ''
       +        if amount:
       +            if currency:
       +                self.amount = Decimal(amount) / self.exchanger.exchange(1, currency) if currency else amount
       +            else:
       +                self.amount = Decimal(amount)
       +            self.amount = self.amount.quantize(Decimal('1.0000'))
       +
       +            if currency:
       +                amount_text += "<span style='font-size: 18pt'>%s %s</span><br/>" % (amount, currency)
       +            amount_text += "<span style='font-size: 21pt'>%s</span> <span style='font-size: 16pt'>BTC</span> " % str(self.amount) 
                self.amount_label.setText(amount_text)
        
                self.label = label
       t@@ -244,7 +338,7 @@ class QR_Window(QWidget):
        
                msg = 'bitcoin:'+self.address
                if self.amount is not None:
       -            msg += '?amount=%s'%(str( Decimal(self.amount) /100000000))
       +            msg += '?amount=%s'%(str( self.amount))
                    if self.label is not None:
                        msg += '&label=%s'%(self.label)
                elif self.label is not None:
       t@@ -288,10 +382,14 @@ def ok_cancel_buttons(dialog):
            return hbox
        
        
       +default_column_widths = { "history":[40,140,350,140,140], "contacts":[350,330,100], 
       +        "receive":[[50,310,200,130,130,10],[50,310,200,130,130,10],[50,310,200,130,130,10]] }
       +
        class ElectrumWindow(QMainWindow):
        
            def __init__(self, wallet, config):
                QMainWindow.__init__(self)
       +        self.lite = None
                self.wallet = wallet
                self.config = config
                self.wallet.interface.register_callback('updated', self.update_callback)
       t@@ -307,6 +405,7 @@ class ElectrumWindow(QMainWindow):
                self.completions = QStringListModel()
        
                self.tabs = tabs = QTabWidget(self)
       +        self.column_widths = self.config.get("column-widths", default_column_widths )
                tabs.addTab(self.create_history_tab(), _('History') )
                tabs.addTab(self.create_send_tab(), _('Send') )
                tabs.addTab(self.create_receive_tab(), _('Receive') )
       t@@ -316,7 +415,6 @@ class ElectrumWindow(QMainWindow):
                tabs.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
                self.setCentralWidget(tabs)
                self.create_status_bar()
       -        self.toggle_QR_window(self.receive_tab_mode == 2)
        
                g = self.config.get("winpos-qt",[100, 100, 840, 400])
                self.setGeometry(g[0], g[1], g[2], g[3])
       t@@ -332,6 +430,10 @@ class ElectrumWindow(QMainWindow):
                self.connect(self, QtCore.SIGNAL('updatesignal'), self.update_wallet)
                #self.connect(self, SIGNAL('editamount'), self.edit_amount)
                self.history_list.setFocus(True)
       +        
       +        self.exchanger = exchange_rate.Exchanger(self)
       +        self.toggle_QR_window(self.receive_tab_mode == 2)
       +        self.connect(self, SIGNAL("refresh_balance()"), self.update_wallet)
        
                # dark magic fix by flatfly; https://bitcointalk.org/index.php?topic=73651.msg959913#msg959913
                if platform.system() == 'Windows':
       t@@ -346,9 +448,8 @@ class ElectrumWindow(QMainWindow):
                    self.qr_window = None
        
            def connect_slots(self, sender):
       -        if self.wallet.seed:
       -            self.connect(sender, QtCore.SIGNAL('timersignal'), self.timer_actions)
       -            self.previous_payto_e=''
       +        self.connect(sender, QtCore.SIGNAL('timersignal'), self.timer_actions)
       +        self.previous_payto_e=''
        
            def timer_actions(self):
                if self.qr_window:
       t@@ -382,14 +483,13 @@ class ElectrumWindow(QMainWindow):
                        c, u = self.wallet.get_balance()
                        text =  _( "Balance" ) + ": %s "%( format_satoshis(c,False,self.wallet.num_zeros) )
                        if u: text +=  "[%s unconfirmed]"%( format_satoshis(u,True,self.wallet.num_zeros).strip() )
       +                text += self.create_quote_text(Decimal(c+u)/100000000)
                        icon = QIcon(":icons/status_connected.png")
                else:
                    text = _( "Not connected" )
                    icon = QIcon(":icons/status_disconnected.png")
        
       -        if self.funds_error:
       -            text = _( "Not enough funds" )
       -
       +        self.status_text = text
                self.statusBar().showMessage(text)
                self.status_button.setIcon( icon )
        
       t@@ -400,15 +500,20 @@ class ElectrumWindow(QMainWindow):
                    self.update_contacts_tab()
                    self.update_completions()
        
       -
       +    def create_quote_text(self, btc_balance):
       +        quote_currency = self.config.get("currency", "None")
       +        quote_balance = self.exchanger.exchange(btc_balance, quote_currency)
       +        if quote_balance is None:
       +            quote_text = ""
       +        else:
       +            quote_text = "  (%.2f %s)" % (quote_balance, quote_currency)
       +        return quote_text
       +        
            def create_history_tab(self):
                self.history_list = l = MyTreeWidget(self)
                l.setColumnCount(5)
       -        l.setColumnWidth(0, 40) 
       -        l.setColumnWidth(1, 140) 
       -        l.setColumnWidth(2, 350) 
       -        l.setColumnWidth(3, 140) 
       -        l.setColumnWidth(4, 140) 
       +        for i,width in enumerate(self.column_widths['history']):
       +            l.setColumnWidth(i, width)
                l.setHeaderLabels( [ '', _( 'Date' ), _( 'Description' ) , _('Amount'), _('Balance')] )
                self.connect(l, SIGNAL('itemDoubleClicked(QTreeWidgetItem*, int)'), self.tx_label_clicked)
                self.connect(l, SIGNAL('itemChanged(QTreeWidgetItem*, int)'), self.tx_label_changed)
       t@@ -422,7 +527,7 @@ class ElectrumWindow(QMainWindow):
                self.history_list.selectedIndexes() 
                item = self.history_list.currentItem()
                if not item: return
       -        tx_hash = str(item.toolTip(0))
       +        tx_hash = str(item.data(0, Qt.UserRole).toString())
                if not tx_hash: return
                menu = QMenu()
                menu.addAction(_("Copy ID to Clipboard"), lambda: self.app.clipboard().setText(tx_hash))
       t@@ -432,15 +537,32 @@ class ElectrumWindow(QMainWindow):
        
        
            def tx_details(self, tx_hash):
       -        tx_details = self.wallet.get_tx_details(tx_hash)
       -        QMessageBox.information(self, 'Details', tx_details, 'OK')
       +        dialog = QDialog(None)
       +        dialog.setModal(1)
       +        dialog.setWindowTitle(_("Transaction Details"))
        
       +        main_text = QTextEdit()
       +        main_text.setText(self.wallet.get_tx_details(tx_hash))
       +        main_text.setReadOnly(True)
       +        main_text.setMinimumSize(550,275)
       +        
       +        ok_button = QPushButton(_("OK"))
       +        ok_button.setDefault(True)
       +        ok_button.clicked.connect(dialog.accept)
       +        
       +        hbox = QHBoxLayout()
       +        hbox.addStretch(1)
       +        hbox.addWidget(ok_button)
       +        
       +        vbox = QVBoxLayout()
       +        vbox.addWidget(main_text)
       +        vbox.addLayout(hbox)
       +        dialog.setLayout(vbox)
       +        dialog.exec_()
        
            def tx_label_clicked(self, item, column):
                if column==2 and item.isSelected():
       -            tx_hash = str(item.toolTip(0))
                    self.is_edit=True
       -            #if not self.wallet.labels.get(tx_hash): item.setText(2,'')
                    item.setFlags(Qt.ItemIsEditable|Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled)
                    self.history_list.editItem( item, column )
                    item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled)
       t@@ -450,7 +572,7 @@ class ElectrumWindow(QMainWindow):
                if self.is_edit: 
                    return
                self.is_edit=True
       -        tx_hash = str(item.toolTip(0))
       +        tx_hash = str(item.data(0, Qt.UserRole).toString())
                tx = self.wallet.transactions.get(tx_hash)
                s = self.wallet.labels.get(tx_hash)
                text = unicode( item.text(2) )
       t@@ -522,34 +644,38 @@ class ElectrumWindow(QMainWindow):
                    self.recv_changed(item)
        
                if column == 3:
       -            address = unicode( item.text(column_addr) )
       -            text = unicode( item.text(3) )
       +            address = str( item.text(column_addr) )
       +            text = str( item.text(3) )
                    try:
                        index = self.wallet.addresses.index(address)
                    except:
                        return
        
       -            try:
       -                amount = int( Decimal(text) * 100000000 )
       -                item.setText(3,format_satoshis(amount,False, self.wallet.num_zeros))
       -            except:
       -                amount = self.wallet.requested_amounts.get(address)
       -                if amount: 
       -                    item.setText(3,format_satoshis(amount,False, self.wallet.num_zeros))
       +            text = text.strip().upper()
       +            m = re.match('^(\d+(|\.\d*))\s*(|BTC|EUR|USD|GBP|CNY|JPY|RUB|BRL)$', text)
       +            if m:
       +                amount = m.group(1)
       +                currency = m.group(3)
       +                if not currency:
       +                    currency = 'BTC'
                        else:
       -                    item.setText(3,"")
       -                return
       +                    currency = currency.upper()
       +                self.wallet.requested_amounts[address] = (amount, currency)
        
       -            self.wallet.requested_amounts[address] = amount
       +                label = self.wallet.labels.get(address)
       +                if label is None:
       +                    label = self.merchant_name + ' - %04d'%(index+1)
       +                    self.wallet.labels[address] = label
        
       -            label = self.wallet.labels.get(address)
       -            if label is None:
       -                label = self.merchant_name + ' - %04d'%(index+1)
       -                self.wallet.labels[address] = label
       +                if self.qr_window:
       +                    self.qr_window.set_content( address, label, amount, currency )
        
       +            else:
       +                item.setText(3,'')
       +                if address in self.wallet.requested_amounts:
       +                    self.wallet.requested_amounts.pop(address)
       +            
                    self.update_receive_item(self.receive_list.currentItem())
       -            if self.qr_window:
       -                self.qr_window.set_content( address, label, amount )
        
        
            def recv_changed(self, a):
       t@@ -557,8 +683,11 @@ class ElectrumWindow(QMainWindow):
                if a is not None and self.qr_window and self.qr_window.isVisible():
                    address = str(a.text(1))
                    label = self.wallet.labels.get(address)
       -            amount = self.wallet.requested_amounts.get(address)
       -            self.qr_window.set_content( address, label, amount )
       +            try:
       +                amount, currency = self.wallet.requested_amounts.get(address, (None, None))
       +            except:
       +                amount, currency = None, None
       +            self.qr_window.set_content( address, label, amount, currency )
        
        
            def update_history_tab(self):
       t@@ -600,8 +729,11 @@ class ElectrumWindow(QMainWindow):
                    item.setFont(2, QFont(MONOSPACE_FONT))
                    item.setFont(3, QFont(MONOSPACE_FONT))
                    item.setFont(4, QFont(MONOSPACE_FONT))
       +            if value < 0:
       +                item.setForeground(3, QBrush(QColor("#BC1E1E")))
                    if tx_hash:
       -                item.setToolTip(0, tx_hash)
       +                item.setData(0, Qt.UserRole, tx_hash)
       +                item.setToolTip(0, "%d %s\nTxId:%s" % (conf, _('Confirmations'), tx_hash) )
                    if is_default_label:
                        item.setForeground(2, QBrush(QColor('grey')))
        
       t@@ -700,10 +832,14 @@ class ElectrumWindow(QMainWindow):
                    if inputs:
                        palette = QPalette()
                        palette.setColor(self.amount_e.foregroundRole(), QColor('black'))
       +                text = self.status_text
                    else:
                        palette = QPalette()
                        palette.setColor(self.amount_e.foregroundRole(), QColor('red'))
                        self.funds_error = True
       +                text = _( "Not enough funds" )
       +
       +            self.statusBar().showMessage(text)
                    self.amount_e.setPalette(palette)
                    self.fee_e.setPalette(palette)
        
       t@@ -878,23 +1014,30 @@ class ElectrumWindow(QMainWindow):
                self.connect(l, SIGNAL('currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)'), lambda a,b: self.recv_changed(a))
                self.receive_list = l
                self.receive_buttons_hbox = hbox
       -        view_combo = QComboBox()
       -        view_combo.addItems([_('Simple View'), _('Detailed View'), _('Point of Sale')])
       -        view_combo.setCurrentIndex(self.receive_tab_mode)
       -        hbox.addWidget(view_combo)
       -        view_combo.currentIndexChanged.connect(self.receive_tab_set_mode)
                hbox.addStretch(1)
                return w
        
        
        
            def receive_tab_set_mode(self, i):
       +        self.save_column_widths()
                self.receive_tab_mode = i
                self.config.set_key('qt_receive_tab_mode', self.receive_tab_mode, True)
                self.wallet.save()
                self.update_receive_tab()
                self.toggle_QR_window(self.receive_tab_mode == 2)
        
       +    def save_column_widths(self):
       +        widths = []
       +        for i in range(self.receive_list.columnCount()):
       +            widths.append(self.receive_list.columnWidth(i))
       +        self.column_widths["receive"][self.receive_tab_mode] = widths
       +        self.column_widths["history"] = []
       +        for i in range(self.history_list.columnCount()):
       +            self.column_widths["history"].append(self.history_list.columnWidth(i))
       +        self.column_widths["contacts"] = []
       +        for i in range(self.contacts_list.columnCount()):
       +            self.column_widths["contacts"].append(self.contacts_list.columnWidth(i))
        
            def create_contacts_tab(self):
                l,w,hbox = self.create_list_tab([_('Address'), _('Label'), _('Tx')])
       t@@ -909,6 +1052,14 @@ class ElectrumWindow(QMainWindow):
                return w
        
        
       +    def delete_imported_key(self, addr):
       +        if self.question("Do you want to remove %s from your wallet?"%addr):
       +            self.wallet.imported_keys.pop(addr)
       +            self.update_receive_tab()
       +            self.update_history_tab()
       +            self.wallet.save()
       +
       +
            def create_receive_menu(self, position):
                # fixme: this function apparently has a side effect.
                # if it is not called the menu pops up several times
       t@@ -924,11 +1075,15 @@ class ElectrumWindow(QMainWindow):
                menu.addAction(_("View QR"), lambda: ElectrumWindow.show_qrcode("Address","bitcoin:"+addr) )
                menu.addAction(_("Edit label"), lambda: self.edit_label(True))
                menu.addAction(_("Sign message"), lambda: self.sign_message(addr))
       -
       -        t = _("Unfreeze") if addr in self.wallet.frozen_addresses else _("Freeze")
       -        menu.addAction(t, lambda: self.toggle_freeze(addr))
       -        t = _("Unprioritize") if addr in self.wallet.prioritized_addresses else _("Prioritize")
       -        menu.addAction(t, lambda: self.toggle_priority(addr))
       +        if addr in self.wallet.imported_keys:
       +            menu.addAction(_("Remove from wallet"), lambda: self.delete_imported_key(addr))
       +
       +        if self.receive_tab_mode == 1:
       +            t = _("Unfreeze") if addr in self.wallet.frozen_addresses else _("Freeze")
       +            menu.addAction(t, lambda: self.toggle_freeze(addr))
       +            t = _("Unprioritize") if addr in self.wallet.prioritized_addresses else _("Prioritize")
       +            menu.addAction(t, lambda: self.toggle_priority(addr))
       +            
                menu.exec_(self.receive_list.viewport().mapToGlobal(position))
        
        
       t@@ -989,18 +1144,23 @@ class ElectrumWindow(QMainWindow):
                label = self.wallet.labels.get(address,'')
                item.setData(2,0,label)
        
       -        amount = self.wallet.requested_amounts.get(address,None)
       -        amount_str = format_satoshis( amount, False, self.wallet.num_zeros ) if amount is not None  else ""
       +        try:
       +            amount, currency = self.wallet.requested_amounts.get(address, (None, None))
       +        except:
       +            amount, currency = None, None
       +            
       +        amount_str = amount + (' ' + currency if currency else '') if amount is not None  else ''
                item.setData(3,0,amount_str)
       -        
       +                
                c, u = self.wallet.get_addr_balance(address)
                balance = format_satoshis( c + u, False, self.wallet.num_zeros )
                item.setData(4,0,balance)
        
       -        if address in self.wallet.frozen_addresses: 
       -            item.setBackgroundColor(1, QColor('lightblue'))
       -        elif address in self.wallet.prioritized_addresses: 
       -            item.setBackgroundColor(1, QColor('lightgreen'))
       +        if self.receive_tab_mode == 1:
       +            if address in self.wallet.frozen_addresses: 
       +                item.setBackgroundColor(1, QColor('lightblue'))
       +            elif address in self.wallet.prioritized_addresses: 
       +                item.setBackgroundColor(1, QColor('lightgreen'))
                
        
            def update_receive_tab(self):
       t@@ -1011,12 +1171,8 @@ class ElectrumWindow(QMainWindow):
                l.setColumnHidden(3, not self.receive_tab_mode == 2)
                l.setColumnHidden(4, self.receive_tab_mode == 0)
                l.setColumnHidden(5, not self.receive_tab_mode == 1)
       -        l.setColumnWidth(0, 50)
       -        l.setColumnWidth(1, 310) 
       -        l.setColumnWidth(2, 200)
       -        l.setColumnWidth(3, 130)
       -        l.setColumnWidth(4, 130)
       -        l.setColumnWidth(5, 10)
       +        for i,width in enumerate(self.column_widths['receive'][self.receive_tab_mode]):
       +            l.setColumnWidth(i, width)        
        
                gap = 0
                is_red = False
       t@@ -1072,9 +1228,8 @@ class ElectrumWindow(QMainWindow):
        
                l = self.contacts_list
                l.clear()
       -        l.setColumnWidth(0, 350) 
       -        l.setColumnWidth(1, 330)
       -        l.setColumnWidth(2, 100) 
       +        for i,width in enumerate(self.column_widths['contacts']):
       +            l.setColumnWidth(i, width)
        
                alias_targets = []
                for alias, v in self.wallet.aliases.items():
       t@@ -1103,17 +1258,37 @@ class ElectrumWindow(QMainWindow):
                textbox.setReadOnly(True)
                return textbox
        
       +
            def create_status_bar(self):
       +        self.status_text = ""
                sb = QStatusBar()
                sb.setFixedHeight(35)
       +        qtVersion = qVersion()
       +
       +        update_notification = UpdateLabel(self.config)
       +        sb.addPermanentWidget(update_notification)
       +
       +        if (int(qtVersion[0]) >= 4 and int(qtVersion[2]) >= 7):
       +             sb.addPermanentWidget( StatusBarButton( QIcon(":icons/switchgui.png"), _("Switch to Lite Mode"), self.go_lite ) )
                if self.wallet.seed:
       -            sb.addPermanentWidget( StatusBarButton( QIcon(":icons/lock.png"), "Password", lambda: self.change_password_dialog(self.wallet, self) ) )
       -        sb.addPermanentWidget( StatusBarButton( QIcon(":icons/preferences.png"), "Preferences", self.settings_dialog ) )
       +            sb.addPermanentWidget( StatusBarButton( QIcon(":icons/lock.png"), _("Password"), lambda: self.change_password_dialog(self.wallet, self) ) )
       +        sb.addPermanentWidget( StatusBarButton( QIcon(":icons/preferences.png"), _("Preferences"), self.settings_dialog ) )
                if self.wallet.seed:
       -            sb.addPermanentWidget( StatusBarButton( QIcon(":icons/seed.png"), "Seed", lambda: self.show_seed_dialog(self.wallet, self) ) )
       -        self.status_button = StatusBarButton( QIcon(":icons/status_disconnected.png"), "Network", lambda: self.network_dialog(self.wallet, self) ) 
       +            sb.addPermanentWidget( StatusBarButton( QIcon(":icons/seed.png"), _("Seed"), lambda: self.show_seed_dialog(self.wallet, self) ) )
       +        self.status_button = StatusBarButton( QIcon(":icons/status_disconnected.png"), _("Network"), lambda: self.network_dialog(self.wallet, self) ) 
                sb.addPermanentWidget( self.status_button )
       +
                self.setStatusBar(sb)
       +        
       +    def go_lite(self):
       +        import gui_lite
       +        self.config.set_key('gui', 'lite', True)
       +        self.hide()
       +        if self.lite:
       +            self.lite.mini.show()
       +        else:
       +            self.lite = gui_lite.ElectrumGui(self.wallet, self.config, self)
       +            self.lite.main(None)
        
            def new_contact_dialog(self):
                text, ok = QInputDialog.getText(self, _('New Contact'), _('Address') + ':')
       t@@ -1128,11 +1303,42 @@ class ElectrumWindow(QMainWindow):
                    else:
                        QMessageBox.warning(self, _('Error'), _('Invalid Address'), _('OK'))
        
       +    def show_master_public_key(self):
       +        dialog = QDialog(None)
       +        dialog.setModal(1)
       +        dialog.setWindowTitle("Master Public Key")
       +
       +        main_text = QTextEdit()
       +        main_text.setText(self.wallet.master_public_key)
       +        main_text.setReadOnly(True)
       +        main_text.setMaximumHeight(170)
       +        qrw = QRCodeWidget(self.wallet.master_public_key, 6)
       +
       +        ok_button = QPushButton(_("OK"))
       +        ok_button.setDefault(True)
       +        ok_button.clicked.connect(dialog.accept)
       +
       +        main_layout = QGridLayout()
       +        main_layout.addWidget(QLabel(_('Your Master Public Key is:')), 0, 0, 1, 2)
       +
       +        main_layout.addWidget(main_text, 1, 0)
       +        main_layout.addWidget(qrw, 1, 1 )
       +
       +        vbox = QVBoxLayout()
       +        vbox.addLayout(main_layout)
       +        hbox = QHBoxLayout()
       +        hbox.addStretch(1)
       +        hbox.addWidget(ok_button)
       +        vbox.addLayout(hbox)
       +
       +        dialog.setLayout(vbox)
       +        dialog.exec_()
       +        
       +
            @staticmethod
            def show_seed_dialog(wallet, parent=None):
                if not wallet.seed:
       -            QMessageBox.information(parent, _('Message'),
       -                                    _('No seed'), _('OK'))
       +            QMessageBox.information(parent, _('Message'), _('No seed'), _('OK'))
                    return
        
                if wallet.use_encryption:
       t@@ -1143,54 +1349,60 @@ class ElectrumWindow(QMainWindow):
                    password = None
                    
                try:
       -            seed = wallet.pw_decode(wallet.seed, password)
       +            seed = wallet.decode_seed(password)
                except:
       -            QMessageBox.warning(parent, _('Error'),
       -                                _('Incorrect Password'), _('OK'))
       +            QMessageBox.warning(parent, _('Error'), _('Incorrect Password'), _('OK'))
                    return
        
                dialog = QDialog(None)
                dialog.setModal(1)
       -        dialog.setWindowTitle("Electrum")
       +        dialog.setWindowTitle(_("Electrum") + ' - ' + _('Seed'))
        
                brainwallet = ' '.join(mnemonic.mn_encode(seed))
        
       -        msg =   _("Your wallet generation seed is") +":<p>\"" + brainwallet + "\"<p>" \
       -              + _("Please write down or memorize these 12 words (order is important).") + " " \
       -              + _("This seed will allow you to recover your wallet in case of computer failure.") + "<p>" \
       -              + _("WARNING: Never disclose your seed. Never type it on a website.") + "<p>"
       +        label1 = QLabel(_("Your wallet generation seed is")+ ":")
        
       -        main_text = QLabel(msg)
       -        main_text.setWordWrap(True)
       +        seed_text = QTextEdit(brainwallet)
       +        seed_text.setReadOnly(True)
       +        seed_text.setMaximumHeight(130)
       +        
       +        msg2 =  _("Please write down or memorize these 12 words (order is important).") + " " \
       +              + _("This seed will allow you to recover your wallet in case of computer failure.") + " " \
       +              + _("Your seed is also displayed as QR code, in case you want to transfer it to a mobile phone.") + "<p>" \
       +              + "<b>"+_("WARNING")+":</b> " + _("Never disclose your seed. Never type it on a website.") + "</b><p>"
       +        label2 = QLabel(msg2)
       +        label2.setWordWrap(True)
        
                logo = QLabel()
                logo.setPixmap(QPixmap(":icons/seed.png").scaledToWidth(56))
       +        logo.setMaximumWidth(60)
        
       -        if parent:
       -            app = parent.app
       -        else:
       -            app = QApplication
       -
       -        copy_function = lambda: app.clipboard().setText(brainwallet)
       -        copy_button = QPushButton(_("Copy to Clipboard"))
       -        copy_button.clicked.connect(copy_function)
       -
       -        show_qr_function = lambda: ElectrumWindow.show_qrcode(_("Seed"), seed)
       -        qr_button = QPushButton(_("View as QR Code"))
       -        qr_button.clicked.connect(show_qr_function)
       +        qrw = QRCodeWidget(seed, 4)
        
                ok_button = QPushButton(_("OK"))
                ok_button.setDefault(True)
                ok_button.clicked.connect(dialog.accept)
        
       -        main_layout = QGridLayout()
       -        main_layout.addWidget(logo, 0, 0)
       -        main_layout.addWidget(main_text, 0, 1, 1, -1)
       -        main_layout.addWidget(copy_button, 1, 1)
       -        main_layout.addWidget(qr_button, 1, 2)
       -        main_layout.addWidget(ok_button, 1, 3)
       -        dialog.setLayout(main_layout)
       +        grid = QGridLayout()
       +        #main_layout.addWidget(logo, 0, 0)
       +
       +        grid.addWidget(logo, 0, 0)
       +        grid.addWidget(label1, 0, 1)
       +
       +        grid.addWidget(seed_text, 1, 0, 1, 2)
       +
       +        grid.addWidget(qrw, 0, 2, 2, 1)
       +
       +        vbox = QVBoxLayout()
       +        vbox.addLayout(grid)
       +        vbox.addWidget(label2)
       +
       +        hbox = QHBoxLayout()
       +        hbox.addStretch(1)
       +        hbox.addWidget(ok_button)
       +        vbox.addLayout(hbox)
        
       +        dialog.setLayout(vbox)
                dialog.exec_()
        
            @staticmethod
       t@@ -1202,8 +1414,8 @@ class ElectrumWindow(QMainWindow):
                d.setMinimumSize(270, 300)
                vbox = QVBoxLayout()
                qrw = QRCodeWidget(data)
       -        vbox.addWidget(qrw)
       -        vbox.addWidget(QLabel(data))
       +        vbox.addWidget(qrw, 1)
       +        vbox.addWidget(QLabel(data), 0, Qt.AlignHCenter)
                hbox = QHBoxLayout()
                hbox.addStretch(1)
        
       t@@ -1229,24 +1441,27 @@ class ElectrumWindow(QMainWindow):
                d = QDialog(self)
                d.setModal(1)
                d.setWindowTitle('Sign Message')
       -        d.setMinimumSize(270, 350)
       +        d.setMinimumSize(410, 290)
        
                tab_widget = QTabWidget()
                tab = QWidget()
                layout = QGridLayout(tab)
        
                sign_address = QLineEdit()
       +
                sign_address.setText(address)
                layout.addWidget(QLabel(_('Address')), 1, 0)
                layout.addWidget(sign_address, 1, 1)
        
                sign_message = QTextEdit()
                layout.addWidget(QLabel(_('Message')), 2, 0)
       -        layout.addWidget(sign_message, 2, 1, 2, 1)
       +        layout.addWidget(sign_message, 2, 1)
       +        layout.setRowStretch(2,3)
        
       -        sign_signature = QLineEdit()
       +        sign_signature = QTextEdit()
                layout.addWidget(QLabel(_('Signature')), 3, 0)
                layout.addWidget(sign_signature, 3, 1)
       +        layout.setRowStretch(3,1)
        
                def do_sign():
                    if self.wallet.use_encryption:
       t@@ -1257,7 +1472,7 @@ class ElectrumWindow(QMainWindow):
                        password = None
        
                    try:
       -                signature = self.wallet.sign_message(sign_address.text(), str(sign_message.toPlainText()), password)
       +                signature = self.wallet.sign_message(str(sign_address.text()), str(sign_message.toPlainText()), password)
                        sign_signature.setText(signature)
                    except BaseException, e:
                        self.show_message(str(e))
       t@@ -1283,15 +1498,17 @@ class ElectrumWindow(QMainWindow):
        
                verify_message = QTextEdit()
                layout.addWidget(QLabel(_('Message')), 2, 0)
       -        layout.addWidget(verify_message, 2, 1, 2, 1)
       +        layout.addWidget(verify_message, 2, 1)
       +        layout.setRowStretch(2,3)
        
       -        verify_signature = QLineEdit()
       +        verify_signature = QTextEdit()
                layout.addWidget(QLabel(_('Signature')), 3, 0)
                layout.addWidget(verify_signature, 3, 1)
       +        layout.setRowStretch(3,1)
        
                def do_verify():
                    try:
       -                self.wallet.verify_message(verify_address.text(), verify_signature.text(), str(verify_message.toPlainText()))
       +                self.wallet.verify_message(verify_address.text(), str(verify_signature.toPlainText()), str(verify_message.toPlainText()))
                        self.show_message("Signature verified")
                    except BaseException, e:
                        self.show_message(str(e))
       t@@ -1315,15 +1532,15 @@ class ElectrumWindow(QMainWindow):
                
            def toggle_QR_window(self, show):
                if show and not self.qr_window:
       -            self.qr_window = QR_Window()
       +            self.qr_window = QR_Window(self.exchanger)
                    self.qr_window.setVisible(True)
                    self.qr_window_geometry = self.qr_window.geometry()
                    item = self.receive_list.currentItem()
                    if item:
                        address = str(item.text(1))
                        label = self.wallet.labels.get(address)
       -                amount = self.wallet.requested_amounts.get(address)
       -                self.qr_window.set_content( address, label, amount )
       +                amount, currency = self.wallet.requested_amounts.get(address, (None, None))
       +                self.qr_window.set_content( address, label, amount, currency )
        
                elif show and self.qr_window and not self.qr_window.isVisible():
                    self.qr_window.setVisible(True)
       t@@ -1422,7 +1639,7 @@ class ElectrumWindow(QMainWindow):
                new_password2 = unicode(conf_pw.text())
        
                try:
       -            seed = wallet.pw_decode( wallet.seed, password)
       +            seed = wallet.decode_seed(password)
                except:
                    QMessageBox.warning(parent, _('Error'), _('Incorrect Password'), _('OK'))
                    return
       t@@ -1465,10 +1682,10 @@ class ElectrumWindow(QMainWindow):
                    gap = int(unicode(gap_e.text()))
                except:
                    QMessageBox.warning(None, _('Error'), 'error', 'OK')
       -            sys.exit(0)
       +            return
        
                try:
       -            seed = unicode(seed_e.text())
       +            seed = str(seed_e.text())
                    seed.decode('hex')
                except:
                    print_error("Warning: Not hex, trying decode")
       t@@ -1476,93 +1693,214 @@ class ElectrumWindow(QMainWindow):
                        seed = mnemonic.mn_decode( seed.split(' ') )
                    except:
                        QMessageBox.warning(None, _('Error'), _('I cannot decode this'), _('OK'))
       -                sys.exit(0)
       +                return
       +
                if not seed:
                    QMessageBox.warning(None, _('Error'), _('No seed'), 'OK')
       -            sys.exit(0)
       +            return
       +
       +        return seed, gap
       +
       +
       +    def do_import_labels(self):
       +        labelsFile = QFileDialog.getOpenFileName(QWidget(), "Open text file", util.user_dir(), self.tr("Text Files (labels.dat)"))
       +        if not labelsFile: return
       +        try:
       +            f = open(labelsFile, 'r')
       +            data = f.read()
       +            f.close()
       +            for key, value in json.loads(data).items():
       +                self.wallet.labels[key] = value
       +            self.wallet.save()
       +            QMessageBox.information(None, "Labels imported", "Your labels where imported from '%s'" % str(labelsFile))
       +        except (IOError, os.error), reason:
       +            QMessageBox.critical(None, "Unable to import labels", "Electrum was unable to import your labels.\n" + str(reason))
                
       -        wallet.seed = str(seed)
       -        #print repr(wallet.seed)
       -        wallet.gap_limit = gap
       -        return True
        
        
       +    def do_export_labels(self):
       +        labels = self.wallet.labels
       +        try:
       +            labelsFile = util.user_dir() + '/labels.dat'
       +            f = open(labelsFile, 'w+')
       +            json.dump(labels, f)
       +            f.close()
       +            QMessageBox.information(None, "Labels exported", "Your labels where exported to '%s'" % str(labelsFile))
       +        except (IOError, os.error), reason:
       +            QMessageBox.critical(None, "Unable to export labels", "Electrum was unable to export your labels.\n" + str(reason))
       +
       +    def do_export_history(self):
       +        from gui_lite import csv_transaction
       +        csv_transaction(self.wallet)
       +
       +    def do_import_privkey(self):
       +        if not self.wallet.imported_keys:
       +            r = QMessageBox.question(None, _('Warning'), _('Warning: Imported keys are not recoverable from seed.') + ' ' \
       +                                         + _('If you ever need to restore your wallet from its seed, these keys will be lost.') + '\n\n' \
       +                                         + _('Are you sure you understand what you are doing?'), 3, 4)
       +            if r == 4: return
       +
       +        text, ok = QInputDialog.getText(self, _('Import private key'), _('Private Key') + ':')
       +        if not ok: return
       +        sec = str(text).strip()
       +        if self.wallet.use_encryption:
       +            password = self.password_dialog()
       +            if not password:
       +                return
       +        else:
       +            password = None
       +        try:
       +            addr = self.wallet.import_key(sec, password)
       +            if not addr:
       +                QMessageBox.critical(None, "Unable to import key", "error")
       +            else:
       +                QMessageBox.information(None, "Key imported", addr)
       +                self.update_receive_tab()
       +                self.update_history_tab()
       +        except BaseException as e:
       +            QMessageBox.critical(None, "Unable to import key", str(e))
        
            def settings_dialog(self):
                d = QDialog(self)
       +        d.setWindowTitle(_('Electrum Settings'))
                d.setModal(1)
                vbox = QVBoxLayout()
       -        msg = _('Here are the settings of your wallet.') + '\n'\
       -              + _('For more explanations, click on the help buttons next to each field.')
        
       -        label = QLabel(msg)
       -        label.setFixedWidth(250)
       -        label.setWordWrap(True)
       -        label.setAlignment(Qt.AlignJustify)
       -        vbox.addWidget(label)
       +        tabs = QTabWidget(self)
       +        vbox.addWidget(tabs)
        
       -        grid = QGridLayout()
       -        grid.setSpacing(8)
       -        vbox.addLayout(grid)
       +        tab1 = QWidget()
       +        grid_ui = QGridLayout(tab1)
       +        grid_ui.setColumnStretch(0,1)
       +        tabs.addTab(tab1, _('Display') )
       +
       +        nz_label = QLabel(_('Display zeros'))
       +        grid_ui.addWidget(nz_label, 3, 0)
       +        nz_e = QLineEdit()
       +        nz_e.setText("%d"% self.wallet.num_zeros)
       +        grid_ui.addWidget(nz_e, 3, 1)
       +        msg = _('Number of zeros displayed after the decimal point. For example, if this is set to 2, "1." will be displayed as "1.00"')
       +        grid_ui.addWidget(HelpButton(msg), 3, 2)
       +        nz_e.textChanged.connect(lambda: numbify(nz_e,True))
       +        if not self.config.is_modifiable('num_zeros'):
       +            for w in [nz_e, nz_label]: w.setEnabled(False)
       +        
       +        lang_label=QLabel(_('Language') + ':')
       +        grid_ui.addWidget(lang_label , 8, 0)
       +        lang_combo = QComboBox()
       +        from i18n import languages
       +        lang_combo.addItems(languages.values())
       +        try:
       +            index = languages.keys().index(self.config.get("language",''))
       +        except:
       +            index = 0
       +        lang_combo.setCurrentIndex(index)
       +        grid_ui.addWidget(lang_combo, 8, 1)
       +        grid_ui.addWidget(HelpButton(_('Select which language is used in the GUI (after restart).')+' '), 8, 2)
       +        if not self.config.is_modifiable('language'):
       +            for w in [lang_combo, lang_label]: w.setEnabled(False)
       +
       +        currencies = self.exchanger.get_currencies()
       +        currencies.insert(0, "None")
       +
       +        cur_label=QLabel(_('Currency') + ':')
       +        grid_ui.addWidget(cur_label , 9, 0)
       +        cur_combo = QComboBox()
       +        cur_combo.addItems(currencies)
       +        try:
       +            index = currencies.index(self.config.get('currency', "None"))
       +        except:
       +            index = 0
       +        cur_combo.setCurrentIndex(index)
       +        grid_ui.addWidget(cur_combo, 9, 1)
       +        grid_ui.addWidget(HelpButton(_('Select which currency is used for quotes.')+' '), 9, 2)
       +        
       +        view_label=QLabel(_('Receive Tab') + ':')
       +        grid_ui.addWidget(view_label , 10, 0)
       +        view_combo = QComboBox()
       +        view_combo.addItems([_('Simple'), _('Advanced'), _('Point of Sale')])
       +        view_combo.setCurrentIndex(self.receive_tab_mode)
       +        grid_ui.addWidget(view_combo, 10, 1)
       +        hh = _('This selects the interaction mode of the "Receive" tab.')+' ' + '\n\n' \
       +             + _('Simple') +   ': ' + _('Show only addresses and labels.') + '\n\n' \
       +             + _('Advanced') + ': ' + _('Show address balances and add extra menu items to freeze/prioritize addresses.') + '\n\n' \
       +             + _('Point of Sale') + ': ' + _('Show QR code window and amounts requested for each address. Add menu item to request amount.') + '\n\n' 
       +        
       +        grid_ui.addWidget(HelpButton(hh), 10, 2)
        
       +        # wallet tab
       +        tab2 = QWidget()
       +        grid_wallet = QGridLayout(tab2)
       +        grid_wallet.setColumnStretch(0,1)
       +        tabs.addTab(tab2, _('Wallet') )
       +        
                fee_label = QLabel(_('Transaction fee'))
       -        grid.addWidget(fee_label, 2, 0)
       +        grid_wallet.addWidget(fee_label, 0, 0)
                fee_e = QLineEdit()
                fee_e.setText("%s"% str( Decimal( self.wallet.fee)/100000000 ) )
       -        grid.addWidget(fee_e, 2, 1)
       +        grid_wallet.addWidget(fee_e, 0, 1)
                msg = _('Fee per transaction input. Transactions involving multiple inputs tend to require a higher fee.') + ' ' \
                    + _('Recommended value') + ': 0.001'
       -        grid.addWidget(HelpButton(msg), 2, 2)
       +        grid_wallet.addWidget(HelpButton(msg), 0, 2)
                fee_e.textChanged.connect(lambda: numbify(fee_e,False))
                if not self.config.is_modifiable('fee'):
                    for w in [fee_e, fee_label]: w.setEnabled(False)
        
       -        nz_label = QLabel(_('Display zeros'))
       -        grid.addWidget(nz_label, 3, 0)
       -        nz_e = QLineEdit()
       -        nz_e.setText("%d"% self.wallet.num_zeros)
       -        grid.addWidget(nz_e, 3, 1)
       -        msg = _('Number of zeros displayed after the decimal point. For example, if this is set to 2, "1." will be displayed as "1.00"')
       -        grid.addWidget(HelpButton(msg), 3, 2)
       -        nz_e.textChanged.connect(lambda: numbify(nz_e,True))
       -        if not self.config.is_modifiable('num_zeros'):
       -            for w in [nz_e, nz_label]: w.setEnabled(False)
       -
       -        usechange_cb = QCheckBox(_('Use change addresses'))
       -        grid.addWidget(usechange_cb, 5, 0)
       -        usechange_cb.setChecked(self.wallet.use_change)
       -        grid.addWidget(HelpButton(_('Using change addresses makes it more difficult for other people to track your transactions. ')), 5, 2)
       -        if not self.config.is_modifiable('use_change'): usechange_cb.setEnabled(False)
       +        usechange_label = QLabel(_('Use change addresses'))
       +        grid_wallet.addWidget(usechange_label, 1, 0)
       +        usechange_combo = QComboBox()
       +        usechange_combo.addItems([_('Yes'), _('No')])
       +        usechange_combo.setCurrentIndex(not self.wallet.use_change)
       +        grid_wallet.addWidget(usechange_combo, 1, 1)
       +        grid_wallet.addWidget(HelpButton(_('Using change addresses makes it more difficult for other people to track your transactions.')+' '), 1, 2)
       +        if not self.config.is_modifiable('use_change'): usechange_combo.setEnabled(False)
        
                gap_label = QLabel(_('Gap limit'))
       -        grid.addWidget(gap_label, 6, 0)
       +        grid_wallet.addWidget(gap_label, 2, 0)
                gap_e = QLineEdit()
                gap_e.setText("%d"% self.wallet.gap_limit)
       -        grid.addWidget(gap_e, 6, 1)
       +        grid_wallet.addWidget(gap_e, 2, 1)
                msg =  _('The gap limit is the maximal number of contiguous unused addresses in your sequence of receiving addresses.') + '\n' \
                      + _('You may increase it if you need more receiving addresses.') + '\n\n' \
                      + _('Your current gap limit is') + ': %d'%self.wallet.gap_limit + '\n' \
       -              + _('Given the current status of your address sequence, the minimum gap limit you can use is: ') + '%d'%self.wallet.min_acceptable_gap() + '\n\n' \
       +              + _('Given the current status of your address sequence, the minimum gap limit you can use is:')+' ' + '%d'%self.wallet.min_acceptable_gap() + '\n\n' \
                      + _('Warning') + ': ' \
                      + _('The gap limit parameter must be provided in order to recover your wallet from seed.') + ' ' \
                      + _('Do not modify it if you do not understand what you are doing, or if you expect to recover your wallet without knowing it!') + '\n\n' 
       -        grid.addWidget(HelpButton(msg), 6, 2)
       +        grid_wallet.addWidget(HelpButton(msg), 2, 2)
                gap_e.textChanged.connect(lambda: numbify(nz_e,True))
                if not self.config.is_modifiable('gap_limit'):
                    for w in [gap_e, gap_label]: w.setEnabled(False)
       -        
       -        gui_label=QLabel(_('Default GUI') + ':')
       -        grid.addWidget(gui_label , 7, 0)
       -        gui_combo = QComboBox()
       -        gui_combo.addItems(['Lite', 'Classic', 'Gtk', 'Text'])
       -        index = gui_combo.findText(self.config.get("gui","classic").capitalize())
       -        if index==-1: index = 1
       -        gui_combo.setCurrentIndex(index)
       -        grid.addWidget(gui_combo, 7, 1)
       -        grid.addWidget(HelpButton(_('Select which GUI mode to use at start up. ')), 7, 2)
       -        if not self.config.is_modifiable('gui'):
       -            for w in [gui_combo, gui_label]: w.setEnabled(False)
        
       +        grid_wallet.setRowStretch(3,1)
       +
       +
       +        # wallet tab
       +        tab3 = QWidget()
       +        grid_io = QGridLayout(tab3)
       +        grid_io.setColumnStretch(0,1)
       +        tabs.addTab(tab3, _('Import/Export') )
       +        
       +        grid_io.addWidget(QLabel(_('Labels')), 1, 0)
       +        grid_io.addWidget(EnterButton(_("Export"), self.do_export_labels), 1, 1)
       +        grid_io.addWidget(EnterButton(_("Import"), self.do_import_labels), 1, 2)
       +        grid_io.addWidget(HelpButton(_('Export your labels as json')), 1, 3)
       +
       +        grid_io.addWidget(QLabel(_('History')), 2, 0)
       +        grid_io.addWidget(EnterButton(_("Export"), self.do_export_history), 2, 1)
       +        grid_io.addWidget(HelpButton(_('Export your transaction history as csv')), 2, 3)
       +
       +        grid_io.addWidget(QLabel(_('Private key')), 3, 0)
       +        grid_io.addWidget(EnterButton(_("Import"), self.do_import_privkey), 3, 2)
       +        grid_io.addWidget(HelpButton(_('Import private key')), 3, 3)
       +
       +        grid_io.addWidget(QLabel(_('Master Public Key')), 4, 0)
       +        grid_io.addWidget(EnterButton(_("Show"), self.show_master_public_key), 4, 1)
       +        grid_io.addWidget(HelpButton(_('Your Master Public Key can be used to create receiving addresses, but not to sign transactions.') + ' ' \
       +                              + _('If you give it to someone, they will be able to see your transactions, but not to spend your money.') + ' ' \
       +                              + _('If you restore your wallet from it, a watching-only (deseeded) wallet will be created.')), 4, 3)
       +
       +        grid_io.setRowStretch(4,1)
                vbox.addLayout(ok_cancel_buttons(d))
                d.setLayout(vbox) 
        
       t@@ -1594,8 +1932,9 @@ class ElectrumWindow(QMainWindow):
                    self.update_history_tab()
                    self.update_receive_tab()
        
       -        if self.wallet.use_change != usechange_cb.isChecked():
       -            self.wallet.use_change = usechange_cb.isChecked()
       +        usechange_result = usechange_combo.currentIndex() == 0
       +        if self.wallet.use_change != usechange_result:
       +            self.wallet.use_change = usechange_result
                    self.config.set_key('use_change', self.wallet.use_change, True)
                
                try:
       t@@ -1611,9 +1950,23 @@ class ElectrumWindow(QMainWindow):
                        self.config.set_key('gap_limit', self.wallet.gap_limit, True)
                    else:
                        QMessageBox.warning(self, _('Error'), _('Invalid value'), _('OK'))
       -                    
       -        self.config.set_key("gui", str(gui_combo.currentText()).lower(), True)
        
       +        need_restart = False
       +
       +        lang_request = languages.keys()[lang_combo.currentIndex()]
       +        if lang_request != self.config.get('language'):
       +            self.config.set_key("language", lang_request, True)
       +            need_restart = True
       +            
       +        cur_request = str(currencies[cur_combo.currentIndex()])
       +        if cur_request != self.config.get('currency', "None"):
       +            self.config.set_key('currency', cur_request, True)
       +            self.update_wallet()
       +
       +        if need_restart:
       +            QMessageBox.warning(self, _('Success'), _('Please restart Electrum to activate the new GUI settings'), _('OK'))
       +
       +        self.receive_tab_set_mode(view_combo.currentIndex())
        
        
            @staticmethod 
       t@@ -1621,7 +1974,7 @@ class ElectrumWindow(QMainWindow):
                interface = wallet.interface
                if parent:
                    if interface.is_connected:
       -                status = _("Connected to")+" %s\n%d blocks"%(interface.host, wallet.verifier.height)
       +                status = _("Connected to")+" %s\n%d "%(interface.host, wallet.verifier.height)+_("blocks")
                    else:
                        status = _("Not connected")
                    server = interface.server
       t@@ -1690,7 +2043,7 @@ class ElectrumWindow(QMainWindow):
                servers_list_widget.setMaximumHeight(150)
                servers_list_widget.setColumnWidth(0, 240)
                for _host in servers_list.keys():
       -            _type = 'pruning' if servers_list[_host].get('pruning') else 'full'
       +            _type = 'P' if servers_list[_host].get('pruning') else 'F'
                    servers_list_widget.addTopLevelItem(QTreeWidgetItem( [ _host, _type ] ))
        
                def change_server(host, protocol=None):
       t@@ -1731,6 +2084,12 @@ class ElectrumWindow(QMainWindow):
                if not wallet.config.is_modifiable('server'):
                    for w in [server_host, server_port, server_protocol, servers_list_widget]: w.setEnabled(False)
        
       +        # auto cycle
       +        autocycle_cb = QCheckBox(_('Try random servers if disconnected'))
       +        autocycle_cb.setChecked(wallet.config.get('auto_cycle', False))
       +        grid.addWidget(autocycle_cb, 3, 1, 3, 2)
       +        if not wallet.config.is_modifiable('auto_cycle'): autocycle_cb.setEnabled(False)
       +
                # proxy setting
                proxy_mode = QComboBox()
                proxy_host = QLineEdit()
       t@@ -1778,12 +2137,14 @@ class ElectrumWindow(QMainWindow):
                wallet.config.set_key("proxy", proxy, True)
                wallet.config.set_key("server", server, True)
                interface.set_server(server, proxy)
       -                
       +        wallet.config.set_key('auto_cycle', autocycle_cb.isChecked(), True)
                return True
        
            def closeEvent(self, event):
                g = self.geometry()
                self.config.set_key("winpos-qt", [g.left(),g.top(),g.width(),g.height()], True)
       +        self.save_column_widths()
       +        self.config.set_key("column-widths", self.column_widths, True)
                event.accept()
        
        
   DIR diff --git a/lib/history_widget.py b/lib/history_widget.py
       t@@ -20,5 +20,7 @@ class HistoryWidget(QTreeWidget):
                if date is None:
                  date = "Unknown"
                item = QTreeWidgetItem([amount, address, date])
       +        if float(amount) < 0:
       +          item.setForeground(0, QBrush(QColor("#BC1E1E")))
                self.insertTopLevelItem(0, item)
        
   DIR diff --git a/lib/i18n.py b/lib/i18n.py
       t@@ -16,10 +16,38 @@
        # You should have received a copy of the GNU General Public License
        # along with this program. If not, see <http://www.gnu.org/licenses/>.
        
       -import gettext
       +import gettext, os
        
       -LOCALE_DIR = '/usr/share/locale'
       -#LOCALE_DIR = './locale'
       +if os.path.exists('./locale'):
       +    LOCALE_DIR = './locale'
       +else:
       +    LOCALE_DIR = '/usr/share/locale'
        
        language = gettext.translation('electrum', LOCALE_DIR, fallback = True)
       -_ = language.ugettext
       +
       +def _(x):
       +    global language
       +    return language.ugettext(x)
       +
       +def set_language(x):
       +    global language
       +    if x: language = gettext.translation('electrum', LOCALE_DIR, fallback = True, languages=[x])
       +    
       +    
       +languages = {
       +    '':_('Default'),
       +    'br':_('Brasilian'),
       +    'cs':_('Czech'),
       +    'de':_('German'),
       +    'eo':_('Esperanto'),
       +    'en':_('English'),
       +    'es':_('Spanish'),
       +    'fr':_('French'),
       +    'it':_('Italian'),
       +    'lv':_('Latvian'),
       +    'nl':_('Dutch'),
       +    'ru':_('Russian'),
       +    'sl':_('Slovenian'),
       +    'vi':_('Vietnamese'),
       +    'zh':_('Chinese')
       +    }
   DIR diff --git a/lib/interface.py b/lib/interface.py
       t@@ -21,7 +21,7 @@ import random, socket, ast, re, ssl
        import threading, traceback, sys, time, json, Queue
        
        from version import ELECTRUM_VERSION, PROTOCOL_VERSION
       -from util import print_error
       +from util import print_error, print_msg
        
        
        DEFAULT_TIMEOUT = 5
       t@@ -39,6 +39,11 @@ DEFAULT_SERVERS = [
            'ecdsa.org:50001:t'
            ]
        
       +# add only port 80 servers here
       +DEFAULT_HTTP_SERVERS = [
       +    'electrum.no-ip.org:80:h'
       +]
       +
        proxy_modes = ['socks4', 'socks5', 'http']
        
        
       t@@ -174,7 +179,14 @@ class Interface(threading.Thread):
                self.init_server(host, port, proxy, use_ssl)
                self.session_id = None
                self.connection_msg = ('https' if self.use_ssl else 'http') + '://%s:%d'%( self.host, self.port )
       -        self.is_connected = True
       +        try:
       +            self.poll()
       +        except:
       +            return
       +
       +        if self.session_id:
       +            print_error('http session:',self.session_id)
       +            self.is_connected = True
        
            def run_http(self):
                self.is_connected = True
       t@@ -232,7 +244,7 @@ class Interface(threading.Thread):
                    headers['cookie'] = 'SESSION=%s'%self.session_id
        
                req = urllib2.Request(self.connection_msg, data_json, headers)
       -        response_stream = urllib2.urlopen(req)
       +        response_stream = urllib2.urlopen(req, timeout=DEFAULT_TIMEOUT)
        
                for index, cookie in enumerate(cj):
                    if cookie.name=='SESSION':
       t@@ -376,6 +388,7 @@ class Interface(threading.Thread):
                self.servers = {} # actual list from IRC
                self.rtime = 0
                self.bytes_received = 0
       +        self.is_connected = False
        
        
        
       t@@ -383,18 +396,28 @@ class Interface(threading.Thread):
                if self.config.get('server'):
                    self.init_with_server(self.config)
                else:
       -            print "Using random server..."
       -            servers = DEFAULT_SERVERS[:]
       -            while servers:
       -                server = random.choice( servers )
       -                servers.remove(server)
       +            if self.config.get('auto_cycle') is None:
       +                self.config.set_key('auto_cycle', True, False)
       +
       +        if not self.is_connected and self.config.get('auto_cycle'):
       +            print_msg("Using random server...")
       +            servers_tcp = DEFAULT_SERVERS[:]
       +            servers_http = DEFAULT_HTTP_SERVERS[:] 
       +            while servers_tcp or servers_http:
       +                if servers_tcp:
       +                    server = random.choice( servers_tcp )
       +                    servers_tcp.remove(server)
       +                else:
       +                    # try HTTP if we can't get a TCP connection
       +                    server = random.choice( servers_http )
       +                    servers_http.remove(server)
       +                print server
                        self.config.set_key('server', server, False)
                        self.init_with_server(self.config)
                        if self.is_connected: break
        
       -            if not servers:
       +            if not self.is_connected:
                        print 'no server available'
       -                self.is_connected = False
                        self.connect_event.set() # to finish start
                        self.server = 'ecdsa.org:50001:t'
                        self.proxy = None
   DIR diff --git a/lib/simple_config.py b/lib/simple_config.py
       t@@ -94,7 +94,7 @@ a SimpleConfig instance then reads the wallet file.
                    try:
                        out = ast.literal_eval(out)
                    except:
       -                print "type error, using default value"
       +                print "type error for '%s': using default value"%key
                        out = default
        
                return out
   DIR diff --git a/lib/verifier.py b/lib/verifier.py
       t@@ -298,7 +298,8 @@ class WalletVerifier(threading.Thread):
                    return
                
                try:
       -            import urllib
       +            import urllib, socket
       +            socket.setdefaulttimeout(30)
                    print_error("downloading ", self.headers_url )
                    urllib.urlretrieve(self.headers_url, filename)
                except:
   DIR diff --git a/lib/version.py b/lib/version.py
       t@@ -1,4 +1,4 @@
       -ELECTRUM_VERSION = "1.5.7"  # version of the client package
       -PROTOCOL_VERSION = '0.6'  # protocol version requested
       -SEED_VERSION     = 4      # bump this everytime the seed generation is modified
       -TRANSLATION_ID   = 33853  # version of the wiki page 
       +ELECTRUM_VERSION = "1.6.1"  # version of the client package
       +PROTOCOL_VERSION = '0.6'    # protocol version requested
       +SEED_VERSION     = 4        # bump this everytime the seed generation is modified
       +TRANSLATION_ID   = 34952    # version of the wiki page 
   DIR diff --git a/lib/wallet.py b/lib/wallet.py
       t@@ -64,13 +64,13 @@ class Wallet:
                self.addresses             = config.get('addresses', [])          # receiving addresses visible for user
                self.change_addresses      = config.get('change_addresses', [])   # addresses used as change
                self.seed                  = config.get('seed', '')               # encrypted
       -        self.labels                = config.get('labels',{})              # labels for addresses and transactions
       +        self.labels                = config.get('labels',{'1NmduGNyC5XejoysbuioodCN3jR3yf64xM':'Electrum donation address'})
                self.aliases               = config.get('aliases', {})            # aliases for addresses
                self.authorities           = config.get('authorities', {})        # trusted addresses
                self.frozen_addresses      = config.get('frozen_addresses',[])
                self.prioritized_addresses = config.get('prioritized_addresses',[])
                self.receipts              = config.get('receipts',{})            # signed URIs
       -        self.addressbook           = config.get('contacts', [])           # outgoing addresses, for payments
       +        self.addressbook           = config.get('contacts', ['1NmduGNyC5XejoysbuioodCN3jR3yf64xM'])
                self.imported_keys         = config.get('imported_keys',{})
                self.history               = config.get('addr_history',{})        # address -> list(txid, height)
                self.transactions          = config.get('transactions',{})        # txid -> deserialised
       t@@ -112,23 +112,33 @@ class Wallet:
                self.interface.poke('synchronizer')
                while not self.is_up_to_date(): time.sleep(0.1)
        
       -    def import_key(self, keypair, password):
       -        address, key = keypair.split(':')
       -        if not self.is_valid(address):
       -            raise BaseException('Invalid Bitcoin address')
       +    def import_key(self, sec, password):
       +        # try password
       +        try:
       +            seed = self.decode_seed(password)
       +        except:
       +            raise BaseException("Invalid password")
       +
       +        # rebuild public key from private key, compressed or uncompressed
       +        pkey = regenerate_key(sec)
       +        if not pkey:
       +            return False
       +        
       +        # figure out if private key is compressed
       +        compressed = is_compressed(sec)
       +        
       +        # rebuild private and public key from regenerated secret
       +        private_key = GetPrivKey(pkey, compressed)
       +        public_key = GetPubKey(pkey, compressed)
       +        address = public_key_to_bc_address(public_key)
       +        
                if address in self.all_addresses():
                    raise BaseException('Address already in wallet')
       -        b = ASecretToSecret( key )
       -        if not b: 
       -            raise BaseException('Unsupported key format')
       -        secexp = int( b.encode('hex'), 16)
       -        private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve=SECP256k1 )
       -        # sanity check
       -        public_key = private_key.get_verifying_key()
       -        if not address == public_key_to_bc_address( '04'.decode('hex') + public_key.to_string() ):
       -            raise BaseException('Address does not match private key')
       -        self.imported_keys[address] = self.pw_encode( key, password )
       -
       +        
       +        # store the originally requested keypair into the imported keys table
       +        self.imported_keys[address] = self.pw_encode(sec, password )
       +        return address
       +        
        
            def new_seed(self, password):
                seed = "%032x"%ecdsa.util.randrange( pow(2,128) )
       t@@ -172,19 +182,22 @@ class Wallet:
                return string_to_number( Hash( "%d:%d:"%(n,for_change) + self.master_public_key.decode('hex') ) )
        
            def get_private_key_base58(self, address, password):
       -        pk = self.get_private_key(address, password)
       -        if pk is None: return None
       -        return SecretToASecret( pk )
       +        secexp, compressed = self.get_private_key(address, password)
       +        if secexp is None: return None
       +        pk = number_to_string( secexp, generator_secp256k1.order() )
       +        return SecretToASecret( pk, compressed )
        
            def get_private_key(self, address, password):
                """  Privatekey(type,n) = Master_private_key + H(n|S|type)  """
                order = generator_secp256k1.order()
                
                if address in self.imported_keys.keys():
       -            b = self.pw_decode( self.imported_keys[address], password )
       -            if not b: return None
       -            b = ASecretToSecret( b )
       -            secexp = int( b.encode('hex'), 16)
       +            sec = self.pw_decode( self.imported_keys[address], password )
       +            if not sec: return None, None
       +            pkey = regenerate_key(sec)
       +            compressed = is_compressed(sec)
       +            secexp = pkey.secret
       +        
                else:
                    if address in self.addresses:
                        n = self.addresses.index(address)
       t@@ -194,27 +207,33 @@ class Wallet:
                        for_change = True
                    else:
                        raise BaseException("unknown address")
       -            try:
       -                seed = self.pw_decode( self.seed, password)
       -            except:
       -                raise BaseException("Invalid password")
       +
       +            seed = self.pw_decode( self.seed, password)
                    if not seed: return None
                    secexp = self.stretch_key(seed)
                    secexp = ( secexp + self.get_sequence(n,for_change) ) % order
       +            compressed = False
       +            pkey = EC_KEY(secexp)
       +
       +        public_key = GetPubKey(pkey, compressed)
       +        addr = public_key_to_bc_address(public_key)
       +        if addr != address:
       +            print_error('Invalid password with correct decoding')
       +            raise BaseException('Invalid password')
        
       -        pk = number_to_string(secexp,order)
       -        return pk
       +        return secexp, compressed
        
            def msg_magic(self, message):
                return "\x18Bitcoin Signed Message:\n" + chr( len(message) ) + message
        
            def sign_message(self, address, message, password):
       -        private_key = ecdsa.SigningKey.from_string( self.get_private_key(address, password), curve = SECP256k1 )
       +        secexp, compressed = self.get_private_key(address, password)
       +        private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve = SECP256k1 )
                public_key = private_key.get_verifying_key()
                signature = private_key.sign_digest( Hash( self.msg_magic( message ) ), sigencode = ecdsa.util.sigencode_string )
                assert public_key.verify_digest( signature, Hash( self.msg_magic( message ) ), sigdecode = ecdsa.util.sigdecode_string)
                for i in range(4):
       -            sig = base64.b64encode( chr(27+i) + signature )
       +            sig = base64.b64encode( chr(27 + i + (4 if compressed else 0)) + signature )
                    try:
                        self.verify_message( address, sig, message)
                        return sig
       t@@ -485,15 +504,16 @@ class Wallet:
                h = self.history.get(address,[])
                if h == ['*']: return 0,0
                c = u = 0
       -        received_coins = [] 
       -        
       +        received_coins = []   # list of coins received at address
       +
                for tx_hash, tx_height in h:
                    d = self.transactions.get(tx_hash)
                    if not d: continue
                    for item in d.get('outputs'):
                        addr = item.get('address')
       -                key = tx_hash + ':%d'%item['index']
       -                received_coins.append(key)
       +                if addr == address:
       +                    key = tx_hash + ':%d'%item['index']
       +                    received_coins.append(key)
        
                for tx_hash, tx_height in h:
                    d = self.transactions.get(tx_hash)
       t@@ -597,9 +617,13 @@ class Wallet:
                s_inputs = []
                for i in range(len(inputs)):
                    addr, v, p_hash, p_pos, p_scriptPubKey, _, _ = inputs[i]
       -            private_key = ecdsa.SigningKey.from_string( self.get_private_key(addr, password), curve = SECP256k1 )
       +            secexp, compressed = self.get_private_key(addr, password)
       +            private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve = SECP256k1 )
                    public_key = private_key.get_verifying_key()
       -            pubkey = public_key.to_string()
       +
       +            pkey = EC_KEY(secexp)
       +            pubkey = GetPubKey(pkey, compressed)
       +
                    tx = filter( raw_tx( inputs, outputs, for_sig = i ) )
                    sig = private_key.sign_digest( Hash( tx.decode('hex') ), sigencode = ecdsa.util.sigencode_der )
                    assert public_key.verify_digest( sig, Hash( tx.decode('hex') ), sigdecode = ecdsa.util.sigdecode_der)
       t@@ -616,16 +640,28 @@ class Wallet:
            def pw_decode(self, s, password):
                if password is not None:
                    secret = Hash(password)
       -            d = DecodeAES(secret, s)
       -            if s == self.seed:
       -                try:
       -                    d.decode('hex')
       -                except:
       -                    raise ValueError("Invalid password")
       +            try:
       +                d = DecodeAES(secret, s)
       +            except:
       +                raise BaseException('Invalid password')
                    return d
                else:
                    return s
        
       +    def decode_seed(self, password):
       +        seed = self.pw_decode(self.seed, password)
       +
       +        # check decoded seed with master public key
       +        curve = SECP256k1
       +        secexp = self.stretch_key(seed)
       +        master_private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve = SECP256k1 )
       +        master_public_key = master_private_key.get_verifying_key().to_string().encode('hex')
       +        if master_public_key != self.master_public_key:
       +            print_error('invalid password (mpk)')
       +            raise BaseException('Invalid password')
       +
       +        return seed
       +
        
            def get_history(self, address):
                with self.lock:
       t@@ -699,7 +735,7 @@ class Wallet:
                balance = c + u - balance
                for tx in history:
                    tx_hash = tx['tx_hash']
       -            conf, timestamp = self.verifier.get_confirmations(tx_hash) if self.verifier else None
       +            conf, timestamp = self.verifier.get_confirmations(tx_hash) if self.verifier else (None, None)
                    is_mine, value, fee = self.get_tx_value(tx_hash)
                    if value is not None:
                        balance += value
   DIR diff --git a/lib/wallet_bitkey.py b/lib/wallet_bitkey.py
       t@@ -0,0 +1,28 @@
       +#!/usr/bin/env python
       +#
       +# Electrum - lightweight Bitcoin client
       +# Copyright (C) 2011 thomasv@gitorious
       +#
       +# This program is free software: you can redistribute it and/or modify
       +# it under the terms of the GNU General Public License as published by
       +# the Free Software Foundation, either version 3 of the License, or
       +# (at your option) any later version.
       +#
       +# This program is distributed in the hope that it will be useful,
       +# but WITHOUT ANY WARRANTY; without even the implied warranty of
       +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
       +# GNU General Public License for more details.
       +#
       +# You should have received a copy of the GNU General Public License
       +# along with this program. If not, see <http://www.gnu.org/licenses/>.
       +
       +import os
       +
       +from wallet import Wallet
       +#import bitkeylib.bitkey_pb2 as proto
       +
       +from version import ELECTRUM_VERSION
       +SEED_VERSION = 4 # Version of bitkey algorithm
       +
       +class WalletBitkey(Wallet):
       +    pass
   DIR diff --git a/lib/wallet_factory.py b/lib/wallet_factory.py
       t@@ -0,0 +1,11 @@
       +class WalletFactory(object):
       +    def __new__(cls, config):
       +        if config.get('bitkey', False):
       +            # if user requested support for Bitkey device,
       +            # import Bitkey driver
       +            from wallet_bitkey import WalletBitkey
       +            return WalletBitkey(config)
       +        
       +        # Load standard wallet
       +        from wallet import Wallet
       +        return Wallet(config)
   DIR diff --git a/setup-release.py b/setup-release.py
       t@@ -60,7 +60,7 @@ if sys.platform == 'darwin':
              qt_menu_location = "/opt/local/lib/Resources/qt_menu.nib"
            else:
              # No dice? Then let's try the brew version
       -      qt_menu_location = os.popen("mdfind -name qt_menu.nib | grep Cellar | head").read()
       +      qt_menu_location = os.popen("find /usr/local/Cellar -name qt_menu.nib | head").read()
              qt_menu_location = re.sub('\n','', qt_menu_location)
        
            if(len(qt_menu_location) == 0):
   DIR diff --git a/setup.py b/setup.py
       t@@ -30,6 +30,10 @@ data_files += [
                "data/cleanlook/name.cfg",
                "data/cleanlook/style.css"
            ]),
       +    (os.path.join(util.appdata_dir(), "sahara"), [
       +        "data/sahara/name.cfg",
       +        "data/sahara/style.css"
       +    ]),    
            (os.path.join(util.appdata_dir(), "dark"), [
                "data/dark/background.png",
                "data/dark/name.cfg",
       t@@ -46,6 +50,8 @@ setup(name = "Electrum",
            data_files = data_files,
            py_modules = ['electrum.version',
                          'electrum.wallet',
       +                  'electrum.wallet_bitkey',
       +                  'electrum.wallet_factory',
                          'electrum.interface',
                          'electrum.gui',
                          'electrum.gui_qt',