X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmsgbase.c;h=2cd006d2e02b406648d90d11b399596d0e895d3a;hb=a18ba8921df83a26402a5c523cbee50e1a790cc7;hp=1539992d85ea257e863b516bf4de4a7c5b92123c;hpb=e750a47a92b48dfa6faf63a61a71f103871c9e5b;p=citadel.git diff --git a/citadel/msgbase.c b/citadel/msgbase.c index 1539992d8..2cd006d2e 100644 --- a/citadel/msgbase.c +++ b/citadel/msgbase.c @@ -12,57 +12,25 @@ * GNU General Public License for more details. */ -#include "sysdep.h" -#include -#include -#include -#include - -#if TIME_WITH_SYS_TIME -# include -# include -#else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif - -#include -#include -#include -#include -#include -#include -#include +#include #include +#include #include "md5.h" -#include -#include "citadel.h" -#include "server.h" -#include "serv_extensions.h" -#include "database.h" -#include "msgbase.h" -#include "support.h" -#include "sysdep_decls.h" +#include "ctdl_module.h" #include "citserver.h" -#include "room_ops.h" -#include "user_ops.h" -#include "config.h" #include "control.h" +#include "clientsocket.h" #include "genstamp.h" +#include "room_ops.h" +#include "user_ops.h" + #include "internet_addressing.h" #include "euidindex.h" +#include "msgbase.h" #include "journaling.h" -#include "citadel_dirs.h" -#include "clientsocket.h" -#include "threads.h" - -#include "ctdl_module.h" struct addresses_to_be_filed *atbf = NULL; @@ -168,6 +136,7 @@ void CM_SetField(struct CtdlMessage *Msg, eMsgField which, const char *buf, long Msg->cm_fields[which] = malloc(length + 1); memcpy(Msg->cm_fields[which], buf, length); Msg->cm_fields[which][length] = '\0'; + Msg->cm_lengths[which] = length; } void CM_SetFieldLONG(struct CtdlMessage *Msg, eMsgField which, long lvalue) @@ -182,8 +151,11 @@ void CM_CutFieldAt(struct CtdlMessage *Msg, eMsgField WhichToCut, long maxlen) if (Msg->cm_fields[WhichToCut] == NULL) return; - if (strlen(Msg->cm_fields[WhichToCut]) > maxlen) + if (Msg->cm_lengths[WhichToCut] > maxlen) + { Msg->cm_fields[WhichToCut][maxlen] = '\0'; + Msg->cm_lengths[WhichToCut] = maxlen; + } } void CM_FlushField(struct CtdlMessage *Msg, eMsgField which) @@ -191,6 +163,7 @@ void CM_FlushField(struct CtdlMessage *Msg, eMsgField which) if (Msg->cm_fields[which] != NULL) free (Msg->cm_fields[which]); Msg->cm_fields[which] = NULL; + Msg->cm_lengths[which] = 0; } void CM_Flush(struct CtdlMessage *Msg) { @@ -213,13 +186,17 @@ void CM_CopyField(struct CtdlMessage *Msg, eMsgField WhichToPutTo, eMsgField Whi if (Msg->cm_fields[WhichtToCopy] != NULL) { - len = strlen(Msg->cm_fields[WhichtToCopy]); + len = Msg->cm_lengths[WhichtToCopy]; Msg->cm_fields[WhichToPutTo] = malloc(len + 1); memcpy(Msg->cm_fields[WhichToPutTo], Msg->cm_fields[WhichtToCopy], len); Msg->cm_fields[WhichToPutTo][len] = '\0'; + Msg->cm_lengths[WhichToPutTo] = len; } else + { Msg->cm_fields[WhichToPutTo] = NULL; + Msg->cm_lengths[WhichToPutTo] = 0; + } } @@ -230,7 +207,7 @@ void CM_PrependToField(struct CtdlMessage *Msg, eMsgField which, const char *buf long newmsgsize; char *new; - oldmsgsize = strlen(Msg->cm_fields[which]) + 1; + oldmsgsize = Msg->cm_lengths[which] + 1; newmsgsize = length + oldmsgsize; new = malloc(newmsgsize); @@ -238,11 +215,13 @@ void CM_PrependToField(struct CtdlMessage *Msg, eMsgField which, const char *buf memcpy(new + length, Msg->cm_fields[which], oldmsgsize); free(Msg->cm_fields[which]); Msg->cm_fields[which] = new; + Msg->cm_lengths[which] = newmsgsize - 1; } else { Msg->cm_fields[which] = malloc(length + 1); memcpy(Msg->cm_fields[which], buf, length); Msg->cm_fields[which][length] = '\0'; + Msg->cm_lengths[which] = length; } } @@ -253,6 +232,7 @@ void CM_SetAsField(struct CtdlMessage *Msg, eMsgField which, char **buf, long le Msg->cm_fields[which] = *buf; *buf = NULL; + Msg->cm_lengths[which] = length; } void CM_SetAsFieldSB(struct CtdlMessage *Msg, eMsgField which, StrBuf **buf) @@ -260,6 +240,7 @@ void CM_SetAsFieldSB(struct CtdlMessage *Msg, eMsgField which, StrBuf **buf) if (Msg->cm_fields[which] != NULL) free (Msg->cm_fields[which]); + Msg->cm_lengths[which] = StrLength(*buf); Msg->cm_fields[which] = SmashStrBuf(buf); } @@ -267,9 +248,10 @@ void CM_GetAsField(struct CtdlMessage *Msg, eMsgField which, char **ret, long *r { if (Msg->cm_fields[which] != NULL) { - *retlen = strlen(Msg->cm_fields[which]); + *retlen = Msg->cm_lengths[which]; *ret = Msg->cm_fields[which]; Msg->cm_fields[which] = NULL; + Msg->cm_lengths[which] = 0; } else { @@ -300,6 +282,7 @@ void CM_FreeContents(struct CtdlMessage *msg) for (i = 0; i < 256; ++i) if (msg->cm_fields[i] != NULL) { free(msg->cm_fields[i]); + msg->cm_lengths[i] = 0; } msg->cm_magic = 0; /* just in case */ @@ -321,12 +304,13 @@ void CM_Free(struct CtdlMessage *msg) int CM_DupField(eMsgField i, struct CtdlMessage *OrgMsg, struct CtdlMessage *NewMsg) { long len; - len = strlen(OrgMsg->cm_fields[i]); + len = OrgMsg->cm_lengths[i]; NewMsg->cm_fields[i] = malloc(len + 1); if (NewMsg->cm_fields[i] == NULL) return 0; memcpy(NewMsg->cm_fields[i], OrgMsg->cm_fields[i], len); NewMsg->cm_fields[i][len] = '\0'; + NewMsg->cm_lengths[i] = len; return 1; } @@ -385,8 +369,9 @@ int CtdlMsgCmp(struct CtdlMessage *msg, struct CtdlMessage *template) { if (IsEmptyStr(template->cm_fields[i])) continue; return 1; } - if (strcasecmp(msg->cm_fields[i], - template->cm_fields[i])) return 1; + if ((template->cm_lengths[i] != msg->cm_lengths[i]) || + (strcasecmp(msg->cm_fields[i], template->cm_fields[i]))) + return 1; } } @@ -956,7 +941,6 @@ void memfmout( MSGM_syslog(LOG_ERR, "memfmout(): aborting due to write failure.\n"); return; } - len = 0; client_write(nl, nllen); column = 0; } @@ -1116,6 +1100,7 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) 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)); @@ -1144,6 +1129,13 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) ret->cm_anon_type = *mptr++; /* Anon type byte */ ret->cm_format_type = *mptr++; /* Format type byte */ + + 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'; + } + /* * The rest is zero or more arbitrary fields. Load them in. * We're done when we encounter either a zero-length field or @@ -1155,8 +1147,9 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) break; } field_header = *mptr++; + which = field_header; len = strlen(mptr); - CM_SetField(ret, field_header, mptr, len); + CM_SetField(ret, which, mptr, len); mptr += len + 1; /* advance to next field */ @@ -1181,7 +1174,7 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) } /* Perform "before read" hooks (aborting if any return nonzero) */ - if (PerformMessageHooks(ret, EVT_BEFOREREAD) > 0) { + if (PerformMessageHooks(ret, NULL, EVT_BEFOREREAD) > 0) { CM_Free(ret); return NULL; } @@ -1598,21 +1591,20 @@ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ if (section) if (!IsEmptyStr(section)) if (strcmp(section, "0")) { memset(&encap, 0, sizeof encap); safestrncpy(encap.desired_section, section, sizeof encap.desired_section); - mime_parser(TheMessage->cm_fields[eMesageText], - NULL, - *extract_encapsulated_message, - NULL, NULL, (void *)&encap, 0 - ); + mime_parser(CM_RANGE(TheMessage, eMesageText), + *extract_encapsulated_message, + NULL, NULL, (void *)&encap, 0 + ); if ((Author != NULL) && (*Author == NULL)) { - *Author = TheMessage->cm_fields[eAuthor]; - TheMessage->cm_fields[eAuthor] = NULL; + long len; + CM_GetAsField(TheMessage, eAuthor, Author, &len); } if ((Address != NULL) && (*Address == NULL)) { - *Address = TheMessage->cm_fields[erFc822Addr]; - TheMessage->cm_fields[erFc822Addr] = NULL; + long len; + CM_GetAsField(TheMessage, erFc822Addr, Address, &len); } CM_Free(TheMessage); TheMessage = NULL; @@ -1645,13 +1637,13 @@ int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ retcode = CtdlOutputPreLoadedMsg(TheMessage, mode, headers_only, do_proto, crlf, flags); if ((Author != NULL) && (*Author == NULL)) { - *Author = TheMessage->cm_fields[eAuthor]; - TheMessage->cm_fields[eAuthor] = NULL; + long len; + CM_GetAsField(TheMessage, eAuthor, Author, &len); } if ((Address != NULL) && (*Address == NULL)) { - *Address = TheMessage->cm_fields[erFc822Addr]; - TheMessage->cm_fields[erFc822Addr] = NULL; + long len; + CM_GetAsField(TheMessage, erFc822Addr, Address, &len); } CM_Free(TheMessage); @@ -2018,7 +2010,6 @@ int CtdlOutputPreLoadedMsg( ) { struct CitContext *CCC = CC; int i; - char *mptr = NULL; const char *nl; /* newline string */ struct ma_info ma; @@ -2050,7 +2041,7 @@ int CtdlOutputPreLoadedMsg( * Pad it with spaces in order to avoid changing the RFC822 length of the message. */ if ( (flags & SUPPRESS_ENV_TO) && (!CM_IsEmpty(TheMessage, eenVelopeTo)) ) { - memset(TheMessage->cm_fields[eenVelopeTo], ' ', strlen(TheMessage->cm_fields[eenVelopeTo])); + memset(TheMessage->cm_fields[eenVelopeTo], ' ', TheMessage->cm_lengths[eenVelopeTo]); } /* Are we downloading a MIME component? */ @@ -2065,8 +2056,8 @@ int CtdlOutputPreLoadedMsg( ERROR + RESOURCE_BUSY); } else { /* Parse the message text component */ - mptr = TheMessage->cm_fields[eMesageText]; - mime_parser(mptr, NULL, *mime_download, NULL, NULL, NULL, 0); + mime_parser(CM_RANGE(TheMessage, eMesageText), + *mime_download, NULL, NULL, NULL, 0); /* If there's no file open by this time, the requested * section wasn't found, so print an error */ @@ -2092,8 +2083,8 @@ int CtdlOutputPreLoadedMsg( /* Parse the message text component */ int found_it = 0; - mptr = TheMessage->cm_fields[eMesageText]; - mime_parser(mptr, NULL, *mime_spew_section, NULL, NULL, (void *)&found_it, 0); + mime_parser(CM_RANGE(TheMessage, eMesageText), + *mime_spew_section, NULL, NULL, (void *)&found_it, 0); /* If section wasn't found, print an error */ if (!found_it) { @@ -2133,7 +2124,7 @@ int CtdlOutputPreLoadedMsg( strcpy(suser, ""); strcpy(luser, ""); strcpy(fuser, ""); - strcpy(snode, NODENAME); + memcpy(snode, CFG_KEY(c_nodename) + 1); if (mode == MT_RFC822) OutputRFC822MsgHeaders( TheMessage, @@ -2190,9 +2181,8 @@ START_TEXT: /* Tell the client about the MIME parts in this message */ if (TheMessage->cm_format_type == FMT_RFC822) { if ( (mode == MT_CITADEL) || (mode == MT_MIME) ) { - mptr = TheMessage->cm_fields[eMesageText]; memset(&ma, 0, sizeof(struct ma_info)); - mime_parser(mptr, NULL, + mime_parser(CM_RANGE(TheMessage, eMesageText), (do_proto ? *list_this_part : NULL), (do_proto ? *list_this_pref : NULL), (do_proto ? *list_this_suff : NULL), @@ -2231,12 +2221,10 @@ START_TEXT: * message to the reader's screen width. */ if (TheMessage->cm_format_type == FMT_CITADEL) { - mptr = TheMessage->cm_fields[eMesageText]; - if (mode == MT_MIME) { cprintf("Content-type: text/x-citadel-variformat\n\n"); } - memfmout(mptr, nl); + memfmout(TheMessage->cm_fields[eMesageText], nl); } /* If the message on disk is format 4 (MIME), we've gotta hand it @@ -2252,17 +2240,17 @@ START_TEXT: strcpy(ma.chosen_part, "1"); ma.chosen_pref = 9999; ma.dont_decode = CCC->msg4_dont_decode; - mime_parser(mptr, NULL, - *choose_preferred, *fixed_output_pre, - *fixed_output_post, (void *)&ma, 1); - mime_parser(mptr, NULL, - *output_preferred, NULL, NULL, (void *)&ma, 1); + mime_parser(CM_RANGE(TheMessage, eMesageText), + *choose_preferred, *fixed_output_pre, + *fixed_output_post, (void *)&ma, 1); + mime_parser(CM_RANGE(TheMessage, eMesageText), + *output_preferred, NULL, NULL, (void *)&ma, 1); } else { ma.use_fo_hooks = 1; - mime_parser(mptr, NULL, - *fixed_output, *fixed_output_pre, - *fixed_output_post, (void *)&ma, 0); + mime_parser(CM_RANGE(TheMessage, eMesageText), + *fixed_output, *fixed_output_pre, + *fixed_output_post, (void *)&ma, 0); } } @@ -2470,6 +2458,7 @@ long send_message(struct CtdlMessage *msg) { struct ser_ret smr; int is_bigmsg = 0; char *holdM = NULL; + long holdMLen = 0; /* Get a new message number */ newmsgid = get_new_message_number(); @@ -2486,10 +2475,12 @@ long send_message(struct CtdlMessage *msg) { /* If the message is big, set its body aside for storage elsewhere */ if (!CM_IsEmpty(msg, eMesageText)) { - if (strlen(msg->cm_fields[eMesageText]) > BIGMSG) { + 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; } } @@ -2498,6 +2489,7 @@ long send_message(struct CtdlMessage *msg) { if (is_bigmsg) { msg->cm_fields[eMesageText] = holdM; + msg->cm_lengths[eMesageText] = holdMLen; } if (smr.len == 0) { @@ -2517,7 +2509,7 @@ long send_message(struct CtdlMessage *msg) { &newmsgid, (int)sizeof(long), holdM, - (strlen(holdM) + 1) + (holdMLen + 1) ); } retval = newmsgid; @@ -2545,11 +2537,8 @@ void CtdlSerializeMessage(struct ser_ret *ret, /* return values */ struct CtdlMessage *msg) /* unserialized msg */ { struct CitContext *CCC = CC; - size_t wlen, fieldlen; + size_t wlen; int i; - long lengths[NDiskFields]; - - memset(lengths, 0, sizeof(lengths)); /* * Check for valid message format @@ -2564,10 +2553,7 @@ void CtdlSerializeMessage(struct ser_ret *ret, /* return values */ ret->len = 3; for (i=0; i < NDiskFields; ++i) if (msg->cm_fields[FieldOrder[i]] != NULL) - { - lengths[i] = strlen(msg->cm_fields[FieldOrder[i]]); - ret->len += lengths[i] + 2; - } + ret->len += msg->cm_lengths[FieldOrder[i]] + 2; ret->ser = malloc(ret->len); if (ret->ser == NULL) { @@ -2586,14 +2572,13 @@ void CtdlSerializeMessage(struct ser_ret *ret, /* return values */ for (i=0; i < NDiskFields; ++i) if (msg->cm_fields[FieldOrder[i]] != NULL) { - fieldlen = lengths[i]; ret->ser[wlen++] = (char)FieldOrder[i]; memcpy(&ret->ser[wlen], msg->cm_fields[FieldOrder[i]], - fieldlen+1); + msg->cm_lengths[FieldOrder[i]] + 1); - wlen = wlen + fieldlen + 1; + wlen = wlen + msg->cm_lengths[FieldOrder[i]] + 1; } if (ret->len != wlen) { @@ -2638,37 +2623,28 @@ void ReplicationChecks(struct CtdlMessage *msg) { * Save a message to disk and submit it into the delivery system. */ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ - struct recptypes *recps, /* recipients (if mail) */ + recptypes *recps, /* recipients (if mail) */ const char *force, /* force a particular room? */ int flags /* should the message be exported clean? */ ) { - char submit_filename[128]; char hold_rm[ROOMNAMELEN]; char actual_rm[ROOMNAMELEN]; char force_room[ROOMNAMELEN]; char content_type[SIZ]; /* We have to learn this */ char recipient[SIZ]; + char bounce_to[1024]; const char *room; long newmsgid; const char *mptr = NULL; struct ctdluser userbuf; int a, i; struct MetaData smi; - FILE *network_fp = NULL; - static int seqnum = 1; - struct CtdlMessage *imsg = NULL; - char *instr = NULL; - size_t instr_alloc = 0; - struct ser_ret smr; - char *hold_R, *hold_D; char *collected_addresses = NULL; struct addresses_to_be_filed *aptr = NULL; StrBuf *saved_rfc822_version = NULL; int qualified_for_journaling = 0; CitContext *CCC = MyContext(); - char bounce_to[1024] = ""; - int rv = 0; MSGM_syslog(LOG_DEBUG, "CtdlSubmitMsg() called\n"); if (CM_IsValidMsg(msg) == 0) return(-1); /* self check */ @@ -2774,7 +2750,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ /* Perform "before save" hooks (aborting if any return nonzero) */ MSGM_syslog(LOG_DEBUG, "Performing before-save hooks\n"); - if (PerformMessageHooks(msg, EVT_BEFORESAVE) > 0) return(-3); + if (PerformMessageHooks(msg, recps, EVT_BEFORESAVE) > 0) return(-3); /* * If this message has an Exclusive ID, and the room is replication @@ -2857,180 +2833,60 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ CtdlPutUserLock(&CCC->user); /* Decide where bounces need to be delivered */ - if ((recps != NULL) && (recps->bounce_to != NULL)) { - safestrncpy(bounce_to, recps->bounce_to, sizeof bounce_to); - } - else if (CCC->logged_in) { - snprintf(bounce_to, sizeof bounce_to, "%s@%s", CCC->user.fullname, config.c_nodename); - } - else { - snprintf(bounce_to, sizeof bounce_to, "%s@%s", msg->cm_fields[eAuthor], msg->cm_fields[eNodeName]); + 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); + else + snprintf(bounce_to, sizeof bounce_to, "%s@%s", + msg->cm_fields[eAuthor], msg->cm_fields[eNodeName]); + recps->bounce_to = bounce_to; } + + CM_SetFieldLONG(msg, eVltMsgNum, newmsgid); + /* If this is private, local mail, make a copy in the * recipient's mailbox and bump the reference count. */ if ((recps != NULL) && (recps->num_local > 0)) - for (i=0; irecp_local, '|'); ++i) { - long recipientlen; - recipientlen = extract_token(recipient, - recps->recp_local, i, - '|', sizeof recipient); - MSG_syslog(LOG_DEBUG, "Delivering private local mail to <%s>\n", - recipient); + { + char *pch; + int ntokens; + + pch = recps->recp_local; + recps->recp_local = recipient; + ntokens = num_tokens(pch, '|'); + for (i=0; i\n", recipient); if (CtdlGetUser(&userbuf, recipient) == 0) { CtdlMailboxName(actual_rm, sizeof actual_rm, &userbuf, MAILROOM); CtdlSaveMsgPointerInRoom(actual_rm, newmsgid, 0, msg); CtdlBumpNewMailCounter(userbuf.usernum); - if (!IsEmptyStr(config.c_funambol_host) || !IsEmptyStr(config.c_pager_program)) { - /* Generate a instruction message for the Funambol notification - * server, in the same style as the SMTP queue - */ - long instrlen; - instr_alloc = 1024; - instr = malloc(instr_alloc); - instrlen = snprintf( - instr, instr_alloc, - "Content-type: %s\n\nmsgid|%ld\nsubmitted|%ld\n" - "bounceto|%s\n", - SPOOLMIME, - newmsgid, - (long)time(NULL), //todo: time() is expensive! - bounce_to - ); - - imsg = malloc(sizeof(struct CtdlMessage)); - memset(imsg, 0, sizeof(struct CtdlMessage)); - imsg->cm_magic = CTDLMESSAGE_MAGIC; - imsg->cm_anon_type = MES_NORMAL; - imsg->cm_format_type = FMT_RFC822; - CM_SetField(imsg, eMsgSubject, HKEY("QMSG")); - CM_SetField(imsg, eAuthor, HKEY("Citadel")); - CM_SetField(imsg, eJournal, HKEY("do not journal")); - CM_SetAsField(imsg, eMesageText, &instr, instrlen); - CM_SetField(imsg, eExtnotify, recipient, recipientlen); - CtdlSubmitMsg(imsg, NULL, FNBL_QUEUE_ROOM, 0); - CM_Free(imsg); - } + PerformMessageHooks(msg, recps, EVT_AFTERUSRMBOXSAVE); } else { MSG_syslog(LOG_DEBUG, "No user <%s>\n", recipient); CtdlSaveMsgPointerInRoom(config.c_aideroom, newmsgid, 0, msg); } } + recps->recp_local = pch; + } /* Perform "after save" hooks */ MSGM_syslog(LOG_DEBUG, "Performing after-save hooks\n"); - CM_SetFieldLONG(msg, eVltMsgNum, newmsgid); - PerformMessageHooks(msg, EVT_AFTERSAVE); + PerformMessageHooks(msg, recps, EVT_AFTERSAVE); CM_FlushField(msg, eVltMsgNum); - /* For IGnet mail, we have to save a new copy into the spooler for - * each recipient, with the R and D fields set to the recipient and - * destination-node. This has two ugly side effects: all other - * recipients end up being unlisted in this recipient's copy of the - * message, and it has to deliver multiple messages to the same - * node. We'll revisit this again in a year or so when everyone has - * a network spool receiver that can handle the new style messages. - */ - if ((recps != NULL) && (recps->num_ignet > 0)) - for (i=0; irecp_ignet, '|'); ++i) { - extract_token(recipient, recps->recp_ignet, i, - '|', sizeof recipient); - - hold_R = msg->cm_fields[eRecipient]; - hold_D = msg->cm_fields[eDestination]; - msg->cm_fields[eRecipient] = malloc(SIZ); - msg->cm_fields[eDestination] = malloc(128); - extract_token(msg->cm_fields[eRecipient], recipient, 0, '@', SIZ); - extract_token(msg->cm_fields[eDestination], recipient, 1, '@', 128); - - CtdlSerializeMessage(&smr, msg); - if (smr.len > 0) { - snprintf(submit_filename, sizeof submit_filename, - "%s/netmail.%04lx.%04x.%04x", - ctdl_netin_dir, - (long) getpid(), CCC->cs_pid, ++seqnum); - network_fp = fopen(submit_filename, "wb+"); - if (network_fp != NULL) { - rv = fwrite(smr.ser, smr.len, 1, network_fp); - if (rv == -1) { - MSG_syslog(LOG_EMERG, "CtdlSubmitMsg(): Couldn't write network spool file: %s\n", - strerror(errno)); - } - fclose(network_fp); - } - free(smr.ser); - } - - free(msg->cm_fields[eRecipient]); - free(msg->cm_fields[eDestination]); - msg->cm_fields[eRecipient] = hold_R; - msg->cm_fields[eDestination] = hold_D; - } - /* 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); - /* For internet mail, generate delivery instructions. - * Yes, this is recursive. Deal with it. Infinite recursion does - * not happen because the delivery instructions message does not - * contain a recipient. - */ - if ((recps != NULL) && (recps->num_internet > 0)) { - StrBuf *SpoolMsg = NewStrBuf(); - long nTokens; - - MSGM_syslog(LOG_DEBUG, "Generating delivery instructions\n"); - - StrBufPrintf(SpoolMsg, - "Content-type: "SPOOLMIME"\n" - "\n" - "msgid|%ld\n" - "submitted|%ld\n" - "bounceto|%s\n", - newmsgid, - (long)time(NULL), - bounce_to); - - if (recps->envelope_from != NULL) { - StrBufAppendBufPlain(SpoolMsg, HKEY("envelope_from|"), 0); - StrBufAppendBufPlain(SpoolMsg, recps->envelope_from, -1, 0); - StrBufAppendBufPlain(SpoolMsg, HKEY("\n"), 0); - } - if (recps->sending_room != NULL) { - StrBufAppendBufPlain(SpoolMsg, HKEY("source_room|"), 0); - StrBufAppendBufPlain(SpoolMsg, recps->sending_room, -1, 0); - StrBufAppendBufPlain(SpoolMsg, HKEY("\n"), 0); - } - - nTokens = num_tokens(recps->recp_internet, '|'); - for (i = 0; i < nTokens; i++) { - long len; - len = extract_token(recipient, recps->recp_internet, i, '|', sizeof recipient); - if (len > 0) { - StrBufAppendBufPlain(SpoolMsg, HKEY("remote|"), 0); - StrBufAppendBufPlain(SpoolMsg, recipient, len, 0); - StrBufAppendBufPlain(SpoolMsg, HKEY("|0||\n"), 0); - } - } - - imsg = malloc(sizeof(struct CtdlMessage)); - memset(imsg, 0, sizeof(struct CtdlMessage)); - imsg->cm_magic = CTDLMESSAGE_MAGIC; - imsg->cm_anon_type = MES_NORMAL; - imsg->cm_format_type = FMT_RFC822; - imsg->cm_fields[eMsgSubject] = strdup("QMSG"); - imsg->cm_fields[eAuthor] = strdup("Citadel"); - imsg->cm_fields[eJournal] = strdup("do not journal"); - imsg->cm_fields[eMesageText] = SmashStrBuf(&SpoolMsg); /* imsg owns this memory now */ - CtdlSubmitMsg(imsg, NULL, SMTP_SPOOLOUT_ROOM, QP_EADDR); - CM_Free(imsg); - } - /* * Any addresses to harvest for someone's address book? */ @@ -3083,6 +2939,9 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ } } + if ((recps != NULL) && (recps->bounce_to == bounce_to)) + recps->bounce_to = NULL; + /* Done. */ return(newmsgid); } @@ -3100,7 +2959,7 @@ void quickie_message(const char *from, const char *subject) { struct CtdlMessage *msg; - struct recptypes *recp = NULL; + recptypes *recp = NULL; msg = malloc(sizeof(struct CtdlMessage)); memset(msg, 0, sizeof(struct CtdlMessage)); @@ -3109,29 +2968,31 @@ void quickie_message(const char *from, msg->cm_format_type = format_type; if (from != NULL) { - msg->cm_fields[eAuthor] = strdup(from); + CM_SetField(msg, eAuthor, from, strlen(from)); } else if (fromaddr != NULL) { - msg->cm_fields[eAuthor] = strdup(fromaddr); - if (strchr(msg->cm_fields[eAuthor], '@')) { - *strchr(msg->cm_fields[eAuthor], '@') = 0; + char *pAt; + CM_SetField(msg, eAuthor, fromaddr, strlen(fromaddr)); + pAt = strchr(msg->cm_fields[eAuthor], '@'); + if (pAt != NULL) { + CM_CutFieldAt(msg, eAuthor, pAt - msg->cm_fields[eAuthor]); } } else { msg->cm_fields[eAuthor] = strdup("Citadel"); } - if (fromaddr != NULL) msg->cm_fields[erFc822Addr] = strdup(fromaddr); - if (room != NULL) msg->cm_fields[eOriginalRoom] = strdup(room); - msg->cm_fields[eNodeName] = strdup(NODENAME); + 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) { - msg->cm_fields[eRecipient] = strdup(to); + CM_SetField(msg, eRecipient, to, strlen(to)); recp = validate_recipients(to, NULL, 0); } if (subject != NULL) { - msg->cm_fields[eMsgSubject] = strdup(subject); + CM_SetField(msg, eMsgSubject, subject, strlen(subject)); } - msg->cm_fields[eMesageText] = strdup(text); + CM_SetField(msg, eMesageText, text, strlen(text)); CtdlSubmitMsg(msg, recp, room, 0); CM_Free(msg); @@ -3465,6 +3326,45 @@ char *CtdlReadMessageBody(char *terminator, /* token signalling EOT */ return SmashStrBuf(&Message); } +struct CtdlMessage *CtdlMakeMessage( + struct ctdluser *author, /* author's user structure */ + char *recipient, /* NULL if it's not mail */ + char *recp_cc, /* NULL if it's not mail */ + char *room, /* room where it's going */ + int type, /* see MES_ types in header file */ + int format_type, /* variformat, plain text, MIME... */ + char *fake_name, /* who we're masquerading as */ + char *my_email, /* which of my email addresses to use (empty is ok) */ + char *subject, /* Subject (optional) */ + char *supplied_euid, /* ...or NULL if this is irrelevant */ + char *preformatted_text, /* ...or NULL to read text from client */ + char *references /* Thread references */ +) +{ + return CtdlMakeMessageLen( + author, /* author's user structure */ + recipient, /* NULL if it's not mail */ + (recipient)?strlen(recipient) : 0, + recp_cc, /* NULL if it's not mail */ + (recp_cc)?strlen(recp_cc): 0, + room, /* room where it's going */ + (room)?strlen(room): 0, + type, /* see MES_ types in header file */ + format_type, /* variformat, plain text, MIME... */ + fake_name, /* who we're masquerading as */ + (fake_name)?strlen(fake_name): 0, + my_email, /* which of my email addresses to use (empty is ok) */ + (my_email)?strlen(my_email): 0, + subject, /* Subject (optional) */ + (subject)?strlen(subject): 0, + supplied_euid, /* ...or NULL if this is irrelevant */ + (supplied_euid)?strlen(supplied_euid):0, + preformatted_text, /* ...or NULL to read text from client */ + (preformatted_text)?strlen(preformatted_text) : 0, + references, /* Thread references */ + (references)?strlen(references):0); + +} /* * Build a binary message to be saved on disk. @@ -3474,21 +3374,34 @@ char *CtdlReadMessageBody(char *terminator, /* token signalling EOT */ * the rest of the fields when CM_Free() is called.) */ -struct CtdlMessage *CtdlMakeMessage( +struct CtdlMessage *CtdlMakeMessageLen( struct ctdluser *author, /* author's user structure */ char *recipient, /* NULL if it's not mail */ + long rcplen, char *recp_cc, /* NULL if it's not mail */ + long cclen, char *room, /* room where it's going */ + long roomlen, int type, /* see MES_ types in header file */ int format_type, /* variformat, plain text, MIME... */ char *fake_name, /* who we're masquerading as */ + long fnlen, char *my_email, /* which of my email addresses to use (empty is ok) */ + long myelen, char *subject, /* Subject (optional) */ + long subjlen, char *supplied_euid, /* ...or NULL if this is irrelevant */ + long euidlen, char *preformatted_text, /* ...or NULL to read text from client */ - char *references /* Thread references */ - ) { - char dest_node[256]; + long textlen, + char *references, /* Thread references */ + long reflen + ) +{ + struct CitContext *CCC = CC; + /* Don't confuse the poor folks if it's not routed mail. * / + char dest_node[256] = "";*/ + long blen; char buf[1024]; struct CtdlMessage *msg; StrBuf *FakeAuthor; @@ -3500,68 +3413,58 @@ struct CtdlMessage *CtdlMakeMessage( msg->cm_anon_type = type; msg->cm_format_type = format_type; - /* Don't confuse the poor folks if it's not routed mail. */ - strcpy(dest_node, ""); - - if (recipient != NULL) striplt(recipient); - if (recp_cc != NULL) striplt(recp_cc); + if (recipient != NULL) rcplen = striplt(recipient); + if (recp_cc != NULL) cclen = striplt(recp_cc); /* Path or Return-Path */ - if (my_email == NULL) my_email = ""; - - if (!IsEmptyStr(my_email)) { - msg->cm_fields[eMessagePath] = strdup(my_email); + if (myelen > 0) { + CM_SetField(msg, eMessagePath, my_email, myelen); } else { - snprintf(buf, sizeof buf, "%s", author->fullname); - msg->cm_fields[eMessagePath] = strdup(buf); + CM_SetField(msg, eMessagePath, author->fullname, strlen(author->fullname)); } convert_spaces_to_underscores(msg->cm_fields[eMessagePath]); - snprintf(buf, sizeof buf, "%ld", (long)time(NULL)); /* timestamp */ - msg->cm_fields[eTimestamp] = strdup(buf); + blen = snprintf(buf, sizeof buf, "%ld", (long)time(NULL)); + CM_SetField(msg, eTimestamp, buf, blen); - if ((fake_name != NULL) && (fake_name[0])) { /* author */ - FakeAuthor = NewStrBufPlain (fake_name, -1); + if (fnlen > 0) { + FakeAuthor = NewStrBufPlain (fake_name, fnlen); } else { FakeAuthor = NewStrBufPlain (author->fullname, -1); } StrBufRFC2047encode(&FakeEncAuthor, FakeAuthor); - msg->cm_fields[eAuthor] = SmashStrBuf(&FakeEncAuthor); + CM_SetAsFieldSB(msg, eAuthor, &FakeEncAuthor); FreeStrBuf(&FakeAuthor); - if (CC->room.QRflags & QR_MAILBOX) { /* room */ - msg->cm_fields[eOriginalRoom] = strdup(&CC->room.QRname[11]); + if (CCC->room.QRflags & QR_MAILBOX) { /* room */ + CM_SetField(msg, eOriginalRoom, &CCC->room.QRname[11], strlen(&CCC->room.QRname[11])); } else { - msg->cm_fields[eOriginalRoom] = strdup(CC->room.QRname); + CM_SetField(msg, eOriginalRoom, CCC->room.QRname, strlen(CCC->room.QRname)); } - msg->cm_fields[eNodeName] = strdup(NODENAME); /* nodename */ - msg->cm_fields[eHumanNode] = strdup(HUMANNODE); /* hnodename */ + CM_SetField(msg, eNodeName, CFG_KEY(c_nodename)); + CM_SetField(msg, eHumanNode, CFG_KEY(c_humannode)); - if ((recipient != NULL) && (recipient[0] != 0)) { - msg->cm_fields[eRecipient] = strdup(recipient); + if (rcplen > 0) { + CM_SetField(msg, eRecipient, recipient, rcplen); } - if ((recp_cc != NULL) && (recp_cc[0] != 0)) { - msg->cm_fields[eCarbonCopY] = strdup(recp_cc); - } - if (dest_node[0] != 0) { - msg->cm_fields[eDestination] = strdup(dest_node); + if (cclen > 0) { + CM_SetField(msg, eCarbonCopY, recp_cc, cclen); } - if (!IsEmptyStr(my_email)) { - msg->cm_fields[erFc822Addr] = strdup(my_email); + if (myelen > 0) { + CM_SetField(msg, erFc822Addr, my_email, myelen); } - else if ( (author == &CC->user) && (!IsEmptyStr(CC->cs_inet_email)) ) { - msg->cm_fields[erFc822Addr] = strdup(CC->cs_inet_email); + else if ( (author == &CCC->user) && (!IsEmptyStr(CCC->cs_inet_email)) ) { + CM_SetField(msg, erFc822Addr, CCC->cs_inet_email, strlen(CCC->cs_inet_email)); } if (subject != NULL) { long length; - striplt(subject); - length = strlen(subject); + length = striplt(subject); if (length > 0) { long i; long IsAscii; @@ -3571,30 +3474,34 @@ struct CtdlMessage *CtdlMakeMessage( (IsAscii = isascii(subject[i]) != 0 )) i++; if (IsAscii != 0) - msg->cm_fields[eMsgSubject] = strdup(subject); + CM_SetField(msg, eMsgSubject, subject, subjlen); else /* ok, we've got utf8 in the string. */ { - msg->cm_fields[eMsgSubject] = rfc2047encode(subject, length); + char *rfc2047Subj; + rfc2047Subj = rfc2047encode(subject, length); + CM_SetAsField(msg, eMsgSubject, &rfc2047Subj, strlen(rfc2047Subj)); } } } - if (supplied_euid != NULL) { - msg->cm_fields[eExclusiveID] = strdup(supplied_euid); + if (euidlen > 0) { + CM_SetField(msg, eExclusiveID, supplied_euid, euidlen); } - if ((references != NULL) && (!IsEmptyStr(references))) { - if (msg->cm_fields[eWeferences] != NULL) - free(msg->cm_fields[eWeferences]); - msg->cm_fields[eWeferences] = strdup(references); + if (reflen > 0) { + CM_SetField(msg, eWeferences, references, reflen); } if (preformatted_text != NULL) { - msg->cm_fields[eMesageText] = preformatted_text; + CM_SetField(msg, eMesageText, preformatted_text, textlen); } else { - msg->cm_fields[eMesageText] = CtdlReadMessageBody(HKEY("000"), config.c_maxmsglen, NULL, 0, 0); + StrBuf *MsgBody; + MsgBody = CtdlReadMessageBodyBuf(HKEY("000"), config.c_maxmsglen, NULL, 0, 0); + if (MsgBody != NULL) { + CM_SetAsFieldSB(msg, eMesageText, &MsgBody); + } } return(msg); @@ -4028,7 +3935,7 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ struct ctdlroom qrbuf; char roomname[ROOMNAMELEN]; struct CtdlMessage *msg; - char *encoded_message = NULL; + StrBuf *encoded_message = NULL; if (is_mailbox != NULL) { CtdlMailboxName(roomname, sizeof roomname, is_mailbox, req_room); @@ -4040,39 +3947,28 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ MSG_syslog(LOG_DEBUG, "Raw length is %ld\n", (long)raw_length); if (is_binary) { - encoded_message = malloc((size_t) (((raw_length * 134) / 100) + 4096 ) ); + encoded_message = NewStrBufPlain(NULL, (size_t) (((raw_length * 134) / 100) + 4096 ) ); } else { - encoded_message = malloc((size_t)(raw_length + 4096)); + encoded_message = NewStrBufPlain(NULL, (size_t)(raw_length + 4096)); } - sprintf(encoded_message, "Content-type: %s\n", content_type); + StrBufAppendBufPlain(encoded_message, HKEY("Content-type: "), 0); + StrBufAppendBufPlain(encoded_message, content_type, -1, 0); + StrBufAppendBufPlain(encoded_message, HKEY("\n"), 0); if (is_binary) { - sprintf(&encoded_message[strlen(encoded_message)], - "Content-transfer-encoding: base64\n\n" - ); + StrBufAppendBufPlain(encoded_message, HKEY("Content-transfer-encoding: base64\n\n"), 0); } else { - sprintf(&encoded_message[strlen(encoded_message)], - "Content-transfer-encoding: 7bit\n\n" - ); + StrBufAppendBufPlain(encoded_message, HKEY("Content-transfer-encoding: 7bit\n\n"), 0); } if (is_binary) { - CtdlEncodeBase64( - &encoded_message[strlen(encoded_message)], - raw_message, - (int)raw_length, - 0 - ); + StrBufBase64Append(encoded_message, NULL, raw_message, raw_length, 0); } else { - memcpy( - &encoded_message[strlen(encoded_message)], - raw_message, - (int)(raw_length+1) - ); + StrBufAppendBufPlain(encoded_message, raw_message, raw_length, 0); } MSGM_syslog(LOG_DEBUG, "Allocating\n"); @@ -4081,13 +3977,13 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ msg->cm_magic = CTDLMESSAGE_MAGIC; msg->cm_anon_type = MES_NORMAL; msg->cm_format_type = 4; - msg->cm_fields[eAuthor] = strdup(CCC->user.fullname); - msg->cm_fields[eOriginalRoom] = strdup(req_room); - msg->cm_fields[eNodeName] = strdup(config.c_nodename); - msg->cm_fields[eHumanNode] = strdup(config.c_humannode); + 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)); msg->cm_flags = flags; - msg->cm_fields[eMesageText] = encoded_message; + CM_SetAsFieldSB(msg, eMesageText, &encoded_message); /* Create the requested room if we have to. */ if (CtdlGetRoom(&qrbuf, roomname) != 0) {