* Configuration file support for fetchmail 4.3.8 by
* Frank Damgaard <frda@post3.tele.dk>
*
+ * For license terms, see the file COPYING in this directory.
*/
+#include "config.h"
#include <string.h>
#include <stdlib.h>
-#if defined(HAVE_ALLOCA_H)
-#include <alloca.h>
-#else
-#ifdef _AIX
- #pragma alloca
-#endif
-#endif
+#include <stdio.h>
#include <ctype.h>
#include "fetchmail.h"
+#include "i18n.h"
static unsigned char unhex(unsigned char c)
{
else if ((c >= 'a') && (c <= 'f'))
return (c - 'a' + 10);
else
- return c;
+ return 16; /* invalid hex character */
}
static int qp_char(unsigned char c1, unsigned char c2, unsigned char *c_out)
}
-
/*
* Routines to decode MIME QP-encoded headers, as per RFC 2047.
*/
/* Note: Decoding is done "in-situ", i.e. without using an
* additional buffer for temp. storage. This is possible, since the
* decoded string will always be shorter than the encoded string,
- * due to the en- coding scheme.
+ * due to the encoding scheme.
*/
int state = S_COPY_PLAIN;
unsigned char *p_in, *p_out, *p;
- unsigned char enc;
+ unsigned char enc = '\0'; /* initialization pacifies -Wall */
int i;
/* Speed up in case this is not a MIME-encoded header */
int decoded_count;
delimsave = *p; *p = '\r';
- decoded_count = from64tobits(p_out, p_in);
+ decoded_count = from64tobits(p_out, p_in, 0);
*p = delimsave;
if (decoded_count > 0)
p_out += decoded_count;
* and prepare to process the new MIME charset/encoding
* header.
*/
- p_in = p + strlen(MIMEHDR_INIT);
+ p_in = p + sizeof(MIMEHDR_INIT) - 1;
state = S_SKIP_MIMEINIT;
}
}
* a quoted-printable body part.
*/
static int CurrEncodingIsQP = 0;
+static int CurrTypeNeedsDecode = 0;
/*
* Delimiter for multipart messages. RFC 2046 states that this must
unsigned char *p;
if (XferEncOfs != NULL) {
- memcpy(XferEncOfs, ENC8BIT, strlen(ENC8BIT));
+ memcpy(XferEncOfs, ENC8BIT, sizeof(ENC8BIT) - 1);
/* If anything left, in this header, replace with whitespace */
- for (p=XferEncOfs+strlen(ENC8BIT); (*p >= ' '); p++) *p=' ';
+ for (p=XferEncOfs+sizeof(ENC8BIT)-1; (*p >= ' '); p++) *p=' ';
}
}
}
+int CheckContentType(char *CntType)
+{
+ /*
+ * Static array of Content-Type's for which we will do
+ * quoted-printable decoding, if requested.
+ * It is probably wise to do this only on known text-only types;
+ * be really careful if you change this.
+ */
+
+ static char *DecodedTypes[] = {
+ "text/", /* Will match ALL content-type's starting with 'text/' */
+ "message/rfc822",
+ NULL
+ };
+
+ char *p = CntType;
+ int i;
+
+ /* If no Content-Type header, it isn't MIME - don't touch it */
+ if (CntType == NULL) return 0;
+
+ /* Skip whitespace, if any */
+ for (; isspace(*p); p++) ;
+
+ for (i=0;
+ (DecodedTypes[i] &&
+ (strncasecmp(p, DecodedTypes[i], strlen(DecodedTypes[i]))));
+ i++) ;
+
+ return (DecodedTypes[i] != NULL);
+}
+
+
/*
* This routine does three things:
* 1) It determines - based on the message headers - whether the
* - All other messages are assumed NOT to include 8-bit data.
* 2) It determines the delimiter-string used in multi-part message
* bodies.
- * 3) It sets the initial values of the CurrEncodingIsQP and BodyState
- * variables, from the header contents.
+ * 3) It sets the initial values of the CurrEncodingIsQP,
+ * CurrTypeNeedsDecode, and BodyState variables, from the header
+ * contents.
*
* The return value is a bitmask.
*/
/* Setup for a standard (no MIME, no QP, 7-bit US-ASCII) message */
MultipartDelimiter[0] = '\0';
- CurrEncodingIsQP = 0;
+ CurrEncodingIsQP = CurrTypeNeedsDecode = 0;
BodyState = S_BODY_DATA;
BodyType = 0;
XferEncOfs = NxtHdr;
p = nxtaddr(NxtHdr);
if (p != NULL) {
- XferEnc = (char *)alloca(strlen(p) + 1);
+ xalloca(XferEnc, char *, strlen(p) + 1);
strcpy(XferEnc, p);
HdrsFound++;
}
} while ( (p != NULL) && ((*(p+1) == '\t') || (*(p+1) == ' ')) );
if (p == NULL) p = NxtHdr + strlen(NxtHdr);
- CntType = (char *)alloca(p-NxtHdr+2);
+ xalloca(CntType, char *, p-NxtHdr+2);
strncpy(CntType, NxtHdr, (p-NxtHdr));
*(CntType+(p-NxtHdr)) = '\0';
HdrsFound++;
else if (strncasecmp("MIME-Version:", NxtHdr, 13) == 0) {
p = nxtaddr(NxtHdr);
if (p != NULL) {
- MimeVer = (char *)alloca(strlen(p) + 1);
+ xalloca(MimeVer, char *, strlen(p) + 1);
strcpy(MimeVer, p);
HdrsFound++;
}
/* Done looking through the headers, now check what they say */
if ((MimeVer != NULL) && (strcmp(MimeVer, "1.0") == 0)) {
+ CurrTypeNeedsDecode = CheckContentType(CntType);
+
/* Check Content-Type to see if this is a multipart message */
if ( (CntType != NULL) &&
- ((strncasecmp(CntType, "multipart/", 10) == 0) ||
+ ((strncasecmp(CntType, "multipart/mixed", 16) == 0) ||
(strncasecmp(CntType, "message/", 8) == 0)) ) {
char *p1 = GetBoundary(CntType);
if (strcasecmp(XferEnc, "quoted-printable") == 0) {
CurrEncodingIsQP = 1;
BodyType = (MSG_IS_8BIT | MSG_NEEDS_DECODE);
- if (WantDecode) {
+ if (WantDecode && CurrTypeNeedsDecode) {
SetEncoding8bit(XferEncOfs);
}
}
* Return flag set if this line ends with a soft line-break.
* 'bufp' is modified to point to the end of the output buffer.
*/
-static int DoOneQPLine(unsigned char **bufp, int collapsedoubledot)
+static int DoOneQPLine(unsigned char **bufp, flag delimited, flag issoftline)
{
unsigned char *buf = *bufp;
unsigned char *p_in, *p_out, *p;
int n;
int ret = 0;
+ /*
+ * Special case: line consists of a single =2E and messages are
+ * dot-terminated. Line has to be dot-stuffed after decoding.
+ */
+ if (delimited && !issoftline && buf[0]=='=' && !strncmp(*bufp, "=2E\r\n", 5))
+ {
+ strcpy(buf, "..\r\n");
+ *bufp += 5;
+ return(FALSE);
+ }
+
p_in = buf;
- if (collapsedoubledot && (strncmp(buf, "..", 2) == 0))
+ if (delimited && issoftline && (strncmp(buf, "..", 2) == 0))
p_in++;
for (p_out = buf; (*p_in); ) {
* 'bufp' is modified to point to the end of the output buffer.
*/
-int UnMimeBodyline(unsigned char **bufp, int collapsedoubledot)
+int UnMimeBodyline(unsigned char **bufp, flag delimited, flag softline)
{
unsigned char *buf = *bufp;
int ret = 0;
switch (BodyState) {
case S_BODY_HDR:
UnMimeHeader(buf); /* Headers in body-parts can be encoded, too! */
- if (strncasecmp("Content-Transfer-Encoding:", buf, 26) == 0) {
+ if ((*buf == '\0') || (*buf == '\n') || (strcmp(buf, "\r\n") == 0)) {
+ BodyState = S_BODY_DATA;
+ }
+ else if (strncasecmp("Content-Transfer-Encoding:", buf, 26) == 0) {
char *XferEnc;
XferEnc = nxtaddr(buf);
if ((XferEnc != NULL) && (strcasecmp(XferEnc, "quoted-printable") == 0)) {
CurrEncodingIsQP = 1;
- SetEncoding8bit(buf);
+
+ /*
+ * Hmm ... we cannot be really sure that CurrTypeNeedsDecode
+ * has been set - we may not have seen the Content-Type header
+ * yet. But *usually* the Content-Type header comes first, so
+ * this will work. And there is really no way of doing it
+ * "right" as long as we stick with the line-by-line processing.
+ */
+ if (CurrTypeNeedsDecode)
+ SetEncoding8bit(buf);
}
}
- else if ((*buf == '\0') || (*buf == '\n') || (strcmp(buf, "\r\n") == 0))
- BodyState = S_BODY_DATA;
+ else if (strncasecmp("Content-Type:", buf, 13) == 0) {
+ CurrTypeNeedsDecode = CheckContentType(nxtaddr(buf));
+ }
*bufp = (buf + strlen(buf));
break;
if ((*MultipartDelimiter) &&
(strncmp(buf, MultipartDelimiter, strlen(MultipartDelimiter)) == 0)) {
BodyState = S_BODY_HDR;
- CurrEncodingIsQP = 0;
+ CurrEncodingIsQP = CurrTypeNeedsDecode = 0;
}
- if (CurrEncodingIsQP)
- ret = DoOneQPLine(bufp, collapsedoubledot);
+ if (CurrEncodingIsQP && CurrTypeNeedsDecode)
+ ret = DoOneQPLine(bufp, delimited, softline);
else
*bufp = (buf + strlen(buf));
break;
#include <unistd.h>
char *program_name = "unmime";
+int outlevel = 0;
#define BUFSIZE_INCREMENT 4096