* First cut at Solaris fixes. There may still be some *printf("%s", NULL)
[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 (REMOVED) */
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 #ifdef HAVE_CURSES_H
265         case UI_CURSES:
266                 do {
267                         clear();
268                         standout();
269                         mvprintw(1, 20, "Question");
270                         standend();
271                         mvprintw(10, 0, "%-80s", question);
272                         mvprintw(20, 0, "%80s", "");
273                         mvprintw(20, 0, "Yes/No -> ");
274                         refresh();
275                         answer = getch();
276                         answer = tolower(answer);
277                         if (answer == 'y')
278                                 answer = 1;
279                         else if (answer == 'n')
280                                 answer = 0;
281                 } while ((answer < 0) || (answer > 1));
282                 break;
283 #endif
284
285         }
286         return (answer);
287 }
288
289
290
291 void dump_access_levels(void)
292 {
293         int a;
294         for (a = 0; a <= 6; ++a)
295                 printf("%d %s\n", a, axdefs[a]);
296 }
297
298 void get_setup_msg(char *dispbuf, int msgnum)
299 {
300         int a, b;
301
302         a = 0;
303         b = 0;
304         while (atol(setup_text[a]) != msgnum)
305                 ++a;
306         ++a;
307         strcpy(dispbuf, "");
308         do {
309                 strcat(dispbuf, setup_text[a++]);
310                 strcat(dispbuf, "\n");
311         } while (atol(setup_text[a]) != (msgnum + 1));
312 }
313
314 void print_setup(int msgnum)
315 {
316         char dispbuf[4096];
317
318         get_setup_msg(dispbuf, msgnum);
319         printf("\n\n%s\n\n", dispbuf);
320 }
321
322
323 void important_message(char *title, char *msgtext)
324 {
325
326         switch (setup_type) {
327
328         case UI_TEXT:
329                 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");
330                 printf("       %s \n\n%s\n\n", title, msgtext);
331                 hit_any_key();
332                 break;
333
334 #ifdef HAVE_CURSES_H
335         case UI_CURSES:
336                 clear();
337                 move(1, 20);
338                 standout();
339                 printw("  Important Message  ");
340                 standend();
341                 move(3, 0);
342                 printw("%s", msgtext);
343                 refresh();
344                 hit_any_key();
345                 break;
346 #endif
347
348         }
349 }
350
351 void important_msgnum(int msgnum)
352 {
353         char dispbuf[4096];
354
355         get_setup_msg(dispbuf, msgnum);
356         important_message("Important Message", dispbuf);
357 }
358
359 void display_error(char *error_message)
360 {
361         important_message("Error", error_message);
362 }
363
364 void progress(char *text, long int curr, long int cmax)
365 {
366         static long dots_printed;
367         long a;
368
369         switch (setup_type) {
370
371         case UI_TEXT:
372                 if (curr == 0) {
373                         printf("%s\n", text);
374                         printf("..........................");
375                         printf("..........................");
376                         printf("..........................\r");
377                         fflush(stdout);
378                         dots_printed = 0;
379                 } else if (curr == cmax) {
380                         printf("\r%79s\n", "");
381                 } else {
382                         a = (curr * 100) / cmax;
383                         a = a * 78;
384                         a = a / 100;
385                         while (dots_printed < a) {
386                                 printf("*");
387                                 ++dots_printed;
388                                 fflush(stdout);
389                         }
390                 }
391                 break;
392
393 #ifdef HAVE_CURSES_H
394         case UI_CURSES:
395                 if (curr == 0) {
396                         clear();
397                         move(5, 20);
398                         printw("%s\n", text);
399                         move(10, 1);
400                         printf("..........................");
401                         printf("..........................");
402                         printf("..........................\r");
403                         refresh();
404                         dots_printed = 0;
405                 } else if (curr == cmax) {
406                         clear();
407                         refresh();
408                 } else {
409                         a = (curr * 100) / cmax;
410                         a = a * 78;
411                         a = a / 100;
412                         move(10, 1);
413                         dots_printed = 0;
414                         while (dots_printed < a) {
415                                 printw("*");
416                                 ++dots_printed;
417                         }
418                         refresh();
419                 }
420                 break;
421 #endif
422
423         }
424 }
425
426
427
428 /*
429  * check_services_entry()  -- Make sure "citadel" is in /etc/services
430  *
431  */
432 void check_services_entry(void)
433 {
434         char question[128];
435         FILE *sfp;
436
437         sprintf(question,
438                 "There is no '%s' entry in /etc/services.  Would you like to add one?",
439                 SERVICE_NAME);
440
441         if (getservbyname(SERVICE_NAME, PROTO_NAME) == NULL) {
442                 if (yesno(question) == 1) {
443                         sfp = fopen("/etc/services", "a");
444                         if (sfp == NULL) {
445                                 display_error(strerror(errno));
446                         } else {
447                                 fprintf(sfp, "%s                504/tcp\n",
448                                         SERVICE_NAME);
449                                 fclose(sfp);
450                         }
451                 }
452         }
453 }
454
455
456 /*
457  * check_inittab_entry()  -- Make sure "citadel" is in /etc/inittab
458  *
459  */
460 void check_inittab_entry(void)
461 {
462         FILE *infp;
463         char buf[256];
464         char looking_for[256];
465         char question[128];
466         char *ptr;
467         int have_entry = 0;
468         char entryname[3];
469
470         /* Determine the fully qualified path name of citserver */
471         sprintf(looking_for, "%s/citserver ", BBSDIR);
472
473         /* Pound through /etc/inittab line by line.  Set have_entry to 1 if
474          * an entry is found which we believe starts citserver.
475          */
476         infp = fopen("/etc/inittab", "r");
477         if (infp == NULL) {
478                 return;
479         } else {
480                 while (fgets(buf, 256, infp) != NULL) {
481                         buf[strlen(buf) - 1] = 0;
482                         ptr = strtok(buf, ":");
483                         ptr = strtok(NULL, ":");
484                         ptr = strtok(NULL, ":");
485                         ptr = strtok(NULL, ":");
486                         if (ptr != NULL) {
487                                 if (!strncmp(ptr, looking_for, strlen(looking_for))) {
488                                         ++have_entry;
489                                 }
490                         }
491                 }
492                 fclose(infp);
493         }
494
495         /* If there's already an entry, then we have nothing left to do. */
496         if (have_entry > 0)
497                 return;
498
499         /* Otherwise, prompt the user to create an entry. */
500         sprintf(question,
501                 "There is no '%s' entry in /etc/inittab.\nWould you like to add one?",
502                 looking_for);
503         if (yesno(question) == 0)
504                 return;
505
506         /* Generate a unique entry name for /etc/inittab */
507         sprintf(entryname, "c0");
508         do {
509                 ++entryname[1];
510                 if (entryname[1] > '9') {
511                         entryname[1] = 0;
512                         ++entryname[0];
513                         if (entryname[0] > 'z') {
514                                 display_error(
515                                    "Can't generate a unique entry name");
516                                 return;
517                         }
518                 }
519                 sprintf(buf,
520                      "grep %s: /etc/inittab >/dev/null 2>&1", entryname);
521         } while (system(buf) == 0);
522
523         /* Now write it out to /etc/inittab */
524         infp = fopen("/etc/inittab", "a");
525         if (infp == NULL) {
526                 display_error(strerror(errno));
527         } else {
528                 fprintf(infp, "# Start the Citadel/UX server...\n");
529                 fprintf(infp, "%s:2345:respawn:%s -h%s\n",
530                         entryname, looking_for, setup_directory);
531                 fclose(infp);
532                 need_init_q = 1;
533         }
534 }
535
536
537
538 void set_str_val(int msgpos, char str[])
539 {
540         char buf[4096];
541         char tempfile[64];
542         char setupmsg[256];
543
544         sprintf(tempfile, tmpnam(NULL));
545         strcpy(setupmsg, "");
546
547         switch (setup_type) {
548         case UI_TEXT:
549                 title(setup_titles[msgpos]);
550                 print_setup(msgpos);
551                 if (msgpos == 11)
552                         dump_access_levels();
553                 printf("This is currently set to:\n%s\n", str);
554                 printf("Enter new value or press return to leave unchanged:\n");
555                 fgets(buf, 4096, stdin);
556                 buf[strlen(buf) - 1] = 0;
557                 if (strlen(buf) != 0)
558                         strcpy(str, buf);
559                 break;
560 #ifdef HAVE_CURSES_H
561         case UI_CURSES:
562                 clear();
563                 move(1, ((80 - strlen(setup_titles[msgpos])) / 2));
564                 standout();
565                 printw("%s", setup_titles[msgpos]);
566                 standend();
567                 move(3, 0);
568                 get_setup_msg(setupmsg, msgpos);
569                 printw("%s", setupmsg);
570                 refresh();
571                 getlin(20, 0, str, 80);
572                 break;
573 #endif
574         }
575 }
576
577 void set_int_val(int msgpos, int *ip)
578 {
579         char buf[16];
580         sprintf(buf, "%d", (int) *ip);
581         set_str_val(msgpos, buf);
582         *ip = atoi(buf);
583 }
584
585
586 void set_char_val(int msgpos, char *ip)
587 {
588         char buf[16];
589         sprintf(buf, "%d", (int) *ip);
590         set_str_val(msgpos, buf);
591         *ip = (char) atoi(buf);
592 }
593
594
595 void set_long_val(int msgpos, long int *ip)
596 {
597         char buf[16];
598         sprintf(buf, "%ld", *ip);
599         set_str_val(msgpos, buf);
600         *ip = atol(buf);
601 }
602
603
604 void edit_value(int curr)
605 {
606         int a;
607         long l;
608
609         switch (curr) {
610
611         case 1:
612                 set_str_val(curr, config.c_sysadm);
613                 break;
614
615         case 2:
616                 l = config.c_bbsuid;
617                 set_long_val(curr, &l);
618                 config.c_bbsuid = l;
619                 break;
620
621         case 3:
622                 set_str_val(curr, config.c_bucket_dir);
623                 config.c_bucket_dir[14] = 0;
624                 for (a = 0; a < strlen(config.c_bucket_dir); ++a)
625                         if (!isalpha(config.c_bucket_dir[a]))
626                                 strcpy(&config.c_bucket_dir[a],
627                                        &config.c_bucket_dir[a + 1]);
628                 break;
629
630         case 4:
631                 set_int_val(curr, &config.c_port_number);
632                 break;
633
634
635         }
636 }
637
638 /*
639  * (re-)write the config data to disk
640  */
641 void write_config_to_disk(void)
642 {
643         FILE *fp;
644         int fd;
645
646         if ((fd = creat("citadel.config", S_IRUSR | S_IWUSR)) == -1) {
647                 display_error("setup: cannot open citadel.config");
648                 cleanup(1);
649         }
650         fp = fdopen(fd, "wb");
651         if (fp == NULL) {
652                 display_error("setup: cannot open citadel.config");
653                 cleanup(1);
654         }
655         fwrite((char *) &config, sizeof(struct config), 1, fp);
656         fclose(fp);
657 }
658
659
660
661
662 /*
663  * Figure out what type of user interface we're going to use
664  */
665 int discover_ui(void)
666 {
667
668 #ifdef HAVE_CURSES_H
669         return UI_CURSES;
670 #endif
671         return UI_TEXT;
672 }
673
674
675
676
677
678 int main(int argc, char *argv[])
679 {
680         int a;
681         int curr;
682         char aaa[128];
683         FILE *fp;
684         int old_setup_level = 0;
685         int info_only = 0;
686         struct utsname my_utsname;
687         struct passwd *pw;
688         struct hostent *he;
689         gid_t gid;
690
691         /* set an invalid setup type */
692         setup_type = (-1);
693
694         /* parse command line args */
695         for (a = 0; a < argc; ++a) {
696                 if (!strncmp(argv[a], "-u", 2)) {
697                         strcpy(aaa, argv[a]);
698                         strcpy(aaa, &aaa[2]);
699                         setup_type = atoi(aaa);
700                 }
701                 if (!strcmp(argv[a], "-i")) {
702                         info_only = 1;
703                 }
704         }
705
706
707         /* If a setup type was not specified, try to determine automatically
708          * the best one to use out of all available types.
709          */
710         if (setup_type < 0) {
711                 setup_type = discover_ui();
712         }
713 #ifdef HAVE_CURSES_H
714         if (setup_type == UI_CURSES) {
715                 initscr();
716                 raw();
717                 noecho();
718         }
719 #endif
720
721         if (info_only == 1) {
722                 important_message("Citadel/UX Setup", CITADEL);
723                 cleanup(0);
724         }
725         /* Get started in a valid setup directory. */
726         strcpy(setup_directory, BBSDIR);
727         set_str_val(0, setup_directory);
728         if (chdir(setup_directory) != 0) {
729                 important_message("Citadel/UX Setup",
730                           "The directory you specified does not exist.");
731                 cleanup(errno);
732         }
733         /* Determine our host name, in case we need to use it as a default */
734         uname(&my_utsname);
735
736         /* Now begin. */
737         switch (setup_type) {
738
739         case UI_TEXT:
740                 printf("\n\n\n               *** Citadel/UX setup program ***\n\n");
741                 break;
742
743         }
744
745         /*
746          * What we're going to try to do here is append a whole bunch of
747          * nulls to the citadel.config file, so we can keep the old config
748          * values if they exist, but if the file is missing or from an
749          * earlier version with a shorter config structure, when setup tries
750          * to read the old config parameters, they'll all come up zero.
751          * The length of the config file will be set to what it's supposed
752          * to be when we rewrite it, because we replace the old file with a
753          * completely new copy.  (Neat, eh?)
754          */
755
756         if ((a = open("citadel.config", O_WRONLY | O_CREAT | O_APPEND,
757                       S_IRUSR | S_IWUSR)) == -1) {
758                 display_error("setup: cannot append citadel.config");
759                 cleanup(errno);
760         }
761         fp = fdopen(a, "ab");
762         if (fp == NULL) {
763                 display_error("setup: cannot append citadel.config");
764                 cleanup(errno);
765         }
766         for (a = 0; a < sizeof(struct config); ++a)
767                 putc(0, fp);
768         fclose(fp);
769
770         /* now we re-open it, and read the old or blank configuration */
771         fp = fopen("citadel.config", "rb");
772         if (fp == NULL) {
773                 display_error("setup: cannot open citadel.config");
774                 cleanup(errno);
775         }
776         fread((char *) &config, sizeof(struct config), 1, fp);
777         fclose(fp);
778
779
780         /* set some sample/default values in place of blanks... */
781         if (strlen(config.c_nodename) == 0)
782                 safestrncpy(config.c_nodename, my_utsname.nodename,
783                             sizeof config.c_nodename);
784         strtok(config.c_nodename, ".");
785         if (strlen(config.c_fqdn) == 0) {
786                 if ((he = gethostbyname(my_utsname.nodename)) != NULL)
787                         safestrncpy(config.c_fqdn, he->h_name,
788                                     sizeof config.c_fqdn);
789                 else
790                         safestrncpy(config.c_fqdn, my_utsname.nodename,
791                                     sizeof config.c_fqdn);
792         }
793         if (strlen(config.c_humannode) == 0)
794                 strcpy(config.c_humannode, "My System");
795         if (strlen(config.c_phonenum) == 0)
796                 strcpy(config.c_phonenum, "US 800 555 1212");
797         if (config.c_initax == 0)
798                 config.c_initax = 1;
799         if (strlen(config.c_moreprompt) == 0)
800                 strcpy(config.c_moreprompt, "<more>");
801         if (strlen(config.c_twitroom) == 0)
802                 strcpy(config.c_twitroom, "Trashcan");
803         if (strlen(config.c_bucket_dir) == 0)
804                 strcpy(config.c_bucket_dir, "bitbucket");
805         if (strlen(config.c_net_password) == 0)
806                 strcpy(config.c_net_password, "netpassword");
807         if (config.c_port_number == 0) {
808                 config.c_port_number = 504;
809         }
810         if (config.c_ipgm_secret == 0) {
811                 srand(getpid());
812                 config.c_ipgm_secret = rand();
813         }
814         if (config.c_sleeping == 0) {
815                 config.c_sleeping = 900;
816         }
817         if (config.c_bbsuid == 0) {
818                 pw = getpwnam("citadel");
819                 if (pw != NULL)
820                         config.c_bbsuid = pw->pw_uid;
821         }
822         if (config.c_bbsuid == 0) {
823                 pw = getpwnam("bbs");
824                 if (pw != NULL)
825                         config.c_bbsuid = pw->pw_uid;
826         }
827         if (config.c_bbsuid == 0) {
828                 pw = getpwnam("guest");
829                 if (pw != NULL)
830                         config.c_bbsuid = pw->pw_uid;
831         }
832         if (config.c_createax == 0) {
833                 config.c_createax = 3;
834         }
835         /*
836          * Negative values for maxsessions are not allowed.
837          */
838         if (config.c_maxsessions < 0) {
839                 config.c_maxsessions = 0;
840         }
841         /* We need a system default message expiry policy, because this is
842          * the top level and there's no 'higher' policy to fall back on.
843          */
844         if (config.c_ep.expire_mode == 0) {
845                 config.c_ep.expire_mode = EXPIRE_NUMMSGS;
846                 config.c_ep.expire_value = 150;
847         }
848
849         /*
850          * Default port numbers for various services
851          */
852         if (config.c_pop3_port == 0) config.c_pop3_port = 110;
853         if (config.c_smtp_port == 0) config.c_smtp_port = 25;
854
855
856         /* Go through a series of dialogs prompting for config info */
857         for (curr = 1; curr <= MAXSETUP; ++curr) {
858                 edit_value(curr);
859         }
860
861         /*
862            if (setuid(config.c_bbsuid) != 0) {
863            important_message("Citadel/UX Setup",
864            "Failed to change the user ID to your BBS user.");
865            cleanup(errno);
866            }
867          */
868
869 /***** begin version update section ***** */
870         /* take care of any updating that is necessary */
871
872         old_setup_level = config.c_setup_level;
873
874         if (old_setup_level == 0)
875                 goto NEW_INST;
876
877         if (old_setup_level < 323) {
878                 important_message("Citadel/UX Setup",
879                                   "This Citadel/UX installation is too old to be upgraded.");
880                 cleanup(1);
881         }
882         write_config_to_disk();
883
884         if ((config.c_setup_level / 10) == 32) {
885                 important_msgnum(31);
886                 cleanup(0);
887         }
888         if (config.c_setup_level < 400) {
889                 config.c_setup_level = 400;
890         }
891         /* end of 3.23 -> 4.00 update section */
892
893         /* end of 4.00 -> 4.02 update section */
894
895         old_setup_level = config.c_setup_level;
896
897         /* end of version update section */
898
899 NEW_INST:
900         config.c_setup_level = REV_LEVEL;
901
902 /******************************************/
903
904         write_config_to_disk();
905
906         system("mkdir info 2>/dev/null");       /* Create these */
907         system("mkdir bio 2>/dev/null");
908         system("mkdir userpics 2>/dev/null");
909         system("mkdir messages 2>/dev/null");
910         system("mkdir help 2>/dev/null");
911         system("mkdir images 2>/dev/null");
912         sprintf(aaa, "mkdir %s 2>/dev/null", config.c_bucket_dir);
913         system(aaa);
914
915         /* Delete a bunch of old files from Citadel v4; don't need anymore */
916         system("rm -fr ./chatpipes ./expressmsgs sessions 2>/dev/null");
917
918         check_services_entry(); /* Check /etc/services */
919         check_inittab_entry();  /* Check /etc/inittab */
920
921         if ((pw = getpwuid(config.c_bbsuid)) == NULL)
922                 gid = getgid();
923         else
924                 gid = pw->pw_gid;
925
926         progress("Setting file permissions", 0, 5);
927         chown(".", config.c_bbsuid, gid);
928         progress("Setting file permissions", 1, 5);
929         chown("citadel.config", config.c_bbsuid, gid);
930         progress("Setting file permissions", 2, 5);
931         sprintf(aaa, "find . | grep -v chkpwd | xargs chown %ld:%ld 2>/dev/null",
932                 (long)config.c_bbsuid, (long)gid);
933         system(aaa);
934         progress("Setting file permissions", 3, 5);
935         chmod("citadel.config", S_IRUSR | S_IWUSR);
936         progress("Setting file permissions", 4, 5);
937
938         important_message("Setup finished",
939             "Setup is finished.  You may now start the Citadel server.");
940
941
942         cleanup(0);
943         return 0;
944 }