X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmsgbase.c;h=49f634595e8f4259a18034e36247632aa6a7a064;hb=c4609169aa7baf208848e72c16d33a3f892353b8;hp=776680b6df7cd5dd04f16bd04979fe23cf07cff6;hpb=4e9952daf6d736348f34fa1e02f33a568d25d894;p=citadel.git diff --git a/citadel/msgbase.c b/citadel/msgbase.c index 776680b6d..49f634595 100644 --- a/citadel/msgbase.c +++ b/citadel/msgbase.c @@ -1,7 +1,7 @@ /* * Implements the message store. * - * Copyright (c) 1987-2012 by the citadel.org team + * Copyright (c) 1987-2015 by the citadel.org team * * This program is open source software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3. @@ -22,6 +22,7 @@ #include "ctdl_module.h" #include "citserver.h" #include "control.h" +#include "config.h" #include "clientsocket.h" #include "genstamp.h" #include "room_ops.h" @@ -737,7 +738,7 @@ int CtdlForEachMessage(int mode, long ref, char *search_string, free(msglist); return -1; } - msg = CtdlFetchMessage(msglist[a], 1); + msg = CtdlFetchMessage(msglist[a], 1, 1); if (msg != NULL) { if (CtdlMsgCmp(msg, compare)) { msglist[a] = 0L; @@ -1083,33 +1084,18 @@ void mime_spew_section(char *name, char *filename, char *partnum, char *disp, } } - -/* - * Load a message from disk into memory. - * This is used by CtdlOutputMsg() and other fetch functions. - * - * NOTE: Caller is responsible for freeing the returned CtdlMessage struct - * using the CtdlMessageFree() function. - */ -struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) +struct CtdlMessage *CtdlDeserializeMessage(long msgnum, int with_body, const char *Buffer, long Length) { struct CitContext *CCC = CC; - struct cdbdata *dmsgtext; struct CtdlMessage *ret = NULL; - char *mptr; - char *upper_bound; + const char *mptr; + const char *upper_bound; cit_uint8_t ch; cit_uint8_t field_header; eMsgField which; - MSG_syslog(LOG_DEBUG, "CtdlFetchMessage(%ld, %d)\n", msgnum, with_body); - dmsgtext = cdb_fetch(CDB_MSGMAIN, &msgnum, sizeof(long)); - if (dmsgtext == NULL) { - MSG_syslog(LOG_ERR, "CtdlFetchMessage(%ld, %d) Failed!\n", msgnum, with_body); - return NULL; - } - mptr = dmsgtext->ptr; - upper_bound = mptr + dmsgtext->len; + mptr = Buffer; + upper_bound = Buffer + Length; /* Parse the three bytes that begin EVERY message on disk. * The first is always 0xFF, the on-disk magic number. @@ -1119,7 +1105,6 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) ch = *mptr++; if (ch != 255) { MSG_syslog(LOG_ERR, "Message %ld appears to be corrupted.\n", msgnum); - cdb_free(dmsgtext); return NULL; } ret = (struct CtdlMessage *) malloc(sizeof(struct CtdlMessage)); @@ -1135,21 +1120,67 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) * have just processed the 'M' (message text) field. */ do { + field_header = '\0'; long len; + + /* work around possibly buggy messages: */ + while (field_header == '\0') + { + if (mptr >= upper_bound) { + break; + } + field_header = *mptr++; + } if (mptr >= upper_bound) { break; } - field_header = *mptr++; which = field_header; len = strlen(mptr); + CM_SetField(ret, which, mptr, len); mptr += len + 1; /* advance to next field */ } while ((mptr < upper_bound) && (field_header != 'M')); + return (ret); +} + + +/* + * Load a message from disk into memory. + * This is used by CtdlOutputMsg() and other fetch functions. + * + * NOTE: Caller is responsible for freeing the returned CtdlMessage struct + * using the CtdlMessageFree() function. + */ +struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body, int run_msg_hooks) +{ + struct CitContext *CCC = CC; + struct cdbdata *dmsgtext; + struct CtdlMessage *ret = NULL; + + MSG_syslog(LOG_DEBUG, "CtdlFetchMessage(%ld, %d)\n", msgnum, with_body); + dmsgtext = cdb_fetch(CDB_MSGMAIN, &msgnum, sizeof(long)); + if (dmsgtext == NULL) { + MSG_syslog(LOG_ERR, "CtdlFetchMessage(%ld, %d) Failed!\n", msgnum, with_body); + return NULL; + } + + if (dmsgtext->ptr[dmsgtext->len - 1] != '\0') + { + MSG_syslog(LOG_ERR, "CtdlFetchMessage(%ld, %d) Forcefully terminating message!!\n", msgnum, with_body); + dmsgtext->ptr[dmsgtext->len - 1] = '\0'; + } + + ret = CtdlDeserializeMessage(msgnum, with_body, dmsgtext->ptr, dmsgtext->len); + cdb_free(dmsgtext); + if (ret == NULL) { + return NULL; + } + /* Always make sure there's something in the msg text field. If * it's NULL, the message text is most likely stored separately, * so go ahead and fetch that. Failing that, just set a dummy @@ -1158,7 +1189,7 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) if ( (CM_IsEmpty(ret, eMesageText)) && (with_body) ) { dmsgtext = cdb_fetch(CDB_BIGMSGS, &msgnum, sizeof(long)); if (dmsgtext != NULL) { - CM_SetAsField(ret, eMesageText, &dmsgtext->ptr, dmsgtext->len); + CM_SetAsField(ret, eMesageText, &dmsgtext->ptr, dmsgtext->len - 1); cdb_free(dmsgtext); } } @@ -1167,7 +1198,7 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) } /* Perform "before read" hooks (aborting if any return nonzero) */ - if (PerformMessageHooks(ret, NULL, EVT_BEFOREREAD) > 0) { + if (run_msg_hooks && (PerformMessageHooks(ret, NULL, EVT_BEFOREREAD) > 0)) { CM_Free(ret); return NULL; } @@ -1504,14 +1535,15 @@ int check_cached_msglist(long msgnum) { * */ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ - int mode, /* how would you like that message? */ - int headers_only, /* eschew the message body? */ - int do_proto, /* do Citadel protocol responses? */ - int crlf, /* Use CRLF newlines instead of LF? */ - char *section, /* NULL or a message/rfc822 section */ - int flags, /* various flags; see msgbase.h */ - char **Author, - char **Address + int mode, /* how would you like that message? */ + int headers_only, /* eschew the message body? */ + int do_proto, /* do Citadel protocol responses? */ + int crlf, /* Use CRLF newlines instead of LF? */ + char *section, /* NULL or a message/rfc822 section */ + int flags, /* various flags; see msgbase.h */ + char **Author, + char **Address, + char **MessageID ) { struct CitContext *CCC = CC; struct CtdlMessage *TheMessage = NULL; @@ -1566,10 +1598,10 @@ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ * request that we don't even bother loading the body into memory. */ if (headers_only == HEADERS_FAST) { - TheMessage = CtdlFetchMessage(msg_num, 0); + TheMessage = CtdlFetchMessage(msg_num, 0, 1); } else { - TheMessage = CtdlFetchMessage(msg_num, 1); + TheMessage = CtdlFetchMessage(msg_num, 1, 1); } if (TheMessage == NULL) { @@ -1599,6 +1631,11 @@ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ long len; CM_GetAsField(TheMessage, erFc822Addr, Address, &len); } + if ((MessageID != NULL) && (*MessageID == NULL)) + { + long len; + CM_GetAsField(TheMessage, emessageId, MessageID, &len); + } CM_Free(TheMessage); TheMessage = NULL; @@ -1638,6 +1675,11 @@ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ long len; CM_GetAsField(TheMessage, erFc822Addr, Address, &len); } + if ((MessageID != NULL) && (*MessageID == NULL)) + { + long len; + CM_GetAsField(TheMessage, emessageId, MessageID, &len); + } CM_Free(TheMessage); @@ -1724,7 +1766,7 @@ void OutputCtdlMsgHeaders( void OutputRFC822MsgHeaders( struct CtdlMessage *TheMessage, int flags, /* should the bessage be exported clean */ - const char *nl, + const char *nl, int nlen, char *mid, long sizeof_mid, char *suser, long sizeof_suser, char *luser, long sizeof_luser, @@ -1739,28 +1781,28 @@ void OutputRFC822MsgHeaders( char *mpptr = NULL; char *hptr; - for (i = 0; i < 256; ++i) { - if (TheMessage->cm_fields[i]) { - mptr = mpptr = TheMessage->cm_fields[i]; - - if (i == eAuthor) { + for (i = 0; i < NDiskFields; ++i) { + if (TheMessage->cm_fields[FieldOrder[i]]) { + mptr = mpptr = TheMessage->cm_fields[FieldOrder[i]]; + switch (FieldOrder[i]) { + case eAuthor: safestrncpy(luser, mptr, sizeof_luser); safestrncpy(suser, mptr, sizeof_suser); - } - else if (i == 'Y') { + break; + case eCarbonCopY: if ((flags & QP_EADDR) != 0) { mptr = qp_encode_email_addrs(mptr); } sanitize_truncated_recipient(mptr); cprintf("CC: %s%s", mptr, nl); - } - else if (i == 'P') { + break; + case eMessagePath: cprintf("Return-Path: %s%s", mptr, nl); - } - else if (i == eListID) { + break; + case eListID: cprintf("List-ID: %s%s", mptr, nl); - } - else if (i == 'V') { + break; + case eenVelopeTo: if ((flags & QP_EADDR) != 0) mptr = qp_encode_email_addrs(mptr); hptr = mptr; @@ -1768,26 +1810,29 @@ void OutputRFC822MsgHeaders( hptr ++; if (!IsEmptyStr(hptr)) cprintf("Envelope-To: %s%s", hptr, nl); - } - else if (i == 'U') { + break; + case eMsgSubject: cprintf("Subject: %s%s", mptr, nl); subject_found = 1; - } - else if (i == 'I') + break; + case emessageId: safestrncpy(mid, mptr, sizeof_mid); /// TODO: detect @ here and copy @nodename in if not found. - else if (i == erFc822Addr) + break; + case erFc822Addr: safestrncpy(fuser, mptr, sizeof_fuser); - /* else if (i == 'O') + /* case eOriginalRoom: cprintf("X-Citadel-Room: %s%s", - mptr, nl); */ - else if (i == 'N') + mptr, nl) + break; + ; */ + case eNodeName: safestrncpy(snode, mptr, sizeof_snode); - else if (i == 'R') - { + break; + case eRecipient: if (haschar(mptr, '@') == 0) { sanitize_truncated_recipient(mptr); - cprintf("To: %s@%s", mptr, config.c_fqdn); + cprintf("To: %s@%s", mptr, CtdlGetConfigStr("c_fqdn")); cprintf("%s", nl); } else @@ -1799,13 +1844,13 @@ void OutputRFC822MsgHeaders( cprintf("To: %s", mptr); cprintf("%s", nl); } - } - else if (i == 'T') { + break; + case eTimestamp: datestring(datestamp, sizeof datestamp, atol(mptr), DATESTRING_RFC822); cprintf("Date: %s%s", datestamp, nl); - } - else if (i == 'W') { + break; + case eWeferences: cprintf("References: "); k = num_tokens(mptr, '|'); for (j=0; jcm_fields[eMesageText]; @@ -1906,12 +1970,16 @@ void Dump_RFC822HeadersBody( MSGM_syslog(LOG_ERR, "Dump_RFC822HeadersBody(): aborting due to write failure.\n"); return; } + lfSent = (outbuf[outlen - 1] == '\n'); outlen = 0; } } if (outlen > 0) { client_write(outbuf, outlen); + lfSent = (outbuf[outlen - 1] == '\n'); } + if (!lfSent) + client_write(nl, nlen); } @@ -1923,13 +1991,12 @@ void Dump_RFC822HeadersBody( void DumpFormatFixed( struct CtdlMessage *TheMessage, int mode, /* how would you like that message? */ - const char *nl) + const char *nl, int nllen) { cit_uint8_t ch; char buf[SIZ]; int buflen; int xlline = 0; - int nllen = strlen (nl); char *mptr; mptr = TheMessage->cm_fields[eMesageText]; @@ -2004,6 +2071,7 @@ int CtdlOutputPreLoadedMsg( struct CitContext *CCC = CC; int i; const char *nl; /* newline string */ + int nlen; struct ma_info ma; /* Buffers needed for RFC822 translation. These are all filled @@ -2022,6 +2090,7 @@ int CtdlOutputPreLoadedMsg( strcpy(mid, "unknown"); nl = (crlf ? "\r\n" : "\n"); + nlen = crlf ? 2 : 1; if (!CM_IsValidMsg(TheMessage)) { MSGM_syslog(LOG_ERR, @@ -2117,12 +2186,12 @@ int CtdlOutputPreLoadedMsg( strcpy(suser, ""); strcpy(luser, ""); strcpy(fuser, ""); - memcpy(snode, CFG_KEY(c_nodename) + 1); + memcpy(snode, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename")) + 1); if (mode == MT_RFC822) OutputRFC822MsgHeaders( TheMessage, flags, - nl, + nl, nlen, mid, sizeof(mid), suser, sizeof(suser), luser, sizeof(luser), @@ -2186,7 +2255,7 @@ START_TEXT: TheMessage, headers_only, flags, - nl); + nl, nlen); goto DONE; } } @@ -2204,7 +2273,7 @@ START_TEXT: DumpFormatFixed( TheMessage, mode, /* how would you like that message? */ - nl); + nl, nlen); /* If the message on disk is format 0 (Citadel vari-format), we * output using the formatter at 80 columns. This is the final output @@ -2376,7 +2445,7 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms msg = supplied_msg; } else { - msg = CtdlFetchMessage(msgid, 0); + msg = CtdlFetchMessage(msgid, 0, 1); } if (msg != NULL) { @@ -2442,75 +2511,101 @@ int CtdlSaveMsgPointerInRoom(char *roomname, long msgid, * called by server-side modules. * */ -long send_message(struct CtdlMessage *msg) { +long CtdlSaveThisMessage(struct CtdlMessage *msg, long msgid, int Reply) { struct CitContext *CCC = CC; - long newmsgid; long retval; - char msgidbuf[256]; - long msgidbuflen; struct ser_ret smr; int is_bigmsg = 0; char *holdM = NULL; long holdMLen = 0; - /* Get a new message number */ - newmsgid = get_new_message_number(); - msgidbuflen = snprintf(msgidbuf, sizeof msgidbuf, "%08lX-%08lX@%s", - (long unsigned int) time(NULL), - (long unsigned int) newmsgid, - config.c_fqdn - ); - - /* Generate an ID if we don't have one already */ - if (CM_IsEmpty(msg, emessageId)) { - CM_SetField(msg, emessageId, msgidbuf, msgidbuflen); - } - - /* If the message is big, set its body aside for storage elsewhere */ - if (!CM_IsEmpty(msg, eMesageText)) { - if (msg->cm_lengths[eMesageText] > BIGMSG) { - is_bigmsg = 1; - holdM = msg->cm_fields[eMesageText]; - msg->cm_fields[eMesageText] = NULL; - holdMLen = msg->cm_lengths[eMesageText]; - msg->cm_lengths[eMesageText] = 0; - } + /* + * If the message is big, set its body aside for storage elsewhere + * and we hide the message body from the serializer + */ + if (!CM_IsEmpty(msg, eMesageText) && msg->cm_lengths[eMesageText] > BIGMSG) + { + is_bigmsg = 1; + holdM = msg->cm_fields[eMesageText]; + msg->cm_fields[eMesageText] = NULL; + holdMLen = msg->cm_lengths[eMesageText]; + msg->cm_lengths[eMesageText] = 0; } /* Serialize our data structure for storage in the database */ CtdlSerializeMessage(&smr, msg); if (is_bigmsg) { + /* put the message body back into the message */ msg->cm_fields[eMesageText] = holdM; msg->cm_lengths[eMesageText] = holdMLen; } if (smr.len == 0) { - cprintf("%d Unable to serialize message\n", - ERROR + INTERNAL_ERROR); + if (Reply) { + cprintf("%d Unable to serialize message\n", + ERROR + INTERNAL_ERROR); + } + else { + MSGM_syslog(LOG_ERR, "CtdlSaveMessage() unable to serialize message"); + + } return (-1L); } /* Write our little bundle of joy into the message base */ - if (cdb_store(CDB_MSGMAIN, &newmsgid, (int)sizeof(long), - smr.ser, smr.len) < 0) { - MSGM_syslog(LOG_ERR, "Can't store message\n"); - retval = 0L; - } else { + retval = cdb_store(CDB_MSGMAIN, &msgid, (int)sizeof(long), + smr.ser, smr.len); + if (retval < 0) { + MSG_syslog(LOG_ERR, "Can't store message %ld: %ld", msgid, retval); + } + else { if (is_bigmsg) { - cdb_store(CDB_BIGMSGS, - &newmsgid, - (int)sizeof(long), - holdM, - (holdMLen + 1) + retval = cdb_store(CDB_BIGMSGS, + &msgid, + (int)sizeof(long), + holdM, + (holdMLen + 1) ); + if (retval < 0) { + MSG_syslog(LOG_ERR, "failed to store message body for msgid %ld: %ld", + msgid, retval); + } } - retval = newmsgid; } /* Free the memory we used for the serialized message */ free(smr.ser); + return(retval); +} + +long send_message(struct CtdlMessage *msg) { + long newmsgid; + long retval; + char msgidbuf[256]; + long msgidbuflen; + + /* Get a new message number */ + newmsgid = get_new_message_number(); + + /* Generate an ID if we don't have one already */ + if (CM_IsEmpty(msg, emessageId)) { + msgidbuflen = snprintf(msgidbuf, sizeof msgidbuf, "%08lX-%08lX@%s", + (long unsigned int) time(NULL), + (long unsigned int) newmsgid, + CtdlGetConfigStr("c_fqdn") + ); + + CM_SetField(msg, emessageId, msgidbuf, msgidbuflen); + } + + retval = CtdlSaveThisMessage(msg, newmsgid, 1); + + if (retval == 0) { + retval = newmsgid; + } + /* Return the *local* message ID to the caller * (even if we're storing an incoming network message) */ @@ -2527,7 +2622,7 @@ long send_message(struct CtdlMessage *msg) { * serialized message in memory. THE LATTER MUST BE FREED BY THE CALLER. */ void CtdlSerializeMessage(struct ser_ret *ret, /* return values */ - struct CtdlMessage *msg) /* unserialized msg */ + struct CtdlMessage *msg) /* unserialized msg */ { struct CitContext *CCC = CC; size_t wlen; @@ -2718,7 +2813,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ if (TWITDETECT) { if (CCC->user.axlevel == AxProbU) { strcpy(hold_rm, actual_rm); - strcpy(actual_rm, config.c_twitroom); + strcpy(actual_rm, CtdlGetConfigStr("c_twitroom")); MSGM_syslog(LOG_DEBUG, "Diverting to twit room\n"); } } @@ -2731,13 +2826,13 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ MSG_syslog(LOG_INFO, "Final selection: %s (%s)\n", actual_rm, room); if (strcasecmp(actual_rm, CCC->room.QRname)) { /* CtdlGetRoom(&CCC->room, actual_rm); */ - CtdlUserGoto(actual_rm, 0, 1, NULL, NULL); + CtdlUserGoto(actual_rm, 0, 1, NULL, NULL, NULL, NULL); } /* * If this message has no O (room) field, generate one. */ - if (CM_IsEmpty(msg, eOriginalRoom)) { + if (CM_IsEmpty(msg, eOriginalRoom) && !IsEmptyStr(CCC->room.QRname)) { CM_SetField(msg, eOriginalRoom, CCC->room.QRname, strlen(CCC->room.QRname)); } @@ -2801,7 +2896,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ if ((!CCC->internal_pgm) || (recps == NULL)) { if (CtdlSaveMsgPointerInRoom(actual_rm, newmsgid, 1, msg) != 0) { MSGM_syslog(LOG_ERR, "ERROR saving message pointer!\n"); - CtdlSaveMsgPointerInRoom(config.c_aideroom, newmsgid, 0, msg); + CtdlSaveMsgPointerInRoom(CtdlGetConfigStr("c_aideroom"), newmsgid, 0, msg); } } @@ -2821,16 +2916,16 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ /* Bump this user's messages posted counter. */ MSGM_syslog(LOG_DEBUG, "Updating user\n"); - CtdlGetUserLock(&CCC->user, CCC->curr_user); + CtdlLockGetCurrentUser(); CCC->user.posted = CCC->user.posted + 1; - CtdlPutUserLock(&CCC->user); + CtdlPutCurrentUserLock(); /* Decide where bounces need to be delivered */ if ((recps != NULL) && (recps->bounce_to == NULL)) { if (CCC->logged_in) snprintf(bounce_to, sizeof bounce_to, "%s@%s", - CCC->user.fullname, config.c_nodename); + CCC->user.fullname, CtdlGetConfigStr("c_nodename")); else snprintf(bounce_to, sizeof bounce_to, "%s@%s", msg->cm_fields[eAuthor], msg->cm_fields[eNodeName]); @@ -2863,7 +2958,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ } else { MSG_syslog(LOG_DEBUG, "No user <%s>\n", recipient); - CtdlSaveMsgPointerInRoom(config.c_aideroom, newmsgid, 0, msg); + CtdlSaveMsgPointerInRoom(CtdlGetConfigStr("c_aideroom"), newmsgid, 0, msg); } } recps->recp_local = pch; @@ -2878,7 +2973,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ /* Go back to the room we started from */ MSG_syslog(LOG_DEBUG, "Returning to original room %s\n", hold_rm); if (strcasecmp(hold_rm, CCC->room.QRname)) - CtdlUserGoto(hold_rm, 0, 1, NULL, NULL); + CtdlUserGoto(hold_rm, 0, 1, NULL, NULL, NULL, NULL); /* * Any addresses to harvest for someone's address book? @@ -2908,13 +3003,13 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ } else { if (recps == NULL) { - qualified_for_journaling = config.c_journal_pubmsgs; + qualified_for_journaling = CtdlGetConfigInt("c_journal_pubmsgs"); } else if (recps->num_local + recps->num_ignet + recps->num_internet > 0) { - qualified_for_journaling = config.c_journal_email; + qualified_for_journaling = CtdlGetConfigInt("c_journal_email"); } else { - qualified_for_journaling = config.c_journal_pubmsgs; + qualified_for_journaling = CtdlGetConfigInt("c_journal_pubmsgs"); } } @@ -2960,10 +3055,10 @@ void quickie_message(const char *from, msg->cm_anon_type = MES_NORMAL; msg->cm_format_type = format_type; - if (from != NULL) { + if (!IsEmptyStr(from)) { CM_SetField(msg, eAuthor, from, strlen(from)); } - else if (fromaddr != NULL) { + else if (!IsEmptyStr(fromaddr)) { char *pAt; CM_SetField(msg, eAuthor, fromaddr, strlen(fromaddr)); pAt = strchr(msg->cm_fields[eAuthor], '@'); @@ -2975,17 +3070,19 @@ void quickie_message(const char *from, msg->cm_fields[eAuthor] = strdup("Citadel"); } - if (fromaddr != NULL) CM_SetField(msg, erFc822Addr, fromaddr, strlen(fromaddr)); - if (room != NULL) CM_SetField(msg, eOriginalRoom, room, strlen(room)); - CM_SetField(msg, eNodeName, CFG_KEY(c_nodename)); - if (to != NULL) { + if (!IsEmptyStr(fromaddr)) CM_SetField(msg, erFc822Addr, fromaddr, strlen(fromaddr)); + if (!IsEmptyStr(room)) CM_SetField(msg, eOriginalRoom, room, strlen(room)); + CM_SetField(msg, eNodeName, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename"))); + if (!IsEmptyStr(to)) { CM_SetField(msg, eRecipient, to, strlen(to)); recp = validate_recipients(to, NULL, 0); } - if (subject != NULL) { + if (!IsEmptyStr(subject)) { CM_SetField(msg, eMsgSubject, subject, strlen(subject)); } - CM_SetField(msg, eMesageText, text, strlen(text)); + if (!IsEmptyStr(text)) { + CM_SetField(msg, eMesageText, text, strlen(text)); + } CtdlSubmitMsg(msg, recp, room, 0); CM_Free(msg); @@ -3001,7 +3098,7 @@ void flood_protect_quickie_message(const char *from, const char *subject, int nCriterions, const char **CritStr, - long *CritStrLen, + const long *CritStrLen, long ccid, long ioid, time_t NOW) @@ -3012,7 +3109,8 @@ void flood_protect_quickie_message(const char *from, StrBuf *guid; char timestamp[64]; long tslen; - time_t tsday = NOW / (8*60*60); /* just care for a day... */ + static const time_t tsday = (8*60*60); /* just care for a day... */ + time_t seenstamp; tslen = snprintf(timestamp, sizeof(timestamp), "%ld", tsday); MD5Init(&md5context); @@ -3031,29 +3129,35 @@ void flood_protect_quickie_message(const char *from, if (StrLength(guid) > 40) StrBufCutAt(guid, 40, NULL); - if (CheckIfAlreadySeen("FPAideMessage", - guid, - NOW, - tsday, - eUpdate, - ccid, - ioid)!= 0) + seenstamp = CheckIfAlreadySeen("FPAideMessage", + guid, + NOW, + tsday, + eUpdate, + ccid, + ioid); + if ((seenstamp > 0) && (seenstamp < tsday)) { FreeStrBuf(&guid); /* yes, we did. flood protection kicks in. */ syslog(LOG_DEBUG, - "not sending message again\n"); + "not sending message again - %ld < %ld \n", seenstamp, tsday); return; } - FreeStrBuf(&guid); - /* no, this message isn't sent recently; go ahead. */ - quickie_message(from, - fromaddr, - to, - room, - text, - format_type, - subject); + else + { + syslog(LOG_DEBUG, + "sending message. %ld >= %ld", seenstamp, tsday); + FreeStrBuf(&guid); + /* no, this message isn't sent recently; go ahead. */ + quickie_message(from, + fromaddr, + to, + room, + text, + format_type, + subject); + } } @@ -3208,6 +3312,11 @@ eReadState CtdlReadMessageBodyAsync(AsyncIO *IO) IO->SendBuf.fd); fd = fopen(fn, "a+"); + if (fd == NULL) { + syslog(LOG_EMERG, "failed to open file %s: %s", fn, strerror(errno)); + cit_backtrace(); + exit(1); + } #endif ReadMsg = IO->ReadMsg; @@ -3289,7 +3398,7 @@ eReadState CtdlReadMessageBodyAsync(AsyncIO *IO) if (MsgFinished) return eReadSuccess; else - return eAbort; + return eReadFail; } @@ -3413,7 +3522,7 @@ struct CtdlMessage *CtdlMakeMessageLen( if (myelen > 0) { CM_SetField(msg, eMessagePath, my_email, myelen); } - else { + else if (!IsEmptyStr(author->fullname)) { CM_SetField(msg, eMessagePath, author->fullname, strlen(author->fullname)); } convert_spaces_to_underscores(msg->cm_fields[eMessagePath]); @@ -3429,16 +3538,19 @@ struct CtdlMessage *CtdlMakeMessageLen( } StrBufRFC2047encode(&FakeEncAuthor, FakeAuthor); CM_SetAsFieldSB(msg, eAuthor, &FakeEncAuthor); + FreeStrBuf(&FakeAuthor); - if (CCC->room.QRflags & QR_MAILBOX) { /* room */ - CM_SetField(msg, eOriginalRoom, &CCC->room.QRname[11], strlen(&CCC->room.QRname[11])); - } - else { - CM_SetField(msg, eOriginalRoom, CCC->room.QRname, strlen(CCC->room.QRname)); + if (!!IsEmptyStr(CCC->room.QRname)) { + if (CCC->room.QRflags & QR_MAILBOX) { /* room */ + CM_SetField(msg, eOriginalRoom, &CCC->room.QRname[11], strlen(&CCC->room.QRname[11])); + } + else { + CM_SetField(msg, eOriginalRoom, CCC->room.QRname, strlen(CCC->room.QRname)); + } } - CM_SetField(msg, eNodeName, CFG_KEY(c_nodename)); - CM_SetField(msg, eHumanNode, CFG_KEY(c_humannode)); + CM_SetField(msg, eNodeName, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename"))); + CM_SetField(msg, eHumanNode, CtdlGetConfigStr("c_humannode"), strlen(CtdlGetConfigStr("c_humannode"))); if (rcplen > 0) { CM_SetField(msg, eRecipient, recipient, rcplen); @@ -3489,9 +3601,10 @@ struct CtdlMessage *CtdlMakeMessageLen( CM_SetField(msg, eMesageText, preformatted_text, textlen); } else { - preformatted_text = CtdlReadMessageBody(HKEY("000"), config.c_maxmsglen, NULL, 0, 0); - if (preformatted_text != NULL) { - CM_SetField(msg, eMesageText, preformatted_text, strlen(preformatted_text)); + StrBuf *MsgBody; + MsgBody = CtdlReadMessageBodyBuf(HKEY("000"), CtdlGetConfigLong("c_maxmsglen"), NULL, 0, 0); + if (MsgBody != NULL) { + CM_SetAsFieldSB(msg, eMesageText, &MsgBody); } } @@ -3505,7 +3618,7 @@ struct CtdlMessage *CtdlMakeMessageLen( * API function to delete messages which match a set of criteria * (returns the actual number of messages deleted) */ -int CtdlDeleteMessages(char *room_name, /* which room */ +int CtdlDeleteMessages(const char *room_name, /* which room */ long *dmsgnums, /* array of msg numbers to be deleted */ int num_dmsgnums, /* number of msgs to be deleted, or 0 for "any" */ char *content_type /* or "" for any. regular expressions expected. */ @@ -3970,8 +4083,8 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ msg->cm_format_type = 4; CM_SetField(msg, eAuthor, CCC->user.fullname, strlen(CCC->user.fullname)); CM_SetField(msg, eOriginalRoom, req_room, strlen(req_room)); - CM_SetField(msg, eNodeName, CFG_KEY(c_nodename)); - CM_SetField(msg, eHumanNode, CFG_KEY(c_humannode)); + CM_SetField(msg, eNodeName, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename"))); + CM_SetField(msg, eHumanNode, CtdlGetConfigStr("c_humannode"), strlen(CtdlGetConfigStr("c_humannode"))); msg->cm_flags = flags; CM_SetAsFieldSB(msg, eMesageText, &encoded_message);