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