big refactoring: command line options and electrum.conf options override settings...
authorthomasv <thomasv@gitorious>
Thu, 11 Oct 2012 18:10:12 +0000 (20:10 +0200)
committerthomasv <thomasv@gitorious>
Thu, 11 Oct 2012 18:10:12 +0000 (20:10 +0200)
13 files changed:
electrum
lib/__init__.py
lib/gui.py
lib/gui_lite.py
lib/gui_qt.py
lib/interface.py
lib/simple_config.py
lib/wallet.py
scripts/blocks
scripts/get_history
scripts/merchant.py
scripts/peers
scripts/watch_address

index df1332d..314d25e 100755 (executable)
--- a/electrum
+++ b/electrum
@@ -18,7 +18,6 @@
 
 import re
 import sys
-# import argparse
 import optparse
 
 try:
@@ -37,9 +36,9 @@ except ImportError:
     sys.exit("Error: AES does not seem to be installed. Try 'sudo pip install slowaes'")
 
 try:
-    from lib import Wallet, WalletSynchronizer, format_satoshis, mnemonic, prompt_password, parse_proxy_options, SimpleConfig
+    from lib import Wallet, WalletSynchronizer, format_satoshis, mnemonic, prompt_password, SimpleConfig, pick_random_server
 except ImportError:
-    from electrum import Wallet, WalletSynchronizer, format_satoshis, mnemonic, prompt_password, parse_proxy_options, SimpleConfig
+    from electrum import Wallet, WalletSynchronizer, format_satoshis, mnemonic, prompt_password, SimpleConfig, pick_random_server
 
 from decimal import Decimal
 
@@ -95,33 +94,39 @@ options:\n  --fee, -f: set transaction fee\n  --fromaddr, -s: send from address
 
 
 
-offline_commands = [ 'password', 'mktx', 'label', 'contacts', 'help', 'validateaddress', 'signmessage', 'verifymessage', 'eval', 'create', 'addresses', 'import', 'seed','deseed','reseed','freeze','unfreeze','prioritize','unprioritize']
+offline_commands = [ 'password', 'mktx',
+                     'label', 'contacts',
+                     'help', 'validateaddress',
+                     'signmessage', 'verifymessage',
+                     'eval', 'create', 'addresses',
+                     'import', 'seed',
+                     'deseed','reseed',
+                     'freeze','unfreeze',
+                     'prioritize','unprioritize']
+
 
 protected_commands = ['payto', 'password', 'mktx', 'seed', 'import','signmessage' ]
 
 if __name__ == '__main__':
 
-    # Load simple config class
-    simple_config = SimpleConfig()
-
     usage = "usage: %prog [options] command\nCommands: "+ (', '.join(known_commands))
     parser = optparse.OptionParser(prog=usage)
-    parser.add_option("-g", "--gui", dest="gui", default=simple_config.config["gui"], help="gui")
+    parser.add_option("-g", "--gui", dest="gui", help="gui")
     parser.add_option("-w", "--wallet", dest="wallet_path", help="wallet path (default: electrum.dat)")
     parser.add_option("-o", "--offline", action="store_true", dest="offline", default=False, help="remain offline")
     parser.add_option("-a", "--all", action="store_true", dest="show_all", default=False, help="show all addresses")
     parser.add_option("-b", "--balance", action="store_true", dest="show_balance", default=False, help="show the balance at listed addresses")
     parser.add_option("-k", "--keys",action="store_true", dest="show_keys",default=False, help="show the private keys of listed addresses")
     parser.add_option("-f", "--fee", dest="tx_fee", default="0.005", help="set tx fee")
-    parser.add_option("-s", "--fromaddr", dest="from_addr", default=None, help="set source address for payto/mktx. if it isn't in the wallet, it will ask for the private key unless supplied in the format public_key:private_key. It's not saved in the wallet.")
+    parser.add_option("-F", "--fromaddr", dest="from_addr", default=None, help="set source address for payto/mktx. if it isn't in the wallet, it will ask for the private key unless supplied in the format public_key:private_key. It's not saved in the wallet.")
     parser.add_option("-c", "--changeaddr", dest="change_addr", default=None, help="set the change address for payto/mktx. default is a spare address, or the source address if it's not in the wallet")
+    parser.add_option("-s", "--server", dest="server", default=None, help="set server host:port:protocol, where protocol is t or h")
     parser.add_option("-p", "--proxy", dest="proxy", default=None, help="set proxy [type:]host[:port], where type is socks4,socks5 or http")
     options, args = parser.parse_args()
 
-    proxy = parse_proxy_options(options.proxy) if options.proxy else simple_config.config["proxy"]
-    wallet = Wallet()
-    wallet.set_path(options.wallet_path)
-    wallet.read()
+    # config is an object passed to the various constructors (wallet, interface, gui)
+    config = SimpleConfig(options)
+    wallet = Wallet(config)
 
     if len(args)==0:
         url = None
@@ -136,31 +141,31 @@ if __name__ == '__main__':
     #this entire if/else block is just concerned with importing the 
     #right GUI toolkit based the GUI command line option given 
     if cmd == 'gui':
-        
-        if options.gui=='gtk':
+        pref_gui = config.get('gui','qt')
+        if pref_gui == 'gtk':
             try:
                 import lib.gui as gui
             except ImportError:
                 import electrum.gui as gui
-        elif options.gui=='qt':
+        elif pref_gui == 'qt':
             try:
                 import lib.gui_qt as gui
             except ImportError:
                 import electrum.gui_qt as gui
-        elif options.gui == 'lite':
+        elif pref_gui == 'lite':
               try:
                   import lib.gui_lite as gui
               except ImportError:
                   import electrum.gui_lite as gui
         else:
-            sys.exit("Error: Unknown GUI: " + options.gui)
+            sys.exit("Error: Unknown GUI: " + pref_gui )
 
-        gui = gui.ElectrumGui(wallet)
-        interface = WalletSynchronizer(wallet, True, gui.server_list_changed, proxy)
+        gui = gui.ElectrumGui(wallet, config)
+        interface = WalletSynchronizer(wallet, config, True, gui.server_list_changed)
         interface.start()
 
         try:
