diff --git a/TODO b/TODO index b5c8430d..89affccd 100644 --- a/TODO +++ b/TODO @@ -3,6 +3,7 @@ Client: - Wizard - Multiple wallets - Themes +- Extend GUI with history view (View -> Show History) - Settings window Server: diff --git a/data/noface.svg b/data/noface.svg index 9956854c..dc24f111 100644 --- a/data/noface.svg +++ b/data/noface.svg @@ -52,7 +52,7 @@ inkscape:groupmode="layer" id="layer1"> . -import re, sys +import re +import sys +# import argparse +import optparse + try: from lib.util import print_error except ImportError: @@ -24,22 +28,19 @@ except ImportError: try: import ecdsa -except: - print_error("Error: python-ecdsa does not seem to be installed. Try 'sudo pip install ecdsa'") - sys.exit(1) +except ImportError: + sys.exit("Error: python-ecdsa does not seem to be installed. Try 'sudo pip install ecdsa'") try: import aes -except: - print_error("Error: AES does not seem to be installed. Try 'sudo pip install slowaes'") - sys.exit(1) +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 except ImportError: from electrum import Wallet, WalletSynchronizer, format_satoshis, mnemonic, prompt_password -from optparse import OptionParser from decimal import Decimal known_commands = { @@ -77,9 +78,9 @@ options:\n --fee, -f: set transaction fee\n --fromaddr, -s: send from address 'import': 'Imports a key pair\nSyntax: import
:', 'signmessage': - 'Signs a message with a key\nSyntax: signmessage
', + 'Signs a message with a key\nSyntax: signmessage
\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': - 'Verifies a signature\nSyntax: verifymessage
', + 'Verifies a signature\nSyntax: verifymessage
\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 "', 'eval': "Run python eval() on an object\nSyntax: eval \nExample: eval \"wallet.aliases\"", 'deseed': @@ -101,7 +102,7 @@ protected_commands = ['payto', 'password', 'mktx', 'seed', 'import','signmessage if __name__ == '__main__': usage = "usage: %prog [options] command\nCommands: "+ (', '.join(known_commands)) - parser = OptionParser(usage=usage) + parser = optparse.OptionParser(prog=usage) parser.add_option("-g", "--gui", dest="gui", default="lite", 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") @@ -128,7 +129,9 @@ if __name__ == '__main__': else: cmd = args[0] firstarg = args[1] if len(args) > 1 else '' - + + #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': @@ -165,16 +168,17 @@ if __name__ == '__main__': except ImportError: import electrum.gui_qt as gui else: + #use the lite version if no toolkit specified try: import lib.gui_lite as gui except ImportError: import electrum.gui_lite as gui else: - print_error("Error: Unknown GUI: " + options.gui) - exit(1) + sys.exit("Error: Unknown GUI: " + options.gui) gui = gui.ElectrumGui(wallet) - WalletSynchronizer(wallet,True).start() + interface = WalletSynchronizer(wallet, True, gui.server_list_changed) + interface.start() try: found = wallet.file_exists @@ -198,15 +202,13 @@ if __name__ == '__main__': cmd = 'help' if not wallet.file_exists and cmd not in ['help','create','restore']: - print_error("Error: Wallet file not found.") - print_error("Type 'electrum create' to create a new wallet, or provide a path to a wallet with the -w option") + 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: - print_error("Error: Remove the existing wallet first!") - sys.stderr.flush() - sys.exit(0) + 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(':') @@ -230,8 +232,7 @@ if __name__ == '__main__': print_error("Warning: Not hex, trying decode.") seed = mnemonic.mn_decode( seed.split(' ') ) if not seed: - print_error("Error: No seed") - sys.exit(1) + sys.exit("Error: No seed") wallet.seed = str(seed) wallet.init_mpk( wallet.seed ) @@ -316,7 +317,6 @@ if __name__ == '__main__': cmd2 = firstarg if cmd2 not in known_commands: parser.print_help() - print print "Type 'electrum help ' to see the help for a specific command" print "Type 'electrum --help' to see the list of options" print "List of commands:", ', '.join(known_commands) @@ -355,17 +355,15 @@ if __name__ == '__main__': f = open(ns,'r') data = f.read() f.close() - except: - print_error("Error: Seed file not found") - sys.exit() + except IOError: + sys.exit("Error: Seed file not found") try: import ast d = ast.literal_eval( data ) seed = d['seed'] imported_keys = d.get('imported_keys',{}) except: - print_error("Error: Error with seed file") - sys.exit(1) + sys.exit("Error: Error with seed file") mpk = wallet.master_public_key wallet.seed = seed @@ -511,9 +509,8 @@ if __name__ == '__main__': elif cmd == 'password': try: seed = wallet.pw_decode( wallet.seed, password) - except: - print_error("Error: Password does not decrypt this wallet.") - sys.exit(1) + except ValueError: + sys.exit("Error: Password does not decrypt this wallet.") new_password = prompt_password('New password:') wallet.update_password(seed, password, new_password) @@ -543,7 +540,8 @@ if __name__ == '__main__': try: wallet.verify_message(address, signature, message) print True - except: + except BaseException as e: + print "Verification error: {0}".format(e) print False elif cmd == 'freeze': diff --git a/electrum.png b/electrum.png index f47d03b0..a45fe95d 100644 Binary files a/electrum.png and b/electrum.png differ diff --git a/lib/exchange_rate.py b/lib/exchange_rate.py index e8c9fac2..77cbf9b1 100644 --- a/lib/exchange_rate.py +++ b/lib/exchange_rate.py @@ -31,7 +31,7 @@ class Exchanger(threading.Thread): connection = httplib.HTTPSConnection('intersango.com') connection.request("GET", "/api/ticker.php") response = connection.getresponse() - if response.status == 404: + if response.reason == httplib.responses[httplib.NOT_FOUND]: return response = json.loads(response.read()) # 1 = BTC:GBP @@ -40,16 +40,16 @@ class Exchanger(threading.Thread): # 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) + quote_currencies["GBP"] = self._lookup_rate(response, 1) + quote_currencies["EUR"] = self._lookup_rate(response, 2) + quote_currencies["USD"] = self._lookup_rate(response, 3) with self.lock: self.quote_currencies = quote_currencies self.parent.emit(SIGNAL("refresh_balance()")) except KeyError: pass - def lookup_rate(self, response, quote_id): + def _lookup_rate(self, response, quote_id): return decimal.Decimal(response[str(quote_id)]["last"]) if __name__ == "__main__": diff --git a/lib/gui_lite.py b/lib/gui_lite.py index 6112b246..f63c1812 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -4,6 +4,7 @@ from PyQt4.QtCore import * from PyQt4.QtGui import * from decimal import Decimal as D +from interface import DEFAULT_SERVERS from util import get_resource_path as rsrc from i18n import _ import decimal @@ -41,14 +42,18 @@ def resize_line_edit_width(line_edit, text_input): text_input += "A" line_edit.setMinimumWidth(metrics.width(text_input)) -class ElectrumGui: +class ElectrumGui(QObject): def __init__(self, wallet): + super(QObject, self).__init__() + self.wallet = wallet self.app = QApplication(sys.argv) def main(self, url): actuator = MiniActuator(self.wallet) + self.connect(self, SIGNAL("updateservers()"), + actuator.update_servers_list) # Should probably not modify the current path but instead # change the behaviour of rsrc(...) old_path = QDir.currentPath() @@ -73,7 +78,11 @@ class ElectrumGui: self.app.exec_() + def server_list_changed(self): + self.emit(SIGNAL("updateservers()")) + def expand(self): + """Hide the lite mode window and show pro-mode.""" self.mini.hide() self.expert.show() @@ -174,13 +183,15 @@ class MiniWindow(QDialog): menubar = QMenuBar() electrum_menu = menubar.addMenu(_("&Bitcoin")) - self.servers_menu = electrum_menu.addMenu(_("&Servers")) - self.servers_menu.addAction(_("Foo")) + servers_menu = electrum_menu.addMenu(_("&Servers")) + servers_group = QActionGroup(self) + self.actuator.set_servers_gui_stuff(servers_menu, servers_group) + self.actuator.populate_servers_menu() electrum_menu.addSeparator() brain_seed = electrum_menu.addAction(_("&BrainWallet Info")) brain_seed.triggered.connect(self.actuator.show_seed_dialog) - - electrum_menu.addAction(_("&Quit")) + quit_option = electrum_menu.addAction(_("&Quit")) + quit_option.triggered.connect(self.close) view_menu = menubar.addMenu(_("&View")) expert_gui = view_menu.addAction(_("&Pro Mode")) @@ -254,9 +265,10 @@ class MiniWindow(QDialog): pass def set_quote_currency(self, currency): + """Set and display the fiat currency country.""" assert currency in self.quote_currencies self.quote_currencies.remove(currency) - self.quote_currencies = [currency] + self.quote_currencies + self.quote_currencies.insert(0, currency) self.refresh_balance() def change_quote_currency(self): @@ -274,6 +286,7 @@ class MiniWindow(QDialog): self.amount_input_changed(self.amount_input.text()) def set_balances(self, btc_balance): + """Set the bitcoin balance and update the amount label accordingly.""" self.btc_balance = btc_balance quote_text = self.create_quote_text(btc_balance) if quote_text: @@ -283,6 +296,7 @@ class MiniWindow(QDialog): self.setWindowTitle("Electrum - %s BTC" % btc_balance) def amount_input_changed(self, amount_text): + """Update the number of bitcoins displayed.""" self.check_button_status() try: @@ -298,6 +312,8 @@ class MiniWindow(QDialog): self.balance_label.show_balance() def create_quote_text(self, btc_balance): + """Return a string copy of the amount fiat currency the + user has in bitcoins.""" quote_currency = self.quote_currencies[0] quote_balance = self.exchanger.exchange(btc_balance, quote_currency) if quote_balance is None: @@ -314,8 +330,16 @@ class MiniWindow(QDialog): self.amount_input.setText("") def check_button_status(self): + """Check that the bitcoin address is valid and that something + is entered in the amount before making the send button clickable.""" + try: + value = D(str(self.amount_input.text())) * 10**8 + except decimal.InvalidOperation: + value = None + # self.address_input.property(...) returns a qVariant, not a bool. + # The == is needed to properly invoke a comparison. if (self.address_input.property("isValid") == True and - len(self.amount_input.text()) > 0): + value is not None and 0 < value <= self.btc_balance): self.send_button.setDisabled(False) else: self.send_button.setDisabled(True) @@ -385,10 +409,12 @@ class BalanceLabel(QLabel): self.amount_text = "" def mousePressEvent(self, event): + """Change the fiat currency selection if window background is clicked.""" if self.state != self.SHOW_CONNECTING: self.change_quote_currency() def set_balance_text(self, btc_balance, quote_text): + """Set the amount of bitcoins in the gui.""" if self.state == self.SHOW_CONNECTING: self.state = self.SHOW_BALANCE self.balance_text = "%s BTC %s" % (btc_balance, quote_text) @@ -466,7 +492,8 @@ class ReceivePopup(QDialog): self.setMouseTracking(True) self.setWindowTitle("Electrum - " + _("Receive Bitcoin payment")) - self.setWindowFlags(Qt.Window|Qt.FramelessWindowHint|Qt.MSWindowsFixedSizeDialogHint) + self.setWindowFlags(Qt.Window|Qt.FramelessWindowHint| + Qt.MSWindowsFixedSizeDialogHint) self.layout().setSizeConstraint(QLayout.SetFixedSize) #self.setFrameStyle(QFrame.WinPanel|QFrame.Raised) #self.setAlignment(Qt.AlignCenter) @@ -480,33 +507,43 @@ class ReceivePopup(QDialog): self.show() class MiniActuator: - + """Initialize the definitions relating to themes and + sending/recieving bitcoins.""" + + def __init__(self, wallet): + """Retrieve the gui theme used in previous session.""" self.wallet = wallet - self.theme_name = self.wallet.theme self.themes = util.load_theme_paths() def load_theme(self): + """Load theme retrieved from wallet file.""" try: theme_prefix, theme_path = self.themes[self.theme_name] except KeyError: - util.print_error("Theme not found! ", self.theme_name) + util.print_error("Theme not found!", self.theme_name) return QDir.setCurrent(os.path.join(theme_prefix, theme_path)) with open(rsrc("style.css")) as style_file: qApp.setStyleSheet(style_file.read()) def theme_names(self): - return self.themes.keys() + """Sort themes.""" + return sorted(self.themes.keys()) + def selected_theme(self): + """Select theme.""" return self.theme_name def change_theme(self, theme_name): + """Change theme.""" self.wallet.theme = self.theme_name = 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 can be none when Electrum is used for the first # time and no setting has been created yet. @@ -514,9 +551,70 @@ class MiniActuator: set_quote_currency(currency) def set_config_currency(self, conversion_currency): + """Change the wallet fiat currency country.""" self.wallet.conversion_currency = conversion_currency + def set_servers_gui_stuff(self, servers_menu, servers_group): + self.servers_menu = servers_menu + self.servers_group = servers_group + + def populate_servers_menu(self): + interface = self.wallet.interface + if not interface.servers: + print "No servers loaded yet." + self.servers_list = [] + for server_string in DEFAULT_SERVERS: + host, port, protocol = server_string.split(':') + transports = [(protocol,port)] + self.servers_list.append((host, transports)) + else: + 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] + for server_name in server_names: + server_action = self.servers_menu.addAction(server_name) + server_action.setCheckable(True) + if server_name == current_server: + server_action.setChecked(True) + class SelectServerFunctor: + def __init__(self, server_name, server_selected): + self.server_name = server_name + self.server_selected = server_selected + def __call__(self, checked): + if checked: + # call server_selected + self.server_selected(self.server_name) + delegate = SelectServerFunctor(server_name, self.server_selected) + server_action.toggled.connect(delegate) + self.servers_group.addAction(server_action) + + def update_servers_list(self): + # Clear servers_group + for action in self.servers_group.actions(): + self.servers_group.removeAction(action) + self.populate_servers_menu() + + def server_selected(self, server_name): + match = [transports for (host, transports) in self.servers_list + if host == server_name] + assert len(match) == 1 + match = match[0] + # Default to TCP if available else use anything + # TODO: protocol should be selectable. + tcp_port = [port for (protocol, port) in match if protocol == "t"] + if len(tcp_port) == 0: + protocol = match[0][0] + port = match[0][1] + else: + protocol = "t" + port = tcp_port[0] + server_line = "%s:%s:%s" % (server_name, port, protocol) + # Should this have exception handling? + self.wallet.set_server(server_line) + def copy_address(self, receive_popup): + """Copy the wallet addresses into the client.""" addrs = [addr for addr in self.wallet.all_addresses() if not self.wallet.is_change(addr)] # Select most recent addresses from gap limit @@ -527,6 +625,7 @@ class MiniActuator: receive_popup.popup() def send(self, address, amount, parent_window): + """Send bitcoins to the target address.""" dest_address = self.fetch_destination(address) if dest_address is None or not self.wallet.is_valid(dest_address): @@ -589,6 +688,7 @@ class MiniActuator: return recipient def is_valid(self, address): + """Check if bitcoin address is valid.""" return self.wallet.is_valid(address) def acceptbit(self, currency): diff --git a/lib/gui_qt.py b/lib/gui_qt.py index e866c066..66930735 100644 --- a/lib/gui_qt.py +++ b/lib/gui_qt.py @@ -23,9 +23,7 @@ from util import print_error try: import PyQt4 except: - print_error("Error: Could not import PyQt4") - print_error("on Linux systems, you may try 'sudo apt-get install python-qt4'") - sys.exit(1) + sys.exit("Error: Could not import PyQt4 on Linux systems, you may try 'sudo apt-get install python-qt4'") from PyQt4.QtGui import * from PyQt4.QtCore import * @@ -36,9 +34,7 @@ from interface import DEFAULT_SERVERS try: import icons_rc except: - print_error("Error: Could not import icons_rc.py") - print_error("Please generate it with: 'pyrcc4 icons.qrc -o lib/icons_rc.py'") - sys.exit(1) + 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 import bmp, mnemonic, pyqrnative, qrscanner @@ -1434,6 +1430,9 @@ class ElectrumGui: if app is None: self.app = QApplication(sys.argv) + def server_list_changed(self): + pass + def waiting_dialog(self): s = Timer() diff --git a/lib/interface.py b/lib/interface.py index 76a3e4c8..6a28cf8e 100644 --- a/lib/interface.py +++ b/lib/interface.py @@ -27,7 +27,7 @@ DEFAULT_TIMEOUT = 5 DEFAULT_SERVERS = [ 'ecdsa.org:50001:t', 'electrum.novit.ro:50001:t', 'uncle-enzo.info:50001:t', - 'electrum.bytesized-hosting.com:50000:t'] # list of default servers + 'electrum.bytesized-hosting.com:50001:t'] # list of default servers def replace_keys(obj, old_key, new_key): @@ -306,12 +306,13 @@ class TcpStratumInterface(Interface): class WalletSynchronizer(threading.Thread): - def __init__(self, wallet, loop=False): + def __init__(self, wallet, loop=False, servers_loaded_callback=None): threading.Thread.__init__(self) self.daemon = True self.wallet = wallet self.loop = loop self.init_interface() + self.servers_loaded_callback = servers_loaded_callback def init_interface(self): try: @@ -334,7 +335,6 @@ class WalletSynchronizer(threading.Thread): self.interface = InterfaceClass(host, port, self.wallet.debug_server) self.wallet.interface = self.interface - def handle_response(self, r): if r is None: return @@ -354,15 +354,19 @@ class WalletSynchronizer(threading.Thread): host = item[1] ports = [] version = None - if len(item)>2: + if len(item) > 2: for v in item[2]: - if re.match("[th]\d+",v): - ports.append((v[0],v[1:])) - if re.match("v(.?)+",v): + if re.match("[th]\d+", v): + ports.append((v[0], v[1:])) + if re.match("v(.?)+", v): version = v[1:] if ports and version: - servers.append( (host, ports) ) + servers.append((host, ports)) self.interface.servers = servers + # servers_loaded_callback is None for commands, but should + # NEVER be None when using the GUI. + if self.servers_loaded_callback is not None: + self.servers_loaded_callback() elif method == 'blockchain.address.subscribe': addr = params[0] @@ -425,6 +429,7 @@ class WalletSynchronizer(threading.Thread): self.wallet.trigger_callbacks() if self.loop: time.sleep(5) + # Server has been changed. Copy callback for new interface. self.init_interface() self.start_interface() continue diff --git a/lib/util.py b/lib/util.py index 98a820c0..2aabcedf 100644 --- a/lib/util.py +++ b/lib/util.py @@ -3,12 +3,13 @@ import platform import sys def print_error(*args): - for item in args: - sys.stderr.write(str(item)) - sys.stderr.write("\n") + # Stringify args + args = [str(item) for item in args] + sys.stderr.write(" ".join(args) + "\n") sys.stderr.flush() def appdata_dir(): + """Find the path to the application data directory; add an electrum folder and return path.""" if platform.system() == "Windows": return os.path.join(os.environ["APPDATA"], "Electrum") elif platform.system() == "Linux": @@ -23,6 +24,7 @@ def get_resource_path(*args): return os.path.join(".", *args) def local_data_dir(): + """Return path to the data folder.""" assert sys.argv prefix_path = os.path.dirname(sys.argv[0]) local_data = os.path.join(prefix_path, "data") diff --git a/lib/wallet.py b/lib/wallet.py index 8c658769..18125891 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -16,9 +16,20 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import sys +import base64 +import os +import re +import hashlib +import copy +import operator +import ast +import threading +import random +import getpass +import aes +import ecdsa -import sys, base64, os, re, hashlib, copy, operator, ast, threading, random, getpass -import aes, ecdsa from ecdsa.util import string_to_number, number_to_string from util import print_error @@ -65,8 +76,7 @@ __b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' __b58base = len(__b58chars) def b58encode(v): - """ encode v, which is a string of bytes, to base58. - """ + """ encode v, which is a string of bytes, to base58.""" long_value = 0L for (i, c) in enumerate(v[::-1]): @@ -89,8 +99,7 @@ def b58encode(v): return (__b58chars[0]*nPad) + result def b58decode(v, length): - """ decode v into a string of len bytes - """ + """ decode v into a string of len bytes.""" long_value = 0L for (i, c) in enumerate(v[::-1]): long_value += __b58chars.find(c) * (__b58base**i) @@ -157,8 +166,7 @@ def prompt_password(prompt, confirm=True): password2 = getpass.getpass("Confirm: ") if password != password2: - print_error("Error: Passwords do not match.") - sys.exit(1) + sys.exit("Error: Passwords do not match.") else: password = raw_input(prompt) @@ -282,7 +290,7 @@ class Wallet: self.num_zeros = 0 self.master_public_key = '' self.conversion_currency = None - self.theme = None + self.theme = "Cleanlook" # saved fields self.use_encryption = False @@ -342,7 +350,7 @@ class Wallet: # raise an error if the format isnt correct a,b,c = server.split(':') b = int(b) - assert c in ['t','h','n'] + assert c in ['t', 'h', 'n'] # set the server if server != self.server: self.server = server @@ -351,22 +359,24 @@ class Wallet: 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. + if "HOME" in os.environ: + wallet_dir = os.path.join(os.environ["HOME"], ".electrum") + elif "LOCALAPPDATA" in os.environ: + wallet_dir = os.path.join(os.environ["LOCALAPPDATA"], "Electrum") + elif "APPDATA" in os.environ: + wallet_dir = os.path.join(os.environ["APPDATA"], "Electrum") else: - # backward compatibility: look for wallet file in the default data directory - if "HOME" in os.environ: - wallet_dir = os.path.join( os.environ["HOME"], '.electrum') - elif "LOCALAPPDATA" in os.environ: - wallet_dir = os.path.join( os.environ["LOCALAPPDATA"], 'Electrum' ) - elif "APPDATA" in os.environ: - wallet_dir = os.path.join( os.environ["APPDATA"], 'Electrum' ) - else: - raise BaseException("No home directory found in environment variables.") - - if not os.path.exists( wallet_dir ): os.mkdir( wallet_dir ) - self.path = os.path.join( wallet_dir, 'electrum.dat' ) + raise BaseException("No home directory found in environment variables.") + # 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(':') @@ -676,19 +686,19 @@ class Wallet: os.chmod(self.path,stat.S_IREAD | stat.S_IWRITE) def read(self): + """Read the contents of the wallet file.""" import interface - upgrade_msg = """This wallet seed is deprecated. Please run upgrade.py for a diagnostic.""" self.file_exists = False try: - f = open(self.path,"r") - data = f.read() - f.close() - except: + with open(self.path, "r") as f: + data = f.read() + except IOError: return try: - d = ast.literal_eval( data ) + 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') @@ -714,12 +724,12 @@ class Wallet: self.conversion_currency = d.get('conversion_currency', 'USD') self.theme = d.get('theme', 'Cleanlook') except: - raise BaseException("cannot read wallet file") + raise IOError("Cannot read wallet file.") self.update_tx_history() if self.seed_version != SEED_VERSION: - raise BaseException(upgrade_msg) + raise ValueError("This wallet seed is deprecated. Please run upgrade.py for a diagnostic.") if self.remote_url: assert self.master_public_key.encode('hex') == self.get_remote_mpk() @@ -838,7 +848,7 @@ class Wallet: try: d.decode('hex') except: - raise BaseException("Invalid password") + raise ValueError("Invalid password") return d else: return s @@ -921,10 +931,10 @@ class Wallet: def mktx(self, to_address, amount, label, password, fee=None, change_addr=None, from_addr= None): if not self.is_valid(to_address): - raise BaseException("Invalid address") + raise ValueError("Invalid address") inputs, total, fee = self.choose_tx_inputs( amount, fee, from_addr ) if not inputs: - raise BaseException("Not enough funds") + raise ValueError("Not enough funds") if not self.use_change and not change_addr: change_addr = inputs[0][0] @@ -995,7 +1005,7 @@ class Wallet: self.verify_message(previous, signature, "alias:%s:%s"%(alias,target)) if not self.is_valid(target): - raise BaseException("Invalid bitcoin address") + raise ValueError("Invalid bitcoin address") return target, signing_addr, auth_name diff --git a/setup.py b/setup.py index fe3049f4..0e2fcb3b 100644 --- a/setup.py +++ b/setup.py @@ -7,15 +7,12 @@ from lib.version import ELECTRUM_VERSION as version import lib.util as util import os, sys, platform from lib.util import print_error - if sys.version_info[:3] < (2,6,0): - print_error("Error: Electrum requires Python version >= 2.6.0...") - sys.exit(1) - + sys.exit("Error: Electrum requires Python version >= 2.6.0...") data_files = [] - -if platform.system() != 'Windows' and platform.system() != 'Darwin': +if (len(sys.argv) > 1 and (sys.argv[1] == "sdist")) or (platform.system() != 'Windows' and platform.system() != 'Darwin'): + print "Including all files" data_files += [ ('/usr/share/applications/',['electrum.desktop']), ('/usr/share/app-install/icons/',['electrum.png']) @@ -27,10 +24,15 @@ if platform.system() != 'Windows' and platform.system() != 'Darwin': data_files.append( ('/usr/share/locale/%s/LC_MESSAGES'%lang, ['locale/%s/LC_MESSAGES/electrum.mo'%lang]) ) data_files += [ - (util.appdata_dir(), ["data/background.png", "data/style.css"]), - (os.path.join(util.appdata_dir(), "icons"), [ - "data/icons/confirmed.png", - "data/icons/unconfirmed.png" + (util.appdata_dir(), ["data/noface.svg", "data/README"]), + (os.path.join(util.appdata_dir(), "cleanlook"), [ + "data/cleanlook/name.cfg", + "data/cleanlook/style.css" + ]), + (os.path.join(util.appdata_dir(), "dark"), [ + "data/dark/background.png", + "data/dark/name.cfg", + "data/dark/style.css" ]) ]