]> code.citadel.org Git - citadel.git/blobdiff - citadel/setup.c
HUGE PATCH. This moves all of mime_parser.c and all
[citadel.git] / citadel / setup.c
index bd3196adf3cfbd21069d04a7eaf9d2ae24dddd39..f0ad438a376009f5248b489c1c49a28966bb19d0 100644 (file)
 #include <errno.h>
 #include <limits.h>
 #include <pwd.h>
 #include <errno.h>
 #include <limits.h>
 #include <pwd.h>
-
+#include <time.h>
+#include <libcitadel.h>
 #include "citadel.h"
 #include "axdefs.h"
 #include "sysdep.h"
 #include "config.h"
 #include "citadel.h"
 #include "axdefs.h"
 #include "sysdep.h"
 #include "config.h"
-#include "tools.h"
-
-#ifdef HAVE_NEWT
-#include <newt.h>
-#endif
+#include "citadel_dirs.h"
 
 
-
-#define MAXSETUP 4     /* How many setup questions to ask */
+#define MAXSETUP 5     /* How many setup questions to ask */
 
 #define UI_TEXT                0       /* Default setup type -- text only */
 #define UI_DIALOG      2       /* Use the 'dialog' program */
 #define UI_SILENT      3       /* Silent running, for use in scripts */
 
 #define UI_TEXT                0       /* Default setup type -- text only */
 #define UI_DIALOG      2       /* Use the 'dialog' program */
 #define UI_SILENT      3       /* Silent running, for use in scripts */
-#define UI_NEWT                4       /* Use the "newt" window library */
 
 #define SERVICE_NAME   "citadel"
 #define PROTO_NAME     "tcp"
 
 #define SERVICE_NAME   "citadel"
 #define PROTO_NAME     "tcp"
+#define NSSCONF                "/etc/nsswitch.conf"
 
 int setup_type;
 
 int setup_type;
-char setup_directory[SIZ];
-char citserver_init_entry[SIZ];
+char setup_directory[PATH_MAX];
 int using_web_installer = 0;
 int using_web_installer = 0;
-
-#ifdef HAVE_LDAP
-void contemplate_ldap(void);
-#endif
+int enable_home = 1;
 
 char *setup_titles[] =
 {
 
 char *setup_titles[] =
 {
@@ -58,18 +50,33 @@ char *setup_titles[] =
        "Citadel User ID",
        "Server IP address",
        "Server port number",
        "Citadel User ID",
        "Server IP address",
        "Server port number",
+       "Authentication mode"
 };
 
 
 };
 
 
