move master_private_keys and master_public_keys to NewWallet
[electrum-nvc.git] / gui / android.py
index 9750453..a89673c 100644 (file)
 
 
 
+from __future__ import absolute_import
 import android
 
-from electrum import SimpleConfig, Interface, WalletSynchronizer, Wallet, format_satoshis, mnemonic_encode, mnemonic_decode, is_valid
+from electrum import SimpleConfig, Wallet, WalletStorage, format_satoshis, mnemonic_encode, mnemonic_decode
+from electrum.bitcoin import is_valid
 from electrum import util
 from decimal import Decimal
 import datetime, re
@@ -42,10 +44,12 @@ def modal_input(title, msg, value = None, etype=None):
     droid.dialogShow()
     response = droid.dialogGetResponse()
     result = response.result
+    droid.dialogDismiss()
+
     if result is None:
         print "modal input: result is none"
-        return False
-    droid.dialogDismiss()
+        return modal_input(title, msg, value, etype)
+
     if result.get('which') == 'positive':
         return result.get('value')
 
@@ -56,10 +60,12 @@ def modal_question(q, msg, pos_text = 'OK', neg_text = 'Cancel'):
     droid.dialogShow()
     response = droid.dialogGetResponse()
     result = response.result
+    droid.dialogDismiss()
+
     if result is None:
         print "modal question: result is none"
-        return False
-    droid.dialogDismiss()
+        return modal_question(q,msg, pos_text, neg_text)
+
     return result.get('which') == 'positive'
 
 def edit_label(addr):
@@ -119,7 +125,7 @@ def select_from_addresses():
 def protocol_name(p):
     if p == 't': return 'TCP'
     if p == 'h': return 'HTTP'
-    if p == 's': return 'TCP/SSL'
+    if p == 's': return 'SSL'
     if p == 'g': return 'HTTPS'
 
 
@@ -144,9 +150,7 @@ def protocol_dialog(host, protocol, z):
     if not response: return
     if not selected_item: return
     if response.get('which') == 'positive':
-        p = protocols[selected_item[0]]
-        port = z[p]
-        return host + ':' + port + ':' + p
+        return protocols[selected_item[0]]
 
 
 
@@ -341,7 +345,7 @@ def get_history_values(n):
                 time_str = str( dt.time() )
             else:
                 time_str = str( dt.date() )
-        except:
+        except Exception:
             time_str = 'pending'
 
         conf_str = 'v' if conf else 'o'
@@ -417,7 +421,7 @@ def set_history_layout(n):
 status_text = ''
 def update_layout():
     global status_text
-    if not wallet.interface.is_connected:
+    if not network.is_connected():
         text = "Not connected..."
     elif not wallet.up_to_date:
         text = "Synchronizing..."
@@ -429,7 +433,7 @@ def update_layout():
 
     # vibrate if status changed
     if text != status_text:
-        if status_text and wallet.interface.is_connected and wallet.up_to_date:
+        if status_text and network.is_connected() and wallet.up_to_date:
             droid.vibrate()
         status_text = text
 
@@ -454,7 +458,7 @@ def pay_to(recipient, amount, fee, label):
 
     try:
         tx = wallet.mktx( [(recipient, amount)], password, fee)
-    except BaseException, e:
+    except Exception as e:
         modal_dialog('error', e.message)
         droid.dialogDismiss()
         return
@@ -484,7 +488,7 @@ def make_new_contact():
         data = r['extras']['SCAN_RESULT']
         if data:
             if re.match('^bitcoin:', data):
-                address, _, _, _, _, _, _ = util.parse_url(data)
+                address, _, _, _, _ = util.parse_URI(data)
             elif is_valid(data):
                 address = data
             else:
@@ -500,7 +504,7 @@ do_refresh = False
 
 def update_callback():
     global do_refresh
-    print "gui callback", wallet.interface.is_connected, wallet.up_to_date
+    print "gui callback", network.is_connected()
     do_refresh = True
     droid.eventPost("refresh",'z')
 
@@ -596,7 +600,7 @@ def payto_loop():
 
                 try:
                     amount = int( 100000000 * Decimal(amount) )
-                except:
+                except Exception:
                     modal_dialog('Error','Invalid amount')
                     continue
 
@@ -615,7 +619,7 @@ def payto_loop():
                     data = r['extras']['SCAN_RESULT']
                     if data:
                         if re.match('^bitcoin:', data):
