Transferred help text into README.md file.
[btcspy.git] / btcspy.py
1 #!/usr/bin/env python
2 #
3 # btcspy - electrum client history outputter
4 # Copyright (C) 2011 thomasv@gitorious
5 # Copyright (C) 2014 David Llewellyn-Jones (david@flypig.co.uk)
6 #
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20 from decimal import Decimal
21 import json
22 import optparse
23 import os
24 import re
25 import ast
26 import sys
27 import time
28 import traceback
29 import inspect
30
31 # use this if you want to include modules from a subforder
32 cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"lib")))
33 if cmd_subfolder not in sys.path:
34 sys.path.insert(0, cmd_subfolder)
35
36
37 import simple_config, wallet
38 from simple_config import *
39 from commands import *
40 from util import print_msg, print_stderr, print_json, set_verbosity
41 from wallet import *
42
43 is_local = os.path.dirname(os.path.realpath(__file__)) == os.getcwd()
44 is_android = 'ANDROID_DATA' in os.environ
45
46 #import __builtin__
47 #__builtin__.use_local_modules = is_local or is_android
48
49 ## load local module as electrum
50 #if __builtin__.use_local_modules:
51 # import imp
52 # #imp.load_module('electrum', *imp.find_module('lib'))
53
54 #if is_local:
55 sys.path.append('lib')
56
57
58 #from electrum import SimpleConfig, Wallet, WalletStorage
59 #from electrum.util import print_msg, print_stderr, print_json, set_verbosity
60
61 # get password routine
62 def prompt_password(prompt, confirm=True):
63 import getpass
64 if sys.stdin.isatty():
65 password = getpass.getpass(prompt)
66 if password and confirm:
67 password2 = getpass.getpass("Confirm: ")
68 if password != password2:
69 sys.exit("Error: Passwords do not match.")
70 else:
71 password = raw_input(prompt)
72 if not password:
73 password = None
74 return password
75
76
77 def arg_parser():
78 usage = "btcspy [options] command"
79 details = "Outputs a list of Bitcoin transactions in JSON format taken from the Electrum wallet of the current user. It can also be imported into a Python program using 'import btcspy', after which 'btcspy.history()' will return the history as a structure,"
80 parser = optparse.OptionParser(prog=usage, add_help_option=False, description=details)
81
82 parser.add_option("-h", "--help", action="callback", callback=print_help_cb, help="show this help text")
83 parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False, help="show debugging information")
84 parser.add_option("-W", "--password", dest="password", default=None, help="set password for usage with commands (currently only implemented for create command, do not use it for longrunning gui session since the password is visible in /proc)")
85 parser.add_option("-w", "--wallet", dest="wallet_path", help="wallet path (default: electrum.dat)")
86 return parser
87
88
89 def print_help(parser):
90 parser.print_help()
91 print_msg("Type 'btcspy --help' to see the list of options")
92 run_command(known_commands['help'], None)
93 sys.exit(1)
94
95
96 def print_help_cb(self, opt, value, parser):
97 print_help(parser)
98
99
100 def run_command(cmd, wallet, password=None, args=[]):
101 network = None
102
103 cmd_runner = Commands(wallet)
104 func = getattr(cmd_runner, cmd.name)
105 cmd_runner.password = password
106 try:
107 result = func(*args[1:])
108 except Exception:
109 traceback.print_exc(file=sys.stdout)
110 sys.exit(1)
111
112 if type(result) == str:
113 print_msg(result)
114 elif result is not None:
115 print_json(result)
116
117 def get_command(cmd, wallet, password=None, args=[]):
118 network = None
119
120 cmd_runner = Commands(wallet)
121 func = getattr(cmd_runner, cmd.name)
122 cmd_runner.password = password
123 try:
124 result = func(*args[1:])
125 except Exception:
126 traceback.print_exc(file=sys.stdout)
127 sys.exit(1)
128
129 return result
130
131
132 if __name__ == '__main__':
133
134 parser = arg_parser()
135 options, args = parser.parse_args()
136 # if options.wallet_path is None:
137 # options.electrum_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'electrum_data')
138
139 config_options = eval(str(options))
140 for k, v in config_options.items():
141 if v is None:
142 config_options.pop(k)
143
144 set_verbosity(config_options.get('verbose'))
145
146 config = SimpleConfig(config_options)
147
148 if len(args) == 0:
149 url = None
150 cmd = 'history'
151 else:
152 cmd = args[0]
153
154 if cmd not in known_commands:
155 cmd = 'help'
156
157 cmd = known_commands[cmd]
158
159 # instanciate wallet for command-line
160 storage = WalletStorage(config)
161
162
163 if cmd.requires_wallet and not storage.file_exists:
164 print_msg("Error: Wallet file not found.")
165 sys.exit(0)
166
167
168 wallet = Wallet(storage)
169
170
171 # commands needing password
172 if cmd.requires_password:
173 if wallet.seed == '':
174 seed = ''
175 password = None
176 elif wallet.use_encryption:
177 password = prompt_password('Password:', False)
178 if not password:
179 print_msg("Error: Password required")
180 sys.exit(1)
181 # check password
182 try:
183 seed = wallet.get_seed(password)
184 except Exception:
185 print_msg("Error: This password does not decode this wallet.")
186 sys.exit(1)
187 else:
188 password = None
189 seed = wallet.get_seed(None)
190 else:
191 password = None
192
193 # add missing arguments, do type conversions
194 if cmd.name == 'help':
195 if len(args) < 2:
196 print_help(parser)
197
198 # check the number of arguments
199 argslength = len(args) - 1
200 if argslength < 0:
201 argslength = 0
202
203 if argslength < cmd.min_args:
204 print_msg("Not enough arguments")
205 print_msg("Syntax:", cmd.syntax)
206 sys.exit(1)
207
208 if cmd.max_args >= 0 and argslength > cmd.max_args:
209 print_msg("too many arguments", args)
210 print_msg("Syntax:", cmd.syntax)
211 sys.exit(1)
212
213 if cmd.max_args < 0:
214 if len(args) > cmd.min_args + 1:
215 message = ' '.join(args[cmd.min_args:])
216 print_msg("Warning: Final argument was reconstructed from several arguments:", repr(message))
217 args = args[0:cmd.min_args] + [message]
218
219
220
221 # run the command
222 run_command(cmd, wallet, password, args)
223
224
225 time.sleep(0.1)
226 sys.exit(0)
227
228 def history():
229 config = SimpleConfig()
230
231 url = None
232 cmd = 'history'
233
234 cmd = known_commands[cmd]
235
236 # instanciate wallet for command-line
237 storage = WalletStorage(config)
238
239
240 if cmd.requires_wallet and not storage.file_exists:
241 print_msg("Error: Wallet file not found.")
242 sys.exit(0)
243
244
245 wallet = Wallet(storage)
246
247 # commands needing password
248 if cmd.requires_password:
249 if wallet.seed == '':
250 seed = ''
251 password = None
252 elif wallet.use_encryption:
253 password = prompt_password('Password:', False)
254 if not password:
255 print_msg("Error: Password required")
256 sys.exit(1)
257 # check password
258 try:
259 seed = wallet.get_seed(password)
260 except Exception:
261 print_msg("Error: This password does not decode this wallet.")
262 sys.exit(1)
263 else:
264 password = None
265 seed = wallet.get_seed(None)
266 else:
267 password = None
268
269 # run the command
270 return get_command(cmd, wallet, password)
271
272
273