Move is_available() logic to init(), to prevent camera wakeup every second.
[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         self._is_available = self._init()
17         
18     def _init(self):
19         if not zbar:
20             return False
21         try:
22             proc = zbar.Processor()
23             proc.init()
24         except zbar.SystemError:
25             # Cannot open video device
26             return False
27
28         return True
29
30     def is_available(self):
31         return self._is_available
32
33     def create_send_tab(self, grid):
34         b = QPushButton(_("Scan QR code"))
35         b.clicked.connect(self.fill_from_qr)
36         grid.addWidget(b, 1, 5)
37
38
39     def scan_qr(self):
40         proc = zbar.Processor()
41         proc.init()
42         proc.visible = True
43
44         while True:
45             try:
46                 proc.process_one()
47             except:
48                 # User closed the preview window
49                 return {}
50
51             for r in proc.results:
52                 if str(r.type) != 'QRCODE':
53                     continue
54                 return parse_uri(r.data)
55         
56
57     def fill_from_qr(self):
58         qrcode = self.scan_qr()
59         if 'address' in qrcode:
60             self.gui.payto_e.setText(qrcode['address'])
61         if 'amount' in qrcode:
62             self.gui.amount_e.setText(str(qrcode['amount']))
63         if 'label' in qrcode:
64             self.gui.message_e.setText(qrcode['label'])
65         if 'message' in qrcode:
66             self.gui.message_e.setText("%s (%s)" % (self.gui.message_e.text(), qrcode['message']))
67                 
68
69
70
71 def parse_uri(uri):
72     if ':' not in uri:
73         # It's just an address (not BIP21)
74         return {'address': uri}
75
76     if '//' not in uri:
77         # Workaround for urlparse, it don't handle bitcoin: URI properly
78         uri = uri.replace(':', '://')
79         
80     uri = urlparse(uri)
81     result = {'address': uri.netloc} 
82     
83     if uri.path.startswith('?'):
84         params = parse_qs(uri.path[1:])
85     else:
86         params = parse_qs(uri.path)    
87
88     for k,v in params.items():
89         if k in ('amount', 'label', 'message'):
90             result[k] = v[0]
91         
92     return result    
93
94
95
96
97
98 if __name__ == '__main__':
99     # Run some tests
100     
101     assert(parse_uri('1Marek48fwU7mugmSe186do2QpUkBnpzSN') ==
102            {'address': '1Marek48fwU7mugmSe186do2QpUkBnpzSN'})
103
104     assert(parse_uri('bitcoin://1Marek48fwU7mugmSe186do2QpUkBnpzSN') ==
105            {'address': '1Marek48fwU7mugmSe186do2QpUkBnpzSN'})
106     
107     assert(parse_uri('bitcoin:1Marek48fwU7mugmSe186do2QpUkBnpzSN') ==
108            {'address': '1Marek48fwU7mugmSe186do2QpUkBnpzSN'})
109     
110     assert(parse_uri('bitcoin:1Marek48fwU7mugmSe186do2QpUkBnpzSN?amount=10') ==
111            {'amount': '10', 'address': '1Marek48fwU7mugmSe186do2QpUkBnpzSN'})
112     
113     assert(parse_uri('bitcoin:1Marek48fwU7mugmSe186do2QpUkBnpzSN?amount=10&label=slush&message=Small%20tip%20to%20slush') ==
114            {'amount': '10', 'label': 'slush', 'message': 'Small tip to slush', 'address': '1Marek48fwU7mugmSe186do2QpUkBnpzSN'})
115     
116