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