* Began (but did not finish) applying GPL3+ declarations to each source file. This...
[citadel.git] / citadel / citadel_ipc.c
index 840c4f2c63708e6d4fa973d602e02aab93a1b650..ef902281dd69ae44310bc98799eb5de28abae09a 100644 (file)
@@ -1,4 +1,21 @@
-/* $Id$ */
+/* $Id$ 
+ *
+ * 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.
+ *
+ *  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.
+ *
+ *  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
+ */
 
 #include "sysdep.h"
 #if TIME_WITH_SYS_TIME
 #ifdef THREADED_CLIENT
 #include <pthread.h>
 #endif
+#include <libcitadel.h>
 #include "citadel.h"
 #include "citadel_ipc.h"
 #include "citadel_decls.h"
-#include "tools.h"
-
+#include "citadel_dirs.h"
 #ifdef THREADED_CLIENT
 pthread_mutex_t rwlock;
 #endif
@@ -71,7 +88,6 @@ static void serv_write(CtdlIPC *ipc, const char *buf, unsigned int nbytes);
 #ifdef HAVE_OPENSSL
 static void serv_read_ssl(CtdlIPC *ipc, char *buf, unsigned int bytes);
 static void serv_write_ssl(CtdlIPC *ipc, const char *buf, unsigned int nbytes);
-static void ssl_lock(int mode, int n, const char *file, int line);
 static void endtls(SSL *ssl);
 #ifdef THREADED_CLIENT
 static unsigned long id_callback(void);
@@ -81,6 +97,9 @@ static void CtdlIPC_getline(CtdlIPC* ipc, char *buf);
 static void CtdlIPC_putline(CtdlIPC *ipc, const char *buf);
 
 
+
+const char *svn_revision(void);
+
 /*
  * Does nothing.  The server should always return 200.
  */
@@ -121,7 +140,7 @@ int CtdlIPCEcho(CtdlIPC *ipc, const char *arg, char *cret)
 int CtdlIPCQuit(CtdlIPC *ipc)
 {
        register int ret = 221;         /* Default to successful quit */
-       char aaa[128];
+       char aaa[SIZ]; 
 
        CtdlIPC_lock(ipc);
        if (ipc->sock > -1) {
@@ -143,13 +162,13 @@ int CtdlIPCQuit(CtdlIPC *ipc)
 
 
 /*
- * Asks the server to logout.  Should always return 200, even if no user
+ * Asks the server to log out.  Should always return 200, even if no user
  * was logged in.  The user will not be logged in after this!
  */
 int CtdlIPCLogout(CtdlIPC *ipc)
 {
        register int ret;
-       char aaa[128];
+       char aaa[SIZ];
 
        CtdlIPC_lock(ipc);
        CtdlIPC_putline(ipc, "LOUT");
@@ -327,6 +346,7 @@ int CtdlIPCKnownRooms(CtdlIPC *ipc, enum RoomList which, int floor, struct march
                }
        }
        *listing = march;
+       if (bbb) free(bbb);
        return ret;
 }
 
@@ -367,6 +387,22 @@ int CtdlIPCSetConfig(CtdlIPC *ipc, struct ctdluser *uret, char *cret)
 }
 
 
+/* RENU */
+int CtdlIPCRenameUser(CtdlIPC *ipc, char *oldname, char *newname, char *cret)
+{
+       register int ret;
+       char cmd[256];
+
+       if (!oldname) return -2;
+       if (!newname) return -2;
+       if (!cret) return -2;
+
+       snprintf(cmd, sizeof cmd, "RENU %s|%s", oldname, newname);
+       ret = CtdlIPCGenericCommand(ipc, cmd, NULL, 0, NULL, NULL, cret);
+       return ret;
+}
+
+
 /* GOTO */
 int CtdlIPCGotoRoom(CtdlIPC *ipc, const char *room, const char *passwd,
                struct ctdlipcroom **rret, char *cret)
