X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fcitadel_ipc.c;h=ef902281dd69ae44310bc98799eb5de28abae09a;hb=4eb74b26380dfde31c86c685f0589e0c653aebf0;hp=d0d68b6fbd5714ebd297ed64497d1be6f6f01ef2;hpb=22095c4da0706cae686aae31e6384755c755aea2;p=citadel.git diff --git a/citadel/citadel_ipc.c b/citadel/citadel_ipc.c index d0d68b6fb..ef902281d 100644 --- a/citadel/citadel_ipc.c +++ b/citadel/citadel_ipc.c @@ -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 @@ -29,11 +46,11 @@ #ifdef THREADED_CLIENT #include #endif +#include #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"); @@ -285,7 +304,7 @@ int CtdlIPCKnownRooms(CtdlIPC *ipc, enum RoomList which, int floor, struct march {"LKRA", "LKRN", "LKRO", "LZRM", "LRMS", "LPRM" }; char aaa[SIZ]; char *bbb = NULL; - size_t bbbsize; + size_t bbb_len; if (!listing) return -2; if (*listing) return -2; /* Free the listing first */ @@ -294,20 +313,20 @@ int CtdlIPCKnownRooms(CtdlIPC *ipc, enum RoomList which, int floor, struct march if (floor < -1) return -2; /* Can't validate upper bound, sorry */ sprintf(aaa, "%s %d", proto[which], floor); - ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, &bbb, &bbbsize, cret); + ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, &bbb, &bbb_len, cret); if (ret / 100 == 1) { struct march *mptr; while (bbb && strlen(bbb)) { int a; - extract_token(aaa, bbb, 0, '\n'); + extract_token(aaa, bbb, 0, '\n', sizeof aaa); a = strlen(aaa); memmove(bbb, bbb + a + 1, strlen(bbb) - a); mptr = (struct march *) malloc(sizeof (struct march)); if (mptr) { mptr->next = NULL; - extract(mptr->march_name, aaa, 0); + extract_token(mptr->march_name, aaa, 0, '|', sizeof mptr->march_name); mptr->march_flags = (unsigned int) extract_int(aaa, 1); mptr->march_floor = (char) extract_int(aaa, 2); mptr->march_order = (char) extract_int(aaa, 3); @@ -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) @@ -396,7 +432,7 @@ int CtdlIPCGotoRoom(CtdlIPC *ipc, const char *room, const char *passwd, } ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret); if (ret / 100 == 2) { - extract(rret[0]->RRname, cret, 0); + extract_token(rret[0]->RRname, cret, 0, '|', sizeof rret[0]->RRname); rret[0]->RRunread = extract_long(cret, 1); rret[0]->RRtotal = extract_long(cret, 2); rret[0]->RRinfoupdated = extract_int(cret, 3); @@ -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; } @@ -426,7 +465,7 @@ int CtdlIPCGetMessages(CtdlIPC *ipc, enum MessageList which, int whicharg, { "ALL", "OLD", "NEW", "LAST", "FIRST", "GT", "LT" }; char aaa[33]; char *bbb = NULL; - size_t bbbsize; + size_t bbb_len; if (!cret) return -2; if (!mret) return -2; @@ -440,7 +479,7 @@ int CtdlIPCGetMessages(CtdlIPC *ipc, enum MessageList which, int whicharg, sprintf(aaa, "MSGS %s|%d|%d", proto[which], whicharg, (mtemplate) ? 1 : 0); if (mtemplate) count = strlen(mtemplate); - ret = CtdlIPCGenericCommand(ipc, aaa, mtemplate, count, &bbb, &bbbsize, cret); + ret = CtdlIPCGenericCommand(ipc, aaa, mtemplate, count, &bbb, &bbb_len, cret); if (ret / 100 != 1) return ret; count = 0; @@ -448,7 +487,7 @@ int CtdlIPCGetMessages(CtdlIPC *ipc, enum MessageList which, int whicharg, if (!*mret) return -1; while (bbb && strlen(bbb)) { - extract_token(aaa, bbb, 0, '\n'); + extract_token(aaa, bbb, 0, '\n', sizeof aaa); remove_token(bbb, 0, '\n'); *mret = (unsigned long *)realloc(*mret, (size_t)((count + 2) * sizeof (unsigned long))); @@ -471,9 +510,10 @@ int CtdlIPCGetSingleMessage(CtdlIPC *ipc, long msgnum, int headers, int as_mime, register int ret; char aaa[SIZ]; char *bbb = NULL; - size_t bbbsize; + size_t bbb_len; int multipart_hunting = 0; - char multipart_prefix[SIZ]; + char multipart_prefix[128]; + char encoding[256]; if (!cret) return -1; if (!mret) return -1; @@ -481,14 +521,15 @@ 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, &bbbsize, cret); + ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, &bbb, &bbb_len, cret); if (ret / 100 == 1) { if (as_mime != 2) { strcpy(mret[0]->mime_chosen, "1"); /* Default chosen-part is "1" */ while (strlen(bbb) > 4 && bbb[4] == '=') { - extract_token(aaa, bbb, 0, '\n'); + extract_token(aaa, bbb, 0, '\n', sizeof aaa); remove_token(bbb, 0, '\n'); if (!strncasecmp(aaa, "nhdr=yes", 8)) @@ -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]); @@ -518,14 +561,14 @@ int CtdlIPCGetSingleMessage(CtdlIPC *ipc, long msgnum, int headers, int as_mime, * us to determine which part we want to download. */ else if (!strncasecmp(aaa, "pref=", 5)) { - extract(multipart_prefix, &aaa[5], 1); + extract_token(multipart_prefix, &aaa[5], 1, '|', sizeof multipart_prefix); if (!strcasecmp(multipart_prefix, "multipart/alternative")) { ++multipart_hunting; } } else if (!strncasecmp(aaa, "suff=", 5)) { - extract(multipart_prefix, &aaa[5], 1); + extract_token(multipart_prefix, &aaa[5], 1, '|', sizeof multipart_prefix); if (!strcasecmp(multipart_prefix, "multipart/alternative")) { ++multipart_hunting; @@ -539,11 +582,11 @@ int CtdlIPCGetSingleMessage(CtdlIPC *ipc, long msgnum, int headers, int as_mime, if (ptr) { /* Fill the buffers for the caller */ - extract(ptr->name, &aaa[5], 0); - extract(ptr->filename, &aaa[5], 1); - extract(ptr->number, &aaa[5], 2); - extract(ptr->disposition, &aaa[5], 3); - extract(ptr->mimetype, &aaa[5], 4); + extract_token(ptr->name, &aaa[5], 0, '|', sizeof ptr->name); + extract_token(ptr->filename, &aaa[5], 1, '|', sizeof ptr->filename); + extract_token(ptr->number, &aaa[5], 2, '|', sizeof ptr->number); + extract_token(ptr->disposition, &aaa[5], 3, '|', sizeof ptr->disposition); + extract_token(ptr->mimetype, &aaa[5], 4, '|', sizeof ptr->mimetype); ptr->length = extract_long(&aaa[5], 5); if (!mret[0]->attachments) mret[0]->attachments = ptr; @@ -574,11 +617,29 @@ 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)) { - extract_token(mret[0]->content_type, bbb, 0, '\n'); - strcpy(mret[0]->content_type, - &mret[0]->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[13]); striplt(mret[0]->content_type); + + /* strip out ";charset=" portion. FIXME do something with + * the charset (like... convert it) instead of just throwing + * it away + */ + if (strstr(mret[0]->content_type, ";") != NULL) { + strcpy(strstr(mret[0]->content_type, ";"), ""); + } + + } + 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')); @@ -588,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'; @@ -630,7 +708,7 @@ int CtdlIPCServerInfo(CtdlIPC *ipc, char *cret) int line = 0; while (*listing && strlen(listing)) { - extract_token(buf, listing, 0, '\n'); + extract_token(buf, listing, 0, '\n', sizeof buf); remove_token(listing, 0, '\n'); switch (line++) { case 0: ipc->ServInfo.pid = atoi(buf); @@ -645,7 +723,7 @@ int CtdlIPCServerInfo(CtdlIPC *ipc, char *cret) break; case 5: ipc->ServInfo.rev_level = atoi(buf); break; - case 6: strcpy(ipc->ServInfo.bbs_city,buf); + case 6: strcpy(ipc->ServInfo.site_location,buf); break; case 7: strcpy(ipc->ServInfo.sysadm,buf); break; @@ -659,10 +737,27 @@ int CtdlIPCServerInfo(CtdlIPC *ipc, char *cret) break; case 14: ipc->ServInfo.supports_ldap = atoi(buf); 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; } @@ -752,9 +847,9 @@ int CtdlIPCGetRoomAttributes(CtdlIPC *ipc, struct ctdlroom **qret, char *cret) ret = CtdlIPCGenericCommand(ipc, "GETR", NULL, 0, NULL, NULL, cret); if (ret / 100 == 2) { - extract(qret[0]->QRname, cret, 0); - extract(qret[0]->QRpasswd, cret, 1); - extract(qret[0]->QRdirname, cret, 2); + extract_token(qret[0]->QRname, cret, 0, '|', sizeof qret[0]->QRname); + extract_token(qret[0]->QRpasswd, cret, 1, '|', sizeof qret[0]->QRpasswd); + extract_token(qret[0]->QRdirname, cret, 2, '|', sizeof qret[0]->QRdirname); qret[0]->QRflags = extract_int(cret, 3); qret[0]->QRfloor = extract_int(cret, 4); qret[0]->QRorder = extract_int(cret, 5); @@ -818,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; } @@ -1021,15 +1131,23 @@ int CtdlIPCSetRoomInfo(CtdlIPC *ipc, int for_real, const char *info, char *cret) /* LIST */ -int CtdlIPCUserListing(CtdlIPC *ipc, char **listing, char *cret) +int CtdlIPCUserListing(CtdlIPC *ipc, char *searchstring, char **listing, char *cret) { size_t bytes; + char *cmd; + int ret; if (!cret) return -1; if (!listing) return -1; if (*listing) return -1; + if (!searchstring) return -1; + + cmd = malloc(strlen(searchstring) + 10); + sprintf(cmd, "LIST %s", searchstring); - return CtdlIPCGenericCommand(ipc, "LIST", NULL, 0, listing, &bytes, cret); + ret = CtdlIPCGenericCommand(ipc, cmd, NULL, 0, listing, &bytes, cret); + free(cmd); + return(ret); } @@ -1101,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) { @@ -1168,7 +1266,7 @@ int CtdlIPCFileDownload(CtdlIPC *ipc, const char *filename, void **buf, ipc->downloading = 1; bytes = extract_long(cret, 0); last_mod = extract_int(cret, 1); - extract(mimetype, cret, 2); + extract_token(mimetype, cret, 2, '|', sizeof mimetype); ret = CtdlIPCReadDownload(ipc, buf, bytes, resume, progress_gauge_callback, cret); @@ -1213,8 +1311,8 @@ int CtdlIPCAttachmentDownload(CtdlIPC *ipc, long msgnum, const char *part, ipc->downloading = 1; bytes = extract_long(cret, 0); last_mod = extract_int(cret, 1); - extract(filename, cret, 2); - extract(mimetype, cret, 3); + extract_token(filename, cret, 2, '|', sizeof filename); + extract_token(mimetype, cret, 3, '|', sizeof mimetype); /* ret = CtdlIPCReadDownload(ipc, buf, bytes, 0, progress_gauge_callback, cret); */ ret = CtdlIPCHighSpeedReadDownload(ipc, buf, bytes, 0, progress_gauge_callback, cret); ret = CtdlIPCEndDownload(ipc, cret); @@ -1254,7 +1352,7 @@ int CtdlIPCImageDownload(CtdlIPC *ipc, const char *filename, void **buf, ipc->downloading = 1; bytes = extract_long(cret, 0); last_mod = extract_int(cret, 1); - extract(mimetype, cret, 2); + extract_token(mimetype, cret, 2, '|', sizeof mimetype); /* ret = CtdlIPCReadDownload(ipc, buf, bytes, 0, progress_gauge_callback, cret); */ ret = CtdlIPCHighSpeedReadDownload(ipc, buf, bytes, 0, progress_gauge_callback, cret); ret = CtdlIPCEndDownload(ipc, cret); @@ -1267,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; @@ -1283,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; } @@ -1307,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; @@ -1318,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; } @@ -1694,8 +1818,8 @@ int CtdlIPCAideGetUserParameters(CtdlIPC *ipc, const char *who, ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret); if (ret / 100 == 2) { - extract(uret[0]->fullname, cret, 0); - extract(uret[0]->password, cret, 1); + extract_token(uret[0]->fullname, cret, 0, '|', sizeof uret[0]->fullname); + extract_token(uret[0]->password, cret, 1, '|', sizeof uret[0]->password); uret[0]->flags = extract_int(cret, 2); uret[0]->timescalled = extract_long(cret, 3); uret[0]->posted = extract_long(cret, 4); @@ -1737,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; @@ -1746,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; - } @@ -1807,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; @@ -1818,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; } @@ -1827,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; @@ -1836,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; } @@ -1914,8 +2043,8 @@ int CtdlIPCStartEncryption(CtdlIPC *ipc, char *cret) SSL_set_session_id_context(temp_ssl, "Citadel SID", 14); #endif - if (!access("/var/run/egd-pool", F_OK)) - RAND_egd("/var/run/egd-pool"); + if (!access(EGD_POOL, F_OK)) + RAND_egd(EGD_POOL); if (!RAND_status()) { error_printf("PRNG not properly seeded\n"); @@ -1989,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; @@ -1998,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; } @@ -2280,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) @@ -2290,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); @@ -2335,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); } @@ -2594,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; @@ -2644,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); @@ -2702,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; @@ -2782,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) { @@ -2800,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; @@ -2820,13 +3127,17 @@ 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) { - return CtdlIPC_getline(ipc, buf); + CtdlIPC_getline(ipc, buf); } /* @@ -2856,7 +3167,7 @@ static void CtdlIPC_putline(CtdlIPC *ipc, const char *buf) void CtdlIPC_chat_send(CtdlIPC* ipc, const char* buf) { - return CtdlIPC_putline(ipc, buf); + CtdlIPC_putline(ipc, buf); } @@ -2888,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 */ @@ -2923,12 +3237,10 @@ 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)) { - snprintf(sockpath, sizeof sockpath, "%s%s", - BBSDIR, "/citadel.socket"); + snprintf(sockpath, sizeof sockpath, file_citadel_socket); } else { - snprintf(sockpath, sizeof sockpath, "%s%s", - citport, "/citadel.socket"); + snprintf(sockpath, sizeof sockpath, "%s/%s", citport, "citadel.socket"); } ipc->sock = uds_connectsock(&(ipc->isLocal), sockpath); if (ipc->sock == -1) { @@ -2967,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); }