-            found = wallet.file_exists
+            found = config.wallet_file_exists
             if not found:
                 found = gui.restore_or_create()
         except SystemExit, e:
@@ -180,17 +185,19 @@ if __name__ == '__main__':
     if cmd not in known_commands:
         cmd = 'help'
 
-    if not wallet.file_exists and cmd not in ['help','create','restore']:
+    if not config.wallet_file_exists and cmd not in ['help','create','restore']:
         print "Error: Wallet file not found."
         print "Type 'electrum create' to create a new wallet, or provide a path to a wallet with the -w option"
         sys.exit(0)
     
     if cmd in ['create', 'restore']:
-        if wallet.file_exists:
+        if config.wallet_file_exists:
             sys.exit("Error: Remove the existing wallet first!")
         password = prompt_password("Password (hit return if you do not wish to encrypt your wallet):")
 
-        w_host, w_port, w_protocol = wallet.server.split(':')
+        server = config.get('server')
+        if not server: server = pick_random_server()
+        w_host, w_port, w_protocol = server.split(':')
         host = raw_input("server (default:%s):"%w_host)
         port = raw_input("port (default:%s):"%w_port)
         protocol = raw_input("protocol [t=tcp;h=http;n=native] (default:%s):"%w_protocol)
@@ -199,7 +206,7 @@ if __name__ == '__main__':
         if host: w_host = host
         if port: w_port = port
         if protocol: w_protocol = protocol
-        wallet.server = w_host + ':' + w_port + ':' +w_protocol
+        wallet.config.set_key('server', w_host + ':' + w_port + ':' +w_protocol)
         if fee: wallet.fee = float(fee)
         if gap: wallet.gap_limit = int(gap)
 
@@ -216,7 +223,7 @@ if __name__ == '__main__':
             wallet.seed = str(seed)
             wallet.init_mpk( wallet.seed )
             if not options.offline:
-                WalletSynchronizer(wallet, proxy=proxy).start()
+                WalletSynchronizer(wallet, config).start()
                 print "Recovering wallet..."
                 wallet.up_to_date_event.clear()
                 wallet.up_to_date = False
@@ -239,7 +246,7 @@ if __name__ == '__main__':
             print "Please keep it in a safe place; if you lose it, you will not be able to restore your wallet."
             print "Equivalently, your wallet seed can be stored and recovered with the following mnemonic code:"
             print "\""+' '.join(mnemonic.mn_encode(wallet.seed))+"\""
-            print "Wallet saved in '%s'"%wallet.path
+            print "Wallet saved in '%s'"%wallet.config.path
             
         if password:
             wallet.update_password(wallet.seed, None, password)
@@ -259,7 +266,7 @@ if __name__ == '__main__':
 
     # open session
     if cmd not in offline_commands and not options.offline:
-        WalletSynchronizer(wallet, proxy=proxy).start()
+        WalletSynchronizer(wallet, config).start()
         wallet.update()
         wallet.save()
 
index 3618ccf..2ca45e3 100644 (file)
@@ -1,4 +1,3 @@
 from wallet import Wallet, format_satoshis, prompt_password
-from interface import WalletSynchronizer, parse_proxy_options
-from interface import TcpStratumInterface
+from interface import WalletSynchronizer, Interface, pick_random_server
 from simple_config import SimpleConfig
index 13c43d5..837dd9a 100644 (file)
@@ -558,12 +558,13 @@ class ElectrumWindow:
     def show_message(self, msg):
         show_message(msg, self.window)
 
-    def __init__(self, wallet):
+    def __init__(self, wallet, config):
+        self.config = config
         self.wallet = wallet
         self.funds_error = False # True if not enough funds
 
         self.window = MyWindow(gtk.WINDOW_TOPLEVEL)
-        title = 'Electrum ' + self.wallet.electrum_version + '  -  ' + self.wallet.path
+        title = 'Electrum ' + self.wallet.electrum_version + '  -  ' + self.config.path
         if not self.wallet.seed: title += ' [seedless]'
         self.window.set_title(title)
         self.window.connect("destroy", gtk.main_quit)
@@ -1298,11 +1299,12 @@ class ElectrumWindow:
 
 class ElectrumGui():
 
-    def __init__(self, wallet):
+    def __init__(self, wallet, config):
         self.wallet = wallet
+        self.config = config
 
     def main(self, url=None):
-        ew = ElectrumWindow(self.wallet)
+        ew = ElectrumWindow(self.wallet, self.config)
         if url: ew.set_url(url)
         gtk.main()
 
index 16f2e3a..d17da04 100644 (file)
@@ -13,17 +13,13 @@ except ImportError:
 qtVersion = qVersion()
 if not(int(qtVersion[0]) >= 4 and int(qtVersion[2]) >= 7):
     app = QApplication(sys.argv)
-    QMessageBox.warning(None,"Could not start Lite GUI.", "Electrum was unable to load the 'Lite GUI' because it needs Qt version >= 4.7.\nElectrum was set to use the 'Qt' GUI")
-    from simple_config import SimpleConfig
-    cfg = SimpleConfig()
-    cfg.set_key("gui", "qt",True)
+    QMessageBox.warning(None,"Could not start Lite GUI.", "Electrum was unable to load the 'Lite GUI' because it needs Qt version >= 4.7.\nPlease use the 'Qt' GUI")
     sys.exit(0)
 
 
 
 from decimal import Decimal as D
 from interface import DEFAULT_SERVERS
-from simple_config import SimpleConfig
 from util import get_resource_path as rsrc
 from i18n import _
 import decimal
@@ -61,10 +57,11 @@ def resize_line_edit_width(line_edit, text_input):
 
 class ElectrumGui(QObject):
 
-    def __init__(self, wallet):
+    def __init__(self, wallet, config):
         super(QObject, self).__init__()
 
         self.wallet = wallet
+        self.config = config
         self.app = QApplication(sys.argv)
 
     def main(self, url):
@@ -76,7 +73,7 @@ class ElectrumGui(QObject):
         old_path = QDir.currentPath()
         actuator.load_theme()
 