@@ -407,9 +443,12 @@ int CtdlIPCGotoRoom(CtdlIPC *ipc, const char *room, const char *passwd,
                rret[0]->RRaide = extract_int(cret, 8);
                rret[0]->RRnewmail = extract_long(cret, 9);
                rret[0]->RRfloor = extract_int(cret, 10);
+               rret[0]->RRflags2 = extract_int(cret, 14);
        } else {
                free(*rret);
+               *rret = NULL;
        }
+       free(aaa);
        return ret;
 }
 
@@ -474,6 +513,7 @@ int CtdlIPCGetSingleMessage(CtdlIPC *ipc, long msgnum, int headers, int as_mime,
        size_t bbb_len;
        int multipart_hunting = 0;
        char multipart_prefix[128];
+       char encoding[256];
 
        if (!cret) return -1;
        if (!mret) return -1;
@@ -481,6 +521,7 @@ int CtdlIPCGetSingleMessage(CtdlIPC *ipc, long msgnum, int headers, int as_mime,
        if (!*mret) return -1;
        if (!msgnum) return -1;
 
+       strcpy(encoding, "");
        strcpy(mret[0]->content_type, "");
        sprintf(aaa, "MSG%d %ld|%d", as_mime, msgnum, headers);
        ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, &bbb, &bbb_len, cret);
@@ -511,6 +552,8 @@ int CtdlIPCGetSingleMessage(CtdlIPC *ipc, long msgnum, int headers, int as_mime,
                                        safestrncpy(mret[0]->node, &aaa[5], SIZ);
                                else if (!strncasecmp(aaa, "rcpt=", 5))
                                        safestrncpy(mret[0]->recipient, &aaa[5], SIZ);
+                               else if (!strncasecmp(aaa, "wefw=", 5))
+                                       safestrncpy(mret[0]->references, &aaa[5], SIZ);
                                else if (!strncasecmp(aaa, "time=", 5))
                                        mret[0]->time = atol(&aaa[5]);
 
@@ -574,10 +617,9 @@ int CtdlIPCGetSingleMessage(CtdlIPC *ipc, long msgnum, int headers, int as_mime,
                        /* If doing a MIME thing, pull out the extra headers */
                        if (as_mime == 4) {
                                do {
-                                       if (!strncasecmp(bbb, "Content-type: ", 14)) {
+                                       if (!strncasecmp(bbb, "Content-type:", 13)) {
                                                extract_token(mret[0]->content_type, bbb, 0, '\n', sizeof mret[0]->content_type);
-                                               strcpy(mret[0]->content_type,
-                                                       &mret[0]->content_type[14]);
+                                               strcpy(mret[0]->content_type, &mret[0]->content_type[13]);
                                                striplt(mret[0]->content_type);
 
                                                /* strip out ";charset=" portion.  FIXME do something with
@@ -589,6 +631,16 @@ int CtdlIPCGetSingleMessage(CtdlIPC *ipc, long msgnum, int headers, int as_mime,
                                                }
 
                                        }
+                                       if (!strncasecmp(bbb, "X-Citadel-MSG4-Partnum:", 23)) {
+                                               extract_token(mret[0]->mime_chosen, bbb, 0, '\n', sizeof mret[0]->mime_chosen);
+                                               strcpy(mret[0]->mime_chosen, &mret[0]->mime_chosen[23]);
+                                               striplt(mret[0]->mime_chosen);
+                                       }
+                                       if (!strncasecmp(bbb, "Content-transfer-encoding:", 26)) {
+                                               extract_token(encoding, bbb, 0, '\n', sizeof encoding);
+                                               strcpy(encoding, &encoding[26]);
+                                               striplt(encoding);
+                                       }
                                        remove_token(bbb, 0, '\n');
                                } while ((bbb[0] != 0) && (bbb[0] != '\n'));
                                remove_token(bbb, 0, '\n');
@@ -597,8 +649,25 @@ int CtdlIPCGetSingleMessage(CtdlIPC *ipc, long msgnum, int headers, int as_mime,
 
                }
                if (strlen(bbb)) {
+
+                       if ( (!strcasecmp(encoding, "base64")) || (!strcasecmp(encoding, "quoted-printable")) ) {
+                               char *ccc = NULL;
+                               int bytes_decoded = 0;
+                               ccc = malloc(strlen(bbb) + 32768);
+                               if (!strcasecmp(encoding, "base64")) {
+                                       bytes_decoded = CtdlDecodeBase64(ccc, bbb, strlen(bbb));
+                               }
+                               else if (!strcasecmp(encoding, "quoted-printable")) {
+                                       bytes_decoded = CtdlDecodeQuotedPrintable(ccc, bbb, strlen(bbb));
+                               }
+                               ccc[bytes_decoded] = 0;
+                               free(bbb);
+                               bbb = ccc;
+                       }
+
                        /* FIXME: Strip trailing whitespace */
                        bbb = (char *)realloc(bbb, (size_t)(strlen(bbb) + 1));
+
                } else {
                        bbb = (char *)realloc(bbb, 1);
                        *bbb = '\0';
@@ -670,10 +739,25 @@ int CtdlIPCServerInfo(CtdlIPC *ipc, char *cret)
                                        break;
                        case 15:        ipc->ServInfo.newuser_disabled = atoi(buf);
                                        break;
+                       case 16:        strcpy(ipc->ServInfo.default_cal_zone, buf);
+                                       break;
+                       case 17:        ipc->ServInfo.load_avg = atof(buf);
+                                       break;
+                       case 18:        ipc->ServInfo.worker_avg = atof(buf);
+                                       break;
+                       case 19:        ipc->ServInfo.thread_count = atoi(buf);
+                                       break;
+                       case 20:        ipc->ServInfo.has_sieve = atoi(buf);
+                                       break;
+                       case 21:        ipc->ServInfo.fulltext_enabled = atoi(buf);
+                                       break;
+                       case 22:        strcpy(ipc->ServInfo.svn_revision, buf);
+                                       break;
                        }
                }
 
        }
+       if (listing) free(listing);
        return ret;
 }
 
@@ -829,19 +913,34 @@ int CtdlIPCSetRoomAide(CtdlIPC *ipc, const char *username, char *cret)
 
 
 /* ENT0 */
-int CtdlIPCPostMessage(CtdlIPC *ipc, int flag, const struct ctdlipcmessage *mr, char *cret)
+int CtdlIPCPostMessage(CtdlIPC *ipc, int flag, int *subject_required,  struct ctdlipcmessage *mr, char *cret)
 {
        register int ret;
        char cmd[SIZ];
+       char *ptr;
 
        if (!cret) return -2;
        if (!mr) return -2;
 
+       if (mr->references) {
+               for (ptr=mr->references; *ptr != 0; ++ptr) {
+                       if (*ptr == '|') *ptr = '!';
+               }
+       }
+
        snprintf(cmd, sizeof cmd,
-                       "ENT0 %d|%s|%d|%d|%s|%s", flag, mr->recipient,
-                       mr->anonymous, mr->type, mr->subject, mr->author);
+                       "ENT0 %d|%s|%d|%d|%s|%s||||||%s|", flag, mr->recipient,
+                       mr->anonymous, mr->type, mr->subject, mr->author, mr->references);
        ret = CtdlIPCGenericCommand(ipc, cmd, mr->text, strlen(mr->text), NULL,
                        NULL, cret);
+       if ((flag == 0) && (subject_required != NULL)) {
+               /* Is the server strongly recommending that the user enter a message subject? */
+               if ((cret[3] != '\0') && (cret[4] != '\0')) {
+                       *subject_required = extract_int(&cret[4], 1);
+               }
+
+               
+       }
        return ret;
 }
 
@@ -1120,26 +1219,6 @@ int CtdlIPCMoveFile(CtdlIPC *ipc, const char *filename, const char *destroom, ch
 }
 
 
-/* NETF */
-int CtdlIPCNetSendFile(CtdlIPC *ipc, const char *filename, const char *destnode, char *cret)
-{
-       register int ret;
-       char *aaa;
-
-       if (!cret) return -2;
-       if (!filename) return -2;
-       if (!destnode) return -2;
-
-       aaa = (char *)malloc(strlen(filename) + strlen(destnode) + 7);
-       if (!aaa) return -1;
-
-       sprintf(aaa, "NETF %s|%s", filename, destnode);
-       ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
-       free(aaa);
-       return ret;
-}
-
-
 /* RWHO */
 int CtdlIPCOnlineUsers(CtdlIPC *ipc, char **listing, time_t *stamp, char *cret)
 {
@@ -1286,14 +1365,18 @@ int CtdlIPCImageDownload(CtdlIPC *ipc, const char *filename, void **buf,
 
 
 /* UOPN */
-int CtdlIPCFileUpload(CtdlIPC *ipc, const char *save_as, const char *comment,
-               const char *path,
+int CtdlIPCFileUpload(CtdlIPC *ipc, const char *save_as, const char *comment, 
+               const char *path, 
                void (*progress_gauge_callback)
                        (CtdlIPC*, unsigned long, unsigned long),
                char *cret)
 {
        register int ret;
        char *aaa;
+       FILE *uploadFP;
+       char MimeTestBuf[64];
+       const char *MimeType;
+       long len;
 
        if (!cret) return -1;
        if (!save_as) return -1;
@@ -1302,15 +1385,24 @@ int CtdlIPCFileUpload(CtdlIPC *ipc, const char *save_as, const char *comment,
        if (!*path) return -1;
        if (ipc->uploading) return -1;
 
+       uploadFP = fopen(path, "r");
+       if (!uploadFP) return -2;
+
+       len = fread(&MimeTestBuf[0], 1, 64, uploadFP);
+       rewind (uploadFP);
+       if (len < 0) 
+               return -3;
+
+       MimeType = GuessMimeType(&MimeTestBuf[0], len);
        aaa = (char *)malloc(strlen(save_as) + strlen(comment) + 7);
        if (!aaa) return -1;
 
-       sprintf(aaa, "UOPN %s|%s", save_as, comment);
+       sprintf(aaa, "UOPN %s|%s|%s", save_as, MimeType,  comment);
        ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
        free(aaa);
        if (ret / 100 == 2) {
                ipc->uploading = 1;
-               ret = CtdlIPCWriteUpload(ipc, path, progress_gauge_callback, cret);
+               ret = CtdlIPCWriteUpload(ipc, uploadFP, progress_gauge_callback, cret);
                ret = CtdlIPCEndUpload(ipc, (ret == -2 ? 1 : 0), cret);
                ipc->uploading = 0;
        }
@@ -1326,7 +1418,11 @@ int CtdlIPCImageUpload(CtdlIPC *ipc, int for_real, const char *path,
                char *cret)
 {
        register int ret;
+       FILE *uploadFP;
        char *aaa;
+       char MimeTestBuf[64];
+       const char *MimeType;
+       long len;
 
        if (!cret) return -1;
        if (!save_as) return -1;
@@ -1337,12 +1433,21 @@ int CtdlIPCImageUpload(CtdlIPC *ipc, int for_real, const char *path,
        aaa = (char *)malloc(strlen(save_as) + 17);
        if (!aaa) return -1;
 
-       sprintf(aaa, "UIMG %d|%s", for_real, save_as);
+       uploadFP = fopen(path, "r");
+       if (!uploadFP) return -2;
+
+       len = fread(&MimeTestBuf[0], 1, 64, uploadFP);
+       rewind (uploadFP);
+       if (len < 0) 
+               return -3;
+       MimeType = GuessMimeType(&MimeTestBuf[0], 64);
+
+       sprintf(aaa, "UIMG %d|%s|%s", for_real, MimeType, save_as);
        ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
        free(aaa);
        if (ret / 100 == 2 && for_real) {
                ipc->uploading = 1;
-               ret = CtdlIPCWriteUpload(ipc, path, progress_gauge_callback, cret);
+               ret = CtdlIPCWriteUpload(ipc, uploadFP, progress_gauge_callback, cret);
                ret = CtdlIPCEndUpload(ipc, (ret == -2 ? 1 : 0), cret);
                ipc->uploading = 0;
        }
@@ -1756,7 +1861,7 @@ int CtdlIPCGetMessageExpirationPolicy(CtdlIPC *ipc, int which,
                struct ExpirePolicy **policy, char *cret)
 {
        static char *proto[] = {"room", "floor", "site", "mailboxes" };
-       char aaa[11];
+       char cmd[256];
        register int ret;
 
        if (!cret) return -2;
@@ -1765,14 +1870,13 @@ int CtdlIPCGetMessageExpirationPolicy(CtdlIPC *ipc, int which,
        if (!*policy) return -1;
        if (which < 0 || which > 3) return -2;
        
-       sprintf(aaa, "GPEX %s", proto[which]);
-       ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
+       sprintf(cmd, "GPEX %s", proto[which]);
+       ret = CtdlIPCGenericCommand(ipc, cmd, NULL, 0, NULL, NULL, cret);
        if (ret / 100 == 2) {
                policy[0]->expire_mode = extract_int(cret, 0);
                policy[0]->expire_value = extract_int(cret, 1);
        }
        return ret;
-
 }
 
 
@@ -1826,6 +1930,7 @@ int CtdlIPCSetSystemConfig(CtdlIPC *ipc, const char *listing, char *cret)
 int CtdlIPCGetSystemConfigByType(CtdlIPC *ipc, const char *mimetype,
                char **listing, char *cret)
 {
+       register int ret;
        char *aaa;
        size_t bytes;
 
@@ -1837,8 +1942,10 @@ int CtdlIPCGetSystemConfigByType(CtdlIPC *ipc, const char *mimetype,
        aaa = malloc(strlen(mimetype) + 13);
        if (!aaa) return -1;
        sprintf(aaa, "CONF GETSYS|%s", mimetype);
-       return CtdlIPCGenericCommand(ipc, aaa, NULL, 0,
+       ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0,
                        listing, &bytes, cret);
+    free(aaa);
+    return ret;
 }
 
 
@@ -1846,6 +1953,7 @@ int CtdlIPCGetSystemConfigByType(CtdlIPC *ipc, const char *mimetype,
 int CtdlIPCSetSystemConfigByType(CtdlIPC *ipc, const char *mimetype,
               const char *listing, char *cret)
 {
+    register int ret;
        char *aaa;
 
        if (!cret) return -2;
@@ -1855,8 +1963,10 @@ int CtdlIPCSetSystemConfigByType(CtdlIPC *ipc, const char *mimetype,
        aaa = malloc(strlen(mimetype) + 13);
        if (!aaa) return -1;
        sprintf(aaa, "CONF PUTSYS|%s", mimetype);
-       return CtdlIPCGenericCommand(ipc, aaa, listing, strlen(listing),
+       ret = CtdlIPCGenericCommand(ipc, aaa, listing, strlen(listing),
                        NULL, NULL, cret);
+    free(aaa);
+    return ret;
 }
 
 
@@ -2008,6 +2118,7 @@ static void endtls(SSL *ssl)
 /* QDIR */
 int CtdlIPCDirectoryLookup(CtdlIPC *ipc, const char *address, char *cret)
 {
+    register int ret;
        char *aaa;
 
        if (!address) return -2;
@@ -2017,7 +2128,9 @@ int CtdlIPCDirectoryLookup(CtdlIPC *ipc, const char *address, char *cret)
        if (!aaa) return -1;
 
        sprintf(aaa, "QDIR %s", address);
-       return CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
+       ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret);
+    free(aaa);
+    return ret;
 }
 
 
@@ -2299,7 +2412,7 @@ int CtdlIPCEndUpload(CtdlIPC *ipc, int discard, char *cret)
 
 
 /* WRIT */
-int CtdlIPCWriteUpload(CtdlIPC *ipc, const char *path,
+int CtdlIPCWriteUpload(CtdlIPC *ipc, FILE *uploadFP,
                void (*progress_gauge_callback)
                        (CtdlIPC*, unsigned long, unsigned long),
                char *cret)
@@ -2309,14 +2422,10 @@ int CtdlIPCWriteUpload(CtdlIPC *ipc, const char *path,
        size_t bytes;
        char aaa[SIZ];
        char buf[4096];
-       FILE *fd;
+       FILE *fd = uploadFP;
+       int ferr;
 
        if (!cret) return -1;
-       if (!path) return -1;
-       if (!*path) return -1;
-
-       fd = fopen(path, "r");
-       if (!fd) return -2;
 
        fseek(fd, 0L, SEEK_END);
        bytes = ftell(fd);
@@ -2354,7 +2463,9 @@ int CtdlIPCWriteUpload(CtdlIPC *ipc, const char *path,
        }
        if (progress_gauge_callback)
                progress_gauge_callback(ipc, 1, 1);
-       return (!ferror(fd) ? ret : -2);
+       ferr = ferror(fd);
+       fclose(fd);
+       return (!ferr ? ret : -2);
 }
 
 
@@ -2613,7 +2724,7 @@ static void serv_read(CtdlIPC *ipc, char *buf, unsigned int bytes)
 /*
  * send binary to server
  */
-static void serv_write(CtdlIPC *ipc, const char *buf, unsigned int nbytes)
+void serv_write(CtdlIPC *ipc, const char *buf, unsigned int nbytes)
 {
        unsigned int bytes_written = 0;
        int retval;
@@ -2663,11 +2774,17 @@ static void serv_read_ssl(CtdlIPC* ipc, char *buf, unsigned int bytes)
                                sleep(1);
                                continue;
                        }
+/***
+ Not sure why we'd want to handle these error codes any differently,
+ but this definitely isn't the way to handle them.  Someone must have
+ naively assumed that we could fall back to unencrypted communications,
+ but all it does is just recursively blow the stack.
                        if (errval == SSL_ERROR_ZERO_RETURN ||
                                        errval == SSL_ERROR_SSL) {
                                serv_read(ipc, &buf[len], bytes - len);
                                return;
                        }
+ ***/
                        error_printf("SSL_read in serv_read: %s\n",
                                        ERR_reason_error_string(ERR_peek_error()));
                        connection_died(ipc, 1);
@@ -2721,6 +2838,17 @@ static void serv_write_ssl(CtdlIPC *ipc, const char *buf, unsigned int nbytes)
 }
 
 
+#ifdef THREADED_CLIENT
+static void ssl_lock(int mode, int n, const char *file, int line)
+{
+       if (mode & CRYPTO_LOCK)
+               pthread_mutex_lock(Critters[n]);
+       else
+               pthread_mutex_unlock(Critters[n]);
+}
+#endif /* THREADED_CLIENT */
+
+
 static void CtdlIPC_init_OpenSSL(void)
 {
        int a;
@@ -2801,15 +2929,6 @@ static void CtdlIPC_init_OpenSSL(void)
 }
 
 
-static void ssl_lock(int mode, int n, const char *file, int line)
-{
-#ifdef THREADED_CLIENT
-       if (mode & CRYPTO_LOCK)
-               pthread_mutex_lock(Critters[n]);
-       else
-               pthread_mutex_unlock(Critters[n]);
-#endif /* THREADED_CLIENT */
-}
 
 #ifdef THREADED_CLIENT
 static unsigned long id_callback(void) {
@@ -2819,9 +2938,178 @@ static unsigned long id_callback(void) {
 #endif /* HAVE_OPENSSL */
 
 
+int
+ReadNetworkChunk(CtdlIPC* ipc)
+{
+       fd_set read_fd;
+       int tries;
+       int ret = 0;
+       int err = 0;
+       struct timeval tv;
+       size_t n;
+
+       tv.tv_sec = 1;
+       tv.tv_usec = 1000;
+       tries = 0;
+       n = 0;
+       while (1)
+       {
+               errno=0;
+               FD_ZERO(&read_fd);
+               FD_SET(ipc->sock, &read_fd);
+               ret = select(ipc->sock+1, &read_fd, NULL, NULL,  &tv);
+               
+//             fprintf(stderr, "\nselect failed: %d %d %s\n", ret,  err, strerror(err));
+               
+               if (ret > 0) {
+                       
+                       *(ipc->BufPtr) = '\0';
+//                     n = read(ipc->sock, ipc->BufPtr, ipc->BufSize  - (ipc->BufPtr - ipc->Buf) - 1);
+                       n = recv(ipc->sock, ipc->BufPtr, ipc->BufSize  - (ipc->BufPtr - ipc->Buf) - 1, 0);
+                       if (n > 0) {
+                               ipc->BufPtr[n]='\0';
+                               ipc->BufUsed += n;
+                               return n;
+                       }
+                       else 
+                               return n;
+               }
+               else if (ret < 0) {
+                       if (!(errno == EINTR || errno == EAGAIN))
+                               error_printf( "\nselect failed: %d %s\n", err, strerror(err));
+                       return -1;
+               }/*
+               else {
+                       tries ++;
+                       if (tries >= 10)
+                       n = read(ipc->sock, ipc->BufPtr, ipc->BufSize  - (ipc->BufPtr - ipc->Buf) - 1);
+                       if (n > 0) {
+                               ipc->BufPtr[n]='\0';
+                               ipc->BufUsed += n;
+                               return n;
+                       }
+                       else {
+                               connection_died(ipc, 0);
+                               return -1;
+                       }
+                       }*/
+       }
+}
+
 /*
  * input string from socket - implemented in terms of serv_read()
  */
+#ifdef CHUNKED_READ
+
+static void CtdlIPC_getline(CtdlIPC* ipc, char *buf)
+{
+       int i, ntries;
+       char *aptr, *bptr, *aeptr, *beptr;
+
+//     error_printf("---\n");
+
+       beptr = buf + SIZ;
+#if defined(HAVE_OPENSSL)
+       if (ipc->ssl) {
+               
+               /* Read one character at a time. */
+               for (i = 0;; i++) {
+                       serv_read(ipc, &buf[i], 1);
+                       if (buf[i] == '\n' || i == (SIZ-1))
+                               break;
+               }
+               
+               /* If we got a long line, discard characters until the newline. */
+               if (i == (SIZ-1))
+                       while (buf[i] != '\n')
+                               serv_read(ipc, &buf[i], 1);
+               
+               /* Strip the trailing newline (and carriage return, if present) */
+               if (i>=0 && buf[i] == 10) buf[i--] = 0;
+               if (i>=0 && buf[i] == 13) buf[i--] = 0;
+       }
+       else
+#endif
+       {
+               if (ipc->Buf == NULL)
+               {
+                       ipc->BufSize = SIZ;
+                       ipc->Buf = (char*) malloc(ipc->BufSize + 10);
+                       *(ipc->Buf) = '\0';
+                       ipc->BufPtr = ipc->Buf;
+               }
+
+               ntries = 0;
+//             while ((ipc->BufUsed == 0)||(ntries++ > 10))
+               if (ipc->BufUsed == 0)
+                       ReadNetworkChunk(ipc);
+
+////           if (ipc->BufUsed != 0) while (1)
+               bptr = buf;
+
+               while (1)
+               {
+                       aptr = ipc->BufPtr;
+                       aeptr = ipc->Buf + ipc->BufSize;
+                       while ((aptr < aeptr) && 
+                              (bptr < beptr) &&
+                              (*aptr != '\0') && 
+                              (*aptr != '\n'))
+                               *(bptr++) = *(aptr++);
+                       if ((*aptr == '\n') && (aptr < aeptr))
+                       {
+                               /* Terminate it right, remove the line breaks */
+                               while ((aptr < aeptr) && ((*aptr == '\n') || (*aptr == '\r')))
+                                       aptr ++;
+                               while ((aptr < aeptr ) && (*(aptr + 1) == '\0') )
+                                       aptr ++;
+                               *(bptr++) = '\0';
+//                             fprintf(stderr, "parsing %d %d %d - %d %d %d %s\n", ipc->BufPtr - ipc->Buf, aptr - ipc->BufPtr, ipc->BufUsed , *aptr, *(aptr-1), *(aptr+1), buf);
+                               if ((bptr > buf + 1) && (*(bptr-1) == '\r'))
+                                       *(--bptr) = '\0';
+                               
+                               /* is there more in the buffer we need to read later? */
+                               if (ipc->Buf + ipc->BufUsed > aptr)
+                               {
+                                       ipc->BufPtr = aptr;
+                               }
+                               else
+                               {
+                                       ipc->BufUsed = 0;
+                                       ipc->BufPtr = ipc->Buf;
+                               }
+//                             error_printf("----bla6\n");
+                               return;
+                               
+                       }/* should we move our read stuf to the bufferstart so we have more space at the end? */
+                       else if ((ipc->BufPtr != ipc->Buf) && 
+                                (ipc->BufUsed > (ipc->BufSize  - (ipc->BufSize / 4))))
+                       {
+                               size_t NewBufSize = ipc->BufSize * 2;
+                               int delta = (ipc->BufPtr - ipc->Buf);
+                               char *NewBuf;
+
+                               /* if the line would end after our buffer, we should use a bigger buffer. */
+                               NewBuf = (char *)malloc (NewBufSize + 10);
+                               memcpy (NewBuf, ipc->BufPtr, ipc->BufUsed - delta);
+                               free(ipc->Buf);
+                               ipc->Buf = ipc->BufPtr = NewBuf;
+                               ipc->BufUsed -= delta;
+                               ipc->BufSize = NewBufSize;
+                       }
+                       if (ReadNetworkChunk(ipc) <0)
+                       {
+//                             error_printf("----bla\n");
+                               return;
+                       }
+               }
+///            error_printf("----bl45761%s\nipc->BufUsed");
+       }
+//     error_printf("----bla1\n");
+}
+
+#else  /* CHUNKED_READ */
+
 static void CtdlIPC_getline(CtdlIPC* ipc, char *buf)
 {
        int i;
@@ -2839,10 +3127,14 @@ static void CtdlIPC_getline(CtdlIPC* ipc, char *buf)
                        serv_read(ipc, &buf[i], 1);
 
        /* Strip the trailing newline (and carriage return, if present) */
-       if (buf[i] == 10) buf[i--] = 0;
-       if (buf[i] == 13) buf[i--] = 0;
+       if (i>=0 && buf[i] == 10) buf[i--] = 0;
+       if (i>=0 && buf[i] == 13) buf[i--] = 0;
 }
 
+
+#endif /* CHUNKED_READ */
+
+
 void CtdlIPC_chat_recv(CtdlIPC* ipc, char* buf)
 {
        CtdlIPC_getline(ipc, buf);
@@ -2907,6 +3199,9 @@ CtdlIPC* CtdlIPC_new(int argc, char **argv, char *hostbuf, char *portbuf)
        ipc->uploading = 0;
        ipc->last_command_sent = 0L;
        ipc->network_status_cb = NULL;
+       ipc->Buf = NULL;
+       ipc->BufUsed = 0;
+       ipc->BufPtr = NULL;
 
        strcpy(cithost, DEFAULT_HOST);  /* default host */
        strcpy(citport, DEFAULT_PORT);  /* default port */
@@ -2942,11 +3237,7 @@ CtdlIPC* CtdlIPC_new(int argc, char **argv, char *hostbuf, char *portbuf)
        /* If we're using a unix domain socket we can do a bunch of stuff */
        if (!strcmp(cithost, UDS)) {
                if (!strcasecmp(citport, DEFAULT_PORT)) {
-#ifdef HAVE_RUN_DIR
-                       snprintf(sockpath, sizeof sockpath, RUN_DIR "/citadel.socket");
-#else
-                       snprintf(sockpath, sizeof sockpath, CTDLDIR "/citadel.socket");
-#endif
+                       snprintf(sockpath, sizeof sockpath, file_citadel_socket);
                }
                else {
                        snprintf(sockpath, sizeof sockpath, "%s/%s", citport, "citadel.socket");
@@ -2988,6 +3279,10 @@ void CtdlIPC_delete(CtdlIPC* ipc)
                shutdown(ipc->sock, 2); /* Close it up */
                ipc->sock = -1;
        }
+       if (ipc->Buf != NULL)
+               free (ipc->Buf);
+       ipc->Buf = NULL;
+       ipc->BufPtr = NULL;
        ifree(ipc);
 }