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