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