head 1.23;
access;
symbols
SOURCE_RESTRUCTURING_BEFORE:1.22
LMTP2NNTP_1_2a1:1.22
LMTP2NNTP_1_1_1:1.22
LMTP2NNTP_1_1_0:1.18
LMTP2NNTP_1_1b4:1.18
LMTP2NNTP_1_1b3:1.18
LMTP2NNTP_1_1b2:1.18
LMTP2NNTP_1_1b1:1.18
LMTP2NNTP_1_0_0:1.18
LMTP2NNTP_0_9_7:1.18
LMTP2NNTP_0_9_6:1.18
LMTP2NNTP_0_9_5:1.18
LMTP2NNTP_0_9_4:1.15
LMTP2NNTP_0_9_3:1.14
LMTP2NNTP_0_9_2:1.9
LMTP2NNTP_0_9_1:1.5
LMTP2NNTP_0_9_0:1.5;
locks; strict;
comment @ * @;
1.23
date 2001.12.31.11.09.53; author thl; state dead;
branches;
next 1.22;
1.22
date 2001.11.14.14.37.10; author thl; state Exp;
branches;
next 1.21;
1.21
date 2001.11.14.14.32.36; author thl; state Exp;
branches;
next 1.20;
1.20
date 2001.11.14.14.25.47; author thl; state Exp;
branches;
next 1.19;
1.19
date 2001.11.14.14.22.25; author thl; state Exp;
branches;
next 1.18;
1.18
date 2001.09.12.14.35.14; author thl; state Exp;
branches;
next 1.17;
1.17
date 2001.09.11.13.41.22; author thl; state Exp;
branches;
next 1.16;
1.16
date 2001.09.04.09.46.06; author rse; state Exp;
branches;
next 1.15;
1.15
date 2001.08.30.13.57.21; author thl; state Exp;
branches;
next 1.14;
1.14
date 2001.08.28.14.24.03; author thl; state Exp;
branches;
next 1.13;
1.13
date 2001.08.28.11.31.22; author thl; state Exp;
branches;
next 1.12;
1.12
date 2001.08.27.14.49.32; author thl; state Exp;
branches;
next 1.11;
1.11
date 2001.08.27.14.29.11; author thl; state Exp;
branches;
next 1.10;
1.10
date 2001.08.27.13.45.53; author thl; state Exp;
branches;
next 1.9;
1.9
date 2001.08.23.09.12.30; author rse; state Exp;
branches;
next 1.8;
1.8
date 2001.08.23.08.36.53; author rse; state Exp;
branches;
next 1.7;
1.7
date 2001.08.23.07.54.06; author thl; state Exp;
branches;
next 1.6;
1.6
date 2001.08.21.07.40.41; author thl; state Exp;
branches;
next 1.5;
1.5
date 2001.08.16.15.00.50; author thl; state Exp;
branches;
next 1.4;
1.4
date 2001.08.14.14.42.41; author thl; state Exp;
branches;
next 1.3;
1.3
date 2001.08.14.08.15.25; author thl; state Exp;
branches;
next 1.2;
1.2
date 2001.08.13.15.16.32; author thl; state Exp;
branches;
next 1.1;
1.1
date 2001.08.13.06.41.41; author thl; state Exp;
branches;
next ;
desc
@@
1.23
log
@Mega-Commit: Finally restructure the lmtp2nntp source tree in order to clean
it up. We especially use a consistent prefix for all inlined sources.
@
text
@/*
** Copyright (c) 2001 The OSSP Project
** Copyright (c) 2001 Cable & Wireless Deutschland
**
** This file is part of OSSP lmtp2nntp, an LMTP speaking local
** mailer which forwards mails as Usenet news articles via NNTP.
** It can be found at http://www.ossp.org/pkg/lmtp2nntp/.
**
** 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
** 2.0 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 file; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
** USA, or contact the OSSP project .
**
** msg.c: mail message manipulation library
*/
#include
#include
#include "msg.h"
#include "str.h"
#include "argz.h"
/* third party */
#include "l2.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#if defined(HAVE_DMALLOC_H) && defined(DMALLOC)
#include "dmalloc.h"
#endif
msg_t *msg_create(void)
{
msg_t *msg;
if ((msg = (msg_t *)malloc(sizeof(msg_t))) == NULL)
return NULL;
msg->azEnvgroups = NULL;
msg->asEnvgroups = 0;
msg->cpMsg = NULL;
msg->azHeaders = NULL;
msg->asHeaders = 0;
msg->cpFid = NULL;
msg->cpBody = NULL;
msg->cpMsgid = NULL;
msg->mail_from = NULL;
msg->azRcpt = NULL;
msg->asRcpt = 0;
msg->azNewsgroups = NULL;
msg->asNewsgroups = 0;
msg->l2 = NULL; /* this is a copy only */
return msg;
}
void msg_destroy(msg_t *msg)
{
if (msg == NULL)
return;
if (msg->azEnvgroups != NULL)
free(msg->azEnvgroups);
if (msg->cpMsg != NULL)
free(msg->cpMsg);
if (msg->azHeaders != NULL)
free(msg->azHeaders);
if (msg->cpFid != NULL)
free(msg->cpFid);
if (msg->cpBody != NULL)
free(msg->cpBody);
if (msg->cpMsgid != NULL)
free(msg->cpMsgid);
if (msg->mail_from != NULL)
free(msg->mail_from);
if (msg->azRcpt != NULL)
free(msg->azRcpt);
if (msg->azNewsgroups != NULL)
free(msg->azNewsgroups);
msg->l2 = NULL; /* this is a copy only, the "parent" needs to clean this up */
free(msg);
return;
}
msg_rc_t msg_split(msg_t *msg)
{
char *cpName;
char *cpValue;
char *cpRem; /* Remainder */
char *cp;
char *cpHeaders;
/* INPUTS
*
* msg->cpMsg
* must contain the wholly RFC0822 formatted message with native
* (unescaped) dots at the beginning of a line, the 'From ' envelope,
* headers, double newline, body, NUL, no trailing dot;
*
* OUTPUTS
*
* msg->cpMsg
* free()d and set to NULL
*
* msg->azHeaders, msg->asHeaders contains the headers in argz format, one
* logical NUL-terminated line per header which might be wrapped into
* multiple '\n'-ended physical lines. The "From " envelope, "Received:",
* "Path:", "To:" and "Cc:" headers are removed silently. The
* "Newsgroups:" and "Message-ID" headers are removed and their values are
* stored in separate structures (see below).
*
* msg->cpBody
* contains the unmodified body of the message, NUL-terminated, no
* trailing dot.
*
* msg->cpMsgid
* contains the message id including surrounding angle brackets.
*
* msg->azNewsgroups, asNewsgroups
* is a argz-type array of strings containing the Newsgroups based on the
* header information.
*/
log0(msg, DEBUG, "split message into header and body");
if (str_parse(msg->cpMsg, "m/((?:.*?)\\n)\\n(.*)$/s", &cpHeaders, &msg->cpBody) <= 0)
return MSG_ERR_SPLITHEADBODY;
free(msg->cpMsg);
msg->cpMsg = NULL;
log0(msg, DEBUG, "replace envelope From w/o colon by X-F: pseudotag");
/* This eliminates the special case of having one header, which is really
* an embedded envelope, not ending with a colon while all others do.
* After splitting headers into name and value pairs this envelope ist
* stripped off.
*/
if (strncasecmp(cpHeaders, "From", 4) == 0)
memcpy(cpHeaders, "X-F:", 4);
log0(msg, DEBUG, "unwrap header lines");
/* poor man's s///g simulator as current str library doesn't support global substitution */
while (str_parse(cpHeaders, "s/(.*?)\\n[ \\t]+(.*)/$1 $2/s", &cpRem) > 0) {
free(cpHeaders);
cpHeaders = cpRem;
}
log0(msg, DEBUG, "split header lines into names and values");
while (str_parse(cpHeaders, "m/^[> \\t]*([\\x21-\\x7e]+?:)[ \\t]*([^\\n]*?)[ \\t]*\\n(.*)/s", &cpName, &cpValue, &cpRem) > 0) {
free(cpHeaders);
cpHeaders = cpRem;
argz_add(&msg->azHeaders, &msg->asHeaders, cpName);
argz_add(&msg->azHeaders, &msg->asHeaders, cpValue);
free(cpName);
free(cpValue);
}
log0(msg, DEBUG, "check for headers we care about and do whatever neccessary");
msg->cpMsgid = NULL;
msg->azNewsgroups = NULL;
msg->asNewsgroups = 0;
cp = msg->azHeaders;
while (cp != NULL) {
log1(msg, DEBUG, "processing header \"%s\"", cp);
if (strcasecmp("X-F:", cp) == 0) {
argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del name */
argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del value */
continue;
}
if (strcasecmp("Path:", cp) == 0) {
argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del name */
argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del value */
continue;
}
if (strcasecmp("Received:", cp) == 0) {
argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del name */
if ((msg->cpFid == NULL) &&
(str_parse(cp, "m/\\sid\\s+([\\w\\d]{1,30})/i", &msg->cpFid) > 0))
log1(msg, DEBUG, "found foreign-ID \"%s\" for logging", msg->cpFid);
argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del value */
continue;
}
if (strcasecmp("To:", cp) == 0) {
argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del name */
argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del value */
continue;
}
if (strcasecmp("Cc:", cp) == 0) {
argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del name */
argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del value */
continue;
}
if (strcasecmp("Message-ID:", cp) == 0) {
if (msg->cpMsgid != NULL)
return MSG_ERR_SPLITIDMULTI;
argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del name */
if ((cp == NULL) || (strlen(cp) == 0)) /* get value */
return MSG_ERR_SPLITIDEMPTY;
if ((msg->cpMsgid = strdup(cp)) == NULL)
return MSG_ERR_MEM;
argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del value */
continue;
}
if (strcasecmp("Newsgroups:", cp) == 0) {
argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del name */
if (argz_add(&msg->azNewsgroups, &msg->asNewsgroups, cp) != 0) /* get value */
return MSG_ERR_MEM;
argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del value */
continue;
}
if ((cp = argz_next(msg->azHeaders, msg->asHeaders, cp)) == NULL) /* next value */
break;
if ((cp = argz_next(msg->azHeaders, msg->asHeaders, cp)) == NULL) /* next name */
break;
}
log0(msg, DEBUG, "checking Message-ID");
if (msg->cpMsgid == NULL)
return MSG_ERR_SPLITIDNONE;
log0(msg, DEBUG, "checking Newsgroups");
if (msg->azNewsgroups != NULL) {
argz_stringify(msg->azNewsgroups, msg->asNewsgroups, ',');
if (argz_create_sep(msg->azNewsgroups, ',', &msg->azNewsgroups, &msg->asNewsgroups) != 0)
return MSG_ERR_MEM;
}
log0(msg, DEBUG, "adding mandatory Path: header");
argz_add(&msg->azHeaders, &msg->asHeaders, "Path:");
argz_add(&msg->azHeaders, &msg->asHeaders, "lmtp2nntp!not-for-mail");
log0(msg, DEBUG, "split complete");
return MSG_OK;
}
msg_rc_t msg_join(msg_t *msg)
{
char *cp;
char *cpRem;
char **aHeaders;
int i;
int o;
char *cpCut;
char *cpWrap;
char c;
char cOld;
int n;
char *cpHeaders;
char *azNewheaders;
size_t asNewheaders;
log0(msg, DEBUG, "verify Newsgroups");
if (msg->azNewsgroups == NULL)
return MSG_ERR_JOINGROUPNONE;
argz_stringify(msg->azNewsgroups, msg->asNewsgroups, ',');
if (strlen(msg->azNewsgroups) == 0)
return MSG_ERR_JOINGROUPEMPTY;
argz_add(&msg->azHeaders, &msg->asHeaders, "Newsgroups:");
argz_add(&msg->azHeaders, &msg->asHeaders, msg->azNewsgroups);
log0(msg, DEBUG, "verify Message-ID");
if (msg->cpMsgid == NULL)
return MSG_ERR_JOINIDNONE;
if (strlen(msg->cpMsgid) == 0)
return MSG_ERR_JOINIDEMPTY;
argz_add(&msg->azHeaders, &msg->asHeaders, "Message-ID:");
argz_add(&msg->azHeaders, &msg->asHeaders, msg->cpMsgid);
log0(msg, DEBUG, "merge name/value pairs into single string");
argz_add(&msg->azHeaders, &msg->asHeaders, ""); /* append empty string */
if ((aHeaders = (char **)malloc((argz_count(msg->azHeaders, msg->asHeaders) + 1) * sizeof(char *))) == NULL)
return MSG_ERR_MEM;
argz_extract(msg->azHeaders, msg->asHeaders, aHeaders);
/* replace the trailing NUL, which is *(cp-1) of the predecessor, with a
* space at every second string. Break action when terminating NULL string
* is detected */
i=0;
while(1) {
if ((cp = aHeaders[++i]) == NULL)
break;
*(cp-1) = ' ';
if ((cp = aHeaders[++i]) == NULL)
break;
}
free(aHeaders);
log0(msg, DEBUG, "fold headers");
/* A logical line is split into one or more physical '\n'-terminated
* lines. The physical line is never longer than WRAPAT characters. This
* includes the folded data and the header name + colon + space for the
* first line and WRAPUSING string prefix for all other lines. Leading and
* trailing blanks of folded lines are removed while blanks inside the
* line are preserved. The header is never left alone in a physical line.
* Fragments exceeding WRAPAT characters without having a blank as a
* splitting point are forcibly cut at a non-blank character.
*/
azNewheaders = NULL;
asNewheaders = 0;
cp = NULL;
while ((cp = argz_next(msg->azHeaders, msg->asHeaders, cp)) != NULL) {
if (strlen(cp) > WRAPAT) {
cpRem = cp;
cpWrap = NULL;
for (o = 0; (cpRem[o] != ':') && (cpRem[o] != NUL); o++); /* offset name so at least one char of value remains in first line */
o += 2; /* skip ": " */
while ((strlen(cpRem) + (cpWrap == NULL ? 0 : strlen(WRAPUSING))) > WRAPAT) {
for (i = WRAPAT - 1 - (cpWrap == NULL ? 0 :
strlen(WRAPUSING)); (i >= o) && !isspace((int)cpRem[i]); i--);
if (i < o)
i = WRAPAT - 1 - (cpWrap == NULL ? 0 : strlen(WRAPUSING) - 1); /* sorry, forced cut at non-blank */
cpCut = cpRem;
cpRem += i;
for (; (isspace((int)*cpRem) && (*cpRem != NUL)); cpRem++); /* skip next lines leading blanks */
for (; (i >= o) && isspace((int)cpCut[i-1]); i--); /* chop off this lines trailing blanks */
if (i >= o) { /* only keep line fragment if some non-blanks inside */
if (cpWrap == NULL) {
if ((cpWrap = (char *)malloc(i+strlen(WRAPUSING)+1)) == NULL)
return MSG_ERR_MEM;
*cpWrap = NUL;
o = 1;
}
else {
if ((cpWrap = (char *)realloc(cpWrap, strlen(cpWrap)+i+strlen(WRAPUSING)+1)) == NULL)
return MSG_ERR_MEM;
strcat(cpWrap, WRAPUSING);
}
strncat(cpWrap, cpCut, i);
}
}
if (strlen(cpRem) > 0) {
if ((cpWrap = (char *)realloc(cpWrap, strlen(cpWrap)+strlen(cpRem)+strlen(WRAPUSING)+1)) == NULL)
return MSG_ERR_MEM;
strcat(cpWrap, WRAPUSING);
strcat(cpWrap, cpRem);
}
argz_add(&azNewheaders, &asNewheaders, cpWrap);
log2(msg, DEBUG, "a folded header \"%{text}D\"", cpWrap, strlen(cpWrap));
free(cpWrap);
}
else {
argz_add(&azNewheaders, &asNewheaders, cp);
log2(msg, DEBUG, "verbatim header \"%{text}D\"", cp, strlen(cp));
}
}
free(msg->azHeaders);
msg->azHeaders = azNewheaders;
msg->asHeaders = asNewheaders;
log0(msg, DEBUG, "strigify headers");
argz_stringify(msg->azHeaders, msg->asHeaders, '\n');
cpHeaders = msg->azHeaders;
/********************************************************************
* header + CRLF + body + '.' + CRLF + NUL, replacing NL with CRLF *
********************************************************************/
log0(msg, DEBUG, "assemble header and body");
n = 0;
/* count size of headers, reserve space for NL to CRLF conversion */
for (i = 0; ((c = cpHeaders[i]) != NUL); i++) {
if (c == '\n')
n++;
n++;
}
/* if headers don't end with NL, reserve space for CRLF */
if (i >= 0 && cpHeaders[i - 1] != '\n')
n+=2;
/* reserve space for CRLF between headers and body */
n+=2;
/* count size of body, reserve space for NL-DOT escape and NL to CRLF conversion */
cOld = '\n';
for (i = 0; ((c = msg->cpBody[i]) != NUL); i++) {
if (c == '\n')
n++;
if (c == '.' && cOld == '\n')
n++;
n++;
cOld = c;
}
/* if body doesn't end with NL, reserve space for CRLF */
if (i >= 0 && msg->cpBody[i - 1] != '\n')
n+=2;
/* reserve space for terminating '.'-CRLF-NUL at the end of the message */
n+=4;
if ((msg->cpMsg = (char *)malloc(n)) == NULL)
return MSG_ERR_MEM;
n = 0;
/* copy headers, do NL to CRLF conversion */
for (i = 0; ((c = cpHeaders[i]) != NUL); i++) {
if (c == '\n')
msg->cpMsg[n++] = '\r';
msg->cpMsg[n++] = c;
}
/* if headers don't end with NL, append CRLF */
if (i >= 0 && cpHeaders[i - 1] != '\n') {
msg->cpMsg[n++] = '\r';
msg->cpMsg[n++] = '\n';
}
/* add CRLF between headers and body */
msg->cpMsg[n++] = '\r';
msg->cpMsg[n++] = '\n';
/* copy body, do NL-DOT escape and NL to CRLF conversion */
cOld = '\n';
for (i = 0; ((c = msg->cpBody[i]) != NUL); i++) {
if (c == '\n')
msg->cpMsg[n++] = '\r';
if (c == '.' && cOld == '\n')
msg->cpMsg[n++] = '.';
msg->cpMsg[n++] = c;
cOld = c;
}
/* if body doesn't end with NL, append CRLF */
if (i >= 0 && msg->cpBody[i - 1] != '\n') {
msg->cpMsg[n++] = '\r';
msg->cpMsg[n++] = '\n';
}
/* add terminating '.'-CRLF-NUL at the end of the message */
msg->cpMsg[n++] = '.';
msg->cpMsg[n++] = '\r';
msg->cpMsg[n++] = '\n';
msg->cpMsg[n] = NUL;
log0(msg, DEBUG, "join complete");
return MSG_OK;
}
char *msg_error(msg_rc_t rc)
{
char *str;
str = "MSG: no description";
if (rc == MSG_OK ) str = "MSG: no error";
else if (rc == MSG_ERR_MEM ) str = "MSG: memory";
else if (rc == MSG_ERR_SPLITHEADBODY ) str = "MSG: split into header and body failed";
else if (rc == MSG_ERR_SPLITLEN ) str = "MSG: header is too short";
else if (rc == MSG_ERR_SPLITMISSINGFROM ) str = "MSG: header is missing 'From ' envelope";
else if (rc == MSG_ERR_SPLITIDNONE ) str = "MSG: header is missing 'Message-ID'";
else if (rc == MSG_ERR_SPLITIDEMPTY ) str = "MSG: header has empty 'Message-ID'";
else if (rc == MSG_ERR_SPLITIDMULTI ) str = "MSG: header has multiple 'Message-ID's";
else if (rc == MSG_ERR_JOINGROUPNONE ) str = "MSG: join with no 'Newsgroup'";
else if (rc == MSG_ERR_JOINGROUPEMPTY ) str = "MSG: join with empty 'Newsgroup'";
else if (rc == MSG_ERR_JOINIDNONE ) str = "MSG: join with no 'Message-ID'";
else if (rc == MSG_ERR_JOINIDEMPTY ) str = "MSG: join with empty 'Message-ID'";
return str;
}
@
1.22
log
@ricudis@@paiko.gr - How about adding a custom entry on the Path: header on
gated messages, so the news system can distinguish messages that should be
passed back to the mailing list on doubly gated mailing lists?
Path: lmtp2nntp!not-for-mail
and placing in the INN newsfeeds file :
news2mail-feed/lmtp2nntp:*:blah blah blah
would prevent loops caused by messages gated to Usenet by lmtp2nntp then
forwarded back to their origination message-list by the newsfeed feeding the
Usenet->mail side of the gateway.
@
text
@@
1.21
log
@allow indented headers and respect RFC0822 character range - ricudis@@paiko.gr
@
text
@d242 1
a242 1
argz_add(&msg->azHeaders, &msg->asHeaders, "not-for-mail");
@
1.20
log
@msg.c
@
text
@@
1.19
log
@ALERT! The line folding algorithm in LMTP2NNTP_1_1_0 had a bug when wrapping
long lines. It used argz_insert() inside an iteration loop while manipulating
the elements the loop's based on. When the element being inserted did not fit
into the previously allocated buffer, a realloc() occured. This rendered the
iteration loop pointer invalid causing the code to write into the wilderness.
This caused segfaults at the very best but it also happend that the folding
code hung in an arbitrary loop effectively exhausting all available CPU
horsepower. This happend on our live machine and was reported by
ricudis@@paiko.gr, too. This fix is the ultimate reason for releasing
LMTP2NNTP_1_1_1.
@
text
@d161 1
a161 1
while (str_parse(cpHeaders, "m/^([\\w-]+?:)[ \\t]*([^\\n]*?)[ \\t]*\\n(.*)/s", &cpName, &cpValue, &cpRem) > 0) {
@
1.18
log
@fixed a memory leak
@
text
@d261 2
d309 2
d348 2
a349 2
argz_delete(&msg->azHeaders, &msg->asHeaders, cp);
argz_insert(&msg->azHeaders, &msg->asHeaders, cp, cpWrap);
d352 4
d357 3
@
1.17
log
@msg.c is now l2 enabled; improved logging using foreign (aka sendmail queuing)
id; now calculating and logging message size;
@
text
@d166 2
@
1.16
log
@Finally apply GNU General Public License (GPL) to OSSP lmtp2nntp.
@
text
@d34 3
d56 1
d64 1
d80 2
d92 1
d137 1
a137 1
/* split message into header and body */
d144 5
a148 4
/* replace envelope From w/o colon by X-F: pseudotag. This eliminates the
* special case of having one header, which is really an embedded
* envelope, not ending with a colon while all others do. After splitting
* headers into name and value pairs this envelope ist stripped off.
d153 1
a153 1
/* unwrap header lines */
d160 1
a160 1
/* split header lines into names and values */
d168 1
a168 1
/* check for headers we care about and do whatever neccessary */
d174 1
d187 3
d226 2
d231 1
d237 2
d242 1
d260 1
a260 1
/* verify asNewsgroups */
d269 1
a269 1
/* verify Message-ID */
d277 1
a277 1
/* merge name/value pairs into single string */
d295 2
a296 3
/* fold headers
*
* A logical line is split into one or more physical '\n'-terminated
d348 1
d356 1
d424 1
@
1.15
log
@get rid of warnings by properly casting char to int for isdigit()
@
text
@d1 25
d28 2
a32 1
#include
@
1.14
log
@isblank() not available on solaris8 - replaced by isspace()
@
text
@d269 2
a270 1
for (i = WRAPAT - 1 - (cpWrap == NULL ? 0 : strlen(WRAPUSING)); (i >= o) && !isspace(cpRem[i]); i--);
d275 2
a276 2
for (; (isspace(*cpRem) && (*cpRem != NUL)); cpRem++); /* skip next lines leading blanks */
for (; (i >= o) && isspace(cpCut[i-1]); i--); /* chop off this lines trailing blanks */
@
1.13
log
@reduced dmalloc() complaints about non-free()d resources during one a "lmtp
post arg cw.de.sd.apps.dev.test" run to zero regarding own code; A memoryleak
in str library 0.9.5 was detected which was reported to and fixed by RSE;
@
text
@d269 1
a269 1
for (i = WRAPAT - 1 - (cpWrap == NULL ? 0 : strlen(WRAPUSING)); (i >= o) && !isblank(cpRem[i]); i--);
d274 2
a275 2
for (; (isblank(*cpRem) && (*cpRem != NUL)); cpRem++); /* skip next lines leading blanks */
for (; (i >= o) && isblank(cpCut[i-1]); i--); /* chop off this lines trailing blanks */
@
1.12
log
@now using NUL instead of '\0'
@
text
@d81 3
d106 3
@
1.11
log
@removed DEBUGs; updated 00TODO;
@
text
@d77 1
a77 1
* headers, double newline, body, '\0', no trailing dot;
d82 1
a82 1
* logical '\0'-terminated line per header which might be wrapped into
d89 1
a89 1
* contains the unmodified body of the message, '\0'-terminated, no
d231 1
a231 1
/* replace the trailing '\0', which is *(cp-1) of the predecessor, with a
d260 1
a260 1
for (o = 0; (cpRem[o] != ':') && (cpRem[o] != '\0'); o++); /* offset name so at least one char of value remains in first line */
d268 1
a268 1
for (; (isblank(*cpRem) && (*cpRem != '\0')); cpRem++); /* skip next lines leading blanks */
d274 1
a274 1
*cpWrap = '\0';
d301 1
a301 1
* header + CRLF + body + '.' + CRLF + '\0', replacing NL with CRLF *
d306 1
a306 1
for (i = 0; ((c = cpHeaders[i]) != '\0'); i++) {
d318 1
a318 1
for (i = 0; ((c = msg->cpBody[i]) != '\0'); i++) {
d337 1
a337 1
for (i = 0; ((c = cpHeaders[i]) != '\0'); i++) {
d352 1
a352 1
for (i = 0; ((c = msg->cpBody[i]) != '\0'); i++) {
d369 1
a369 1
msg->cpMsg[n] = '\0';
@
1.10
log
@worked out all FIXMEs in msg.c; renamed SPLITSPLITBODY to SPLITHEADBODY - this
was a search'n'replace accident; major changes in the "fold headers"
functionality in msg_join(); modified str_parse calls to (re)use the now fixed
[^not] operator; made workarounds for missing str_parse() functionality "s//g"
and "malloc optimization" permanent; reviewed "Path: not-for-mail" issue and
kept it as is; the "testmessage.vialmtp" now contains very long headers to be
wrapped/ folded; updated 00TODO;
@
text
@a161 1
/*fprintf(stderr, "DEBUG: Message-ID cp = ***%s***\n", cp); */
a170 1
/*fprintf(stderr, "DEBUG: Newsgroups cp = ***%s***\n", cp); */
a212 1
/*fprintf(stderr, "DEBUG: join consolidated azNewsgroups = ***%s***\n", msg->azNewsgroups); */
a370 1
/*fprintf(stderr, "DEBUG: Message = ***%s***\n", msg->cpMsg); */
@
1.9
log
@Add DMalloc support
@
text
@d42 1
a42 1
/*FIXME what about non-graceful aborts? */
d102 1
a102 1
return MSG_ERR_SPLITSPLITBODY;
d113 1
a113 1
/*FIXME poor man's s///g simulator as current str library doesn't support //global substitution */
d120 1
a120 6
/*FIXME str enhancement requests and bugs to be fixed */
/*FIXME - fix bug "not" [^...] working */
/*FIXME - improve str_parse(foo, "...", &foo) should free foo() on it's own */
/*FIXME - add "global" in s/search/replace/g (see above "unwrap hader lines") */
while (str_parse(cpHeaders, "m/^([\\w-]+?:)[ \\t]*(.*?)[ \\t]*\\n(.*)/s",
&cpName, &cpValue, &cpRem) > 0) {
d192 1
a192 1
argz_add(&msg->azHeaders, &msg->asHeaders, "not-for-mail"); /*FIXME */
d203 1
d247 11
a257 1
/* fold headers */
d260 1
a260 1
if (strlen(cp) >= WRAPAT) {
d263 23
a285 17
while (strlen(cpRem) >= WRAPAT) {
for (i = WRAPAT; i >= 1 && (cpRem[i] != ' ') && (cpRem[i] != '\t'); i--);
if (i == 0)
i = WRAPAT; /* sorry, hard cut at non-whitespace */
if (i < WRAPAT)
i++; /* we don't care about the whitespace itself */
cpCut = str_dup(cpRem, i);
/*FIXME 1.) continue searching downwards skipping all whitespaces and 2.) as we know the length replace str_dup/ strcat/ free with strncat only */
if (cpWrap == NULL) {
if ((cpWrap = (char *)malloc(strlen(cpCut)+strlen(WRAPUSING)+1)) == NULL)
return MSG_ERR_MEM;
*cpWrap = '\0';
}
else {
if ((cpWrap = (char *)realloc(cpWrap, strlen(cpWrap)+strlen(cpCut)+strlen(WRAPUSING)+1)) == NULL)
return MSG_ERR_MEM;
strcat(cpWrap, WRAPUSING);
a286 3
strcat(cpWrap, cpCut);
free(cpCut);
cpRem += i;
a287 2
for (i = 0; i < strlen(cpRem) && ((cpRem[i] == ' ') || (cpRem[i] == '\t')); i++);
cpRem += i;
d384 1
a384 1
else if (rc == MSG_ERR_SPLITSPLITBODY ) str = "MSG: split into header and body failed";
@
1.8
log
@adjust for recently fixed return code semantic of str_parse()
@
text
@d8 7
@
1.7
log
@cosmetic correction make all RFC references match RFC\d{4} allowing to grep for them when writing documentation
@
text
@d94 1
a94 1
if (!str_parse(msg->cpMsg, "m/((?:.*?)\\n)\\n(.*)$/s", &cpHeaders, &msg->cpBody))
d107 1
a107 1
while (str_parse(cpHeaders, "s/(.*?)\\n[ \\t]+(.*)/$1 $2/s", &cpRem)) {
d117 2
a118 1
while (str_parse(cpHeaders, "m/^([\\w-]+?:)[ \\t]*(.*?)[ \\t]*\\n(.*)/s", &cpName, &cpValue, &cpRem)) {
@
1.6
log
@replaced c++ style // comments with c style /* */ comments
@
text
@d68 1
a68 1
* must contain the wholly RFC822 formatted message with native
@
1.5
log
@INN kludge, IHAVE feeding, -d deliverymode command line option, DEFER handing
@
text
@d35 1
a35 1
//FIXME what about non-graceful aborts?
d106 1
a106 1
//FIXME poor man's s///g simulator as current str library doesn't support //global substitution
d113 4
a116 4
//FIXME str enhancement requests and bugs to be fixed
//FIXME - fix bug "not" [^...] working
//FIXME - improve str_parse(foo, "...", &foo) should free foo() on it's own
//FIXME - add "global" in s/search/replace/g (see above "unwrap hader lines")
d159 1
a159 1
//fprintf(stderr, "DEBUG: Message-ID cp = ***%s***\n", cp);
d169 1
a169 1
//fprintf(stderr, "DEBUG: Newsgroups cp = ***%s***\n", cp);
d189 1
a189 1
argz_add(&msg->azHeaders, &msg->asHeaders, "not-for-mail"); //FIXME
d211 1
a211 1
//fprintf(stderr, "DEBUG: join consolidated azNewsgroups = ***%s***\n", msg->azNewsgroups);
d256 1
a256 1
//FIXME 1.) continue searching downwards skipping all whitespaces and 2.) as we know the length replace str_dup/ strcat/ free with strncat only
d359 1
a359 1
//fprintf(stderr, "DEBUG: Message = ***%s***\n", msg->cpMsg);
@
1.4
log
@connected LMTP and NNTP side, now featuring all three -g groupmodes, added post1000 articles burn-in
@
text
@d77 3
a79 3
* "To:" and "Cc:" headers are removed silently. The "Newsgroups:" and
* "Message-ID" headers are removed and their values are stored in
* separate structures (see below).
d135 5
d188 2
@
1.3
log
@cleanup msg.[ch], moved tracing to trace.[ch], added target to Makefile, added -t switch in lmtp2nntp.[c|pod], incorporated tracing into lmtp.[ch] and nntp.[ch], run.sh now using new tracing option
@
text
@d15 2
d36 2
d76 4
a79 4
* multiple '\n'-ended physical lines. The "From " envelope, "To:" and
* "Cc:" headers are removed silently. The "Newsgroups:" and "Message-ID"
* headers are removed and their values are stored in separate structures
* (see below).
d100 1
a100 1
* headers into name and value pairs this action is reversed.
d102 2
a103 5
if (strlen(cpHeaders) < 4)
return MSG_ERR_SPLITLEN;
if (strncasecmp(cpHeaders, "From", 4) != 0)
return MSG_ERR_SPLITMISSINGFROM;
memcpy(cpHeaders, "X-F:", 4);
a123 3
/* reverse the 'From ' to 'X-F: ' replacement */
memcpy(msg->azHeaders, "From", 4); /* replace envelope X-F: pseudotag with From w/o colon */
d130 6
a135 1
if (strcasecmp("From", cp) == 0) {
d356 1
a356 1
char *msg_error(msg_t *msg, msg_rc_t rc)
@
1.2
log
@first successful posting
@
text
@d15 5
a24 6
msg->azHeaders = NULL;
msg->asHeaders = 0;
msg->cpMsg = NULL;
msg->cpHeaders = NULL;
msg->cpBody = NULL;
msg->cpMsgid = NULL;
d34 8
a45 2
if (msg->azHeaders != NULL)
free(msg->azHeaders);
d48 1
a48 6
if (msg->cpMsg != NULL)
free(msg->cpMsg);
if (msg->cpHeaders != NULL)
free(msg->cpHeaders);
if (msg->cpBody != NULL)
free(msg->cpBody);
d50 1
d57 1
a57 1
char *cpRem;
d59 1
d70 6
a75 6
* msg->azHeaders, msg->asHeaders
* contains the headers in argz format, one logical '\0'-terminated line
* per header which might be wrapped into multiple '\n'-ended physical
* lines. The "To:" and "Cc:" headers are silently. The "Newsgroups:" and
* "Message-ID" headers are removed and their values are stored in
* separate structures (see below).
d90 1
a90 1
if (!str_parse(msg->cpMsg, "m/((?:.*?)\\n)\\n(.*)$/s", &msg->cpHeaders, &msg->cpBody))
d95 1
a95 1
* envelope, not ending with a colon while all other do. After splitting
d98 1
a98 1
if (strlen(msg->cpHeaders) < 4)
d100 1
a100 1
if (strncasecmp(msg->cpHeaders, "From", 4) != 0)
d102 1
a102 1
memcpy(msg->cpHeaders, "X-F:", 4);
d106 3
a108 3
while (str_parse(msg->cpHeaders, "s/(.*?)\\n[ \\t]+(.*)/$1 $2/s", &cpRem)) {
free(msg->cpHeaders);
msg->cpHeaders = cpRem;
d116 3
a118 3
while (str_parse(msg->cpHeaders, "m/^([\\w-]+?:)[ \\t]*(.*?)[ \\t]*\\n(.*)/s", &cpName, &cpValue, &cpRem)) {
free(msg->cpHeaders);
msg->cpHeaders = cpRem;
a191 1
char *cpNew;
d193 1
d195 1
d217 2
a218 3
if ((aHeaders = (char **)malloc((argz_count(msg->azHeaders,
msg->asHeaders) + 1) * sizeof(char *))) == NULL)
exit(1); //FIXME
d220 3
a229 1
// *(cp-1) = '\n';
d231 1
a233 3
//FIXME where to place this defines best
#define WRAPAT 120
#define WRAPUSING "\n "
d249 1
a249 1
exit(1); //FIXME
d254 1
a254 1
exit(1); //FIXME
d265 1
a265 1
exit(1); //FIXME
d276 1
a276 22
msg->cpHeaders = msg->azHeaders;
if (argz_create_sep(msg->cpBody, '\n', &msg->azBody, &msg->asBody) != 0)
return MSG_ERR_MEM;
/* escape dots at the beginning of each line */
cp = NULL;
while ((cp =argz_next(msg->azBody, msg->asBody, cp)) != NULL) {
if (*cp == '.') {
if ((cpNew = malloc(strlen(cp) + 1)) == NULL)
return MSG_ERR_MEM;
*cpNew = '.';
cpNew++;
*cpNew = '\0';
strcat(cpNew, cp);
argz_delete(&msg->azBody, &msg->asBody, cp);
argz_insert(&msg->azBody, &msg->asBody, cp, cpNew);
}
}
argz_stringify(msg->azBody, msg->asBody, '\n');
msg->cpBody = msg->azBody;
d284 1
a284 1
for (i = 0; ((c = msg->cpHeaders[i]) != '\0'); i++) {
d290 1
a290 1
if (i >= 0 && msg->cpHeaders[i - 1] != '\n')
d294 2
a295 1
/* count size of body, reserve space for NL to CRLF conversion */
d299 2
d302 1
d315 1
a315 1
for (i = 0; ((c = msg->cpHeaders[i]) != '\0'); i++) {
d321 1
a321 1
if (i >= 0 && msg->cpHeaders[i - 1] != '\n') {
d328 2
a329 1
/* copy body, do NL to CRLF conversion */
d333 2
d336 1
a349 1
@
1.1
log
@moved message issues from lmtp2nntp.[ch] and nntp.[ch] into separate new file msg.[ch]
@
text
@d130 5
d191 2
d297 29
a325 1
if ((msg->cpMsg = malloc(strlen(msg->cpHeaders) + 1 + strlen(msg->cpBody) + 2 + 1)) == NULL)
d327 32
a358 5
*msg->cpMsg = '\0'; /* + 1 in the end */
strcat(msg->cpMsg, msg->cpHeaders);
strcat(msg->cpMsg, "\n"); /* + 1 */
strcat(msg->cpMsg, msg->cpBody);
strcat(msg->cpMsg, ".\n"); /* + 2 */
@