diff options
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); +} |
