]> code.citadel.org Git - citadel.git/blob - citadel/routines2.c
* Full-screen curses support for Citadel text client
[citadel.git] / citadel / routines2.c
1 /* $Id$
2  *
3  * More client-side support functions.
4  * Unlike routines.c, some of these DO use global variables.
5  *
6  */
7
8 #include "sysdep.h"
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <stdio.h>
15 #include <ctype.h>
16 #include <string.h>
17 #include <limits.h>
18
19 #if TIME_WITH_SYS_TIME
20 # include <sys/time.h>
21 # include <time.h>
22 #else
23 # if HAVE_SYS_TIME_H
24 #  include <sys/time.h>
25 # else
26 #  include <time.h>
27 # endif
28 #endif
29
30 #include <signal.h>
31 #include <pwd.h>
32 #include <setjmp.h>
33 #include <errno.h>
34 #include <stdarg.h>
35 #include "citadel.h"
36 #include "citadel_decls.h"
37 #include "routines2.h"
38 #include "routines.h"
39 #include "commands.h"
40 #include "tools.h"
41 #include "messages.h"
42 #ifndef HAVE_SNPRINTF
43 #include "snprintf.h"
44 #endif
45 #include "screen.h"
46
47 void interr(int errnum);
48 void strprompt(char *prompt, char *str, int len);
49 void newprompt(char *prompt, char *str, int len);
50 void sttybbs(int cmd);
51 int inkey(void);
52 void serv_write(char *buf, int nbytes);
53 int haschar(char *st, int ch);
54 void progress(long int curr, long int cmax);
55 int yesno(void);
56
57 extern char temp[];
58 extern char tempdir[];
59 extern char *axdefs[7];
60 extern long highest_msg_read;
61 extern long maxmsgnum;
62 extern unsigned room_flags;
63 extern int screenwidth;
64
65
66 int eopen(char *name, int mode)
67 {
68         int ret;
69         ret = open(name, mode);
70         if (ret < 0) {
71                 err_printf("Cannot open file '%s', mode=%d, errno=%d\n",
72                         name, mode, errno);
73                 interr(errno);
74         }
75         return (ret);
76 }
77
78
79 int room_prompt(int qrflags)
80 {                               /* return proper room prompt character */
81         int a;
82         a = '>';
83         if (qrflags & QR_DIRECTORY)
84                 a = ']';
85         if ((a == ']') && (qrflags & QR_NETWORK))
86                 a = '}';
87         if ((a == '>') && (qrflags & QR_NETWORK))
88                 a = ')';
89         return (a);
90 }
91
92 void entregis(void)
93 {                               /* register with name and address */
94
95         char buf[SIZ];
96         char tmpname[SIZ];
97         char tmpaddr[SIZ];
98         char tmpcity[SIZ];
99         char tmpstate[SIZ];
100         char tmpzip[SIZ];
101         char tmpphone[SIZ];
102         char tmpemail[SIZ];
103         char tmpcountry[SIZ];
104         int a;
105
106         strcpy(tmpname, "");
107         strcpy(tmpaddr, "");
108         strcpy(tmpcity, "");
109         strcpy(tmpstate, "");
110         strcpy(tmpzip, "");
111         strcpy(tmpphone, "");
112         strcpy(tmpemail, "");
113         strcpy(tmpcountry, "");
114
115         serv_puts("GREG _SELF_");
116         serv_gets(buf);
117         if (buf[0] == '1') {
118                 a = 0;
119                 while (serv_gets(buf), strcmp(buf, "000")) {
120                         if (a == 2)
121                                 strcpy(tmpname, buf);
122                         if (a == 3)
123                                 strcpy(tmpaddr, buf);
124                         if (a == 4)
125                                 strcpy(tmpcity, buf);
126                         if (a == 5)
127                                 strcpy(tmpstate, buf);
128                         if (a == 6)
129                                 strcpy(tmpzip, buf);
130                         if (a == 7)
131                                 strcpy(tmpphone, buf);
132                         if (a == 9)
133                                 strcpy(tmpemail, buf);
134                         if (a == 10)
135                                 strcpy(tmpcountry, buf);
136                         ++a;
137                 }
138         }
139         strprompt("REAL name", tmpname, 29);
140         strprompt("Address", tmpaddr, 24);
141         strprompt("City/town", tmpcity, 14);
142         strprompt("State/province", tmpstate, 2);
143         strprompt("ZIP/Postal Code", tmpzip, 10);
144         strprompt("Country", tmpcountry, 31);
145         strprompt("Telephone number", tmpphone, 14);
146         strprompt("Email address", tmpemail, 31);
147
148         /* now send the registration info back to the server */
149         serv_puts("REGI");
150         serv_gets(buf);
151         if (buf[0] != '4') {
152                 scr_printf("%s\n", &buf[4]);
153                 return;
154         }
155         serv_puts(tmpname);
156         serv_puts(tmpaddr);
157         serv_puts(tmpcity);
158         serv_puts(tmpstate);
159         serv_puts(tmpzip);
160         serv_puts(tmpphone);
161         serv_puts(tmpemail);
162         serv_puts(tmpcountry);
163         serv_puts("000");
164         scr_printf("\n");
165 }
166
167 void updatels(void)
168 {                               /* make all messages old in current room */
169         char buf[SIZ];
170
171         if (rc_alt_semantics) {
172                 if (maxmsgnum == highest_msg_read == 0) {
173                         /* err_printf("maxmsgnum == highest_msg_read == 0\n"); */
174                         return;
175                 }
176                 snprintf(buf, sizeof(buf), "SLRP %ld",
177                                 (maxmsgnum > highest_msg_read) ?
178                                  maxmsgnum : highest_msg_read);
179                 serv_puts(buf);
180         } else {
181                 serv_puts("SLRP HIGHEST");
182         }
183         serv_gets(buf);
184         if (buf[0] != '2')
185                 scr_printf("%s\n", &buf[4]);
186 }
187
188 /*
189  * only make messages old in this room that have been read
190  */
191 void updatelsa(void)
192 {
193         char buf[SIZ];
194
195         sprintf(buf, "SLRP %ld", highest_msg_read);
196         serv_puts(buf);
197         serv_gets(buf);
198         if (buf[0] != '2')
199                 scr_printf("%s\n", &buf[4]);
200 }
201
202
203 /*
204  * This routine completes a client upload
205  */
206 void do_upload(int fd)
207 {
208         char buf[SIZ];
209         char tbuf[4096];
210         long transmitted_bytes, total_bytes;
211         int bytes_to_send;
212         int bytes_expected;
213
214         /* learn the size of the file */
215         total_bytes = lseek(fd, 0L, 2);
216         lseek(fd, 0L, 0);
217
218         transmitted_bytes = 0L;
219         progress(transmitted_bytes, total_bytes);
220         do {
221                 bytes_to_send = read(fd, tbuf, 4096);
222                 if (bytes_to_send > 0) {
223                         sprintf(buf, "WRIT %d", bytes_to_send);
224                         serv_puts(buf);
225                         serv_gets(buf);
226                         if (buf[0] == '7') {
227                                 bytes_expected = atoi(&buf[4]);
228                                 serv_write(tbuf, bytes_expected);
229                         } else {
230                                 scr_printf("%s\n", &buf[4]);
231                         }
232                 }
233                 transmitted_bytes = transmitted_bytes + (long) bytes_to_send;
234                 progress(transmitted_bytes, total_bytes);
235         } while (bytes_to_send > 0);
236
237         /* close the upload file, locally and at the server */
238         close(fd);
239         serv_puts("UCLS 1");
240         serv_gets(buf);
241         scr_printf("%s\n", &buf[4]);
242 }
243
244
245 /*
246  * client-based uploads (for users with their own clientware)
247  */
248 void cli_upload(void)
249 {
250         char flnm[SIZ];
251         char desc[151];
252         char buf[SIZ];
253         char tbuf[SIZ];
254         int a;
255         int fd;
256
257         if ((room_flags & QR_UPLOAD) == 0) {
258                 scr_printf("*** You cannot upload to this room.\n");
259                 return;
260         }
261         newprompt("File to be uploaded: ", flnm, 55);
262         fd = open(flnm, O_RDONLY);
263         if (fd < 0) {
264                 scr_printf("Cannot open '%s': %s\n", flnm, strerror(errno));
265                 return;
266         }
267         scr_printf("Enter a description of this file:\n");
268         newprompt(": ", desc, 75);
269
270         /* keep generating filenames in hope of finding a unique one */
271         a = 0;
272         do {
273                 if (a == 10)
274                         return; /* fail if tried 10 times */
275                 strcpy(buf, flnm);
276                 while ((strlen(buf) > 0) && (haschar(buf, '/')))
277                         strcpy(buf, &buf[1]);
278                 if (a > 0)
279                         sprintf(&buf[strlen(buf)], "%d", a);
280                 sprintf(tbuf, "UOPN %s|%s", buf, desc);
281                 serv_puts(tbuf);
282                 serv_gets(buf);
283                 if (buf[0] != '2')
284                         scr_printf("%s\n", &buf[4]);
285                 ++a;
286         } while (buf[0] != '2');
287
288         /* at this point we have an open upload file at the server */
289         do_upload(fd);
290 }
291
292
293 /*
294  * Function used for various image upload commands
295  */
296 void cli_image_upload(char *keyname)
297 {
298         char flnm[SIZ];
299         char buf[SIZ];
300         int fd;
301
302         sprintf(buf, "UIMG 0|%s", keyname);
303         serv_puts(buf);
304         serv_gets(buf);
305         if (buf[0] != '2') {
306                 scr_printf("%s\n", &buf[4]);
307                 return;
308         }
309         newprompt("Image file to be uploaded: ", flnm, 55);
310         fd = open(flnm, O_RDONLY);
311         if (fd < 0) {
312                 scr_printf("Cannot open '%s': %s\n", flnm, strerror(errno));
313                 return;
314         }
315         sprintf(buf, "UIMG 1|%s", keyname);
316         serv_puts(buf);
317         serv_gets(buf);
318         if (buf[0] != '2') {
319                 scr_printf("%s\n", &buf[4]);
320                 return;
321         }
322         do_upload(fd);
323 }
324
325
326 /*
327  * protocol-based uploads (Xmodem, Ymodem, Zmodem)
328  */
329 void upload(int c)
330 {                               /* c = upload mode */
331         char flnm[SIZ];
332         char desc[151];
333         char buf[SIZ];
334         char tbuf[4096];
335         int xfer_pid;
336         int a, b;
337         FILE *fp, *lsfp;
338         int fd;
339
340         if ((room_flags & QR_UPLOAD) == 0) {
341                 scr_printf("*** You cannot upload to this room.\n");
342                 return;
343         }
344         /* we don't need a filename when receiving batch y/z modem */
345         if ((c == 2) || (c == 3))
346                 strcpy(flnm, "x");
347         else
348                 newprompt("Enter filename: ", flnm, 15);
349
350         for (a = 0; a < strlen(flnm); ++a)
351                 if ((flnm[a] == '/') || (flnm[a] == '\\') || (flnm[a] == '>')
352                     || (flnm[a] == '?') || (flnm[a] == '*')
353                     || (flnm[a] == ';') || (flnm[a] == '&'))
354                         flnm[a] = '_';
355
356         newprompt("Enter a short description of the file:\n: ", desc, 150);
357
358         /* create a temporary directory... */
359         if (mkdir(tempdir, 0700) != 0) {
360                 scr_printf("*** Could not create temporary directory %s: %s\n",
361                        tempdir, strerror(errno));
362                 return;
363         }
364         /* now do the transfer ... in a separate process */
365         xfer_pid = fork();
366         if (xfer_pid == 0) {
367                 chdir(tempdir);
368                 switch (c) {
369                 case 0:
370                         sttybbs(0);
371                         scr_printf("Receiving %s - press Ctrl-D to end.\n", flnm);
372                         fp = fopen(flnm, "w");
373                         do {
374                                 b = inkey();
375                                 if (b == 13) {
376                                         b = 10;
377                                 }
378                                 if (b != 4) {
379                                         scr_printf("%c", b);
380                                         putc(b, fp);
381                                 }
382                         } while (b != 4);
383                         fclose(fp);
384                         exit(0);
385                 case 1:
386                         screen_reset();
387                         sttybbs(3);
388                         execlp("rx", "rx", flnm, NULL);
389                         exit(1);
390                 case 2:
391                         screen_reset();
392                         sttybbs(3);
393                         execlp("rb", "rb", NULL);
394                         exit(1);
395                 case 3:
396                         screen_reset();
397                         sttybbs(3);
398                         execlp("rz", "rz", NULL);
399                         exit(1);
400                 }
401         } else
402                 do {
403                         b = ka_wait(&a);
404                 } while ((b != xfer_pid) && (b != (-1)));
405         sttybbs(0);
406         screen_set();
407
408         if (a != 0) {
409                 scr_printf("\r*** Transfer unsuccessful.\n");
410                 nukedir(tempdir);
411                 return;
412         }
413         scr_printf("\r*** Transfer successful.  Sending file(s) to server...\n");
414         sprintf(buf, "cd %s; ls", tempdir);
415         lsfp = popen(buf, "r");
416         if (lsfp != NULL) {
417                 while (fgets(flnm, sizeof flnm, lsfp) != NULL) {
418                         flnm[strlen(flnm) - 1] = 0;
419                         sprintf(buf, "%s/%s", tempdir, flnm);
420                         fd = open(buf, O_RDONLY);
421                         if (fd >= 0) {
422                                 a = 0;
423                                 do {
424                                         sprintf(buf, "UOPN %s|%s", flnm, desc);
425                                         if (a > 0)
426                                                 sprintf(&buf[strlen(buf)],
427                                                         ".%d", a);
428                                         ++a;
429                                         serv_puts(buf);
430                                         serv_gets(buf);
431                                 } while ((buf[0] != '2') && (a < 100));
432                                 if (buf[0] == '2')
433                                         do {
434                                                 a = read(fd, tbuf, 4096);
435                                                 if (a > 0) {
436                                                         sprintf(buf, "WRIT %d", a);
437                                                         serv_puts(buf);
438                                                         serv_gets(buf);
439                                                         if (buf[0] == '7')
440                                                                 serv_write(tbuf, a);
441                                                 }
442                                         } while (a > 0);
443                                 close(fd);
444                                 serv_puts("UCLS 1");
445                                 serv_gets(buf);
446                                 scr_printf("%s\n", &buf[4]);
447                         }
448                 }
449                 pclose(lsfp);
450         }
451         nukedir(tempdir);
452 }
453
454 /* 
455  * validate a user
456  */
457 void val_user(char *user, int do_validate)
458 {
459         int a;
460         char cmd[SIZ];
461         char buf[SIZ];
462         int ax = 0;
463
464         sprintf(cmd, "GREG %s", user);
465         serv_puts(cmd);
466         serv_gets(cmd);
467         if (cmd[0] == '1') {
468                 a = 0;
469                 do {
470                         serv_gets(buf);
471                         ++a;
472                         if (a == 1)
473                                 scr_printf("User #%s - %s  ", buf, &cmd[4]);
474                         if (a == 2)
475                                 scr_printf("PW: %s\n", buf);
476                         if (a == 3)
477                                 scr_printf("%s\n", buf);
478                         if (a == 4)
479                                 scr_printf("%s\n", buf);
480                         if (a == 5)
481                                 scr_printf("%s, ", buf);
482                         if (a == 6)
483                                 scr_printf("%s ", buf);
484                         if (a == 7)
485                                 scr_printf("%s\n", buf);
486                         if (a == 8)
487                                 scr_printf("%s\n", buf);
488                         if (a == 9)
489                                 ax = atoi(buf);
490                         if (a == 10)
491                                 scr_printf("%s\n", buf);
492                         if (a == 11)
493                                 scr_printf("%s\n", buf);
494                 } while (strcmp(buf, "000"));
495                 scr_printf("Current access level: %d (%s)\n", ax, axdefs[ax]);
496         } else {
497                 scr_printf("%-30s\n%s\n", user, &cmd[4]);
498         }
499
500         if (do_validate) {
501                 /* now set the access level */
502                 ax = intprompt("Access level", ax, 0, 6);
503                 sprintf(cmd, "VALI %s|%d", user, ax);
504                 serv_puts(cmd);
505                 serv_gets(cmd);
506                 if (cmd[0] != '2')
507                         scr_printf("%s\n", &cmd[4]);
508         }
509         scr_printf("\n");
510 }
511
512
513 void validate(void)
514 {                               /* validate new users */
515         char cmd[SIZ];
516         char buf[SIZ];
517         int finished = 0;
518
519         do {
520                 serv_puts("GNUR");
521                 serv_gets(cmd);
522                 if (cmd[0] != '3')
523                         finished = 1;
524                 if (cmd[0] == '2')
525                         scr_printf("%s\n", &cmd[4]);
526                 if (cmd[0] == '3') {
527                         extract(buf, cmd, 0);
528                         val_user(&buf[4], 1);
529                 }
530         } while (finished == 0);
531 }
532
533 void subshell(void)
534 {
535         int a, b;
536         a = fork();
537         if (a == 0) {
538                 screen_reset();
539                 sttybbs(SB_RESTORE);
540                 signal(SIGINT, SIG_DFL);
541                 signal(SIGQUIT, SIG_DFL);
542                 execlp(getenv("SHELL"), getenv("SHELL"), NULL);
543                 err_printf("Could not open a shell: %s\n", strerror(errno));
544                 exit(errno);
545         }
546         do {
547                 b = ka_wait(NULL);
548         } while ((a != b) && (a != (-1)));
549         sttybbs(0);
550         screen_set();
551 }
552
553 /*
554  * <.A>ide <F>ile <D>elete command
555  */
556 void deletefile(void)
557 {
558         char filename[32];
559         char cmd[SIZ];
560
561         newprompt("Filename: ", filename, 31);
562         if (strlen(filename) == 0)
563                 return;
564         sprintf(cmd, "DELF %s", filename);
565         serv_puts(cmd);
566         serv_gets(cmd);
567         err_printf("%s\n", &cmd[4]);
568 }
569
570 /*
571  * <.A>ide <F>ile <S>end command
572  */
573 void netsendfile(void)
574 {
575         char filename[32], destsys[20], cmd[SIZ];
576
577         newprompt("Filename: ", filename, 31);
578         if (strlen(filename) == 0)
579                 return;
580         newprompt("System to send to: ", destsys, 19);
581         sprintf(cmd, "NETF %s|%s", filename, destsys);
582         serv_puts(cmd);
583         serv_gets(cmd);
584         err_printf("%s\n", &cmd[4]);
585         return;
586 }
587
588 /*
589  * <.A>ide <F>ile <M>ove command
590  */
591 void movefile(void)
592 {
593         char filename[64];
594         char newroom[ROOMNAMELEN];
595         char cmd[SIZ];
596
597         newprompt("Filename: ", filename, 63);
598         if (strlen(filename) == 0)
599                 return;
600         newprompt("Enter target room: ", newroom, ROOMNAMELEN - 1);
601
602         sprintf(cmd, "MOVF %s|%s", filename, newroom);
603         serv_puts(cmd);
604         serv_gets(cmd);
605         err_printf("%s\n", &cmd[4]);
606 }
607
608
609 /* 
610  * list of users who have filled out a bio
611  */
612 void list_bio(void)
613 {
614         char buf[SIZ];
615         int pos = 1;
616
617         serv_puts("LBIO");
618         serv_gets(buf);
619         if (buf[0] != '1') {
620                 pprintf("%s\n", &buf[4]);
621                 return;
622         }
623         while (serv_gets(buf), strcmp(buf, "000")) {
624                 if ((pos + strlen(buf) + 5) > screenwidth) {
625                         pprintf("\n");
626                         pos = 1;
627                 }
628                 pprintf("%s, ", buf);
629                 pos = pos + strlen(buf) + 2;
630         }
631         pprintf("%c%c  \n\n", 8, 8);
632 }
633
634
635 /*
636  * read bio
637  */
638 void read_bio(void)
639 {
640         char who[SIZ];
641         char buf[SIZ];
642
643         do {
644                 newprompt("Read bio for who ('?' for list) : ", who, 25);
645                 pprintf("\n");
646                 if (!strcmp(who, "?"))
647                         list_bio();
648         } while (!strcmp(who, "?"));
649         sprintf(buf, "RBIO %s", who);
650         serv_puts(buf);
651         serv_gets(buf);
652         if (buf[0] != '1') {
653                 pprintf("%s\n", &buf[4]);
654                 return;
655         }
656         while (serv_gets(buf), strcmp(buf, "000")) {
657                 pprintf("%s\n", buf);
658         }
659 }
660
661
662 /* 
663  * General system configuration command
664  */
665 void do_system_configuration(void)
666 {
667         char buf[SIZ];
668         char sc[29][SIZ];
669         int expire_mode = 0;
670         int expire_value = 0;
671         int a;
672         int logpages = 0;
673
674         /* Clear out the config buffers */
675         memset(&sc[0][0], 0, sizeof(sc));
676
677         /* Fetch the current config */
678         serv_puts("CONF get");
679         serv_gets(buf);
680         if (buf[0] == '1') {
681                 a = 0;
682                 while (serv_gets(buf), strcmp(buf, "000")) {
683                         if (a < 29) {
684                                 strcpy(&sc[a][0], buf);
685                         }
686                         ++a;
687                 }
688         }
689         /* Fetch the expire policy (this will silently fail on old servers,
690          * resulting in "default" policy)
691          */
692         serv_puts("GPEX site");
693         serv_gets(buf);
694         if (buf[0] == '2') {
695                 expire_mode = extract_int(&buf[4], 0);
696                 expire_value = extract_int(&buf[4], 1);
697         }
698
699
700         /* Identification parameters */
701
702         strprompt("Node name", &sc[0][0], 15);
703         strprompt("Fully qualified domain name", &sc[1][0], 63);
704         strprompt("Human readable node name", &sc[2][0], 20);
705         strprompt("Modem dialup number", &sc[3][0], 15);
706         strprompt("Geographic location of this system", &sc[12][0], 31);
707         strprompt("Name of system administrator", &sc[13][0], 25);
708         strprompt("Paginator prompt", &sc[10][0], 79);
709
710         /* this prompt is commented out until we finish the moderation system
711         strprompt("Default moderation filter for new users", &sc[25][0], 4);
712         */
713
714         /* Security parameters */
715
716         sprintf(&sc[7][0], "%d", (boolprompt(
717                                     "Require registration for new users",
718                                                     atoi(&sc[7][0]))));
719         strprompt("Initial access level for new users", &sc[6][0], 1);
720         strprompt("Access level required to create rooms", &sc[19][0], 1);
721         sprintf(&sc[4][0], "%d", (boolprompt(
722                                                     "Automatically give room aide privs to a user who creates a private room",
723                                                     atoi(&sc[4][0]))));
724
725         sprintf(&sc[8][0], "%d", (boolprompt(
726                  "Automatically move problem user messages to twit room",
727                                                     atoi(&sc[8][0]))));
728
729         strprompt("Name of twit room", &sc[9][0], ROOMNAMELEN);
730         sprintf(&sc[11][0], "%d", (boolprompt(
731               "Restrict Internet mail to only those with that privilege",
732                                                      atoi(&sc[11][0]))));
733         sprintf(&sc[26][0], "%d", (boolprompt(
734               "Allow Aides to Zap (forget) rooms",
735                                                      atoi(&sc[26][0]))));
736
737         if (strlen(&sc[18][0]) > 0) logpages = 1;
738         else logpages = 0;
739         logpages = boolprompt("Log all pages", logpages);
740         if (logpages) {
741                 strprompt("Name of logging room", &sc[18][0], ROOMNAMELEN);
742         }
743         else {
744                 sc[18][0] = 0;
745         }
746
747
748         /* Server tuning */
749
750         strprompt("Server connection idle timeout (in seconds)", &sc[5][0], 4);
751         strprompt("Maximum concurrent sessions", &sc[14][0], 4);
752         strprompt("Maximum message length", &sc[20][0], 20);
753         strprompt("Minimum number of worker threads", &sc[21][0], 3);
754         strprompt("Maximum number of worker threads", &sc[22][0], 3);
755
756         /* no longer applicable ... deprecated
757         strprompt("Server-to-server networking password", &sc[15][0], 19);
758         */
759
760         strprompt("How often to run network jobs (in seconds)", &sc[28][0], 5);
761         strprompt("SMTP server port (-1 to disable)", &sc[24][0], 5);
762         strprompt("POP3 server port (-1 to disable)", &sc[23][0], 5);
763         strprompt("IMAP server port (-1 to disable)", &sc[27][0], 5);
764
765         /* Expiry settings */
766         strprompt("Default user purge time (days)", &sc[16][0], 5);
767         strprompt("Default room purge time (days)", &sc[17][0], 5);
768
769         /* Angels and demons dancing in my head... */
770         do {
771                 sprintf(buf, "%d", expire_mode);
772                 strprompt("System default message expire policy (? for list)",
773                           buf, 1);
774                 if (buf[0] == '?') {
775                         scr_printf("\n"
776                                 "1. Never automatically expire messages\n"
777                                 "2. Expire by message count\n"
778                                 "3. Expire by message age\n");
779                 }
780         } while ((buf[0] < 49) || (buf[0] > 51));
781         expire_mode = buf[0] - 48;
782
783         /* ...lunatics and monsters underneath my bed */
784         if (expire_mode == 2) {
785                 sprintf(buf, "%d", expire_value);
786                 strprompt("Keep how many messages online?", buf, 10);
787                 expire_value = atol(buf);
788         }
789         if (expire_mode == 3) {
790                 sprintf(buf, "%d", expire_value);
791                 strprompt("Keep messages for how many days?", buf, 10);
792                 expire_value = atol(buf);
793         }
794         /* Save it */
795         scr_printf("Save this configuration? ");
796         if (yesno()) {
797                 serv_puts("CONF set");
798                 serv_gets(buf);
799                 if (buf[0] == '4') {
800                         for (a = 0; a < 29; ++a)
801                                 serv_puts(&sc[a][0]);
802                         serv_puts("000");
803                 }
804                 snprintf(buf, sizeof buf, "SPEX site|%d|%d",
805                          expire_mode, expire_value);
806                 serv_puts(buf);
807                 serv_gets(buf);
808         }
809 }
810
811
812 /*
813  * support function for do_internet_configuration()
814  */
815 void get_inet_rec_type(char *buf) {
816         int sel;
817
818         keyopt(" <1> localhost      (Alias for this computer)\n");
819         keyopt(" <2> gateway domain (Domain for all Citadel systems)\n");
820         keyopt(" <3> smart-host     (Forward all outbound mail to this host)\n");
821         keyopt(" <4> directory      (Consult the Global Address Book)\n");
822         sel = intprompt("Which one", 1, 1, 4);
823         switch(sel) {
824                 case 1: strcpy(buf, "localhost");
825                         return;
826                 case 2: strcpy(buf, "gatewaydomain");
827                         return;
828                 case 3: strcpy(buf, "smarthost");
829                         return;
830                 case 4: strcpy(buf, "directory");
831                         return;
832         }
833 }
834
835
836 /*
837  * Internet mail configuration
838  */
839 void do_internet_configuration(void) {
840         char buf[SIZ];
841         int num_recs = 0;
842         char **recs = NULL;
843         char ch;
844         int badkey;
845         int i, j;
846         int quitting = 0;
847         
848
849         sprintf(buf, "CONF getsys|%s", INTERNETCFG);
850         serv_puts(buf);
851         serv_gets(buf);
852         if (buf[0] == '1') while (serv_gets(buf), strcmp(buf, "000")) {
853                 ++num_recs;
854                 if (num_recs == 1) recs = malloc(sizeof(char *));
855                 else recs = realloc(recs, (sizeof(char *)) * num_recs);
856                 recs[num_recs-1] = malloc(SIZ);
857                 strcpy(recs[num_recs-1], buf);
858         }
859
860         do {
861                 scr_printf("\n");
862                 color(BRIGHT_WHITE);
863                 scr_printf("###                    Host or domain                     Record type      \n");
864                 color(DIM_WHITE);
865                 scr_printf("--- -------------------------------------------------- --------------------\n");
866                 for (i=0; i<num_recs; ++i) {
867                 color(DIM_WHITE);
868                 scr_printf("%3d ", i+1);
869                 extract(buf, recs[i], 0);
870                 color(BRIGHT_CYAN);
871                 scr_printf("%-50s ", buf);
872                 extract(buf, recs[i], 1);
873                 color(BRIGHT_MAGENTA);
874                 scr_printf("%-20s\n", buf);
875                 color(DIM_WHITE);
876                 }
877
878                 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
879                 switch(ch) {
880                         case 'a':
881                                 ++num_recs;
882                                 if (num_recs == 1)
883                                         recs = malloc(sizeof(char *));
884                                 else recs = realloc(recs,
885                                         (sizeof(char *)) * num_recs);
886                                 newprompt("Enter host name: ",
887                                         buf, 50);
888                                 strcat(buf, "|");
889                                 get_inet_rec_type(&buf[strlen(buf)]);
890                                 recs[num_recs-1] = strdup(buf);
891                                 break;
892                         case 'd':
893                                 i = intprompt("Delete which one",
894                                         1, 1, num_recs) - 1;
895                                 free(recs[i]);
896                                 --num_recs;
897                                 for (j=i; j<num_recs; ++j)
898                                         recs[j] = recs[j+1];
899                                 break;
900                         case 's':
901                                 sprintf(buf, "CONF putsys|%s",
902                                         INTERNETCFG);
903                                 serv_puts(buf);
904                                 serv_gets(buf);
905                                 if (buf[0] == '4') {
906                                         for (i=0; i<num_recs; ++i) {
907                                                 serv_puts(recs[i]);
908                                         }
909                                         serv_puts("000");
910                                 }
911                                 else {
912                                         scr_printf("%s\n", &buf[4]);
913                                 }
914                                 quitting = 1;
915                                 break;
916                         case 'q':
917                                 quitting = boolprompt(
918                                         "Quit without saving", 0);
919                                 break;
920                         default:
921                                 badkey = 1;
922                 }
923         } while (quitting == 0);
924
925         if (recs != NULL) {
926                 for (i=0; i<num_recs; ++i) free(recs[i]);
927                 free(recs);
928         }
929 }
930
931
932
933 /*
934  * Edit network configuration for room sharing, mailing lists, etc.
935  */
936 void network_config_management(char *entrytype, char *comment) {
937         char filename[PATH_MAX];
938         char changefile[PATH_MAX];
939         int e_ex_code;
940         pid_t editor_pid;
941         int cksum;
942         int b, i;
943         char buf[SIZ];
944         char instr[SIZ];
945         char addr[SIZ];
946         FILE *tempfp;
947         FILE *changefp;
948
949         if (strlen(editor_path) == 0) {
950                 scr_printf("You must have an external editor configured in"
951                         " order to use this function.\n");
952                 return;
953         }
954
955         snprintf(filename, sizeof filename, "%s.listedit", tmpnam(NULL));
956         snprintf(changefile, sizeof changefile, "%s.listedit", tmpnam(NULL));
957
958         tempfp = fopen(filename, "w");
959         if (tempfp == NULL) {
960                 err_printf("Cannot open %s: %s\n", filename, strerror(errno));
961                 return;
962         }
963
964         fprintf(tempfp, "# Configuration for room: %s\n", room_name);
965         fprintf(tempfp, "# %s\n", comment);
966         fprintf(tempfp, "# Specify one per line.\n"
967                         "\n\n");
968
969         serv_puts("GNET");
970         serv_gets(buf);
971         if (buf[0] == '1') {
972                 while(serv_gets(buf), strcmp(buf, "000")) {
973                         extract(instr, buf, 0);
974                         if (!strcasecmp(instr, entrytype)) {
975                                 extract(addr, buf, 1);
976                                 fprintf(tempfp, "%s\n", addr);
977                         }
978                 }
979         }
980         fclose(tempfp);
981
982         e_ex_code = 1;  /* start with a failed exit code */
983         editor_pid = fork();
984         cksum = file_checksum(filename);
985         if (editor_pid == 0) {
986                 chmod(filename, 0600);
987                 screen_reset();
988                 sttybbs(SB_RESTORE);
989                 setenv("WINDOW_TITLE", "Network configuration", 1);
990                 execlp(editor_path, editor_path, filename, NULL);
991                 exit(1);
992         }
993         if (editor_pid > 0) {
994                 do {
995                         e_ex_code = 0;
996                         b = ka_wait(&e_ex_code);
997                 } while ((b != editor_pid) && (b >= 0));
998         editor_pid = (-1);
999         sttybbs(0);
1000         screen_set();
1001         }
1002
1003         if (file_checksum(filename) == cksum) {
1004                 err_printf("*** Not saving changes.\n");
1005                 e_ex_code = 1;
1006         }
1007
1008         if (e_ex_code == 0) {           /* Save changes */
1009                 changefp = fopen(changefile, "w");
1010                 serv_puts("GNET");
1011                 serv_gets(buf);
1012                 if (buf[0] == '1') {
1013                         while(serv_gets(buf), strcmp(buf, "000")) {
1014                                 extract(instr, buf, 0);
1015                                 if (strcasecmp(instr, entrytype)) {
1016                                         fprintf(changefp, "%s\n", buf);
1017                                 }
1018                         }
1019                 }
1020                 tempfp = fopen(filename, "r");
1021                 while (fgets(buf, sizeof buf, tempfp) != NULL) {
1022                         for (i=0; i<strlen(buf); ++i) {
1023                                 if (buf[i] == '#') buf[i] = 0;
1024                         }
1025                         striplt(buf);
1026                         if (strlen(buf) > 0) {
1027                                 fprintf(changefp, "%s|%s\n", entrytype, buf);
1028                         }
1029                 }
1030                 fclose(tempfp);
1031                 fclose(changefp);
1032
1033                 /* now write it to the server... */
1034                 serv_puts("SNET");
1035                 serv_gets(buf);
1036                 if (buf[0] == '4') {
1037                         changefp = fopen(changefile, "r");
1038                         if (changefp != NULL) {
1039                                 while (fgets(buf, sizeof buf,
1040                                        changefp) != NULL) {
1041                                         buf[strlen(buf) - 1] = 0;
1042                                         serv_puts(buf);
1043                                 }
1044                                 fclose(changefp);
1045                         }
1046                         serv_puts("000");
1047                 }
1048         }
1049
1050         unlink(filename);               /* Delete the temporary files */
1051         unlink(changefile);
1052 }
1053
1054
1055 /*
1056  * IGnet node configuration
1057  */
1058 void do_ignet_configuration(void) {
1059         char buf[SIZ];
1060         int num_recs = 0;
1061         char **recs = NULL;
1062         char ch;
1063         int badkey;
1064         int i, j;
1065         int quitting = 0;
1066         
1067
1068         sprintf(buf, "CONF getsys|%s", IGNETCFG);
1069         serv_puts(buf);
1070         serv_gets(buf);
1071         if (buf[0] == '1') while (serv_gets(buf), strcmp(buf, "000")) {
1072                 ++num_recs;
1073                 if (num_recs == 1) recs = malloc(sizeof(char *));
1074                 else recs = realloc(recs, (sizeof(char *)) * num_recs);
1075                 recs[num_recs-1] = malloc(SIZ);
1076                 strcpy(recs[num_recs-1], buf);
1077         }
1078
1079         do {
1080                 scr_printf("\n");
1081                 color(BRIGHT_WHITE);
1082                 scr_printf(     "### "
1083                         "   Node          "
1084                         "  Secret           "
1085                         "          Host or IP             "
1086                         "Port#\n");
1087                 color(DIM_WHITE);
1088                 scr_printf(     "--- "
1089                         "---------------- "
1090                         "------------------ "
1091                         "-------------------------------- "
1092                         "-----\n");
1093                 for (i=0; i<num_recs; ++i) {
1094                 color(DIM_WHITE);
1095                 scr_printf("%3d ", i+1);
1096                 extract(buf, recs[i], 0);
1097                 color(BRIGHT_CYAN);
1098                 scr_printf("%-16s ", buf);
1099                 extract(buf, recs[i], 1);
1100                 color(BRIGHT_MAGENTA);
1101                 scr_printf("%-18s ", buf);
1102                 extract(buf, recs[i], 2);
1103                 color(BRIGHT_CYAN);
1104                 scr_printf("%-32s ", buf);
1105                 extract(buf, recs[i], 3);
1106                 color(BRIGHT_MAGENTA);
1107                 scr_printf("%-3s\n", buf);
1108                 color(DIM_WHITE);
1109                 }
1110
1111                 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
1112                 switch(ch) {
1113                         case 'a':
1114                                 ++num_recs;
1115                                 if (num_recs == 1)
1116                                         recs = malloc(sizeof(char *));
1117                                 else recs = realloc(recs,
1118                                         (sizeof(char *)) * num_recs);
1119                                 newprompt("Enter node name    : ", buf, 16);
1120                                 strcat(buf, "|");
1121                                 newprompt("Enter shared secret: ",
1122                                         &buf[strlen(buf)], 18);
1123                                 strcat(buf, "|");
1124                                 newprompt("Enter host or IP   : ",
1125                                         &buf[strlen(buf)], 32);
1126                                 strcat(buf, "|504");
1127                                 strprompt("Enter port number  : ",
1128                                         &buf[strlen(buf)-3], 5);
1129                                 recs[num_recs-1] = strdup(buf);
1130                                 break;
1131                         case 'd':
1132                                 i = intprompt("Delete which one",
1133                                         1, 1, num_recs) - 1;
1134                                 free(recs[i]);
1135                                 --num_recs;
1136                                 for (j=i; j<num_recs; ++j)
1137                                         recs[j] = recs[j+1];
1138                                 break;
1139                         case 's':
1140                                 sprintf(buf, "CONF putsys|%s", IGNETCFG);
1141                                 serv_puts(buf);
1142                                 serv_gets(buf);
1143                                 if (buf[0] == '4') {
1144                                         for (i=0; i<num_recs; ++i) {
1145                                                 serv_puts(recs[i]);
1146                                         }
1147                                         serv_puts("000");
1148                                 }
1149                                 else {
1150                                         scr_printf("%s\n", &buf[4]);
1151                                 }
1152                                 quitting = 1;
1153                                 break;
1154                         case 'q':
1155                                 quitting = boolprompt(
1156                                         "Quit without saving", 0);
1157                                 break;
1158                         default:
1159                                 badkey = 1;
1160                 }
1161         } while (quitting == 0);
1162
1163         if (recs != NULL) {
1164                 for (i=0; i<num_recs; ++i) free(recs[i]);
1165                 free(recs);
1166         }
1167 }
1168
1169