New server command DLAT (DownLoad ATtachment) which
[citadel.git] / citadel / citserver.c
index bc7e493e09c1976d6356d1ebf7b9002145ce3ea8..95eab2fc673ceac0d2c6cf8a8d0b238effdedc88 100644 (file)
@@ -5,10 +5,6 @@
  *
  */
 
-#ifdef DLL_EXPORT
-#define IN_LIBCIT
-#endif
-
 #include "sysdep.h"
 #include <stdlib.h>
 #include <unistd.h>
@@ -35,7 +31,6 @@
 #include <dirent.h>
 #include <errno.h>
 #include <limits.h>
-/* #include <dlfcn.h> */
 #include <netdb.h>
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -58,6 +53,7 @@
 #include "policy.h"
 #include "control.h"
 #include "tools.h"
+#include "euidindex.h"
 
 #ifndef HAVE_SNPRINTF
 #include "snprintf.h"
@@ -189,6 +185,15 @@ void master_cleanup(int exitcode) {
        dump_heap();
 #endif
 
+       /* If the operator requested a halt but not an exit, halt here. */
+       if (shutdown_and_halt) {
+               lprintf(CTDL_NOTICE, "citserver: Halting server without exiting.\n");
+               fflush(stdout); fflush(stderr);
+               while(1) {
+                       sleep(32767);
+               }
+       }
+
        /* Now go away. */
        lprintf(CTDL_NOTICE, "citserver: Exiting with status %d\n", exitcode);
        fflush(stdout); fflush(stderr);
@@ -255,11 +260,21 @@ void cmd_info(void) {
        cprintf("1\n"); /* 1 = we support the extended paging options */
        cprintf("%s\n", CC->cs_nonce);
        cprintf("1\n"); /* 1 = yes, this system supports the QNOP command */
+
 #ifdef HAVE_LDAP
        cprintf("1\n"); /* 1 = yes, this server is LDAP-enabled */
 #else
        cprintf("0\n"); /* 1 = no, this server is not LDAP-enabled */
 #endif
+
+#ifdef ENABLE_AUTOLOGIN
+       cprintf("1\n"); /* "create new user" never works with autologin */
+#else
+       cprintf("%d\n", config.c_disable_newu); /* otherwise, site defined */
+#endif
+
+       cprintf("%s\n", config.c_default_cal_zone);
+
        cprintf("000\n");
 }
 
@@ -309,12 +324,12 @@ int is_public_client(void)
        struct stat statbuf;
        static time_t pc_timestamp = 0;
        static char public_clients[SIZ];
+       static char public_clients_file[SIZ];
 
-#ifndef HAVE_ETC
-#define PUBLIC_CLIENTS "./public_clients"
-#else
-#define PUBLIC_CLIENTS ETC_DIR"/public_clients"
-#endif
+       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
@@ -322,15 +337,16 @@ int is_public_client(void)
         * time we've been through the loop), read its contents and learn
         * the IP addresses of the listed hosts.
         */
-       if (stat(PUBLIC_CLIENTS, &statbuf) != 0) {
+       if (stat(public_clients_file, &statbuf) != 0) {
                /* No public_clients file exists, so bail out */
-               lprintf(CTDL_WARNING, "Warning: '%s' does not exist\n", PUBLIC_CLIENTS);
+               lprintf(CTDL_WARNING, "Warning: '%s' does not exist\n", 
+                               public_clients_file);
                return(0);
        }
 
        if (statbuf.st_mtime > pc_timestamp) {
                begin_critical_section(S_PUBLIC_CLIENTS);
-               lprintf(CTDL_INFO, "Loading %s\n", PUBLIC_CLIENTS);
+               lprintf(CTDL_INFO, "Loading %s\n", public_clients_file);
 
                safestrncpy(public_clients, "127.0.0.1", sizeof public_clients);
                if (hostname_to_dotted_quad(addrbuf, config.c_fqdn) == 0) {
@@ -338,13 +354,7 @@ int is_public_client(void)
                        strcat(public_clients, addrbuf);
                }
 
-               fp = fopen(
-#ifndef HAVE_ETC
-                                  "."
-#else
-                                  ETC_DIR
-#endif
-                                  "/public_clients", "r");
+               fp = fopen(public_clients_file, "r");
                if (fp != NULL) while (fgets(buf, sizeof buf, fp)!=NULL) {
                        for (i=0; i<strlen(buf); ++i) {
                                if (buf[i] == '#') buf[i] = 0;
@@ -458,22 +468,15 @@ void cmd_mesg(char *mname)
 
        extract_token(buf, mname, 0, '|', sizeof buf);
 
-       dirs[0] = strdup(
-#ifdef HAVE_DATA_DIR
-                                        DATA_DIR"/"
-#endif
-                                        "messages");
-       dirs[1] = strdup(
-#ifdef HAVE_DATA_DIR
-                                        DATA_DIR"/"
-#endif
-                                        "help");
+       dirs[0] = strdup(ctdl_message_dir);
+       dirs[1] = strdup(ctdl_hlp_dir);
+
        snprintf(buf2, sizeof buf2, "%s.%d.%d",
                buf, CC->cs_clientdev, CC->cs_clienttyp);
 
        /* If the client requested "?" then produce a listing */
        if (!strcmp(buf, "?")) {
-               cprintf("%d %s\n",LISTING_FOLLOWS,buf);
+               cprintf("%d %s\n", LISTING_FOLLOWS, buf);
                dp = opendir(dirs[1]);
                if (dp != NULL) {
                        while (d = readdir(dp), d != NULL) {
@@ -484,6 +487,9 @@ void cmd_mesg(char *mname)
                        closedir(dp);
                }
                cprintf("000\n");
+               free(dirs[0]);
+               free(dirs[1]);
+               return;
        }
 
        /* Otherwise, look for the requested file by name. */
@@ -505,17 +511,22 @@ void cmd_mesg(char *mname)
        free(dirs[1]);
 
        if (strlen(targ)==0) {
-               cprintf("%d '%s' not found.\n",ERROR + FILE_NOT_FOUND, mname);
+               cprintf("%d '%s' not found.  (Searching in %s and %s)\n",
+                       ERROR + FILE_NOT_FOUND,
+                       mname,
+                       ctdl_message_dir,
+                       ctdl_hlp_dir
+               );
                return;
        }
 
-       mfp = fopen(targ,"r");
+       mfp = fopen(targ, "r");
        if (mfp==NULL) {
                cprintf("%d Cannot open '%s': %s\n",
                        ERROR + INTERNAL_ERROR, targ, strerror(errno));
                return;
        }
-       cprintf("%d %s\n",LISTING_FOLLOWS,buf);
+       cprintf("%d %s\n", LISTING_FOLLOWS,buf);
 
        while (fgets(buf, (sizeof buf - 1), mfp) != NULL) {
                buf[strlen(buf)-1] = 0;
@@ -548,28 +559,17 @@ void cmd_emsg(char *mname)
                if (buf[a] == '/') buf[a] = '.';
        }
 
-       dirs[0] = strdup(
-#ifdef HAVE_DATA_DIR
-                                        DATA_DIR"/"
-#endif
-                                        "messages");
-       dirs[1] = strdup(
-#ifdef HAVE_DATA_DIR
-                                        DATA_DIR"/"
-#endif
-                                        "help");
+       dirs[0] = strdup(ctdl_message_dir);
+       dirs[1] = strdup(ctdl_hlp_dir);
+
        mesg_locate(targ, sizeof targ, buf, 2, (const char**)dirs);
        free(dirs[0]);
        free(dirs[1]);
 
        if (strlen(targ)==0) {
                snprintf(targ, sizeof targ, 
-#ifndef HAVE_DATA_DIR
-                        "."
-#else
-                        DATA_DIR
-#endif
-                                "/help/%s", buf);
+                                "%s/%s",
+                                ctdl_hlp_dir, buf);
        }
 
        mfp = fopen(targ,"w");
@@ -776,6 +776,18 @@ void cmd_down(void) {
        time_to_die = 1;
 }
 
+/*
+ * Halt the server without exiting the server process.
+ */
+void cmd_halt(void) {
+
+       if (CtdlAccessCheck(ac_aide)) return;
+
+       cprintf("%d Halting server.  Goodbye.\n", CIT_OK);
+       time_to_die = 1;
+       shutdown_and_halt = 1;
+}
+
 /*
  * Schedule or cancel a server shutdown
  */
@@ -832,7 +844,7 @@ void generate_nonce(struct CitContext *con) {
  */
 void begin_session(struct CitContext *con)
 {
-       int len;
+       socklen_t len;
        struct sockaddr_in sin;
 
        /* 
@@ -859,11 +871,12 @@ void begin_session(struct CitContext *con)
        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))     /* should be socklen_t but doesn't work on Macintosh */
+               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);
+                               &sin.sin_addr
+                       );
+               }
        }
        else {
                strcpy(con->cs_host, "");
@@ -903,12 +916,12 @@ void citproto_begin_session() {
  * This loop recognizes all server commands.
  */
 void do_command_loop(void) {
-       char cmdbuf[1024];
+       char cmdbuf[SIZ];
 
        time(&CC->lastcmd);
        memset(cmdbuf, 0, sizeof cmdbuf); /* Clear it, just in case */
        if (client_getln(cmdbuf, sizeof cmdbuf) < 1) {
-               lprintf(CTDL_ERR, "Client socket is broken; ending session\n");
+               lprintf(CTDL_ERR, "Client disconnected: ending session.\n");
                CC->kill_me = 1;
                return;
        }
@@ -926,12 +939,14 @@ void do_command_loop(void) {
 
        /*
         * Let other clients see the last command we executed, and
-        * update the idle time, but not NOOP, QNOP, PEXP, or GEXP.
+        * update the idle time, but not NOOP, QNOP, PEXP, GEXP, RWHO, or TIME.
         */
        if ( (strncasecmp(cmdbuf, "NOOP", 4))
           && (strncasecmp(cmdbuf, "QNOP", 4))
           && (strncasecmp(cmdbuf, "PEXP", 4))
-          && (strncasecmp(cmdbuf, "GEXP", 4)) ) {
+          && (strncasecmp(cmdbuf, "GEXP", 4))
+          && (strncasecmp(cmdbuf, "RWHO", 4))
+          && (strncasecmp(cmdbuf, "TIME", 4)) ) {
                strcpy(CC->lastcmdname, "    ");
                safestrncpy(CC->lastcmdname, cmdbuf, sizeof(CC->lastcmdname));
                time(&CC->lastidle);
@@ -1034,6 +1049,10 @@ void do_command_loop(void) {
                cmd_rdir();
        }
 
+       else if (!strncasecmp(cmdbuf,"EUID",4)) {
+               cmd_euid(&cmdbuf[5]);
+       }
+
        else if (!strncasecmp(cmdbuf,"MSG0",4)) {
                cmd_msg0(&cmdbuf[5]);
        }
@@ -1058,6 +1077,10 @@ void do_command_loop(void) {
                cmd_opna(&cmdbuf[5]);
        }
 
+       else if (!strncasecmp(cmdbuf,"DLAT",4)) {
+               cmd_dlat(&cmdbuf[5]);
+       }
+
        else if (!strncasecmp(cmdbuf,"INFO",4)) {
                cmd_info();
        }
@@ -1238,6 +1261,10 @@ void do_command_loop(void) {
                cmd_down();
        }
 
+       else if (!strncasecmp(cmdbuf,"HALT",4)) {
+               cmd_halt();
+       }
+
        else if (!strncasecmp(cmdbuf,"SCDN",4)) {
                cmd_scdn(&cmdbuf[5]);
        }