5632262b32ac44d63f189839860f44b9c9159fa7
[citadel.git] / citadel / setup.c
1 /*
2  * Citadel/UX setup program
3  * $Id$
4  *
5  * *** YOU MUST EDIT sysconfig.h >BEFORE< COMPILING SETUP ***
6  */
7
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include <fcntl.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <sys/utsname.h>
17 #include <netdb.h>
18 #include <errno.h>
19 #include <limits.h>
20 #include <pwd.h>
21
22 #include "citadel.h"
23 #include "axdefs.h"
24 #include "sysdep.h"
25 #include "config.h"
26 #include "tools.h"
27
28 #ifdef HAVE_CURSES_H
29 #ifdef OK
30 #undef OK
31 #endif
32 #include <curses.h>
33 #endif
34
35 #define MAXSETUP 5
36
37 #define UI_TEXT         0       /* Default setup type -- text only */
38 #define UI_DIALOG       1       /* Use the 'dialog' program */
39 #define UI_CURSES       2       /* Use curses */
40
41 #define SERVICE_NAME    "citadel"
42 #define PROTO_NAME      "tcp"
43
44 int setup_type;
45 char setup_directory[128];
46 int need_init_q = 0;
47
48 char *setup_titles[] =
49 {
50         "BBS Home Directory",
51         "System Administrator",
52         "BBS User ID",
53         "Name of bit bucket subdirectory",
54         "Server port number",
55 };
56
57
58 char *setup_text[] =
59 {
60
61 "0",
62 "Enter the full pathname of the directory in which the BBS you are",
63 "creating or updating resides.  If you specify a directory other than the",
64 "default, you will need to specify the -h flag to the server when you start",
65 "it up.",
66
67 "1",
68 "Enter the name of the system administrator (which is probably you).",
69 "When an account is created with this name, it will automatically be",
70 "assigned the highest access level.",
71
72 "2",
73 "You should create a user called 'bbs', 'guest', 'citadel', or something",
74 "similar, that will allow users a way into your BBS.  The server will run",
75 "under this user ID.  Please specify that (numeric) user ID here.",
76
77 "3",
78 "Select the name of a subdirectory (relative to the main",
79 "Citadel directory - do not type an absolute pathname!) in",
80 "which to place arriving file transfers that otherwise",
81 "don't have a home.",
82
83 "4",
84 "Specify the TCP port number on which your server will run.  Normally, this",
85 "will be port 504, which is the official port assigned by the IANA for",
86 "Citadel servers.  You'll only need to specify a different port number if",
87 "you run multiple BBS's on the same computer and there's something else",
88 "already using port 504.",
89
90 "5",
91 "6",
92 "7",
93 "8",
94 "9",
95 "10",
96 "11",
97 "12",
98 "13",
99 "14",
100 "15",
101 "16",
102 "17",
103 "18",
104 "19",
105 "20",
106 "21",
107 "22",
108 "23",
109 "24",
110 "25",
111 "26",
112 "27",
113 "28",
114 "29",
115 "30",
116
117 "31",
118 "Setup has detected that you currently have data files from a Citadel/UX",
119 "version 3.2x installation.  The program 'conv_32_40' can upgrade your",
120 "files to version 4.0x format.",
121 " Setup will now exit.  Please either run 'conv_32_40' or delete your data",
122 "files, and run setup again.",
123
124 "32",
125
126 };
127
128 struct config config;
129 int direction;
130
131 void cleanup(int exitcode)
132 {
133 #ifdef HAVE_CURSES_H
134         if (setup_type == UI_CURSES) {
135                 clear();
136                 refresh();
137                 endwin();
138         }
139 #endif
140
141         /* Do an 'init q' if we need to.  When we hit the right one, init
142          * will take over and setup won't come back because we didn't do a
143          * fork().  If init isn't found, we fall through the bottom of the
144          * loop and setup exits quietly.
145          */
146         if (need_init_q) {
147                 execlp("/sbin/init", "init", "q", NULL);
148                 execlp("/usr/sbin/init", "init", "q", NULL);
149                 execlp("/bin/init", "init", "q", NULL);
150                 execlp("/usr/bin/init", "init", "q", NULL);
151                 execlp("init", "init", "q", NULL);
152         }
153         exit(exitcode);
154 }
155
156
157 /* Gets a line from the terminal */
158 /* Where on the screen to start */
159 /* Pointer to string buffer */
160 /* Maximum length - if negative, no-show */
161 #ifdef HAVE_CURSES_H
162 void getlin(int yp, int xp, char *string, int lim) {
163         int a, b;
164         char flag;
165
166         flag = 0;
167         if (lim < 0) {
168                 lim = (0 - lim);
169                 flag = 1;
170         }
171         move(yp, xp);
172         standout();
173         for (a = 0; a < lim; ++a)
174                 addch('-');
175         refresh();
176         move(yp, xp);
177         for (a = 0; a < lim; ++a)
178                 addch(' ');
179         move(yp, xp);
180         printw("%s", string);
181       GLA:move(yp, xp + strlen(string));
182         refresh();
183         a = getch();
184         if (a == 127)
185                 a = 8;
186         a = (a & 127);
187         if (a == 10)
188                 a = 13;
189         if ((a == 8) && (strlen(string) == 0))
190                 goto GLA;
191         if ((a != 13) && (a != 8) && (strlen(string) == lim))
192                 goto GLA;
193         if ((a == 8) && (string[0] != 0)) {
194                 string[strlen(string) - 1] = 0;
195                 move(yp, xp + strlen(string));
196                 addch(' ');
197                 goto GLA;
198         }
199         if ((a == 13) || (a == 10)) {
200                 standend();
201                 move(yp, xp);
202                 for (a = 0; a < lim; ++a)
203                         addch(' ');
204                 mvprintw(yp, xp, "%s", string);
205                 refresh();
206                 return;
207         }
208         b = strlen(string);
209         string[b] = a;
210         string[b + 1] = 0;
211         if (flag == 0)
212                 addch(a);
213         if (flag == 1)
214                 addch('*');
215         goto GLA;
216 }
217 #endif
218
219
220
221 void title(char *text)
222 {
223         if (setup_type == UI_TEXT) {
224                 printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<%s>\n", text);
225         }
226 }
227
228
229 void hit_any_key(void)
230 {
231         char junk[5];
232
233 #ifdef HAVE_CURSES_H
234         if (setup_type == UI_CURSES) {
235                 mvprintw(20, 0, "Press any key to continue... ");
236                 refresh();
237                 getch();
238                 return;
239         }
240 #endif
241         printf("Press return to continue...");
242         fgets(junk, 5, stdin);
243 }
244
245 int yesno(char *question)
246 {
247         int answer = 0;
248         char buf[4096];
249
250         switch (setup_type) {
251
252         case UI_TEXT:
253                 do {
254                         printf("%s\nYes/No --> ", question);
255                         fgets(buf, 4096, stdin);
256                         answer = tolower(buf[0]);
257                         if (answer == 'y')
258                                 answer = 1;
259                         else if (answer == 'n')
260                                 answer = 0;
261                 } while ((answer < 0) || (answer > 1));
262                 break;
263
264         case UI_DIALOG:
265                 sprintf(buf, "dialog --yesno \"%s\" 7 80", question);
266                 answer = ((system(buf) == 0) ? 1 : 0);
267                 break;
268 #ifdef HAVE_CURSES_H
269         case UI_CURSES:
270                 do {
271                         clear();
272                         standout();
273                         mvprintw(1, 20, "Question");
274                         standend();
275                         mvprintw(10, 0, "%-80s", question);
276                         mvprintw(20, 0, "%80s", "");
277                         mvprintw(20, 0, "Yes/No -> ");
278                         refresh();
279                         answer = getch();
280                         answer = tolower(answer);
281                         if (answer == 'y')
282                                 answer = 1;
283                         else if (answer == 'n')
284                                 answer = 0;
285                 } while ((answer < 0) || (answer > 1));
286                 break;
287 #endif
288
289         }
290         return (answer);
291 }
292
293
294
295 void dump_access_levels(void)
296 {
297         int a;
298         for (a = 0; a <= 6; ++a)
299                 printf("%d %s\n", a, axdefs[a]);
300 }
301
302 void get_setup_msg(char *dispbuf, int msgnum)
303 {
304         int a, b;
305
306         a = 0;
307         b = 0;
308         while (atol(setup_text[a]) != msgnum)
309                 ++a;
310         ++a;
311         strcpy(dispbuf, "");
312         do {
313                 strcat(dispbuf, setup_text[a++]);
314                 strcat(dispbuf, "\n");
315         } while (atol(setup_text[a]) != (msgnum + 1));
316 }
317
318 void print_setup(int msgnum)
319 {
320         char dispbuf[4096];
321
322         get_setup_msg(dispbuf, msgnum);
323         printf("\n\n%s\n\n", dispbuf);
324 }
325
326
327 void important_message(char *title, char *msgtext)
328 {
329         char buf[4096];
330
331         switch (setup_type) {
332
333         case UI_TEXT:
334                 printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
335                 printf("       %s \n\n%s\n\n", title, msgtext);
336                 hit_any_key();
337                 break;
338
339         case UI_DIALOG:
340                 sprintf(buf, "dialog --title \"%s\" --msgbox \"\n%s\" 20 80",
341                         title, msgtext);
342                 system(buf);
343                 break;
344 #ifdef HAVE_CURSES_H
345         case UI_CURSES:
346                 clear();
347                 move(1, 20);
348                 standout();
349                 printw("  Important Message  ");
350                 standend();
351                 move(3, 0);
352                 printw("%s", msgtext);
353                 refresh();
354                 hit_any_key();
355                 break;
356 #endif
357
358         }
359 }
360
361 void important_msgnum(int msgnum)
362 {
363         char dispbuf[4096];
364
365         get_setup_msg(dispbuf, msgnum);
366         important_message("Important Message", dispbuf);
367 }
368
369 void display_error(char *error_message)
370 {
371         important_message("Error", error_message);
372 }
373
374 void progress(char *text, long int curr, long int cmax)
375 {
376         static long dots_printed;
377         long a;
378         static long prev;
379         static FILE *gauge = NULL;
380         char gcmd[256];
381
382         switch (setup_type) {
383
384         case UI_TEXT:
385                 if (curr == 0) {
386                         printf("%s\n", text);
387                         printf("..........................");
388                         printf("..........................");
389                         printf("..........................\r");
390                         fflush(stdout);
391                         dots_printed = 0;
392                 } else if (curr == cmax) {
393                         printf("\r%79s\n", "");
394                 } else {
395                         a = (curr * 100) / cmax;
396                         a = a * 78;
397                         a = a / 100;
398                         while (dots_printed < a) {
399                                 printf("*");
400                                 ++dots_printed;
401                                 fflush(stdout);
402                         }
403                 }
404                 break;
405
406 #ifdef HAVE_CURSES_H
407         case UI_CURSES:
408                 if (curr == 0) {
409                         clear();
410                         move(5, 20);
411                         printw("%s\n", text);
412                         move(10, 1);
413                         printf("..........................");
414                         printf("..........................");
415                         printf("..........................\r");
416                         refresh();
417                         dots_printed = 0;
418                 } else if (curr == cmax) {
419                         clear();
420                         refresh();
421                 } else {
422                         a = (curr * 100) / cmax;
423                         a = a * 78;
424                         a = a / 100;
425                         move(10, 1);
426                         dots_printed = 0;
427                         while (dots_printed < a) {
428                                 printw("*");
429                                 ++dots_printed;
430                         }
431                         refresh();
432                 }
433                 break;
434 #endif
435
436         case UI_DIALOG:
437                 if ((curr == 0) && (gauge == NULL)) {
438                         sprintf(gcmd, "dialog --guage \"%s\" 7 80 0",
439                                 text);
440                         gauge = (FILE *) popen(gcmd, "w");
441                         prev = 0;
442                 } else if (curr == cmax) {
443                         fprintf(gauge, "100\n");
444                         pclose(gauge);
445                         gauge = NULL;
446                 } else {
447                         a = (curr * 100) / cmax;
448                         if (a != prev) {
449                                 fprintf(gauge, "%ld\n", a);
450                                 fflush(gauge);
451                         }
452                         prev = a;
453                 }
454                 break;
455         }
456 }
457
458
459
460 /*
461  * check_services_entry()  -- Make sure "citadel" is in /etc/services
462  *
463  */
464 void check_services_entry(void)
465 {
466         char question[128];
467         FILE *sfp;
468
469         sprintf(question,
470                 "There is no '%s' entry in /etc/services.  Would you like to add one?",
471                 SERVICE_NAME);
472
473         if (getservbyname(SERVICE_NAME, PROTO_NAME) == NULL) {
474                 if (yesno(question) == 1) {
475                         sfp = fopen("/etc/services", "a");
476                         if (sfp == NULL) {
477                                 display_error(strerror(errno));
478                         } else {
479                                 fprintf(sfp, "%s                504/tcp\n",
480                                         SERVICE_NAME);
481                                 fclose(sfp);
482                         }
483                 }
484         }
485 }
486
487
488 /*
489  * check_inittab_entry()  -- Make sure "citadel" is in /etc/inittab
490  *
491  */
492 void check_inittab_entry(void)
493 {
494         FILE *infp;
495         char buf[256];
496         char looking_for[256];
497         char question[128];
498         char *ptr;
499         int have_entry = 0;
500         char entryname[3];
501
502         /* Determine the fully qualified path name of citserver */
503         sprintf(looking_for, "%s/citserver ", BBSDIR);
504
505         /* Pound through /etc/inittab line by line.  Set have_entry to 1 if
506          * an entry is found which we believe starts citserver.
507          */
508         infp = fopen("/etc/inittab", "r");
509         if (infp == NULL) {
510                 return;
511         } else {
512                 while (fgets(buf, 256, infp) != NULL) {
513                         buf[strlen(buf) - 1] = 0;
514                         ptr = strtok(buf, ":");
515                         ptr = strtok(NULL, ":");
516                         ptr = strtok(NULL, ":");
517                         ptr = strtok(NULL, ":");
518                         if (ptr != NULL) {
519                                 if (!strncmp(ptr, looking_for, strlen(looking_for))) {
520                                         ++have_entry;
521                                 }
522                         }
523                 }
524                 fclose(infp);
525         }
526
527         /* If there's already an entry, then we have nothing left to do. */
528         if (have_entry > 0)
529                 return;
530
531         /* Otherwise, prompt the user to create an entry. */
532         sprintf(question,
533                 "There is no '%s' entry in /etc/inittab.\nWould you like to add one?",
534                 looking_for);
535         if (yesno(question) == 0)
536                 return;
537
538         /* Generate a unique entry name for /etc/inittab */
539         sprintf(entryname, "c0");
540         do {
541                 ++entryname[1];
542                 if (entryname[1] > '9') {
543                         entryname[1] = 0;
544                         ++entryname[0];
545                         if (entryname[0] > 'z') {
546                                 display_error(
547                                    "Can't generate a unique entry name");
548                                 return;
549                         }
550                 }
551                 sprintf(buf,
552                      "grep %s: /etc/inittab >/dev/null 2>&1", entryname);
553         } while (system(buf) == 0);
554
555         /* Now write it out to /etc/inittab */
556         infp = fopen("/etc/inittab", "a");
557         if (infp == NULL) {
558                 display_error(strerror(errno));
559         } else {
560                 fprintf(infp, "# Start the Citadel/UX server...\n");
561                 fprintf(infp, "%s:2345:respawn:%s -h%s\n",
562                         entryname, looking_for, setup_directory);
563                 fclose(infp);
564                 need_init_q = 1;
565         }
566 }
567
568
569
570 void set_str_val(int msgpos, char str[])
571 {
572         char buf[4096];
573         char setupmsg[4096];
574         char tempfile[64];
575         FILE *fp;
576
577         sprintf(tempfile, tmpnam(NULL));
578
579         switch (setup_type) {
580         case UI_TEXT:
581                 title(setup_titles[msgpos]);
582                 print_setup(msgpos);
583                 if (msgpos == 11)
584                         dump_access_levels();
585                 printf("This is currently set to:\n%s\n", str);
586                 printf("Enter new value or press return to leave unchanged:\n");
587                 fgets(buf, 4096, stdin);
588                 buf[strlen(buf) - 1] = 0;
589                 if (strlen(buf) != 0)
590                         strcpy(str, buf);
591                 break;
592         case UI_DIALOG:
593                 get_setup_msg(setupmsg, msgpos);
594                 sprintf(buf,
595                         "dialog --title \"%s\" --inputbox \"\n%s\n\" 20 80 \"%s\" 2>%s",
596                         setup_titles[msgpos],
597                         setupmsg,
598                         str, tempfile);
599                 if (system(buf) == 0) {
600                         fp = fopen(tempfile, "rb");
601                         fgets(str, 4095, fp);
602                         fclose(fp);
603                         if (strlen(str) > 0)
604                                 if (str[strlen(str) - 1] == 10)
605                                         str[strlen(str) - 1] = 0;
606                 }
607                 break;
608 #ifdef HAVE_CURSES_H
609         case UI_CURSES:
610                 clear();
611                 move(1, ((80 - strlen(setup_titles[msgpos])) / 2));
612                 standout();
613                 printw("%s", setup_titles[msgpos]);
614                 standend();
615                 move(3, 0);
616                 get_setup_msg(setupmsg, msgpos);
617                 printw("%s", setupmsg);
618                 refresh();
619                 getlin(20, 0, str, 80);
620                 break;
621 #endif
622         }
623 }
624
625 void set_int_val(int msgpos, int *ip)
626 {
627         char buf[16];
628         sprintf(buf, "%d", (int) *ip);
629         set_str_val(msgpos, buf);
630         *ip = atoi(buf);
631 }
632
633
634 void set_char_val(int msgpos, char *ip)
635 {
636         char buf[16];
637         sprintf(buf, "%d", (int) *ip);
638         set_str_val(msgpos, buf);
639         *ip = (char) atoi(buf);
640 }
641
642
643 void set_long_val(int msgpos, long int *ip)
644 {
645         char buf[16];
646         sprintf(buf, "%ld", *ip);
647         set_str_val(msgpos, buf);
648         *ip = atol(buf);
649 }
650
651
652 void edit_value(int curr)
653 {
654         int a;
655
656         switch (curr) {
657
658         case 1:
659                 set_str_val(curr, config.c_sysadm);
660                 break;
661
662         case 2:
663                 set_int_val(curr, &config.c_bbsuid);
664                 break;
665
666         case 3:
667                 set_str_val(curr, config.c_bucket_dir);
668                 config.c_bucket_dir[14] = 0;
669                 for (a = 0; a < strlen(config.c_bucket_dir); ++a)
670                         if (!isalpha(config.c_bucket_dir[a]))
671                                 strcpy(&config.c_bucket_dir[a],
672                                        &config.c_bucket_dir[a + 1]);
673                 break;
674
675         case 4:
676                 set_int_val(curr, &config.c_port_number);
677                 break;
678
679
680         }
681 }
682
683 /*
684  * (re-)write the config data to disk
685  */
686 void write_config_to_disk(void)
687 {
688         FILE *fp;
689         int fd;
690
691         if ((fd = creat("citadel.config", S_IRUSR | S_IWUSR)) == -1) {
692                 display_error("setup: cannot open citadel.config");
693                 cleanup(1);
694         }
695         fp = fdopen(fd, "wb");
696         if (fp == NULL) {
697                 display_error("setup: cannot open citadel.config");
698                 cleanup(1);
699         }
700         fwrite((char *) &config, sizeof(struct config), 1, fp);
701         fclose(fp);
702 }
703
704
705
706
707 /*
708  * Figure out what type of user interface we're going to use
709  */
710 int discover_ui(void)
711 {
712
713 #ifdef HAVE_CURSES_H
714         return UI_CURSES;
715 #endif
716
717         if (system("dialog -h </dev/null 2>&1 |grep Savio") == 0) {
718                 return UI_DIALOG;
719         }
720         return UI_TEXT;
721 }
722
723
724
725
726
727 int main(int argc, char *argv[])
728 {
729         int a;
730         int curr;
731         char aaa[128];
732         FILE *fp;
733         int old_setup_level = 0;
734         int info_only = 0;
735         struct utsname my_utsname;
736         struct passwd *pw;
737         struct hostent *he;
738         gid_t gid;
739
740         /* set an invalid setup type */
741         setup_type = (-1);
742
743         /* parse command line args */
744         for (a = 0; a < argc; ++a) {
745                 if (!strncmp(argv[a], "-u", 2)) {
746                         strcpy(aaa, argv[a]);
747                         strcpy(aaa, &aaa[2]);
748                         setup_type = atoi(aaa);
749                 }
750                 if (!strcmp(argv[a], "-i")) {
751                         info_only = 1;
752                 }
753         }
754
755
756         /* If a setup type was not specified, try to determine automatically
757          * the best one to use out of all available types.
758          */
759         if (setup_type < 0) {
760                 setup_type = discover_ui();
761         }
762 #ifdef HAVE_CURSES_H
763         if (setup_type == UI_CURSES) {
764                 initscr();
765                 raw();
766                 noecho();
767         }
768 #endif
769
770         if (info_only == 1) {
771                 important_message("Citadel/UX Setup", CITADEL);
772                 cleanup(0);
773         }
774         /* Get started in a valid setup directory. */
775         strcpy(setup_directory, BBSDIR);
776         set_str_val(0, setup_directory);
777         if (chdir(setup_directory) != 0) {
778                 important_message("Citadel/UX Setup",
779                           "The directory you specified does not exist.");
780                 cleanup(errno);
781         }
782         /* Determine our host name, in case we need to use it as a default */
783         uname(&my_utsname);
784
785         /* Now begin. */
786         switch (setup_type) {
787
788         case UI_TEXT:
789                 printf("\n\n\n               *** Citadel/UX setup program ***\n\n");
790                 break;
791
792         case UI_DIALOG:
793                 system("exec clear");
794                 break;
795
796         }
797
798         /*
799          * What we're going to try to do here is append a whole bunch of
800          * nulls to the citadel.config file, so we can keep the old config
801          * values if they exist, but if the file is missing or from an
802          * earlier version with a shorter config structure, when setup tries
803          * to read the old config parameters, they'll all come up zero.
804          * The length of the config file will be set to what it's supposed
805          * to be when we rewrite it, because we replace the old file with a
806          * completely new copy.  (Neat, eh?)
807          */
808
809         if ((a = open("citadel.config", O_WRONLY | O_CREAT | O_APPEND,
810                       S_IRUSR | S_IWUSR)) == -1) {
811                 display_error("setup: cannot append citadel.config");
812                 cleanup(errno);
813         }
814         fp = fdopen(a, "ab");
815         if (fp == NULL) {
816                 display_error("setup: cannot append citadel.config");
817                 cleanup(errno);
818         }
819         for (a = 0; a < sizeof(struct config); ++a)
820                 putc(0, fp);
821         fclose(fp);
822
823         /* now we re-open it, and read the old or blank configuration */
824         fp = fopen("citadel.config", "rb");
825         if (fp == NULL) {
826                 display_error("setup: cannot open citadel.config");
827                 cleanup(errno);
828         }
829         fread((char *) &config, sizeof(struct config), 1, fp);
830         fclose(fp);
831
832
833         /* set some sample/default values in place of blanks... */
834         if (strlen(config.c_nodename) == 0)
835                 safestrncpy(config.c_nodename, my_utsname.nodename,
836                             sizeof config.c_nodename);
837         strtok(config.c_nodename, ".");
838         if (strlen(config.c_fqdn) == 0) {
839                 if ((he = gethostbyname(my_utsname.nodename)) != NULL)
840                         safestrncpy(config.c_fqdn, he->h_name,
841                                     sizeof config.c_fqdn);
842                 else
843                         safestrncpy(config.c_fqdn, my_utsname.nodename,
844                                     sizeof config.c_fqdn);
845         }
846         if (strlen(config.c_humannode) == 0)
847                 strcpy(config.c_humannode, "My System");
848         if (strlen(config.c_phonenum) == 0)
849                 strcpy(config.c_phonenum, "US 800 555 1212");
850         if (config.c_initax == 0)
851                 config.c_initax = 1;
852         if (strlen(config.c_moreprompt) == 0)
853                 strcpy(config.c_moreprompt, "<more>");
854         if (strlen(config.c_twitroom) == 0)
855                 strcpy(config.c_twitroom, "Trashcan");
856         if (strlen(config.c_bucket_dir) == 0)
857                 strcpy(config.c_bucket_dir, "bitbucket");
858         if (strlen(config.c_net_password) == 0)
859                 strcpy(config.c_net_password, "netpassword");
860         if (config.c_port_number == 0) {
861                 config.c_port_number = 504;
862         }
863         if (config.c_ipgm_secret == 0) {
864                 srand(getpid());
865                 config.c_ipgm_secret = rand();
866         }
867         if (config.c_sleeping == 0) {
868                 config.c_sleeping = 900;
869         }
870         if (config.c_bbsuid == 0) {
871                 pw = getpwnam("citadel");
872                 if (pw != NULL)
873                         config.c_bbsuid = pw->pw_uid;
874         }
875         if (config.c_bbsuid == 0) {
876                 pw = getpwnam("bbs");
877                 if (pw != NULL)
878                         config.c_bbsuid = pw->pw_uid;
879         }
880         if (config.c_bbsuid == 0) {
881                 pw = getpwnam("guest");
882                 if (pw != NULL)
883                         config.c_bbsuid = pw->pw_uid;
884         }
885         if (config.c_createax == 0) {
886                 config.c_createax = 3;
887         }
888         /*
889          * Negative values for maxsessions are not allowed.
890          */
891         if (config.c_maxsessions < 0) {
892                 config.c_maxsessions = 0;
893         }
894         /* We need a system default message expiry policy, because this is
895          * the top level and there's no 'higher' policy to fall back on.
896          */
897         if (config.c_ep.expire_mode == 0) {
898                 config.c_ep.expire_mode = EXPIRE_NUMMSGS;
899                 config.c_ep.expire_value = 150;
900         }
901
902
903         /* Default maximum message length is 'unlimited' (max int)
904          * and the minimum is 8192
905          */
906         if (config.c_maxmsglen <= 0)
907                 config.c_maxmsglen = INT_MAX;
908         if (config.c_maxmsglen < 8192)
909                 config.c_maxmsglen = 8192;
910
911
912         /* Go through a series of dialogs prompting for config info */
913         for (curr = 1; curr <= MAXSETUP; ++curr) {
914                 edit_value(curr);
915         }
916
917         /*
918            if (setuid(config.c_bbsuid) != 0) {
919            important_message("Citadel/UX Setup",
920            "Failed to change the user ID to your BBS user.");
921            cleanup(errno);
922            }
923          */
924
925 /***** begin version update section ***** */
926         /* take care of any updating that is necessary */
927
928         old_setup_level = config.c_setup_level;
929
930         if (old_setup_level == 0)
931                 goto NEW_INST;
932
933         if (old_setup_level < 323) {
934                 important_message("Citadel/UX Setup",
935                                   "This Citadel/UX installation is too old to be upgraded.");
936                 cleanup(1);
937         }
938         write_config_to_disk();
939
940         if ((config.c_setup_level / 10) == 32) {
941                 important_msgnum(31);
942                 cleanup(0);
943         }
944         if (config.c_setup_level < 400) {
945                 config.c_setup_level = 400;
946         }
947         /* end of 3.23 -> 4.00 update section */
948
949         /* end of 4.00 -> 4.02 update section */
950
951         old_setup_level = config.c_setup_level;
952
953         /* end of version update section */
954
955 NEW_INST:
956         config.c_setup_level = REV_LEVEL;
957
958 /******************************************/
959
960         write_config_to_disk();
961
962         system("mkdir info 2>/dev/null");       /* Create these */
963         system("mkdir bio 2>/dev/null");
964         system("mkdir userpics 2>/dev/null");
965         system("mkdir messages 2>/dev/null");
966         system("mkdir help 2>/dev/null");
967         system("mkdir images 2>/dev/null");
968         sprintf(aaa, "mkdir %s 2>/dev/null", config.c_bucket_dir);
969         system(aaa);
970
971         /* Delete a bunch of old files from Citadel v4; don't need anymore */
972         system("rm -fr ./chatpipes ./expressmsgs sessions 2>/dev/null");
973
974         check_services_entry(); /* Check /etc/services */
975         check_inittab_entry();  /* Check /etc/inittab */
976
977         if ((pw = getpwuid(config.c_bbsuid)) == NULL)
978                 gid = getgid();
979         else
980                 gid = pw->pw_gid;
981
982         progress("Setting file permissions", 0, 5);
983         chown(".", config.c_bbsuid, gid);
984         progress("Setting file permissions", 1, 5);
985         chown("citadel.config", config.c_bbsuid, gid);
986         progress("Setting file permissions", 2, 5);
987         sprintf(aaa, "find . | grep -v chkpwd | xargs chown %d:%d 2>/dev/null",
988                 config.c_bbsuid, gid);
989         system(aaa);
990         progress("Setting file permissions", 3, 5);
991         chmod("citadel.config", S_IRUSR | S_IWUSR);
992         progress("Setting file permissions", 4, 5);
993
994         important_message("Setup finished",
995             "Setup is finished.  You may now start the Citadel server.");
996
997
998         cleanup(0);
999         return 0;
1000 }