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