Init file handling and writing
[jan-pona-mute.git] / jan-pona-mute.py
1 #!/usr/bin/env python3
2 # Copyright (C) 2019 Alex Schroeder <alex@gnu.org>
3
4 # This program is free software: you can redistribute it and/or modify it under
5 # the terms of the GNU Affero General Public License as published by the Free
6 # Software Foundation, either version 3 of the License, or (at your option) any
7 # later version.
8 #
9 # This program is distributed in the hope that it will be useful, but WITHOUT
10 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
12 # details.
13 #
14 # You should have received a copy of the GNU Affero General Public License along
15 # with this program. If not, see <https://www.gnu.org/licenses/>.
16
17 import diaspy
18 import argparse
19 import cmd
20 import sys
21 import os
22
23 # Command abbreviations
24 _ABBREVS = {
25 "q": "quit",
26 }
27
28 _RC_PATHS = (
29 "~/.config/jan-pona-mute/login",
30 "~/.config/.jan-pona-mute",
31 "~/.jan-pona-mute"
32 )
33
34 # Init file finder
35 def get_rcfile():
36 for rc_path in _RC_PATHS:
37 rcfile = os.path.expanduser(rc_path)
38 if os.path.exists(rcfile):
39 return rcfile
40 return None
41
42 class DiasporaClient(cmd.Cmd):
43
44 prompt = "\x1b[38;5;255m" + "> " + "\x1b[0m"
45 intro = "Welcome to Diaspora!"
46
47 username = None
48 pod = None
49 password = None
50
51 connection = None
52 things = []
53 index = None
54
55 # dict mapping user ids to usernames
56 users = {}
57
58 def get_username(self, guid):
59 if guid in self.users:
60 return self.users[guid]
61 else:
62 user = diaspy.people.User(connection = self.connection, guid = guid)
63 self.users[guid] = user.handle()
64 return self.users[guid]
65
66 def do_account(self, account):
67 """Set username and pod using the format username@pod."""
68 try:
69 (self.username, self.pod) = account.split('@')
70 print("Username and pod set: %s@%s" % (self.username, self.pod))
71 except ValueError:
72 print("The account must contain an @ character, e.g. kensanata@pluspora.com.")
73 print("Use the account comand to set the account.")
74
75 def do_info(self, line):
76 """Get some info about things. By default, it is info about yourself."""
77 print("Info about yourself:")
78 print("Username: %s" % self.username)
79 print("Password: %s" % ("None" if self.password == None else "set"))
80 print("Pod: %s" % self.pod)
81
82 def do_password(self, password):
83 """Set the password."""
84 self.password = (None if self.password == "" else password)
85 print("Password %s" % ("unset" if self.password == "" else "set"))
86
87 def do_save(self, line):
88 if self.username == None or self.pod == None:
89 print("Use the account command to set username and pod")
90 elif self.password == None:
91 print("Use the password command")
92 else:
93 rcfile = get_rcfile()
94 if rcfile == None:
95 rfile = first(_RC_PATHS)
96 seen_account = False
97 seen_password = False
98 seen_login = False
99 changed = False
100 file = []
101 with open(rcfile, "r") as fp:
102 for line in fp:
103 words = line.strip().split()
104 if words:
105 if words[0] == "account":
106 seen_account = True
107 account = "%s@%s" % (self.username, self.pod)
108 if len(words) > 1 and words[1] != account:
109 line = "account %s\n" % account
110 changed = True
111 elif words[0] == "password":
112 seen_password = True
113 if len(words) > 1 and words[1] != self.password:
114 line = "password %s\n" % self.password
115 changed = True
116 elif words[0] == "login":
117 if seen_account and seen_password:
118 seen_login = True
119 else:
120 # skip login if no account or no password given
121 line = None
122 changed = True
123 if line != None:
124 file.append(line)
125 if not seen_account:
126 file.append("account %s@%s\n" % (self.username, self.pod))
127 changed = True
128 if not seen_password:
129 file.append("password %s\n" % self.password)
130 changed = True
131 if not seen_login:
132 file.append("login\n")
133 changed = True
134 if changed:
135 if os.path.isfile(rcfile):
136 os.rename(rcfile, rcfile + "~")
137 if not os.path.isdir(os.path.dirname(rcfile)):
138 os.makedirs(os.path.dirname(rcfile))
139 with open(rcfile, "w") as fp:
140 fp.write("".join(file))
141 print("Wrote %s" % rcfile)
142 else:
143 print("No changes made, %s left unchanged" % rcfile)
144
145 def do_login(self, line):
146 """Login."""
147 if line != "":
148 self.onecmd("account %s" % line)
149 if self.username == None or self.pod == None:
150 print("Use the account command to set username and pod")
151 elif self.password == None:
152 print("Use the password command")
153 else:
154 self.connection = diaspy.connection.Connection(
155 pod = "https://%s" % self.pod, username = self.username, password = self.password)
156 try:
157 self.connection.login()
158 self.onecmd("notifications")
159 except diaspy.errors.LoginError:
160 print("Login failed")
161
162 def do_notifications(self, line):
163 """List notifications."""
164 if self.connection == None:
165 print("Use the login command, first.")
166 return
167 self.things = diaspy.notifications.Notifications(self.connection).last()
168 for n, notification in enumerate(self.things):
169 print("%2d. %s %s" % (n+1, notification.when(), notification))
170
171 ### The end!
172 def do_quit(self, *args):
173 """Exit jan-pona-mute."""
174 print("Be safe!")
175 sys.exit()
176
177 def default(self, line):
178 if line.strip() == "EOF":
179 return self.onecmd("quit")
180
181 # Expand abbreviated commands
182 first_word = line.split()[0].strip()
183 if first_word in _ABBREVS:
184 full_cmd = _ABBREVS[first_word]
185 expanded = line.replace(first_word, full_cmd, 1)
186 return self.onecmd(expanded)
187
188 # Try to parse numerical index for lookup table
189 try:
190 n = int(line.strip())
191 except ValueError:
192 print("Use the help command")
193 return
194
195 try:
196 item = self.things[n-1]
197 except IndexError:
198 print ("Index too high!")
199 return
200
201 self.index = n
202 self.show(item)
203
204 def show(self, item):
205 """Show the current item."""
206 print (str(item))
207
208 # Main function
209 def main():
210
211 # Parse args
212 parser = argparse.ArgumentParser(description='A command line Diaspora client.')
213 parser.add_argument('--no-init-file', dest='init_file', action='store_const',
214 const=False, default=True, help='Do not load a init file')
215 args = parser.parse_args()
216
217 # Instantiate client
218 c = DiasporaClient()
219
220 # Process init file
221 if args.init_file:
222 rcfile = get_rcfile()
223 if rcfile:
224 print("Using init file %s" % rcfile)
225 with open(rcfile, "r") as fp:
226 for line in fp:
227 line = line.strip()
228 c.cmdqueue.append(line)
229 else:
230 print("Use the save command to save your login sequence to an init file")
231
232 # Endless interpret loop
233 while True:
234 try:
235 c.cmdloop()
236 except KeyboardInterrupt:
237 print("")
238
239 if __name__ == '__main__':
240 main()