-                            payto, amount, label, _, _, _, _ = util.parse_url(data)
+                            payto, amount, label, _, _ = util.parse_URI(data)
                             droid.fullSetProperty("recipient", "text",payto)
                             droid.fullSetProperty("amount", "text", amount)
                             droid.fullSetProperty("label", "text", label)
@@ -705,7 +709,7 @@ def server_dialog(servers):
         return response
 
 
-def seed_dialog():
+def show_seed():
     if wallet.use_encryption:
         password  = droid.dialogGetPassword('Seed').result
         if not password: return
@@ -713,8 +717,8 @@ def seed_dialog():
         password = None
     
     try:
-        seed = wallet.decode_seed(password)
-    except:
+        seed = wallet.get_seed(password)
+    except Exception:
         modal_dialog('error','incorrect password')
         return
 
@@ -729,8 +733,8 @@ def change_password_dialog():
         password = None
 
     try:
-        seed = wallet.decode_seed(password)
-    except:
+        wallet.get_seed(password)
+    except Exception:
         modal_dialog('error','incorrect password')
         return
 
@@ -744,7 +748,7 @@ def change_password_dialog():
             modal_dialog('error','passwords do not match')
             return
 
-    wallet.update_password(seed, password, new_password)
+    wallet.update_password(password, new_password)
     if new_password:
         modal_dialog('Password updated','your wallet is encrypted')
     else:
@@ -756,12 +760,12 @@ def settings_loop():
 
 
     def set_listview():
-        server, port, p = interface.server.split(':')
+        host, port, p = network.default_server.split(':')
         fee = str( Decimal( wallet.fee)/100000000 )
         is_encrypted = 'yes' if wallet.use_encryption else 'no'
         protocol = protocol_name(p)
         droid.fullShow(settings_layout)
-        droid.fullSetList("myListView",['Server: ' + server, 'Protocol: '+ protocol, 'Port: '+port, 'Transaction fee: '+fee, 'Password: '+is_encrypted, 'Seed'])
+        droid.fullSetList("myListView",['Server: ' + host, 'Protocol: '+ protocol, 'Port: '+port, 'Transaction fee: '+fee, 'Password: '+is_encrypted, 'Seed'])
 
     set_listview()
 
@@ -773,56 +777,41 @@ def settings_loop():
         if event == 'OK': continue
         if not event: continue
 
-        servers = interface.get_servers()
+        servers = network.get_servers()
         name = event.get("name")
         if not name: continue
 
         if name == "itemclick":
             pos = event["data"]["position"]
-            host, port, protocol = interface.server.split(':')
+            host, port, protocol = network.default_server.split(':')
+            network_changed = False
 
             if pos == "0": #server
                 host = server_dialog(servers)
                 if host:
                     p = servers[host]
-                    port = p['t']
-                    srv = host + ':' + port + ':t'
-                    wallet.config.set_key("server", srv, True)
-                    try:
-                        wallet.interface.set_server(srv)
-                    except:
-                        modal_dialog('error','invalid server')
-                    set_listview()
+                    port = p[protocol]
+                    network_changed = True
 
             elif pos == "1": #protocol
                 if host in servers:
-                    srv = protocol_dialog(host, protocol, servers[host])
-                    if srv:
-                        wallet.config.set_key("server", srv, True)
-                        try:
-                            wallet.interface.set_server(srv)
-                        except:
-                            modal_dialog('error','invalid server')
-                        set_listview()
+                    protocol = protocol_dialog(host, protocol, servers[host])
+                    z = servers[host]
+                    port = z[protocol]
+                    network_changed = True
 
             elif pos == "2": #port
                 a_port = modal_input('Port number', 'If you use a public server, this field is set automatically when you set the protocol', port, "number")
-                if a_port:
-                    if a_port != port:
-                        srv = host + ':' + a_port + ':'+ protocol
-                        wallet.config.set_key("server", srv, True)
-                        try:
-                            wallet.interface.set_server(srv)
-                        except:
-                            modal_dialog('error','invalid port number')
-                        set_listview()
+                if a_port != port:
+                    port = a_port
+                    network_changed = True
 
             elif pos == "3": #fee
                 fee = modal_input('Transaction fee', 'The fee will be this amount multiplied by the number of inputs in your transaction. ', str( Decimal( wallet.fee)/100000000 ), "numberDecimal")
                 if fee:
                     try:
                         fee = int( 100000000 * Decimal(fee) )
