From 4d7b86eab71baaed6a1953e4d1968a0988456661 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Wilfried=20G=C3=B6esgens?= Date: Wed, 10 Feb 2010 23:32:09 +0000 Subject: [PATCH] * migrate convert_internet_message to StrBuf, the new approach saves tons of strlens, strcpy's and friends --- citadel/internet_addressing.c | 142 ++++++++++++++++++++----------- citadel/internet_addressing.h | 2 + citadel/modules/smtp/serv_smtp.c | 6 +- citadel/msgbase.c | 42 +++++++-- citadel/msgbase.h | 9 ++ 5 files changed, 141 insertions(+), 60 deletions(-) diff --git a/citadel/internet_addressing.c b/citadel/internet_addressing.c index ca1dffd19..1a8bdea12 100644 --- a/citadel/internet_addressing.c +++ b/citadel/internet_addressing.c @@ -367,22 +367,44 @@ int fuzzy_match(struct ctdluser *us, char *matchstring) { /* * Unfold a multi-line field into a single line, removing multi-whitespaces */ -void unfold_rfc822_field(char *field) { - int i; +void unfold_rfc822_field(char **field, char **FieldEnd) +{ int quote = 0; + char *pField = *field; + char *sField; + char *pFieldEnd = *FieldEnd; + + while (isspace(*pField)) + pField++; + /* remove leading/trailing whitespace */ + ; - striplt(field); /* remove leading/trailing whitespace */ + while (isspace(*pFieldEnd)) + pFieldEnd --; + *FieldEnd = pFieldEnd; /* convert non-space whitespace to spaces, and remove double blanks */ - for (i=0; icm_fields['M']; /* M field contains rfc822 text */ - for (i = end; i >= beg; --i) { - if (rfc822[i] == ':') colonpos = i; + for (pos = end; pos >= beg; pos--) { + if (*pos == ':') colonpos = pos; } if (colonpos < 0) return(0); /* no colon? not a valid header line */ - key = malloc((end - beg) + 2); - safestrncpy(key, &rfc822[beg], (end-beg)+1); - key[colonpos - beg] = 0; + len = end - beg; + key = malloc(len + 2); + memcpy(key, beg, len + 1); + key[len] = '\0'; + valueend = key + len; + * ( key + (colonpos - beg) ) = '\0'; value = &key[(colonpos - beg) + 1]; - unfold_rfc822_field(value); + unfold_rfc822_field(&value, &valueend); + valuelen = valueend - value; /* * Here's the big rfc822-to-citadel loop. @@ -579,25 +606,25 @@ int convert_field(struct CtdlMessage *msg, int beg, int end) { else if (!strcasecmp(key, "Subject")) { if (msg->cm_fields['U'] == NULL) - msg->cm_fields['U'] = strdup(value); + msg->cm_fields['U'] = strndup(value, valuelen); processed = 1; } else if (!strcasecmp(key, "List-ID")) { if (msg->cm_fields['L'] == NULL) - msg->cm_fields['L'] = strdup(value); + msg->cm_fields['L'] = strndup(value, valuelen); processed = 1; } else if (!strcasecmp(key, "To")) { if (msg->cm_fields['R'] == NULL) - msg->cm_fields['R'] = strdup(value); + msg->cm_fields['R'] = strndup(value, valuelen); processed = 1; } else if (!strcasecmp(key, "CC")) { if (msg->cm_fields['Y'] == NULL) - msg->cm_fields['Y'] = strdup(value); + msg->cm_fields['Y'] = strndup(value, valuelen); processed = 1; } @@ -607,7 +634,7 @@ int convert_field(struct CtdlMessage *msg, int beg, int end) { } if (msg->cm_fields['I'] == NULL) { - msg->cm_fields['I'] = strdup(value); + msg->cm_fields['I'] = strndup(value, valuelen); /* Strip angle brackets */ while (haschar(msg->cm_fields['I'], '<') > 0) { @@ -624,13 +651,13 @@ int convert_field(struct CtdlMessage *msg, int beg, int end) { else if (!strcasecmp(key, "Return-Path")) { if (msg->cm_fields['P'] == NULL) - msg->cm_fields['P'] = strdup(value); + msg->cm_fields['P'] = strndup(value, valuelen); processed = 1; } else if (!strcasecmp(key, "Envelope-To")) { if (msg->cm_fields['V'] == NULL) - msg->cm_fields['V'] = strdup(value); + msg->cm_fields['V'] = strndup(value, valuelen); processed = 1; } @@ -638,13 +665,13 @@ int convert_field(struct CtdlMessage *msg, int beg, int end) { if (msg->cm_fields['W'] != NULL) { free(msg->cm_fields['W']); } - msg->cm_fields['W'] = strdup(value); + msg->cm_fields['W'] = strndup(value, valuelen); processed = 1; } else if (!strcasecmp(key, "In-reply-to")) { if (msg->cm_fields['W'] == NULL) { /* References: supersedes In-reply-to: */ - msg->cm_fields['W'] = strdup(value); + msg->cm_fields['W'] = strndup(value, valuelen); } processed = 1; } @@ -700,12 +727,21 @@ void convert_references_to_wefewences(char *str) { * again. */ struct CtdlMessage *convert_internet_message(char *rfc822) { + StrBuf *RFCBuf = NewStrBufPlain(rfc822, -1); + free (rfc822); + return convert_internet_message_buf(&RFCBuf); +} + + +struct CtdlMessage *convert_internet_message_buf(StrBuf **rfc822) +{ struct CtdlMessage *msg; - int pos, beg, end, msglen; - int done; + const char *pos, *beg, *end, *totalend; + int done, alldone = 0; char buf[SIZ]; int converted; + StrBuf *OtherHeaders; msg = malloc(sizeof(struct CtdlMessage)); if (msg == NULL) return msg; @@ -714,36 +750,40 @@ struct CtdlMessage *convert_internet_message(char *rfc822) { msg->cm_magic = CTDLMESSAGE_MAGIC; /* self check */ msg->cm_anon_type = 0; /* never anonymous */ msg->cm_format_type = FMT_RFC822; /* internet message */ - msg->cm_fields['M'] = rfc822; - pos = 0; + pos = ChrPtr(*rfc822); + totalend = pos + StrLength(*rfc822); done = 0; + OtherHeaders = NewStrBufPlain(NULL, StrLength(*rfc822)); - while (!done) { + while (!alldone) { /* Locate beginning and end of field, keeping in mind that * some fields might be multiline */ - beg = pos; - end = (-1); + end = beg = pos; - msglen = strlen(rfc822); - while ( (end < 0) && (done == 0) ) { + while ((end < totalend) && + (end == beg) && + (done == 0) ) + { - if ((rfc822[pos]=='\n') - && (!isspace(rfc822[pos+1]))) { + if ((*pos=='\n') && + (!isspace(*(pos+1)))) + { end = pos; } /* done with headers? */ - if ( (rfc822[pos]=='\n') - && ( (rfc822[pos+1]=='\n') - ||(rfc822[pos+1]=='\r')) ) { - end = pos; - done = 1; + if ((*pos=='\n') && + ( (*(pos+1)=='\n') || + (*(pos+1)=='\r')) ) + { + alldone = 1; } - if (pos >= (msglen-1) ) { + if (pos >= (totalend - 1) ) + { end = pos; done = 1; } @@ -756,14 +796,18 @@ struct CtdlMessage *convert_internet_message(char *rfc822) { converted = convert_field(msg, beg, end); /* Strip the field out of the RFC822 header if we used it */ - if (converted) { - strcpy(&rfc822[beg], &rfc822[pos]); - pos = beg; + if (!converted) { + StrBufAppendBufPlain(OtherHeaders, beg, end - beg, 0); } /* If we've hit the end of the message, bail out */ - if (pos > strlen(rfc822)) done = 1; + if (pos >= totalend) + alldone = 1; } + if (pos < totalend) + StrBufAppendBufPlain(OtherHeaders, pos, totalend - pos, 0); + FreeStrBuf(rfc822); + msg->cm_fields['M'] = SmashStrBuf(&OtherHeaders); /* Follow-up sanity checks... */ diff --git a/citadel/internet_addressing.h b/citadel/internet_addressing.h index 60f741049..0a31c2662 100644 --- a/citadel/internet_addressing.h +++ b/citadel/internet_addressing.h @@ -23,6 +23,8 @@ void CtdlDirectoryAddUser(char *internet_addr, char *citadel_addr); void CtdlDirectoryDelUser(char *internet_addr, char *citadel_addr); int CtdlDirectoryLookup(char *target, char *internet_addr, size_t targbuflen); struct CtdlMessage *convert_internet_message(char *rfc822); +struct CtdlMessage *convert_internet_message_buf(StrBuf **rfc822); + int CtdlHostAlias(char *fqdn); char *harvest_collected_addresses(struct CtdlMessage *msg); diff --git a/citadel/modules/smtp/serv_smtp.c b/citadel/modules/smtp/serv_smtp.c index cc8057f8b..2647a83a0 100644 --- a/citadel/modules/smtp/serv_smtp.c +++ b/citadel/modules/smtp/serv_smtp.c @@ -667,7 +667,7 @@ void smtp_rcpt(char *argbuf) { * Implements the DATA command */ void smtp_data(void) { - char *body; + StrBuf *body; struct CtdlMessage *msg = NULL; long msgnum = (-1L); char nowstamp[SIZ]; @@ -713,14 +713,14 @@ void smtp_data(void) { nowstamp); } } - body = CtdlReadMessageBody(HKEY("."), config.c_maxmsglen, body, 1, 0); + body = CtdlReadMessageBodyBuf(HKEY("."), config.c_maxmsglen, body, 1, 0); if (body == NULL) { cprintf("550 Unable to save message: internal error.\r\n"); return; } CtdlLogPrintf(CTDL_DEBUG, "Converting message...\n"); - msg = convert_internet_message(body); + msg = convert_internet_message_buf(&body); /* If the user is locally authenticated, FORCE the From: header to * show up as the real sender. Yes, this violates the RFC standard, diff --git a/citadel/msgbase.c b/citadel/msgbase.c index ef7bdf8c0..700e12288 100644 --- a/citadel/msgbase.c +++ b/citadel/msgbase.c @@ -3223,13 +3223,13 @@ void quickie_message(const char *from, const char *fromaddr, char *to, char *roo /* * Back end function used by CtdlMakeMessage() and similar functions */ -char *CtdlReadMessageBody(char *terminator, /* token signalling EOT */ - long tlen, - size_t maxlen, /* maximum message length */ - char *exist, /* if non-null, append to it; - exist is ALWAYS freed */ - int crlf, /* CRLF newlines instead of LF */ - int sock /* socket handle or 0 for this session's client socket */ +StrBuf *CtdlReadMessageBodyBuf(char *terminator, /* token signalling EOT */ + long tlen, + size_t maxlen, /* maximum message length */ + char *exist, /* if non-null, append to it; + exist is ALWAYS freed */ + int crlf, /* CRLF newlines instead of LF */ + int sock /* socket handle or 0 for this session's client socket */ ) { StrBuf *Message; @@ -3288,10 +3288,36 @@ char *CtdlReadMessageBody(char *terminator, /* token signalling EOT */ if (StrLength(Message) >= maxlen) flushing = 1; } while (!finished); - return SmashStrBuf(&Message); + FreeStrBuf(&LineBuf); + return Message; } +/* + * Back end function used by CtdlMakeMessage() and similar functions + */ +char *CtdlReadMessageBody(char *terminator, /* token signalling EOT */ + long tlen, + size_t maxlen, /* maximum message length */ + char *exist, /* if non-null, append to it; + exist is ALWAYS freed */ + int crlf, /* CRLF newlines instead of LF */ + int sock /* socket handle or 0 for this session's client socket */ + ) +{ + StrBuf *Message; + + Message = CtdlReadMessageBodyBuf(terminator, + tlen, + maxlen, + exist, + crlf, + sock); + if (Message == NULL) + return NULL; + else + return SmashStrBuf(&Message); +} /* diff --git a/citadel/msgbase.h b/citadel/msgbase.h index 854cefee4..3202c1e6f 100644 --- a/citadel/msgbase.h +++ b/citadel/msgbase.h @@ -147,6 +147,15 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms int do_repl_check, struct CtdlMessage *supplied_msg); int CtdlSaveMsgPointerInRoom(char *roomname, long msgid, int do_repl_check, struct CtdlMessage *msg); char *CtdlReadMessageBody(char *terminator, long tlen, size_t maxlen, char *exist, int crlf, int sock); +StrBuf *CtdlReadMessageBodyBuf(char *terminator, /* token signalling EOT */ + long tlen, + size_t maxlen, /* maximum message length */ + char *exist, /* if non-null, append to it; + exist is ALWAYS freed */ + int crlf, /* CRLF newlines instead of LF */ + int sock /* socket handle or 0 for this session's client socket */ + ); + 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? */ -- 2.30.2