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