diff options
author | cvs2svn <cvs2svn@FreeBSD.org> | 1997-02-05 04:29:56 +0000 |
---|---|---|
committer | cvs2svn <cvs2svn@FreeBSD.org> | 1997-02-05 04:29:56 +0000 |
commit | 860c2cf2bc6592828a3468ab8ee661042b059ae8 (patch) | |
tree | fde30676422ab07fdec2d11fde3fc5693fdbb8cf /usr.sbin/sendmail/src/mime.c | |
parent | b61013aa0c73c687493c80193bc040d29b351fb8 (diff) |
Diffstat (limited to 'usr.sbin/sendmail/src/mime.c')
-rw-r--r-- | usr.sbin/sendmail/src/mime.c | 341 |
1 files changed, 329 insertions, 12 deletions
diff --git a/usr.sbin/sendmail/src/mime.c b/usr.sbin/sendmail/src/mime.c index 1c71a84ac6bbd..9ee726adb1123 100644 --- a/usr.sbin/sendmail/src/mime.c +++ b/usr.sbin/sendmail/src/mime.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994 Eric P. Allman + * Copyright (c) 1994, 1996 Eric P. Allman * Copyright (c) 1994 * The Regents of the University of California. All rights reserved. * @@ -36,7 +36,7 @@ # include <string.h> #ifndef lint -static char sccsid[] = "@(#)mime.c 8.30.1.1 (Berkeley) 9/16/96"; +static char sccsid[] = "@(#)mime.c 8.49 (Berkeley) 10/30/96"; #endif /* not lint */ /* @@ -72,6 +72,10 @@ static char *MimeBoundaryNames[] = { "SYNTAX", "NOTSEP", "INTERMED", "FINAL" }; + +bool MapNLtoCRLF; + +extern int mimeboundary __P((char *, char **)); /* ** MIME8TO7 -- output 8 bit body in 7 bit format ** @@ -125,11 +129,14 @@ mime8to7(mci, header, e, boundaries, flags) char **pvp; int argc = 0; char *bp; + bool use_qp = FALSE; struct args argv[MAXMIMEARGS]; char bbuf[128]; char buf[MAXLINE]; char pvpbuf[MAXLINE]; extern u_char MimeTokenTab[256]; + extern int mime_getchar __P((FILE *, char **, int *)); + extern int mime_getchar_crlf __P((FILE *, char **, int *)); if (tTd(43, 1)) { @@ -143,6 +150,7 @@ mime8to7(mci, header, e, boundaries, flags) } printf("\n"); } + MapNLtoCRLF = TRUE; p = hvalue("Content-Transfer-Encoding", header); if (p == NULL || (pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL, @@ -226,6 +234,13 @@ mime8to7(mci, header, e, boundaries, flags) if (wordinclass(buf, 'n') || (cte != NULL && !wordinclass(cte, 'e'))) flags |= M87F_NO8BIT; +#ifdef USE_B_CLASS + if (wordinclass(buf, 'b') || wordinclass(type, 'b')) + MapNLtoCRLF = FALSE; +#endif + if (wordinclass(buf, 'q') || wordinclass(type, 'q')) + use_qp = TRUE; + /* ** Multipart requires special processing. ** @@ -246,8 +261,12 @@ mime8to7(mci, header, e, boundaries, flags) } if (i >= argc) { - syserr("mime8to7: Content-Type: %s missing boundary", p); + syserr("mime8to7: Content-Type: \"%s\": missing boundary", + p); p = "---"; + + /* avoid bounce loops */ + e->e_flags |= EF_DONT_MIME; } else { @@ -260,6 +279,9 @@ mime8to7(mci, header, e, boundaries, flags) syserr("mime8to7: multipart boundary \"%s\" too long", p); blen = sizeof bbuf - 1; + + /* avoid bounce loops */ + e->e_flags |= EF_DONT_MIME; } strncpy(bbuf, p, blen); bbuf[blen] = '\0'; @@ -269,7 +291,12 @@ mime8to7(mci, header, e, boundaries, flags) if (boundaries[i] == NULL) break; if (i >= MAXMIMENESTING) + { syserr("mime8to7: multipart nesting boundary too deep"); + + /* avoid bounce loops */ + e->e_flags |= EF_DONT_MIME; + } else { boundaries[i] = bbuf; @@ -332,7 +359,7 @@ mime8to7(mci, header, e, boundaries, flags) } /* - ** Message/* types -- recurse exactly once. + ** Message/xxx types -- recurse exactly once. ** ** Class 's' is predefined to have "rfc822" only. */ @@ -422,9 +449,11 @@ mime8to7(mci, header, e, boundaries, flags) if (tTd(43, 8)) { - printf("mime8to7: %ld high bit(s) in %ld byte(s), cte=%s\n", + printf("mime8to7: %ld high bit(s) in %ld byte(s), cte=%s, type=%s/%s\n", sectionhighbits, sectionsize, - cte == NULL ? "[none]" : cte); + cte == NULL ? "[none]" : cte, + type == NULL ? "[none]" : type, + subtype == NULL ? "[none]" : subtype); } if (cte != NULL && strcasecmp(cte, "binary") == 0) sectionsize = sectionhighbits; @@ -453,14 +482,19 @@ mime8to7(mci, header, e, boundaries, flags) if (feof(e->e_dfp)) bt = MBT_FINAL; } - else if (sectionsize / 8 < sectionhighbits) + else if (!MapNLtoCRLF || + (sectionsize / 8 < sectionhighbits && !use_qp)) { /* use base64 encoding */ int c1, c2; - putline("Content-Transfer-Encoding: base64", mci); if (tTd(43, 36)) printf(" ...Content-Transfer-Encoding: base64\n"); + putline("Content-Transfer-Encoding: base64", mci); + snprintf(buf, sizeof buf, + "X-MIME-Autoconverted: from 8bit to base64 by %s id %s", + MyHostName, e->e_id); + putline(buf, mci); putline("", mci); mci->mci_flags &= ~MCIF_INHEADER; while ((c1 = mime_getchar_crlf(e->e_dfp, boundaries, &bt)) != EOF) @@ -519,9 +553,13 @@ mime8to7(mci, header, e, boundaries, flags) for (p = "!\"#$@[\\]^`{|}~"; *p != '\0'; p++) setbitn(*p, badchars); - putline("Content-Transfer-Encoding: quoted-printable", mci); if (tTd(43, 36)) printf(" ...Content-Transfer-Encoding: quoted-printable\n"); + putline("Content-Transfer-Encoding: quoted-printable", mci); + snprintf(buf, sizeof buf, + "X-MIME-Autoconverted: from 8bit to quoted-printable by %s id %s", + MyHostName, e->e_id); + putline(buf, mci); putline("", mci); mci->mci_flags &= ~MCIF_INHEADER; fromstate = 0; @@ -693,7 +731,7 @@ mime_getchar(fp, boundaries, btp) *bp++ = c; } *bp = '\0'; - bt = mimeboundary(&buf[1], boundaries); + bt = mimeboundary((char *) &buf[1], boundaries); switch (bt) { case MBT_FINAL: @@ -746,7 +784,7 @@ mime_getchar_crlf(fp, boundaries, btp) return '\n'; } c = mime_getchar(fp, boundaries, btp); - if (c == '\n') + if (c == '\n' && MapNLtoCRLF) { sendlf = TRUE; return '\r'; @@ -776,6 +814,7 @@ mimeboundary(line, boundaries) int type = MBT_NOTSEP; int i; int savec; + extern int isboundary __P((char *, char **)); if (line[0] != '-' || line[1] != '-' || boundaries == NULL) return MBT_NOTSEP; @@ -864,4 +903,282 @@ isboundary(line, boundaries) return -1; } -#endif /* MIME */ +#endif /* MIME8TO7 */ + +#if MIME7TO8 + +/* +** MIME7TO8 -- output 7 bit encoded MIME body in 8 bit format +** +** This is a hack. Supports translating the two 7-bit body-encodings +** (quoted-printable and base64) to 8-bit coded bodies. +** +** There is not much point in supporting multipart here, as the UA +** will be able to deal with encoded MIME bodies if it can parse MIME +** multipart messages. +** +** Note also that we wont be called unless it is a text/plain MIME +** message, encoded base64 or QP and mailer flag '9' has been defined +** on mailer. +** +** Contributed by Marius Olaffson <marius@rhi.hi.is>. +** +** Parameters: +** mci -- mailer connection information. +** header -- the header for this body part. +** e -- envelope. +** +** Returns: +** none. +*/ + +extern int mime_fromqp __P((u_char *, u_char **, int, int)); + +static char index_64[128] = +{ + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, + 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, + 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, + -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, + 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 +}; + +#define CHAR64(c) (((c) < 0 || (c) > 127) ? -1 : index_64[(c)]) + + +void +mime7to8(mci, header, e) + register MCI *mci; + HDR *header; + register ENVELOPE *e; +{ + register char *p; + char *cte; + char **pvp; + u_char *obp; + u_char ch, *fbufp, *obufp; + char buf[MAXLINE]; + u_char obuf[MAXLINE + 1]; + u_char fbuf[MAXLINE + 1]; + char pvpbuf[MAXLINE]; + extern u_char MimeTokenTab[256]; + + p = hvalue("Content-Transfer-Encoding", header); + if (p == NULL || + (pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL, + MimeTokenTab)) == NULL || + pvp[0] == NULL) + { + /* "can't happen" -- upper level should have caught this */ + syserr("mime7to8: unparsable CTE %s", p == NULL ? "<NULL>" : p); + + /* avoid bounce loops */ + e->e_flags |= EF_DONT_MIME; + + /* cheap failsafe algorithm -- should work on text/plain */ + if (p != NULL) + { + snprintf(buf, sizeof buf, + "Content-Transfer-Encoding: %s", p); + putline(buf, mci); + } + putline("", mci); + mci->mci_flags &= ~MCIF_INHEADER; + while (fgets(buf, sizeof buf, e->e_dfp) != NULL) + putline(buf, mci); + return; + } + cataddr(pvp, NULL, buf, sizeof buf, '\0'); + cte = newstr(buf); + + putline("Content-Transfer-Encoding: 8bit", mci); + snprintf(buf, sizeof buf, + "X-MIME-Autoconverted: from %.200s to 8bit by %s id %s", + cte, MyHostName, e->e_id); + putline(buf, mci); + putline("", mci); + mci->mci_flags &= ~MCIF_INHEADER; + + /* + ** Translate body encoding to 8-bit. Supports two types of + ** encodings; "base64" and "quoted-printable". Assume qp if + ** it is not base64. + */ + + if (strcasecmp(cte, "base64") == 0) + { + int nchar = 0; + int c1, c2, c3, c4; + + fbufp = fbuf; + while ((c1 = fgetc(e->e_dfp)) != EOF) + { + if (isascii(c1) && isspace(c1)) + continue; + + do + { + c2 = fgetc(e->e_dfp); + } while (isascii(c2) && isspace(c2)); + if (c2 == EOF) + break; + + do + { + c3 = fgetc(e->e_dfp); + } while (isascii(c3) && isspace(c3)); + if (c3 == EOF) + break; + + do + { + c4 = fgetc(e->e_dfp); + } while (isascii(c4) && isspace(c4)); + if (c4 == EOF) + break; + + if (c1 == '=' || c2 == '=') + continue; + c1 = CHAR64(c1); + c2 = CHAR64(c2); + + *fbufp = (c1 << 2) | ((c2 & 0x30) >> 4); + if (*fbufp++ == '\n' || fbuf >= &fbuf[MAXLINE]) + { + if (*--fbufp != '\n' || *--fbufp != '\r') + fbufp++; + *fbufp = '\0'; + putline((char *) fbuf, mci); + fbufp = fbuf; + } + if (c3 == '=') + continue; + c3 = CHAR64(c3); + *fbufp = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2); + if (*fbufp++ == '\n' || fbuf >= &fbuf[MAXLINE]) + { + if (*--fbufp != '\n' || *--fbufp != '\r') + fbufp++; + *fbufp = '\0'; + putline((char *) fbuf, mci); + fbufp = fbuf; + } + if (c4 == '=') + continue; + c4 = CHAR64(c4); + *fbufp = ((c3 & 0x03) << 6) | c4; + if (*fbufp++ == '\n' || fbuf >= &fbuf[MAXLINE]) + { + if (*--fbufp != '\n' || *--fbufp != '\r') + fbufp++; + *fbufp = '\0'; + putline((char *) fbuf, mci); + fbufp = fbuf; + } + } + + /* force out partial last line */ + if (fbufp > fbuf) + { + *fbufp = '\0'; + putline((char *) fbuf, mci); + } + } + else + { + /* quoted-printable */ + obp = obuf; + while (fgets(buf, sizeof buf, e->e_dfp) != NULL) + { + if (mime_fromqp((u_char *) buf, &obp, 0, &obuf[MAXLINE] - obp) == 0) + continue; + + putline((char *) obuf, mci); + obp = obuf; + } + } + if (tTd(43, 3)) + printf("\t\t\tmime7to8 => %s to 8bit done\n", cte); +} +/* +** The following is based on Borenstein's "codes.c" module, with simplifying +** changes as we do not deal with multipart, and to do the translation in-core, +** with an attempt to prevent overrun of output buffers. +** +** What is needed here are changes to defned this code better against +** bad encodings. Questionable to always return 0xFF for bad mappings. +*/ + +static char index_hex[128] = +{ + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1, + -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1 +}; + +#define HEXCHAR(c) (((c) < 0 || (c) > 127) ? -1 : index_hex[(c)]) + +int +mime_fromqp(infile, outfile, state, maxlen) + u_char *infile; + u_char **outfile; + int state; /* Decoding body (0) or header (1) */ + int maxlen; /* Max # of chars allowed in outfile */ +{ + int c1, c2; + int nchar = 0; + + while ((c1 = *infile++) != '\0') + { + if (c1 == '=') + { + if ((c1 = *infile++) == 0) + break; + + if (c1 == '\n') /* ignore it */ + { + if (state == 0) + return 0; + } + else + { + if ((c2 = *infile++) == '\0') + break; + + c1 = HEXCHAR(c1); + c2 = HEXCHAR(c2); + + if (++nchar > maxlen) + break; + + *(*outfile)++ = c1 << 4 | c2; + } + } + else + { + if (state == 1 && c1 == '_') + c1 = ' '; + + if (++nchar > maxlen) + break; + + *(*outfile)++ = c1; + + if (c1 == '\n') + break; + } + } + *(*outfile)++ = '\0'; + return 1; +} + + +#endif /* MIME7TO8 */ |