]> code.citadel.org Git - citadel.git/blob - citadel/setup.c
* setup.c: removed all prompts that can be configured from within the
[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
661         fp=fopen("citadel.config","wb");
662         if (fp==NULL) {
663                 display_error("setup: cannot open citadel.config");
664                 cleanup(1);
665                 }
666         fwrite((char *)&config,sizeof(struct config),1,fp);
667         fclose(fp);
668         }
669
670
671
672
673 /*
674  * Figure out what type of user interface we're going to use
675  */
676 int discover_ui(void) {
677
678 #ifdef HAVE_CURSES_H
679         return UI_CURSES;
680 #endif
681
682         if (system("dialog -h </dev/null 2>&1 |grep Savio")==0) {
683                 return UI_DIALOG;
684                 }
685
686         return UI_TEXT;
687         }
688
689
690
691
692
693 int main(int argc, char *argv[]) {
694         int a;
695         int curr;
696         char aaa[128];
697         FILE *fp;
698         int old_setup_level = 0;
699         int info_only = 0;
700         struct utsname my_utsname;
701         struct passwd *pw;
702
703         /* set an invalid setup type */
704         setup_type = (-1);
705
706         /* parse command line args */
707         for (a=0; a<argc; ++a) {
708                 if (!strncmp(argv[a], "-u", 2)) {
709                         strcpy(aaa, argv[a]);
710                         strcpy(aaa, &aaa[2]);
711                         setup_type = atoi(aaa);
712                         }
713                 if (!strcmp(argv[a], "-i")) {
714                         info_only = 1;
715                         }
716                 }
717
718
719         /* If a setup type was not specified, try to determine automatically
720          * the best one to use out of all available types.
721          */
722         if (setup_type < 0) {
723                 setup_type = discover_ui();
724                 }
725
726 #ifdef HAVE_CURSES_H
727         if (setup_type == UI_CURSES) {
728                 initscr();
729                 raw();
730                 noecho();
731                 }
732 #endif
733
734         if (info_only == 1) {
735                 important_message("Citadel/UX Setup", CITADEL);
736                 cleanup(0);
737                 }
738
739         /* Get started in a valid setup directory. */
740         strcpy(setup_directory, BBSDIR);
741         set_str_val(0, setup_directory);
742         if (chdir(setup_directory) != 0) {
743                 important_message("Citadel/UX Setup",
744                         "The directory you specified does not exist.");
745                 cleanup(errno);
746                 }
747
748         /* Determine our host name, in case we need to use it as a default */
749         uname(&my_utsname);
750
751         /* Now begin. */
752         switch(setup_type) {
753                 
754                 case UI_TEXT:
755                         printf("\n\n\n               *** Citadel/UX setup program ***\n\n");
756                         break;
757                 
758                 case UI_DIALOG:
759                         system("exec clear");
760                         break;
761                         
762                 }
763
764         /*
765          * What we're going to try to do here is append a whole bunch of
766          * nulls to the citadel.config file, so we can keep the old config
767          * values if they exist, but if the file is missing or from an
768          * earlier version with a shorter config structure, when setup tries
769          * to read the old config parameters, they'll all come up zero.
770          * The length of the config file will be set to what it's supposed
771          * to be when we rewrite it, because we replace the old file with a
772          * completely new copy.  (Neat, eh?)
773          */
774
775         fp=fopen("citadel.config","ab");
776         if (fp==NULL) {
777                 display_error("setup: cannot append citadel.config");
778                 cleanup(errno);
779                 }
780         for (a=0; a<sizeof(struct config); ++a) putc(0,fp);
781         fclose(fp);
782
783         /* now we re-open it, and read the old or blank configuration */
784         fp=fopen("citadel.config","rb");
785         if (fp==NULL) {
786                 display_error("setup: cannot open citadel.config");
787                 cleanup(errno);
788                 }
789         fread((char *)&config,sizeof(struct config),1,fp);
790         fclose(fp);
791
792
793         /* set some sample/default values in place of blanks... */
794         if (strlen(config.c_nodename)==0)
795                 strcpy(config.c_nodename, my_utsname.nodename);
796         if (strlen(config.c_fqdn)==0)
797                 sprintf(config.c_fqdn, "%s.local", my_utsname.nodename);
798         if (strlen(config.c_humannode)==0)
799                 strcpy(config.c_humannode,"My System");
800         if (strlen(config.c_phonenum)==0)
801                 strcpy(config.c_phonenum,"US 800 555 1212");
802         if (config.c_initax == 0)
803                 config.c_initax = 1;
804         if (strlen(config.c_moreprompt)==0)
805                 strcpy(config.c_moreprompt,"<more>");
806         if (strlen(config.c_twitroom)==0)
807                 strcpy(config.c_twitroom,"Trashcan");
808         if (strlen(config.c_bucket_dir)==0)
809                 strcpy(config.c_bucket_dir,"bitbucket");
810         if (strlen(config.c_net_password)==0)
811                 strcpy(config.c_net_password,"netpassword");
812         if (config.c_port_number == 0) {
813                 config.c_port_number = 504;
814                 }
815         if (config.c_ipgm_secret == 0) {
816                 srand(getpid());
817                 config.c_ipgm_secret = rand();
818                 }
819         if (config.c_sleeping == 0) {
820                 config.c_sleeping = 900;
821                 }
822         if (config.c_bbsuid == 0) {
823                 pw = getpwnam("citadel");
824                 if (pw != NULL) config.c_bbsuid = pw->pw_uid;
825                 }
826         if (config.c_bbsuid == 0) {
827                 pw = getpwnam("bbs");
828                 if (pw != NULL) config.c_bbsuid = pw->pw_uid;
829                 }
830         if (config.c_bbsuid == 0) {
831                 pw = getpwnam("guest");
832                 if (pw != NULL) config.c_bbsuid = pw->pw_uid;
833                 }
834         
835         /*
836          * Make sure that at least one concurrent session is allowed!
837          */
838         if (config.c_maxsessions < 1) {
839                 config.c_maxsessions = 1;
840                 }
841
842         /* We need a system default message expiry policy, because this is
843          * the top level and there's no 'higher' policy to fall back on.
844          */
845         if (config.c_ep.expire_mode == 0) {
846                 config.c_ep.expire_mode = EXPIRE_NUMMSGS;
847                 config.c_ep.expire_value = 150;
848                 }
849
850         /* Go through a series of dialogs prompting for config info */
851         for (curr = 1; curr <= MAXSETUP; ++curr) {
852                 edit_value(curr);
853                 }
854
855         /*
856         if (setuid(config.c_bbsuid) != 0) {
857                 important_message("Citadel/UX Setup",
858                         "Failed to change the user ID to your BBS user.");
859                 cleanup(errno);
860                 }
861         */
862
863         /***** begin version update section ***** */
864         /* take care of any updating that is necessary */
865
866         old_setup_level = config.c_setup_level;
867
868         if (old_setup_level == 0) goto NEW_INST;
869         
870         if (old_setup_level < 323) {
871                 important_message("Citadel/UX Setup",
872                         "This Citadel/UX installation is too old to be upgraded.");
873                 cleanup(1);
874                 }
875
876         write_config_to_disk();
877
878         if ((config.c_setup_level / 10) == 32) {
879                 important_msgnum(31);
880                 cleanup(0);
881                 }
882
883         if (config.c_setup_level < 400) {
884                 config.c_setup_level = 400;
885                 }
886
887         /* end of 3.23 -> 4.00 update section */
888
889         /* end of 4.00 -> 4.02 update section */
890
891         old_setup_level = config.c_setup_level;
892
893         /* end of version update section */
894
895 NEW_INST:
896         config.c_setup_level = REV_LEVEL;
897
898 /******************************************/
899
900         write_config_to_disk();
901
902         system("mkdir info 2>/dev/null");               /* Create these */
903         system("mkdir bio 2>/dev/null");
904         system("mkdir userpics 2>/dev/null");
905         system("mkdir messages 2>/dev/null");
906         system("mkdir help 2>/dev/null");
907         system("mkdir images 2>/dev/null");
908         sprintf(aaa,"mkdir %s 2>/dev/null",config.c_bucket_dir);
909         system(aaa);
910
911         /* Delete a bunch of old files from Citadel v4; don't need anymore */
912         system("rm -fr ./chatpipes ./expressmsgs sessions 2>/dev/null");
913
914         check_services_entry();         /* Check /etc/services */
915         check_inittab_entry();          /* Check /etc/inittab */
916
917         progress("Setting file permissions", 0, 3);
918         chown(".", config.c_bbsuid, getgid());
919         progress("Setting file permissions", 1, 3);
920         chown("citadel.config", config.c_bbsuid, getgid());
921         progress("Setting file permissions", 2, 3);
922         sprintf(aaa, "find . -exec chown %d {} \\; 2>/dev/null",
923                 config.c_bbsuid);
924         system(aaa);
925         progress("Setting file permissions", 3, 3);
926
927         important_message("Setup finished", 
928                 "Setup is finished.  You may now start the Citadel server.");
929
930
931         cleanup(0);
932         return 0;
933 }