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