+struct config config;
+
+       /* calculate all our path on a central place */
+    /* where to keep our config */
+       
+
 char *setup_text[] = {
 char *setup_text[] = {
+#ifndef HAVE_RUN_DIR
 "Enter the full pathname of the directory in which the Citadel\n"
 "installation you are creating or updating resides.  If you\n"
 "specify a directory other than the default, you will need to\n"
 "specify the -h flag to the server when you start it up.\n",
 "Enter the full pathname of the directory in which the Citadel\n"
 "installation you are creating or updating resides.  If you\n"
 "specify a directory other than the default, you will need to\n"
 "specify the -h flag to the server when you start it up.\n",
+#else
+"Enter the subdirectory name for an alternate installation of "
+"Citadel. To do a default installation just leave it blank."
+"If you specify a directory other than the default, you will need to\n"
+"specify the -h flag to the server when you start it up.\n"
+"note that it may not have a leading /",
+#endif
 
 "Enter the name of the system administrator (which is probably\n"
 "you).  When an account is created with this name, it will\n"
 
 "Enter the name of the system administrator (which is probably\n"
 "you).  When an account is created with this name, it will\n"
-"automatically be assigned the highest access level.\n",
+"automatically be given administrator-level access.\n",
 
 "Citadel needs to run under its own user ID.  This would\n"
 "typically be called \"citadel\", but if you are running Citadel\n"
 
 "Citadel needs to run under its own user ID.  This would\n"
 "typically be called \"citadel\", but if you are running Citadel\n"
@@ -90,135 +97,24 @@ char *setup_text[] = {
 "of Citadel on the same computer and there is something else\n"
 "already using port 504.\n",
 
 "of Citadel on the same computer and there is something else\n"
 "already using port 504.\n",
 
+"Normally, a Citadel system uses a \"black box\" authentication mode.\n"
+"This means that users do not have accounts or home directories on\n"
+"the underlying host system -- Citadel manages its own user database.\n"
+"However, if you wish to override this behavior, you can enable the\n"
+"host based authentication mode which is traditional for Unix systems.\n"
+"WARNING: do *not* change this setting once your system is installed.\n"
+"\n"
+"(Answer \"no\" unless you completely understand this option)\n"
+"Do you want to enable host based authentication mode?\n"
+
 };
 
 struct config config;
 int direction;
 
 };
 
 struct config config;
 int direction;
 
-/*
- * Set an entry in inittab to the desired state
- */
-void set_init_entry(char *which_entry, char *new_state) {
-       char *inittab = NULL;
-       FILE *fp;
-       char buf[SIZ];
-       char entry[SIZ];
-       char levels[SIZ];
-       char state[SIZ];
-       char prog[SIZ];
-
-       if (which_entry == NULL) return;
-       if (strlen(which_entry) == 0) return;
-
-       inittab = strdup("");
-       if (inittab == NULL) return;
-
-       fp = fopen("/etc/inittab", "r");
-       if (fp == NULL) return;
-
-       while(fgets(buf, sizeof buf, fp) != NULL) {
-
-               if (num_tokens(buf, ':') == 4) {
-                       extract_token(entry, buf, 0, ':');
-                       extract_token(levels, buf, 1, ':');
-                       extract_token(state, buf, 2, ':');
-                       extract_token(prog, buf, 3, ':'); /* includes 0x0a LF */
-
-                       if (!strcmp(entry, which_entry)) {
-                               strcpy(state, new_state);
-                               sprintf(buf, "%s:%s:%s:%s",
-                                       entry, levels, state, prog);
-                       }
-               }
-
-               inittab = realloc(inittab, strlen(inittab) + strlen(buf) + 2);
-               if (inittab == NULL) {
-                       fclose(fp);
-                       return;
-               }
-               
-               strcat(inittab, buf);
-       }
-       fclose(fp);
-       fp = fopen("/etc/inittab", "w");
-       if (fp != NULL) {
-               fwrite(inittab, strlen(inittab), 1, fp);
-               fclose(fp);
-               kill(1, SIGHUP);        /* Tell init to re-read /etc/inittab */
-       }
-       free(inittab);
-}
-
-
-/*
- * Locate the name of an inittab entry for a specific program
- */
-void locate_init_entry(char *init_entry, char *program) {
-
-       FILE *infp;
-       char buf[SIZ];
-       int have_entry = 0;
-       char looking_for[SIZ];
-       char entry[SIZ];
-       char prog[SIZ];
-
-       strcpy(init_entry, "");
-
-       /* Pound through /etc/inittab line by line.  Set have_entry to 1 if
-        * an entry is found which we believe starts the specified program.
-        */
-       infp = fopen("/etc/inittab", "r");
-       if (infp == NULL) {
-               return;
-       } else {
-               while (fgets(buf, sizeof buf, infp) != NULL) {
-                       buf[strlen(buf) - 1] = 0;
-                       extract_token(entry, buf, 0, ':');      
-                       extract_token(prog, buf, 3, ':');
-                       if (!strncasecmp(prog, looking_for,
-                          strlen(looking_for))) {
-                               ++have_entry;
-                               strcpy(init_entry, entry);
-                       }
-               }
-               fclose(infp);
-       }
-
-}
-
-
-/* 
- * Shut down the Citadel service if necessary, during setup.
- */
-void shutdown_citserver(void) {
-       char looking_for[SIZ];
-
-       snprintf(looking_for, sizeof looking_for, "%s/citserver", BBSDIR);
-       locate_init_entry(citserver_init_entry, looking_for);
-       if (strlen(citserver_init_entry) > 0) {
-               set_init_entry(citserver_init_entry, "off");
-       }
-}
-
-
-/*
- * Start the Citadel service.
- */
-void start_citserver(void) {
-       if (strlen(citserver_init_entry) > 0) {
-               set_init_entry(citserver_init_entry, "respawn");
-       }
-}
-
-
 
 void cleanup(int exitcode)
 {
 
 void cleanup(int exitcode)
 {
-#ifdef HAVE_NEWT
-       newtCls();
-       newtRefresh();
-       newtFinished();
-#endif
        exit(exitcode);
 }
 
        exit(exitcode);
 }
 
@@ -233,14 +129,8 @@ void title(char *text)
 
 
 
 
 
 
-int yesno(char *question)
+int yesno(char *question, int default_value)
 {
 {
-#ifdef HAVE_NEWT
-       newtComponent form = NULL;
-       newtComponent yesbutton = NULL;
-       newtComponent nobutton = NULL;
-       int prompt_window_height = 0;
-#endif
        int i = 0;
        int answer = 0;
        char buf[SIZ];
        int i = 0;
        int answer = 0;
        char buf[SIZ];
@@ -249,10 +139,15 @@ int yesno(char *question)
 
        case UI_TEXT:
                do {
 
        case UI_TEXT:
                do {
-                       printf("%s\nYes/No --> ", question);
+                       printf("%s\nYes/No [%s] --> ",
+                               question,
+                               ( default_value ? "Yes" : "No" )
+                       );
                        fgets(buf, sizeof buf, stdin);
                        answer = tolower(buf[0]);
                        fgets(buf, sizeof buf, stdin);
                        answer = tolower(buf[0]);
-                       if (answer == 'y')
+                       if ((buf[0]==0) || (buf[0]==13) || (buf[0]==10))
+                               answer = default_value;
+                       else if (answer == 'y')
                                answer = 1;
                        else if (answer == 'n')
                                answer = 0;
                                answer = 1;
                        else if (answer == 'n')
                                answer = 0;
@@ -260,8 +155,9 @@ int yesno(char *question)
                break;
 
        case UI_DIALOG:
                break;
 
        case UI_DIALOG:
-               sprintf(buf, "exec %s --yesno '%s' 10 72",
+               sprintf(buf, "exec %s %s --yesno '%s' 15 75",
                        getenv("CTDL_DIALOG"),
                        getenv("CTDL_DIALOG"),
+                       ( default_value ? "" : "--defaultno" ),
                        question);
                i = system(buf);
                if (i == 0) {
                        question);
                i = system(buf);
                if (i == 0) {
@@ -272,31 +168,6 @@ int yesno(char *question)
                }
                break;
 
                }
                break;
 
-#ifdef HAVE_NEWT
-       case UI_NEWT:
-               prompt_window_height = num_tokens(question, '\n') + 5;
-               newtCenteredWindow(76, prompt_window_height, "Question");
-               form = newtForm(NULL, NULL, 0);
-               for (i=0; i<num_tokens(question, '\n'); ++i) {
-                       extract_token(buf, question, i, '\n');
-                       newtFormAddComponent(form, newtLabel(1, 1+i, buf));
-               }
-               yesbutton = newtButton(10, (prompt_window_height - 4), "Yes");
-               nobutton = newtButton(60, (prompt_window_height - 4), "No");
-               newtFormAddComponent(form, yesbutton);
-               newtFormAddComponent(form, nobutton);
-               if (newtRunForm(form) == yesbutton) {
-                       answer = 1;
-               }
-               else {
-                       answer = 0;
-               }
-               newtPopWindow();
-               newtFormDestroy(form);  
-
-               break;
-#endif
-
        }
        return (answer);
 }
        }
        return (answer);
 }
@@ -304,10 +175,6 @@ int yesno(char *question)
 
 void important_message(char *title, char *msgtext)
 {
 
 void important_message(char *title, char *msgtext)
 {
-#ifdef HAVE_NEWT
-       newtComponent form = NULL;
-       int i = 0;
-#endif
        char buf[SIZ];
 
        switch (setup_type) {
        char buf[SIZ];
 
        switch (setup_type) {
@@ -320,28 +187,11 @@ void important_message(char *title, char *msgtext)
                break;
 
        case UI_DIALOG:
                break;
 
        case UI_DIALOG:
-               sprintf(buf, "exec %s --backtitle '%s' --msgbox '%s' 19 72",
+               sprintf(buf, "exec %s --msgbox '%s' 19 72",
                        getenv("CTDL_DIALOG"),
                        getenv("CTDL_DIALOG"),
-                       title,
                        msgtext);
                system(buf);
                break;
                        msgtext);
                system(buf);
                break;
-
-#ifdef HAVE_NEWT
-       case UI_NEWT:
-               newtCenteredWindow(76, 10, title);
-               form = newtForm(NULL, NULL, 0);
-               for (i=0; i<num_tokens(msgtext, '\n'); ++i) {
-                       extract_token(buf, msgtext, i, '\n');
-                       newtFormAddComponent(form, newtLabel(1, 1+i, buf));
-               }
-               newtFormAddComponent(form, newtButton(35, 5, "OK"));
-               newtRunForm(form);
-               newtPopWindow();
-               newtFormDestroy(form);  
-               break;
-#endif
-
        }
 }
 
        }
 }
 
@@ -357,16 +207,6 @@ void display_error(char *error_message)
 
 void progress(char *text, long int curr, long int cmax)
 {
 
 void progress(char *text, long int curr, long int cmax)
 {
-#ifdef HAVE_NEWT
-
-       /* These variables are static because progress() gets called
-        * multiple times during the course of whatever operation is
-        * being performed.  This makes setup non-threadsafe, but who
-        * cares?
-        */
-       static newtComponent form = NULL;
-       static newtComponent scale = NULL;
-#endif
        static long dots_printed = 0L;
        long a = 0;
        static FILE *fp = NULL;
        static long dots_printed = 0L;
        long a = 0;
        static FILE *fp = NULL;
@@ -423,28 +263,6 @@ void progress(char *text, long int curr, long int cmax)
                }
                break;
 
                }
                break;
 
-#ifdef HAVE_NEWT
-       case UI_NEWT:
-               if (curr == 0) {
-                       newtCenteredWindow(76, 8, text);
-                       form = newtForm(NULL, NULL, 0);
-                       scale = newtScale(1, 3, 74, cmax);
-                       newtFormAddComponent(form, scale);
-                       newtDrawForm(form);
-                       newtRefresh();
-               }
-               if ((curr > 0) && (curr <= cmax)) {
-                       newtScaleSet(scale, curr);
-                       newtRefresh();
-               }
-               if (curr == cmax) {
-                       newtFormDestroy(form);  
-                       newtPopWindow();
-                       newtRefresh();
-               }
-               break;
-#endif
-
        }
 }
 
        }
 }
 
@@ -458,97 +276,202 @@ void check_services_entry(void)
 {
        int i;
        FILE *sfp;
 {
        int i;
        FILE *sfp;
+       char errmsg[256];
 
        if (getservbyname(SERVICE_NAME, PROTO_NAME) == NULL) {
 
        if (getservbyname(SERVICE_NAME, PROTO_NAME) == NULL) {
-               for (i=0; i<=3; ++i) {
-                       progress("Adding service entry...", i, 3);
+               for (i=0; i<=2; ++i) {
+                       progress("Adding service entry...", i, 2);
                        if (i == 0) {
                                sfp = fopen("/etc/services", "a");
                                if (sfp == NULL) {
                        if (i == 0) {
                                sfp = fopen("/etc/services", "a");
                                if (sfp == NULL) {
-                                       display_error(strerror(errno));
+                                       sprintf(errmsg, "Cannot open /etc/services: %s", strerror(errno));
+                                       display_error(errmsg);
                                } else {
                                } else {
-                                       fprintf(sfp, "%s                504/tcp\n",
-                                               SERVICE_NAME);
+                                       fprintf(sfp, "%s                504/tcp\n", SERVICE_NAME);
                                        fclose(sfp);
                                }
                        }
                                        fclose(sfp);
                                }
                        }
-                       sleep(1);
                }
        }
 }
 
 
                }
        }
 }
 
 
+
+
 /*
 /*
- * Generate a unique entry name for a new inittab entry
+ * delete_inittab_entry()  -- Remove obsolete /etc/inittab entry for Citadel
+ *
  */
  */
