]> code.citadel.org Git - citadel.git/blob - citadel/setup.c
Now that we have a message base of unlimited size, setup doesn't have to ask
[citadel.git] / citadel / setup.c
1 /*
2  * Citadel/UX setup program
3  * v4.1 / by Art Cancro
4  * see copyright.txt for copyright information
5  *
6  * *** YOU MUST EDIT sysconfig.h >BEFORE< COMPILING SETUP ***
7  */
8
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <ctype.h>
14 #include <fcntl.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <netdb.h>
18 #include <errno.h>
19
20 #include "citadel.h"
21 #include "axdefs.h"
22 #include "sysdep.h"
23
24 #ifdef CURSES_INC
25 # ifdef OK
26 # undef OK
27 # endif
28 #include CURSES_INC
29 #endif
30
31 #define MAXSETUP 20
32
33 #define UI_TEXT         0       /* Default setup type -- text only */
34 #define UI_DIALOG       1       /* Use the 'dialog' program */
35 #define UI_CURSES       2       /* Use curses */
36
37 #define SERVICE_NAME    "citadel"
38 #define PROTO_NAME      "tcp"
39
40 int setup_type;
41 char setup_directory[128];
42 int need_init_q = 0;
43
44 char *setup_titles[] = {
45         "BBS Home Directory",
46         "Citadel node name",
47         "Fully Qualified Domain Name (FQDN)",
48         "Human-readable node name",
49         "Phone number",
50         "BBS City and State",
51         "System Administrator",
52         "BBS User ID",
53         "Password encryption seed",
54         "'Room Creator = Room Aide' flag",
55         "Server timeout period",
56         "Initial access level",
57         "Registration requirements",
58         "Twit Detect!",
59         "Twit Detect target room",
60         "Maximum concurrent sessions",
61         "Paginator prompt",
62         "Restrict Internet mail flag",
63         "Name of bit bucket subdirectory",
64         "System net password",
65         "Server port number",
66         };
67
68
69 char *setup_text[] = {
70
71 "0",
72 "Enter the full pathname of the directory in which the BBS you are",
73 "creating or updating resides.  If you specify a directory other than the",
74 "default, you will need to specify the -h flag to the server when you start",
75 "it up.",
76
77 "1",
78 "This is the name your system is known by on a Citadel/UX network.  It",
79 "should be 8 characters or less, and should generally be comprised only of",
80 "letters.  You can also use numbers and hyphens if necessary.",
81
82 "2",
83 "This is the name your system is known by on the Internet.",
84 "If you're not on the Internet, simply set this to your",
85 "node name followed by '.UUCP'.",
86
87 "3",
88 "This is a longer description of your system, readable by",
89 "us mere humans.  It can be up to 20 characters long and it",
90 "can have spaces in it.  Note that if you are part of a",
91 "Cit86Net, this is the name your system will be known by on",
92 "that network.",
93
94 "4",
95 "This is the main dialup number for your system.  If yours",
96 "can not be dialed into, then make one up!  It should be in",
97 "the format 'US 000 000 0000' - the US is your country code",
98 "(look it up if you're not in the United States) and the",
99 "rest is, of course, your area code and phone number.",
100 "This doesn't have any use in Citadel/UX, but gateways to",
101 "other networks may require it, and someday we may use this",
102 "to have the networker automatically build a BBS list.",
103
104 "5",
105 "Enter the geographical location of your system (city and",
106 "state/province/country etc.)",
107
108 "6",
109 "Enter the name of the system administrator (which is probably you).",
110 "When an account is created with this name, it will automatically be",
111 "assigned the highest access level.",
112
113 "7",
114 "You should create a user called 'bbs', 'guest', 'citadel', or something",
115 "similar, that will allow users a way into your BBS.  The server will run",
116 "under this user ID.  Please specify that (numeric) user ID here.",
117
118 "8",
119 "Citadel uses a (very) simple password encryption scheme",
120 "to thwart breakins that could occur if someone snatched",
121 "a copy of your userlog.  This parameter is part of the",
122 "algorithm, so that the code can be different on each",
123 "system.  Once it has been set, DO NOT change it --",
124 "otherwise no one will be able to log in!",
125
126 "9",
127 "This is a boolean value.  If you set it to 1, anyone who",
128 "creates a class 3 (passworded) or class 4 (invitation",
129 "only) room will automatically become the Room Aide for",
130 "that room, allowing them to edit it, delete/move messages,",
131 "etc.  This is an administrative decision: it works well on",
132 "some systems, and not so well on others.  Set this to 0 to",
133 "disable this function.",
134
135 "10",
136 "This setting specifies how long a server session may sit idle before it is",
137 "automatically terminated.  The recommended value is 900 seconds (15",
138 "minutes).  Note that this has *nothing* to do with any watchdog timer that",
139 "is presented to the user.  The server's timeout is intended to kill idle or",
140 "zombie sessions running on a network, etc.  ",
141 "You MUST set this to a reasonable value.  Setting it to zero will cause",
142 "the server to malfunction.",
143
144 "11",
145 "This is the access level new users are assigned.",
146 "",
147 "The most common settings for this will be either 1, for",
148 "systems which require new user validation by the system",
149 "administrator ('sysop' is a word for people who run DOS",
150 "boards!), or 4, for systems which give instant access.",
151 "The current access levels available are:",
152
153 "12",
154 "'Registration' refers to the boring part of logging into a BBS for the first",
155 "time: typing your name, address, and telephone number.  Set this value to 1",
156 "to automatically do registration for new users, or 0 to not auto-register.",
157 "Optionally, you could set it to, say, 2, to auto-register on a user's second",
158 "call, but there really isn't much point to doing this.  The recommended",
159 "value is 1 if you've set your inital access level to 1, or 0 if you've set",
160 "your initial access level to something higher.",
161
162 "13",
163 "Every BBS has its share of problem users.  This is one",
164 "good way to deal with them: if you enable this option,",
165 "anyone you flag as a 'problem user' (access level 2) can",
166 "post anywhere they want, but their messages will all be",
167 "automatically moved to a room of your choosing.  Set this",
168 "value to 1 to enable Twit Detect, or 0 to disable it.",
169
170 "14",
171 "This is the name of the room that problem user messages",
172 "get moved to if you have Twit Detect enabled.",
173 "(Note: don't forget to *create* this room!)",
174
175 "15",
176 "This is the maximum number of concurrent Citadel sessions which may be",
177 "running at any given time.  Use this to keep very busy systems from being",
178 "overloaded.",
179 "  Set this value to 0 to allow an unlimited number of sessions.",
180
181 "16",
182 "This is the prompt that appears after each screenful of",
183 "text - for users that have chosen that option.  Usually",
184 "a simple '<more>' will do, but some folks like to be",
185 "creative...",
186
187 "17",
188 "If you have a gateway set up to allow Citadel users to",
189 "send Internet mail, with sendmail, qmail, or whatever, and",
190 "you wish to restrict this to only users to whom you have",
191 "given this privilege, set this flag to 1.  Otherwise, set",
192 "it to 0 to allow everyone to send Internet mail.",
193 "(Obviously, if your system doesn't have the ability to",
194 "send mail to the outside world, this is all irrelevant.)",
195
196 "18",
197 "Select the name of a subdirectory (relative to the main",
198 "Citadel directory - do not type an absolute pathname!) in",
199 "which to place arriving file transfers that otherwise",
200 "don't have a home.",
201
202 "19",
203 "If you use Citadel client/server sessions to transport network spool data",
204 "between systems, this is the password other systems will use to authenticate",
205 "themselves as network nodes rather than regular callers.",
206
207 "20",
208 "Specify the TCP port number on which your server will run.  Normally, this",
209 "will be port 504, which is the official port assigned by the IANA for",
210 "Citadel servers.  You'll only need to specify a different port number if",
211 "you run multiple BBS's on the same computer and there's something else",
212 "already using port 504.",
213
214 "21",
215 "22",
216 "23",
217 "24",
218 "25",
219 "26",
220 "27",
221 "28",
222 "29",
223 "30",
224
225 "31",
226 "Setup has detected that you currently have data files from a Citadel/UX",
227 "version 3.2x installation.  The program 'conv_32_40' can upgrade your",
228 "files to version 4.0x format.",
229 " Setup will now exit.  Please either run 'conv_32_40' or delete your data",
230 "files, and run setup again.",
231
232 "32",
233
234 };
235
236
237 long atol();
238 void get_config();
239 struct config config;
240 int direction;
241
242 void cleanup(int exitcode) {
243 #ifdef CURSES_INC
244         if (setup_type == UI_CURSES) {
245                 clear();
246                 refresh();
247                 endwin();
248                 }
249 #endif
250
251         /* Do an 'init q' if we need to.  When we hit the right one, init
252          * will take over and setup won't come back because we didn't do a
253          * fork().  If init isn't found, we fall through the bottom of the
254          * loop and setup exits quietly.
255          */
256         if (need_init_q) {
257                 execlp("/sbin/init", "init", "q", NULL);
258                 execlp("/usr/sbin/init", "init", "q", NULL);
259                 execlp("/bin/init", "init", "q", NULL);
260                 execlp("/usr/bin/init", "init", "q", NULL);
261                 execlp("init", "init", "q", NULL);
262                 }
263
264         exit(exitcode);
265         }
266
267
268 #ifdef CURSES_INC
269 void getlin(yp,xp,string,lim)   /* Gets a line from the terminal */
270 int yp,xp;                      /* Where on the screen to start */
271 char string[];                  /* Pointer to string buffer */
272 int lim;                        /* Maximum length - if negative, no-show */
273 {
274 int a,b; char flag;
275
276         flag=0;
277         if (lim<0) { lim=(0-lim); flag=1; }
278         move(yp,xp);
279         standout();
280         for (a=0; a<lim; ++a) addch('-');
281         refresh();
282         move(yp,xp);
283         for (a=0; a<lim; ++a) addch(' ');
284         move(yp,xp);
285         printw("%s", string);
286 GLA:    move(yp,xp+strlen(string));
287         refresh();
288         a=getch();
289         if (a==127) a=8;
290         a=(a&127);
291         if (a==10) a=13;
292         if ((a==8)&&(strlen(string)==0)) goto GLA;
293         if ((a!=13)&&(a!=8)&&(strlen(string)==lim)) goto GLA;
294         if ((a==8)&&(string[0]!=0)) {
295                 string[strlen(string)-1]=0;
296                 move(yp,xp+strlen(string));
297                 addch(' ');
298                 goto GLA;
299                 }
300         if ((a==13)||(a==10)) {
301                 standend();
302                 move(yp,xp);
303                 for (a=0; a<lim; ++a) addch(' ');
304                 mvprintw(yp,xp,"%s",string);
305                 refresh();
306                 return;
307                 }
308         b=strlen(string);
309         string[b]=a;
310         string[b+1]=0;
311         if (flag==0) addch(a);
312         if (flag==1) addch('*');
313         goto GLA;
314 }
315 #endif
316
317
318
319 void title(text)
320 char *text; {
321         if (setup_type == UI_TEXT) {
322                 printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<%s>\n",text);
323                 }
324         }
325
326
327 void hit_any_key() {
328         char junk[5];
329
330 #ifdef CURSES_INC
331         if (setup_type == UI_CURSES) {
332                 mvprintw(20, 0, "Press any key to continue... ");
333                 refresh();
334                 getch();
335                 return;
336                 }
337 #endif
338         printf("Press return to continue...");
339         fgets(junk, 5, stdin);
340         }
341
342 int yesno(question)
343 char *question; {
344         int answer = 0;
345         char buf[4096];
346
347         switch(setup_type) {
348
349                 case UI_TEXT:
350                         do {
351                                 printf("%s\nYes/No --> ",question);
352                                 fgets(buf, 4096, stdin);
353                                 answer=tolower(buf[0]);
354                                 if (answer=='y') answer=1;
355                                 else if (answer=='n') answer=0;
356                                 } while ((answer<0)||(answer>1));
357                         break;
358
359                 case UI_DIALOG:
360                         sprintf(buf, "dialog --yesno \"%s\" 7 80", question);
361                         answer = ( (system(buf)==0) ? 1 : 0);
362                         break;
363 #ifdef CURSES_INC
364                 case UI_CURSES:
365                         do {
366                                 clear();
367                                 standout();
368                                 mvprintw(1, 20, "Question");
369                                 standend();
370                                 mvprintw(10, 0, "%-80s", question);
371                                 mvprintw(20, 0, "%80s", "");
372                                 mvprintw(20, 0, "Yes/No -> ");
373                                 refresh();
374                                 answer = getch();
375                                 answer=tolower(answer);
376                                 if (answer=='y') answer=1;
377                                 else if (answer=='n') answer=0;
378                                 } while ((answer<0)||(answer>1));
379                         break;
380 #endif
381
382                 }
383         return(answer);
384         }
385
386
387
388 void dump_access_levels() {
389         int a;
390         for (a=0; a<=6; ++a) printf("%d %s\n",a,axdefs[a]);
391         }
392
393 void get_setup_msg(char *dispbuf, int msgnum) {
394         int a,b;
395
396         a=0;
397         b=0;
398         while (atol(setup_text[a]) != msgnum) ++a;
399         ++a;
400         strcpy(dispbuf, "");
401         do {
402                 strcat(dispbuf, setup_text[a++]);
403                 strcat(dispbuf, "\n");
404                 } while(atol(setup_text[a])!=(msgnum+1));
405         }
406
407 void print_setup(msgnum) {
408         char dispbuf[4096];
409
410         get_setup_msg(dispbuf, msgnum);
411         printf("\n\n%s\n\n", dispbuf);
412         }
413
414
415 void important_message(char *title, char *msgtext) {
416         char buf[4096];
417
418         switch(setup_type) {
419                 
420                 case UI_TEXT:
421                         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");
422                         printf("       %s \n\n%s\n\n", title, msgtext);
423                         hit_any_key();
424                         break;
425
426                 case UI_DIALOG:
427                         sprintf(buf, "dialog --title \"%s\" --msgbox \"\n%s\" 20 80",
428                                 title, msgtext);
429                         system(buf);
430                         break;
431 #ifdef CURSES_INC
432                 case UI_CURSES:
433                         clear();
434                         move(1, 20);
435                         standout();
436                         printw("  Important Message  ");
437                         standend();
438                         move(3, 0);
439                         printw("%s", msgtext);
440                         refresh();
441                         hit_any_key();
442                         break;
443 #endif
444
445                 }
446         }
447
448 void important_msgnum(int msgnum) {
449         char dispbuf[4096];
450         
451         get_setup_msg(dispbuf, msgnum);
452         important_message("Important Message", dispbuf);
453         }
454
455 void display_error(char *error_message) {
456         important_message("Error", error_message);
457         }
458
459 void progress(text,curr,cmax)
460 char *text;
461 long curr;
462 long cmax; {
463         static long dots_printed;
464         long a;
465         static long prev;
466         static FILE *gauge = NULL;
467         char gcmd[256];
468
469         switch(setup_type) {
470
471                 case UI_TEXT:
472                         if (curr==0) {
473                                 printf("%s\n",text);
474                                 printf("..........................");
475                                 printf("..........................");
476                                 printf("..........................\r");
477                                 fflush(stdout);
478                                 dots_printed = 0;
479                                 }
480                         else if (curr==cmax) {
481                                 printf("\r%79s\n","");
482                                 }
483                         else {
484                                 a=(curr * 100) / cmax;
485                                 a=a*78; a=a/100;
486                                 while (dots_printed < a) {
487                                         printf("*");
488                                         ++dots_printed;
489                                         fflush(stdout);
490                                         }
491                                 }
492                         break;
493
494 #ifdef CURSES_INC
495                 case UI_CURSES:
496                         if (curr==0) {
497                                 clear();
498                                 move(5, 20);
499                                 printw("%s\n",text);
500                                 move(10, 1);
501                                 printf("..........................");
502                                 printf("..........................");
503                                 printf("..........................\r");
504                                 refresh();
505                                 dots_printed = 0;
506                                 }
507                         else if (curr==cmax) {
508                                 clear();
509                                 refresh();
510                                 }
511                         else {
512                                 a=(curr * 100) / cmax;
513                                 a=a*78; a=a/100;
514                                 move(10,1);
515                                 dots_printed = 0;
516                                 while (dots_printed < a) {
517                                         printw("*");
518                                         ++dots_printed;
519                                         }
520                                 refresh();
521                                 }
522                         break;
523 #endif
524                         
525                 case UI_DIALOG:
526                         if ( (curr == 0) && (gauge == NULL) ) {
527                                 sprintf(gcmd, "dialog --guage \"%s\" 7 80 0",
528                                         text);
529                                 gauge = (FILE *) popen(gcmd, "w");
530                                 prev = 0;
531                                 }
532                         else if (curr==cmax) {
533                                 fprintf(gauge, "100\n");
534                                 pclose(gauge);
535                                 gauge = NULL;
536                                 }
537                         else {
538                                 a=(curr * 100) / cmax;
539                                 if (a != prev) {
540                                         fprintf(gauge, "%ld\n", a);
541                                         fflush(gauge);
542                                         }
543                                 prev = a;
544                                 }
545                         break;
546                 }
547         }
548
549
550
551 /*
552  * check_services_entry()  -- Make sure "citadel" is in /etc/services
553  *
554  */
555 void check_services_entry() {
556         char question[128];
557         FILE *sfp;
558
559         sprintf(question,
560 "There is no '%s' entry in /etc/services.  Would you like to add one?",
561                 SERVICE_NAME);
562
563         if (getservbyname(SERVICE_NAME, PROTO_NAME) == NULL) {
564                 if (yesno(question)==1) {
565                         sfp = fopen("/etc/services", "a");
566                         if (sfp == NULL) {
567                                 display_error(strerror(errno));
568                                 }
569                         else {
570                                 fprintf(sfp, "%s                504/tcp\n",
571                                         SERVICE_NAME);
572                                 fclose(sfp);
573                                 }
574                         }
575                 }
576
577         }
578
579
580 /*
581  * check_inittab_entry()  -- Make sure "citadel" is in /etc/inittab
582  *
583  */
584 void check_inittab_entry() {
585         FILE *infp;
586         char buf[256];
587         char looking_for[256];
588         char question[128];
589         char *ptr;
590         int have_entry = 0;
591         char entryname[3];
592
593         /* Determine the fully qualified path name of citserver */
594         sprintf(looking_for, "%s/citserver ", BBSDIR);
595
596         /* Pound through /etc/inittab line by line.  Set have_entry to 1 if
597          * an entry is found which we believe starts citserver.
598          */
599         infp = fopen("/etc/inittab", "r");
600         if (infp == NULL) {
601                 display_error(strerror(errno));
602                 }
603         else {
604                 while (fgets(buf, 256, infp) != NULL) {
605                         buf[strlen(buf) - 1] = 0;
606                         ptr = strtok(buf, ":");
607                         ptr = strtok(NULL, ":");
608                         ptr = strtok(NULL, ":");
609                         ptr = strtok(NULL, ":");
610                         if (ptr != NULL) {
611                          if (!strncmp(ptr, looking_for, strlen(looking_for))) {
612                                         ++have_entry;
613                                         }
614                                 }
615                         }
616                 fclose(infp);
617                 }
618
619         /* If there's already an entry, then we have nothing left to do. */
620         if (have_entry > 0) return;
621
622         /* Otherwise, prompt the user to create an entry. */
623         sprintf(question,
624 "There is no '%s' entry in /etc/inittab.\nWould you like to add one?",
625                 looking_for);
626         if (yesno(question)==0) return;
627
628         /* Generate a unique entry name for /etc/inittab */
629         sprintf(entryname, "c0");
630         do {
631                 ++entryname[1];
632                 if (entryname[1] > '9') {
633                         entryname[1] = 0;
634                         ++entryname[0];
635                         if (entryname[0] > 'z') {
636                                 display_error(
637                                         "Can't generate a unique entry name");
638                                 return;
639                                 }
640                         }
641                 sprintf(buf,
642                         "grep %s: /etc/inittab >/dev/null 2>&1", entryname);
643                 } while(system(buf)==0);
644
645         /* Now write it out to /etc/inittab */
646         infp = fopen("/etc/inittab", "a");
647         if (infp == NULL) {
648                 display_error(strerror(errno));
649                 }
650         else {
651                 fprintf(infp, "# Start the Citadel/UX server...\n");
652                 fprintf(infp,"%s:2345:respawn:%s -h%s\n",
653                         entryname, looking_for, setup_directory);
654                 fclose(infp);
655                 need_init_q = 1;
656                 }
657         }
658
659
660
661 void set_str_val(int msgpos, char str[]) {
662         char buf[4096];
663         char setupmsg[4096];
664         char tempfile[64];
665         FILE *fp;
666
667         sprintf(tempfile, "/tmp/setup.%d", getpid());
668
669         switch (setup_type) {
670                 case UI_TEXT:
671                         title(setup_titles[msgpos]);
672                         print_setup(msgpos);
673                         if (msgpos==11) dump_access_levels();
674                         printf("This is currently set to:\n%s\n",str);
675                         printf("Enter new value or press return to leave unchanged:\n");
676                         fgets(buf, 4096, stdin);
677                         buf[strlen(buf)-1] = 0;
678                         if (strlen(buf)!=0) strcpy(str,buf);
679                         break;
680                 case UI_DIALOG:
681                         get_setup_msg(setupmsg, msgpos);
682                         sprintf(buf,
683                                 "dialog --title \"%s\" --inputbox \"\n%s\n\" 20 80 \"%s\" 2>%s",
684                                 setup_titles[msgpos],
685                                 setupmsg,
686                                 str, tempfile);
687                         if (system(buf)==0) {
688                                 fp = fopen(tempfile, "rb");
689                                 fgets(str, 4095, fp);
690                                 fclose(fp);
691                                 if (strlen(str)>0) 
692                                         if (str[strlen(str)-1]==10)
693                                                 str[strlen(str)-1]=0;
694                                 }
695                         break;
696 #ifdef CURSES_INC
697                 case UI_CURSES:
698                         clear();
699                         move(1, ((80-strlen(setup_titles[msgpos]))/2) );
700                         standout();
701                         printw("%s", setup_titles[msgpos]);
702                         standend();
703                         move(3, 0);
704                         get_setup_msg(setupmsg, msgpos);
705                         printw("%s", setupmsg);
706                         refresh();
707                         getlin(20, 0, str, 80);
708                         break;
709 #endif
710                 }
711         }
712
713 void set_int_val(msgpos, ip)
714 int msgpos;
715 int *ip; {
716         char buf[16];
717         sprintf(buf,"%d",(int)*ip);
718         set_str_val(msgpos, buf);
719         *ip = atoi(buf);
720         }
721
722
723 void set_char_val(msgpos, ip)
724 int msgpos;
725 char *ip; {
726         char buf[16];
727         sprintf(buf,"%d",(int)*ip);
728         set_str_val(msgpos, buf);
729         *ip = (char)atoi(buf);
730         }
731
732
733 void set_long_val(msgpos, ip)
734 int msgpos;
735 long *ip; {
736         char buf[16];
737         sprintf(buf,"%ld",*ip);
738         set_str_val(msgpos, buf);
739         *ip = atol(buf);
740         }
741
742
743 int yesno_s(question) {
744         int a;
745         char buf[4096];
746         char tempfile[64];
747         FILE *fp;
748
749         sprintf(tempfile, "/tmp/setup.%d", getpid());
750         switch (setup_type) {
751         
752                 case UI_TEXT:
753                         a=yesno(question);
754                         if (a==1) a=yesno("Are you SURE you want to reinitialize this file? ");
755                         return(a);
756                         break;
757
758                 case UI_CURSES:
759                         a=yesno(question);
760                         if (a==1) a=yesno("Are you SURE you want to reinitialize this file? ");
761                         return(a);
762                         break;
763
764                 case UI_DIALOG:
765                         a = yesno(question);
766                         if (a==0) return(a);
767                         sprintf(buf, "dialog --title \"Confirm file overwrite\" --menu \"\nAre you SURE you want to reinitialize this file?\n\" 13 80 2 NO \"No, don't overwrite\" YES \"Yes, overwrite the existing file\" 2>%s", tempfile);
768                         a = system(buf);
769                         if (a != 0) return(0);
770                         fp = fopen(tempfile, "rb");
771                         fgets(buf, 4095, fp);
772                         fclose(fp);
773                         if (strlen(buf)>0) 
774                                 if (buf[strlen(buf)-1]==10)
775                                         buf[strlen(buf)-1]=0;
776                         return( (!strcmp(buf, "YES")) ? 1 : 0 );
777                         break;
778
779                 }
780
781         return(0); /* just in case */
782         }
783
784
785 void edit_value(curr)
786 int curr; {
787  int a;
788  
789  switch(curr) {
790
791 case 1:
792         set_str_val(curr, config.c_nodename);
793         break;
794
795 case 2:
796         set_str_val(curr, config.c_fqdn);
797         break;
798
799 case 3:
800         set_str_val(curr, config.c_humannode);
801         break;
802
803 case 4:
804         set_str_val(curr, config.c_phonenum);
805         break;
806
807 case 5:
808         set_str_val(curr, config.c_bbs_city);
809         break;
810
811 case 6:
812         set_str_val(curr, config.c_sysadm);
813         break;
814
815 case 7:
816         set_int_val(curr, &config.c_bbsuid);
817         break;
818
819 case 8:
820         set_int_val(curr, &config.c_pwcrypt);
821         break;
822
823 case 9:
824         set_char_val(curr, &config.c_creataide);
825         break;
826
827 case 10:
828         set_int_val(curr, &config.c_sleeping);
829         break;
830
831 case 11:
832         set_char_val(curr, &config.c_initax);
833         break;
834
835 case 12:
836         set_char_val(curr, &config.c_regiscall);
837         break;
838
839 case 13:
840         set_char_val(curr, &config.c_twitdetect);
841         break;
842
843 case 14:
844         set_str_val(curr, config.c_twitroom);
845         break;
846
847 case 15:
848         set_int_val(curr, &config.c_maxsessions);
849         break;
850
851 case 16:
852         set_str_val(curr, config.c_moreprompt);
853         break;
854
855 case 17:
856         set_char_val(curr, &config.c_restrict);
857         break;
858
859 case 18:
860         set_str_val(curr, config.c_bucket_dir);
861         config.c_bucket_dir[14] = 0;
862         for (a=0; a<strlen(config.c_bucket_dir); ++a)
863                 if (!isalpha(config.c_bucket_dir[a]))
864                         strcpy(&config.c_bucket_dir[a],
865                                 &config.c_bucket_dir[a+1]);
866         break;
867
868 case 19:
869         set_str_val(curr, config.c_net_password);
870         break;
871
872 case 20:
873         set_int_val(curr, &config.c_port_number);
874         break;
875
876
877  }
878 }
879
880 /*
881  * (re-)write the config data to disk
882  */
883 void write_config_to_disk() {
884         FILE *fp;
885
886         fp=fopen("citadel.config","wb");
887         if (fp==NULL) {
888                 display_error("setup: cannot open citadel.config");
889                 cleanup(1);
890                 }
891         fwrite((char *)&config,sizeof(struct config),1,fp);
892         fclose(fp);
893         }
894
895
896
897
898 /*
899  * Figure out what type of user interface we're going to use
900  */
901 int discover_ui() {
902
903 #ifdef CURSES_INC
904         return UI_CURSES;
905 #endif
906
907         if (system("dialog -h </dev/null 2>&1 |grep Savio")==0) {
908                 return UI_DIALOG;
909                 }
910
911         return UI_TEXT;
912         }
913
914
915
916
917
918 void main(int argc, char *argv[]) {
919         int a;
920         int curr;
921         char aaa[128];
922         FILE *fp;
923         int old_setup_level = 0;
924         int info_only = 0;
925
926         /* set an invalid setup type */
927         setup_type = (-1);
928
929         /* parse command line args */
930         for (a=0; a<argc; ++a) {
931                 if (!strncmp(argv[a], "-u", 2)) {
932                         strcpy(aaa, argv[a]);
933                         strcpy(aaa, &aaa[2]);
934                         setup_type = atoi(aaa);
935                         }
936                 if (!strcmp(argv[a], "-i")) {
937                         info_only = 1;
938                         }
939                 }
940
941
942         /* If a setup type was not specified, try to determine automatically
943          * the best one to use out of all available types.
944          */
945         if (setup_type < 0) {
946                 setup_type = discover_ui();
947                 }
948
949 #ifdef CURSES_INC
950         if (setup_type == UI_CURSES) {
951                 initscr();
952                 raw();
953                 noecho();
954                 }
955 #endif
956
957         if (info_only == 1) {
958                 important_message("Citadel/UX Setup", CITADEL);
959                 cleanup(0);
960                 }
961
962         strcpy(setup_directory, BBSDIR);
963         set_str_val(0, setup_directory);
964         if (chdir(setup_directory) != 0) {
965                 important_message("Citadel/UX Setup",
966                         "The directory you specified does not exist.");
967                 cleanup(errno);
968                 }
969
970
971         switch(setup_type) {
972                 
973                 case UI_TEXT:
974                         printf("\n\n\n               *** Citadel/UX setup program ***\n\n");
975                         break;
976                 
977                 case UI_DIALOG:
978                         system("exec clear");
979                         break;
980                         
981                 }
982
983         /*
984          * What we're going to try to do here is append a whole bunch of
985          * nulls to the citadel.config file, so we can keep the old config
986          * values if they exist, but if the file is missing or from an
987          * earlier version with a shorter config structure, when setup tries
988          * to read the old config parameters, they'll all come up zero.
989          * The length of the config file will be set to what it's supposed
990          * to be when we rewrite it, because we replace the old file with a
991          * completely new copy.  (Neat, eh?)
992          */
993
994         fp=fopen("citadel.config","ab");
995         if (fp==NULL) {
996                 display_error("setup: cannot append citadel.config");
997                 cleanup(errno);
998                 }
999         for (a=0; a<sizeof(struct config); ++a) putc(0,fp);
1000         fclose(fp);
1001
1002         /* now we re-open it, and read the old or blank configuration */
1003         fp=fopen("citadel.config","rb");
1004         if (fp==NULL) {
1005                 display_error("setup: cannot open citadel.config");
1006                 cleanup(errno);
1007                 }
1008         fread((char *)&config,sizeof(struct config),1,fp);
1009         fclose(fp);
1010
1011
1012         /* set some sample/default values in place of blanks... */
1013         if (strlen(config.c_nodename)==0)
1014                 strcpy(config.c_nodename,"mysystem");
1015         if (strlen(config.c_fqdn)==0)
1016                 sprintf(config.c_fqdn,"%s.UUCP",config.c_nodename);
1017         if (strlen(config.c_humannode)==0)
1018                 strcpy(config.c_humannode,"My System");
1019         if (strlen(config.c_phonenum)==0)
1020                 strcpy(config.c_phonenum,"US 800 555 1212");
1021         if (config.c_initax == 0)
1022                 config.c_initax = 1;
1023         if (strlen(config.c_moreprompt)==0)
1024                 strcpy(config.c_moreprompt,"<more>");
1025         if (strlen(config.c_twitroom)==0)
1026                 strcpy(config.c_twitroom,"Trashcan");
1027         if (strlen(config.c_bucket_dir)==0)
1028                 strcpy(config.c_bucket_dir,"bitbucket");
1029         if (strlen(config.c_net_password)==0)
1030                 strcpy(config.c_net_password,"netpassword");
1031         if (config.c_port_number == 0) {
1032                 config.c_port_number = 504;
1033                 }
1034         if (config.c_ipgm_secret == 0) {
1035                 srand(getpid());
1036                 config.c_ipgm_secret = rand();
1037                 }
1038         if (config.c_sleeping == 0) {
1039                 config.c_sleeping = 900;
1040                 }
1041
1042         /* Go through a series of dialogs prompting for config info */
1043         for (curr = 1; curr <= MAXSETUP; ++curr) {
1044                 edit_value(curr);
1045                 }
1046
1047         /*
1048         if (setuid(config.c_bbsuid) != 0) {
1049                 important_message("Citadel/UX Setup",
1050                         "Failed to change the user ID to your BBS user.");
1051                 cleanup(errno);
1052                 }
1053         */
1054
1055         /***** begin version update section ***** */
1056         /* take care of any updating that is necessary */
1057
1058         old_setup_level = config.c_setup_level;
1059
1060         if (old_setup_level == 0) goto NEW_INST;
1061         
1062         if (old_setup_level < 323) {
1063                 important_message("Citadel/UX Setup",
1064                         "This Citadel/UX installation is too old to be upgraded.");
1065                 cleanup(1);
1066                 }
1067
1068         write_config_to_disk();
1069
1070         if ((config.c_setup_level / 10) == 32) {
1071                 important_msgnum(31);
1072                 cleanup(0);
1073                 }
1074
1075         if (config.c_setup_level < 400) {
1076                 config.c_setup_level = 400;
1077                 }
1078
1079         /* end of 3.23 -> 4.00 update section */
1080
1081         /* end of 4.00 -> 4.02 update section */
1082
1083         old_setup_level = config.c_setup_level;
1084
1085         /* end of version update section */
1086
1087 NEW_INST:
1088         config.c_setup_level = REV_LEVEL;
1089         write_config_to_disk();
1090
1091         system("mkdir info 2>/dev/null");               /* Create these */
1092         system("mkdir bio 2>/dev/null");
1093         system("mkdir userpics 2>/dev/null");
1094         system("mkdir messages 2>/dev/null");
1095         system("mkdir help 2>/dev/null");
1096         system("mkdir images 2>/dev/null");
1097         sprintf(aaa,"mkdir %s 2>/dev/null",config.c_bucket_dir);
1098         system(aaa);
1099
1100
1101         system("rm -fr ./chatpipes 2>/dev/null");       /* Don't need these */
1102         system("rm -fr ./expressmsgs 2>/dev/null");
1103         unlink("sessions");
1104
1105         check_services_entry();         /* Check /etc/services */
1106         check_inittab_entry();          /* Check /etc/inittab */
1107
1108         progress("Setting file permissions", 0, 3);
1109         chown(".", config.c_bbsuid, getgid());
1110         progress("Setting file permissions", 1, 3);
1111         chown("citadel.config", config.c_bbsuid, getgid());
1112         progress("Setting file permissions", 2, 3);
1113         sprintf(aaa, "find . -exec chown %d {} \\; 2>/dev/null",
1114                 config.c_bbsuid);
1115         system(aaa);
1116         progress("Setting file permissions", 3, 3);
1117
1118         important_message("Setup finished", 
1119                 "Setup is finished.  You may now start the Citadel server.");
1120
1121
1122         cleanup(0);
1123 }