Save the text client!
[citadel.git] / textclient / routines2.c
1 // More client-side support functions.
2 //
3 // Copyright (c) 1987-2017 by the citadel.org team
4 //
5 // This program is open source software.  Use, duplication, and/or
6 // disclosure are subject to the GNU General Purpose License version 3.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
12
13 #include "textclient.h"
14
15 // work around solaris include files
16 #ifdef reg
17 #undef reg
18 #endif
19
20 extern char temp[];
21 extern char tempdir[];
22 extern char *axdefs[8];
23 extern long highest_msg_read;
24 extern long maxmsgnum;
25 extern unsigned room_flags;
26 extern int screenwidth;
27
28
29 // return proper room prompt character
30 int room_prompt(unsigned int qrflags) {
31         int a;
32         a = '>';
33         if (qrflags & QR_DIRECTORY) {
34                 a = ']';
35         }
36         return (a);
37 }
38
39
40 // Register with name and address
41 void entregis(CtdlIPC * ipc) {
42
43         char buf[SIZ];
44         char tmpname[30];
45         char tmpaddr[25];
46         char tmpcity[15];
47         char tmpstate[3];
48         char tmpzip[11];
49         char tmpphone[15];
50         char tmpemail[SIZ];
51         char tmpcountry[32];
52         char diruser[256];
53         char dirnode[256];
54         char holdemail[SIZ];
55         char *reg = NULL;
56         int ok = 0;
57         int r;                  /* IPC response code */
58
59         strcpy(tmpname, "");
60         strcpy(tmpaddr, "");
61         strcpy(tmpcity, "");
62         strcpy(tmpstate, "");
63         strcpy(tmpzip, "");
64         strcpy(tmpphone, "");
65         strcpy(tmpemail, "");
66         strcpy(tmpcountry, "");
67
68         r = CtdlIPCGetUserRegistration(ipc, NULL, &reg, buf);
69         if (r / 100 == 1) {
70                 int a = 0;
71
72                 while (reg && !IsEmptyStr(reg)) {
73
74                         extract_token(buf, reg, 0, '\n', sizeof buf);
75                         remove_token(reg, 0, '\n');
76
77                         if (a == 2)
78                                 safestrncpy(tmpname, buf, sizeof tmpname);
79                         else if (a == 3)
80                                 safestrncpy(tmpaddr, buf, sizeof tmpaddr);
81                         else if (a == 4)
82                                 safestrncpy(tmpcity, buf, sizeof tmpcity);
83                         else if (a == 5)
84                                 safestrncpy(tmpstate, buf, sizeof tmpstate);
85                         else if (a == 6)
86                                 safestrncpy(tmpzip, buf, sizeof tmpzip);
87                         else if (a == 7)
88                                 safestrncpy(tmpphone, buf, sizeof tmpphone);
89                         else if (a == 9)
90                                 safestrncpy(tmpemail, buf, sizeof tmpemail);
91                         else if (a == 10)
92                                 safestrncpy(tmpcountry, buf, sizeof tmpcountry);
93                         ++a;
94                 }
95         }
96         strprompt("REAL name", tmpname, 29);
97         strprompt("Address", tmpaddr, 24);
98         strprompt("City/town", tmpcity, 14);
99         strprompt("State/province", tmpstate, 2);
100         strprompt("ZIP/Postal Code", tmpzip, 10);
101         strprompt("Country", tmpcountry, 31);
102         strprompt("Telephone number", tmpphone, 14);
103
104         do {
105                 ok = 1;
106                 safestrncpy(holdemail, tmpemail, sizeof holdemail);
107                 strprompt("Email address", tmpemail, 31);
108                 r = CtdlIPCDirectoryLookup(ipc, tmpemail, buf);
109                 if (r / 100 == 2) {
110                         extract_token(diruser, buf, 0, '@', sizeof diruser);
111                         extract_token(dirnode, buf, 1, '@', sizeof dirnode);
112                         striplt(diruser);
113                         striplt(dirnode);
114                         if ((strcasecmp(diruser, fullname))
115                             || (strcasecmp(dirnode, ipc->ServInfo.nodename))) {
116                                 scr_printf("\nYou can't use %s as your address.\n", tmpemail);
117                                 scr_printf("It is already in use by %s @ %s.\n", diruser, dirnode);
118                                 ok = 0;
119                                 safestrncpy(tmpemail, holdemail, sizeof tmpemail);
120                         }
121                 }
122         } while (ok == 0);
123
124         /* now send the registration info back to the server */
125         reg = (char *) realloc(reg, SIZ);
126         if (reg) {
127                 sprintf(reg, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
128                         tmpname, tmpaddr, tmpcity, tmpstate, tmpzip, tmpphone, tmpemail, tmpcountry);
129                 r = CtdlIPCSetRegistration(ipc, reg, buf);
130                 if (r / 100 != 4)
131                         scr_printf("%s\n", buf);
132                 free(reg);
133         }
134         scr_printf("\n");
135 }
136
137 /*
138  * make all messages old in current room
139  */
140 void updatels(CtdlIPC * ipc)
141 {
142         char buf[256];
143         int r;                  /* IPC response code */
144
145         r = CtdlIPCSetLastRead(ipc, (maxmsgnum > highest_msg_read) ? maxmsgnum : highest_msg_read, buf);
146
147         if (r / 100 != 2)
148                 scr_printf("%s\n", buf);
149 }
150
151 /*
152  * only make messages old in this room that have been read
153  */
154 void updatelsa(CtdlIPC * ipc)
155 {
156         char buf[256];
157         int r;                  /* IPC response code */
158
159         r = CtdlIPCSetLastRead(ipc, highest_msg_read, buf);
160         if (r / 100 != 2)
161                 scr_printf("%s\n", &buf[4]);
162 }
163
164
165 /*
166  * client-based uploads (for users with their own clientware)
167  */
168 void cli_upload(CtdlIPC * ipc)
169 {
170         char flnm[PATH_MAX];
171         char desc[151];
172         char buf[256];
173         char tbuf[256];
174         int r;                  /* IPC response code */
175         int a;
176         int fd;
177
178         if ((room_flags & QR_UPLOAD) == 0) {
179                 scr_printf("*** You cannot upload to this room.\n");
180                 return;
181         }
182         newprompt("File to be uploaded: ", flnm, 55);
183         fd = open(flnm, O_RDONLY);
184         if (fd < 0) {
185                 scr_printf("Cannot open '%s': %s\n", flnm, strerror(errno));
186                 return;
187         }
188         scr_printf("Enter a description of this file:\n");
189         newprompt(": ", desc, 75);
190
191         /* Keep generating filenames in hope of finding a unique one */
192         a = 0;
193         while (a < 10) {
194                 /* basename of filename */
195                 strcpy(tbuf, flnm);
196                 if (haschar(tbuf, '/'))
197                         extract_token(tbuf, flnm, num_tokens(tbuf, '/') - 1, '/', sizeof tbuf);
198                 /* filename.1, filename.2, etc */
199                 if (a > 0) {
200                         sprintf(&tbuf[strlen(tbuf)], ".%d", a);
201                 }
202                 /* Try upload */
203                 r = CtdlIPCFileUpload(ipc, tbuf, desc, flnm, progress, buf);
204                 if (r / 100 == 5 || r < 0)
205                         scr_printf("%s\n", buf);
206                 else
207                         break;
208                 ++a;
209         }
210         if (a > 0)
211                 scr_printf("Saved as '%s'\n", tbuf);
212 }
213
214
215 /*
216  * Function used for various image upload commands
217  */
218 void cli_image_upload(CtdlIPC * ipc, char *keyname)
219 {
220         char flnm[PATH_MAX];
221         char buf[256];
222         int r;
223
224         /* Can we upload this image? */
225         r = CtdlIPCImageUpload(ipc, 0, NULL, keyname, NULL, buf);
226         if (r / 100 != 2) {
227                 scr_printf("%s\n", buf);
228                 return;
229         }
230         newprompt("Image file to be uploaded: ", flnm, 55);
231         r = CtdlIPCImageUpload(ipc, 1, flnm, keyname, progress, buf);
232         if (r / 100 == 5) {
233                 scr_printf("%s\n", buf);
234         }
235         else if (r < 0) {
236                 scr_printf("Cannot upload '%s': %s\n", flnm, strerror(errno));
237         }
238         /* else upload succeeded */
239 }
240
241
242 /*
243  * protocol-based uploads (Xmodem, Ymodem, Zmodem)
244  */
245 void upload(CtdlIPC * ipc, int c)
246 {                               /* c = upload mode */
247         char flnm[PATH_MAX];
248         char desc[151];
249         char buf[256];
250         char tbuf[4096];
251         int xfer_pid;
252         int a, b;
253         FILE *fp, *lsfp;
254         int rv;
255
256         if ((room_flags & QR_UPLOAD) == 0) {
257                 scr_printf("*** You cannot upload to this room.\n");
258                 return;
259         }
260         /* we don't need a filename when receiving batch y/z modem */
261         if ((c == 2) || (c == 3))
262                 strcpy(flnm, "x");
263         else
264                 newprompt("Enter filename: ", flnm, 15);
265
266         for (a = 0; !IsEmptyStr(&flnm[a]); ++a)
267                 if ((flnm[a] == '/') || (flnm[a] == '\\') || (flnm[a] == '>')
268                     || (flnm[a] == '?') || (flnm[a] == '*')
269                     || (flnm[a] == ';') || (flnm[a] == '&'))
270                         flnm[a] = '_';
271
272         /* create a temporary directory... */
273         if (mkdir(tempdir, 0700) != 0) {
274                 scr_printf("*** Could not create temporary directory %s: %s\n", tempdir, strerror(errno));
275                 return;
276         }
277         /* now do the transfer ... in a separate process */
278         xfer_pid = fork();
279         if (xfer_pid == 0) {
280                 rv = chdir(tempdir);
281                 if (rv < 0) {
282                         scr_printf("failed to change into %s Reason %s\nAborting now.\n", tempdir, strerror(errno));
283                         nukedir(tempdir);
284                         return;
285                 }
286                 switch (c) {
287                 case 0:
288                         stty_ctdl(0);
289                         scr_printf("Receiving %s - press Ctrl-D to end.\n", flnm);
290                         fp = fopen(flnm, "w");
291                         do {
292                                 b = inkey();
293                                 if (b == 13) {
294                                         b = 10;
295                                 }
296                                 if (b != 4) {
297                                         scr_printf("%c", b);
298                                         putc(b, fp);
299                                 }
300                         } while (b != 4);
301                         fclose(fp);
302                         exit(0);
303                 case 1:
304                         stty_ctdl(3);
305                         execlp("rx", "rx", flnm, NULL);
306                         exit(1);
307                 case 2:
308                         stty_ctdl(3);
309                         execlp("rb", "rb", NULL);
310                         exit(1);
311                 case 3:
312                         stty_ctdl(3);
313                         execlp("rz", "rz", NULL);
314                         exit(1);
315                 }
316         }
317         else do {
318                 b = ka_wait(&a);
319         } while ((b != xfer_pid) && (b != (-1)));
320         stty_ctdl(0);
321
322         if (a != 0) {
323                 scr_printf("\r*** Transfer unsuccessful.\n");
324                 nukedir(tempdir);
325                 return;
326         }
327         scr_printf("\r*** Transfer successful.\n");
328         snprintf(buf, sizeof buf, "cd %s; ls", tempdir);
329         lsfp = popen(buf, "r");
330         if (lsfp != NULL) {
331                 while (fgets(flnm, sizeof flnm, lsfp) != NULL) {
332                         flnm[strlen(flnm) - 1] = 0;     /* chop newline */
333                         snprintf(buf, sizeof buf, "Enter a short description of '%s':\n: ", flnm);
334                         newprompt(buf, desc, 150);
335                         snprintf(buf, sizeof buf, "%s/%s", tempdir, flnm);
336                         CtdlIPCFileUpload(ipc, flnm, desc, buf, progress, tbuf);
337                         scr_printf("%s\n", tbuf);
338                 }
339                 pclose(lsfp);
340         }
341         nukedir(tempdir);
342 }
343
344
345 /* 
346  * validate a user (returns 0 for successful validation, nonzero if quitting)
347  */
348 int val_user(CtdlIPC * ipc, char *user, int do_validate)
349 {
350         int a;
351         char cmd[256];
352         char buf[256];
353         char *resp = NULL;
354         int ax = 0;
355         char answer[2];
356         int r;                  /* IPC response code */
357
358         scr_printf("\n");
359         r = CtdlIPCGetUserRegistration(ipc, user, &resp, cmd);
360         if (r / 100 == 1) {
361                 a = 0;
362                 do {
363                         extract_token(buf, resp, 0, '\n', sizeof buf);
364                         remove_token(resp, 0, '\n');
365                         ++a;
366                         if (a == 1)
367                                 scr_printf("User #%s - %s  ", buf, cmd);
368                         if (a == 2)
369                                 scr_printf("PW: %s\n", (IsEmptyStr(buf) ? "<NOT SET>" : "<SET>"));
370                         if (a == 3)
371                                 scr_printf("%s\n", buf);
372                         if (a == 4)
373                                 scr_printf("%s\n", buf);
374                         if (a == 5)
375                                 scr_printf("%s, ", buf);
376                         if (a == 6)
377                                 scr_printf("%s ", buf);
378                         if (a == 7)
379                                 scr_printf("%s\n", buf);
380                         if (a == 8)
381                                 scr_printf("%s\n", buf);
382                         if (a == 9)
383                                 ax = atoi(buf);
384                         if (a == 10)
385                                 scr_printf("%s\n", buf);
386                         if (a == 11)
387                                 scr_printf("%s\n", buf);
388                 } while (!IsEmptyStr(resp));
389
390 /* TODODRW: discrepancy here. Parts of the code refer to axdefs[7] as the highest
391  * but most of it limits it to axdefs[6].
392  * Webcit limits to 6 as does the code here but there are 7 in axdefs.h
393  */
394                 scr_printf("Current access level: %d (%s)\n", ax, axdefs[ax]);
395         } else {
396                 scr_printf("%s\n%s\n", user, &cmd[4]);
397         }
398         if (resp)
399                 free(resp);
400
401         if (do_validate) {
402                 /* now set the access level */
403                 while (1) {
404                         sprintf(answer, "%d", ax);
405                         strprompt("New access level (? for help, q to quit)", answer, 1);
406                         if ((answer[0] >= '0') && (answer[0] <= '6')) {
407                                 ax = atoi(answer);
408                                 r = CtdlIPCValidateUser(ipc, user, ax, cmd);
409                                 if (r / 100 != 2)
410                                         scr_printf("%s\n\n", cmd);
411                                 return (0);
412                         }
413                         if (tolower(answer[0]) == 'q') {
414                                 scr_printf("*** Aborted.\n\n");
415                                 return (1);
416                         }
417                         if (answer[0] == '?') {
418                                 scr_printf("Available access levels:\n");
419                                 for (a = 0; a < 7; ++a) {
420                                         scr_printf("%d - %s\n", a, axdefs[a]);
421                                 }
422                         }
423                 }
424         }
425         return (0);
426 }
427
428
429 /*
430  * Validate new users
431  */
432 void validate(CtdlIPC * ipc)
433 {
434         char cmd[256];
435         char buf[256];
436         int finished = 0;
437         int r;                  /* IPC response code */
438
439         do {
440                 r = CtdlIPCNextUnvalidatedUser(ipc, cmd);
441                 if (r / 100 != 3)
442                         finished = 1;
443                 if (r / 100 == 2)
444                         scr_printf("%s\n", cmd);
445                 if (r / 100 == 3) {
446                         extract_token(buf, cmd, 0, '|', sizeof buf);
447                         if (val_user(ipc, buf, 1) != 0)
448                                 finished = 1;
449                 }
450         } while (finished == 0);
451 }
452
453
454 void subshell(void)
455 {
456         int a, b;
457
458         stty_ctdl(SB_RESTORE);
459         a = fork();
460         if (a == 0) {
461                 signal(SIGINT, SIG_DFL);
462                 signal(SIGQUIT, SIG_DFL);
463                 execlp(getenv("SHELL"), getenv("SHELL"), NULL);
464                 scr_printf("Could not open a shell: %s\n", strerror(errno));
465                 exit(errno);
466         }
467         do {
468                 b = ka_wait(NULL);
469         } while ((a != b) && (a != (-1)));
470         stty_ctdl(0);
471 }
472
473 /*
474  * <.A>ide <F>ile <D>elete command
475  */
476 void deletefile(CtdlIPC * ipc)
477 {
478         char filename[32];
479         char buf[256];
480
481         newprompt("Filename: ", filename, 31);
482         if (IsEmptyStr(filename))
483                 return;
484         CtdlIPCDeleteFile(ipc, filename, buf);
485         scr_printf("%s\n", buf);
486 }
487
488
489 /*
490  * <.A>ide <F>ile <M>ove command
491  */
492 void movefile(CtdlIPC * ipc)
493 {
494         char filename[64];
495         char newroom[ROOMNAMELEN];
496         char buf[256];
497
498         newprompt("Filename: ", filename, 63);
499         if (IsEmptyStr(filename))
500                 return;
501         newprompt("Enter target room: ", newroom, ROOMNAMELEN - 1);
502         CtdlIPCMoveFile(ipc, filename, newroom, buf);
503         scr_printf("%s\n", buf);
504 }
505
506
507 /* 
508  * list of users who have filled out a bio
509  */
510 void list_bio(CtdlIPC * ipc)
511 {
512         char buf[256];
513         char *resp = NULL;
514         int pos = 1;
515         int r;                  /* IPC response code */
516
517         r = CtdlIPCListUsersWithBios(ipc, &resp, buf);
518         if (r / 100 != 1) {
519                 scr_printf("%s\n", buf);
520                 return;
521         }
522         while (resp && !IsEmptyStr(resp)) {
523                 extract_token(buf, resp, 0, '\n', sizeof buf);
524                 remove_token(resp, 0, '\n');
525                 if ((pos + strlen(buf) + 5) > screenwidth) {
526                         scr_printf("\n");
527                         pos = 1;
528                 }
529                 scr_printf("%s, ", buf);
530                 pos = pos + strlen(buf) + 2;
531         }
532         scr_printf("%c%c  \n\n", 8, 8);
533         if (resp)
534                 free(resp);
535 }
536
537
538 // read bio
539 void read_bio(CtdlIPC * ipc) {
540         char who[256];
541         char buf[256];
542         char *resp = NULL;
543         int r;                  /* IPC response code */
544
545         do {
546                 newprompt("Read bio for who ('?' for list) : ", who, 25);
547                 scr_printf("\n");
548                 if (!strcmp(who, "?"))
549                         list_bio(ipc);
550         } while (!strcmp(who, "?"));
551
552         r = CtdlIPCGetBio(ipc, who, &resp, buf);
553         if (r / 100 != 1) {
554                 scr_printf("%s\n", buf);
555                 return;
556         }
557         while (!IsEmptyStr(resp)) {
558                 extract_token(buf, resp, 0, '\n', sizeof buf);
559                 remove_token(resp, 0, '\n');
560                 scr_printf("%s\n", buf);
561         }
562         if (resp)
563                 free(resp);
564 }