Added netbank executable.
[fulbank.git] / netbank
1 #!/usr/bin/python3
2
3 import sys, os, getopt, pwd
4 from fulbank import auth
5
6 sesstype = None
7 sess = None
8
9 def find(seq, *, item=None, match=None, key=None, default=LookupError):
10     if key is None:
11         key = lambda o: o
12     if match is None and item is not None:
13         match = lambda o: o == item
14     for thing in seq:
15         if match(key(thing)):
16             return thing
17     if default is LookupError:
18         raise LookupError()
19     else:
20         return default
21
22 def usage(out):
23     out.write("usage: netbank [-h] BANK-ID COMMAND [ARGS...]")
24
25 def requiresess(fn):
26     def wrap(cmd, args):
27         if sess is None:
28             sys.stderr.write("netbank: %s: no current session\n" % (cmd))
29             sys.exit(1)
30         return fn(cmd, args)
31     return wrap
32
33 commands = {}
34
35 def cmd_login(cmd, args):
36     global sess
37     if len(args) < 1:
38         sys.stderr.write("usage: login TYPE\n")
39         sys.exit(1)
40     sess = sesstype.create()
41     if args[0] == "bankid":
42         if len(args) < 2:
43             sys.stderr.write("usage: login bankid USER-ID\n")
44             sys.exit(1)
45         with auth.ttyconv() as conv:
46             sess.auth_bankid(args[1], conv)
47     else:
48         sys.stderr.write("netbank: %s: unknown authentication type\n" % (args[0]))
49         sys.exit(1)
50 commands["login"] = cmd_login
51
52 @requiresess
53 def cmd_logout(cmd, args):
54     if sess is not None:
55         sess.close()
56         sess = None
57 commands["logout"] = cmd_logout
58
59 @requiresess
60 def cmd_ping(cmd, args):
61     sess.keepalive()
62 commands["ping"] = cmd_ping
63
64 @requiresess
65 def cmd_lsacct(cmd, args):
66     for acct in sess.accounts:
67         sys.stdout.write("%s (%s): %s\n" % (acct.number, acct.name, acct.balance))
68 commands["lsacct"] = cmd_lsacct
69
70 @requiresess
71 def cmd_lstxn(cmd, args):
72     opts, args = getopt.getopt(args, "n:")
73     num = 10
74     for o, a in opts:
75         if o == "-n":
76             num = int(a)
77     if len(args) < 1:
78         sys.stderr.write("usage: lstxn [-n NUM] ACCOUNT\n")
79         sys.exit(1)
80     try:
81         acct = find(sess.accounts, item=args[0], key=lambda acct: acct.number)
82     except LookupError:
83         sys.stderr.write("netbank: %s: no such account\n" % (args[0]))
84         sys.exit(1)
85     for i, txn in zip(range(num), acct.transactions()):
86         sys.stdout.write("%s %s: %s\n" % (txn.date.isoformat(), txn.value, txn.message))
87 commands["lstxn"] = cmd_lstxn
88
89 def main():
90     global sess, sesstype
91
92     opts, args = getopt.getopt(sys.argv[1:], "h")
93     for o, a in opts:
94         if o == "-h":
95             usage(sys.stdout)
96             sys.exit(0)
97     if len(args) < 2:
98         usage(sys.stderr)
99         sys.exit(1)
100
101     if args[0] == "fsb":
102         import fulbank.fsb
103         sesstype = fulbank.fsb.session
104     else:
105         sys.stderr.write("netbank: %s: unknown bank id\n" % (args[0]))
106         sys.exit(1)
107     sesspath = os.path.join(pwd.getpwuid(os.getuid()).pw_dir, ".cache/fulbank", args[0])
108     cmd = args[1]
109     args = args[2:]
110
111     if os.path.exists(sesspath):
112         sess = sesstype.load(sesspath)
113     else:
114         sess = None
115     if cmd in commands:
116         commands[cmd](cmd, args)
117     else:
118         sys.stderr.write("netbank: %s: unknown command\n" % (cmd))
119         sys.exit(1)
120     if sess is not None:
121         sessdir = os.path.dirname(sesspath)
122         if not os.path.isdir(sessdir):
123             os.makedirs(sessdir)
124         sess.save(sesspath)
125     else:
126         if os.path.exists(sesspath):
127             os.unlink(sesspath)
128
129 try:
130     if __name__ == "__main__":
131         main()
132 except KeyboardInterrupt:
133     sys.exit(1)