-        self.mini = MiniWindow(actuator, self.expand)
+        self.mini = MiniWindow(actuator, self.expand, self.config)
         driver = MiniDriver(self.wallet, self.mini)
 
         # Reset path back to original value now that loading the GUI
@@ -88,12 +85,10 @@ class ElectrumGui(QObject):
 
         timer = Timer()
         timer.start()
-        self.expert = gui_qt.ElectrumWindow(self.wallet)
+        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 server_list_changed(self):
@@ -124,10 +119,11 @@ class ElectrumGui(QObject):
 
 class MiniWindow(QDialog):
 
-    def __init__(self, actuator, expand_callback):
+    def __init__(self, actuator, expand_callback, config):
         super(MiniWindow, self).__init__()
 
         self.actuator = actuator
+        self.config = config
 
         self.btc_balance = None
         self.quote_currencies = ["EUR", "USD", "GBP"]
@@ -259,11 +255,12 @@ class MiniWindow(QDialog):
         close_shortcut = QShortcut(QKeySequence("Ctrl+W"), self)
         close_shortcut.activated.connect(self.close)
 
-        self.cfg = SimpleConfig()
-        g = self.cfg.config["winpos-lite"]
+        g = self.config.get("winpos-lite",[4, 25, 351, 149])
         self.setGeometry(g[0], g[1], g[2], g[3])
-        show_history.setChecked(self.cfg.config["history"])
-        self.show_history(self.cfg.config["history"])
+
+        show_hist = self.config.get("gui_show_history",False)
+        show_history.setChecked(show_hist)
+        self.show_history(show_hist)
         
         self.setWindowIcon(QIcon(":electrum.png"))
         self.setWindowTitle("Electrum")
@@ -282,9 +279,8 @@ class MiniWindow(QDialog):
 
     def closeEvent(self, event):
         g = self.geometry()
-        self.cfg.set_key("winpos-lite", [g.left(),g.top(),g.width(),g.height()])
-        self.cfg.set_key("history", self.history_list.isVisible())
-        self.cfg.save_config()
+        self.config.set_key("winpos-lite", [g.left(),g.top(),g.width(),g.height()],True)
+        self.config.set_key("history", self.history_list.isVisible(),True)
         
         super(MiniWindow, self).closeEvent(event)
         qApp.quit()
@@ -563,7 +559,7 @@ class MiniActuator:
     def __init__(self, wallet):
         """Retrieve the gui theme used in previous session."""
         self.wallet = wallet
-        self.theme_name = self.wallet.theme
+        self.theme_name = self.wallet.config.get('litegui_theme','Cleanlook')
         self.themes = util.load_theme_paths()
 
     def load_theme(self):
@@ -587,13 +583,14 @@ class MiniActuator:
 
     def change_theme(self, theme_name):
         """Change theme."""
-        self.wallet.theme = self.theme_name = theme_name
+        self.theme_name = theme_name
+        self.wallet.config.set_key('litegui_theme',theme_name)
         self.load_theme()
     
     def set_configured_currency(self, set_quote_currency):
         """Set the inital fiat currency conversion country (USD/EUR/GBP) in 
         the GUI to what it was set to in the wallet."""
-        currency = self.wallet.conversion_currency
+        currency = self.wallet.config.get('conversion_currency')
         # currency can be none when Electrum is used for the first
         # time and no setting has been created yet.
         if currency is not None:
@@ -601,7 +598,7 @@ class MiniActuator:
 
     def set_config_currency(self, conversion_currency):
         """Change the wallet fiat currency country."""
-        self.wallet.conversion_currency = conversion_currency
+        self.wallet.config.set_key('conversion_currency',conversion_currency,True)
 
     def set_servers_gui_stuff(self, servers_menu, servers_group):
         self.servers_menu = servers_menu
@@ -620,7 +617,7 @@ class MiniActuator:
             print "Servers loaded."
             self.servers_list = interface.servers
         server_names = [details[0] for details in self.servers_list]
-        current_server = self.wallet.server.split(":")[0]
+        current_server = interface.server.split(":")[0]
         for server_name in server_names:
             server_action = self.servers_menu.addAction(server_name)
             server_action.setCheckable(True)
@@ -661,8 +658,7 @@ class MiniActuator:
         server_line = "%s:%s:%s" % (server_name, port, protocol)
 
         # Should this have exception handling?
-        self.cfg = SimpleConfig()
-        self.wallet.set_server(server_line, self.cfg.config["proxy"])
+        self.wallet.set_server(server_line, self.config.get(["proxy"]))
 
     def copy_address(self, receive_popup):
         """Copy the wallet addresses into the client."""
index df0af81..f0f4db5 100644 (file)
@@ -37,9 +37,7 @@ except:
     sys.exit("Error: Could not import icons_rc.py, please generate it with: 'pyrcc4 icons.qrc -o lib/icons_rc.py'")
 
 from wallet import format_satoshis
-from simple_config import SimpleConfig
 import bmp, mnemonic, pyqrnative, qrscanner
-from simple_config import SimpleConfig
 
 from decimal import Decimal
 
@@ -185,11 +183,14 @@ def ok_cancel_buttons(dialog):
 
 class ElectrumWindow(QMainWindow):
 
-    def __init__(self, wallet):
+    def __init__(self, wallet, config):
         QMainWindow.__init__(self)
         self.wallet = wallet
+        self.config = config
         self.wallet.register_callback(self.update_callback)
 
+        self.detailed_view = config.get('qt_detailed_view', False)
+
         self.funds_error = False
         self.completions = QStringListModel()
 
@@ -204,10 +205,10 @@ class ElectrumWindow(QMainWindow):
         tabs.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
         self.setCentralWidget(tabs)
         self.create_status_bar()
-        cfg = SimpleConfig()
-        g = cfg.config["winpos-qt"]
+
+        g = self.config.get("winpos-qt",[100, 100, 840, 400])
         self.setGeometry(g[0], g[1], g[2], g[3])
