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