]> code.citadel.org Git - citadel.git/blob - citadel/routines2.c
* Removed the unfinished moderation system.
[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         /* Security parameters */
736
737         snprintf(sc[7], sizeof sc[7], "%d", (boolprompt(
738                                     "Require registration for new users",
739                                                     atoi(&sc[7][0]))));
740         snprintf(sc[29], sizeof sc[29], "%d", (boolprompt(
741               "Disable self-service user account creation",
742                                                      atoi(&sc[29][0]))));
743         strprompt("Initial access level for new users", &sc[6][0], 1);
744         strprompt("Access level required to create rooms", &sc[19][0], 1);
745         snprintf(sc[4], sizeof sc[4], "%d", (boolprompt(
746                                                     "Automatically give room aide privs to a user who creates a private room",
747                                                     atoi(&sc[4][0]))));
748
749         snprintf(sc[8], sizeof sc[8], "%d", (boolprompt(
750                  "Automatically move problem user messages to twit room",
751                                                     atoi(&sc[8][0]))));
752
753         strprompt("Name of twit room", &sc[9][0], ROOMNAMELEN);
754         snprintf(sc[11], sizeof sc[11], "%d", (boolprompt(
755               "Restrict Internet mail to only those with that privilege",
756                                                      atoi(&sc[11][0]))));
757         snprintf(sc[26], sizeof sc[26], "%d", (boolprompt(
758               "Allow Aides to Zap (forget) rooms",
759                                                      atoi(&sc[26][0]))));
760         snprintf(sc[30], sizeof sc[29], "%d", (boolprompt(
761               "Allow system Aides access to user mailboxes",
762                                                      atoi(&sc[30][0]))));
763
764         if (strlen(&sc[18][0]) > 0) logpages = 1;
765         else logpages = 0;
766         logpages = boolprompt("Log all pages", logpages);
767         if (logpages) {
768                 strprompt("Name of logging room", &sc[18][0], ROOMNAMELEN);
769         }
770         else {
771                 sc[18][0] = 0;
772         }
773
774
775         /* Server tuning */
776
777         strprompt("Server connection idle timeout (in seconds)", &sc[5][0], 4);
778         strprompt("Maximum concurrent sessions", &sc[14][0], 4);
779         strprompt("Maximum message length", &sc[20][0], 20);
780         strprompt("Minimum number of worker threads", &sc[21][0], 3);
781         strprompt("Maximum number of worker threads", &sc[22][0], 3);
782
783         /* no longer applicable ... deprecated
784         strprompt("Server-to-server networking password", &sc[15][0], 19);
785         */
786
787         strprompt("How often to run network jobs (in seconds)", &sc[28][0], 5);
788         strprompt("SMTP server port (-1 to disable)", &sc[24][0], 5);
789         strprompt("POP3 server port (-1 to disable)", &sc[23][0], 5);
790         strprompt("IMAP server port (-1 to disable)", &sc[27][0], 5);
791
792         /* Expiry settings */
793         strprompt("Default user purge time (days)", &sc[16][0], 5);
794         strprompt("Default room purge time (days)", &sc[17][0], 5);
795
796         /* Angels and demons dancing in my head... */
797         do {
798                 snprintf(buf, sizeof buf, "%d", expire_mode);
799                 strprompt("System default message expire policy (? for list)",
800                           buf, 1);
801                 if (buf[0] == '?') {
802                         scr_printf("\n"
803                                 "1. Never automatically expire messages\n"
804                                 "2. Expire by message count\n"
805                                 "3. Expire by message age\n");
806                 }
807         } while ((buf[0] < 49) || (buf[0] > 51));
808         expire_mode = buf[0] - 48;
809
810         /* ...lunatics and monsters underneath my bed */
811         if (expire_mode == 2) {
812                 snprintf(buf, sizeof buf, "%d", expire_value);
813                 strprompt("Keep how many messages online?", buf, 10);
814                 expire_value = atol(buf);
815         }
816         if (expire_mode == 3) {
817                 snprintf(buf, sizeof buf, "%d", expire_value);
818                 strprompt("Keep messages for how many days?", buf, 10);
819                 expire_value = atol(buf);
820         }
821         /* Save it */
822         scr_printf("Save this configuration? ");
823         if (yesno()) {
824                 serv_puts("CONF set");
825                 serv_gets(buf);
826                 if (buf[0] == '4') {
827                         for (a = 0; a < 31; ++a)
828                                 serv_puts(&sc[a][0]);
829                         serv_puts("000");
830                 }
831                 snprintf(buf, sizeof buf, "SPEX site|%d|%d",
832                          expire_mode, expire_value);
833                 serv_puts(buf);
834                 serv_gets(buf);
835         }
836 }
837
838
839 /*
840  * support function for do_internet_configuration()
841  */
842 void get_inet_rec_type(char *buf) {
843         int sel;
844
845         keyopt(" <1> localhost      (Alias for this computer)\n");
846         keyopt(" <2> gateway domain (Domain for all Citadel systems)\n");
847         keyopt(" <3> smart-host     (Forward all outbound mail to this host)\n");
848         keyopt(" <4> directory      (Consult the Global Address Book)\n");
849         sel = intprompt("Which one", 1, 1, 4);
850         switch(sel) {
851                 case 1: strcpy(buf, "localhost");
852                         return;
853                 case 2: strcpy(buf, "gatewaydomain");
854                         return;
855                 case 3: strcpy(buf, "smarthost");
856                         return;
857                 case 4: strcpy(buf, "directory");
858                         return;
859         }
860 }
861
862
863 /*
864  * Internet mail configuration
865  */
866 void do_internet_configuration(void) {
867         char buf[SIZ];
868         int num_recs = 0;
869         char **recs = NULL;
870         char ch;
871         int badkey;
872         int i, j;
873         int quitting = 0;
874         
875
876         snprintf(buf, sizeof buf, "CONF getsys|%s", INTERNETCFG);
877         serv_puts(buf);
878         serv_gets(buf);
879         if (buf[0] == '1') while (serv_gets(buf), strcmp(buf, "000")) {
880                 ++num_recs;
881                 if (num_recs == 1) recs = malloc(sizeof(char *));
882                 else recs = realloc(recs, (sizeof(char *)) * num_recs);
883                 recs[num_recs-1] = malloc(SIZ);
884                 strcpy(recs[num_recs-1], buf);
885         }
886
887         do {
888                 scr_printf("\n");
889                 color(BRIGHT_WHITE);
890                 scr_printf("###                    Host or domain                     Record type      \n");
891                 color(DIM_WHITE);
892                 scr_printf("--- -------------------------------------------------- --------------------\n");
893                 for (i=0; i<num_recs; ++i) {
894                 color(DIM_WHITE);
895                 scr_printf("%3d ", i+1);
896                 extract(buf, recs[i], 0);
897                 color(BRIGHT_CYAN);
898                 scr_printf("%-50s ", buf);
899                 extract(buf, recs[i], 1);
900                 color(BRIGHT_MAGENTA);
901                 scr_printf("%-20s\n", buf);
902                 color(DIM_WHITE);
903                 }
904
905                 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
906                 switch(ch) {
907                         case 'a':
908                                 ++num_recs;
909                                 if (num_recs == 1)
910                                         recs = malloc(sizeof(char *));
911                                 else recs = realloc(recs,
912                                         (sizeof(char *)) * num_recs);
913                                 newprompt("Enter host name: ",
914                                         buf, 50);
915                                 strcat(buf, "|");
916                                 get_inet_rec_type(&buf[strlen(buf)]);
917                                 recs[num_recs-1] = strdup(buf);
918                                 break;
919                         case 'd':
920                                 i = intprompt("Delete which one",
921                                         1, 1, num_recs) - 1;
922                                 free(recs[i]);
923                                 --num_recs;
924                                 for (j=i; j<num_recs; ++j)
925                                         recs[j] = recs[j+1];
926                                 break;
927                         case 's':
928                                 snprintf(buf, sizeof buf, "CONF putsys|%s",
929                                         INTERNETCFG);
930                                 serv_puts(buf);
931                                 serv_gets(buf);
932                                 if (buf[0] == '4') {
933                                         for (i=0; i<num_recs; ++i) {
934                                                 serv_puts(recs[i]);
935                                         }
936                                         serv_puts("000");
937                                 }
938                                 else {
939                                         scr_printf("%s\n", &buf[4]);
940                                 }
941                                 quitting = 1;
942                                 break;
943                         case 'q':
944                                 quitting = boolprompt(
945                                         "Quit without saving", 0);
946                                 break;
947                         default:
948                                 badkey = 1;
949                 }
950         } while (quitting == 0);
951
952         if (recs != NULL) {
953                 for (i=0; i<num_recs; ++i) free(recs[i]);
954                 free(recs);
955         }
956 }
957
958
959
960 /*
961  * Edit network configuration for room sharing, mailing lists, etc.
962  */
963 void network_config_management(char *entrytype, char *comment) {
964         char filename[PATH_MAX];
965         char changefile[PATH_MAX];
966         int e_ex_code;
967         pid_t editor_pid;
968         int cksum;
969         int b, i;
970         char buf[SIZ];
971         char instr[SIZ];
972         char addr[SIZ];
973         FILE *tempfp;
974         FILE *changefp;
975
976         if (strlen(editor_path) == 0) {
977                 scr_printf("You must have an external editor configured in"
978                         " order to use this function.\n");
979                 return;
980         }
981
982         snprintf(filename, sizeof filename, "%s.listedit", tmpnam(NULL));
983         snprintf(changefile, sizeof changefile, "%s.listedit", tmpnam(NULL));
984
985         tempfp = fopen(filename, "w");
986         if (tempfp == NULL) {
987                 err_printf("Cannot open %s: %s\n", filename, strerror(errno));
988                 return;
989         }
990
991         fprintf(tempfp, "# Configuration for room: %s\n", room_name);
992         fprintf(tempfp, "# %s\n", comment);
993         fprintf(tempfp, "# Specify one per line.\n"
994                         "\n\n");
995
996         serv_puts("GNET");
997         serv_gets(buf);
998         if (buf[0] == '1') {
999                 while(serv_gets(buf), strcmp(buf, "000")) {
1000                         extract(instr, buf, 0);
1001                         if (!strcasecmp(instr, entrytype)) {
1002                                 extract(addr, buf, 1);
1003                                 fprintf(tempfp, "%s\n", addr);
1004                         }
1005                 }
1006         }
1007         fclose(tempfp);
1008
1009         e_ex_code = 1;  /* start with a failed exit code */
1010         editor_pid = fork();
1011         cksum = file_checksum(filename);
1012         if (editor_pid == 0) {
1013                 chmod(filename, 0600);
1014                 screen_reset();
1015                 sttybbs(SB_RESTORE);
1016                 putenv("WINDOW_TITLE=Network configuration");
1017                 execlp(editor_path, editor_path, filename, NULL);
1018                 exit(1);
1019         }
1020         if (editor_pid > 0) {
1021                 do {
1022                         e_ex_code = 0;
1023                         b = ka_wait(&e_ex_code);
1024                 } while ((b != editor_pid) && (b >= 0));
1025         editor_pid = (-1);
1026         sttybbs(0);
1027         screen_set();
1028         }
1029
1030         if (file_checksum(filename) == cksum) {
1031                 err_printf("*** Not saving changes.\n");
1032                 e_ex_code = 1;
1033         }
1034
1035         if (e_ex_code == 0) {           /* Save changes */
1036                 changefp = fopen(changefile, "w");
1037                 serv_puts("GNET");
1038                 serv_gets(buf);
1039                 if (buf[0] == '1') {
1040                         while(serv_gets(buf), strcmp(buf, "000")) {
1041                                 extract(instr, buf, 0);
1042                                 if (strcasecmp(instr, entrytype)) {
1043                                         fprintf(changefp, "%s\n", buf);
1044                                 }
1045                         }
1046                 }
1047                 tempfp = fopen(filename, "r");
1048                 while (fgets(buf, sizeof buf, tempfp) != NULL) {
1049                         for (i=0; i<strlen(buf); ++i) {
1050                                 if (buf[i] == '#') buf[i] = 0;
1051                         }
1052                         striplt(buf);
1053                         if (strlen(buf) > 0) {
1054                                 fprintf(changefp, "%s|%s\n", entrytype, buf);
1055                         }
1056                 }
1057                 fclose(tempfp);
1058                 fclose(changefp);
1059
1060                 /* now write it to the server... */
1061                 serv_puts("SNET");
1062                 serv_gets(buf);
1063                 if (buf[0] == '4') {
1064                         changefp = fopen(changefile, "r");
1065                         if (changefp != NULL) {
1066                                 while (fgets(buf, sizeof buf,
1067                                        changefp) != NULL) {
1068                                         buf[strlen(buf) - 1] = 0;
1069                                         serv_puts(buf);
1070                                 }
1071                                 fclose(changefp);
1072                         }
1073                         serv_puts("000");
1074                 }
1075         }
1076
1077         unlink(filename);               /* Delete the temporary files */
1078         unlink(changefile);
1079 }
1080
1081
1082 /*
1083  * IGnet node configuration
1084  */
1085 void do_ignet_configuration(void) {
1086         char buf[SIZ];
1087         int num_recs = 0;
1088         char **recs = NULL;
1089         char ch;
1090         int badkey;
1091         int i, j;
1092         int quitting = 0;
1093         
1094
1095         snprintf(buf, sizeof buf, "CONF getsys|%s", IGNETCFG);
1096         serv_puts(buf);
1097         serv_gets(buf);
1098         if (buf[0] == '1') while (serv_gets(buf), strcmp(buf, "000")) {
1099                 ++num_recs;
1100                 if (num_recs == 1) recs = malloc(sizeof(char *));
1101                 else recs = realloc(recs, (sizeof(char *)) * num_recs);
1102                 recs[num_recs-1] = malloc(SIZ);
1103                 strcpy(recs[num_recs-1], buf);
1104         }
1105
1106         do {
1107                 scr_printf("\n");
1108                 color(BRIGHT_WHITE);
1109                 scr_printf(     "### "
1110                         "   Node          "
1111                         "  Secret           "
1112                         "          Host or IP             "
1113                         "Port#\n");
1114                 color(DIM_WHITE);
1115                 scr_printf(     "--- "
1116                         "---------------- "
1117                         "------------------ "
1118                         "-------------------------------- "
1119                         "-----\n");
1120                 for (i=0; i<num_recs; ++i) {
1121                 color(DIM_WHITE);
1122                 scr_printf("%3d ", i+1);
1123                 extract(buf, recs[i], 0);
1124                 color(BRIGHT_CYAN);
1125                 scr_printf("%-16s ", buf);
1126                 extract(buf, recs[i], 1);
1127                 color(BRIGHT_MAGENTA);
1128                 scr_printf("%-18s ", buf);
1129                 extract(buf, recs[i], 2);
1130                 color(BRIGHT_CYAN);
1131                 scr_printf("%-32s ", buf);
1132                 extract(buf, recs[i], 3);
1133                 color(BRIGHT_MAGENTA);
1134                 scr_printf("%-3s\n", buf);
1135                 color(DIM_WHITE);
1136                 }
1137
1138                 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
1139                 switch(ch) {
1140                         case 'a':
1141                                 ++num_recs;
1142                                 if (num_recs == 1)
1143                                         recs = malloc(sizeof(char *));
1144                                 else recs = realloc(recs,
1145                                         (sizeof(char *)) * num_recs);
1146                                 newprompt("Enter node name    : ", buf, 16);
1147                                 strcat(buf, "|");
1148                                 newprompt("Enter shared secret: ",
1149                                         &buf[strlen(buf)], 18);
1150                                 strcat(buf, "|");
1151                                 newprompt("Enter host or IP   : ",
1152                                         &buf[strlen(buf)], 32);
1153                                 strcat(buf, "|504");
1154                                 strprompt("Enter port number  : ",
1155                                         &buf[strlen(buf)-3], 5);
1156                                 recs[num_recs-1] = strdup(buf);
1157                                 break;
1158                         case 'd':
1159                                 i = intprompt("Delete which one",
1160                                         1, 1, num_recs) - 1;
1161                                 free(recs[i]);
1162                                 --num_recs;
1163                                 for (j=i; j<num_recs; ++j)
1164                                         recs[j] = recs[j+1];
1165                                 break;
1166                         case 's':
1167                                 snprintf(buf, sizeof buf, "CONF putsys|%s", IGNETCFG);
1168                                 serv_puts(buf);
1169                                 serv_gets(buf);
1170                                 if (buf[0] == '4') {
1171                                         for (i=0; i<num_recs; ++i) {
1172                                                 serv_puts(recs[i]);
1173                                         }
1174                                         serv_puts("000");
1175                                 }
1176                                 else {
1177                                         scr_printf("%s\n", &buf[4]);
1178                                 }
1179                                 quitting = 1;
1180                                 break;
1181                         case 'q':
1182                                 quitting = boolprompt(
1183                                         "Quit without saving", 0);
1184                                 break;
1185                         default:
1186                                 badkey = 1;
1187                 }
1188         } while (quitting == 0);
1189
1190         if (recs != NULL) {
1191                 for (i=0; i<num_recs; ++i) free(recs[i]);
1192                 free(recs);
1193         }
1194 }
1195
1196 /*
1197  * Filter list configuration
1198  */
1199 void do_filterlist_configuration(void) {
1200         char buf[SIZ];
1201         int num_recs = 0;
1202         char **recs = NULL;
1203         char ch;
1204         int badkey;
1205         int i, j;
1206         int quitting = 0;
1207         
1208
1209         snprintf(buf, sizeof buf, "CONF getsys|%s", FILTERLIST);
1210         serv_puts(buf);
1211         serv_gets(buf);
1212         if (buf[0] == '1') while (serv_gets(buf), strcmp(buf, "000")) {
1213                 ++num_recs;
1214                 if (num_recs == 1) recs = malloc(sizeof(char *));
1215                 else recs = realloc(recs, (sizeof(char *)) * num_recs);
1216                 recs[num_recs-1] = malloc(SIZ);
1217                 strcpy(recs[num_recs-1], buf);
1218         }
1219
1220         do {
1221                 scr_printf("\n");
1222                 color(BRIGHT_WHITE);
1223                 scr_printf(     "### "
1224                         "         User name           "
1225                         "         Room name           "
1226                         "    Node name    "
1227                         "\n");
1228                 color(DIM_WHITE);
1229                 scr_printf(     "--- "
1230                         "---------------------------- "
1231                         "---------------------------- "
1232                         "---------------- "
1233                         "\n");
1234                 for (i=0; i<num_recs; ++i) {
1235                 color(DIM_WHITE);
1236                 scr_printf("%3d ", i+1);
1237                 extract(buf, recs[i], 0);
1238                 color(BRIGHT_CYAN);
1239                 scr_printf("%-28s ", buf);
1240                 extract(buf, recs[i], 1);
1241                 color(BRIGHT_MAGENTA);
1242                 scr_printf("%-28s ", buf);
1243                 extract(buf, recs[i], 2);
1244                 color(BRIGHT_CYAN);
1245                 scr_printf("%-16s\n", buf);
1246                 extract(buf, recs[i], 3);
1247                 color(DIM_WHITE);
1248                 }
1249
1250                 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
1251                 switch(ch) {
1252                         case 'a':
1253                                 ++num_recs;
1254                                 if (num_recs == 1)
1255                                         recs = malloc(sizeof(char *));
1256                                 else recs = realloc(recs,
1257                                         (sizeof(char *)) * num_recs);
1258                                 newprompt("Enter user name: ", buf, 28);
1259                                 strcat(buf, "|");
1260                                 newprompt("Enter room name: ",
1261                                         &buf[strlen(buf)], 28);
1262                                 strcat(buf, "|");
1263                                 newprompt("Enter node name: ",
1264                                         &buf[strlen(buf)], 16);
1265                                 strcat(buf, "|");
1266                                 recs[num_recs-1] = strdup(buf);
1267                                 break;
1268                         case 'd':
1269                                 i = intprompt("Delete which one",
1270                                         1, 1, num_recs) - 1;
1271                                 free(recs[i]);
1272                                 --num_recs;
1273                                 for (j=i; j<num_recs; ++j)
1274                                         recs[j] = recs[j+1];
1275                                 break;
1276                         case 's':
1277                                 snprintf(buf, sizeof buf, "CONF putsys|%s", FILTERLIST);
1278                                 serv_puts(buf);
1279                                 serv_gets(buf);
1280                                 if (buf[0] == '4') {
1281                                         for (i=0; i<num_recs; ++i) {
1282                                                 serv_puts(recs[i]);
1283                                         }
1284                                         serv_puts("000");
1285                                 }
1286                                 else {
1287                                         scr_printf("%s\n", &buf[4]);
1288                                 }
1289                                 quitting = 1;
1290                                 break;
1291                         case 'q':
1292                                 quitting = boolprompt(
1293                                         "Quit without saving", 0);
1294                                 break;
1295                         default:
1296                                 badkey = 1;
1297                 }
1298         } while (quitting == 0);
1299
1300         if (recs != NULL) {
1301                 for (i=0; i<num_recs; ++i) free(recs[i]);
1302                 free(recs);
1303         }
1304 }
1305
1306