-void generate_entry_name(char *entryname) {
-       char buf[SIZ];
+void delete_inittab_entry(void)
+{
+       FILE *infp;
+       FILE *outfp;
+       char looking_for[256];
+       char buf[1024];
+       char outfilename[32];
+       int changes_made = 0;
 
 
-       snprintf(entryname, sizeof entryname, "c0");
-       do {
-               ++entryname[1];
-               if (entryname[1] > '9') {
-                       entryname[1] = 0;
-                       ++entryname[0];
-                       if (entryname[0] > 'z') {
-                               display_error(
-                                  "Can't generate a unique entry name");
-                               return;
-                       }
+       /* Determine the fully qualified path name of citserver */
+       snprintf(looking_for, 
+                sizeof looking_for,
+                "%s/citserver", 
+                ctdl_sbin_dir
+                );
+
+       /* Now tweak /etc/inittab */
+       infp = fopen("/etc/inittab", "r");
+       if (infp == NULL) {
+
+               /* If /etc/inittab does not exist, return quietly.
+                * Not all host platforms have it.
+                */
+               if (errno == ENOENT) {
+                       return;
                }
                }
-               snprintf(buf, sizeof buf,
-                    "grep %s: /etc/inittab >/dev/null 2>&1", entryname);
-       } while (system(buf) == 0);
-}
 
 
+               /* Other errors might mean something really did go wrong.
+                */
+               sprintf(buf, "Cannot open /etc/inittab: %s", strerror(errno));
+               display_error(buf);
+               return;
+       }
+
+       strcpy(outfilename, "/tmp/ctdlsetup.XXXXXX");
+       outfp = fdopen(mkstemp(outfilename), "w+");
+       if (outfp == NULL) {
+               sprintf(buf, "Cannot open %s: %s", outfilename, strerror(errno));
+               display_error(buf);
+               fclose(infp);
+               return;
+       }
+
+       while (fgets(buf, sizeof buf, infp) != NULL) {
+               if (strstr(buf, looking_for) != NULL) {
+                       fwrite("#", 1, 1, outfp);
+                       ++changes_made;
+               }
+               fwrite(buf, strlen(buf), 1, outfp);
+       }
+
+       fclose(infp);
+       fclose(outfp);
+
+       if (changes_made) {
+               sprintf(buf, "/bin/mv -f %s /etc/inittab 2>/dev/null", outfilename);
+               system(buf);
+               system("/sbin/init q 2>/dev/null");
+       }
+       else {
+               unlink(outfilename);
+       }
+}
 
 
 /*
 
 
 /*
- * check_inittab_entry()  -- Make sure "citadel" is in /etc/inittab
+ * install_init_scripts()  -- Try to configure to start Citadel at boot
  *
  */
  *
  */
-void check_inittab_entry(void)
+void install_init_scripts(void)
 {
 {
-       FILE *infp;
-       char looking_for[SIZ];
-       char question[SIZ];
-       char entryname[5];
+       struct stat etcinitd;
+       FILE *fp;
+       char *initfile = "/etc/init.d/citadel";
+       char command[SIZ];
+
+       if ((stat("/etc/init.d/", &etcinitd) == -1) && 
+           (errno == ENOENT))
+       {
+               if ((stat("/etc/rc.d/init.d/", &etcinitd) == -1) &&
+                   (errno == ENOENT))
+                       initfile = CTDLDIR"/citadel.init";
+               else
+                       initfile = "/etc/rc.d/init.d/citadel";
+       }
 
 
-       /* Determine the fully qualified path name of citserver */
-       snprintf(looking_for, sizeof looking_for, "%s/citserver", BBSDIR);
-       locate_init_entry(citserver_init_entry, looking_for);
+       fp = fopen(initfile, "r");
+       if (fp != NULL) {
+               if (yesno("Citadel already appears to be configured to start at boot.\n"
+                  "Would you like to keep your boot configuration as is?\n", 1) == 1) {
+                       return;
+               }
+               fclose(fp);
+               
+       }
 
 
-       /* If there's already an entry, then we have nothing left to do. */
-       if (strlen(citserver_init_entry) > 0) {
+       if (yesno("Would you like to automatically start Citadel at boot?\n", 1) == 0) {
                return;
        }
 
                return;
        }
 
-       /* Otherwise, prompt the user to create an entry. */
-       snprintf(question, sizeof question,
-               "Do you want this computer configured to start the Citadel\n"
-               "service automatically?  (If you answer yes, an entry in\n"
-               "/etc/inittab pointing to %s will be added.)\n",
-               looking_for);
-       if (yesno(question) == 0)
+       fp = fopen(initfile, "w");
+       if (fp == NULL) {
+               display_error("Cannot create /etc/init.d/citadel");
                return;
                return;
+       }
 
 
-       /* Generate a unique entry name for /etc/inittab */
-       generate_entry_name(entryname);
+       fprintf(fp,     "#!/bin/sh\n"
+                       "#\n"
+                       "# Init file for Citadel\n"
+                       "#\n"
+                       "# chkconfig: - 79 30\n"
+                       "# description: Citadel service\n"
+                       "# processname: citserver\n"
+                       "# pidfile: %s/citadel.pid\n"
+                       "\n"
+                       "CITADEL_DIR=%s\n"
+                       ,
+                               setup_directory,
+                               setup_directory
+                       );
+       fprintf(fp,     "\n"
+                       "test -d /var/run || exit 0\n"
+                       "\n"
+                       "case \"$1\" in\n"
+                       "\n"
+                       "start)         echo -n \"Starting Citadel... \"\n"
+                       "               if $CITADEL_DIR/citserver -d -h$CITADEL_DIR\n"
+                       "               then\n"
+                       "                       echo \"ok\"\n"
+                       "               else\n"
+                       "                       echo \"failed\"\n"
+                       "               fi\n");
+       fprintf(fp,     "               ;;\n"
+                       "stop)          echo -n \"Stopping Citadel... \"\n"
+                       "               if $CITADEL_DIR/sendcommand DOWN >/dev/null 2>&1 ; then\n"
+                       "                       echo \"ok\"\n"
+                       "               else\n"
+                       "                       echo \"failed\"\n"
+                       "               fi\n"
+                       "               rm -f %s/citadel.pid 2>/dev/null\n"
+                       ,
+                               setup_directory
+                       );
+       fprintf(fp,     "               ;;\n"
+                       "restart)       $0 stop\n"
+                       "               $0 start\n"
+                       "               ;;\n"
+                       "*)             echo \"Usage: $0 {start|stop|restart}\"\n"
+                       "               exit 1\n"
+                       "               ;;\n"
+                       "esac\n"
+       );
+
+       fclose(fp);
+       chmod(initfile, 0755);
+
+       /* Set up the run levels. */
+       system("/bin/rm -f /etc/rc?.d/[SK]??citadel 2>/dev/null");
+       snprintf(command, sizeof(command), "for x in 2 3 4 5 ; do [ -d /etc/rc$x.d ] && ln -s %s /etc/rc$x.d/S79citadel ; done 2>/dev/null", initfile);
+       system(command);
+       snprintf(command, sizeof(command),"for x in 0 6 S; do [ -d /etc/rc$x.d ] && ln -s %s /etc/rc$x.d/K30citadel ; done 2>/dev/null", initfile);
+       system(command);
 
 
-       /* Now write it out to /etc/inittab */
-       infp = fopen("/etc/inittab", "a");
-       if (infp == NULL) {
-               display_error(strerror(errno));
-       } else {
-               fprintf(infp, "# Start the Citadel server...\n");
-               fprintf(infp, "%s:2345:respawn:%s -h%s -x3 -llocal4\n",
-                       entryname, looking_for, setup_directory);
-               fclose(infp);
-               strcpy(citserver_init_entry, entryname);
-       }
 }
 
 
 }
 
 
+
+
+
+
 /*
  * On systems which use xinetd, see if we can offer to install Citadel as
  * the default telnet target.
 /*
  * On systems which use xinetd, see if we can offer to install Citadel as
  * the default telnet target.
@@ -569,13 +492,21 @@ void check_xinetd_entry(void) {
        if (already_citadel) return;    /* Already set up this way. */
 
        /* Otherwise, prompt the user to create an entry. */
        if (already_citadel) return;    /* Already set up this way. */
 
        /* Otherwise, prompt the user to create an entry. */
