X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fcitadel_ipc.c;h=ef902281dd69ae44310bc98799eb5de28abae09a;hb=4eb74b26380dfde31c86c685f0589e0c653aebf0;hp=56c3190c73a13a735544db6e88a64cd8efc463b8;hpb=8e88eb3a2e2bc2a6380b46fa05e3b3d01d88c4fb;p=citadel.git diff --git a/citadel/citadel_ipc.c b/citadel/citadel_ipc.c index 56c3190c7..ef902281d 100644 --- a/citadel/citadel_ipc.c +++ b/citadel/citadel_ipc.c @@ -1,8 +1,21 @@ -/* $Id$ */ - -#define UDS "_UDS_" -#define DEFAULT_HOST UDS -#define DEFAULT_PORT "citadel" +/* $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 @@ -33,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 @@ -67,7 +80,7 @@ void CtdlIPC_SetNetworkStatusCallback(CtdlIPC *ipc, void (*hook)(int state)) { } -char express_msgs = 0; +char instant_msgs = 0; static void serv_read(CtdlIPC *ipc, char *buf, unsigned int bytes); @@ -75,14 +88,18 @@ 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); #endif /* THREADED_CLIENT */ #endif /* HAVE_OPENSSL */ +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. */ @@ -122,26 +139,36 @@ int CtdlIPCEcho(CtdlIPC *ipc, const char *arg, char *cret) */ int CtdlIPCQuit(CtdlIPC *ipc) { - register int ret; - char aaa[128]; + register int ret = 221; /* Default to successful quit */ + char aaa[SIZ]; CtdlIPC_lock(ipc); - CtdlIPC_putline(ipc, "QUIT"); - CtdlIPC_getline(ipc, aaa); - ret = atoi(aaa); + if (ipc->sock > -1) { + CtdlIPC_putline(ipc, "QUIT"); + CtdlIPC_getline(ipc, aaa); + ret = atoi(aaa); + } +#ifdef HAVE_OPENSSL + if (ipc->ssl) + SSL_shutdown(ipc->ssl); + ipc->ssl = NULL; +#endif + if (ipc->sock) + shutdown(ipc->sock, 2); /* Close connection; we're dead */ + ipc->sock = -1; CtdlIPC_unlock(ipc); return ret; } /* - * 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"); @@ -277,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 */ @@ -286,23 +313,25 @@ 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); + mptr->march_flags2 = (unsigned int) extract_int(aaa, 4); + mptr->march_access = (char) extract_int(aaa, 5); if (march == NULL) march = mptr; else { @@ -317,19 +346,20 @@ int CtdlIPCKnownRooms(CtdlIPC *ipc, enum RoomList which, int floor, struct march } } *listing = march; + if (bbb) free(bbb); return ret; } /* GETU */ -/* Caller must free the struct usersupp; caller may pass an existing one */ -int CtdlIPCGetConfig(CtdlIPC *ipc, struct usersupp **uret, char *cret) +/* Caller must free the struct ctdluser; caller may pass an existing one */ +int CtdlIPCGetConfig(CtdlIPC *ipc, struct ctdluser **uret, char *cret) { register int ret; if (!cret) return -2; if (!uret) return -2; - if (!*uret) *uret = (struct usersupp *)calloc(1, sizeof (struct usersupp)); + if (!*uret) *uret = (struct ctdluser *)calloc(1, sizeof (struct ctdluser)); if (!*uret) return -1; ret = CtdlIPCGenericCommand(ipc, "GETU", NULL, 0, NULL, NULL, cret); @@ -343,7 +373,7 @@ int CtdlIPCGetConfig(CtdlIPC *ipc, struct usersupp **uret, char *cret) /* SETU */ -int CtdlIPCSetConfig(CtdlIPC *ipc, struct usersupp *uret, char *cret) +int CtdlIPCSetConfig(CtdlIPC *ipc, struct ctdluser *uret, char *cret) { char aaa[48]; @@ -357,6 +387,22 @@ int CtdlIPCSetConfig(CtdlIPC *ipc, struct usersupp *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) @@ -386,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); @@ -397,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; } @@ -416,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; @@ -430,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; @@ -438,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))); @@ -461,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; @@ -471,36 +521,39 @@ 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)) mret[0]->nhdr = 1; else if (!strncasecmp(aaa, "from=", 5)) - strcpy(mret[0]->author, &aaa[5]); + safestrncpy(mret[0]->author, &aaa[5], SIZ); else if (!strncasecmp(aaa, "type=", 5)) mret[0]->type = atoi(&aaa[5]); else if (!strncasecmp(aaa, "msgn=", 5)) - strcpy(mret[0]->msgid, &aaa[5]); + safestrncpy(mret[0]->msgid, &aaa[5], SIZ); else if (!strncasecmp(aaa, "subj=", 5)) - strcpy(mret[0]->subject, &aaa[5]); + safestrncpy(mret[0]->subject, &aaa[5], SIZ); else if (!strncasecmp(aaa, "rfca=", 5)) - strcpy(mret[0]->email, &aaa[5]); + safestrncpy(mret[0]->email, &aaa[5], SIZ); else if (!strncasecmp(aaa, "hnod=", 5)) - strcpy(mret[0]->hnod, &aaa[5]); + safestrncpy(mret[0]->hnod, &aaa[5], SIZ); else if (!strncasecmp(aaa, "room=", 5)) - strcpy(mret[0]->room, &aaa[5]); + safestrncpy(mret[0]->room, &aaa[5], SIZ); else if (!strncasecmp(aaa, "node=", 5)) - strcpy(mret[0]->node, &aaa[5]); + safestrncpy(mret[0]->node, &aaa[5], SIZ); else if (!strncasecmp(aaa, "rcpt=", 5)) - strcpy(mret[0]->recipient, &aaa[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]); @@ -508,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; @@ -529,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; @@ -564,22 +617,57 @@ 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')); - /*ooga*/ remove_token(bbb, 0, '\n'); + remove_token(bbb, 0, '\n'); } } 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'; @@ -606,7 +694,7 @@ int CtdlIPCWhoKnowsRoom(CtdlIPC *ipc, char **listing, char *cret) /* INFO */ -int CtdlIPCServerInfo(CtdlIPC *ipc, struct CtdlServInfo *ServInfo, char *cret) +int CtdlIPCServerInfo(CtdlIPC *ipc, char *cret) { register int ret; size_t bytes; @@ -614,44 +702,62 @@ int CtdlIPCServerInfo(CtdlIPC *ipc, struct CtdlServInfo *ServInfo, char *cret) char buf[SIZ]; if (!cret) return -2; - if (!ServInfo) return -2; ret = CtdlIPCGenericCommand(ipc, "INFO", NULL, 0, &listing, &bytes, cret); if (ret / 100 == 1) { 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: ServInfo->serv_pid = atoi(buf); + case 0: ipc->ServInfo.pid = atoi(buf); + break; + case 1: strcpy(ipc->ServInfo.nodename,buf); + break; + case 2: strcpy(ipc->ServInfo.humannode,buf); + break; + case 3: strcpy(ipc->ServInfo.fqdn,buf); + break; + case 4: strcpy(ipc->ServInfo.software,buf); break; - case 1: strcpy(ServInfo->serv_nodename,buf); + case 5: ipc->ServInfo.rev_level = atoi(buf); break; - case 2: strcpy(ServInfo->serv_humannode,buf); + case 6: strcpy(ipc->ServInfo.site_location,buf); break; - case 3: strcpy(ServInfo->serv_fqdn,buf); + case 7: strcpy(ipc->ServInfo.sysadm,buf); break; - case 4: strcpy(ServInfo->serv_software,buf); + case 9: strcpy(ipc->ServInfo.moreprompt,buf); break; - case 5: ServInfo->serv_rev_level = atoi(buf); + case 10: ipc->ServInfo.ok_floors = atoi(buf); break; - case 6: strcpy(ServInfo->serv_bbs_city,buf); + case 11: ipc->ServInfo.paging_level = atoi(buf); break; - case 7: strcpy(ServInfo->serv_sysadm,buf); + case 13: ipc->ServInfo.supports_qnop = atoi(buf); break; - case 9: strcpy(ServInfo->serv_moreprompt,buf); + case 14: ipc->ServInfo.supports_ldap = atoi(buf); break; - case 10: ServInfo->serv_ok_floors = atoi(buf); + case 15: ipc->ServInfo.newuser_disabled = atoi(buf); break; - case 11: ServInfo->serv_paging_level = atoi(buf); + case 16: strcpy(ipc->ServInfo.default_cal_zone, buf); break; - case 13: ServInfo->serv_supports_qnop = atoi(buf); + 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; } @@ -730,20 +836,20 @@ int CtdlIPCKickoutUserFromRoom(CtdlIPC *ipc, const char *username, char *cret) /* GETR */ -int CtdlIPCGetRoomAttributes(CtdlIPC *ipc, struct quickroom **qret, char *cret) +int CtdlIPCGetRoomAttributes(CtdlIPC *ipc, struct ctdlroom **qret, char *cret) { register int ret; if (!cret) return -2; if (!qret) return -2; - if (!*qret) *qret = (struct quickroom *)calloc(1, sizeof (struct quickroom)); + if (!*qret) *qret = (struct ctdlroom *)calloc(1, sizeof (struct ctdlroom)); if (!*qret) return -1; 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); @@ -756,7 +862,7 @@ int CtdlIPCGetRoomAttributes(CtdlIPC *ipc, struct quickroom **qret, char *cret) /* SETR */ /* set forget to kick all users out of room */ -int CtdlIPCSetRoomAttributes(CtdlIPC *ipc, int forget, struct quickroom *qret, char *cret) +int CtdlIPCSetRoomAttributes(CtdlIPC *ipc, int forget, struct ctdlroom *qret, char *cret) { register int ret; char *aaa; @@ -765,12 +871,13 @@ int CtdlIPCSetRoomAttributes(CtdlIPC *ipc, int forget, struct quickroom *qret, c if (!qret) return -2; aaa = (char *)malloc(strlen(qret->QRname) + strlen(qret->QRpasswd) + - strlen(qret->QRdirname) + 52); + strlen(qret->QRdirname) + 64); if (!aaa) return -1; - sprintf(aaa, "SETR %s|%s|%s|%d|%d|%d|%d", + sprintf(aaa, "SETR %s|%s|%s|%d|%d|%d|%d|%d|%d", qret->QRname, qret->QRpasswd, qret->QRdirname, - qret->QRflags, forget, qret->QRfloor, qret->QRorder); + qret->QRflags, forget, qret->QRfloor, qret->QRorder, + qret->QRdefaultview, qret->QRflags2); ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret); free(aaa); return ret; @@ -806,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; } @@ -1009,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); } @@ -1089,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) { @@ -1130,7 +1240,8 @@ int CtdlIPCOnlineUsers(CtdlIPC *ipc, char **listing, time_t *stamp, char *cret) /* OPEN */ int CtdlIPCFileDownload(CtdlIPC *ipc, const char *filename, void **buf, size_t resume, - void (*progress_gauge_callback)(unsigned long, unsigned long), + void (*progress_gauge_callback) + (CtdlIPC*, unsigned long, unsigned long), char *cret) { register int ret; @@ -1155,9 +1266,15 @@ 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); -/* ret = CtdlIPCReadDownload(ipc, buf, bytes, resume, progress_gauge_callback, cret); */ - ret = CtdlIPCHighSpeedReadDownload(ipc, buf, bytes, resume, progress_gauge_callback, cret); + extract_token(mimetype, cret, 2, '|', sizeof mimetype); + + ret = CtdlIPCReadDownload(ipc, buf, bytes, resume, + progress_gauge_callback, cret); + /* + ret = CtdlIPCHighSpeedReadDownload(ipc, buf, bytes, resume, + progress_gauge_callback, cret); + */ + ret = CtdlIPCEndDownload(ipc, cret); if (ret / 100 == 2) sprintf(cret, "%d|%ld|%s|%s", (int)bytes, last_mod, @@ -1170,7 +1287,8 @@ int CtdlIPCFileDownload(CtdlIPC *ipc, const char *filename, void **buf, /* OPNA */ int CtdlIPCAttachmentDownload(CtdlIPC *ipc, long msgnum, const char *part, void **buf, - void (*progress_gauge_callback)(unsigned long, unsigned long), + void (*progress_gauge_callback) + (CtdlIPC*, unsigned long, unsigned long), char *cret) { register int ret; @@ -1178,7 +1296,7 @@ int CtdlIPCAttachmentDownload(CtdlIPC *ipc, long msgnum, const char *part, time_t last_mod; char filename[SIZ]; char mimetype[SIZ]; - char *aaa; + char aaa[SIZ]; if (!cret) return -2; if (!buf) return -2; @@ -1187,18 +1305,15 @@ int CtdlIPCAttachmentDownload(CtdlIPC *ipc, long msgnum, const char *part, if (!msgnum) return -2; if (ipc->downloading) return -2; - aaa = (char *)malloc(strlen(part) + 17); - if (!aaa) return -1; - sprintf(aaa, "OPNA %ld|%s", msgnum, part); ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret); - free(aaa); if (ret / 100 == 2) { ipc->downloading = 1; bytes = extract_long(cret, 0); last_mod = extract_int(cret, 1); - extract(mimetype, cret, 2); -/* ret = CtdlIPCReadDownload(ipc, buf, bytes, 0, progress_gauge_callback, cret); */ + 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); if (ret / 100 == 2) @@ -1211,7 +1326,8 @@ int CtdlIPCAttachmentDownload(CtdlIPC *ipc, long msgnum, const char *part, /* OIMG */ int CtdlIPCImageDownload(CtdlIPC *ipc, const char *filename, void **buf, - void (*progress_gauge_callback)(unsigned long, unsigned long), + void (*progress_gauge_callback) + (CtdlIPC*, unsigned long, unsigned long), char *cret) { register int ret; @@ -1236,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); @@ -1249,13 +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, - void (*progress_gauge_callback)(unsigned long, unsigned long), +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; @@ -1264,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; } @@ -1283,11 +1413,16 @@ int CtdlIPCFileUpload(CtdlIPC *ipc, const char *save_as, const char *comment, /* UIMG */ int CtdlIPCImageUpload(CtdlIPC *ipc, int for_real, const char *path, const char *save_as, - void (*progress_gauge_callback)(unsigned long, unsigned long), + void (*progress_gauge_callback) + (CtdlIPC*, unsigned long, unsigned long), 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; @@ -1298,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; } @@ -1347,18 +1491,13 @@ int CtdlIPCFloorListing(CtdlIPC *ipc, char **listing, char *cret) int CtdlIPCCreateFloor(CtdlIPC *ipc, int for_real, const char *name, char *cret) { register int ret; - char *aaa; + char aaa[SIZ]; if (!cret) return -2; if (!name) return -2; - if (!*name) return -2; - - aaa = (char *)malloc(strlen(name) + 17); - if (!aaa) return -1; sprintf(aaa, "CFLR %s|%d", name, for_real); ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret); - free(aaa); return ret; } @@ -1366,7 +1505,7 @@ int CtdlIPCCreateFloor(CtdlIPC *ipc, int for_real, const char *name, char *cret) /* KFLR */ int CtdlIPCDeleteFloor(CtdlIPC *ipc, int for_real, int floornum, char *cret) { - char aaa[27]; + char aaa[SIZ]; if (!cret) return -1; if (floornum < 0) return -1; @@ -1380,18 +1519,14 @@ int CtdlIPCDeleteFloor(CtdlIPC *ipc, int for_real, int floornum, char *cret) int CtdlIPCEditFloor(CtdlIPC *ipc, int floornum, const char *floorname, char *cret) { register int ret; - char *aaa; + char aaa[SIZ]; if (!cret) return -2; if (!floorname) return -2; if (floornum < 0) return -2; - aaa = (char *)malloc(strlen(floorname) + 17); - if (!aaa) return -1; - sprintf(aaa, "EFLR %d|%s", floornum, floorname); ret = CtdlIPCGenericCommand(ipc, aaa, NULL, 0, NULL, NULL, cret); - free(aaa); return ret; } @@ -1414,7 +1549,7 @@ int CtdlIPCIdentifySoftware(CtdlIPC *ipc, int developerid, int clientid, developerid = 8; clientid = 0; revision = REV_LEVEL - 600; - software_name = "Citadel/UX (libcitadel)"; + software_name = "Citadel (libcitadel)"; } if (!hostname) return -2; @@ -1669,22 +1804,22 @@ time_t CtdlIPCServerTime(CtdlIPC *ipc, char *cret) /* AGUP */ int CtdlIPCAideGetUserParameters(CtdlIPC *ipc, const char *who, - struct usersupp **uret, char *cret) + struct ctdluser **uret, char *cret) { register int ret; char aaa[SIZ]; if (!cret) return -2; if (!uret) return -2; - if (!*uret) *uret = (struct usersupp *)calloc(1, sizeof(struct usersupp)); + if (!*uret) *uret = (struct ctdluser *)calloc(1, sizeof(struct ctdluser)); if (!*uret) return -1; sprintf(aaa, "AGUP %s", 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); @@ -1698,7 +1833,7 @@ int CtdlIPCAideGetUserParameters(CtdlIPC *ipc, const char *who, /* ASUP */ -int CtdlIPCAideSetUserParameters(CtdlIPC *ipc, const struct usersupp *uret, char *cret) +int CtdlIPCAideSetUserParameters(CtdlIPC *ipc, const struct ctdluser *uret, char *cret) { register int ret; char *aaa; @@ -1720,43 +1855,42 @@ int CtdlIPCAideSetUserParameters(CtdlIPC *ipc, const struct usersupp *uret, char /* GPEX */ -/* which is 0 = room, 1 = floor, 2 = site */ +/* which is 0 = room, 1 = floor, 2 = site, 3 = default for mailboxes */ /* caller must free the struct ExpirePolicy */ int CtdlIPCGetMessageExpirationPolicy(CtdlIPC *ipc, int which, struct ExpirePolicy **policy, char *cret) { - static char *proto[] = {"room", "floor", "site"}; - char aaa[11]; + static char *proto[] = {"room", "floor", "site", "mailboxes" }; + char cmd[256]; register int ret; if (!cret) return -2; if (!policy) return -2; if (!*policy) *policy = (struct ExpirePolicy *)calloc(1, sizeof(struct ExpirePolicy)); if (!*policy) return -1; - if (which < 0 || which > 2) return -2; + 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; - } /* SPEX */ -/* which is 0 = room, 1 = floor, 2 = site */ +/* which is 0 = room, 1 = floor, 2 = site, 3 = default for mailboxes */ /* policy is 0 = inherit, 1 = no purge, 2 = by count, 3 = by age (days) */ int CtdlIPCSetMessageExpirationPolicy(CtdlIPC *ipc, int which, struct ExpirePolicy *policy, char *cret) { char aaa[38]; - char *whichvals[] = { "room", "floor", "site" }; + char *whichvals[] = { "room", "floor", "site", "mailboxes" }; if (!cret) return -2; - if (which < 0 || which > 2) return -2; + if (which < 0 || which > 3) return -2; if (!policy) return -2; if (policy->expire_mode < 0 || policy->expire_mode > 3) return -2; if (policy->expire_mode >= 2 && policy->expire_value < 1) return -2; @@ -1796,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; @@ -1807,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; } @@ -1816,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; @@ -1825,7 +1963,34 @@ 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; +} + + +/* GNET */ +int CtdlIPCGetRoomNetworkConfig(CtdlIPC *ipc, char **listing, char *cret) +{ + size_t bytes; + + if (!cret) return -2; + if (!listing) return -2; + if (*listing) return -2; + + return CtdlIPCGenericCommand(ipc, "GNET", NULL, 0, + listing, &bytes, cret); +} + + +/* SNET */ +int CtdlIPCSetRoomNetworkConfig(CtdlIPC *ipc, const char *listing, char *cret) +{ + if (!cret) return -2; + if (!listing) return -2; + + return CtdlIPCGenericCommand(ipc, "SNET", listing, strlen(listing), NULL, NULL, cret); } @@ -1875,11 +2040,11 @@ int CtdlIPCStartEncryption(CtdlIPC *ipc, char *cret) } /* Pointless flag waving */ #if SSLEAY_VERSION_NUMBER >= 0x0922 - SSL_set_session_id_context(temp_ssl, "Citadel/UX SID", 14); + 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"); @@ -1953,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; @@ -1962,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; } @@ -2012,7 +2180,7 @@ int CtdlIPCMessageBaseCheck(CtdlIPC *ipc, char **mret, char *cret) /* ************************************************************************** */ -inline void CtdlIPC_lock(CtdlIPC *ipc) +INLINE void CtdlIPC_lock(CtdlIPC *ipc) { if (ipc->network_status_cb) ipc->network_status_cb(1); #ifdef THREADED_CLIENT @@ -2021,7 +2189,7 @@ inline void CtdlIPC_lock(CtdlIPC *ipc) } -inline void CtdlIPC_unlock(CtdlIPC *ipc) +INLINE void CtdlIPC_unlock(CtdlIPC *ipc) { #ifdef THREADED_CLIENT pthread_mutex_unlock(&(ipc->mutex)); @@ -2092,7 +2260,6 @@ size_t CtdlIPCPartialRead(CtdlIPC *ipc, void **buf, size_t offset, size_t bytes, if (!buf) return 0; if (!cret) return 0; if (bytes < 1) return 0; - if (offset < 0) return 0; CtdlIPC_lock(ipc); sprintf(aaa, "READ %d|%d", (int)offset, (int)bytes); @@ -2105,7 +2272,7 @@ size_t CtdlIPCPartialRead(CtdlIPC *ipc, void **buf, size_t offset, size_t bytes, *buf = (void *)realloc(*buf, (size_t)(offset + len)); if (*buf) { /* I know what I'm doing */ - serv_read(ipc, (*buf + offset), len); + serv_read(ipc, ((char *)(*buf) + offset), len); } else { /* We have to read regardless */ serv_read(ipc, aaa, len); @@ -2146,7 +2313,8 @@ int CtdlIPCSpecifyPreferredFormats(CtdlIPC *ipc, char *cret, char *formats) { /* READ */ int CtdlIPCReadDownload(CtdlIPC *ipc, void **buf, size_t bytes, size_t resume, - void (*progress_gauge_callback)(unsigned long, unsigned long), + void (*progress_gauge_callback) + (CtdlIPC*, unsigned long, unsigned long), char *cret) { register size_t len; @@ -2158,7 +2326,7 @@ int CtdlIPCReadDownload(CtdlIPC *ipc, void **buf, size_t bytes, size_t resume, len = resume; if (progress_gauge_callback) - progress_gauge_callback(len, bytes); + progress_gauge_callback(ipc, len, bytes); while (len < bytes) { register size_t block; @@ -2169,16 +2337,16 @@ int CtdlIPCReadDownload(CtdlIPC *ipc, void **buf, size_t bytes, size_t resume, } len += block; if (progress_gauge_callback) - progress_gauge_callback(len, bytes); + progress_gauge_callback(ipc, len, bytes); } return len; } - /* READ - pipelined */ int CtdlIPCHighSpeedReadDownload(CtdlIPC *ipc, void **buf, size_t bytes, size_t resume, - void (*progress_gauge_callback)(unsigned long, unsigned long), + void (*progress_gauge_callback) + (CtdlIPC*, unsigned long, unsigned long), char *cret) { register size_t len; @@ -2197,7 +2365,7 @@ int CtdlIPCHighSpeedReadDownload(CtdlIPC *ipc, void **buf, size_t bytes, len = 0; CtdlIPC_lock(ipc); if (progress_gauge_callback) - progress_gauge_callback(len, bytes); + progress_gauge_callback(ipc, len, bytes); /* How many calls will be in the pipeline? */ calls = (bytes - resume) / 4096; @@ -2217,10 +2385,10 @@ int CtdlIPCHighSpeedReadDownload(CtdlIPC *ipc, void **buf, size_t bytes, else { len = extract_long(&aaa[4], 0); /* I know what I'm doing */ - serv_read(ipc, ((*buf) + (i * 4096)), len); + serv_read(ipc, ((char *)(*buf) + (i * 4096)), len); } if (progress_gauge_callback) - progress_gauge_callback(i * 4096 + len, bytes); + progress_gauge_callback(ipc, i * 4096 + len, bytes); } CtdlIPC_unlock(ipc); return len; @@ -2244,8 +2412,9 @@ int CtdlIPCEndUpload(CtdlIPC *ipc, int discard, char *cret) /* WRIT */ -int CtdlIPCWriteUpload(CtdlIPC *ipc, const char *path, - void (*progress_gauge_callback)(unsigned long, unsigned long), +int CtdlIPCWriteUpload(CtdlIPC *ipc, FILE *uploadFP, + void (*progress_gauge_callback) + (CtdlIPC*, unsigned long, unsigned long), char *cret) { register int ret = -1; @@ -2253,21 +2422,17 @@ 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); rewind(fd); if (progress_gauge_callback) - progress_gauge_callback(0, bytes); + progress_gauge_callback(ipc, 0, bytes); while (offset < bytes) { register size_t to_write; @@ -2288,7 +2453,7 @@ int CtdlIPCWriteUpload(CtdlIPC *ipc, const char *path, serv_write(ipc, buf, to_write); offset += to_write; if (progress_gauge_callback) - progress_gauge_callback(offset, bytes); + progress_gauge_callback(ipc, offset, bytes); /* Detect short reads and back up if needed */ /* offset will never be negative anyway */ fseek(fd, (signed)offset, SEEK_SET); @@ -2297,8 +2462,10 @@ int CtdlIPCWriteUpload(CtdlIPC *ipc, const char *path, } } if (progress_gauge_callback) - progress_gauge_callback(1, 1); - return (!ferror(fd) ? ret : -2); + progress_gauge_callback(ipc, 1, 1); + ferr = ferror(fd); + fclose(fd); + return (!ferr ? ret : -2); } @@ -2350,7 +2517,7 @@ int CtdlIPCGenericCommand(CtdlIPC *ipc, while (1) { CtdlIPC_getline(ipc, proto_response); if (proto_response[3] == '*') - express_msgs = 1; + instant_msgs = 1; ret = atoi(proto_response); strcpy(proto_response, &proto_response[4]); switch (ret / 100) { @@ -2498,6 +2665,7 @@ static int connectsock(char *host, char *service, char *protocol, int defaultPor } if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) { + close(s); return -1; } @@ -2519,6 +2687,7 @@ static int uds_connectsock(int *isLocal, char *sockpath) } if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + close(s); return -1; } @@ -2544,7 +2713,7 @@ static void serv_read(CtdlIPC *ipc, char *buf, unsigned int bytes) while (len < bytes) { rlen = read(ipc->sock, &buf[len], bytes - len); if (rlen < 1) { - connection_died(ipc); + connection_died(ipc, 0); return; } len += rlen; @@ -2555,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; @@ -2570,7 +2739,7 @@ static void serv_write(CtdlIPC *ipc, const char *buf, unsigned int nbytes) retval = write(ipc->sock, &buf[bytes_written], nbytes - bytes_written); if (retval < 1) { - connection_died(ipc); + connection_died(ipc, 0); return; } bytes_written += retval; @@ -2605,14 +2774,20 @@ 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:\n"); - ERR_print_errors_fp(stderr); - connection_died(NULL); + ***/ + error_printf("SSL_read in serv_read: %s\n", + ERR_reason_error_string(ERR_peek_error())); + connection_died(ipc, 1); return; } len += rlen; @@ -2653,9 +2828,9 @@ static void serv_write_ssl(CtdlIPC *ipc, const char *buf, unsigned int nbytes) nbytes - bytes_written); return; } - error_printf("SSL_write in serv_write:\n"); - ERR_print_errors_fp(stderr); - connection_died(NULL); + error_printf("SSL_write in serv_write: %s\n", + ERR_reason_error_string(ERR_peek_error())); + connection_died(ipc, 1); return; } bytes_written += retval; @@ -2663,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; @@ -2675,6 +2861,7 @@ static void CtdlIPC_init_OpenSSL(void) } /* Get started */ + a = 0; ssl_ctx = NULL; dh = NULL; SSL_load_error_strings(); @@ -2742,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) { @@ -2760,10 +2938,179 @@ 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() */ -void CtdlIPC_getline(CtdlIPC* ipc, char *buf) +#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; @@ -2779,24 +3126,50 @@ void CtdlIPC_getline(CtdlIPC* ipc, char *buf) while (buf[i] != '\n') serv_read(ipc, &buf[i], 1); - /* Strip the trailing newline. - */ - buf[i] = 0; + /* 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; } +#endif /* CHUNKED_READ */ + + +void CtdlIPC_chat_recv(CtdlIPC* ipc, char* buf) +{ + CtdlIPC_getline(ipc, buf); +} + /* * send line to server - implemented in terms of serv_write() */ -void CtdlIPC_putline(CtdlIPC *ipc, const char *buf) +static void CtdlIPC_putline(CtdlIPC *ipc, const char *buf) { - /* error_printf("< %s\n", buf); */ - serv_write(ipc, buf, strlen(buf)); - serv_write(ipc, "\n", 1); + char *cmd = NULL; + int len; + + len = strlen(buf); + cmd = malloc(len + 2); + if (!cmd) { + /* This requires no extra memory */ + serv_write(ipc, buf, len); + serv_write(ipc, "\n", 1); + } else { + /* This is network-optimized */ + strncpy(cmd, buf, len); + strcpy(cmd + len, "\n"); + serv_write(ipc, cmd, len + 1); + free(cmd); + } ipc->last_command_sent = time(NULL); } +void CtdlIPC_chat_send(CtdlIPC* ipc, const char* buf) +{ + CtdlIPC_putline(ipc, buf); +} + /* * attach to server @@ -2807,8 +3180,9 @@ CtdlIPC* CtdlIPC_new(int argc, char **argv, char *hostbuf, char *portbuf) char cithost[SIZ]; char citport[SIZ]; char sockpath[SIZ]; + CtdlIPC* ipc; - CtdlIPC *ipc = ialloc(CtdlIPC); + ipc = ialloc(CtdlIPC); if (!ipc) { return 0; } @@ -2825,10 +3199,20 @@ 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 */ + /* Allow caller to supply our values (Windows) */ + if (hostbuf && strlen(hostbuf) > 0) + strcpy(cithost, hostbuf); + if (portbuf && strlen(portbuf) > 0) + strcpy(citport, portbuf); + + /* Read host/port from command line if present */ for (a = 0; a < argc; ++a) { if (a == 0) { /* do nothing */ @@ -2852,7 +3236,12 @@ 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)) { - snprintf(sockpath, sizeof sockpath, BBSDIR "/citadel.socket"); + if (!strcasecmp(citport, DEFAULT_PORT)) { + snprintf(sockpath, sizeof sockpath, file_citadel_socket); + } + else { + snprintf(sockpath, sizeof sockpath, "%s/%s", citport, "citadel.socket"); + } ipc->sock = uds_connectsock(&(ipc->isLocal), sockpath); if (ipc->sock == -1) { ifree(ipc); @@ -2873,6 +3262,42 @@ CtdlIPC* CtdlIPC_new(int argc, char **argv, char *hostbuf, char *portbuf) return ipc; } + +/* + * Disconnect and delete the IPC class (destructor) + */ +void CtdlIPC_delete(CtdlIPC* ipc) +{ +#ifdef HAVE_OPENSSL + if (ipc->ssl) { + SSL_shutdown(ipc->ssl); + SSL_free(ipc->ssl); + ipc->ssl = NULL; + } +#endif + if (ipc->sock > -1) { + 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); +} + + +/* + * Disconnect and delete the IPC class (destructor) + * Also NULLs out the pointer + */ +void CtdlIPC_delete_ptr(CtdlIPC** pipc) +{ + CtdlIPC_delete(*pipc); + *pipc = NULL; +} + + /* * return the file descriptor of the server socket so we can select() on it. *