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