Removed test_binary_compatibility() from ctdlvisor.c because we don't do it that...
[citadel.git] / citadel / setup.c
index bf1374d5a018e3be3ee3d41e85150c1fea856311..9083fb8d48d77ed85d7808f161f2192c2ae2c69b 100644 (file)
@@ -1,10 +1,18 @@
 /*
- * $Id$
- *
  * Citadel setup utility
  *
+ * Copyright (c) 1987-2021 by the citadel.org team
+ *
+ * This program is open source software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  */
 
+#define SHOW_ME_VAPPEND_PRINTF
 #include <stdlib.h>
 #include <unistd.h>
 #include <stdio.h>
@@ -13,7 +21,6 @@
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/utsname.h>
 #include <sys/wait.h>
 #include <signal.h>
 #include <netdb.h>
 #include <limits.h>
 #include <pwd.h>
 #include <time.h>
-
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <assert.h>
+#include <libcitadel.h>
 #include "citadel.h"
 #include "axdefs.h"
 #include "sysdep.h"
-#include "config.h"
-#include "tools.h"
 #include "citadel_dirs.h"
 
-#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 */
+#ifdef ENABLE_NLS
+#ifdef HAVE_XLOCALE_H
+#include <xlocale.h>
+#endif
+#include <libintl.h>
+#include <locale.h>
+#define _(string)      gettext(string)
+#else
+#define _(string)      (string)
+#endif
 
 #define SERVICE_NAME   "citadel"
 #define PROTO_NAME     "tcp"
 #define NSSCONF                "/etc/nsswitch.conf"
 
