Upsie, usleep is 10^6 times smaller than sleep
[citadel.git] / citadel / citserver.c
index 94132babc1c2f85abb322641a384df3364ef94e6..0c8955a8a2b3fb10386b589818e6a3618aff6088 100644 (file)
@@ -1,23 +1,15 @@
 /* 
- * $Id$
- *
  * Main source module for the Citadel server
  *
- * Copyright (c) 1987-2009 by the citadel.org team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 3 of the License, or
- *  (at your option) any later version.
+ * Copyright (c) 1987-2011 by the citadel.org team
  *
- *  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.
+ * 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.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 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.
  */
 
 #include "sysdep.h"
@@ -29,7 +21,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
-
 #if TIME_WITH_SYS_TIME
 # include <sys/time.h>
 # include <time.h>
@@ -70,9 +61,9 @@
 #include "locate_host.h"
 #include "room_ops.h"
 #include "file_ops.h"
-#include "policy.h"
 #include "control.h"
 #include "euidindex.h"
+#include "context.h"
 #include "svn_revision.h"
 
 #ifndef HAVE_SNPRINTF
 
 #include "ctdl_module.h"
 
-
-struct CitContext *ContextList = NULL;
-struct CitContext* next_session = NULL;
 char *unique_session_numbers;
 int ScheduledShutdown = 0;
 time_t server_startup_time;
 int panic_fd;
+int openid_level_supported = 0;
 
-/**
- * \brief print the actual stack frame.
+/*
+ * print the actual stack frame.
  */
 void cit_backtrace(void)
 {
@@ -104,16 +93,42 @@ void cit_backtrace(void)
        strings = backtrace_symbols(stack_frames, size);
        for (i = 0; i < size; i++) {
                if (strings != NULL)
-                       CtdlLogPrintf(1, "%s\n", strings[i]);
+                       syslog(LOG_ALERT, "%s\n", strings[i]);
                else
-                       CtdlLogPrintf(1, "%p\n", stack_frames[i]);
+                       syslog(LOG_ALERT, "%p\n", stack_frames[i]);
        }
        free(strings);
 #endif
 }
 
