diff --git a/client/LICENCE b/LICENCE similarity index 100% rename from client/LICENCE rename to LICENCE diff --git a/client/MANIFEST.in b/MANIFEST.in similarity index 100% rename from client/MANIFEST.in rename to MANIFEST.in diff --git a/client/README b/README similarity index 100% rename from client/README rename to README diff --git a/client/RELEASE-NOTES b/RELEASE-NOTES similarity index 100% rename from client/RELEASE-NOTES rename to RELEASE-NOTES diff --git a/client/blocks b/blocks similarity index 100% rename from client/blocks rename to blocks diff --git a/client/bmp.py b/bmp.py similarity index 90% rename from client/bmp.py rename to bmp.py index bfdd165b..b4bd4102 100644 --- a/client/bmp.py +++ b/bmp.py @@ -193,7 +193,23 @@ class BitMap(object): f.close() +def save_qrcode(qr, filename): + bitmap = BitMap( 35*8, 35*8 ) + #print len(bitmap.bitarray) + bitmap.bitarray = [] + k = 33 + for r in range(35): + tmparray = [ 0 ] * 35*8 + if 0 < r < 34: + for c in range(k): + if qr.isDark(r-1, c): + tmparray[ (1+c)*8:(2+c)*8] = [1]*8 + + for i in range(8): + bitmap.bitarray.append( tmparray[:] ) + + bitmap.saveFile( filename ) diff --git a/client/docs/android.html b/docs/android.html similarity index 100% rename from client/docs/android.html rename to docs/android.html diff --git a/client/electrum b/electrum similarity index 99% rename from client/electrum rename to electrum index 011d56f2..e7f378d6 100755 --- a/client/electrum +++ b/electrum @@ -288,7 +288,7 @@ if __name__ == '__main__': h = wallet.history.get(addr,[]) ni = no = 0 for item in h: - if item['is_in']: ni += 1 + if item['is_input']: ni += 1 else: no += 1 b = "%d %d %s"%(no, ni, str(Decimal(wallet.get_addr_balance(addr)[0])/100000000)) else: b='' diff --git a/client/electrum4a.py b/electrum4a.py similarity index 96% rename from client/electrum4a.py rename to electrum4a.py index f2477644..513267b2 100755 --- a/client/electrum4a.py +++ b/electrum4a.py @@ -26,7 +26,7 @@ from wallet import format_satoshis from decimal import Decimal import mnemonic -import datetime +import datetime, re @@ -606,6 +606,11 @@ def main_loop(): elif out == "receive": global receive_addr receive_addr = select_from_addresses() + if receive_addr: + amount = modal_input('Amount', 'Amount you want receive. ', '', "numberDecimal") + if amount: + receive_addr = 'bitcoin:%s?amount=%s'%(receive_addr, amount) + if not receive_addr: out = None @@ -656,9 +661,16 @@ def payto_loop(): code = droid.scanBarcode() r = code.result if r: - addr = r['extras']['SCAN_RESULT'] - if addr: - droid.fullSetProperty("recipient","text",addr) + data = r['extras']['SCAN_RESULT'] + if data: + if re.match('^bitcoin:', data): + payto, amount, label, _, _, _, _ = wallet.parse_url(data, None, None) + droid.fullSetProperty("recipient", "text",payto) + droid.fullSetProperty("amount", "text", amount) + droid.fullSetProperty("label", "text", label) + else: + droid.fullSetProperty("recipient", "text", data) + elif event["name"] in menu_commands: out = event["name"] @@ -923,29 +935,16 @@ def make_bitmap(addr): # fixme: this is highly inefficient droid.dialogCreateSpinnerProgress("please wait") droid.dialogShow() - import pyqrnative, bmp - qr = pyqrnative.QRCode(4, pyqrnative.QRErrorCorrectLevel.H) - qr.addData(addr) - qr.make() - k = qr.getModuleCount() - bitmap = bmp.BitMap( 35*8, 35*8 ) - print len(bitmap.bitarray) - bitmap.bitarray = [] - assert k == 33 - - for r in range(35): - tmparray = [ 0 ] * 35*8 - - if 0 < r < 34: - for c in range(k): - if qr.isDark(r-1, c): - tmparray[ (1+c)*8:(2+c)*8] = [1]*8 - - for i in range(8): - bitmap.bitarray.append( tmparray[:] ) - - bitmap.saveFile( "/sdcard/sl4a/qrcode.bmp" ) - droid.dialogDismiss() + try: + import pyqrnative, bmp + qr = pyqrnative.QRCode(4, pyqrnative.QRErrorCorrectLevel.L) + qr.addData(addr) + qr.make() + k = qr.getModuleCount() + assert k == 33 + bmp.save_qrcode(qr,"/sdcard/sl4a/qrcode.bmp") + finally: + droid.dialogDismiss() diff --git a/client/electrum_text_320.png b/electrum_text_320.png similarity index 100% rename from client/electrum_text_320.png rename to electrum_text_320.png diff --git a/client/gui.py b/gui.py similarity index 99% rename from client/gui.py rename to gui.py index 77acdd1c..1703ddf3 100644 --- a/client/gui.py +++ b/gui.py @@ -328,9 +328,6 @@ def run_network_dialog( wallet, parent ): radio2 = gtk.RadioButton(radio1, "http") p_box.pack_start(radio2, True, True, 0) radio2.show() - radio3 = gtk.RadioButton(radio1, "native") - p_box.pack_start(radio3, True, True, 0) - radio3.show() def current_line(): return unicode(host_entry.get_text()).split(':') @@ -340,8 +337,6 @@ def run_network_dialog( wallet, parent ): radio1.set_active(1) elif protocol == 'h': radio2.set_active(1) - elif protocol == 'n': - radio3.set_active(1) def set_protocol(protocol): host = current_line()[0] @@ -354,7 +349,6 @@ def run_network_dialog( wallet, parent ): radio1.connect("toggled", lambda x,y:set_protocol('t'), "radio button 1") radio2.connect("toggled", lambda x,y:set_protocol('h'), "radio button 1") - radio3.connect("toggled", lambda x,y:set_protocol('n'), "radio button 1") server_list = gtk.ListStore(str) for host in plist.keys(): diff --git a/client/gui_qt.py b/gui_qt.py similarity index 94% rename from client/gui_qt.py rename to gui_qt.py index 21f52d7c..67118007 100644 --- a/client/gui_qt.py +++ b/gui_qt.py @@ -96,11 +96,14 @@ class StatusBarButton(QPushButton): class QRCodeWidget(QWidget): def __init__(self, addr): - import pyqrnative super(QRCodeWidget, self).__init__() - self.addr = addr self.setGeometry(300, 300, 350, 350) - self.qr = pyqrnative.QRCode(4, pyqrnative.QRErrorCorrectLevel.H) + self.set_addr(addr) + + def set_addr(self, addr): + import pyqrnative + self.addr = addr + self.qr = pyqrnative.QRCode(4, pyqrnative.QRErrorCorrectLevel.L) self.qr.addData(addr) self.qr.make() @@ -527,7 +530,7 @@ class ElectrumWindow(QMainWindow): addr = unicode( i.text(0) ) return addr - qrButton = EnterButton("QR",lambda: ElectrumWindow.showqrcode(get_addr(l))) + qrButton = EnterButton("QR",lambda: self.show_address_qrcode(get_addr(l))) def copy2clipboard(addr): self.app.clipboard().setText(addr) @@ -659,18 +662,75 @@ class ElectrumWindow(QMainWindow): + ' '.join(mnemonic.mn_encode(seed)) + "\"" QMessageBox.information(parent, 'Seed', msg, 'OK') - ElectrumWindow.showqrcode(seed) + if parent: ElectrumWindow.show_seed_qrcode(seed) @staticmethod - def showqrcode(address): + def show_seed_qrcode(seed): + if not seed: return + d = QDialog(None) + d.setModal(1) + d.setWindowTitle(seed) + d.setMinimumSize(270, 300) + vbox = QVBoxLayout() + vbox.addWidget(QRCodeWidget(seed)) + hbox = QHBoxLayout() + hbox.addStretch(1) + b = QPushButton("OK") + hbox.addWidget(b) + b.clicked.connect(d.accept) + + vbox.addLayout(hbox) + d.setLayout(vbox) + d.exec_() + + def show_address_qrcode(self,address): if not address: return d = QDialog(None) d.setModal(1) d.setWindowTitle(address) - d.setMinimumSize(270, 300) + d.setMinimumSize(270, 350) vbox = QVBoxLayout() - vbox.addWidget(QRCodeWidget(address)) - vbox.addLayout(ok_cancel_buttons(d)) + qrw = QRCodeWidget(address) + vbox.addWidget(qrw) + + hbox = QHBoxLayout() + amount_e = QLineEdit() + hbox.addWidget(QLabel('Amount')) + hbox.addWidget(amount_e) + vbox.addLayout(hbox) + + #hbox = QHBoxLayout() + #label_e = QLineEdit() + #hbox.addWidget(QLabel('Label')) + #hbox.addWidget(label_e) + #vbox.addLayout(hbox) + + def amount_changed(): + amount = numbify(amount_e) + #label = str( label_e.getText() ) + if amount is not None: + qrw.set_addr('bitcoin:%s?amount=%s'%(address,str( Decimal(amount) /100000000))) + else: + qrw.set_addr( address ) + qrw.repaint() + + def do_save(): + import bmp + bmp.save_qrcode(qrw.qr, "qrcode.bmp") + self.show_message("QR code saved to file 'qrcode.bmp'") + + amount_e.textChanged.connect( amount_changed ) + + hbox = QHBoxLayout() + hbox.addStretch(1) + b = QPushButton("Save") + b.clicked.connect(do_save) + hbox.addWidget(b) + b = QPushButton("Close") + hbox.addWidget(b) + b.clicked.connect(d.accept) + + vbox.addLayout(hbox) d.setLayout(vbox) d.exec_() @@ -897,7 +957,6 @@ class ElectrumWindow(QMainWindow): buttonGroup = QGroupBox("protocol") radio1 = QRadioButton("tcp", buttonGroup) radio2 = QRadioButton("http", buttonGroup) - radio3 = QRadioButton("native", buttonGroup) def current_line(): return unicode(host_line.text()).split(':') @@ -907,8 +966,6 @@ class ElectrumWindow(QMainWindow): radio1.setChecked(1) elif protocol == 'h': radio2.setChecked(1) - elif protocol == 'n': - radio3.setChecked(1) def set_protocol(protocol): host = current_line()[0] @@ -921,14 +978,12 @@ class ElectrumWindow(QMainWindow): radio1.clicked.connect(lambda x: set_protocol('t') ) radio2.clicked.connect(lambda x: set_protocol('h') ) - radio3.clicked.connect(lambda x: set_protocol('n') ) set_button(current_line()[2]) hbox.addWidget(QLabel('Protocol:')) hbox.addWidget(radio1) hbox.addWidget(radio2) - hbox.addWidget(radio3) vbox.addLayout(hbox) diff --git a/client/icons.qrc b/icons.qrc similarity index 100% rename from client/icons.qrc rename to icons.qrc diff --git a/client/icons/confirmed.png b/icons/confirmed.png similarity index 100% rename from client/icons/confirmed.png rename to icons/confirmed.png diff --git a/client/icons/lock.png b/icons/lock.png similarity index 100% rename from client/icons/lock.png rename to icons/lock.png diff --git a/client/icons/lock.svg b/icons/lock.svg similarity index 100% rename from client/icons/lock.svg rename to icons/lock.svg diff --git a/client/icons/network.png b/icons/network.png similarity index 100% rename from client/icons/network.png rename to icons/network.png diff --git a/client/icons/preferences.png b/icons/preferences.png similarity index 100% rename from client/icons/preferences.png rename to icons/preferences.png diff --git a/client/icons/seed.png b/icons/seed.png similarity index 100% rename from client/icons/seed.png rename to icons/seed.png diff --git a/client/icons/status_connected.png b/icons/status_connected.png similarity index 100% rename from client/icons/status_connected.png rename to icons/status_connected.png diff --git a/client/icons/status_disconnected.png b/icons/status_disconnected.png similarity index 100% rename from client/icons/status_disconnected.png rename to icons/status_disconnected.png diff --git a/client/icons/status_disconnected.svg b/icons/status_disconnected.svg similarity index 100% rename from client/icons/status_disconnected.svg rename to icons/status_disconnected.svg diff --git a/client/icons/status_waiting.png b/icons/status_waiting.png similarity index 100% rename from client/icons/status_waiting.png rename to icons/status_waiting.png diff --git a/client/icons/status_waiting.svg b/icons/status_waiting.svg similarity index 100% rename from client/icons/status_waiting.svg rename to icons/status_waiting.svg diff --git a/client/icons/unconfirmed.png b/icons/unconfirmed.png similarity index 100% rename from client/icons/unconfirmed.png rename to icons/unconfirmed.png diff --git a/client/icons/unconfirmed.svg b/icons/unconfirmed.svg similarity index 100% rename from client/icons/unconfirmed.svg rename to icons/unconfirmed.svg diff --git a/client/interface.py b/interface.py similarity index 78% rename from client/interface.py rename to interface.py index bdba222d..21ea5a83 100644 --- a/client/interface.py +++ b/interface.py @@ -49,25 +49,41 @@ class Interface(threading.Thread): #json self.message_id = 0 self.responses = Queue.Queue() + self.methods = {} def poke(self): # push a fake response so that the getting thread exits its loop self.responses.put(None) def queue_json_response(self, c): - #print repr(c) + + #print "<--",c msg_id = c.get('id') - result = c.get('result') error = c.get('error') - params = c.get('params',[]) - method = c.get('method',None) - if not method: - return if error: - print "received error:", c, method, params + print "received error:", c + return + + if msg_id is not None: + method, params = self.methods.pop(msg_id) + result = c.get('result') else: - self.responses.put({'method':method, 'params':params, 'result':result}) + # notification + method = c.get('method') + params = c.get('params') + + if method == 'blockchain.numblocks.subscribe': + result = params[0] + params = [] + + elif method == 'blockchain.address.subscribe': + addr = params[0] + result = params[1] + params = [addr] + + self.responses.put({'method':method, 'params':params, 'result':result}) + def subscribe(self, addresses): @@ -148,71 +164,6 @@ class PollingInterface(Interface): -class NativeInterface(PollingInterface): - - def start_session(self, addresses, version): - self.send([('session.new', [ version, addresses ])] ) - self.send([('server.peers.subscribe',[])]) - - def poll(self): - self.send([('session.poll', [])]) - - def send(self, messages): - import time - cmds = {'session.new':'new_session', - 'server.peers.subscribe':'peers', - 'session.poll':'poll', - 'blockchain.transaction.broadcast':'tx', - 'blockchain.address.get_history':'h', - 'blockchain.address.subscribe':'address.subscribe' - } - - for m in messages: - method, params = m - cmd = cmds[method] - - if cmd == 'poll': - params = self.session_id - - if cmd == 'address.subscribe': - params = [ self.session_id ] + params - - if cmd in ['h', 'tx']: - str_params = params[0] - elif type(params) != type(''): - str_params = repr( params ) - else: - str_params = params - t1 = time.time() - request = repr ( (cmd, str_params) ) + "#" - s = socket.socket( socket.AF_INET, socket.SOCK_STREAM) - s.settimeout(DEFAULT_TIMEOUT) - s.connect(( self.host, self.port) ) - s.send( request ) - out = '' - while 1: - msg = s.recv(1024) - if msg: out += msg - else: break - s.close() - self.rtime = time.time() - t1 - self.is_connected = True - - if cmd == 'h': - out = old_to_new(out) - - if cmd in ['peers','h','poll']: - out = ast.literal_eval( out ) - - if out == '': - out = None - - if cmd == 'new_session': - self.session_id, msg = ast.literal_eval( out ) - self.responses.put({'method':'server.banner', 'params':[], 'result':msg}) - else: - self.responses.put({'method':method, 'params':params, 'result':out}) - @@ -235,6 +186,7 @@ class HttpStratumInterface(PollingInterface): method, params = m if type(params) != type([]): params = [params] data.append( { 'method':method, 'id':self.message_id, 'params':params } ) + self.methods[self.message_id] = method, params self.message_id += 1 if data: @@ -324,6 +276,8 @@ class TcpStratumInterface(Interface): for m in messages: method, params = m request = json.dumps( { 'id':self.message_id, 'method':method, 'params':params } ) + self.methods[self.message_id] = method, params + #print "-->",request self.message_id += 1 out += request + '\n' self.s.send( out ) @@ -357,16 +311,6 @@ class WalletSynchronizer(threading.Thread): self.wallet.banner = result self.wallet.was_updated = True - elif method == 'session.poll': - # native poll - blocks, changed_addresses = result - if blocks == -1: raise BaseException("session not found") - self.wallet.blocks = int(blocks) - if changed_addresses: - self.wallet.was_updated = True - for addr, status in changed_addresses.items(): - self.wallet.receive_status_callback(addr, status) - elif method == 'server.peers.subscribe': servers = [] for item in result: @@ -375,18 +319,14 @@ class WalletSynchronizer(threading.Thread): ports = [] if len(item)>2: for v in item[2]: - if re.match("[thn]\d+",v): + if re.match("[th]\d+",v): ports.append((v[0],v[1:])) - #if not s: - # s.append(host+":50000:n") - #else: - # s.append(host+":50000:n") if ports: servers.append( (host, ports) ) self.interface.servers = servers elif method == 'blockchain.address.subscribe': - addr = params[-1] + addr = params[0] self.wallet.receive_status_callback(addr, result) elif method == 'blockchain.address.get_history': @@ -418,15 +358,13 @@ class WalletSynchronizer(threading.Thread): port = int(port) #print protocol, host, port - if protocol == 'n': - InterfaceClass = NativeInterface - elif protocol == 't': + if protocol == 't': InterfaceClass = TcpStratumInterface elif protocol == 'h': InterfaceClass = HttpStratumInterface else: print "unknown protocol" - InterfaceClass = NativeInterface + InterfaceClass = TcpStratumInterface self.interface = InterfaceClass(host, port) self.wallet.interface = self.interface diff --git a/client/mnemonic.py b/mnemonic.py similarity index 100% rename from client/mnemonic.py rename to mnemonic.py diff --git a/client/msqr.py b/msqr.py similarity index 100% rename from client/msqr.py rename to msqr.py diff --git a/client/peers b/peers similarity index 100% rename from client/peers rename to peers diff --git a/client/pyqrnative.py b/pyqrnative.py similarity index 100% rename from client/pyqrnative.py rename to pyqrnative.py diff --git a/client/remote.php b/remote.php similarity index 100% rename from client/remote.php rename to remote.php diff --git a/client/remote_wallet.py b/remote_wallet.py similarity index 100% rename from client/remote_wallet.py rename to remote_wallet.py diff --git a/client/ripemd.py b/ripemd.py similarity index 100% rename from client/ripemd.py rename to ripemd.py diff --git a/client/setup.py b/setup.py similarity index 100% rename from client/setup.py rename to setup.py diff --git a/client/upgrade.py b/upgrade.py similarity index 100% rename from client/upgrade.py rename to upgrade.py diff --git a/client/version.py b/version.py similarity index 72% rename from client/version.py rename to version.py index be8b02d5..ee1f00c2 100644 --- a/client/version.py +++ b/version.py @@ -1,2 +1,2 @@ -ELECTRUM_VERSION = "0.43e" +ELECTRUM_VERSION = "0.45" SEED_VERSION = 4 # bump this everytime the seed generation is modified diff --git a/client/wallet.py b/wallet.py similarity index 99% rename from client/wallet.py rename to wallet.py index d30bea71..d4be6852 100644 --- a/client/wallet.py +++ b/wallet.py @@ -609,11 +609,8 @@ class Wallet: def get_addr_balance(self, addr): - if self.is_mine(addr): - h = self.history.get(addr) - else: - h = self.interface.retrieve_history(addr) - if not h: return 0,0 + assert self.is_mine(addr) + h = self.history.get(addr,[]) c = u = 0 for item in h: v = item['value'] diff --git a/watch_address b/watch_address new file mode 100755 index 00000000..162c5a6d --- /dev/null +++ b/watch_address @@ -0,0 +1,31 @@ +#!/usr/bin/env python + +import interface, sys +try: + addr = sys.argv[1] +except: + print "usage: watch_address " + +i = interface.TcpStratumInterface('ecdsa.org', 50001) +i.start() +i.send([('blockchain.address.subscribe',[addr])]) + +while True: + r = i.responses.get(True, 100000000000) + method = r.get('method') + if method == 'blockchain.address.subscribe': + i.send([('blockchain.address.get_history',[addr])]) + elif method == 'blockchain.address.get_history': + confirmed = unconfirmed = 0 + h = r.get('result') + if h is None: + continue + for item in h: + v = item['value'] + if item['height']: + confirmed += v + else: + unconfirmed += v + print (confirmed+unconfirmed)/1.e8 + +