Merge branch 'servers'
authorAmir Taaki <genjix@riseup.net>
Mon, 27 Aug 2012 01:48:57 +0000 (03:48 +0200)
committerAmir Taaki <genjix@riseup.net>
Mon, 27 Aug 2012 01:48:57 +0000 (03:48 +0200)
Conflicts:
lib/gui_lite.py

TODO
data/noface.svg
electrum
electrum.png
lib/exchange_rate.py
lib/gui_lite.py
lib/wallet.py
setup.py

diff --git a/TODO b/TODO
index b5c8430..89affcc 100644 (file)
--- a/TODO
+++ b/TODO
@@ -3,6 +3,7 @@ Client:
 - Wizard
 - Multiple wallets
 - Themes
+- Extend GUI with history view (View -> Show History)
 - Settings window
 
 Server:
index 9956854..dc24f11 100644 (file)
@@ -52,7 +52,7 @@
      inkscape:groupmode="layer"
      id="layer1">
     <path
-       style="opacity:1;fill:#d7d7d7;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none"
+       style="opacity:0.83716047999999998;fill:#d7d7d7;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none"
        d="m 472.75139,908.92052 c 46.46702,-26.26397 56.56855,-68.69038 66.67007,-98.99495 10.10153,-30.30458 52.52793,-228.29448 42.42641,-347.49248 -10.10153,-119.198 -58.58885,-135.36044 -107.07617,-159.6041 -48.48732,-24.24366 -133.34014,-18.18275 -175.76654,8.08122 -42.42642,26.26397 -92.93405,60.60915 -101.01527,143.44166 -8.08122,82.83251 9.13377,276.70605 46.46702,371.73614 22.22336,56.56854 47.29278,70.95769 78.79191,84.85281 31.49913,13.89512 116.60088,16.01267 149.50257,-2.0203 z"
        id="path3050"
        inkscape:connector-curvature="0"
index bd9bb72..d87d276 100755 (executable)
--- a/electrum
+++ b/electrum
 # 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 re, sys
+import re
+import sys
+# import argparse
+import optparse
+
 try:
     from lib.util import print_error
 except ImportError:
@@ -37,7 +41,6 @@ try:
 except ImportError:
     from electrum import Wallet, WalletSynchronizer, format_satoshis, mnemonic, prompt_password
     
-from optparse import OptionParser
 from decimal import Decimal
 
 known_commands = {
@@ -75,9 +78,9 @@ options:\n  --fee, -f: set transaction fee\n  --fromaddr, -s: send from address
     'import': 
             'Imports a key pair\nSyntax: import <address>:<privatekey>',
     'signmessage':
-            'Signs a message with a key\nSyntax: signmessage <address> <message>',
+            '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':
-             'Verifies a signature\nSyntax: verifymessage <address> <signature> <message>',
+             'Verifies a signature\nSyntax: verifymessage <address> <signature> <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 "',
     'eval':  
              "Run python eval() on an object\nSyntax: eval <expression>\nExample: eval \"wallet.aliases\"",
     'deseed':
@@ -99,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")
@@ -126,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':
@@ -158,14 +163,14 @@ if __name__ == '__main__':
               error_message.showMessage("<p>Sorry, Electrum requires Qt >= 4.7 to run.</p><p>Check your distributions packages or download it at http://qt.nokia.com/downloads</p>")
               app.exec_()
               sys.exit(0)
-
+           
+            #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()
@@ -307,7 +312,6 @@ if __name__ == '__main__':
         cmd2 = firstarg
         if cmd2 not in known_commands:
             parser.print_help()
-            print
             print "Type 'electrum help <command>' 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)
@@ -353,7 +357,7 @@ if __name__ == '__main__':
                 d = ast.literal_eval( data )
                 seed = d['seed']
                 imported_keys = d.get('imported_keys',{})
-            except IOError:
+            except:
                 sys.exit("Error: Error with seed file")
 
             mpk = wallet.master_public_key
@@ -500,7 +504,7 @@ if __name__ == '__main__':
     elif cmd == 'password':
         try:
             seed = wallet.pw_decode( wallet.seed, password)
-        except StandardError:
+        except ValueError:
             sys.exit("Error: Password does not decrypt this wallet.")
 
         new_password = prompt_password('New password:')
@@ -531,7 +535,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':
index f47d03b..a45fe95 100644 (file)
Binary files a/electrum.png and b/electrum.png differ
index e8c9fac..77cbf9b 100644 (file)
@@ -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__":
index a703f8d..3a05812 100644 (file)
@@ -75,6 +75,7 @@ class ElectrumGui:
         self.app.exec_()
 
     def expand(self):
+        """Hide the lite mode window and show pro-mode."""
         self.mini.hide()
         self.expert.show()
 
@@ -182,8 +183,8 @@ class MiniWindow(QDialog):
         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"))
@@ -257,9 +258,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):
@@ -277,6 +279,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:
@@ -286,6 +289,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:
@@ -301,6 +305,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:
@@ -317,6 +323,10 @@ 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."""
+        # 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):
             self.send_button.setDisabled(False)
@@ -388,10 +398,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 = "<span style='font-size: 18pt'>%s</span> <span style='font-size: 10pt'>BTC</span> <span style='font-size: 10pt'>%s</span>" % (btc_balance, quote_text)
@@ -483,17 +495,22 @@ class ReceivePopup(QDialog):
         QCursor.setPos(center_mouse_pos)
         self.show()
 
-class MiniActuator(QObject):
-
+class MiniActuator:
+    """Initialize the definitions relating to themes and 
+    sending/recieving bitcoins.
+    """
+    
+    
     def __init__(self, wallet):
+        """Retrieve the gui theme used in previous session."""
         super(QObject, self).__init__()
 
         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:
@@ -504,15 +521,21 @@ class MiniActuator(QObject):
             qApp.setStyleSheet(style_file.read())
 
     def theme_names(self):
+        """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.
@@ -520,6 +543,7 @@ class MiniActuator(QObject):
             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):
@@ -587,6 +611,7 @@ class MiniActuator(QObject):
         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
@@ -597,6 +622,7 @@ class MiniActuator(QObject):
         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):
@@ -659,6 +685,7 @@ class MiniActuator(QObject):
             return recipient
 
     def is_valid(self, address):
+        """Check if bitcoin address is valid."""
         return self.wallet.is_valid(address)
 
     def acceptbit(self, currency):
index 023daf7..5677cd4 100644 (file)
 # 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 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)
@@ -678,20 +686,19 @@ class Wallet:
         os.chmod(self.path,stat.S_IREAD | stat.S_IWRITE)
 
     def read(self):
-        '''Read the contents of the wallet file.'''
+        """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 )  #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')
@@ -717,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()
 
@@ -841,7 +848,7 @@ class Wallet:
                 try:
                     d.decode('hex')
                 except:
-                    raise BaseException("Invalid password")
+                    raise ValueError("Invalid password")
             return d
         else:
             return s
@@ -924,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]
@@ -998,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
 
index abf1ce8..0e2fcb3 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -7,13 +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):
     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'])
@@ -25,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"
     ])
 ]