-       snprintf(buf, sizeof buf,
-               "Setup can configure the \"xinetd\" service to automatically\n"
-               "connect incoming telnet sessions to Citadel, bypassing the\n"
-               "host system login: prompt.  Would you like to do this?\n"
-       );
-       if (yesno(buf) == 0)
-               return;
+       if (getenv("CREATE_XINETD_ENTRY") != NULL) {
+               if (strcasecmp(getenv("CREATE_XINETD_ENTRY"), "yes")) {
+                       return;
+               }
+       }
+       else {
+               snprintf(buf, sizeof buf,
+                       "Setup can configure the \"xinetd\" service to automatically\n"
+                       "connect incoming telnet sessions to Citadel, bypassing the\n"
+                       "host system login: prompt.  Would you like to do this?\n"
+               );
+               if (yesno(buf, 1) == 0) {
+                       return;
+               }
+       }
 
        fp = fopen(filename, "w");
        fprintf(fp,
 
        fp = fopen(filename, "w");
        fprintf(fp,
@@ -591,8 +522,7 @@ void check_xinetd_entry(void) {
                "       server_args     = -h -L %s/citadel\n"
                "       log_on_failure  += USERID\n"
                "}\n",
                "       server_args     = -h -L %s/citadel\n"
                "       log_on_failure  += USERID\n"
                "}\n",
-               setup_directory
-       );
+               ctdl_bin_dir);
        fclose(fp);
 
        /* Now try to restart the service */
        fclose(fp);
 
        /* Now try to restart the service */
@@ -621,15 +551,29 @@ void disable_other_mta(char *mta) {
        fclose(fp);
        if (lines == 0) return;         /* Nothing to do. */
 
        fclose(fp);
        if (lines == 0) return;         /* Nothing to do. */
 
+
        /* Offer to replace other MTA with the vastly superior Citadel :)  */
        /* Offer to replace other MTA with the vastly superior Citadel :)  */
-       snprintf(buf, sizeof buf,
-               "You appear to have the \"%s\" email program\n"
-               "running on your system.  Would you like to disable it,\n"
-               "allowing Citadel to handle your Internet mail instead?\n",
-               mta
-       );
-       if (yesno(buf) == 0)
-               return;
+
+       if (getenv("ACT_AS_MTA")) {
+               if (strcasecmp(getenv("ACT_AS_MTA"), "yes")) {
+                       return;
+               }
+       }
+       else {
+               snprintf(buf, sizeof buf,
+                       "You appear to have the \"%s\" email program\n"
+                       "running on your system.  If you want Citadel mail\n"
+                       "connected with %s, you will have to manually integrate\n"
+                       "them.  It is preferable to disable %s, and use Citadel's\n"
+                       "SMTP, POP3, and IMAP services.\n\n"
+                       "May we disable %s so that Citadel has access to ports\n"
+                       "25, 110, and 143?\n",
+                       mta, mta, mta, mta
+               );
+               if (yesno(buf, 1) == 0) {
+                       return;
+               }
+       }
 
        sprintf(buf, "for x in /etc/rc*.d/S*%s; do mv $x `echo $x |sed s/S/K/g`; done >/dev/null 2>&1", mta);
        system(buf);
 
        sprintf(buf, "for x in /etc/rc*.d/S*%s; do mv $x `echo $x |sed s/S/K/g`; done >/dev/null 2>&1", mta);
        system(buf);
@@ -654,11 +598,12 @@ int test_server(void) {
         * to the server and try to get it back.  The cookie does not
         * have to be secret ... just unique.
         */
         * to the server and try to get it back.  The cookie does not
         * have to be secret ... just unique.
         */
-       sprintf(cookie, "%ld.%d", time(NULL), getpid());
+       sprintf(cookie, "--test--%d--", getpid());
 
 
-       sprintf(cmd, "%s/sendcommand -h%s ECHO %s 2>&1",
-               setup_directory,
-               setup_directory,
+       sprintf(cmd, "%s/sendcommand %s%s ECHO %s 2>&1",
+               ctdl_sbin_dir,
+               (enable_home)?"-h":"", 
+               (enable_home)?ctdl_run_dir:"",
                cookie);
 
        fp = popen(cmd, "r");
                cookie);
 
        fp = popen(cmd, "r");
@@ -680,15 +625,9 @@ int test_server(void) {
 
 void strprompt(char *prompt_title, char *prompt_text, char *str)
 {
 
 void strprompt(char *prompt_title, char *prompt_text, char *str)
 {
-#ifdef HAVE_NEWT
-       newtComponent form;
-       char *result;
-       int i;
-       int prompt_window_height = 0;
-#endif
        char buf[SIZ];
        char setupmsg[SIZ];
        char buf[SIZ];
        char setupmsg[SIZ];
-       char *dialog_result;
+       char dialog_result[PATH_MAX];
        FILE *fp = NULL;
 
        strcpy(setupmsg, "");
        FILE *fp = NULL;
 
        strcpy(setupmsg, "");
@@ -701,15 +640,14 @@ void strprompt(char *prompt_title, char *prompt_text, char *str)
                printf("Enter new value or press return to leave unchanged:\n");
                fgets(buf, sizeof buf, stdin);
                buf[strlen(buf) - 1] = 0;
                printf("Enter new value or press return to leave unchanged:\n");
                fgets(buf, sizeof buf, stdin);
                buf[strlen(buf) - 1] = 0;
-               if (strlen(buf) != 0)
+               if (!IsEmptyStr(buf))
                        strcpy(str, buf);
                break;
 
        case UI_DIALOG:
                        strcpy(str, buf);
                break;
 
        case UI_DIALOG:
-               dialog_result = tmpnam(NULL);
-               sprintf(buf, "exec %s --backtitle '%s' --inputbox '%s' 19 72 '%s' 2>%s",
+               CtdlMakeTempFileName(dialog_result, sizeof dialog_result);
+               sprintf(buf, "exec %s --inputbox '%s' 19 72 '%s' 2>%s",
                        getenv("CTDL_DIALOG"),
                        getenv("CTDL_DIALOG"),
-                       prompt_title,
                        prompt_text,
                        str,
                        dialog_result);
                        prompt_text,
                        str,
                        dialog_result);
@@ -725,42 +663,18 @@ void strprompt(char *prompt_title, char *prompt_text, char *str)
                }
                break;
 
                }
                break;
 
-#ifdef HAVE_NEWT
-       case UI_NEWT:
-
-               prompt_window_height = num_tokens(prompt_text, '\n') + 5 ;
-               newtCenteredWindow(76,
-                               prompt_window_height,
-                               prompt_title);
-               form = newtForm(NULL, NULL, 0);
-               for (i=0; i<num_tokens(prompt_text, '\n'); ++i) {
-                       extract_token(buf, prompt_text, i, '\n');
-                       newtFormAddComponent(form, newtLabel(1, 1+i, buf));
-               }
-               newtFormAddComponent(form,
-                       newtEntry(1,
-                               (prompt_window_height - 2),
-                               str,
-                               74,
-                               &result,
-                               NEWT_FLAG_RETURNEXIT)
-               );
-               newtRunForm(form);
-               strcpy(str, result);
-
-               newtPopWindow();
-               newtFormDestroy(form);  
-
-#endif
        }
 }
 
        }
 }
 
+void set_bool_val(int msgpos, int *ip) {
+       title(setup_titles[msgpos]);
+       *ip = yesno(setup_text[msgpos], *ip);
+}
+
 void set_str_val(int msgpos, char *str) {
        strprompt(setup_titles[msgpos], setup_text[msgpos], str);
 }
 
 void set_str_val(int msgpos, char *str) {
        strprompt(setup_titles[msgpos], setup_text[msgpos], str);
 }
 
