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