-        title = 'Electrum ' + self.wallet.electrum_version + '  -  ' + self.wallet.path
+        title = 'Electrum ' + self.wallet.electrum_version + '  -  ' + self.config.path
         if not self.wallet.seed: title += ' [seedless]'
         self.setWindowTitle( title )
 
@@ -696,10 +697,12 @@ class ElectrumWindow(QMainWindow):
         return w
 
     def details_button_text(self):
-        return _('Hide details') if self.wallet.gui_detailed_view else _('Show details')
+        return _('Hide details') if self.detailed_view else _('Show details')
 
     def toggle_detailed_view(self):
-        self.wallet.gui_detailed_view = not self.wallet.gui_detailed_view
+        self.detailed_view = not self.detailed_view
+        self.config.set_key('qt_detailed_view', self.detailed_view, True)
+
         self.details_button.setText(self.details_button_text())
         self.wallet.save()
         self.update_receive_tab()
@@ -731,11 +734,11 @@ class ElectrumWindow(QMainWindow):
         menu.addAction(_("Copy to Clipboard"), lambda: self.app.clipboard().setText(addr))
         menu.addAction(_("View QR code"),lambda: self.show_address_qrcode(addr))
         menu.addAction(_("Edit label"), lambda: self.edit_label(True))
-        if self.wallet.gui_detailed_view:
-            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))
+
+        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))
 
 
@@ -790,9 +793,9 @@ class ElectrumWindow(QMainWindow):
     def update_receive_tab(self):
         l = self.receive_list
         l.clear()
-        l.setColumnHidden(0,not self.wallet.gui_detailed_view)
-        l.setColumnHidden(3,not self.wallet.gui_detailed_view)
-        l.setColumnHidden(4,not self.wallet.gui_detailed_view)
+        l.setColumnHidden(0,not self.detailed_view)
+        l.setColumnHidden(3,not self.detailed_view)
+        l.setColumnHidden(4,not self.detailed_view)
         l.setColumnWidth(0, 50) 
         l.setColumnWidth(1, 310) 
         l.setColumnWidth(2, 250)
@@ -803,7 +806,7 @@ class ElectrumWindow(QMainWindow):
         is_red = False
         for address in self.wallet.all_addresses():
 
-            if self.wallet.is_change(address) and not self.wallet.gui_detailed_view:
+            if self.wallet.is_change(address) and not self.detailed_view:
                 continue
 
             label = self.wallet.labels.get(address,'')
@@ -855,7 +858,7 @@ class ElectrumWindow(QMainWindow):
 
         l = self.contacts_list
         l.clear()
-        l.setColumnHidden(2, not self.wallet.gui_detailed_view)
+        l.setColumnHidden(2, not self.detailed_view)
         l.setColumnWidth(0, 350) 
         l.setColumnWidth(1, 330)
         l.setColumnWidth(2, 100) 
@@ -1247,9 +1250,8 @@ class ElectrumWindow(QMainWindow):
         gap_e.textChanged.connect(lambda: numbify(nz_e,True))
         
         gui = QComboBox()
-        gui.addItems(['Lite', 'Qt'])
-        cfg = SimpleConfig()
-        gui.setCurrentIndex(gui.findText(cfg.config["gui"].capitalize()))
+        gui.addItems(['Lite', 'Qt', 'Gtk'])
+        gui.setCurrentIndex(gui.findText(self.config.get("gui","lite").capitalize()))
         grid.addWidget(QLabel(_('Default GUI') + ':'), 7, 0)
         grid.addWidget(gui, 7, 1)
         grid.addWidget(HelpButton(_('Select which GUI mode to use at start up. ')), 7, 2)
@@ -1298,9 +1300,7 @@ class ElectrumWindow(QMainWindow):
             else:
                 QMessageBox.warning(self, _('Error'), _('Invalid value'), _('OK'))
                     
-        cfg = SimpleConfig()
-        cfg.set_key("gui", str(gui.currentText()).lower())
-        cfg.save_config()
+        self.config.set_key("gui", str(gui.currentText()).lower(), True)
 
 
 
@@ -1312,7 +1312,7 @@ class ElectrumWindow(QMainWindow):
                 status = _("Connected to")+" %s:%d\n%d blocks"%(interface.host, interface.port, wallet.blocks)
             else:
                 status = _("Not connected")
-            server = wallet.server
+            server = interface.server
         else:
             import random
             status = _("Please choose a server.")
@@ -1458,37 +1458,28 @@ class ElectrumWindow(QMainWindow):
         if not d.exec_(): return
         server = unicode( host_line.text() )
 
-        try:
-            if proxy_mode.currentText() != 'NONE':
-                proxy = { u'mode':unicode(proxy_mode.currentText()).lower(), u'host':unicode(proxy_host.text()), u'port':unicode(proxy_port.text()) }
-            else:
-                proxy = None
+        if proxy_mode.currentText() != 'NONE':
+            proxy = { u'mode':unicode(proxy_mode.currentText()).lower(), u'host':unicode(proxy_host.text()), u'port':unicode(proxy_port.text()) }
+        else:
+            proxy = None
 
-            cfg = SimpleConfig()
-            cfg.set_key("proxy", proxy, True)
-            wallet.set_server(server, proxy)
+        wallet.config.set_key("proxy", proxy, True)
+        wallet.config.set_key("server", server, True)
+        interface.set_server(server, proxy)
                 
-        except Exception as err:
-            QMessageBox.information(None, _('Error'), str(err), _('OK'))
-            if parent == None:
-                sys.exit(1)
-            else:
-                return
-
         return True
 
     def closeEvent(self, event):
-        cfg = SimpleConfig()
         g = self.geometry()
-        cfg.set_key("winpos-qt", [g.left(),g.top(),g.width(),g.height()])
-        cfg.save_config()
+        self.config.set_key("winpos-qt", [g.left(),g.top(),g.width(),g.height()], True)
         event.accept()
 
 
 class ElectrumGui:
 
-    def __init__(self, wallet, app=None):
+    def __init__(self, wallet, config, app=None):
         self.wallet = wallet
+        self.config = config
         if app is None:
             self.app = QApplication(sys.argv)
 
@@ -1563,7 +1554,7 @@ class ElectrumGui:
     def main(self,url):
         s = Timer()
         s.start()
