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