diff options
| author | Sam Varshavchik | 2013-08-19 16:39:41 -0400 | 
|---|---|---|
| committer | Sam Varshavchik | 2013-08-25 14:43:51 -0400 | 
| commit | 9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch) | |
| tree | 7a81a04cb51efb078ee350859a64be2ebc6b8813 /rfc2045/rfc2045rewrite.c | |
| parent | a9520698b770168d1f33d6301463bb70a19655ec (diff) | |
| download | courier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2 | |
Initial checkin
Imported from subversion report, converted to git. Updated all paths in
scripts and makefiles, reflecting the new directory hierarchy.
Diffstat (limited to 'rfc2045/rfc2045rewrite.c')
| -rw-r--r-- | rfc2045/rfc2045rewrite.c | 441 | 
1 files changed, 441 insertions, 0 deletions
| diff --git a/rfc2045/rfc2045rewrite.c b/rfc2045/rfc2045rewrite.c new file mode 100644 index 0000000..89bc6e7 --- /dev/null +++ b/rfc2045/rfc2045rewrite.c @@ -0,0 +1,441 @@ +/* +** Copyright 1998 - 2011 Double Precision, Inc.  See COPYING for +** distribution information. +*/ + +#if	HAVE_CONFIG_H +#include "rfc2045_config.h" +#endif +#include	"rfc2045.h" +#include	"rfc2045charset.h" +#include	"rfc822/encode.h" +#include	"rfc822/rfc822hdr.h" +#if	HAVE_UNISTD_H +#include	<unistd.h> +#endif +#include	<stdio.h> +#include	<stdlib.h> +#include	<ctype.h> +#include       <string.h> +#if    HAVE_STRINGS_H +#include       <strings.h> +#endif + + +static char *rw_boundary_root; +static int rw_boundary_cnt; +static const char *rw_appname; + +static int fdout; +static int (*fdout_func)(const char *, int, void *); +static void *fdout_arg; + +static char fdout_buf[512]; +static char *fdout_ptr; +static size_t fdout_left; +static int conv_err; + +static int fdout_flush() +{ +int	n=fdout_ptr-fdout_buf; +int	i=0; +char	*p=fdout_buf; + +	while (n) +	{ +		i=fdout_func ? (*fdout_func)(p, n, fdout_arg): +				write(fdout, p, n); +		if (i <= 0)	return (-1); +		p += i; +		n -= i; +	} +	fdout_ptr=fdout_buf; +	fdout_left=sizeof(fdout_buf); +	return (0); +} + +static int fdout_add(const char *p, size_t cnt) +{ +	while (cnt) +	{ +		if (cnt < fdout_left) +		{ +			memcpy(fdout_ptr, p, cnt); +			fdout_ptr += cnt; +			fdout_left -= cnt; +			return (0); +		} +		if (fdout_left == 0) +		{ +			if (fdout_flush())	return (-1); +			continue; +		} +		memcpy(fdout_ptr, p, fdout_left); +		p += fdout_left; +		cnt -= fdout_left; +		fdout_ptr += fdout_left; +		fdout_left=0; +	} +	return (0); +} + +static int do_8bit(const char *p, size_t cnt, void *ptr) +{ +	if (fdout_add(p, cnt)) +		conv_err=1; +	return (0); +} + +static int fdout_autoconverted(const char *oldte, const char *newte) +{ +	if (fdout_add("X-Mime-Autoconverted: from ", 27) || +		fdout_add(oldte, strlen(oldte)) || +		fdout_add(" to ", 4) || +		fdout_add(newte, strlen(newte)) || +		(rw_appname && (fdout_add(" by ", 4) || +			fdout_add(rw_appname, strlen(rw_appname)))) || +		fdout_add("\n", 1))	return (-1); +	return (0); +} + +static int fdout_value(const char *); + +static int fdout_attr(const struct rfc2045attr *a) +{ +	if (fdout_add(a->name, strlen(a->name)))	return (-1); +	if (a->value && (fdout_add("=", 1) || fdout_value(a->value))) +		return (-1); +	return (0); +} + +static int fdout_value(const char *v) +{ +size_t i,j; + +	for (i=0; v[i]; i++) +	{ +		if ( !isalnum((int)(unsigned char)v[i]) && v[i] != '-') +		{ +			if (fdout_add("\"", 1))	return (-1); +			for (j=i=0; v[i]; i++) +				if (v[i] == '\\' || v[i] == '"') +				{ +					if (fdout_add(v+j, i-j) || +						fdout_add("\\", 1)) +						return (-1); +					j=i; +				} +			if (fdout_add(v+j, i-j) || fdout_add("\"", 1)) +				return (-1); +			return (0); +		} +	} +	return (fdout_add(v, i)); +} + +static int fdout_add_qp(const char *ptr, size_t cnt, void *dummy) +{ +	return (fdout_add(ptr, cnt)); +} + +static int qpe_do(const char *p, size_t i, void *ptr) +{ +	return libmail_encode( (struct libmail_encode_info *)ptr, p, i); +} + +#define	TE(p)	((p)->rw_transfer_encoding ? \ +		(p)->rw_transfer_encoding: (p)->content_transfer_encoding) + +static int rwmime(struct rfc2045 *p) +{ +static char mimever[]="Mime-Version: 1.0\n"; +const char *te; +struct	rfc2045attr *a; + +	if (!p->parent) +		if (fdout_add(mimever, sizeof(mimever)-1))	return (-1); + +	if (p->content_type) +	{ +		if (fdout_add("Content-Type: ", 14) || +			fdout_add(p->content_type, strlen(p->content_type))) +			return (-1); + +		for (a=p->content_type_attr; a; a=a->next) +		{ +			if (!a->name || strcmp(a->name, "boundary") == 0) +				continue; +			if ( fdout_add("; ", 2) || +				fdout_attr(a))	return (-1); +		} +	} + +	if (p->firstpart +		&& p->firstpart->next /* ADDED 8/30/99, see below */) +	{ +	char	buf[80]; + +		++rw_boundary_cnt; +		sprintf(buf, "-%d", rw_boundary_cnt); +		if ( fdout_add("; boundary=\"", 12) || +			fdout_add(rw_boundary_root, strlen(rw_boundary_root)) || +			fdout_add(buf, strlen(buf)) || +			fdout_add("\"", 1))	return (-1); +	} +	if (fdout_add("\n", 1))	return (-1); + +	/* +	** Show content transfer encoding, unless this is a multipart +	** section. +	*/ + +	te=TE(p); +	if (te && p->firstpart == NULL) +	{ +		if (fdout_add("Content-Transfer-Encoding: ", 27) || +			fdout_add(te, strlen(te)) || +			fdout_add("\n", 1))	return (-1); +	} +	return (0); +} + +static int dorw(struct rfc2045 *p, struct rfc2045src *src) +{ +	int seen_mime=0; +	char	buf[BUFSIZ]; +	struct libmail_encode_info qp_encode; +	int	bcnt; +	struct rfc2045headerinfo *hdr; +	char *name, *value; + +	/* Slurp the untouchable portion of multipart/signed */ + +#if 1 +	if (p->parent && p->parent->content_type && +	    strcasecmp(p->parent->content_type, "multipart/signed") == 0 && +	    p->next) +	{ +		off_t ps=p->startpos; + +		if ((*src->seek_func)(ps, src->arg) == (off_t)-1) +			return (-1); + +		while (ps < p->endbody) +		{ +			ssize_t n; + +			if (p->endbody - ps > sizeof(buf)) +				n=sizeof(buf); +			else	n=p->endbody-ps; +			n=(*src->read_func)(buf, n, src->arg); +			if (n <= 0)	return (-1); + +			if (fdout_add(buf, n))	return (-1); +			ps += n; +		} +		return (0); +	} +#endif + +	if (p->parent) +	{ +		seen_mime=1; +		if (rwmime(p))	return (-1); +	} + +	hdr=rfc2045header_start(src, p); + +	while (1) +	{ +		if (rfc2045header_get(hdr, &name, &value, +				      RFC2045H_NOLC | RFC2045H_KEEPNL) < 0) +		{ +			rfc2045header_end(hdr); +			return (-1); +		} + +		if (name == NULL) +			break; + +		if (RFC2045_ISMIME1DEF(p->mime_version) && +		    rfc822hdr_namecmp(name, "mime-version") == 0 && +			!seen_mime) +		{ +			seen_mime=1; +			rwmime(p); +			continue; +		} + +		if (!RFC2045_ISMIME1DEF(p->mime_version) || +		    (rfc822hdr_namecmp(name, "mime-version") && +		     rfc822hdr_namecmp(name, "content-type") && +		     rfc822hdr_namecmp(name, "content-transfer-encoding"))) +		{ +			if (fdout_add(name, strlen(name)) || +			    fdout_add(": ", 2) || +			    fdout_add(value, strlen(value)) || +			    fdout_add("\n", 1)) +			{ +				rfc2045header_end(hdr); +				return (-1); +			} +		} +	} +	rfc2045header_end(hdr); + +	if (RFC2045_ISMIME1DEF(p->mime_version)) +	{ +		if (!seen_mime) +			if (rwmime(p))	return (-1); + +		if (!p->firstpart && p->rw_transfer_encoding) +			if (fdout_autoconverted(p->content_transfer_encoding, +				p->rw_transfer_encoding))	return (-1); +	} + +	if (fdout_add("\n", 1))	return (-1); + +	if ((*src->seek_func)(p->startbody, src->arg) == (off_t)-1) +		return (-1); + +	/* For non-multipart section, just print the body */ + +	if (!p->firstpart) +	{ +	off_t	ps=p->startbody; +	int	convmode=0; + +		if (p->rw_transfer_encoding) +		{ +			if ( strcasecmp(p->rw_transfer_encoding, +				"quoted-printable") == 0) +				convmode=RFC2045_RW_7BIT; +			else +				convmode=RFC2045_RW_8BIT; +		} + +		conv_err=0; +		if (convmode == RFC2045_RW_7BIT) +		{ +			libmail_encode_start(&qp_encode, +					     "quoted-printable", +					     fdout_add_qp, NULL); +			rfc2045_cdecode_start(p, &qpe_do, &qp_encode); +		} + +		if (convmode == RFC2045_RW_8BIT) +		{ +			rfc2045_cdecode_start(p, &do_8bit, 0); +		} + +		while (ps < p->endbody) +		{ +		int	n; + +			if (p->endbody - ps > sizeof(buf)) +				n=sizeof(buf); +			else	n=p->endbody-ps; +			n=(*src->read_func)(buf, n, src->arg); +			if (n <= 0)	return (-1); +			if (convmode) +				rfc2045_cdecode(p, buf, n); +			else	if (fdout_add(buf, n))	conv_err=1; +			ps += n; +			if (conv_err)	break; +		} +		if (convmode == RFC2045_RW_7BIT) +		{ +			rfc2045_cdecode_end(p); +			if (libmail_encode_end(&qp_encode)) +				conv_err=1; +		} +		if (convmode == RFC2045_RW_8BIT) +		{ +			rfc2045_cdecode_end(p); +		} +		if (conv_err)	return (-1); +		return (0); +	} + +	bcnt=rw_boundary_cnt; + +	/* Sam 8/30/99 fix - handle message/rfc822: + +            --boundary +            Content-Type: message/rfc822 + +         --><-- we're here, DON'T add RFC2045MIMEMSG and rest of crap here +	*/ +	if (p->firstpart->next == 0) +	{ +	int	rc; + +		p->firstpart->parent=0; +		rc=dorw(p->firstpart, src); +		p->firstpart->parent=p; +		return (rc); +	} + +	if (fdout_add(RFC2045MIMEMSG, sizeof(RFC2045MIMEMSG)-1)) +		return (-1); +	for (p=p->firstpart; p; p=p->next) +	{ +		if (p->isdummy)	continue; +		sprintf(buf, "\n--%s-%d\n", rw_boundary_root, bcnt); +		if (fdout_add(buf, strlen(buf)))	return (-1); +		if (dorw(p, src) != 0)	return(-1); +	} +	sprintf(buf, "\n--%s-%d--\n", rw_boundary_root, bcnt); +	if (fdout_add(buf, strlen(buf)))	return (-1); +	return (0); +} + +static int rfc2045_rewrite_common(struct rfc2045 *, struct rfc2045src *src, +				  const char *); + +int rfc2045_rewrite(struct rfc2045 *p, struct rfc2045src *src, int fdout_arg, +		    const char *appname) +{ +	fdout=fdout_arg; +	fdout_func=0; +	return (rfc2045_rewrite_common(p, src, appname)); +} + +int rfc2045_rewrite_func(struct rfc2045 *p, struct rfc2045src *src, +	int (*funcarg)(const char *, int, void *), void *funcargarg, +	const char *appname) +{ +	fdout= -1; +	fdout_func=funcarg; +	fdout_arg=funcargarg; +	return (rfc2045_rewrite_common(p, src, appname)); +} + +static int rfc2045_rewrite_common(struct rfc2045 *p, +				   struct rfc2045src *src, const char *appname) +{ +	int	rc; + +	rw_appname=appname; + +	fdout_ptr=fdout_buf; +	fdout_left=sizeof(fdout_buf); + +	rw_boundary_root=rfc2045_mk_boundary(p, src); +	if (rw_boundary_root == 0) +		rc= -1; +	else +	{ +		rw_boundary_cnt=1; +		rc=dorw(p, src); +		free(rw_boundary_root); +	} +	if (rc == 0 && fdout_ptr > fdout_buf +	    && fdout_ptr[-1] != '\n') +	{ +		fdout_add("\n", 1); +	} +	if (rc == 0 && fdout_ptr > fdout_buf) +		rc=fdout_flush(); +	return (rc); +} | 