-
-
 void set_int_val(int msgpos, int *ip)
 {
        char buf[16];
 void set_int_val(int msgpos, int *ip)
 {
        char buf[16];
@@ -792,46 +706,96 @@ void edit_value(int curr)
 {
        int i;
        struct passwd *pw;
 {
        int i;
        struct passwd *pw;
-       char bbsuidname[SIZ];
+       char ctdluidname[256];
 
        switch (curr) {
 
        case 1:
 
        switch (curr) {
 
        case 1:
-               set_str_val(curr, config.c_sysadm);
+               if (setup_type == UI_SILENT)
+               {
+                       if (getenv("SYSADMIN_NAME")) {
+                               strcpy(config.c_sysadm, getenv("SYSADMIN_NAME"));
+                       }
+               }
+               else {
+                       set_str_val(curr, config.c_sysadm);
+               }
                break;
 
        case 2:
                break;
 
        case 2:
+               if (setup_type == UI_SILENT)
+               {               
+                       if (getenv("CITADEL_UID")) {
+                               config.c_ctdluid = atoi(getenv("CITADEL_UID"));
+                       }                                       
+               }
+               else
+               {
 #ifdef __CYGWIN__
 #ifdef __CYGWIN__
-               config.c_bbsuid = 0;    /* XXX Windows hack, prob. insecure */
+                       config.c_ctdluid = 0;   /* XXX Windows hack, prob. insecure */
 #else
 #else
-               i = config.c_bbsuid;
-               pw = getpwuid(i);
-               if (pw == NULL) {
-                       set_int_val(curr, &i);
-                       config.c_bbsuid = i;
-               }
-               else {
-                       strcpy(bbsuidname, pw->pw_name);
-                       set_str_val(curr, bbsuidname);
-                       pw = getpwnam(bbsuidname);
-                       if (pw != NULL) {
-                               config.c_bbsuid = pw->pw_uid;
+                       i = config.c_ctdluid;
+                       pw = getpwuid(i);
+                       if (pw == NULL) {
+                               set_int_val(curr, &i);
+                               config.c_ctdluid = i;
                        }
                        }
-                       else if (atoi(bbsuidname) > 0) {
-                               config.c_bbsuid = atoi(bbsuidname);
+                       else {
+                               strcpy(ctdluidname, pw->pw_name);
+                               set_str_val(curr, ctdluidname);
+                               pw = getpwnam(ctdluidname);
+                               if (pw != NULL) {
+                                       config.c_ctdluid = pw->pw_uid;
+                               }
+                               else if (atoi(ctdluidname) > 0) {
+                                       config.c_ctdluid = atoi(ctdluidname);
+                               }
                        }
                        }
-               }
 #endif
 #endif
+               }
                break;
 
        case 3:
                break;
 
        case 3:
-               set_str_val(curr, config.c_ip_addr);
+               if (setup_type == UI_SILENT)
+               {
+                       if (getenv("IP_ADDR")) {
+                               strcpy(config.c_ip_addr, getenv("IP_ADDR"));
+                       }
+               }
+               else {
+                       set_str_val(curr, config.c_ip_addr);
+               }
                break;
 
        case 4:
                break;
 
        case 4:
-               set_int_val(curr, &config.c_port_number);
+               if (setup_type == UI_SILENT)
+               {
+                       if (getenv("CITADEL_PORT")) {
+                               config.c_port_number = atoi(getenv("CITADEL_PORT"));
+                       }
+               }
+               else
+               {
+                       set_int_val(curr, &config.c_port_number);
+               }
                break;
 
                break;
 
+       case 5:
+               if (setup_type == UI_SILENT)
+               {
+                       if (getenv("ENABLE_UNIX_AUTH")) {
+                               if (!strcasecmp(getenv("ENABLE_UNIX_AUTH"), "yes")) {
+                                       config.c_auth_mode = 1;
+                               }
+                               else {
+                                       config.c_auth_mode = 0;
+                               }
+                       }
+               }
+               else {
+                       set_bool_val(curr, &config.c_auth_mode);
+               }
+               break;
 
        }
 }
 
        }
 }
@@ -844,7 +808,7 @@ void write_config_to_disk(void)
        FILE *fp;
        int fd;
 
        FILE *fp;
        int fd;
 
-       if ((fd = creat("citadel.config", S_IRUSR | S_IWUSR)) == -1) {
+       if ((fd = creat(file_citadel_config, S_IRUSR | S_IWUSR)) == -1) {
                display_error("setup: cannot open citadel.config");
                cleanup(1);
        }
                display_error("setup: cannot open citadel.config");
                cleanup(1);
        }
@@ -871,13 +835,6 @@ int discover_ui(void)
                return UI_DIALOG;
        }
                
                return UI_DIALOG;
        }
                
-
-#ifdef HAVE_NEWT
-       newtInit();
-       newtCls();
-       newtDrawRootText(0, 0, "Citadel Setup");
-       return UI_NEWT;
-#endif
        return UI_TEXT;
 }
 
        return UI_TEXT;
 }
 
@@ -885,10 +842,100 @@ int discover_ui(void)
 
 
 
 
 
 
+/*
+ * Strip "db" entries out of /etc/nsswitch.conf
+ */
+void fixnss(void) {
+       FILE *fp_read;
+       int fd_write;
+       char buf[256];
+       char buf_nc[256];
+       char question[512];
+       int i;
+       int changed = 0;
+       int file_changed = 0;
+       char new_filename[64];
+
+       fp_read = fopen(NSSCONF, "r");
+       if (fp_read == NULL) {
+               return;
+       }
+
+       strcpy(new_filename, "/tmp/ctdl_fixnss_XXXXXX");
+       fd_write = mkstemp(new_filename);
+       if (fd_write < 0) {
+               fclose(fp_read);
+               return;
+       }
+
+       while (fgets(buf, sizeof buf, fp_read) != NULL) {
+               changed = 0;
+               strcpy(buf_nc, buf);
+               for (i=0; i<strlen(buf_nc); ++i) {
+                       if (buf_nc[i] == '#') {
+                               buf_nc[i] = 0;
+                       }
+               }
+               for (i=0; i<strlen(buf_nc); ++i) {
+                       if (!strncasecmp(&buf_nc[i], "db", 2)) {
+                               if (i > 0) {
+                                       if ((isspace(buf_nc[i+2])) || (buf_nc[i+2]==0)) {
+                                               changed = 1;
+                                               file_changed = 1;
+                                               strcpy(&buf_nc[i], &buf_nc[i+2]);
+                                               strcpy(&buf[i], &buf[i+2]);
+                                               if (buf[i]==32) {
+                                                       strcpy(&buf_nc[i], &buf_nc[i+1]);
+                                                       strcpy(&buf[i], &buf[i+1]);
+                                               }
+                                       }
+                               }
+                       }
+               }
+               if (write(fd_write, buf, strlen(buf)) != strlen(buf)) {
+                       fclose(fp_read);
+                       close(fd_write);
+                       unlink(new_filename);
+                       return;
+               }
+       }
+
+       fclose(fp_read);
+       
+       if (!file_changed) {
+               unlink(new_filename);
+               return;
+       }
+
+       snprintf(question, sizeof question,
+               "\n"
+               "/etc/nsswitch.conf is configured to use the 'db' module for\n"
+               "one or more services.  This is not necessary on most systems,\n"
+               "and it is known to crash the Citadel server when delivering\n"
+               "mail to the Internet.\n"
+               "\n"
+               "Do you want this module to be automatically disabled?\n"
+               "\n"
+       );
+
+       if (yesno(question, 1)) {
+               sprintf(buf, "/bin/mv -f %s %s", new_filename, NSSCONF);
+               system(buf);
+       }
+       unlink(new_filename);
+}
+
+
+
+
+
+
+
+
 int main(int argc, char *argv[])
 {
        int a;
 int main(int argc, char *argv[])
 {
        int a;
-       int curr;
+       int curr; 
        char aaa[128];
        FILE *fp;
        int old_setup_level = 0;
        char aaa[128];
        FILE *fp;
        int old_setup_level = 0;
@@ -897,11 +944,17 @@ int main(int argc, char *argv[])
        struct passwd *pw;
        struct hostent *he;
        gid_t gid;
        struct passwd *pw;
        struct hostent *he;
        gid_t gid;
+       int relh=0;
+       int home=0;
+       char relhome[PATH_MAX]="";
+       char ctdldir[PATH_MAX]=CTDLDIR;
+       
+       CtdlInitBase64Table();
 
        /* set an invalid setup type */
        setup_type = (-1);
 
 
        /* set an invalid setup type */
        setup_type = (-1);
 
-        /* Check to see if we're running the web installer */
+       /* Check to see if we're running the web installer */
        if (getenv("CITADEL_INSTALLER") != NULL) {
                using_web_installer = 1;
        }
        if (getenv("CITADEL_INSTALLER") != NULL) {
                using_web_installer = 1;
        }
@@ -934,7 +987,7 @@ int main(int argc, char *argv[])
        }
 
        /* Get started in a valid setup directory. */
        }
 
        /* Get started in a valid setup directory. */