-/**
- * \brief print the actual stack frame.
+void cit_oneline_backtrace(void)
+{
+#ifdef HAVE_BACKTRACE
+       void *stack_frames[50];
+       size_t size, i;
+       char **strings;
+       StrBuf *Buf;
+
+       size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
+       strings = backtrace_symbols(stack_frames, size);
+       if (size > 0)
+       {
+               Buf = NewStrBuf();
+               for (i = 1; i < size; i++) {
+                       if (strings != NULL)
+                               StrBufAppendPrintf(Buf, "%s : ", strings[i]);
+                       else
+                               StrBufAppendPrintf(Buf, "%p : ", stack_frames[i]);
+               }
+               free(strings);
+               syslog(LOG_ALERT, "%s\n", ChrPtr(Buf));
+               FreeStrBuf(&Buf);
+       }
+#endif
+}
+
+/*
+ * print the actual stack frame.
  */
 void cit_panic_backtrace(int SigNum)
 {
@@ -127,9 +142,9 @@ void cit_panic_backtrace(int SigNum)
        strings = backtrace_symbols(stack_frames, size);
        for (i = 0; i < size; i++) {
                if (strings != NULL)
-                       CtdlLogPrintf(1, "%s\n", strings[i]);
+                       syslog(LOG_ALERT, "%s\n", strings[i]);
                else
-                       CtdlLogPrintf(1, "%p\n", stack_frames[i]);
+                       syslog(LOG_ALERT, "%p\n", stack_frames[i]);
        }
        free(strings);
 #endif
@@ -146,22 +161,18 @@ void master_startup(void) {
        struct ctdlroom qrbuf;
        int rv;
        
-       CtdlLogPrintf(CTDL_DEBUG, "master_startup() started\n");
+       syslog(LOG_DEBUG, "master_startup() started\n");
        time(&server_startup_time);
+       get_config();
 
-       CtdlLogPrintf(CTDL_INFO, "Opening databases\n");
+       syslog(LOG_INFO, "Opening databases\n");
        open_databases();
-
-       ctdl_thread_internal_init_tsd();
-       
-       CtdlThreadAllocTSD();
-       
        check_ref_counts();
 
-       CtdlLogPrintf(CTDL_INFO, "Creating base rooms (if necessary)\n");
+       syslog(LOG_INFO, "Creating base rooms (if necessary)\n");
        CtdlCreateRoom(config.c_baseroom,       0, "", 0, 1, 0, VIEW_BBS);
        CtdlCreateRoom(AIDEROOM,                3, "", 0, 1, 0, VIEW_BBS);
-       CtdlCreateRoom(SYSCONFIGROOM,   3, "", 0, 1, 0, VIEW_BBS);
+       CtdlCreateRoom(SYSCONFIGROOM,           3, "", 0, 1, 0, VIEW_BBS);
        CtdlCreateRoom(config.c_twitroom,       0, "", 0, 1, 0, VIEW_BBS);
 
        /* The "Local System Configuration" room doesn't need to be visible */
@@ -176,10 +187,13 @@ void master_startup(void) {
                 CtdlPutRoomLock(&qrbuf);
         }
 
-       CtdlLogPrintf(CTDL_INFO, "Seeding the pseudo-random number generator...\n");
+       syslog(LOG_INFO, "Seeding the pseudo-random number generator...\n");
        urandom = fopen("/dev/urandom", "r");
        if (urandom != NULL) {
                rv = fread(&seed, sizeof seed, 1, urandom);
+               if (rv == -1)
+                       syslog(LOG_EMERG, "failed to read random seed: %s\n", 
+                              strerror(errno));
                fclose(urandom);
        }
        else {
@@ -189,12 +203,9 @@ void master_startup(void) {
        srand(seed);
        srandom(seed);
 
-       CtdlLogPrintf(CTDL_INFO, "Initializing ipgm secret\n");
-       get_config();
-       config.c_ipgm_secret = rand();
        put_config();
 
-       CtdlLogPrintf(CTDL_DEBUG, "master_startup() finished\n");
+       syslog(LOG_DEBUG, "master_startup() finished\n");
 }
 
 
@@ -205,7 +216,7 @@ void master_cleanup(int exitcode) {
        struct CleanupFunctionHook *fcn;
        static int already_cleaning_up = 0;
 
-       if (already_cleaning_up) while(1) sleep(1);
+       if (already_cleaning_up) while(1) usleep(1000000);
        already_cleaning_up = 1;
 
        /* Run any cleanup routines registered by loadable modules */
@@ -220,16 +231,12 @@ void master_cleanup(int exitcode) {
        sysdep_master_cleanup();
        
        /* Close databases */
-       CtdlLogPrintf(CTDL_INFO, "Closing databases\n");
+       syslog(LOG_INFO, "Closing databases\n");
        close_databases();
 
-#ifdef DEBUG_MEMORY_LEAKS
-       dump_heap();
-#endif
-
        /* If the operator requested a halt but not an exit, halt here. */
        if (shutdown_and_halt) {
-               CtdlLogPrintf(CTDL_NOTICE, "citserver: Halting server without exiting.\n");
+               syslog(LOG_NOTICE, "citserver: Halting server without exiting.\n");
                fflush(stdout); fflush(stderr);
                while(1) {
                        sleep(32767);
@@ -239,58 +246,18 @@ void master_cleanup(int exitcode) {
        release_control();
 
        /* Now go away. */
-       CtdlLogPrintf(CTDL_NOTICE, "citserver: Exiting with status %d\n", exitcode);
+       syslog(LOG_NOTICE, "citserver: Exiting with status %d\n", exitcode);
        fflush(stdout); fflush(stderr);
        
        if (restart_server != 0)
                exit(1);
-       if ((running_as_daemon != 0) && (exitcode == 0))
+       if ((running_as_daemon != 0) && ((exitcode == 0) ))
                exitcode = CTDLEXIT_SHUTDOWN;
        exit(exitcode);
 }
 
 
 
-/*
- * Terminate a session.
- */
-void RemoveContext (struct CitContext *con)
-{
-       if (con==NULL) {
-               CtdlLogPrintf(CTDL_ERR,
-                       "WARNING: RemoveContext() called with NULL!\n");
-               return;
-       }
-       CtdlLogPrintf(CTDL_DEBUG, "RemoveContext() session %d\n", con->cs_pid);
-
-       /* Run any cleanup routines registered by loadable modules.
-        * Note: We have to "become_session()" because the cleanup functions
-        *       might make references to "CC" assuming it's the right one.
-        */
-       become_session(con);
-       logout();
-       PerformSessionHooks(EVT_STOP);
-       become_session(NULL);
-
-       CtdlLogPrintf(CTDL_NOTICE, "[%3d] Session ended.\n", con->cs_pid);
-
-       /* If the client is still connected, blow 'em away. */
-       CtdlLogPrintf(CTDL_DEBUG, "Closing socket %d\n", con->client_socket);
-       close(con->client_socket);
-
-       /* If using AUTHMODE_LDAP, free the DN */
-       if (con->ldap_dn) {
-               free(con->ldap_dn);
-               con->ldap_dn = NULL;
-       }
-
-       CtdlLogPrintf(CTDL_DEBUG, "Done with RemoveContext()\n");
-}
-
-
-
-
-
 /*
  * cmd_info()  -  tell the client about this server
  */
@@ -308,7 +275,7 @@ void cmd_info(char *cmdbuf) {
        cprintf("%s\n", config.c_moreprompt);
        cprintf("1\n"); /* 1 = yes, this system supports floors */
        cprintf("1\n"); /* 1 = we support the extended paging options */
-       cprintf("%s\n", CC->cs_nonce);
+       cprintf("\n");  /* nonce no longer supported */
        cprintf("1\n"); /* 1 = yes, this system supports the QNOP command */
 
 #ifdef HAVE_LDAP
@@ -326,21 +293,23 @@ void cmd_info(char *cmdbuf) {
 
        cprintf("%s\n", config.c_default_cal_zone);
 
-       /* Output load averages */
-       cprintf("%f\n", CtdlThreadLoadAvg);
-       cprintf("%f\n", CtdlThreadWorkerAvg);
-       cprintf("%d\n", CtdlThreadGetCount());
+       /* thread load averages -- temporarily disabled during refactoring of this code */
+       cprintf("0\n");         /* load average */
+       cprintf("0\n");         /* worker average */
+       cprintf("0\n");         /* thread count */
 
        cprintf("1\n");         /* yes, Sieve mail filtering is supported */
        cprintf("%d\n", config.c_enable_fulltext);
        cprintf("%s\n", svn_revision());
 
        if (config.c_auth_mode == AUTHMODE_NATIVE) {
-               cprintf("1\n"); /* OpenID is enabled when using native auth */
+               cprintf("%d\n", openid_level_supported); /* OpenID is enabled when using native auth */
        }
        else {
                cprintf("0\n"); /* OpenID is disabled when using non-native auth */
        }
+
+       cprintf("%d\n", config.c_guest_logins);
        
        cprintf("000\n");
 }
@@ -369,9 +338,9 @@ void cmd_time(char *argbuf)
    
    /* timezone and daylight global variables are not portable. */
 #ifdef HAVE_STRUCT_TM_TM_GMTOFF
-   cprintf("%d %ld|%ld|%d\n", CIT_OK, (long)tv, tmp.tm_gmtoff, tmp.tm_isdst);
+   cprintf("%d %ld|%ld|%d|%ld\n", CIT_OK, (long)tv, tmp.tm_gmtoff, tmp.tm_isdst, server_startup_time);
 #else
-   cprintf("%d %ld|%ld|%d\n", CIT_OK, (long)tv, timezone, tmp.tm_isdst);
+   cprintf("%d %ld|%ld|%d|%ld\n", CIT_OK, (long)tv, timezone, tmp.tm_isdst, server_startup_time);
 #endif
 }
 
@@ -398,10 +367,7 @@ int is_public_client(void)
 
 #define LOCALHOSTSTR "127.0.0.1"
 
-       snprintf(public_clients_file, 
-                        sizeof public_clients_file,
-                        "%s/public_clients",
-                        ctdl_etc_dir);
+       snprintf(public_clients_file, sizeof public_clients_file, "%s/public_clients", ctdl_etc_dir);
 
        /*
         * Check the time stamp on the public_clients file.  If it's been
@@ -411,14 +377,14 @@ int is_public_client(void)
         */
        if (stat(public_clients_file, &statbuf) != 0) {
                /* No public_clients file exists, so bail out */
-               CtdlLogPrintf(CTDL_WARNING, "Warning: '%s' does not exist\n", 
+               syslog(LOG_WARNING, "Warning: '%s' does not exist\n", 
                                public_clients_file);
                return(0);
        }
 
        if (statbuf.st_mtime > pc_timestamp) {
                begin_critical_section(S_PUBLIC_CLIENTS);
-               CtdlLogPrintf(CTDL_INFO, "Loading %s\n", public_clients_file);
+               syslog(LOG_INFO, "Loading %s\n", public_clients_file);
 
                public_clientspos = &public_clients[0];
                public_clientsend = public_clientspos + SIZ;
@@ -459,23 +425,23 @@ int is_public_client(void)
                                        }
                                }
                        }
-               fclose(fp);
+               if (fp != NULL) fclose(fp);
                pc_timestamp = time(NULL);
                end_critical_section(S_PUBLIC_CLIENTS);
        }
 
-       CtdlLogPrintf(CTDL_DEBUG, "Checking whether %s is a local or public client\n",
+       syslog(LOG_DEBUG, "Checking whether %s is a local or public client\n",
                CC->cs_addr);
        for (i=0; i<num_parms(public_clients); ++i) {
                extract_token(addrbuf, public_clients, i, '|', sizeof addrbuf);
                if (!strcasecmp(CC->cs_addr, addrbuf)) {
-                       CtdlLogPrintf(CTDL_DEBUG, "... yes it is.\n");
+                       syslog(LOG_DEBUG, "... yes its local.\n");
                        return(1);
                }
        }
 
        /* No hits.  This is not a public client. */
-       CtdlLogPrintf(CTDL_DEBUG, "... no it isn't.\n");
+       syslog(LOG_DEBUG, "... no it isn't.\n");
        return(0);
 }
 
@@ -490,8 +456,6 @@ void cmd_iden(char *argbuf)
        int rev_level;
        char desc[128];
        char from_host[128];
-       struct in_addr addr;
-       int do_lookup = 0;
 
        if (num_parms(argbuf)<4) {
                cprintf("%d usage error\n", ERROR + ILLEGAL_VALUE);
@@ -513,35 +477,25 @@ void cmd_iden(char *argbuf)
        safestrncpy(CC->cs_clientname, desc, sizeof CC->cs_clientname);
        CC->cs_clientname[31] = 0;
 
-       if (!IsEmptyStr(from_host)) {
-               if (CC->is_local_socket) do_lookup = 1;
-               else if (is_public_client()) do_lookup = 1;
+       /* For local sockets and public clients, trust the hostname supplied by the client */
+       if ( (CC->is_local_socket) || (is_public_client()) ) {
+               safestrncpy(CC->cs_host, from_host, sizeof CC->cs_host);
+               CC->cs_host[sizeof CC->cs_host - 1] = 0;
+               CC->cs_addr[0] = 0;
        }
 
-       if (do_lookup) {
-               CtdlLogPrintf(CTDL_DEBUG, "Looking up hostname '%s'\n", from_host);
-               if ((addr.s_addr = inet_addr(from_host)) != -1) {
-                       locate_host(CC->cs_host, sizeof CC->cs_host,
-                               CC->cs_addr, sizeof CC->cs_addr,
-                               &addr);
-               }
-               else {
-                       safestrncpy(CC->cs_host, from_host, sizeof CC->cs_host);
-                       CC->cs_host[sizeof CC->cs_host - 1] = 0;
-               }
-       }
-
-       CtdlLogPrintf(CTDL_NOTICE, "Client %d/%d/%01d.%02d (%s) from %s\n",
+       syslog(LOG_NOTICE, "Client %d/%d/%01d.%02d (%s) from %s\n",
                dev_code,
                cli_code,
                (rev_level / 100),
                (rev_level % 100),
                desc,
-               CC->cs_host);
+               CC->cs_host
+       );
        cprintf("%d Ok\n",CIT_OK);
 }
 
-
+typedef const char *ccharp;
 /*
  * display system messages or help
  */
@@ -583,15 +537,15 @@ void cmd_mesg(char *mname)
 
        /* Otherwise, look for the requested file by name. */
        else {
-               mesg_locate(targ, sizeof targ, buf2, 2, (const char **)dirs);
+               mesg_locate(targ, sizeof targ, buf2, 2, (const ccharp*)dirs);
                if (IsEmptyStr(targ)) {
                        snprintf(buf2, sizeof buf2, "%s.%d",
                                                        buf, CC->cs_clientdev);
                        mesg_locate(targ, sizeof targ, buf2, 2,
-                                                       (const char **)dirs);
+                                   (const ccharp*)dirs);
                        if (IsEmptyStr(targ)) {
                                mesg_locate(targ, sizeof targ, buf, 2,
-                                                       (const char **)dirs);
+                                           (const ccharp*)dirs);
                        }       
                }
        }
@@ -651,7 +605,7 @@ void cmd_emsg(char *mname)
        dirs[0] = strdup(ctdl_message_dir);
        dirs[1] = strdup(ctdl_hlp_dir);
 
-       mesg_locate(targ, sizeof targ, buf, 2, (const char**)dirs);
+       mesg_locate(targ, sizeof targ, buf, 2, (const ccharp*)dirs);
        free(dirs[0]);
        free(dirs[1]);
 
@@ -681,8 +635,8 @@ void cmd_emsg(char *mname)
  * user also knows the rooms.
  */
 void GenerateRoomDisplay(char *real_room,
-                       struct CitContext *viewed,
-                       struct CitContext *viewer) {
+                       CitContext *viewed,
+                       CitContext *viewer) {
 
        int ra;
 
@@ -693,7 +647,7 @@ void GenerateRoomDisplay(char *real_room,
        if (viewed->room.QRflags & QR_PRIVATE) {
                CtdlRoomAccess(&viewed->room, &viewer->user, &ra, NULL);
                if ( (ra & UA_KNOWN) == 0) {
-                       strcpy(real_room, "<private room>");
+                       strcpy(real_room, " ");
                }
        }
 
@@ -718,21 +672,26 @@ int CtdlAccessCheck(int required_level) {
                return(-1);
        }
 
+       if ((required_level >= ac_logged_in_or_guest) && (CC->logged_in == 0) && (!config.c_guest_logins)) {
+               cprintf("%d Not logged in.\n", ERROR + NOT_LOGGED_IN);
+               return(-1);
+       }
+
        if ((required_level >= ac_logged_in) && (CC->logged_in == 0)) {
                cprintf("%d Not logged in.\n", ERROR + NOT_LOGGED_IN);
                return(-1);
        }
 
-       if (CC->user.axlevel >= 6) return(0);
+       if (CC->user.axlevel >= AxAideU) return(0);
        if (required_level >= ac_aide) {
-               cprintf("%d This command requires Aide access.\n",
+               cprintf("%d This command requires Admin access.\n",
                        ERROR + HIGHER_ACCESS_REQUIRED);
                return(-1);
        }
 
        if (is_room_aide()) return(0);
        if (required_level >= ac_room_aide) {
-               cprintf("%d This command requires Aide or Room Aide access.\n",
+               cprintf("%d This command requires Admin or Room Admin access.\n",
                        ERROR + HIGHER_ACCESS_REQUIRED);
                return(-1);
        }
@@ -749,35 +708,19 @@ int CtdlAccessCheck(int required_level) {
 void cmd_term(char *cmdbuf)
 {
        int session_num;
-       struct CitContext *ccptr;
-       int found_it = 0;
-       int allowed = 0;
+       int terminated = 0;
 
        session_num = extract_int(cmdbuf, 0);
-       if (session_num == CC->cs_pid) {
+
+       terminated = CtdlTerminateOtherSession(session_num);
+
+       if (terminated < 0) {
                cprintf("%d You can't kill your own session.\n", ERROR + ILLEGAL_VALUE);
                return;
        }
 
-       CtdlLogPrintf(CTDL_DEBUG, "Locating session to kill\n");
-       begin_critical_section(S_SESSION_TABLE);
-       for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) {
-               if (session_num == ccptr->cs_pid) {
-                       found_it = 1;
-                       if ((ccptr->user.usernum == CC->user.usernum)
-                          || (CC->user.axlevel >= 6)) {
-                               allowed = 1;
-                               ccptr->kill_me = 1;
-                       }
-                       else {
-                               allowed = 0;
-                       }
-               }
-       }
-       end_critical_section(S_SESSION_TABLE);
-
-       if (found_it) {
-               if (allowed) {
+       if (terminated & TERM_FOUND) {
+               if (terminated == TERM_KILLED) {
                        cprintf("%d Session terminated.\n", CIT_OK);
                }
                else {
@@ -791,9 +734,6 @@ void cmd_term(char *cmdbuf)
 }
 
 
-
-
-
 /* 
  * get the paginator prompt
  */
@@ -801,6 +741,7 @@ void cmd_more(char *argbuf) {
        cprintf("%d %s\n", CIT_OK, config.c_moreprompt);
 }
 
+
 /*
  * echo 
  */
@@ -811,39 +752,6 @@ void cmd_echo(char *etext)
 
 
 
-/* 
- * identify as internal program
- */
-void cmd_ipgm(char *argbuf)
-{
-       int secret;
-
-       secret = extract_int(argbuf, 0);
-
-       /* For security reasons, we do NOT allow this command to run
-        * over the network.  Local sockets only.
-        */
-       if (!CC->is_local_socket) {
-               sleep(5);
-               cprintf("%d Authentication failed.\n",
-                       ERROR + PASSWORD_REQUIRED);
-       }
-       else if (secret == config.c_ipgm_secret) {
-               CC->internal_pgm = 1;
-               strcpy(CC->curr_user, "<internal program>");
-               CC->cs_flags = CC->cs_flags|CS_STEALTH;
-               cprintf("%d Authenticated as an internal program.\n", CIT_OK);
-       }
-       else {
-               sleep(5);
-               cprintf("%d Authentication failed.\n",
-                       ERROR + PASSWORD_REQUIRED);
-               CtdlLogPrintf(CTDL_ERR, "Warning: ipgm authentication failed.\n");
-               CC->kill_me = 1;
-       }
-}
-
-
 /*
  * Shut down the server
  */
@@ -863,7 +771,7 @@ void cmd_down(char *argbuf) {
                }
                if ((restart_server > 0) && !running_as_daemon)
                {
-                       CtdlLogPrintf(CTDL_ERR, "The user requested restart, but not running as daemon! Geronimooooooo!\n");
+                       syslog(LOG_ERR, "The user requested restart, but not running as daemon! Geronimooooooo!\n");
                        Reply = "%d Warning: citserver is not running in daemon mode and is therefore unlikely to restart automatically.\n";
                        state = ERROR;
                }
@@ -873,9 +781,11 @@ void cmd_down(char *argbuf) {
        {
                cprintf(Reply, CIT_OK + SERVER_SHUTTING_DOWN); 
        }
-       CtdlThreadStopAll();
+       CC->kill_me = KILLME_SERVER_SHUTTING_DOWN;
+       server_shutting_down = 1;
 }
 
+
 /*
  * Halt the server without exiting the server process.
  */
@@ -884,10 +794,11 @@ void cmd_halt(char *argbuf) {
        if (CtdlAccessCheck(ac_aide)) return;
 
        cprintf("%d Halting server.  Goodbye.\n", CIT_OK);
-       CtdlThreadStopAll();
+       server_shutting_down = 1;
        shutdown_and_halt = 1;
 }
 
+
 /*
  * Schedule or cancel a server shutdown
  */
@@ -905,7 +816,7 @@ void cmd_scdn(char *argbuf)
                restart_server = 1;
                if (!running_as_daemon)
                {
-                       CtdlLogPrintf(CTDL_ERR, "The user requested restart, but not running as deamon! Geronimooooooo!\n");
+                       syslog(LOG_ERR, "The user requested restart, but not running as deamon! Geronimooooooo!\n");
                        Reply = "%d %d Warning, not running in deamon mode. maybe we will come up again, but don't lean on it.\n";
                        state = ERROR;
                }
@@ -935,33 +846,12 @@ void cmd_asyn(char *argbuf)
 }
 
 
-/*
- * Generate a "nonce" for APOP-style authentication.
- *
- * RFC 1725 et al specify a PID to be placed in front of the nonce.
- * Quoth BTX: That would be stupid.
- */
-void generate_nonce(struct CitContext *con) {
-       struct timeval tv;
-
-       memset(con->cs_nonce, NONCE_SIZE, 0);
-       gettimeofday(&tv, NULL);
-       memset(con->cs_nonce, NONCE_SIZE, 0);
-       snprintf(con->cs_nonce, NONCE_SIZE, "<%d%ld@%s>",
-               rand(), (long)tv.tv_usec, config.c_fqdn);
-}
-
-
-
 
 /*
  * Back-end function for starting a session
  */
-void begin_session(struct CitContext *con)
+void begin_session(CitContext *con)
 {
-       socklen_t len;
-       struct sockaddr_in sin;
-
        /* 
         * Initialize some variables specific to our context.
         */
@@ -969,6 +859,8 @@ void begin_session(struct CitContext *con)
        con->internal_pgm = 0;
        con->download_fp = NULL;
        con->upload_fp = NULL;
+       con->cached_msglist = NULL;
+       con->cached_num_msgs = 0;
        con->FirstExpressMessage = NULL;
        time(&con->lastcmd);
        time(&con->lastidle);
@@ -979,31 +871,29 @@ void begin_session(struct CitContext *con)
        *con->fake_username = '\0';
        *con->fake_hostname = '\0';
        *con->fake_roomname = '\0';
-       generate_nonce(con);
+       *con->cs_clientinfo = '\0';
        safestrncpy(con->cs_host, config.c_fqdn, sizeof con->cs_host);
        safestrncpy(con->cs_addr, "", sizeof con->cs_addr);
        con->cs_UDSclientUID = -1;
        con->cs_host[sizeof con->cs_host - 1] = 0;
-       len = sizeof sin;
        if (!CC->is_local_socket) {
-               if (!getpeername(con->client_socket, (struct sockaddr *) &sin, &len)) {
-                       locate_host(con->cs_host, sizeof con->cs_host,
-                               con->cs_addr, sizeof con->cs_addr,
-                               &sin.sin_addr
-                       );
-               }
+               locate_host(con->cs_host, sizeof con->cs_host,
+                       con->cs_addr, sizeof con->cs_addr,
+                       con->client_socket
+               );
        }
        else {
-               strcpy(con->cs_host, "");
+               con->cs_host[0] = 0;
+               con->cs_addr[0] = 0;
 #ifdef HAVE_STRUCT_UCRED
                {
                        /* as http://www.wsinnovations.com/softeng/articles/uds.html told us... */
                        struct ucred credentials;
-                       int ucred_length = sizeof(struct ucred);
+                       socklen_t ucred_length = sizeof(struct ucred);
                        
                        /*fill in the user data structure */
                        if(getsockopt(con->client_socket, SOL_SOCKET, SO_PEERCRED, &credentials, &ucred_length)) {
-                               CtdlLogPrintf(CTDL_NOTICE, "could obtain credentials from unix domain socket");
+                               syslog(LOG_NOTICE, "could obtain credentials from unix domain socket");
                                
                        }
                        else {          
@@ -1020,6 +910,11 @@ void begin_session(struct CitContext *con)
                                   database, after a reverse lookup on the UID to get the account name.
                                   We can take this opportunity to check to see if this is a legit account.
                                */
+                               snprintf(con->cs_clientinfo, sizeof(con->cs_clientinfo),
+                                        "PID: "F_PID_T"; UID: "F_UID_T"; GID: "F_XPID_T" ", 
+                                        credentials.pid,
+                                        credentials.uid,
+                                        credentials.gid);
                        }
                }
 #endif
@@ -1034,10 +929,10 @@ void begin_session(struct CitContext *con)
        }
 
        if (!CC->is_local_socket) {
-               CtdlLogPrintf(CTDL_NOTICE, "Session started from %s [%s].\n", con->cs_host, con->cs_addr);
+               syslog(LOG_NOTICE, "Session (%s) started from %s (%s).\n", con->ServiceName, con->cs_host, con->cs_addr);
        }
        else {
-               CtdlLogPrintf(CTDL_NOTICE, "Session started via local socket.\n");
+               syslog(LOG_NOTICE, "Session (%s) started via local socket UID:%d.\n", con->ServiceName, con->cs_UDSclientUID);
        }
 
        /* Run any session startup routines registered by loadable modules */
@@ -1051,7 +946,7 @@ void citproto_begin_session() {
                        ERROR + MAX_SESSIONS_EXCEEDED,
                        config.c_nodename, config.c_maxsessions
                );
-               CC->kill_me = 1;
+               CC->kill_me = KILLME_MAX_SESSIONS_EXCEEDED;
        }
        else {
                cprintf("%d %s Citadel server ready.\n", CIT_OK, config.c_nodename);
@@ -1060,55 +955,63 @@ void citproto_begin_session() {
 }
 
 
+void citproto_begin_admin_session() {
+       CC->internal_pgm = 1;
+       cprintf("%d %s Citadel server ADMIN CONNECTION ready.\n", CIT_OK, config.c_nodename);
+}
+
 
 void cmd_noop(char *argbuf)
 {
        cprintf("%d%cok\n", CIT_OK, CtdlCheckExpress() );
 }
 
+
 void cmd_qnop(char *argbuf)
 {
        /* do nothing, this command returns no response */
 }
 
+
 void cmd_quit(char *argbuf)
 {
        cprintf("%d Goodbye.\n", CIT_OK);
-       CC->kill_me = 1;
+       CC->kill_me = KILLME_CLIENT_LOGGED_OUT;
 }
 
+
 void cmd_lout(char *argbuf)
 {
        if (CC->logged_in) 
-               logout();
+               CtdlUserLogout();
        cprintf("%d logged out.\n", CIT_OK);
 }
 
+
 /*
  * This loop recognizes all server commands.
  */
 void do_command_loop(void) {
        char cmdbuf[SIZ];
-       const char *old_name = NULL;
-       
-       old_name = CtdlThreadName("do_command_loop");
        
        time(&CC->lastcmd);
        memset(cmdbuf, 0, sizeof cmdbuf); /* Clear it, just in case */
        if (client_getln(cmdbuf, sizeof cmdbuf) < 1) {
-               CtdlLogPrintf(CTDL_ERR, "Client disconnected: ending session.\n");
-               CC->kill_me = 1;
-               CtdlThreadName(old_name);
+               syslog(LOG_ERR, "Citadel client disconnected: ending session.\n");
+               CC->kill_me = KILLME_CLIENT_DISCONNECTED;
                return;
        }
 
        /* Log the server command, but don't show passwords... */
-       if ( (strncasecmp(cmdbuf, "PASS", 4))
-          && (strncasecmp(cmdbuf, "SETP", 4)) ) {
-               CtdlLogPrintf(CTDL_INFO, "%s\n", cmdbuf);
+       if ( (strncasecmp(cmdbuf, "PASS", 4)) && (strncasecmp(cmdbuf, "SETP", 4)) ) {
+               syslog(LOG_INFO, "[%d][%s(%ld)] %s",
+                       CC->cs_pid, CC->curr_user, CC->user.usernum, cmdbuf
+               );
        }
        else {
-               CtdlLogPrintf(CTDL_INFO, "<password command sent>\n");
+               syslog(LOG_INFO, "[%d][%s(%ld)] <password command hidden from log>",
+                       CC->cs_pid, CC->curr_user, CC->user.usernum
+               );
        }
 
        buffer_output();
@@ -1128,8 +1031,6 @@ void do_command_loop(void) {
                time(&CC->lastidle);
        }
        
-       CtdlThreadName(cmdbuf);
-               
        if ((strncasecmp(cmdbuf, "ENT0", 4))
           && (strncasecmp(cmdbuf, "MESG", 4))
           && (strncasecmp(cmdbuf, "MSGS", 4)))
@@ -1145,7 +1046,6 @@ void do_command_loop(void) {
 
        /* Run any after-each-command routines registered by modules */
        PerformSessionHooks(EVT_CMD);
-       CtdlThreadName(old_name);
 }
 
 
@@ -1157,34 +1057,30 @@ void do_async_loop(void) {
 }
 
 
-
-
-
-
-
 /*****************************************************************************/
 /*                      MODULE INITIALIZATION STUFF                          */
 /*****************************************************************************/
 
 CTDL_MODULE_INIT(citserver)
 {
-       CtdlRegisterProtoHook(cmd_noop, "NOOP", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_qnop, "QNOP", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_quit, "QUIT", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_lout, "LOUT", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_asyn, "ASYN", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_info, "INFO", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_mesg, "MESG", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_emsg, "EMSG", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_echo, "ECHO", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_more, "MORE", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_iden, "IDEN", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_ipgm, "IPGM", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_term, "TERM", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_down, "DOWN", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_halt, "HALT", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_scdn, "SCDN", "Autoconverted. TODO: document me.");
-       CtdlRegisterProtoHook(cmd_time, "TIME", "Autoconverted. TODO: document me.");
-        /* return our Subversion id for the Log */
-       return "$Id$";
+       if (!threading) {
+               CtdlRegisterProtoHook(cmd_noop, "NOOP", "no operation");
+               CtdlRegisterProtoHook(cmd_qnop, "QNOP", "no operation with no response");
+               CtdlRegisterProtoHook(cmd_quit, "QUIT", "log out and disconnect from server");
+               CtdlRegisterProtoHook(cmd_lout, "LOUT", "log out but do not disconnect from server");
+               CtdlRegisterProtoHook(cmd_asyn, "ASYN", "enable asynchronous server responses");
+               CtdlRegisterProtoHook(cmd_info, "INFO", "fetch server capabilities and configuration");
+               CtdlRegisterProtoHook(cmd_mesg, "MESG", "fetch system banners");
+               CtdlRegisterProtoHook(cmd_emsg, "EMSG", "submit system banners");
+               CtdlRegisterProtoHook(cmd_echo, "ECHO", "echo text back to the client");
+               CtdlRegisterProtoHook(cmd_more, "MORE", "fetch the paginator prompt");
+               CtdlRegisterProtoHook(cmd_iden, "IDEN", "identify the client software and location");
+               CtdlRegisterProtoHook(cmd_term, "TERM", "terminate another running session");
+               CtdlRegisterProtoHook(cmd_down, "DOWN", "perform a server shutdown");
+               CtdlRegisterProtoHook(cmd_halt, "HALT", "halt the server without exiting the server process");
+               CtdlRegisterProtoHook(cmd_scdn, "SCDN", "schedule or cancel a server shutdown");
+               CtdlRegisterProtoHook(cmd_time, "TIME", "fetch the date and time from the server");
+       }
+        /* return our id for the Log */
+       return "citserver";
 }