-        w = ElectrumWindow(self.wallet)
+        w = ElectrumWindow(self.wallet, self.config)
         if url: w.set_url(url)
         w.app = self.app
         w.connect_slots(s)
index 7c43dce..b549ded 100644 (file)
@@ -22,7 +22,7 @@ import threading, traceback, sys, time, json, Queue
 
 from version import ELECTRUM_VERSION
 from util import print_error
-from simple_config import SimpleConfig
+
 
 DEFAULT_TIMEOUT = 5
 DEFAULT_SERVERS = [ 'electrum.novit.ro:50001:t', 
@@ -30,23 +30,10 @@ DEFAULT_SERVERS = [ 'electrum.novit.ro:50001:t',
 
 proxy_modes = ['socks4', 'socks5', 'http']
 
-def replace_keys(obj, old_key, new_key):
-    if isinstance(obj, dict):
-        if old_key in obj:
-            obj[new_key] = obj[old_key]
-            del obj[old_key]
-        for elem in obj.itervalues():
-            replace_keys(elem, old_key, new_key)
-    elif isinstance(obj, list):
-        for elem in obj:
-            replace_keys(elem, old_key, new_key)
-
-def old_to_new(d):
-    replace_keys(d, 'blk_hash', 'block_hash')
-    replace_keys(d, 'pos', 'index')
-    replace_keys(d, 'nTime', 'timestamp')
-    replace_keys(d, 'is_in', 'is_input')
-    replace_keys(d, 'raw_scriptPubKey', 'raw_output_script')
+def pick_random_server():
+    print "using random server"
+    return random.choice( DEFAULT_SERVERS )
+
 
 def parse_proxy_options(s):
     if s.lower() == 'none': return None
@@ -65,7 +52,11 @@ def parse_proxy_options(s):
         proxy["port"] = "8080" if proxy["mode"] == "http" else "1080"
     return proxy
 
-class Interface(threading.Thread):
+
+
+
+class InterfaceAncestor(threading.Thread):
+
     def __init__(self, host, port, proxy=None):
         threading.Thread.__init__(self)
         self.daemon = True
@@ -134,11 +125,11 @@ class Interface(threading.Thread):
 
 
 
-class PollingInterface(Interface):
+class PollingInterface(InterfaceAncestor):
     """ non-persistent connection. synchronous calls"""
 
     def __init__(self, host, port, proxy=None):
-        Interface.__init__(self, host, port, proxy)
+        InterfaceAncestor.__init__(self, host, port, proxy)
         self.session_id = None
 
     def get_history(self, address):
@@ -146,14 +137,6 @@ class PollingInterface(Interface):
 
     def poll(self):
         pass
-        #if is_new or wallet.remote_url:
-        #    self.was_updated = True
-        #    is_new = wallet.synchronize()
-        #    wallet.update_tx_history()
-        #    wallet.save()
-        #    return is_new
-        #else:
-        #    return False
 
     def run(self):
         self.is_connected = True
@@ -249,11 +232,11 @@ class HttpStratumInterface(PollingInterface):
 
 
 
-class TcpStratumInterface(Interface):
+class TcpStratumInterface(InterfaceAncestor):
     """json-rpc over persistent TCP connection, asynchronous"""
 
     def __init__(self, host, port, proxy=None):
-        Interface.__init__(self, host, port, proxy)
+        InterfaceAncestor.__init__(self, host, port, proxy)
 
     def init_socket(self):
         global proxy_modes
@@ -328,38 +311,63 @@ class TcpStratumInterface(Interface):
 
 
 
+class Interface(TcpStratumInterface, HttpStratumInterface):
+    
+    def __init__(self, config):
 
-
-class WalletSynchronizer(threading.Thread):
-
-    def __init__(self, wallet, loop=False, servers_loaded_callback=None, proxy=None):
-        threading.Thread.__init__(self)
-        self.daemon = True
-        self.wallet = wallet
-        self.loop = loop
-        self.proxy = proxy
-        self.init_interface()
-        self.servers_loaded_callback = servers_loaded_callback
-
-    def init_interface(self):
         try:
-            host, port, protocol = self.wallet.server.split(':')
+            s = config.get('server')
+            host, port, protocol = s.split(':')
             port = int(port)
         except:
-            self.wallet.pick_random_server()
-            host, port, protocol = self.wallet.server.split(':')
+            s = pick_random_server()
+            host, port, protocol = s.split(':')
             port = int(port)
 
+        proxy = config.get('proxy')
+        self.server = host + ':%d:%s'%(port, protocol)
+
         #print protocol, host, port
         if protocol == 't':
-            InterfaceClass = TcpStratumInterface
+            TcpStratumInterface.__init__(self, host, port, proxy)
         elif protocol == 'h':
-            InterfaceClass = HttpStratumInterface
+            HttpStratumInterface.__init__(self, host, port, proxy)
         else:
             print_error("Error: Unknown protocol")
-            InterfaceClass = TcpStratumInterface
+            TcpStratumInterface.__init__(self, host, port, proxy)
+
+
+    def set_server(self, server, proxy=None):
+        # raise an error if the format isnt correct
+        a,b,c = server.split(':')
+        b = int(b)
+        assert c in ['t', 'h']
+        # set the server
+        if server != self.server or proxy != self.proxy:
+            print "changing server:", server, proxy
+            self.server = server
+            self.proxy = proxy
+            self.is_connected = False  # this exits the polling loop
+            self.poke()
+
+
+
+
+
+
+class WalletSynchronizer(threading.Thread):
 
-        self.interface = InterfaceClass(host, port, self.proxy)
+    def __init__(self, wallet, config, loop=False, servers_loaded_callback=None):
+        threading.Thread.__init__(self)
+        self.daemon = True
+        self.wallet = wallet
+        self.loop = loop
+        self.config = config
+        self.init_interface()
+        self.servers_loaded_callback = servers_loaded_callback
+
+    def init_interface(self):
+        self.interface = Interface(self.config)
         self.wallet.interface = self.interface
 
     def handle_response(self, r):
index 1cf51d1..3712313 100644 (file)
-import json
-import os
+import json, ast
+import os, ast
 from util import user_dir
 
+from version import ELECTRUM_VERSION, SEED_VERSION
+from interface import parse_proxy_options
+
+
+# old stuff.. should be removed at some point
+def replace_keys(obj, old_key, new_key):
+    if isinstance(obj, dict):
+        if old_key in obj:
+            obj[new_key] = obj[old_key]
+            del obj[old_key]
+        for elem in obj.itervalues():
+            replace_keys(elem, old_key, new_key)
+    elif isinstance(obj, list):
+        for elem in obj:
+            replace_keys(elem, old_key, new_key)
+
+def old_to_new(d):
+    replace_keys(d, 'blk_hash', 'block_hash')
+    replace_keys(d, 'pos', 'index')
+    replace_keys(d, 'nTime', 'timestamp')
+    replace_keys(d, 'is_in', 'is_input')
+    replace_keys(d, 'raw_scriptPubKey', 'raw_output_script')
+
+
+
 class SimpleConfig:
 
-    default_options = {
-        "gui": "lite",
-        "proxy": None,
-        "winpos-qt": [100, 100, 840, 400],
-        "winpos-lite": [4, 25, 351, 149],
-        "history": False
-        }
-    
-    def __init__(self):
-        # Find electrum data folder
-        self.config_folder = user_dir()
-        # Read the file
-        if os.path.exists(self.config_file_path()):
-            self.load_config()
+    def __init__(self, options):
+
+        self.wallet_config = {}
+        self.read_wallet_config(options.wallet_path)
+
+        self.common_config = {}
+        self.read_common_config()
+
+        self.options_config = {}
+
+        if options.server: self.options_config['server'] = options.server
+        if options.proxy: self.options_config['proxy'] = parse_proxy_options(options.proxy)
+        if options.gui: self.options_config['gui'] = options.gui
+        
+        
+
+    def set_key(self, key, value, save = False):
+        # find where a setting comes from and save it there
+        if self.options_config.get(key):
+            return
+
+        elif self.wallet_config.get(key):
+            self.wallet_config[key] = value
+            if save: self.save_wallet_config()
+
+        elif self.common_config.get(key):
+            self.common_config[key] = value
+            if save: self.save_common_config()
+
+        else:
+            # add key to wallet config
+            self.wallet_config[key] = value
+            if save: self.save_wallet_config()
+
+
+    def get(self, key, default=None):
+        # 1. command-line options always override everything
+        if self.options_config.has_key(key):
+            # print "found", key, "in options"
+            out = self.options_config.get(key)
+
+        # 2. configuration file overrides wallet file
+        elif self.common_config.has_key(key):
+            out = self.common_config.get(key)
+            
         else:
-            self.config = self.default_options
-            # Make config directory if it does not yet exist.
-            if not os.path.exists(self.config_folder):
-                os.mkdir(self.config_folder)
-            self.save_config()
-
-        # This is a friendly fallback to the old style default proxy options
-        if(self.config.get("proxy") is not None and self.config["proxy"]["mode"] == "none"):
-            self.set_key("proxy", None, True)
-
-    def set_key(self, key, value, save = True):
-        self.config[key] = value
-        if save == True:
-            self.save_config()
-
-    def save_config(self):
-        if not os.path.exists(self.config_folder):
-            os.mkdir(self.config_folder)
-        f = open(self.config_file_path(), "w+")
-        f.write(json.dumps(self.config))
-
-    def load_config(self):
-        f = open(self.config_file_path(), "r")
-        file_contents = f.read()
-        if file_contents:
-            user_config = json.loads(file_contents)
-            for i in user_config:
-                self.config[i] = user_config[i]
+            out = self.wallet_config.get(key)
+
+        if out is None and default is not None:
+            out = default
+        return out
+
+
+    def is_modifiable(self, key):
+        if self.options_config.has_key(key) or self.common_config.has_key(key):
+            return False
         else:
-            self.config = self.default_options
-            self.save_config()
-  
-    def config_file_path(self):
-        return "%s" % (self.config_folder + "/config.json")
-
-    def __init__(self):
-        # Find electrum data folder
-        self.config_folder = user_dir()
-        self.config = self.default_options
-        # Read the file
-        if os.path.exists(self.config_file_path()):
-            self.load_config()
-        self.save_config()
+            return True
+
+
+    def read_common_config(self):
+        for name in [ os.path.join( user_dir(), 'electrum.conf') , '/etc/electrum.conf']:
+            if os.path.exists(name):
+                from interface import parse_proxy_options
+                try:
+                    import ConfigParser
+                except:
+                    print "cannot parse electrum.conf. please install ConfigParser"
+                    return
+                
+                p = ConfigParser.ConfigParser()
+                p.read(name)
+                try:
+                    self.common_config['server'] = p.get('interface','server')
+                except:
+                    pass
+                try:
+                    self.common_config['proxy'] = parse_proxy_options(p.get('interface','proxy'))
+                except:
+                    pass
+                break
+
+
+
+    def init_path(self, wallet_path):
+        """Set the path of the wallet."""
+        if wallet_path is not None:
+            self.path = wallet_path
+            return
+
+        # Look for wallet file in the default data directory.
+        # Keeps backwards compatibility.
+        wallet_dir = user_dir()
+
+        # Make wallet directory if it does not yet exist.
+        if not os.path.exists(wallet_dir):
+            os.mkdir(wallet_dir)
+        self.path = os.path.join(wallet_dir, "electrum.dat")
+
+
+
+    def save_common_config(self):
+        s = repr(self.common_config)
+        # todo: decide what to do 
+        print "not saving settings in common config:", s
+
+
+
+    def read_wallet_config(self, path):
+        """Read the contents of the wallet file."""
+        self.wallet_file_exists = False
+        self.init_path(path)
+        try:
+            with open(self.path, "r") as f:
+                data = f.read()
+        except IOError:
+            return
+        try:
+            d = ast.literal_eval( data )  #parse raw data from reading wallet file
+            old_to_new(d)
+        except:
+            raise IOError("Cannot read wallet file.")
+
+        self.wallet_config = d
+        self.wallet_file_exists = True
+
+
+    def set_interface(self, interface):
+        pass
+
+    def set_gui(self, gui):
+        pass
+
+    def save(self):
+        self.save_wallet_config()
+
 
+    def save_wallet_config(self):
+        s = repr(self.wallet_config)
+        f = open(self.path,"w")
+        f.write( s )
+        f.close()
+        import stat
+        os.chmod(self.path,stat.S_IREAD | stat.S_IWRITE)
 
index d478eac..027d98c 100644 (file)
@@ -273,49 +273,40 @@ def format_satoshis(x, is_diff=False, num_zeros = 0):
 
 
 from version import ELECTRUM_VERSION, SEED_VERSION
-from interface import DEFAULT_SERVERS
-
 
 
 
 class Wallet:
-    def __init__(self):
+    def __init__(self, config={}):
 
+        self.config = config
         self.electrum_version = ELECTRUM_VERSION
-        self.seed_version = SEED_VERSION
         self.update_callbacks = []
 
-        self.gap_limit = 5           # configuration
-        self.use_change = True
-        self.fee = 100000
-        self.num_zeros = 0
-        self.master_public_key = ''
-        self.conversion_currency = None
-        self.theme = "Cleanlook"
-
         # saved fields
-        self.use_encryption = False
-        self.addresses = []          # receiving addresses visible for user
-        self.change_addresses = []   # addresses used as change
-        self.seed = ''               # encrypted
-        self.history = {}
-        self.labels = {}             # labels for addresses and transactions
-        self.aliases = {}            # aliases for addresses
-        self.authorities = {}        # trusted addresses
-        self.frozen_addresses = []
-        self.prioritized_addresses = []
-        self.gui_detailed_view = False
-        
-        self.receipts = {}           # signed URIs
-        self.receipt = None          # next receipt
-        self.addressbook = []        # outgoing addresses, for payments
-        self.debug_server = False    # write server communication debug info to stdout
+        self.seed_version          = config.get('seed_version', SEED_VERSION)
+        self.gap_limit             = config.get('gap_limit', 5)
+        self.use_change            = config.get('use_change',True)
+        self.fee                   = int(config.get('fee',100000))
+        self.num_zeros             = int(config.get('num_zeros',0))
+        self.master_public_key     = config.get('master_public_key','').decode('hex')
+        self.use_encryption        = config.get('use_encryption', False)
+        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.history               = config.get('history',{})
+        self.labels                = config.get('labels',{})              # labels for addresses and transactions
+        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.imported_keys         = config.get('imported_keys',{})
 
         # not saved
+        self.receipt = None          # next receipt
         self.tx_history = {}
-
-        self.imported_keys = {}
-
         self.was_updated = True
         self.blocks = -1
         self.banner = ''
@@ -329,7 +320,10 @@ class Wallet:
         self.lock = threading.Lock()
         self.tx_event = threading.Event()
 
-        self.pick_random_server()
+        self.update_tx_history()
+        if self.seed_version != SEED_VERSION:
+            raise ValueError("This wallet seed is deprecated. Please run upgrade.py for a diagnostic.")
+
 
     def register_callback(self, update_callback):
         with self.lock:
@@ -340,38 +334,9 @@ class Wallet:
             callbacks = self.update_callbacks[:]
         [update() for update in callbacks]
 
-    def pick_random_server(self):
-        self.server = random.choice( DEFAULT_SERVERS )         # random choice when the wallet is created
-
     def is_up_to_date(self):
         return self.interface.responses.empty() and not self.interface.unanswered_requests
 
-    def set_server(self, server, proxy=None):
-        # raise an error if the format isnt correct
-        a,b,c = server.split(':')
-        b = int(b)
-        assert c in ['t', 'h', 'n']
-        # set the server
-        if server != self.server or proxy != self.interface.proxy:
-            self.server = server
-            self.save()
-            self.interface.proxy = proxy
-            self.interface.is_connected = False  # this exits the polling loop
-            self.interface.poke()
-
-    def set_path(self, wallet_path):
-        """Set the path of the wallet."""
-        if wallet_path is not None:
-            self.path = wallet_path
-            return
-        # Look for wallet file in the default data directory.
-        # Keeps backwards compatibility.
-        wallet_dir = user_dir()
-
-        # Make wallet directory if it does not yet exist.
-        if not os.path.exists(wallet_dir):
-            os.mkdir(wallet_dir)
-        self.path = os.path.join(wallet_dir, "electrum.dat")
 
     def import_key(self, keypair, password):
         address, key = keypair.split(':')
@@ -390,6 +355,7 @@ class Wallet:
             raise BaseException('Address does not match private key')
         self.imported_keys[address] = self.pw_encode( key, password )
 
+
     def new_seed(self, password):
         seed = "%032x"%ecdsa.util.randrange( pow(2,128) )
         #self.init_mpk(seed)
@@ -630,91 +596,6 @@ class Wallet:
         self.update_tx_labels()
 
 
-    def save(self):
-        # TODO: Need special config storage class. Should not be mixed
-        # up with the wallet.
-        # Settings should maybe be stored in a flat ini file.
-        s = {
-            'seed_version': self.seed_version,
-            'use_encryption': self.use_encryption,
-            'use_change': self.use_change,
-            'master_public_key': self.master_public_key.encode('hex'),
-            'fee': self.fee,
-            'server': self.server,
-            'seed': self.seed,
-            'addresses': self.addresses,
-            'change_addresses': self.change_addresses,
-            'history': self.history, 
-            'labels': self.labels,
-            'contacts': self.addressbook,
-            'imported_keys': self.imported_keys,
-            'aliases': self.aliases,
-            'authorities': self.authorities,
-            'receipts': self.receipts,
-            'num_zeros': self.num_zeros,
-            'frozen_addresses': self.frozen_addresses,
-            'prioritized_addresses': self.prioritized_addresses,
-            'gui_detailed_view': self.gui_detailed_view,
-            'gap_limit': self.gap_limit,
-            'debug_server': self.debug_server,
-            'conversion_currency': self.conversion_currency,
-            'theme': self.theme
-        }
-        f = open(self.path,"w")
-        f.write( repr(s) )
-        f.close()
-        import stat
-        os.chmod(self.path,stat.S_IREAD | stat.S_IWRITE)
-
-    def read(self):
-        """Read the contents of the wallet file."""
-        import interface
-
-        self.file_exists = False
-        try:
-            with open(self.path, "r") as f:
-                data = f.read()
-        except IOError:
-            return
-        try:
-            d = ast.literal_eval( data )  #parse raw data from reading wallet file
-            interface.old_to_new(d)
-            
-            self.seed_version = d.get('seed_version')
-            self.master_public_key = d.get('master_public_key').decode('hex')
-            self.use_encryption = d.get('use_encryption')
-            self.use_change = bool(d.get('use_change', True))
-            self.fee = int(d.get('fee'))
-            self.seed = d.get('seed')
-            self.server = d.get('server')
-            self.addresses = d.get('addresses')
-            self.change_addresses = d.get('change_addresses')
-            self.history = d.get('history')
-            self.labels = d.get('labels')
-            self.addressbook = d.get('contacts')
-            self.imported_keys = d.get('imported_keys', {})
-            self.aliases = d.get('aliases', {})
-            self.authorities = d.get('authorities', {})
-            self.receipts = d.get('receipts', {})
-            self.num_zeros = d.get('num_zeros', 0)
-            self.frozen_addresses = d.get('frozen_addresses', [])
-            self.prioritized_addresses = d.get('prioritized_addresses', [])
-            self.gui_detailed_view = d.get('gui_detailed_view', False)
-            self.gap_limit = d.get('gap_limit', 5)
-            self.debug_server = d.get('debug_server', False)
-            self.conversion_currency = d.get('conversion_currency', 'USD')
-            self.theme = d.get('theme', 'Cleanlook')
-        except:
-            raise IOError("Cannot read wallet file.")
-
-        self.update_tx_history()
-
-        if self.seed_version != SEED_VERSION:
-            raise ValueError("This wallet seed is deprecated. Please run upgrade.py for a diagnostic.")
-
-        self.file_exists = True
-
-
     def get_address_flags(self, addr):
         flags = "C" if self.is_change(addr) else "I" if addr in self.imported_keys.keys() else "-" 
         flags += "F" if addr in self.frozen_addresses else "P" if addr in self.prioritized_addresses else "-"
@@ -1134,3 +1015,29 @@ class Wallet:
             return True
         else:
             return False
+
+    def save(self):
+        s = {
+            'seed_version': self.seed_version,
+            'use_encryption': self.use_encryption,
+            'use_change': self.use_change,
+            'master_public_key': self.master_public_key.encode('hex'),
+            'fee': self.fee,
+            'seed': self.seed,
+            'addresses': self.addresses,
+            'change_addresses': self.change_addresses,
+            'history': self.history, 
+            'labels': self.labels,
+            'contacts': self.addressbook,
+            'imported_keys': self.imported_keys,
+            'aliases': self.aliases,
+            'authorities': self.authorities,
+            'receipts': self.receipts,
+            'num_zeros': self.num_zeros,
+            'frozen_addresses': self.frozen_addresses,
+            'prioritized_addresses': self.prioritized_addresses,
+            'gap_limit': self.gap_limit,
+        }
+        for k, v in s.items():
+            self.config.set_key(k,v)
+        self.config.save()
index 01fbc70..dfa8919 100755 (executable)
@@ -1,8 +1,8 @@
 #!/usr/bin/env python
 
-from electrum import TcpStratumInterface
+from electrum import Interface
 
-i = TcpStratumInterface('electrum.novit.ro', 50001)
+i = Interface({'server':'electrum.novit.ro:50001:t'})
 i.init_socket()
 i.start()
 i.send([('blockchain.numblocks.subscribe',[])])
index 95600c2..0a8ca08 100755 (executable)
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 
 import sys
-from electrum import TcpStratumInterface
+from electrum import Interface
 
 try:
     addr = sys.argv[1]
@@ -9,7 +9,7 @@ except:
     print "usage: get_history <bitcoin_address>"
     sys.exit(1)
 
-i = TcpStratumInterface('electrum.novit.ro', 50001)
+i = Interface({'server':'electrum.novit.ro:50001:t'})
 i.init_socket()
 i.start()
 i.send([('blockchain.address.get_history',[addr])])
index 32e68ac..409ea56 100644 (file)
@@ -21,7 +21,7 @@ import time, thread, sys, socket, os
 import urllib2,json
 import MySQLdb as mdb
 import Queue
-from electrum import Wallet, TcpStratumInterface
+from electrum import Wallet, Interface
 
 import ConfigParser
 config = ConfigParser.ConfigParser()
@@ -157,7 +157,7 @@ if __name__ == '__main__':
     print "using database", db_name
     conn = mdb.connect(db_instance, db_user, db_password, db_name);
 
-    i = TcpStratumInterface(electrum_server, 50001)
+    i = Interface({'server':"%s:%d:t"%(electrum_server, 50001)})
     i.init_socket()
     i.start()
     
index ac3f539..c3cb02e 100755 (executable)
@@ -1,8 +1,8 @@
 #!/usr/bin/env python
 
-from electrum import TcpStratumInterface
+from electrum import Interface
 
-i = TcpStratumInterface('electrum.novit.ro', 50001)
+i = Interface({'server':'electrum.novit.ro:50001:t'})
 i.init_socket()
 i.start()
 i.send([('server.peers.subscribe',[])])
index 50c3f5d..a8763c7 100755 (executable)
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 
 import sys
-from electrum import TcpStratumInterface
+from electrum import Interface
 
 try:
     addr = sys.argv[1]
@@ -9,7 +9,7 @@ except:
     print "usage: watch_address <bitcoin_address>"
     sys.exit(1)
 
-i = TcpStratumInterface('electrum.novit.ro', 50001)
+i = Interface({'server':'electrum.novit.ro:50001:t'})
 i.init_socket()
 i.start()
 i.send([('blockchain.address.subscribe',[addr])])