-       strcpy(setup_directory, BBSDIR);
+       strcpy(setup_directory, ctdl_run_dir);
        if ( (using_web_installer) && (getenv("CITADEL") != NULL) ) {
                strcpy(setup_directory, getenv("CITADEL"));
        }
        if ( (using_web_installer) && (getenv("CITADEL") != NULL) ) {
                strcpy(setup_directory, getenv("CITADEL"));
        }
@@ -942,23 +995,39 @@ int main(int argc, char *argv[])
                set_str_val(0, setup_directory);
        }
 
                set_str_val(0, setup_directory);
        }
 
-       if (chdir(setup_directory) != 0) {
-               important_message("Citadel Setup",
-                         "The directory you specified does not exist.");
-               cleanup(errno);
+       home=(setup_directory[1]!='\0');
+       relh=home&(setup_directory[1]!='/');
+       if (!relh) {
+               safestrncpy(ctdl_home_directory, setup_directory, sizeof ctdl_home_directory);
+       }
+       else {
+               safestrncpy(relhome, ctdl_home_directory, sizeof relhome);
+       }
+
+       calc_dirs_n_files(relh, home, relhome, ctdldir, 0);
+       
+       enable_home=(relh|home);
+
+       if (home) {
+               if (chdir(setup_directory) == 0) {
+                       strcpy(file_citadel_config, "./citadel.config");
+               }
+               else {
+                       important_message("Citadel Setup",
+                               "The directory you specified does not exist.");
+                       cleanup(errno);
+               }
        }
 
        /* Determine our host name, in case we need to use it as a default */
        uname(&my_utsname);
 
        }
 
        /* Determine our host name, in case we need to use it as a default */
        uname(&my_utsname);
 
-       /* See if we need to shut down the Citadel service. */
-       for (a=0; a<=3; ++a) {
-               progress("Shutting down the Citadel service...", a, 3);
-               if (a == 0) shutdown_citserver();
-               sleep(1);
+       /* Try to stop Citadel if we can */
+       if (!access("/etc/init.d/citadel", X_OK)) {
+               system("/etc/init.d/citadel stop");
        }
 
        }
 