-int setup_type;
-char setup_directory[PATH_MAX];
-int using_web_installer = 0;
-int enable_home = 1;
-
-char *setup_titles[] =
-{
-       "Citadel Home Directory",
-       "System Administrator",
-       "Citadel User ID",
-       "Server IP address",
-       "Server port number",
-       "Authentication mode"
+typedef enum _SetupStep {
+       eCitadelHomeDir = 0,
+       eSysAdminName = 1,
+       eSysAdminPW = 2,
+       eUID = 3,
+       eIP_ADDR = 4,
+       eCTDL_Port = 5,
+       eAuthType = 6,
+       eLDAP_Host = 7,
+       eLDAP_Port = 8,
+       eLDAP_Base_DN = 9,
+       eLDAP_Bind_DN = 10,
+       eLDAP_Bind_PW = 11,
+       eMaxQuestions = 12
+} eSetupStep;
+
+///"CREATE_XINETD_ENTRY";
+/* Environment variables, don't translate! */
+const char *EnvNames [eMaxQuestions] = {
+        "HOME_DIRECTORY",
+       "SYSADMIN_NAME",
+       "SYSADMIN_PW",
+       "CITADEL_UID",
+       "IP_ADDR",
+       "CITADEL_PORT",
+       "ENABLE_UNIX_AUTH",
+       "LDAP_HOST",
+       "LDAP_PORT",
+       "LDAP_BASE_DN",
+       "LDAP_BIND_DN",
+       "LDAP_BIND_PW"
 };
 
+int setup_type = (-1);
+int enable_home = 1;
+char admin_name[SIZ];
+char admin_pass[SIZ];
+char admin_cmd[SIZ];
+int serv_sock = (-1) ;
 
-struct config config;
+const char *setup_titles[eMaxQuestions];
+const char *setup_text[eMaxQuestions];
 
-       /* calculate all our path on a central place */
-    /* where to keep our config */
-       
+char *program_title;
 
-char *setup_text[] = {
+void SetTitles(void)
+{
+       int have_run_dir;
 #ifndef HAVE_RUN_DIR
+       have_run_dir = 1;
+#else
+       have_run_dir = 0;
+#endif
+
+#ifdef ENABLE_NLS
+       setlocale(LC_MESSAGES, getenv("LANG"));
+       bindtextdomain("citadel-setup", LOCALEDIR"/locale");
+       textdomain("citadel-setup");
+       bind_textdomain_codeset("citadel-setup","UTF8");
+#endif
+
+       setup_titles[eCitadelHomeDir] = _("Citadel Home Directory");
+       if (have_run_dir)
+               setup_text[eCitadelHomeDir] = _(
 "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
+"specify the -h flag to the server when you start it up.\n");
+       else
+               setup_text[eCitadelHomeDir] = _(
 "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"
-"automatically be given administrator-level access.\n",
-
+"note that it may not have a leading /");
+
+       setup_titles[eSysAdminName] = _("Citadel administrator username:");
+       setup_text[eSysAdminName] = _(
+"Please enter the name of the Citadel user account that should be granted "
+"administrative privileges once created. If using internal authentication "
+"this user account will be created if it does not exist. For external "
+"authentication this user account has to exist.");
+
+       setup_titles[eSysAdminPW] = _("Administrator password:");
+       setup_text[eSysAdminPW] = _(
+"Enter a password for the system administrator. When setup\n"
+"completes it will attempt to create the administrator user\n"
+"and set the password specified here.\n");
+
+       setup_titles[eUID] = _("Citadel User ID:");
+       setup_text[eUID] = _(
 "Citadel needs to run under its own user ID.  This would\n"
 "typically be called \"citadel\", but if you are running Citadel\n"
-"as a public BBS, you might also call it \"bbs\" or \"guest\".\n"
+"as a public site, you might also call it \"bbs\" or \"guest\".\n"
 "The server will run under this user ID.  Please specify that\n"
 "user ID here.  You may specify either a user name or a numeric\n"
-"UID.\n",
-
-"Specify the IP address on which your server will run.  If you\n"
-"leave this blank, or if you specify 0.0.0.0, Citadel will listen\n"
-"on all addresses.  You can usually skip this unless you are\n"
-"running multiple instances of Citadel on the same computer.\n",
-
+"UID.\n");
+
+       setup_titles[eIP_ADDR] = _("Listening address for the Citadel server:");
+       setup_text[eIP_ADDR] = _(
+"Please specify the IP address which the server should be listening to. "
+"You can name a specific IPv4 or IPv6 address, or you can specify\n"
+"\"*\" for \"any address\", \"::\" for \"any IPv6 address\", or \"0.0.0.0\"\n"
+"for \"any IPv4 address\". If you leave this blank, Citadel will\n"
+"listen on all addresses. "
+"This can usually be left to the default unless multiple instances of Citadel "
+"are running on the same computer.");
+
+       setup_titles[eCTDL_Port] = _("Server port number:");
+       setup_text[eCTDL_Port] = _(
 "Specify the TCP port number on which your server will run.\n"
 "Normally, this will be port 504, which is the official port\n"
 "assigned by the IANA for Citadel servers.  You will only need\n"
 "to specify a different port number if you run multiple instances\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"
+"already using port 504.\n");
+
+       setup_titles[eAuthType] = _("Authentication method to use:");
+       setup_text[eAuthType] = _(
+"Please choose the user authentication mode. By default Citadel will use its "
+"own internal user accounts database. If you choose Host, Citadel users will "
+"have accounts on the host system, authenticated via /etc/passwd or a PAM "
+"source. LDAP chooses an RFC 2307 compliant directory server, the last option "
+"chooses the nonstandard MS Active Directory LDAP scheme."
 "\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;
-
-
-void cleanup(int exitcode)
-{
-       exit(exitcode);
+"Do not change this option unless you are sure it is required, since changing "
+"back requires a full reinstall of Citadel."
+"\n"
+" 0. Self contained authentication\n"
+" 1. Host system integrated authentication\n"
+" 2. External LDAP - RFC 2307 POSIX schema\n"
+" 3. External LDAP - MS Active Directory schema\n"
+"\n"
+"For help: http://www.citadel.org/doku.php/faq:installation:authmodes\n"
+"\n"
+"ANSWER \"0\" UNLESS YOU COMPLETELY UNDERSTAND THIS OPTION.\n");
+
+       setup_titles[eLDAP_Host] = _("LDAP host:");
+       setup_text[eLDAP_Host] = _(
+"Please enter the host name or IP address of your LDAP server.\n");
+
+       setup_titles[eLDAP_Port] = _("LDAP port number:");
+       setup_text[eLDAP_Port] = _(
+"Please enter the port number of the LDAP service (usually 389).\n");
+
+       setup_titles[eLDAP_Base_DN] = _("LDAP base DN:");
+       setup_text[eLDAP_Base_DN] = _(
+"Please enter the Base DN to search for authentication\n"
+"(for example: dc=example,dc=com)\n");
+
+       setup_titles[eLDAP_Bind_DN] = _("LDAP bind DN:");
+       setup_text[eLDAP_Bind_DN] = _(
+"Please enter the DN of an account to use for binding to the LDAP server for "
+"performing queries. The account does not require any other privileges. If "
+"your LDAP server allows anonymous queries, you can leave this blank.\n");
+
+       setup_titles[eLDAP_Bind_PW] = _("LDAP bind password:");
+       setup_text[eLDAP_Bind_PW] = _(
+"If you entered a Bind DN in the previous question, you must now enter\n"
+"the password associated with that account.  Otherwise, you can leave this\n"
+"blank.\n");
+
+#if 0
+// Debug loading of locales... Strace does a better job though.
+       printf("Message catalog directory: %s\n", bindtextdomain("citadel-setup", LOCALEDIR"/locale"));
+       printf("Text domain: %s\n", textdomain("citadel-setup"));
+       printf("Text domain Charset: %s\n", bind_textdomain_codeset("citadel-setup","UTF8"));
+       {
+               int i;
+               for (i = 0; i < eMaxQuestions; i++)
+                       printf("%s - %s\n", setup_titles[i], _(setup_titles[i]));
+               exit(0);
+       }
+#endif
 }
 
 
-
-void title(char *text)
-{
-       if (setup_type == UI_TEXT) {
-               printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<%s>\n", text);
-       }
+void title(const char *text) {
+       printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<%s>\n", text);
 }
 
 
-
-int yesno(char *question, int default_value)
-{
-       int i = 0;
+int yesno(const char *question, int default_value) {
        int answer = 0;
        char buf[SIZ];
 
-       switch (setup_type) {
-
-       case UI_TEXT:
-               do {
-                       printf("%s\nYes/No [%s] --> ",
-                               question,
-                               ( default_value ? "Yes" : "No" )
-                       );
-                       fgets(buf, sizeof buf, stdin);
+       do {
+               printf("%s\n%s [%s] --> ", question, _("Yes/No"), ( default_value ? _("Yes") : _("No") ));
+               if (fgets(buf, sizeof buf, stdin)) {
                        answer = tolower(buf[0]);
-                       if ((buf[0]==0) || (buf[0]==13) || (buf[0]==10))
+                       if ((buf[0]==0) || (buf[0]==13) || (buf[0]==10)) {
                                answer = default_value;
-                       else if (answer == 'y')
+                       }
+                       else if (answer == 'y') {
                                answer = 1;
-                       else if (answer == 'n')
+                       }
+                       else if (answer == 'n') {
                                answer = 0;
-               } while ((answer < 0) || (answer > 1));
-               break;
-
-       case UI_DIALOG:
-               sprintf(buf, "exec %s %s --yesno '%s' 15 75",
-                       getenv("CTDL_DIALOG"),
-                       ( default_value ? "" : "--defaultno" ),
-                       question);
-               i = system(buf);
-               if (i == 0) {
-                       answer = 1;
-               }
-               else {
-                       answer = 0;
+                       }
                }
-               break;
-
-       }
+       } while ((answer < 0) || (answer > 1));
        return (answer);
 }
 
 
-void important_message(char *title, char *msgtext)
-{
+void important_message(const char *title, const char *msgtext) {
        char buf[SIZ];
 
-       switch (setup_type) {
-
-       case UI_TEXT:
-               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");
-               printf("       %s \n\n%s\n\n", title, msgtext);
-               printf("Press return to continue...");
-               fgets(buf, sizeof buf, stdin);
-               break;
-
-       case UI_DIALOG:
-               sprintf(buf, "exec %s --msgbox '%s' 19 72",
-                       getenv("CTDL_DIALOG"),
-                       msgtext);
-               system(buf);
-               break;
+       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");
+       printf("       %s \n\n%s\n\n", title, msgtext);
+       printf("%s", _("Press return to continue..."));
+       if (fgets(buf, sizeof buf, stdin)) {
+               ;
        }
 }
 
-void important_msgnum(int msgnum)
-{
-       important_message("Important Message", setup_text[msgnum]);
+
+void important_msgnum(int msgnum) {
+       important_message(_("Important Message"), setup_text[msgnum]);
 }
 
-void display_error(char *error_message)
-{
-       important_message("Error", error_message);
+
+void display_error(char *error_message_format, ...) {
+       StrBuf *Msg;
+       va_list arg_ptr;
+
+       Msg = NewStrBuf();
+       va_start(arg_ptr, error_message_format);
+       StrBufVAppendPrintf(Msg, error_message_format, arg_ptr);
+       va_end(arg_ptr);
+
+       important_message(_("Error"), ChrPtr(Msg));
+       FreeStrBuf(&Msg);
 }
 
-void progress(char *text, long int curr, long int cmax)
-{
+
+void progress(char *text, long int curr, long int cmax) {
        static long dots_printed = 0L;
        long a = 0;
-       static FILE *fp = NULL;
-       char buf[SIZ];
 
-       switch (setup_type) {
-
-       case UI_TEXT:
-               if (curr == 0) {
-                       printf("%s\n", text);
-                       printf("..........................");
-                       printf("..........................");
-                       printf("..........................\r");
-                       fflush(stdout);
-                       dots_printed = 0;
-               } else if (curr == cmax) {
-                       printf("\r%79s\n", "");
-               } else {
-                       a = (curr * 100) / cmax;
-                       a = a * 78;
-                       a = a / 100;
-                       while (dots_printed < a) {
-                               printf("*");
-                               ++dots_printed;
-                               fflush(stdout);
-                       }
-               }
-               break;
+       if (curr == 0) {
+               printf("%s\n", text);
+               printf("....................................................");
+               printf("..........................\r");
+               dots_printed = 0;
+       } else if (curr == cmax) {
+               printf("\r%79s\n", "");
+       } else {
+               a = (curr * 100) / cmax;
+               a = a * 78;
+               a = a / 100;
+               while (dots_printed < a) {
+                       printf("*");
+                       ++dots_printed;
+               }
+       }
+       fflush(stdout);
+}
 
-       case UI_DIALOG:
-               if (curr == 0) {
-                       sprintf(buf, "exec %s --gauge '%s' 7 72 0",
-                               getenv("CTDL_DIALOG"),
-                               text);
-                       fp = popen(buf, "w");
-                       if (fp != NULL) {
-                               fprintf(fp, "0\n");
-                               fflush(fp);
-                       }
-               } 
-               else if (curr == cmax) {
-                       if (fp != NULL) {
-                               fprintf(fp, "100\n");
-                               pclose(fp);
-                               fp = NULL;
-                       }
-               }
-               else {
-                       a = (curr * 100) / cmax;
-                       if (fp != NULL) {
-                               fprintf(fp, "%ld\n", a);
-                               fflush(fp);
-                       }
-               }
-               break;
 
+int uds_connectsock(char *sockpath) {
+       int s;
+       struct sockaddr_un addr;
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       strcpy(addr.sun_path, sockpath);
+
+       s = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (s < 0) {
+               return(-1);
+       }
+
+       if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               close(s);
+               return(-1);
        }
-}
 
+       return s;
+}
 
 
 /*
- * check_services_entry()  -- Make sure "citadel" is in /etc/services
- *
+ * input binary data from socket
  */
-void check_services_entry(void)
-{
-       int i;
-       FILE *sfp;
-       char errmsg[256];
-
-       if (getservbyname(SERVICE_NAME, PROTO_NAME) == NULL) {
-               for (i=0; i<=2; ++i) {
-                       progress("Adding service entry...", i, 2);
-                       if (i == 0) {
-                               sfp = fopen("/etc/services", "a");
-                               if (sfp == NULL) {
-                                       sprintf(errmsg, "Cannot open /etc/services: %s", strerror(errno));
-                                       display_error(errmsg);
-                               } else {
-                                       fprintf(sfp, "%s                504/tcp\n", SERVICE_NAME);
-                                       fclose(sfp);
-                               }
-                       }
+void serv_read(char *buf, int bytes) {
+       int len, rlen;
+
+       len = 0;
+       while (len < bytes) {
+               rlen = read(serv_sock, &buf[len], bytes - len);
+               if (rlen < 1) {
+                       return;
                }
+               len = len + rlen;
        }
 }
 
 
-
-
 /*
- * delete_inittab_entry()  -- Remove obsolete /etc/inittab entry for Citadel
- *
+ * send binary to server
  */
-void delete_inittab_entry(void)
-{
-       FILE *infp;
-       FILE *outfp;
-       char looking_for[256];
-       char buf[1024];
-       char outfilename[32];
-       int changes_made = 0;
-
-       /* 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) {
+void serv_write(char *buf, int nbytes) {
+       int bytes_written = 0;
+       int retval;
+       while (bytes_written < nbytes) {
+               retval = write(serv_sock, &buf[bytes_written], nbytes - bytes_written);
+               if (retval < 1) {
                        return;
                }
-
-               /* Other errors might mean something really did go wrong.
-                */
-               sprintf(buf, "Cannot open /etc/inittab: %s", strerror(errno));
-               display_error(buf);
-               return;
+               bytes_written = bytes_written + retval;
        }
+}
+
+
+/*
+ * input string from socket - implemented in terms of serv_read()
+ */
+void serv_gets(char *buf) {
+       int i;
 
-       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;
+       /* Read one character at a time.
+        */
+       for (i = 0;; i++) {
+               serv_read(&buf[i], 1);
+               if (buf[i] == '\n' || i == (SIZ-1))
+                       break;
        }
 
-       while (fgets(buf, sizeof buf, infp) != NULL) {
-               if (strstr(buf, looking_for) != NULL) {
-                       fwrite("#", 1, 1, outfp);
-                       ++changes_made;
+       /* If we got a long line, discard characters until the newline.
+        */
+       if (i == (SIZ-1)) {
+               while (buf[i] != '\n') {
+                       serv_read(&buf[i], 1);
                }
-               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);
-       }
+       /* Strip all trailing nonprintables (crlf)
+        */
+       buf[i] = 0;
 }
 
 
 /*
- * install_init_scripts()  -- Try to configure to start Citadel at boot
- *
+ * send line to server - implemented in terms of serv_write()
  */
-void install_init_scripts(void)
-{
-       struct stat etcinitd;
-       FILE *fp;
-       char *initfile = "/etc/init.d/citadel";
-       char command[SIZ];
+void serv_puts(char *buf) {
+       serv_write(buf, strlen(buf));
+       serv_write("\n", 1);
+}
 
-       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";
-       }
 
-       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);
-               
-       }
+/*
+ * Convenience functions to get/set system configuration entries
+ */
+void getconf_str(char *buf, char *key) {
+       char cmd[SIZ];
+       char ret[SIZ];
 
-       if (yesno("Would you like to automatically start Citadel at boot?\n", 1) == 0) {
-               return;
+       sprintf(cmd, "CONF GETVAL|%s", key);
+       serv_puts(cmd);
+       serv_gets(ret);
+       if (ret[0] == '2') {
+               extract_token(buf, &ret[4], 0, '|', SIZ);
        }
-
-       fp = fopen(initfile, "w");
-       if (fp == NULL) {
-               display_error("Cannot create /etc/init.d/citadel");
-               return;
+       else {
+               strcpy(buf, "");
        }
+}
 
-       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);
+int getconf_int(char *key) {
+       char buf[SIZ];
+       getconf_str(buf, key);
+       return atoi(buf);
+}
 
-       /* 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);
 
-}
+void setconf_str(char *key, char *val) {
+       char buf[SIZ];
 
+       sprintf(buf, "CONF PUTVAL|%s|%s", key, val);
+       serv_puts(buf);
+       serv_gets(buf);
+}
 
 
+void setconf_int(char *key, int val) {
+       char buf[SIZ];
 
+       sprintf(buf, "CONF PUTVAL|%s|%d", key, val);
+       serv_puts(buf);
+       serv_gets(buf);
+}
 
 
 /*
  * On systems which use xinetd, see if we can offer to install Citadel as
  * the default telnet target.
  */
-void check_xinetd_entry(void) {
+void check_xinetd_entry(void)
+{
        char *filename = "/etc/xinetd.d/telnet";
        FILE *fp;
        char buf[SIZ];
        int already_citadel = 0;
+       int rv;
 
        fp = fopen(filename, "r+");
        if (fp == NULL) return;         /* Not there.  Oh well... */
 
        while (fgets(buf, sizeof buf, fp) != NULL) {
-               if (strstr(buf, setup_directory) != NULL) already_citadel = 1;
+               if (strstr(buf, "/citadel") != NULL) {
+                       already_citadel = 1;
+               }
        }
        fclose(fp);
        if (already_citadel) return;    /* Already set up this way. */
@@ -500,9 +479,10 @@ void check_xinetd_entry(void) {
        }
        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"
+                        _("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;
@@ -523,441 +503,208 @@ void check_xinetd_entry(void) {
                "       server_args     = -h -L %s/citadel\n"
                "       log_on_failure  += USERID\n"
                "}\n",
-               ctdl_bin_dir);
-       fclose(fp);
-
-       /* Now try to restart the service */
-       system("/etc/init.d/xinetd restart >/dev/null 2>&1");
-}
-
-
-
-/*
- * Offer to disable other MTA's
- */
-void disable_other_mta(char *mta) {
-       char buf[SIZ];
-       FILE *fp;
-       int lines = 0;
-
-       sprintf(buf, "/bin/ls -l /etc/rc*.d/S*%s 2>/dev/null; "
-               "/bin/ls -l /etc/rc.d/rc*.d/S*%s 2>/dev/null",
-               mta, mta);
-       fp = popen(buf, "r");
-       if (fp == NULL) return;
-
-       while (fgets(buf, sizeof buf, fp) != NULL) {
-               ++lines;
-       }
+               ctdl_bin_dir
+       );
        fclose(fp);
-       if (lines == 0) return;         /* Nothing to do. */
-
-
-       /* Offer to replace other MTA with the vastly superior Citadel :)  */
 
-       if (getenv("ACT_AS_MTA")) {
-               if (strcasecmp(getenv("ACT_AS_MTA"), "yes")) {
-                       return;
-               }
+       /* Now try to restart the service.  This will not have the intended effect on Solaris, but who uses Solaris anymore? */
+       rv = system("systemctl restart xinetd >/dev/null 2>&1");
+       if (rv != 0) {
+               rv = system("service xinetd restart >/dev/null 2>&1");
        }
-       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;
-               }
+       if (rv != 0) {
+               display_error(_("failed to restart xinetd.\n"));
        }
-
-       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, "/etc/init.d/%s stop >/dev/null 2>&1", mta);
-       system(buf);
 }
 
 
-
-
-/* 
- * Check to see if our server really works.  Returns 0 on success.
- */
-int test_server(void) {
-       char cmd[256];
-       char cookie[256];
-       FILE *fp;
-       char buf[4096];
-       int found_it = 0;
-
-       /* Generate a silly little cookie.  We're going to write it out
-        * to the server and try to get it back.  The cookie does not
-        * have to be secret ... just unique.
-        */
-       sprintf(cookie, "--test--%d--", getpid());
-
-       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");
-       if (fp == NULL) return(errno);
-
-       while (fgets(buf, sizeof buf, fp) != NULL) {
-               if ( (buf[0]=='2')
-                  && (strstr(buf, cookie) != NULL) ) {
-                       ++found_it;
-               }
-       }
-       pclose(fp);
-
-       if (found_it) {
-               return(0);
-       }
-       return(-1);
-}
-
-void strprompt(char *prompt_title, char *prompt_text, char *str)
+void strprompt(const char *prompt_title, const char *prompt_text, char *Target, char *DefValue)
 {
-       char buf[SIZ];
+       char buf[SIZ] = "";
        char setupmsg[SIZ];
-       char dialog_result[PATH_MAX];
-       FILE *fp = NULL;
 
        strcpy(setupmsg, "");
 
-       switch (setup_type) {
-       case UI_TEXT:
-               title(prompt_title);
-               printf("\n%s\n", prompt_text);
-               printf("This is currently set to:\n%s\n", str);
-               printf("Enter new value or press return to leave unchanged:\n");
-               fgets(buf, sizeof buf, stdin);
+       title(prompt_title);
+       printf("\n%s\n", prompt_text);
+       printf("%s\n%s\n", _("This is currently set to:"), Target);
+       printf("%s\n", _("Enter new value or press return to leave unchanged:"));
+       if (fgets(buf, sizeof buf, stdin)) {
                buf[strlen(buf) - 1] = 0;
-               if (!IsEmptyStr(buf))
-                       strcpy(str, buf);
-               break;
-
-       case UI_DIALOG:
-               CtdlMakeTempFileName(dialog_result, sizeof dialog_result);
-               sprintf(buf, "exec %s --inputbox '%s' 19 72 '%s' 2>%s",
-                       getenv("CTDL_DIALOG"),
-                       prompt_text,
-                       str,
-                       dialog_result);
-               system(buf);
-               fp = fopen(dialog_result, "r");
-               if (fp != NULL) {
-                       fgets(str, sizeof buf, fp);
-                       if (str[strlen(str)-1] == 10) {
-                               str[strlen(str)-1] = 0;
-                       }
-                       fclose(fp);
-                       unlink(dialog_result);
-               }
-               break;
-
+       }
+       if (!IsEmptyStr(buf)) {
+               strcpy(Target, buf);
        }
 }
 
-void set_bool_val(int msgpos, int *ip) {
+
+void set_bool_val(int msgpos, int *ip, char *DefValue) {
        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_int_val(int msgpos, int *ip)
-{
-       char buf[16];
-       snprintf(buf, sizeof buf, "%d", (int) *ip);
-       set_str_val(msgpos, buf);
-       *ip = atoi(buf);
-}
-
 
-void set_char_val(int msgpos, char *ip)
+void set_str_val(int msgpos, char *Target, char *DefValue) 
 {
-       char buf[16];
-       snprintf(buf, sizeof buf, "%d", (int) *ip);
-       set_str_val(msgpos, buf);
-       *ip = (char) atoi(buf);
+       strprompt(setup_titles[msgpos], 
+                 setup_text[msgpos], 
+                 Target, 
+                 DefValue
+       );
 }
 
 
-void set_long_val(int msgpos, long int *ip)
+/* like set_str_val() but for numeric values */
+void set_int_val(int msgpos, int *target, char *default_value)
 {
-       char buf[16];
-       snprintf(buf, sizeof buf, "%ld", *ip);
-       set_str_val(msgpos, buf);
-       *ip = atol(buf);
+       char buf[32];
+       sprintf(buf, "%d", *target);
+       do {
+               set_str_val(msgpos, buf, default_value);
+       } while ( (strcmp(buf, "0")) && (atoi(buf) == 0) );
+       *target = atoi(buf);
 }
 
 
 void edit_value(int curr)
 {
-       int i;
-       struct passwd *pw;
+       struct passwd *pw = NULL;
        char ctdluidname[256];
+       char buf[SIZ];
+       char *default_value = NULL;
+       int ctdluid = 0;
+       int portnum = 0;
+       int auth = 0;
+       int lportnum = 0;
+
+       if (default_value == NULL) {
+               default_value = "";
+       }
 
        switch (curr) {
 
-       case 1:
-               if (setup_type == UI_SILENT)
-               {
-                       if (getenv("SYSADMIN_NAME")) {
-                               strcpy(config.c_sysadm, getenv("SYSADMIN_NAME"));
-                       }
-               }
-               else {
-                       set_str_val(curr, config.c_sysadm);
-               }
+       case eSysAdminName:
+               getconf_str(admin_name, "c_sysadm");
+               set_str_val(curr, admin_name, default_value);
+               setconf_str("c_sysadm", admin_name);
                break;
 
-       case 2:
-               if (setup_type == UI_SILENT)
-               {               
-                       if (getenv("CITADEL_UID")) {
-                               config.c_ctdluid = atoi(getenv("CITADEL_UID"));
-                       }                                       
+       case eSysAdminPW:
+               set_str_val(curr, admin_pass, default_value);
+               break;
+       
+       case eUID:
+               ctdluid = getconf_int("c_ctdluid");
+               pw = getpwuid(ctdluid);
+               if (pw == NULL) {
+                       set_int_val(curr, &ctdluid, default_value);
                }
-               else
-               {
-#ifdef __CYGWIN__
-                       config.c_ctdluid = 0;   /* XXX Windows hack, prob. insecure */
-#else
-                       i = config.c_ctdluid;
-                       pw = getpwuid(i);
-                       if (pw == NULL) {
-                               set_int_val(curr, &i);
-                               config.c_ctdluid = i;
+               else {
+                       strcpy(ctdluidname, pw->pw_name);
+                       set_str_val(curr, ctdluidname, default_value);
+                       pw = getpwnam(ctdluidname);
+                       if (pw != NULL) {
+                               ctdluid = pw->pw_uid;
                        }
-                       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);
-                               }
+                       else if (atoi(ctdluidname) > 0) {
+                               ctdluid = atoi(ctdluidname);
                        }
-#endif
                }
+               setconf_int("c_ctdluid", ctdluid);
                break;
 
-       case 3:
-               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);
-               }
+       case eIP_ADDR:
+               getconf_str(buf, "c_ip_addr");
+               set_str_val(curr, buf, default_value);
+               setconf_str("c_ip_addr", buf);
                break;
 
-       case 4:
-               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);
-               }
+       case eCTDL_Port:
+               portnum = getconf_int("c_port_number");
+               set_int_val(curr, &portnum, default_value);
+               setconf_int("c_port_number", portnum);
                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);
-               }
+       case eAuthType:
+               auth = getconf_int("c_auth_mode");
+               set_int_val(curr, &auth, default_value);
+               setconf_int("c_auth_mode", auth);
                break;
 
-       }
-}
-
-/*
- * (re-)write the config data to disk
- */
-void write_config_to_disk(void)
-{
-       FILE *fp;
-       int fd;
-
-       if ((fd = creat(file_citadel_config, S_IRUSR | S_IWUSR)) == -1) {
-               display_error("setup: cannot open citadel.config");
-               cleanup(1);
-       }
-       fp = fdopen(fd, "wb");
-       if (fp == NULL) {
-               display_error("setup: cannot open citadel.config");
-               cleanup(1);
-       }
-       fwrite((char *) &config, sizeof(struct config), 1, fp);
-       fclose(fp);
-}
-
+       case eLDAP_Host:
+               getconf_str(buf, "c_ldap_host");
+               if (IsEmptyStr(buf)) {
+                       strcpy(buf, "localhost");
+               }
+               set_str_val(curr, buf, default_value);
+               setconf_str("c_ldap_host", buf);
+               break;
 
+       case eLDAP_Port:
+               lportnum = getconf_int("c_ldap_port");
+               if (lportnum == 0) {
+                       lportnum = 389;
+               }
+               set_int_val(curr, &lportnum, default_value);
+               setconf_int("c_ldap_port", lportnum);
+               break;
 
+       case eLDAP_Base_DN:
+               getconf_str(buf, "c_ldap_base_dn");
+               set_str_val(curr, buf, default_value);
+               setconf_str("c_ldap_base_dn", buf);
+               break;
 
-/*
- * Figure out what type of user interface we're going to use
- */
-int discover_ui(void)
-{
+       case eLDAP_Bind_DN:
+               getconf_str(buf, "c_ldap_bind_dn");
+               set_str_val(curr, buf, default_value);
+               setconf_str("c_ldap_bind_dn", buf);
+               break;
 
-       /* Use "dialog" if we have it */
-       if (getenv("CTDL_DIALOG") != NULL) {
-               return UI_DIALOG;
+       case eLDAP_Bind_PW:
+               getconf_str(buf, "c_ldap_bind_pw");
+               set_str_val(curr, buf, default_value);
+               setconf_str("c_ldap_bind_pw", buf);
+               break;
        }
-               
-       return UI_TEXT;
 }
 
 
-
-
-
 /*
- * Strip "db" entries out of /etc/nsswitch.conf
+ * Messages that are no longer in use.
+ * We keep them here so we don't lose the translations if we need them later.
  */
-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);
-}
-
-
-
-
-
-
+#if 0
+important_message(_("Setup finished"),
+_("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"));
+important_message(_("Setup failed"),
+_("Setup is finished, but the Citadel server failed to start.\n"
+"Go back and check your configuration.\n");
+important_message(_("Setup finished"),
+_("Setup is finished.  You may now start the server."));
+#endif
 
 
 int main(int argc, char *argv[])
 {
-       int a;
-       int curr; 
+       int a, i;
+       int curr;
+       char buf[1024]; 
        char aaa[128];
-       FILE *fp;
-       int old_setup_level = 0;
-       int info_only = 0;
-       struct utsname my_utsname;
+       char ctdldir[PATH_MAX]=CTDLDIR;
        struct passwd *pw;
-       struct hostent *he;
        gid_t gid;
-       int relh=0;
-       int home=0;
-       char relhome[PATH_MAX]="";
-       char ctdldir[PATH_MAX]=CTDLDIR;
+       char *activity = NULL;
        
+       /* Keep a mild groove on */
+       program_title = _("Citadel setup program");
+
        /* set an invalid setup type */
        setup_type = (-1);
 
-       /* Check to see if we're running the web installer */
-       if (getenv("CITADEL_INSTALLER") != NULL) {
-               using_web_installer = 1;
-       }
-
        /* parse command line args */
        for (a = 0; a < argc; ++a) {
                if (!strncmp(argv[a], "-u", 2)) {
@@ -965,356 +712,196 @@ int main(int argc, char *argv[])
                        strcpy(aaa, &aaa[2]);
                        setup_type = atoi(aaa);
                }
-               if (!strcmp(argv[a], "-i")) {
-                       info_only = 1;
-               }
-               if (!strcmp(argv[a], "-q")) {
-                       setup_type = UI_SILENT;
+               else if (!strncmp(argv[a], "-h", 2)) {
+                       safestrncpy(ctdldir, &argv[a][2], sizeof ctdldir);
                }
        }
 
-
-       /* If a setup type was not specified, try to determine automatically
-        * the best one to use out of all available types.
-        */
-       if (setup_type < 0) {
-               setup_type = discover_ui();
-       }
-       if (info_only == 1) {
-               important_message("Citadel Setup", CITADEL);
-               cleanup(0);
+       if (chdir(ctdldir) != 0) {
+               fprintf(stderr, "sendcommand: %s: %s\n", ctdldir, strerror(errno));
+               exit(errno);
        }
 
-       /* Get started in a valid setup directory. */
-       strcpy(setup_directory, ctdl_run_dir);
-       if ( (using_web_installer) && (getenv("CITADEL") != NULL) ) {
-               strcpy(setup_directory, getenv("CITADEL"));
-       }
-       else {
-               set_str_val(0, setup_directory);
-       }
+       SetTitles();
 
-       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);
+       /*
+        * Connect to the running Citadel server.
+        */
+       char *connectingmsg = _("Connecting to Citadel server");
+       for (i=0; ((i<30) && (serv_sock < 0)) ; ++i) {          /* wait for server to start up */
+               progress(connectingmsg, i, 30);
+               serv_sock = uds_connectsock(file_citadel_admin_socket);
+               sleep(1);
+       }
+       progress(connectingmsg, 30, 30);
+
+       if (serv_sock < 0) { 
+               display_error(
+                       "%s: %s %s\n", 
+                       _("Setup could not connect to a running Citadel server."),
+                       strerror(errno), file_citadel_admin_socket
+               );
+               exit(1);
        }
 
-       calc_dirs_n_files(relh, home, relhome, ctdldir);
-       
-       enable_home=(relh|home);
+       /*
+        * read the server greeting
+        */
+       serv_gets(buf);
+       if (buf[0] != '2') {
+               display_error("%s\n", buf);
+               exit(2);
+       }
 
-       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);
+       /*
+        * Are we connected to the correct Citadel server?
+        */
+       serv_puts("INFO");
+       serv_gets(buf);
+       if (buf[0] != '1') {
+               display_error("%s\n", buf);
+               exit(3);
+       }
+       a = 0;
+       while (serv_gets(buf), strcmp(buf, "000")) {
+               if (a == 5) {
+                       if (atoi(buf) != REV_LEVEL) {
+                               display_error("%s\n",
+                               _("Your setup program and Citadel server are from different versions.")
+                               );
+                               exit(4);
+                       }
                }
+               ++a;
        }
 
-       /* Determine our host name, in case we need to use it as a default */
-       uname(&my_utsname);
+       printf("\n\n\n         *** %s ***\n\n", program_title);
 
-       /* Try to stop Citadel if we can */
-       if (!access("/etc/init.d/citadel", X_OK)) {
-               system("/etc/init.d/citadel stop");
-       }
+       /* Go through a series of dialogs prompting for config info */
+       for (curr = 1; curr < eMaxQuestions; ++curr) {
+               edit_value(curr);
 
-       /* Make sure Citadel is not running. */
-       if (test_server() == 0) {
-               important_message("Citadel Setup",
-                       "The Citadel service is still running.\n"
-                       "Please stop the service manually and run "
-                       "setup again.");
-               cleanup(1);
+               if (    (curr == eAuthType)
+                       && (getconf_int("c_auth_mode") != AUTHMODE_LDAP)
+                       && (getconf_int("c_auth_mode") != AUTHMODE_LDAP_AD)
+               ) {
+                       curr += 5;      /* skip LDAP questions if we're not authenticating against LDAP */
+               }
+
+               if (curr == eSysAdminName) {
+                       if (getconf_int("c_auth_mode") == AUTHMODE_NATIVE) {
+                                               /* for native auth mode, fetch the admin's existing pw */
+                               snprintf(buf, sizeof buf, "AGUP %s", admin_name);
+                               serv_puts(buf);
+                               serv_gets(buf);
+                               if (buf[0] == '2') {
+                                       extract_token(admin_pass, &buf[4], 1, '|', sizeof admin_pass);
+                               }
+                       }
+                       else {
+                               ++curr;         /* skip the password question for non-native auth modes */
+                       }
+               }
        }
 
-       /* Now begin. */
-       switch (setup_type) {
-
-       case UI_TEXT:
-               printf("\n\n\n"
-                       "              *** Citadel setup program ***\n\n");
-               break;
+       if ((pw = getpwuid( getconf_int("c_ctdluid") )) == NULL) {
+               gid = getgid();
+       } else {
+               gid = pw->pw_gid;
+       }
 
+       if (create_run_directories(getconf_int("c_ctdluid"), gid) != 0) {
+               display_error("%s\n", _("failed to create directories"));
        }
+               
+       activity = _("Reconfiguring Citadel server");
+       progress(activity, 0, 5);
+       sleep(1);                                       /* Let the message appear briefly */
 
        /*
-        * What we're going to try to do here is append a whole bunch of
-        * nulls to the citadel.config file, so we can keep the old config
-        * values if they exist, but if the file is missing or from an
-        * earlier version with a shorter config structure, when setup tries
-        * to read the old config parameters, they'll all come up zero.
-        * The length of the config file will be set to what it's supposed
-        * to be when we rewrite it, because we replace the old file with a
-        * completely new copy.
+        * Create the administrator account.  It's ok if the command fails if this user already exists.
         */
-       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);
-       }
-       fp = fdopen(a, "ab");
-       if (fp == NULL) {
-               display_error("setup: cannot append citadel.config");
-               cleanup(errno);
+       if (getconf_int("c_auth_mode") == AUTHMODE_NATIVE) {
+               progress(activity, 1, 5);
+               snprintf(buf, sizeof buf, "CREU %s|%s", admin_name, admin_pass);
+               serv_puts(buf);
+               progress(activity, 2, 5);
+               serv_gets(buf);
        }
-       for (a = 0; a < sizeof(struct config); ++a)
-               putc(0, fp);
-       fclose(fp);
-
-       /* now we re-open it, and read the old or blank configuration */
-       fp = fopen(file_citadel_config, "rb");
-       if (fp == NULL) {
-               display_error("setup: cannot open citadel.config");
-               cleanup(errno);
-       }
-       fread((char *) &config, sizeof(struct config), 1, fp);
-       fclose(fp);
+       progress(activity, 3, 5);
 
-       /* set some sample/default values in place of blanks... */
-       if (IsEmptyStr(config.c_nodename))
-               safestrncpy(config.c_nodename, my_utsname.nodename,
-                           sizeof config.c_nodename);
-       strtok(config.c_nodename, ".");
-       if (IsEmptyStr(config.c_fqdn) ) {
-               if ((he = gethostbyname(my_utsname.nodename)) != NULL)
-                       safestrncpy(config.c_fqdn, he->h_name,
-                                   sizeof config.c_fqdn);
-               else
-                       safestrncpy(config.c_fqdn, my_utsname.nodename,
-                                   sizeof config.c_fqdn);
-       }
-       if (IsEmptyStr(config.c_humannode))
-               strcpy(config.c_humannode, "My System");
-       if (IsEmptyStr(config.c_phonenum))
-               strcpy(config.c_phonenum, "US 800 555 1212");
-       if (config.c_initax == 0) {
-               config.c_initax = 4;
-       }
-       if (IsEmptyStr(config.c_moreprompt))
-               strcpy(config.c_moreprompt, "<more>");
-       if (IsEmptyStr(config.c_twitroom))
-               strcpy(config.c_twitroom, "Trashcan");
-       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;
-       }
-       if (config.c_sleeping == 0) {
-               config.c_sleeping = 900;
-       }
-       if (config.c_ctdluid == 0) {
-               pw = getpwnam("citadel");
-               if (pw != NULL)
-                       config.c_ctdluid = pw->pw_uid;
-       }
-       if (config.c_ctdluid == 0) {
-               pw = getpwnam("bbs");
-               if (pw != NULL)
-                       config.c_ctdluid = pw->pw_uid;
-       }
-       if (config.c_ctdluid == 0) {
-               pw = getpwnam("guest");
-               if (pw != NULL)
-                       config.c_ctdluid = pw->pw_uid;
-       }
-       if (config.c_createax == 0) {
-               config.c_createax = 3;
-       }
        /*
-        * Negative values for maxsessions are not allowed.
+        * Assign the desired password and access level to the administrator account.
         */
-       if (config.c_maxsessions < 0) {
-               config.c_maxsessions = 0;
-       }
-       /* 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) {
-               config.c_ep.expire_mode = EXPIRE_MANUAL;
-               config.c_ep.expire_value = 0;
+       if (getconf_int("c_auth_mode") == AUTHMODE_NATIVE) {
+               snprintf(buf, sizeof buf, "AGUP %s", admin_name);
+               serv_puts(buf);
+               progress(activity, 4, 5);
+               serv_gets(buf);
+               if (buf[0] == '2') {
+                       int admin_flags = extract_int(&buf[4], 2);
+                       int admin_times_called = extract_int(&buf[4], 3);
+                       int admin_msgs_posted = extract_int(&buf[4], 4);
+                       snprintf(buf, sizeof buf, "ASUP %s|%s|%d|%d|%d|6",
+                               admin_name, admin_pass, admin_flags, admin_times_called, admin_msgs_posted
+                       );
+                       serv_puts(buf);
+                       serv_gets(buf);
+               }
        }
+       progress(activity, 5, 5);
+
+       check_xinetd_entry();   /* Check /etc/xinetd.d/telnet */
 
        /*
-        * Default port numbers for various services
+        * Restart citserver
         */
-       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;
+       activity = _("Restarting Citadel server to apply changes");
+       progress(activity, 0, 51);
 
-       /* Go through a series of dialogs prompting for config info */
-       for (curr = 1; curr <= MAXSETUP; ++curr) {
-               edit_value(curr);
-       }
+       serv_puts("TIME");
+       serv_gets(buf);
+       long original_start_time = extract_long(&buf[4], 3);
 
-/***** begin version update section ***** */
-       /* take care of any updating that is necessary */
+       progress(activity, 1, 51);
+       serv_puts("DOWN 1");
+       progress(activity, 2, 51);
+       serv_gets(buf);
+       if (buf[0] != '2') {
+               display_error("%s\n", buf);
+               exit(6);
+       }
 
-       old_setup_level = config.c_setup_level;
+       close(serv_sock);
+       serv_sock = (-1);
 
-       if (old_setup_level == 0) {
-               goto NEW_INST;
+       for (i=3; i<=6; ++i) {                                  /* wait for server to shut down */
+               progress(activity, i, 51);
+               sleep(1);
        }
 
-       if (old_setup_level < 555) {
-               important_message("Citadel Setup",
-                                 "This Citadel installation is too old "
-                                 "to be upgraded.");
-               cleanup(1);
+       for (i=7; ((i<=48) && (serv_sock < 0)) ; ++i) {         /* wait for server to start up */
+               progress(activity, i, 51);
+               serv_sock = uds_connectsock(file_citadel_admin_socket);
+               sleep(1);
        }
-       write_config_to_disk();
-
-       old_setup_level = config.c_setup_level;
-
-       /* end of version update section */
-
-NEW_INST:
-       config.c_setup_level = REV_LEVEL;
-
-/******************************************/
-
-       write_config_to_disk();
-
-       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");
-       unlink("citadel.log");
-       unlink("weekly");
+       progress(activity, 49, 51);
+       serv_gets(buf);
 
-       check_services_entry(); /* Check /etc/services */
-#ifndef __CYGWIN__
-       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. */
-       disable_other_mta("courier-authdaemon");
-       disable_other_mta("courier-imap");
-       disable_other_mta("courier-imap-ssl");
-       disable_other_mta("courier-pop");
-       disable_other_mta("courier-pop3");
-       disable_other_mta("courier-pop3d");
-       disable_other_mta("cyrmaster");
-       disable_other_mta("cyrus");
-       disable_other_mta("dovecot");
-       disable_other_mta("exim");
-       disable_other_mta("exim4");
-       disable_other_mta("hula");
-       disable_other_mta("imapd");
-       disable_other_mta("mta");
-       disable_other_mta("pop3d");
-       disable_other_mta("popd");
-       disable_other_mta("postfix");
-       disable_other_mta("qmail");
-       disable_other_mta("saslauthd");
-       disable_other_mta("sendmail");
-       disable_other_mta("vmailmgrd");
-       disable_other_mta("zimbra");
-#endif
-
-       /* 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;
-
-       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)) {
-
-               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",
-                               "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 {
-                       important_message("Setup failed",
-                               "Setup is finished, but the Citadel server failed to start.\n"
-                               "Go back and check your configuration.\n"
-                       );
-               }
+       progress(activity, 50, 51);
+       serv_puts("TIME");
+       serv_gets(buf);
+       long new_start_time = extract_long(&buf[4], 3);
 
-       }
+       close(serv_sock);
+       progress(activity, 51, 51);
 
-       else {
-               important_message("Setup finished",
-                       "Setup is finished.  You may now start the server.");
+       if ((original_start_time == new_start_time) || (new_start_time <= 0)) {
+               display_error("%s\n", _("Setup failed to restart Citadel server.  Please restart it manually."));
+               exit(7);
        }
 
-       cleanup(0);
+       exit(0);
        return 0;
 }
-
-