-                    except:
+                    except Exception:
                         modal_dialog('error','invalid fee value')
                     wallet.set_fee(fee)
                     set_listview()
@@ -832,8 +821,16 @@ def settings_loop():
                     set_listview()
 
             elif pos == "5":
-                seed_dialog()
+                show_seed()
 
+            if network_changed:
+                proxy = None
+                auto_connect = False
+                try:
+                    network.set_parameters(host, port, protocol, proxy, auto_connect)
+                except Exception:
+                    modal_dialog('error','invalid server')
+                set_listview()
 
         elif name in menu_commands:
             out = event["name"]
@@ -885,18 +882,50 @@ def make_bitmap(addr):
 droid = android.Android()
 menu_commands = ["send", "receive", "settings", "contacts", "main"]
 wallet = None
-interface = None
+network = None
 
 class ElectrumGui:
 
-    def __init__(self, w, config, app=None):
-        global wallet, interface
-        wallet = w
-        interface = wallet.interface
-        interface.register_callback('updated',update_callback)
-        interface.register_callback('connected', update_callback)
-        interface.register_callback('disconnected', update_callback)
-        interface.register_callback('disconnecting', update_callback)
+    def __init__(self, config, _network):
+        global wallet, network
+        network = _network
+        network.register_callback('updated', update_callback)
+        network.register_callback('connected', update_callback)
+        network.register_callback('disconnected', update_callback)
+        network.register_callback('disconnecting', update_callback)
+        
+        storage = WalletStorage(config)
+        if not storage.file_exists:
+            action = self.restore_or_create()
+            if not action: exit()
+
+            wallet = Wallet(storage)
+            if action == 'create':
+                wallet.init_seed(None)
+                self.show_seed()
+                wallet.save_seed(None)
+                wallet.synchronize()  # generate first addresses offline
+                
+            elif action == 'restore':
+                seed = self.seed_dialog()
+                if not seed:
+                    exit()
+                wallet.init_seed(str(seed))
+                wallet.save_seed(None)
+            else:
+                exit()
+
+            wallet.start_threads(network)
+
+            if action == 'restore':
+                if not self.restore_wallet():
+                    exit()
+
+            self.password_dialog()
+
+        else:
+            wallet = Wallet(storage)
+            wallet.start_threads(network)
 
 
     def main(self, url):
@@ -929,6 +958,7 @@ class ElectrumGui:
 
         droid.makeToast("Bye!")
 
+
     def restore_or_create(self):
         droid.dialogCreateAlert("Wallet not found","Do you want to create a new wallet, or restore an existing one?")
         droid.dialogSetPositiveButtonText('Create')
@@ -943,8 +973,9 @@ class ElectrumGui:
 
         return 'restore' if response.get('which') == 'neutral' else 'create'
 
+
     def seed_dialog(self):
-        if modal_question("Input method",None,'QR Code', 'mnemonic'):
+        if modal_question("Enter your seed","Input method",'QR Code', 'mnemonic'):
             code = droid.scanBarcode()
             r = code.result
             if r:
@@ -955,21 +986,16 @@ class ElectrumGui:
             m = modal_input('Mnemonic','please enter your code')
             try:
                 seed = mnemonic_decode(m.split(' '))
-            except:
+            except Exception:
                 modal_dialog('error: could not decode this seed')
                 return
 
-        gap = 5   # default
-
-        return str(seed), gap
+        return str(seed)
 
 
     def network_dialog(self):
         return True
 
-    def verify_seed(self):
-        wallet.save_seed()
-        return True
         
     def show_seed(self):
         modal_dialog('Your seed is:', wallet.seed)
@@ -986,7 +1012,7 @@ class ElectrumGui:
         droid.dialogCreateSpinnerProgress("Electrum", msg)
         droid.dialogShow()
 
-        wallet.update()
+        wallet.restore(lambda x: None)
 
         droid.dialogDismiss()
         droid.vibrate()
@@ -998,6 +1024,5 @@ class ElectrumGui:
             if not modal_question("no transactions found for this seed","do you want to keep this wallet?"):
                 return False
 
-        wallet.save()
         return True