-       /* Make sure it's stopped. */
+       /* Make sure Citadel is not running. */
        if (test_server() == 0) {
                important_message("Citadel Setup",
                        "The Citadel service is still running.\n"
        if (test_server() == 0) {
                important_message("Citadel Setup",
                        "The Citadel service is still running.\n"
@@ -972,7 +1041,7 @@ int main(int argc, char *argv[])
 
        case UI_TEXT:
                printf("\n\n\n"
 
        case UI_TEXT:
                printf("\n\n\n"
-                       "               *** Citadel setup program ***\n\n");
+                       "              *** Citadel setup program ***\n\n");
                break;
 
        }
                break;
 
        }
@@ -987,8 +1056,7 @@ int main(int argc, char *argv[])
         * to be when we rewrite it, because we replace the old file with a
         * completely new copy.
         */
         * to be when we rewrite it, because we replace the old file with a
         * completely new copy.
         */
-
-       if ((a = open("citadel.config", O_WRONLY | O_CREAT | O_APPEND,
+       if ((a = open(file_citadel_config, O_WRONLY | O_CREAT | O_APPEND,
                      S_IRUSR | S_IWUSR)) == -1) {
                display_error("setup: cannot append citadel.config");
                cleanup(errno);
                      S_IRUSR | S_IWUSR)) == -1) {
                display_error("setup: cannot append citadel.config");
                cleanup(errno);
@@ -1003,7 +1071,7 @@ int main(int argc, char *argv[])
        fclose(fp);
 
        /* now we re-open it, and read the old or blank configuration */
        fclose(fp);
 
        /* now we re-open it, and read the old or blank configuration */
-       fp = fopen("citadel.config", "rb");
+       fp = fopen(file_citadel_config, "rb");
        if (fp == NULL) {
                display_error("setup: cannot open citadel.config");
                cleanup(errno);
        if (fp == NULL) {
                display_error("setup: cannot open citadel.config");
                cleanup(errno);
@@ -1012,11 +1080,11 @@ int main(int argc, char *argv[])
        fclose(fp);
 
        /* set some sample/default values in place of blanks... */
        fclose(fp);
 
        /* set some sample/default values in place of blanks... */
-       if (strlen(config.c_nodename) == 0)
+       if (IsEmptyStr(config.c_nodename))
                safestrncpy(config.c_nodename, my_utsname.nodename,
                            sizeof config.c_nodename);
        strtok(config.c_nodename, ".");
                safestrncpy(config.c_nodename, my_utsname.nodename,
                            sizeof config.c_nodename);
        strtok(config.c_nodename, ".");
-       if (strlen(config.c_fqdn) == 0) {
+       if (IsEmptyStr(config.c_fqdn) ) {
                if ((he = gethostbyname(my_utsname.nodename)) != NULL)
                        safestrncpy(config.c_fqdn, he->h_name,
                                    sizeof config.c_fqdn);
                if ((he = gethostbyname(my_utsname.nodename)) != NULL)
                        safestrncpy(config.c_fqdn, he->h_name,
                                    sizeof config.c_fqdn);
@@ -1024,20 +1092,20 @@ int main(int argc, char *argv[])
                        safestrncpy(config.c_fqdn, my_utsname.nodename,
                                    sizeof config.c_fqdn);
        }
                        safestrncpy(config.c_fqdn, my_utsname.nodename,
                                    sizeof config.c_fqdn);
        }
-       if (strlen(config.c_humannode) == 0)
+       if (IsEmptyStr(config.c_humannode))
                strcpy(config.c_humannode, "My System");
                strcpy(config.c_humannode, "My System");
-       if (strlen(config.c_phonenum) == 0)
+       if (IsEmptyStr(config.c_phonenum))
                strcpy(config.c_phonenum, "US 800 555 1212");
        if (config.c_initax == 0) {
                config.c_initax = 4;
        }
                strcpy(config.c_phonenum, "US 800 555 1212");
        if (config.c_initax == 0) {
                config.c_initax = 4;
        }
-       if (strlen(config.c_moreprompt) == 0)
+       if (IsEmptyStr(config.c_moreprompt))
                strcpy(config.c_moreprompt, "<more>");
                strcpy(config.c_moreprompt, "<more>");
-       if (strlen(config.c_twitroom) == 0)
+       if (IsEmptyStr(config.c_twitroom))
                strcpy(config.c_twitroom, "Trashcan");
                strcpy(config.c_twitroom, "Trashcan");
-       if (strlen(config.c_baseroom) == 0)
-               strcpy(config.c_baseroom, "Lobby");
-       if (strlen(config.c_aideroom) == 0)
+       if (IsEmptyStr(config.c_baseroom))
+               strcpy(config.c_baseroom, BASEROOM);
+       if (IsEmptyStr(config.c_aideroom))
                strcpy(config.c_aideroom, "Aide");
        if (config.c_port_number == 0) {
                config.c_port_number = 504;
                strcpy(config.c_aideroom, "Aide");
        if (config.c_port_number == 0) {
                config.c_port_number = 504;
@@ -1045,20 +1113,20 @@ int main(int argc, char *argv[])
        if (config.c_sleeping == 0) {
                config.c_sleeping = 900;
        }
        if (config.c_sleeping == 0) {
                config.c_sleeping = 900;
        }
-       if (config.c_bbsuid == 0) {
+       if (config.c_ctdluid == 0) {
                pw = getpwnam("citadel");
                if (pw != NULL)
                pw = getpwnam("citadel");
                if (pw != NULL)
-                       config.c_bbsuid = pw->pw_uid;
+                       config.c_ctdluid = pw->pw_uid;
        }
        }
-       if (config.c_bbsuid == 0) {
+       if (config.c_ctdluid == 0) {
                pw = getpwnam("bbs");
                if (pw != NULL)
                pw = getpwnam("bbs");
                if (pw != NULL)
-                       config.c_bbsuid = pw->pw_uid;
+                       config.c_ctdluid = pw->pw_uid;
        }
        }
-       if (config.c_bbsuid == 0) {
+       if (config.c_ctdluid == 0) {
                pw = getpwnam("guest");
                if (pw != NULL)
                pw = getpwnam("guest");
                if (pw != NULL)
-                       config.c_bbsuid = pw->pw_uid;
+                       config.c_ctdluid = pw->pw_uid;
        }
        if (config.c_createax == 0) {
                config.c_createax = 3;
        }
        if (config.c_createax == 0) {
                config.c_createax = 3;
@@ -1071,10 +1139,11 @@ int main(int argc, char *argv[])
        }
        /* We need a system default message expiry policy, because this is
         * the top level and there's no 'higher' policy to fall back on.
        }
        /* We need a system default message expiry policy, because this is
         * the top level and there's no 'higher' policy to fall back on.
+        * By default, do not expire messages at all.
         */
        if (config.c_ep.expire_mode == 0) {
         */
        if (config.c_ep.expire_mode == 0) {
-               config.c_ep.expire_mode = EXPIRE_NUMMSGS;
-               config.c_ep.expire_value = 150;
+               config.c_ep.expire_mode = EXPIRE_MANUAL;
+               config.c_ep.expire_value = 0;
        }
 
        /*
        }
 
        /*
@@ -1083,22 +1152,18 @@ int main(int argc, char *argv[])
        if (config.c_smtp_port == 0) config.c_smtp_port = 25;
        if (config.c_pop3_port == 0) config.c_pop3_port = 110;
        if (config.c_imap_port == 0) config.c_imap_port = 143;
        if (config.c_smtp_port == 0) config.c_smtp_port = 25;
        if (config.c_pop3_port == 0) config.c_pop3_port = 110;
        if (config.c_imap_port == 0) config.c_imap_port = 143;
+       if (config.c_msa_port == 0) config.c_msa_port = 587;
+       if (config.c_smtps_port == 0) config.c_smtps_port = 465;
+       if (config.c_pop3s_port == 0) config.c_pop3s_port = 995;
+       if (config.c_imaps_port == 0) config.c_imaps_port = 993;
+       if (config.c_pftcpdict_port == 0) config.c_pftcpdict_port = -1;
+       if (config.c_managesieve_port == 0) config.c_managesieve_port = 2020;
 
        /* Go through a series of dialogs prompting for config info */
 
        /* Go through a series of dialogs prompting for config info */
-       if (setup_type != UI_SILENT) {
-               for (curr = 1; curr <= MAXSETUP; ++curr) {
-                       edit_value(curr);
-               }
+       for (curr = 1; curr <= MAXSETUP; ++curr) {
+               edit_value(curr);
        }
 
        }
 
-       /*
-          if (setuid(config.c_bbsuid) != 0) {
-          important_message("Citadel Setup",
-          "Failed to change the user ID to your Citadel user.");
-          cleanup(errno);
-          }
-        */
-
 /***** begin version update section ***** */
        /* take care of any updating that is necessary */
 
 /***** begin version update section ***** */
        /* take care of any updating that is necessary */
 
@@ -1127,20 +1192,41 @@ NEW_INST:
 
        write_config_to_disk();
 
 
        write_config_to_disk();
 
-       mkdir("info", 0700);
-       chmod("info", 0700);
-       mkdir("bio", 0700);
-       chmod("bio", 0700);
-       mkdir("userpics", 0700);
-       chmod("userpics", 0700);
-       mkdir("messages", 0700);
-       chmod("messages", 0700);
-       mkdir("help", 0700);
-       chmod("help", 0700);
-       mkdir("images", 0700);
-       chmod("images", 0700);
-       mkdir("netconfigs", 0700);
-       chmod("netconfigs", 0700);
+       mkdir(ctdl_info_dir, 0700);
+       chmod(ctdl_info_dir, 0700);
+       chown(ctdl_info_dir, config.c_ctdluid, -1);
+
+       mkdir(ctdl_bio_dir, 0700);
+       chmod(ctdl_bio_dir, 0700);
+       chown(ctdl_bio_dir, config.c_ctdluid, -1);
+
+       mkdir(ctdl_usrpic_dir, 0700);
+       chmod(ctdl_usrpic_dir, 0700);
+       chown(ctdl_usrpic_dir, config.c_ctdluid, -1);
+
+       mkdir(ctdl_message_dir, 0700);
+       chmod(ctdl_message_dir, 0700);
+       chown(ctdl_message_dir, config.c_ctdluid, -1);
+
+       mkdir(ctdl_hlp_dir, 0700);
+       chmod(ctdl_hlp_dir, 0700);
+       chown(ctdl_hlp_dir, config.c_ctdluid, -1);
+
+       mkdir(ctdl_image_dir, 0700);
+       chmod(ctdl_image_dir, 0700);
+       chown(ctdl_image_dir, config.c_ctdluid, -1);
+
+       mkdir(ctdl_bb_dir, 0700);
+       chmod(ctdl_bb_dir, 0700);
+       chown(ctdl_bb_dir, config.c_ctdluid, -1);
+
+       mkdir(ctdl_file_dir, 0700);
+       chmod(ctdl_file_dir, 0700);
+       chown(ctdl_file_dir, config.c_ctdluid, -1);
+
+       mkdir(ctdl_netcfg_dir, 0700);
+       chmod(ctdl_netcfg_dir, 0700);
+       chown(ctdl_netcfg_dir, config.c_ctdluid, -1);
 
        /* Delete files and directories used by older Citadel versions */
        system("exec /bin/rm -fr ./rooms ./chatpipes ./expressmsgs ./sessions 2>/dev/null");
 
        /* Delete files and directories used by older Citadel versions */
        system("exec /bin/rm -fr ./rooms ./chatpipes ./expressmsgs ./sessions 2>/dev/null");
@@ -1149,75 +1235,78 @@ NEW_INST:
 
        check_services_entry(); /* Check /etc/services */
 #ifndef __CYGWIN__
 
        check_services_entry(); /* Check /etc/services */
 #ifndef __CYGWIN__
-       check_inittab_entry();  /* Check /etc/inittab */
+       delete_inittab_entry(); /* Remove obsolete /etc/inittab entry */
        check_xinetd_entry();   /* Check /etc/xinetd.d/telnet */
 
        /* Offer to disable other MTA's on the system. */
        check_xinetd_entry();   /* Check /etc/xinetd.d/telnet */
 
        /* Offer to disable other MTA's on the system. */
-       disable_other_mta("sendmail");
-       disable_other_mta("postfix");
-       disable_other_mta("qmail");
-       disable_other_mta("cyrus");
-       disable_other_mta("cyrmaster");
-       disable_other_mta("saslauthd");
-       disable_other_mta("mta");
+       disable_other_mta("courier-authdaemon");
        disable_other_mta("courier-imap");
        disable_other_mta("courier-imap-ssl");
        disable_other_mta("courier-imap");
        disable_other_mta("courier-imap-ssl");
-       disable_other_mta("courier-authdaemon");
+       disable_other_mta("courier-pop");
        disable_other_mta("courier-pop3");
        disable_other_mta("courier-pop3d");
        disable_other_mta("courier-pop3");
        disable_other_mta("courier-pop3d");
-       disable_other_mta("courier-pop");
-       disable_other_mta("vmailmgrd");
+       disable_other_mta("cyrmaster");
+       disable_other_mta("cyrus");
+       disable_other_mta("dovecot");
+       disable_other_mta("exim");
+       disable_other_mta("exim4");
        disable_other_mta("imapd");
        disable_other_mta("imapd");
-       disable_other_mta("popd");
+       disable_other_mta("mta");
        disable_other_mta("pop3d");
        disable_other_mta("pop3d");
-       disable_other_mta("exim");
+       disable_other_mta("popd");
+       disable_other_mta("postfix");
+       disable_other_mta("qmail");
+       disable_other_mta("saslauthd");
+       disable_other_mta("sendmail");
+       disable_other_mta("vmailmgrd");
 #endif
 
 #endif
 
-       if ((pw = getpwuid(config.c_bbsuid)) == NULL)
+       /* Check for the 'db' nss and offer to disable it */
+       fixnss();
+
+       if ((pw = getpwuid(config.c_ctdluid)) == NULL)
                gid = getgid();
        else
                gid = pw->pw_gid;
 
                gid = getgid();
        else
                gid = pw->pw_gid;
 
-       progress("Setting file permissions", 0, 4);
-       chown(".", config.c_bbsuid, gid);
-       sleep(1);
-       progress("Setting file permissions", 1, 4);
-       chown("citadel.config", config.c_bbsuid, gid);
-       sleep(1);
-       progress("Setting file permissions", 2, 4);
-       snprintf(aaa, sizeof aaa,
-               "find . | grep -v chkpwd | xargs chown %ld:%ld 2>/dev/null",
-               (long)config.c_bbsuid, (long)gid);
-       system(aaa);
-       sleep(1);
-       progress("Setting file permissions", 3, 4);
-       chmod("citadel.config", S_IRUSR | S_IWUSR);
-       sleep(1);
-       progress("Setting file permissions", 4, 4);
-
-#ifdef HAVE_LDAP
-       /* Contemplate the possibility of auto-configuring OpenLDAP */
-       contemplate_ldap();
-#endif
+       progress("Setting file permissions", 0, 3);
+       chown(ctdl_run_dir, config.c_ctdluid, gid);
+       progress("Setting file permissions", 1, 3);
+       chown(file_citadel_config, config.c_ctdluid, gid);
+       progress("Setting file permissions", 2, 3);
+       chmod(file_citadel_config, S_IRUSR | S_IWUSR);
+       progress("Setting file permissions", 3, 3);
+
+       /* 
+        * If we're running on SysV, install init scripts.
+        */
+       if (!access("/var/run", W_OK)) {
 
 
-       /* See if we can start the Citadel service. */
-       if (strlen(citserver_init_entry) > 0) {
-               for (a=0; a<=3; ++a) {
-                       progress("Starting the Citadel service...", a, 3);
-                       if (a == 0) start_citserver();
-                       sleep(1);
+               if (getenv("NO_INIT_SCRIPTS") == NULL) {
+                       install_init_scripts();
                }
                }
+
+               if (!access("/etc/init.d/citadel", X_OK)) {
+                       system("/etc/init.d/citadel start");
+                       sleep(3);
+               }
+
                if (test_server() == 0) {
                        important_message("Setup finished",
                if (test_server() == 0) {
                        important_message("Setup finished",
-                               "Setup is finished.  You may now log in.");
+                               "Setup of the Citadel server is complete.\n"
+                               "If you will be using WebCit, please run its\n"
+                               "setup program now; otherwise, run './citadel'\n"
+                               "to log in.\n");
                }
                else {
                }
                else {
-                       important_message("Setup finished",
-                               "Setup is finished, but the Citadel service "
-                               "failed to start.\n"
-                               "Go back and check your configuration.");
+                       important_message("Setup failed",
+                               "Setup is finished, but the Citadel server failed to start.\n"
+                               "Go back and check your configuration.\n"
+                       );
                }
                }
+
        }
        }
+
        else {
                important_message("Setup finished",
                        "Setup is finished.  You may now start the server.");
        else {
                important_message("Setup finished",
                        "Setup is finished.  You may now start the server.");
@@ -1228,116 +1317,3 @@ NEW_INST:
 }
 
 
 }
 
 
-#ifdef HAVE_LDAP
-/*
- * If we're in the middle of an Easy Install, we might just be able to
- * auto-configure a standalone OpenLDAP server.
- */
-void contemplate_ldap(void) {
-       char question[SIZ];
-       char slapd_init_entry[SIZ];
-       FILE *fp;
-
-       /* If conditions are not ideal, give up on this idea. */
-       if (using_web_installer == 0) return;
-       if (getenv("LDAP_CONFIG") == NULL) return;
-       if (getenv("SUPPORT") == NULL) return;
-       if (getenv("SLAPD_BINARY") == NULL) return;
-       if (getenv("CITADEL") == NULL) return;
-
-       /* Otherwise, prompt the user to create an entry. */
-       snprintf(question, sizeof question,
-               "\n"
-               "Do you want this computer configured to start a standalone\n"
-               "LDAP service automatically?  (If you answer yes, a custom\n"
-               "slapd.conf will be written, and an /etc/inittab entry\n"
-               "pointing to %s will be added.)\n"
-               "\n",
-               getenv("SLAPD_BINARY")
-       );
-       if (yesno(question) == 0)
-               return;
-
-       strcpy(config.c_ldap_base_dn, "dc=example,dc=com");
-       strprompt("Base DN",
-               "\n"
-               "Please enter the Base DN for your directory.  This will\n"
-               "generally be something based on the primary DNS domain in\n"
-               "which you receive mail, but it does not have to be.  Your\n"
-               "LDAP tree will be built using this Distinguished Name.\n"
-               "\n",
-               config.c_ldap_base_dn
-       );
-
-       strcpy(config.c_ldap_host, "localhost");
-       config.c_ldap_port = 389;
-       sprintf(config.c_ldap_bind_dn, "cn=manager,%s", config.c_ldap_base_dn);
-
-       /* FIXME ... make the generated password harder to guess */
-       sprintf(config.c_ldap_bind_pw, "%d%ld", getpid(), time(NULL));
-
-       write_config_to_disk();
-
-       fp = fopen(getenv("LDAP_CONFIG"), "w");
-       if (fp == NULL) {
-               sprintf(question, "\nCannot create %s:\n%s\n\n"
-                               "Citadel will still function, but you will "
-                               "not have an LDAP service.\n\n",
-                               getenv("LDAP_CONFIG"),
-                               strerror(errno)
-               );
-               important_message("Error", question);
-               return;
-       }
-
-       fprintf(fp, "include    %s/citadel-openldap.schema\n",
-               getenv("CITADEL"));
-       fprintf(fp, "pidfile    %s/openldap-data/slapd.pid\n",
-               getenv("CITADEL"));
-       fprintf(fp, "argsfile   %s/openldap-data/slapd.args\n",
-               getenv("CITADEL"));
-       fprintf(fp,     "allow          bind_v2\n"
-                       "database       bdb\n"
-                       "schemacheck    off\n"
-       );
-       fprintf(fp,     "suffix         \"%s\"\n", config.c_ldap_base_dn);
-       fprintf(fp,     "rootdn         \"%s\"\n", config.c_ldap_bind_dn);
-       fprintf(fp,     "rootpw         %s\n", config.c_ldap_bind_pw);
-       fprintf(fp,     "directory      %s/openldap-data\n",
-               getenv("CITADEL"));
-       fprintf(fp,     "index          objectClass     eq\n");
-
-       fclose(fp);
-
-       /* This is where our OpenLDAP server will keep its data. */
-       mkdir("openldap-data", 0700);
-
-       /* If inittab is already starting slapd, disable the old entry. */
-       locate_init_entry(slapd_init_entry, getenv("SLAPD_BINARY"));
-       if (strlen(slapd_init_entry) > 0) {
-               set_init_entry(slapd_init_entry, "off");
-       }
-
-       /* Generate a unique entry name for slapd */
-       generate_entry_name(slapd_init_entry);
-
-       /* Now write it out to /etc/inittab.
-        * FIXME make it run as some non-root user.
-        * The "-d 0" seems superfluous, but it's actually a way to make
-        * slapd run in the foreground without spewing messages to the console.
-        */
-       fp = fopen("/etc/inittab", "a");
-       if (fp == NULL) {
-               display_error(strerror(errno));
-       } else {
-               fprintf(fp, "# Start the OpenLDAP server for Citadel...\n");
-               fprintf(fp, "%s:2345:respawn:%s -d 0 -f %s\n",
-                       slapd_init_entry,
-                       getenv("SLAPD_BINARY"),
-                       getenv("LDAP_CONFIG")
-               );
-               fclose(fp);
-       }
-
-}
-#endif /* HAVE_LDAP */