electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit 513f9c2d89e9a530710bb163ea713f6948185fbc
parent 2bbcae449c0b71fa74d61384888c72a5e437296a
Author: ThomasV <thomasv@gitorious>
Date:   Fri,  6 Jun 2014 16:16:14 +0200

save invoices

Diffstat:
Mgui/qt/__init__.py | 3++-
Mgui/qt/main_window.py | 37++++++++++++++++++++++++++++++++++++-
Mgui/qt/paytoedit.py | 6++++++
Mlib/paymentrequest.py | 55++++++++++++++++++++++++++++++++++++++++++++++---------
4 files changed, 90 insertions(+), 11 deletions(-)

diff --git a/gui/qt/__init__.py b/gui/qt/__init__.py @@ -181,7 +181,8 @@ class ElectrumGui: return def payment_request(): - self.payment_request = paymentrequest.PaymentRequest(request_url) + self.payment_request = paymentrequest.PaymentRequest(self.config) + self.payment_request.read(request_url) if self.payment_request.verify(): self.main_window.emit(SIGNAL('payment_request_ok')) else: diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py @@ -129,6 +129,7 @@ class ElectrumWindow(QMainWindow): tabs.addTab(self.create_send_tab(), _('Send') ) tabs.addTab(self.create_receive_tab(), _('Receive') ) tabs.addTab(self.create_contacts_tab(), _('Contacts') ) + tabs.addTab(self.create_invoices_tab(), _('Invoices') ) tabs.addTab(self.create_console_tab(), _('Console') ) tabs.setMinimumSize(600, 400) tabs.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) @@ -468,6 +469,7 @@ class ElectrumWindow(QMainWindow): self.update_receive_tab() self.update_contacts_tab() self.update_completions() + self.update_invoices_tab() def create_history_tab(self): @@ -808,7 +810,7 @@ class ElectrumWindow(QMainWindow): if addr is None or not bitcoin.is_address(addr): QMessageBox.warning(self, _('Error'), _('Invalid Bitcoin Address'), _('OK')) return - if type(x) is not int: + if x is None: QMessageBox.warning(self, _('Error'), _('Invalid Amount'), _('OK')) return @@ -912,6 +914,7 @@ class ElectrumWindow(QMainWindow): def prepare_for_payment_request(self): self.tabs.setCurrentIndex(1) + self.payto_e.is_pr = True for e in [self.payto_e, self.amount_e, self.message_e]: e.setFrozen(True) for h in [self.payto_help, self.amount_help, self.message_help]: @@ -921,6 +924,13 @@ class ElectrumWindow(QMainWindow): def payment_request_ok(self): pr = self.gui_object.payment_request + pr_id = pr.get_id() + # save it + invoices = self.wallet.storage.get('invoices', {}) + invoices[pr_id] = (pr.get_domain(), pr.get_amount()) + invoices = self.wallet.storage.put('invoices', invoices) + self.update_invoices_tab() + self.payto_help.show() self.payto_help.set_alt(pr.status) self.payto_e.setGreen() @@ -952,6 +962,7 @@ class ElectrumWindow(QMainWindow): def do_clear(self): + self.payto_e.is_pr = False self.payto_sig.setVisible(False) for e in [self.payto_e, self.message_e, self.amount_e, self.fee_e]: e.setText('') @@ -1049,6 +1060,30 @@ class ElectrumWindow(QMainWindow): return w + def create_invoices_tab(self): + l,w,hbox = self.create_list_tab([_('Recipient'), _('Amount'), _('Status')]) + l.setContextMenuPolicy(Qt.CustomContextMenu) + #l.customContextMenuRequested.connect(self.create_contact_menu) + #self.connect(l, SIGNAL('itemDoubleClicked(QTreeWidgetItem*, int)'), lambda a, b: self.address_label_clicked(a,b,l,0,1)) + #self.connect(l, SIGNAL('itemChanged(QTreeWidgetItem*, int)'), lambda a,b: self.address_label_changed(a,b,l,0,1)) + self.invoices_list = l + hbox.addStretch(1) + return w + + def update_invoices_tab(self): + invoices = self.wallet.storage.get('invoices', {}) + l = self.invoices_list + l.clear() + + for item, value in invoices.items(): + domain, amount = value + item = QTreeWidgetItem( [ domain, self.format_amount(amount), ""] ) + l.addTopLevelItem(item) + + l.setCurrentItem(l.topLevelItem(0)) + + + def delete_imported_key(self, addr): if self.question(_("Do you want to remove")+" %s "%addr +_("from your wallet?")): self.wallet.delete_imported_key(addr) diff --git a/gui/qt/paytoedit.py b/gui/qt/paytoedit.py @@ -42,6 +42,7 @@ class PayToEdit(QTextEdit): self.c = None self.textChanged.connect(self.check_text) self.outputs = [] + self.is_pr = False def lock_amount(self): self.amount_edit.setFrozen(True) @@ -54,8 +55,10 @@ class PayToEdit(QTextEdit): self.setStyleSheet(frozen_style if b else normal_style) def setGreen(self): + self.is_pr = True self.setStyleSheet("QWidget { background-color:#00ff00;}") + def parse_address_and_amount(self, line): x, y = line.split(',') address = self.parse_address(x) @@ -77,6 +80,9 @@ class PayToEdit(QTextEdit): def check_text(self): + if self.is_pr: + return + # filter out empty lines lines = filter( lambda x: x, self.lines()) outputs = [] diff --git a/lib/paymentrequest.py b/lib/paymentrequest.py @@ -18,6 +18,7 @@ import urlparse import requests from M2Crypto import X509 +import bitcoin from bitcoin import is_valid import urlparse @@ -29,6 +30,15 @@ import transaction REQUEST_HEADERS = {'Accept': 'application/bitcoin-paymentrequest', 'User-Agent': 'Electrum'} ACK_HEADERS = {'Content-Type':'application/bitcoin-payment','Accept':'application/bitcoin-paymentack','User-Agent':'Electrum'} +# status can be: +PR_UNPAID = 0 +PR_EXPIRED = 1 +PR_SENT = 2 # sent but not propagated +PR_PAID = 3 # send and propagated + + + + ca_path = os.path.expanduser("~/.electrum/ca/ca-bundle.crt") ca_list = {} try: @@ -52,32 +62,52 @@ except Exception: class PaymentRequest: - def __init__(self, url): - self.url = url + def __init__(self, config): + self.config = config self.outputs = [] self.error = "" + def read(self, url): + self.url = url - def verify(self): - u = urlparse.urlparse(self.url) + u = urlparse.urlparse(url) self.domain = u.netloc try: connection = httplib.HTTPConnection(u.netloc) if u.scheme == 'http' else httplib.HTTPSConnection(u.netloc) connection.request("GET",u.geturl(), headers=REQUEST_HEADERS) - resp = connection.getresponse() + response = connection.getresponse() except: self.error = "cannot read url" return - paymntreq = paymentrequest_pb2.PaymentRequest() try: - r = resp.read() - paymntreq.ParseFromString(r) + r = response.read() + except: + self.error = "cannot read" + return + + try: + self.data = paymentrequest_pb2.PaymentRequest() + self.data.ParseFromString(r) except: self.error = "cannot parse payment request" return + self.id = bitcoin.sha256(r)[0:16].encode('hex') + print self.id + + dir_path = os.path.join( self.config.path, 'requests') + if not os.path.exists(dir_path): + os.mkdir(dir_path) + filename = os.path.join(dir_path, self.id) + with open(filename,'w') as f: + f.write(r) + + + + def verify(self): + paymntreq = self.data sig = paymntreq.signature if not sig: self.error = "No signature" @@ -187,6 +217,14 @@ class PaymentRequest: return True + def get_amount(self): + return sum(map(lambda x:x[1], self.outputs)) + + def get_domain(self): + return self.domain + + def get_id(self): + return self.id def send_ack(self, raw_tx, refund_addr): @@ -228,7 +266,6 @@ class PaymentRequest: - if __name__ == "__main__": try: