derive plugins from BasePlugin class
[electrum-nvc.git] / plugins / qrscanner.py
1 from electrum.util import print_error
2 from urlparse import urlparse, parse_qs
3 from PyQt4.QtGui import QPushButton
4 from electrum_gui.i18n import _
5
6 try:
7     import zbar
8 except ImportError:
9     zbar = None
10
11 from electrum_gui import BasePlugin
12 class Plugin(BasePlugin):
13
14     def __init__(self, gui):
15         BasePlugin.__init__(self, gui, 'qrscans', 'QR scans', "QR Scans.\nInstall the zbar package to enable this plugin")
16         
17     def is_available(self):
18         if not zbar:
19             return False
20         try:
21             proc = zbar.Processor()
22             proc.init()
23         except zbar.SystemError:
24             # Cannot open video device
25             return False
26         return True
27
28
29     def create_send_tab(self, grid):
30         b = QPushButton(_("Scan QR code"))
31         b.clicked.connect(self.fill_from_qr)
32         grid.addWidget(b, 1, 5)
33
34
35     def scan_qr(self):
36         proc = zbar.Processor()
37         proc.init()
38         proc.visible = True
39
40         while True:
41             try:
42                 proc.process_one()
43             except:
44                 # User closed the preview window
45                 return {}
46
47             for r in proc.results:
48                 if str(r.type) != 'QRCODE':
49                     continue
50                 return parse_uri(r.data)
51         
52
53     def fill_from_qr(self):
54         qrcode = self.scan_qr()
55         if 'address' in qrcode:
56             self.gui.payto_e.setText(qrcode['address'])
57         if 'amount' in qrcode:
58             self.gui.amount_e.setText(str(qrcode['amount']))
59         if 'label' in qrcode:
60             self.gui.message_e.setText(qrcode['label'])
61         if 'message' in qrcode:
62             self.gui.message_e.setText("%s (%s)" % (self.gui.message_e.text(), qrcode['message']))
63                 
64
65
66
67 def parse_uri(uri):
68     if ':' not in uri:
69         # It's just an address (not BIP21)
70         return {'address': uri}
71
72     if '//' not in uri:
73         # Workaround for urlparse, it don't handle bitcoin: URI properly
74         uri = uri.replace(':', '://')
75         
76     uri = urlparse(uri)
77     result = {'address': uri.netloc} 
78     
79     if uri.path.startswith('?'):
80         params = parse_qs(uri.path[1:])
81     else:
82         params = parse_qs(uri.path)    
83
84     for k,v in params.items():
85         if k in ('amount', 'label', 'message'):
86             result[k] = v[0]
87         
88     return result    
89
90
91
92
93
94 if __name__ == '__main__':
95     # Run some tests
96     
97     assert(parse_uri('1Marek48fwU7mugmSe186do2QpUkBnpzSN') ==
98            {'address': '1Marek48fwU7mugmSe186do2QpUkBnpzSN'})
99
100     assert(parse_uri('bitcoin://1Marek48fwU7mugmSe186do2QpUkBnpzSN') ==
101            {'address': '1Marek48fwU7mugmSe186do2QpUkBnpzSN'})
102     
103     assert(parse_uri('bitcoin:1Marek48fwU7mugmSe186do2QpUkBnpzSN') ==
104            {'address': '1Marek48fwU7mugmSe186do2QpUkBnpzSN'})
105     
106     assert(parse_uri('bitcoin:1Marek48fwU7mugmSe186do2QpUkBnpzSN?amount=10') ==
107            {'amount': '10', 'address': '1Marek48fwU7mugmSe186do2QpUkBnpzSN'})
108     
109     assert(parse_uri('bitcoin:1Marek48fwU7mugmSe186do2QpUkBnpzSN?amount=10&label=slush&message=Small%20tip%20to%20slush') ==
110            {'amount': '10', 'label': 'slush', 'message': 'Small tip to slush', 'address': '1Marek48fwU7mugmSe186do2QpUkBnpzSN'})
111     
112