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