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