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