ACL: remove obsolete demime condition
authorJeremy Harris <jgh146exb@wizmail.org>
Fri, 18 Dec 2015 16:05:37 +0000 (16:05 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Wed, 6 Apr 2016 21:10:31 +0000 (22:10 +0100)
15 files changed:
doc/doc-docbook/spec.xfpt
doc/doc-txt/ChangeLog
src/OS/Makefile-Base
src/OS/Makefile-CYGWIN
src/src/acl.c
src/src/buildconfig.c
src/src/config.h.defaults
src/src/demime.c [deleted file]
src/src/demime.h [deleted file]
src/src/exim.c
src/src/expand.c
src/src/functions.h
src/src/globals.c
src/src/globals.h
src/src/spool_mbox.c

index 33c8e5e..e30f17c 100644 (file)
@@ -11509,18 +11509,6 @@ contain the trailing slash. If &$config_file$& does not contain a slash,
 .vindex "&$config_file$&"
 The name of the main configuration file Exim is using.
 
-.vitem &$demime_errorlevel$&
-.vindex "&$demime_errorlevel$&"
-This variable is available when Exim is compiled with
-the content-scanning extension and the obsolete &%demime%& condition. For
-details, see section &<<SECTdemimecond>>&.
-
-.vitem &$demime_reason$&
-.vindex "&$demime_reason$&"
-This variable is available when Exim is compiled with the
-content-scanning extension and the obsolete &%demime%& condition. For details,
-see section &<<SECTdemimecond>>&.
-
 .vitem &$dkim_cur_signer$& &&&
        &$dkim_verify_status$& &&&
        &$dkim_verify_reason$& &&&
@@ -11652,12 +11640,6 @@ The first character is a major version number, currently 4.
 Then after a dot, the next group of digits is a minor version number.
 There may be other characters following the minor version.
 
-.vitem &$found_extension$&
-.vindex "&$found_extension$&"
-This variable is available when Exim is compiled with the
-content-scanning extension and the obsolete &%demime%& condition. For details,
-see section &<<SECTdemimecond>>&.
-
 .vitem &$header_$&<&'name'&>
 This is not strictly an expansion variable. It is expansion syntax for
 inserting the message header line with the given name. Note that the name must
@@ -29173,12 +29155,6 @@ If all goes well, the condition is true. It is false only if there are
 problems such as a syntax error or a memory shortage. For more details, see
 chapter &<<CHAPexiscan>>&.
 
-.vitem &*demime&~=&~*&<&'extension&~list'&>
-.cindex "&%demime%& ACL condition"
-This condition is available only when Exim is compiled with the
-content-scanning extension. Its use is described in section
-&<<SECTdemimecond>>&.
-
 .vitem &*dnslists&~=&~*&<&'list&~of&~domain&~names&~and&~other&~data'&>
 .cindex "&%dnslists%& ACL condition"
 .cindex "DNS list" "in ACL"
@@ -30989,10 +30965,6 @@ conditions.
 Two new main configuration options: &%av_scanner%& and &%spamd_address%&.
 .endlist
 
-There is another content-scanning configuration option for &_Local/Makefile_&,
-called WITH_OLD_DEMIME. If this is set, the old, deprecated &%demime%& ACL
-condition is compiled, in addition to all the other content-scanning features.
-
 Content-scanning is continually evolving, and new features are still being
 added. While such features are still unstable and liable to incompatible
 changes, they are made available in Exim by setting options whose names begin
@@ -31242,7 +31214,7 @@ This is a daemon type scanner that is aimed mainly at Polish users, though some
 parts of documentation are now available in English. You can get it at
 &url(http://linux.mks.com.pl/). The only option for this scanner type is
 the maximum number of processes used simultaneously to scan the attachments,
-provided that the demime facility is employed and also provided that mksd has
+provided that mksd has
 been run with at least the same number of child processes. For example:
 .code
 av_scanner = mksd:2
@@ -31333,23 +31305,17 @@ When a virus is found, the condition sets up an expansion variable called
 &%message%& modifier that specifies the error returned to the sender, and/or in
 logging data.
 
-If your virus scanner cannot unpack MIME and TNEF containers itself, you should
-use the &%demime%& condition (see section &<<SECTdemimecond>>&) before the
-&%malware%& condition.
-
 Beware the interaction of Exim's &%message_size_limit%& with any size limits
 imposed by your anti-virus scanner.
 
 Here is a very simple scanning example:
 .code
 deny message = This message contains malware ($malware_name)
-     demime = *
      malware = *
 .endd
 The next example accepts messages when there is a problem with the scanner:
 .code
 deny message = This message contains malware ($malware_name)
-     demime = *
      malware = */defer_ok
 .endd
 The next example shows how to use an ACL variable to scan with both sophie and
@@ -31845,90 +31811,6 @@ are set to any substrings captured by the regular expression.
 &*Warning*&: With large messages, these conditions can be fairly
 CPU-intensive.
 
-
-
-
-.section "The demime condition" "SECTdemimecond"
-.cindex "content scanning" "MIME checking"
-.cindex "MIME content scanning"
-The &%demime%& ACL condition provides MIME unpacking, sanity checking and file
-extension blocking. It is usable only in the DATA and non-SMTP ACLs. The
-&%demime%& condition uses a simpler interface to MIME decoding than the MIME
-ACL functionality, but provides no additional facilities. Please note that this
-condition is deprecated and kept only for backward compatibility. You must set
-the WITH_OLD_DEMIME option in &_Local/Makefile_& at build time to be able to
-use the &%demime%& condition.
-
-The &%demime%& condition unpacks MIME containers in the message. It detects
-errors in MIME containers and can match file extensions found in the message
-against a list. Using this facility produces files containing the unpacked MIME
-parts of the message in the temporary scan directory. If you do antivirus
-scanning, it is recommended that you use the &%demime%& condition before the
-antivirus (&%malware%&) condition.
-
-On the right-hand side of the &%demime%& condition you can pass a
-colon-separated list of file extensions that it should match against. For
-example:
-.code
-deny message = Found blacklisted file attachment
-     demime  = vbs:com:bat:pif:prf:lnk
-.endd
-If one of the file extensions is found, the condition is true, otherwise it is
-false. If there is a temporary error while demimeing (for example, &"disk
-full"&), the condition defers, and the message is temporarily rejected (unless
-the condition is on a &%warn%& verb).
-
-The right-hand side is expanded before being treated as a list, so you can have
-conditions and lookups there. If it expands to an empty string, &"false"&, or
-zero (&"0"&), no demimeing is done and the condition is false.
-
-The &%demime%& condition set the following variables:
-
-.vlist
-.vitem &$demime_errorlevel$&
-.vindex "&$demime_errorlevel$&"
-When an error is detected in a MIME container, this variable contains the
-severity of the error, as an integer number. The higher the value, the more
-severe the error (the current maximum value is 3). If this variable is unset or
-zero, no error occurred.
-
-.vitem &$demime_reason$&
-.vindex "&$demime_reason$&"
-When &$demime_errorlevel$& is greater than zero, this variable contains a
-human-readable text string describing the MIME error that occurred.
-.endlist
-
-.vlist
-.vitem &$found_extension$&
-.vindex "&$found_extension$&"
-When the &%demime%& condition is true, this variable contains the file
-extension it found.
-.endlist
-
-Both &$demime_errorlevel$& and &$demime_reason$& are set by the first call of
-the &%demime%& condition, and are not changed on subsequent calls.
-
-If you do not want to check for file extensions, but rather use the &%demime%&
-condition for unpacking or error checking purposes, pass &"*"& as the
-right-hand side value. Here is a more elaborate example of how to use this
-facility:
-.code
-# Reject messages with serious MIME container errors
-deny  message = Found MIME error ($demime_reason).
-      demime = *
-      condition = ${if >{$demime_errorlevel}{2}{1}{0}}
-
-# Reject known virus spreading file extensions.
-# Accepting these is pretty much braindead.
-deny  message = contains $found_extension file (blacklisted).
-      demime  = com:vbs:bat:pif:scr
-
-# Freeze .exe and .doc files. Postmaster can
-# examine them and eventually thaw them.
-deny  log_message = Another $found_extension file.
-      demime = exe:doc
-      control = freeze
-.endd
 .ecindex IIDcosca
 
 
index cfea55e..6c55bd8 100644 (file)
@@ -1,12 +1,15 @@
 Change log file for Exim from version 4.21
 -------------------------------------------
 
-
 Exim version 4.88
 -----------------
 JH/01 Use SIZE on MAIL FROM in a cutthrough connection, if the destination
       supports it and a size is available (ie. the sending peer gave us one).
 
+JH/02 The obsolete acl condition "demime" is removed (finally, after ten
+      years of being deprecated). The replacements are the ACLs
+      acl_smtp_mime and acl_not_smtp_mime.
+
 
 Exim version 4.87
 -----------------
index 229961f..0ae4164 100644 (file)
@@ -314,7 +314,6 @@ convert4r4: Makefile ../src/convert4r4.src
 # are thrown away by the linker.
 
 OBJ_WITH_CONTENT_SCAN = malware.o mime.o regex.o spam.o spool_mbox.o
-OBJ_WITH_OLD_DEMIME = demime.o
 OBJ_EXPERIMENTAL = bmi_spam.o \
                                dane.o \
                                dcc.o \
@@ -340,7 +339,7 @@ OBJ_EXIM = acl.o base64.o child.o crypt16.o daemon.o dbfn.o debug.o deliver.o \
         environment.o \
         $(OBJ_LOOKUPS) \
         local_scan.o $(EXIM_PERL) $(OBJ_WITH_CONTENT_SCAN) \
-        $(OBJ_WITH_OLD_DEMIME) $(OBJ_EXPERIMENTAL)
+        $(OBJ_EXPERIMENTAL)
 
 exim:   buildlookups buildauths pdkim/pdkim.a \
         buildrouters buildtransports \
@@ -643,11 +642,6 @@ spam.o:          $(HDRS) spam.c
 spool_mbox.o:    $(HDRS) spool_mbox.c
 
 
-# Dependencies for WITH_OLD_DEMIME modules
-
-demime.o:       $(HDRS) demime.c
-
-
 # Dependencies for EXPERIMENTAL_* modules
 
 bmi_spam.o:    $(HDRS) bmi_spam.c
index 23981d4..cda5d26 100644 (file)
@@ -80,7 +80,6 @@ LOOKUP_PASSWD=yes
 LDAP_LIB_TYPE=OPENLDAP2
 LOOKUP_LIBS=-lldap -llber
 
-# WITH_OLD_DEMIME=yes
 WITH_CONTENT_SCAN=yes
 
 # It is important to define these variables but the values are always overridden
index 0bc00ac..5e3bacf 100644 (file)
@@ -65,9 +65,6 @@ enum { ACLC_ACL,
        ACLC_DECODE,
 #endif
        ACLC_DELAY,
-#ifdef WITH_OLD_DEMIME
-       ACLC_DEMIME,
-#endif
 #ifndef DISABLE_DKIM
        ACLC_DKIM_SIGNER,
        ACLC_DKIM_STATUS,
@@ -132,9 +129,6 @@ static uschar *conditions[] = {
   US"decode",
 #endif
   US"delay",
-#ifdef WITH_OLD_DEMIME
-  US"demime",
-#endif
 #ifndef DISABLE_DKIM
   US"dkim_signers",
   US"dkim_status",
@@ -281,9 +275,6 @@ static uschar cond_expand_at_top[] = {
   TRUE,    /* decode */
 #endif
   TRUE,    /* delay */
-#ifdef WITH_OLD_DEMIME
-  TRUE,    /* demime */
-#endif
 #ifndef DISABLE_DKIM
   TRUE,    /* dkim_signers */
   TRUE,    /* dkim_status */
@@ -346,9 +337,6 @@ static uschar cond_modifiers[] = {
   FALSE,   /* decode */
 #endif
   TRUE,    /* delay */
-#ifdef WITH_OLD_DEMIME
-  FALSE,   /* demime */
-#endif
 #ifndef DISABLE_DKIM
   FALSE,   /* dkim_signers */
   FALSE,   /* dkim_status */
@@ -453,15 +441,6 @@ static unsigned int cond_forbids[] = {
 
   (1<<ACL_WHERE_NOTQUIT),                          /* delay */
 
-  #ifdef WITH_OLD_DEMIME
-  (unsigned int)
-  ~((1<<ACL_WHERE_DATA)|                           /* demime */
-  #ifndef DISABLE_PRDR
-    (1<<ACL_WHERE_PRDR)|
-  #endif
-    (1<<ACL_WHERE_NOTSMTP)),
-  #endif
-
   #ifndef DISABLE_DKIM
   (unsigned int)
   ~(1<<ACL_WHERE_DKIM),                            /* dkim_signers */
@@ -3533,12 +3512,6 @@ for (; cb != NULL; cb = cb->next)
       }
     break;
 
-    #ifdef WITH_OLD_DEMIME
-    case ACLC_DEMIME:
-      rc = demime(&arg);
-    break;
-    #endif
-
     #ifndef DISABLE_DKIM
     case ACLC_DKIM_SIGNER:
     if (dkim_cur_signer != NULL)
index 27e7314..2f1114d 100644 (file)
@@ -733,11 +733,10 @@ else if (isgroup)
   if (strcmp(name, "WITH_CONTENT_SCAN") == 0)
     {
     char *wcs = getenv("WITH_CONTENT_SCAN");
-    char *wod = getenv("WITH_OLD_DEMIME");
     char *dcc = getenv("EXPERIMENTAL_DCC");
-    if (wcs != NULL || wod != NULL || dcc != NULL)
-      fprintf(new, "#define WITH_CONTENT_SCAN     yes\n");
-    else fprintf(new, "/* WITH_CONTENT_SCAN not set */\n");
+    fprintf(new, wcs || dcc
+      ? "#define WITH_CONTENT_SCAN     yes\n"
+      : "/* WITH_CONTENT_SCAN not set */\n");
     continue;
     }
 
index 266c268..9d5f4c4 100644 (file)
@@ -169,7 +169,6 @@ it's a default value. */
 #define WHITELIST_D_MACROS
 
 #define WITH_CONTENT_SCAN
-#define WITH_OLD_DEMIME
 #define WITH_OLD_CLAMAV_STREAM
 
 /* EXPERIMENTAL features */
diff --git a/src/src/demime.c b/src/src/demime.c
deleted file mode 100644 (file)
index fc778fa..0000000
+++ /dev/null
@@ -1,1245 +0,0 @@
-/*************************************************
-*     Exim - an Internet mail transport agent    *
-*************************************************/
-
-/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-????
- * License: GPL
- * Copyright (c) The Exim Maintainers 2016
- */
-
-/* Code for unpacking MIME containers. Called from acl.c. */
-
-#include "exim.h"
-#ifdef WITH_OLD_DEMIME
-
-#include "demime.h"
-
-uschar demime_reason_buffer[1024];
-struct file_extension *file_extensions = NULL;
-
-int demime(const uschar **listptr) {
-  int sep = 0;
-  const uschar *list = *listptr;
-  uschar *option;
-  uschar option_buffer[64];
-  unsigned long mbox_size;
-  FILE *mbox_file;
-  uschar defer_error_buffer[1024];
-  int demime_rc = 0;
-
-  /* reset found_extension variable */
-  found_extension = NULL;
-
-  /* try to find 1st option */
-  if ((option = string_nextinlist(&list, &sep,
-                                  option_buffer,
-                                  sizeof(option_buffer))) != NULL) {
-
-    /* parse 1st option */
-    if ( (Ustrcmp(option,"false") == 0) || (Ustrcmp(option,"0") == 0) ) {
-      /* explicitly no demimeing */
-      return FAIL;
-    };
-  }
-  else {
-    /* no options -> no demimeing */
-    return FAIL;
-  };
-
-  /* make sure the eml mbox file is spooled up */
-  mbox_file = spool_mbox(&mbox_size, NULL);
-
-  if (mbox_file == NULL) {
-    /* error while spooling */
-    log_write(0, LOG_MAIN|LOG_PANIC,
-           "demime acl condition: error while creating mbox spool file");
-    return DEFER;
-  };
-
-  /* call demimer if not already done earlier */
-  if (!demime_ok)
-    demime_rc = mime_demux(mbox_file, defer_error_buffer);
-
-  (void)fclose(mbox_file);
-
-  if (demime_rc == DEFER) {
-    /* temporary failure (DEFER => DEFER) */
-    log_write(0, LOG_MAIN,
-        "demime acl condition: %s", defer_error_buffer);
-    return DEFER;
-  };
-
-  /* set demime_ok to avoid unpacking again */
-  demime_ok = 1;
-
-  /* check for file extensions, if there */
-  while (option != NULL) {
-    struct file_extension *this_extension = file_extensions;
-
-    /* Look for the wildcard. If it is found, we always return true.
-    The user must then use a custom condition to evaluate demime_errorlevel */
-    if (Ustrcmp(option,"*") == 0) {
-      found_extension = NULL;
-      return OK;
-    };
-
-    /* loop thru extension list */
-    while (this_extension != NULL) {
-      if (strcmpic(option, this_extension->file_extension_string) == 0) {
-        /* found one */
-        found_extension = this_extension->file_extension_string;
-        return OK;
-      };
-      this_extension = this_extension->next;
-    };
-
-    /* grab next extension from option list */
-    option = string_nextinlist(&list, &sep,
-                               option_buffer,
-                               sizeof(option_buffer));
-  };
-
-  /* nothing found */
-  return FAIL;
-}
-
-
-/*************************************************
-* small hex_str -> integer conversion function   *
-*************************************************/
-
-/* needed for quoted-printable
-*/
-
-unsigned int mime_hstr_i(uschar *cptr) {
-  unsigned int i, j = 0;
-
-  while (cptr && *cptr && isxdigit(*cptr)) {
-    i = *cptr++ - '0';
-    if (9 < i) i -= 7;
-    j <<= 4;
-    j |= (i & 0x0f);
-  }
-
-  return(j);
-}
-
-
-/*************************************************
-* decode quoted-printable chars                  *
-*************************************************/
-
-/* gets called when we hit a =
-   returns: new pointer position
-   result code in c:
-          -2 - decode error
-          -1 - soft line break, no char
-           0-255 - char to write
-*/
-
-uschar *mime_decode_qp(uschar *qp_p,int *c) {
-  uschar hex[] = {0,0,0};
-  int nan = 0;
-  uschar *initial_pos = qp_p;
-
-  /* advance one char */
-  qp_p++;
-
-  REPEAT_FIRST:
-  if ( (*qp_p == '\t') || (*qp_p == ' ') || (*qp_p == '\r') )  {
-    /* tab or whitespace may follow
-       just ignore it, but remember
-       that this is not a valid hex
-       encoding any more */
-    nan = 1;
-    qp_p++;
-    goto REPEAT_FIRST;
-  }
-  else if ( (('0' <= *qp_p) && (*qp_p <= '9')) || (('A' <= *qp_p) && (*qp_p <= 'F'))  || (('a' <= *qp_p) && (*qp_p <= 'f')) ) {
-    /* this is a valid hex char, if nan is unset */
-    if (nan) {
-      /* this is illegal */
-      *c = -2;
-      return initial_pos;
-    }
-    else {
-      hex[0] = *qp_p;
-      qp_p++;
-    };
-  }
-  else if (*qp_p == '\n') {
-    /* hit soft line break already, continue */
-    *c = -1;
-    return qp_p;
-  }
-  else {
-    /* illegal char here */
-    *c = -2;
-    return initial_pos;
-  };
-
-  if ( (('0' <= *qp_p) && (*qp_p <= '9')) || (('A' <= *qp_p) && (*qp_p <= 'F')) || (('a' <= *qp_p) && (*qp_p <= 'f')) ) {
-    if (hex[0] > 0) {
-      hex[1] = *qp_p;
-      /* do hex conversion */
-      *c = mime_hstr_i(hex);
-      qp_p++;
-      return qp_p;
-    }
-    else {
-      /* huh ? */
-      *c = -2;
-      return initial_pos;
-    };
-  }
-  else {
-    /* illegal char */
-    *c = -2;
-    return initial_pos;
-  };
-
-}
-
-
-/*************************************************
-* open new dump file                             *
-*************************************************/
-
-/* open new dump file
-   returns: -2 soft error
-            or file #, FILE * in f
-*/
-
-int mime_get_dump_file(uschar *extension, FILE **f, uschar *info) {
-  uschar file_name[1024];
-  int result;
-  unsigned int file_nr;
-  uschar default_extension[] = ".com";
-  uschar *p;
-
-  if (extension == NULL)
-    extension = default_extension;
-
-  /* scan the proposed extension.
-     if it is longer than 4 chars, or
-     contains exotic chars, use the default extension */
-
-/*  if (Ustrlen(extension) > 4) {
-    extension = default_extension;
-  };
-*/
-
-  p = extension+1;
-
-  while (*p != 0) {
-    *p = (uschar)tolower((uschar)*p);
-    if ( (*p < 97) || (*p > 122) ) {
-      extension = default_extension;
-      break;
-    };
-    p++;
-  };
-
-  /* find a new file to write to */
-  file_nr = 0;
-  do {
-    struct stat mystat;
-
-    (void)string_format(file_name,1024,"%s/scan/%s/%s-%05u%s",spool_directory,message_id,message_id,file_nr,extension);
-    file_nr++;
-    if (file_nr >= MIME_SANITY_MAX_DUMP_FILES) {
-      /* max parts reached */
-      mime_trigger_error(MIME_ERRORLEVEL_TOO_MANY_PARTS);
-      break;
-    };
-    result = stat(CS file_name,&mystat);
-  }
-  while(result != -1);
-
-  *f = modefopen(file_name,"wb+",SPOOL_MODE);
-  if (*f == NULL) {
-    /* cannot open new dump file, disk full ? -> soft error */
-    (void)string_format(info, 1024,"unable to open dump file");
-    return -2;
-  };
-
-  return file_nr;
-}
-
-
-/*************************************************
-* Find a string in a mime header                 *
-*************************************************/
-
-/* Find a string in a mime header, and optionally fill in
-   the value associated with it into *value
-
-   returns: 0 - nothing found
-            1 - found param
-            2 - found param + value
-*/
-
-int mime_header_find(uschar *header, uschar *param, uschar **value) {
-  uschar *needle;
-
-  needle = strstric(header,param,FALSE);
-  if (needle != NULL) {
-    if (value != NULL) {
-      needle += Ustrlen(param);
-      if (*needle == '=') {
-        uschar *value_start;
-        uschar *value_end;
-
-        value_start = needle + 1;
-        value_end = strstric(value_start,US";",FALSE);
-        if (value_end != NULL) {
-          /* allocate mem for value */
-          *value = (uschar *)malloc((value_end - value_start)+1);
-          if (*value == NULL)
-            return 0;
-
-          Ustrncpy(*value,value_start,(value_end - value_start));
-          (*value)[(value_end - value_start)] = '\0';
-          return 2;
-        };
-      };
-    };
-    return 1;
-  };
-  return 0;
-}
-
-
-/*************************************************
-* Read a line of MIME input                      *
-*************************************************/
-/* returns status code, one of
-   MIME_READ_LINE_EOF 0
-   MIME_READ_LINE_OK 1
-   MIME_READ_LINE_OVERFLOW 2
-
-   In header mode, the line will be "cooked".
-*/
-
-int mime_read_line(FILE *f, int mime_demux_mode, uschar *buffer, long *num_copied) {
-  int c = EOF;
-  int done = 0;
-  int header_value_mode = 0;
-  int header_open_brackets = 0;
-
-  *num_copied = 0;
-
-  while(!done) {
-
-    c = fgetc(f);
-    if (c == EOF) break;
-
-    /* --------- header mode -------------- */
-    if (mime_demux_mode == MIME_DEMUX_MODE_MIME_HEADERS) {
-
-      /* always skip CRs */
-      if (c == '\r') continue;
-
-      if (c == '\n') {
-        if ((*num_copied) > 0) {
-          /* look if next char is '\t' or ' ' */
-          c = fgetc(f);
-          if (c == EOF) break;
-          if ( (c == '\t') || (c == ' ') ) continue;
-          (void)ungetc(c,f);
-        };
-        /* end of the header, terminate with ';' */
-        c = ';';
-        done = 1;
-      };
-
-      /* skip control characters */
-      if (c < 32) continue;
-
-      /* skip whitespace + tabs */
-      if ( (c == ' ') || (c == '\t') )
-        continue;
-
-      if (header_value_mode) {
-        /* --------- value mode ----------- */
-        /* skip quotes */
-        if (c == '"') continue;
-
-        /* leave value mode on ';' */
-        if (c == ';') {
-          header_value_mode = 0;
-        };
-        /* -------------------------------- */
-      }
-      else {
-        /* -------- non-value mode -------- */
-        if (c == '\\') {
-          /* quote next char. can be used
-          to escape brackets. */
-          c = fgetc(f);
-          if (c == EOF) break;
-        }
-        else if (c == '(') {
-          header_open_brackets++;
-          continue;
-        }
-        else if ((c == ')') && header_open_brackets) {
-          header_open_brackets--;
-          continue;
-        }
-        else if ( (c == '=') && !header_open_brackets ) {
-          /* enter value mode */
-          header_value_mode = 1;
-        };
-
-        /* skip chars while we are in a comment */
-        if (header_open_brackets > 0)
-          continue;
-        /* -------------------------------- */
-      };
-    }
-    /* ------------------------------------ */
-    else {
-    /* ----------- non-header mode -------- */
-      /* break on '\n' */
-      if (c == '\n')
-        done = 1;
-    /* ------------------------------------ */
-    };
-
-    /* copy the char to the buffer */
-    buffer[*num_copied] = (uschar)c;
-    /* raise counter */
-    (*num_copied)++;
-
-    /* break if buffer is full */
-    if (*num_copied > MIME_SANITY_MAX_LINE_LENGTH-1) {
-      done = 1;
-    };
-  }
-
-  /* 0-terminate */
-  buffer[*num_copied] = '\0';
-
-  if (*num_copied > MIME_SANITY_MAX_LINE_LENGTH-1)
-    return MIME_READ_LINE_OVERFLOW;
-  else
-    if (c == EOF)
-      return MIME_READ_LINE_EOF;
-    else
-      return MIME_READ_LINE_OK;
-}
-
-
-/*************************************************
-* Check for a MIME boundary                      *
-*************************************************/
-
-/* returns: 0 - no boundary found
-            1 - start boundary found
-            2 - end boundary found
-*/
-
-int mime_check_boundary(uschar *line, struct boundary *boundaries) {
-  struct boundary *thisboundary = boundaries;
-  uschar workbuf[MIME_SANITY_MAX_LINE_LENGTH+1];
-  unsigned int i,j=0;
-
-  /* check for '--' first */
-  if (Ustrncmp(line,"--",2) == 0) {
-
-    /* strip tab and space */
-    for (i = 2; i < Ustrlen(line); i++) {
-      if ((line[i] != ' ') && (line[i] != '\t')) {
-        workbuf[j] = line[i];
-        j++;
-      };
-    };
-    workbuf[j+1]='\0';
-
-    while(thisboundary != NULL) {
-      if (Ustrncmp(workbuf,thisboundary->boundary_string,Ustrlen(thisboundary->boundary_string)) == 0) {
-        if (Ustrncmp(&workbuf[Ustrlen(thisboundary->boundary_string)],"--",2) == 0) {
-          /* final boundary found */
-          return 2;
-        };
-        return 1;
-      };
-      thisboundary = thisboundary->next;
-    };
-  };
-
-  return 0;
-}
-
-
-/*************************************************
-* Check for start of a UUENCODE block            *
-*************************************************/
-
-/* returns 0 for no hit,
-           >0 for hit
-*/
-
-int mime_check_uu_start(uschar *line, uschar *uu_file_extension, int *has_tnef) {
-
-  if ( (strncmpic(line,US"begin ",6) == 0)) {
-    uschar *uu_filename = &line[6];
-
-    /* skip perms, if present */
-    Ustrtoul(&line[6],&uu_filename,10);
-
-    /* advance one char */
-    uu_filename++;
-
-    /* This should be the filename.
-    Check if winmail.dat is present,
-    which indicates TNEF. */
-    if (strncmpic(uu_filename,US"winmail.dat",11) == 0) {
-      *has_tnef = 1;
-    };
-
-    /* reverse to dot if present,
-    copy up to 4 chars for the extension */
-    if (Ustrrchr(uu_filename,'.') != NULL)
-      uu_filename = Ustrrchr(uu_filename,'.');
-
-    return sscanf(CS uu_filename, "%4[.0-9A-Za-z]",CS uu_file_extension);
-  }
-  else {
-    /* nothing found */
-    return 0;
-  };
-}
-
-
-/*************************************************
-* Decode a uu line                               *
-*************************************************/
-
-/* returns number of decoded bytes
-         -2 for soft errors
-*/
-
-int warned_about_uudec_line_sanity_1 = 0;
-int warned_about_uudec_line_sanity_2 = 0;
-long uu_decode_line(uschar *line, uschar **data, long line_len, uschar *info) {
-  uschar *p;
-  long num_decoded = 0;
-  uschar tmp_c;
-  uschar *work;
-  int uu_decoded_line_len, uu_encoded_line_len;
-
-  /* allocate memory for data and work buffer */
-  *data = (uschar *)malloc(line_len);
-  if (*data == NULL) {
-    (void)string_format(info, 1024,"unable to allocate %lu bytes",line_len);
-    return -2;
-  };
-
-  work = (uschar *)malloc(line_len);
-  if (work == NULL) {
-    (void)string_format(info, 1024,"unable to allocate %lu bytes",line_len);
-    return -2;
-  };
-
-  memcpy(work,line,line_len);
-
-  /* First char is line length
-  This is microsofts way of getting it. Scary. */
-  if (work[0] < 32) {
-    /* ignore this line */
-    return 0;
-  }
-  else {
-    uu_decoded_line_len = uudec[work[0]];
-  };
-
-  p = &work[1];
-
-  while (*p > 32) {
-    *p = uudec[*p];
-    p++;
-  };
-
-  uu_encoded_line_len = (p - &work[1]);
-  p = &work[1];
-
-  /* check that resulting line length is a multiple of 4 */
-  if ( ( uu_encoded_line_len % 4 ) != 0) {
-    if (!warned_about_uudec_line_sanity_1) {
-      mime_trigger_error(MIME_ERRORLEVEL_UU_MISALIGNED);
-      warned_about_uudec_line_sanity_1 = 1;
-    };
-    return -1;
-  };
-
-  /* check that the line length matches */
-  if ( ( (((uu_encoded_line_len/4)*3)-2) > uu_decoded_line_len ) || (((uu_encoded_line_len/4)*3) < uu_decoded_line_len) ) {
-    if (!warned_about_uudec_line_sanity_2) {
-      mime_trigger_error(MIME_ERRORLEVEL_UU_LINE_LENGTH);
-      warned_about_uudec_line_sanity_2 = 1;
-    };
-    return -1;
-  };
-
-  while ( ((p - &work[1]) < uu_encoded_line_len) && (num_decoded < uu_decoded_line_len)) {
-
-    /* byte 0 ---------------------- */
-    if ((p - &work[1] + 1) >= uu_encoded_line_len) {
-      return 0;
-    }
-
-    (*data)[num_decoded] = *p;
-    (*data)[num_decoded] <<= 2;
-
-    tmp_c = *(p+1);
-    tmp_c >>= 4;
-    (*data)[num_decoded] |= tmp_c;
-
-    num_decoded++;
-    p++;
-
-    /* byte 1 ---------------------- */
-    if ((p - &work[1] + 1) >= uu_encoded_line_len) {
-      return 0;
-    }
-
-    (*data)[num_decoded] = *p;
-    (*data)[num_decoded] <<= 4;
-
-    tmp_c = *(p+1);
-    tmp_c >>= 2;
-    (*data)[num_decoded] |= tmp_c;
-
-    num_decoded++;
-    p++;
-
-    /* byte 2 ---------------------- */
-    if ((p - &work[1] + 1) >= uu_encoded_line_len) {
-      return 0;
-    }
-
-    (*data)[num_decoded] = *p;
-    (*data)[num_decoded] <<= 6;
-
-    (*data)[num_decoded] |= *(p+1);
-
-    num_decoded++;
-    p+=2;
-
-  };
-
-  return uu_decoded_line_len;
-}
-
-
-/*************************************************
-* Decode a b64 or qp line                        *
-*************************************************/
-
-/* returns number of decoded bytes
-         -1 for hard errors
-         -2 for soft errors
-*/
-
-int warned_about_b64_line_length = 0;
-int warned_about_b64_line_sanity = 0;
-int warned_about_b64_illegal_char = 0;
-int warned_about_qp_line_sanity = 0;
-long mime_decode_line(int mime_demux_mode,uschar *line, uschar **data, long max_data_len, uschar *info) {
-  uschar *p;
-  long num_decoded = 0;
-  int offset = 0;
-  uschar tmp_c;
-
-  /* allocate memory for data */
-  *data = (uschar *)malloc(max_data_len);
-  if (*data == NULL) {
-    (void)string_format(info, 1024,"unable to allocate %lu bytes",max_data_len);
-    return -2;
-  };
-
-  if (mime_demux_mode == MIME_DEMUX_MODE_BASE64) {
-    /* ---------------------------------------------- */
-
-    /* NULL out trailing '\r' and '\n' chars */
-    while (Ustrrchr(line,'\r') != NULL) {
-      *(Ustrrchr(line,'\r')) = '\0';
-    };
-    while (Ustrrchr(line,'\n') != NULL) {
-      *(Ustrrchr(line,'\n')) = '\0';
-    };
-
-    /* check maximum base 64 line length */
-    if (Ustrlen(line) > MIME_SANITY_MAX_B64_LINE_LENGTH ) {
-      if (!warned_about_b64_line_length) {
-        mime_trigger_error(MIME_ERRORLEVEL_B64_LINE_LENGTH);
-        warned_about_b64_line_length = 1;
-      };
-    };
-
-    p = line;
-    offset = 0;
-    while (*(p+offset) != '\0') {
-      /* hit illegal char ? */
-      if (b64[*(p+offset)] == 128) {
-        if (!warned_about_b64_illegal_char) {
-          mime_trigger_error(MIME_ERRORLEVEL_B64_ILLEGAL_CHAR);
-          warned_about_b64_illegal_char = 1;
-        };
-        offset++;
-      }
-      else {
-        *p = b64[*(p+offset)];
-        p++;
-      };
-    };
-    *p = 255;
-
-    /* check that resulting line length is a multiple of 4 */
-    if ( ( (p - &line[0]) % 4 ) != 0) {
-      if (!warned_about_b64_line_sanity) {
-        mime_trigger_error(MIME_ERRORLEVEL_B64_MISALIGNED);
-        warned_about_b64_line_sanity = 1;
-      };
-    };
-
-    /* line is translated, start bit shifting */
-    p = line;
-    num_decoded = 0;
-
-    while(*p != 255) {
-
-      /* byte 0 ---------------------- */
-      if (*(p+1) == 255) {
-        break;
-      }
-
-      (*data)[num_decoded] = *p;
-      (*data)[num_decoded] <<= 2;
-
-      tmp_c = *(p+1);
-      tmp_c >>= 4;
-      (*data)[num_decoded] |= tmp_c;
-
-      num_decoded++;
-      p++;
-
-      /* byte 1 ---------------------- */
-      if (*(p+1) == 255) {
-        break;
-      }
-
-      (*data)[num_decoded] = *p;
-      (*data)[num_decoded] <<= 4;
-
-      tmp_c = *(p+1);
-      tmp_c >>= 2;
-      (*data)[num_decoded] |= tmp_c;
-
-      num_decoded++;
-      p++;
-
-      /* byte 2 ---------------------- */
-      if (*(p+1) == 255) {
-        break;
-      }
-
-      (*data)[num_decoded] = *p;
-      (*data)[num_decoded] <<= 6;
-
-      (*data)[num_decoded] |= *(p+1);
-
-      num_decoded++;
-      p+=2;
-
-    };
-    return num_decoded;
-    /* ---------------------------------------------- */
-  }
-  else if (mime_demux_mode == MIME_DEMUX_MODE_QP) {
-    /* ---------------------------------------------- */
-    p = line;
-
-    while (*p != 0) {
-      if (*p == '=') {
-        int decode_qp_result;
-
-        p = mime_decode_qp(p,&decode_qp_result);
-
-        if (decode_qp_result == -2) {
-          /* Error from decoder. p is unchanged. */
-          if (!warned_about_qp_line_sanity) {
-            mime_trigger_error(MIME_ERRORLEVEL_QP_ILLEGAL_CHAR);
-            warned_about_qp_line_sanity = 1;
-          };
-          (*data)[num_decoded] = '=';
-          num_decoded++;
-          p++;
-        }
-        else if (decode_qp_result == -1) {
-          /* End of the line with soft line break.
-          Bail out. */
-          goto QP_RETURN;
-        }
-        else if (decode_qp_result >= 0) {
-          (*data)[num_decoded] = decode_qp_result;
-          num_decoded++;
-        };
-      }
-      else {
-        (*data)[num_decoded] = *p;
-        num_decoded++;
-        p++;
-      };
-    };
-    QP_RETURN:
-    return num_decoded;
-    /* ---------------------------------------------- */
-  };
-
-  return 0;
-}
-
-
-
-/*************************************************
-* Log demime errors and set mime error level     *
-*************************************************/
-
-/* This sets the global demime_reason expansion
-variable and the demime_errorlevel gauge. */
-
-void mime_trigger_error(int level, uschar *format, ...) {
-  char *f;
-  va_list ap;
-
-  if( (f = malloc(16384+23)) != NULL ) {
-    /* first log the incident */
-    sprintf(f,"demime acl condition: ");
-    f+=22;
-    va_start(ap, format);
-    (void)string_vformat(US f, 16383,(char *)format, ap);
-    va_end(ap);
-    f-=22;
-    log_write(0, LOG_MAIN, "%s", f);
-    /* then copy to demime_reason_buffer if new
-    level is greater than old level */
-    if (level > demime_errorlevel) {
-      demime_errorlevel = level;
-      Ustrcpy(demime_reason_buffer, US f);
-      demime_reason = demime_reason_buffer;
-    };
-    free(f);
-  };
-}
-
-/*************************************************
-* Demultiplex MIME stream.                       *
-*************************************************/
-
-/* We can handle BASE64, QUOTED-PRINTABLE, and UUENCODE.
- UUENCODE does not need to have a proper
- transfer-encoding header, we detect it with "begin"
-
- This function will report human parsable errors in
- *info.
-
- returns DEFER -> soft error (see *info)
-         OK    -> EOF hit, all ok
-*/
-
-int mime_demux(FILE *f, uschar *info) {
-  int mime_demux_mode = MIME_DEMUX_MODE_MIME_HEADERS;
-  int uu_mode = MIME_UU_MODE_OFF;
-  FILE *mime_dump_file = NULL;
-  FILE *uu_dump_file = NULL;
-  uschar *line;
-  int mime_read_line_status = MIME_READ_LINE_OK;
-  long line_len;
-  struct boundary *boundaries = NULL;
-  struct mime_part mime_part_p;
-  int has_tnef = 0;
-  int has_rfc822 = 0;
-
-  /* allocate room for our linebuffer */
-  line = (uschar *)malloc(MIME_SANITY_MAX_LINE_LENGTH);
-  if (line == NULL) {
-    (void)string_format(info, 1024,"unable to allocate %u bytes",MIME_SANITY_MAX_LINE_LENGTH);
-    return DEFER;
-  };
-
-  /* clear MIME header structure */
-  memset(&mime_part_p,0,sizeof(mime_part));
-
-  /* ----------------------- start demux loop --------------------- */
-  while (mime_read_line_status == MIME_READ_LINE_OK) {
-
-    /* read a line of input. Depending on the mode we are in,
-    the returned format will differ. */
-    mime_read_line_status = mime_read_line(f,mime_demux_mode,line,&line_len);
-
-    if (mime_read_line_status == MIME_READ_LINE_OVERFLOW) {
-      mime_trigger_error(MIME_ERRORLEVEL_LONG_LINE);
-      /* despite the error, continue  .. */
-      mime_read_line_status = MIME_READ_LINE_OK;
-      continue;
-    }
-    else if (mime_read_line_status == MIME_READ_LINE_EOF) {
-      break;
-    };
-
-    if (mime_demux_mode == MIME_DEMUX_MODE_MIME_HEADERS) {
-      /* -------------- header mode --------------------- */
-
-      /* Check for an empty line, which is the end of the headers.
-       In HEADER mode, the line is returned "cooked", with the
-       final '\n' replaced by a ';' */
-      if (line_len == 1) {
-        int tmp;
-
-        /* We have reached the end of the headers. Start decoding
-        with the collected settings. */
-        if (mime_part_p.seen_content_transfer_encoding > 1) {
-          mime_demux_mode = mime_part_p.seen_content_transfer_encoding;
-        }
-        else {
-          /* default to plain mode if no specific encoding type found */
-          mime_demux_mode = MIME_DEMUX_MODE_PLAIN;
-        };
-
-        /* open new dump file */
-        tmp = mime_get_dump_file(mime_part_p.extension, &mime_dump_file, info);
-        if (tmp < 0) {
-          return DEFER;
-        };
-
-        /* clear out mime_part */
-        memset(&mime_part_p,0,sizeof(mime_part));
-      }
-      else {
-        /* Another header to check for file extensions,
-        encoding type and boundaries */
-        if (strncmpic(US"content-type:",line,Ustrlen("content-type:")) == 0) {
-          /* ---------------------------- Content-Type header ------------------------------- */
-          uschar *value = line;
-
-          /* check for message/partial MIME type and reject it */
-          if (mime_header_find(line,US"message/partial",NULL) > 0)
-            mime_trigger_error(MIME_ERRORLEVEL_MESSAGE_PARTIAL);
-
-          /* check for TNEF content type, remember to unpack TNEF later. */
-          if (mime_header_find(line,US"application/ms-tnef",NULL) > 0)
-            has_tnef = 1;
-
-          /* check for message/rfcxxx attachments */
-          if (mime_header_find(line,US"message/rfc822",NULL) > 0)
-            has_rfc822 = 1;
-
-          /* find the file extension, but do not fill it in
-          it is already set, since content-disposition has
-          precedence. */
-          if (mime_part_p.extension == NULL) {
-            if (mime_header_find(line,US"name",&value) == 2) {
-              if (Ustrlen(value) > MIME_SANITY_MAX_FILENAME)
-                mime_trigger_error(MIME_ERRORLEVEL_FILENAME_LENGTH);
-              mime_part_p.extension = value;
-              mime_part_p.extension = Ustrrchr(value,'.');
-              if (mime_part_p.extension == NULL) {
-                /* file without extension, setting
-                NULL will use the default extension later */
-                mime_part_p.extension = NULL;
-              }
-              else {
-                struct file_extension *this_extension =
-                  (struct file_extension *)malloc(sizeof(file_extension));
-
-                this_extension->file_extension_string =
-                  (uschar *)malloc(Ustrlen(mime_part_p.extension)+1);
-                Ustrcpy(this_extension->file_extension_string,
-                        mime_part_p.extension+1);
-                this_extension->next = file_extensions;
-                file_extensions = this_extension;
-              };
-            };
-          };
-
-          /* find a boundary and add it to the list, if present */
-          value = line;
-          if (mime_header_find(line,US"boundary",&value) == 2) {
-            struct boundary *thisboundary;
-
-            if (Ustrlen(value) > MIME_SANITY_MAX_BOUNDARY_LENGTH) {
-              mime_trigger_error(MIME_ERRORLEVEL_BOUNDARY_LENGTH);
-            }
-            else {
-              thisboundary = (struct boundary*)malloc(sizeof(boundary));
-              thisboundary->next = boundaries;
-              thisboundary->boundary_string = value;
-              boundaries = thisboundary;
-            };
-          };
-
-          if (mime_part_p.seen_content_type == 0) {
-            mime_part_p.seen_content_type = 1;
-          }
-          else {
-            mime_trigger_error(MIME_ERRORLEVEL_DOUBLE_HEADERS);
-          };
-          /* ---------------------------------------------------------------------------- */
-        }
-        else if (strncmpic(US"content-transfer-encoding:",line,Ustrlen("content-transfer-encoding:")) == 0) {
-          /* ---------------------------- Content-Transfer-Encoding header -------------- */
-
-         if (mime_part_p.seen_content_transfer_encoding == 0) {
-            if (mime_header_find(line,US"base64",NULL) > 0) {
-              mime_part_p.seen_content_transfer_encoding = MIME_DEMUX_MODE_BASE64;
-            }
-            else if (mime_header_find(line,US"quoted-printable",NULL) > 0) {
-              mime_part_p.seen_content_transfer_encoding = MIME_DEMUX_MODE_QP;
-            }
-            else {
-              mime_part_p.seen_content_transfer_encoding = MIME_DEMUX_MODE_PLAIN;
-            };
-          }
-          else {
-            mime_trigger_error(MIME_ERRORLEVEL_DOUBLE_HEADERS);
-          };
-          /* ---------------------------------------------------------------------------- */
-        }
-        else if (strncmpic(US"content-disposition:",line,Ustrlen("content-disposition:")) == 0) {
-          /* ---------------------------- Content-Disposition header -------------------- */
-          uschar *value = line;
-
-          if (mime_part_p.seen_content_disposition == 0) {
-            mime_part_p.seen_content_disposition = 1;
-
-            if (mime_header_find(line,US"filename",&value) == 2) {
-              if (Ustrlen(value) > MIME_SANITY_MAX_FILENAME)
-                mime_trigger_error(MIME_ERRORLEVEL_FILENAME_LENGTH);
-              mime_part_p.extension = value;
-              mime_part_p.extension = Ustrrchr(value,'.');
-              if (mime_part_p.extension == NULL) {
-                /* file without extension, setting
-                NULL will use the default extension later */
-                mime_part_p.extension = NULL;
-              }
-              else {
-                struct file_extension *this_extension =
-                  (struct file_extension *)malloc(sizeof(file_extension));
-
-                this_extension->file_extension_string =
-                  (uschar *)malloc(Ustrlen(mime_part_p.extension)+1);
-                Ustrcpy(this_extension->file_extension_string,
-                        mime_part_p.extension+1);
-                this_extension->next = file_extensions;
-                file_extensions = this_extension;
-              };
-            };
-          }
-          else {
-            mime_trigger_error(MIME_ERRORLEVEL_DOUBLE_HEADERS);
-          };
-          /* ---------------------------------------------------------------------------- */
-        };
-      };    /* End of header checks */
-      /* ------------------------------------------------ */
-    }
-    else {
-      /* -------------- non-header mode ----------------- */
-      int tmp;
-
-      if (uu_mode == MIME_UU_MODE_OFF) {
-        uschar uu_file_extension[5];
-        /* We are not currently decoding UUENCODE
-        Check for possible UUENCODE start tag. */
-        if (mime_check_uu_start(line,uu_file_extension,&has_tnef)) {
-          /* possible UUENCODING start detected.
-          Set unconfirmed mode first. */
-          uu_mode = MIME_UU_MODE_UNCONFIRMED;
-          /* open new uu dump file */
-          tmp = mime_get_dump_file(uu_file_extension, &uu_dump_file, info);
-          if (tmp < 0) {
-            free(line);
-            return DEFER;
-          };
-        };
-      }
-      else {
-        uschar *data;
-        long data_len = 0;
-
-        if (uu_mode == MIME_UU_MODE_UNCONFIRMED) {
-         /* We are in unconfirmed UUENCODE mode. */
-
-         data_len = uu_decode_line(line,&data,line_len,info);
-
-         if (data_len == -2) {
-           /* temp error, turn off uudecode mode */
-           if (uu_dump_file != NULL) {
-            (void)fclose(uu_dump_file); uu_dump_file = NULL;
-           };
-           uu_mode = MIME_UU_MODE_OFF;
-           return DEFER;
-         }
-         else if (data_len == -1) {
-           if (uu_dump_file != NULL) {
-            (void)fclose(uu_dump_file); uu_dump_file = NULL;
-           };
-           uu_mode = MIME_UU_MODE_OFF;
-           data_len = 0;
-         }
-         else if (data_len > 0) {
-           /* we have at least decoded a valid byte
-           turn on confirmed mode */
-           uu_mode = MIME_UU_MODE_CONFIRMED;
-         };
-        }
-        else if (uu_mode == MIME_UU_MODE_CONFIRMED) {
-          /* If we are in confirmed UU mode,
-          check for single "end" tag on line */
-          if ((strncmpic(line,US"end",3) == 0) && (line[3] < 32)) {
-            if (uu_dump_file != NULL) {
-              (void)fclose(uu_dump_file); uu_dump_file = NULL;
-            };
-            uu_mode = MIME_UU_MODE_OFF;
-          }
-          else {
-            data_len = uu_decode_line(line,&data,line_len,info);
-            if (data_len == -2) {
-               /* temp error, turn off uudecode mode */
-               if (uu_dump_file != NULL) {
-                 (void)fclose(uu_dump_file); uu_dump_file = NULL;
-               };
-               uu_mode = MIME_UU_MODE_OFF;
-               return DEFER;
-             }
-             else if (data_len == -1) {
-               /* skip this line */
-               data_len = 0;
-             };
-          };
-        };
-
-        /* write data to dump file, if available */
-        if (data_len > 0) {
-          if (fwrite(data,1,data_len,uu_dump_file) < data_len) {
-            /* short write */
-            (void)string_format(info, 1024,"short write on uudecode dump file");
-            free(line);
-            return DEFER;
-          };
-        };
-      };
-
-      if (mime_demux_mode != MIME_DEMUX_MODE_SCANNING) {
-        /* Non-scanning and Non-header mode. That means
-        we are currently decoding data to the dump
-        file. */
-
-        /* Check for a known boundary. */
-        tmp = mime_check_boundary(line,boundaries);
-        if (tmp == 1) {
-          /* We have hit a known start boundary.
-          That will put us back in header mode. */
-          mime_demux_mode = MIME_DEMUX_MODE_MIME_HEADERS;
-          if (mime_dump_file != NULL) {
-            /* if the attachment was a RFC822 message, recurse into it */
-            if (has_rfc822) {
-              has_rfc822 = 0;
-              rewind(mime_dump_file);
-              mime_demux(mime_dump_file,info);
-            };
-
-            (void)fclose(mime_dump_file); mime_dump_file = NULL;
-          };
-        }
-        else if (tmp == 2) {
-          /* We have hit a known end boundary.
-          That puts us into scanning mode, which will end when we hit another known start boundary */
-          mime_demux_mode = MIME_DEMUX_MODE_SCANNING;
-          if (mime_dump_file != NULL) {
-            /* if the attachment was a RFC822 message, recurse into it */
-            if (has_rfc822) {
-              has_rfc822 = 0;
-              rewind(mime_dump_file);
-              mime_demux(mime_dump_file,info);
-            };
-
-            (void)fclose(mime_dump_file); mime_dump_file = NULL;
-          };
-        }
-        else {
-          uschar *data;
-          long data_len = 0;
-
-          /* decode the line with the appropriate method */
-          if (mime_demux_mode == MIME_DEMUX_MODE_PLAIN) {
-            /* in plain mode, just dump the line */
-            data = line;
-            data_len = line_len;
-          }
-          else if ( (mime_demux_mode == MIME_DEMUX_MODE_QP) || (mime_demux_mode == MIME_DEMUX_MODE_BASE64) ) {
-            data_len = mime_decode_line(mime_demux_mode,line,&data,line_len,info);
-            if (data_len < 0) {
-              /* Error reported from the line decoder. */
-              data_len = 0;
-            };
-          };
-
-          /* write data to dump file */
-          if (data_len > 0) {
-            if (fwrite(data,1,data_len,mime_dump_file) < data_len) {
-              /* short write */
-              (void)string_format(info, 1024,"short write on dump file");
-              free(line);
-              return DEFER;
-            };
-          };
-
-        };
-      }
-      else {
-        /* Scanning mode. We end up here after a end boundary.
-        This will usually be at the end of a message or at
-        the end of a MIME container.
-        We need to look for another start boundary to get
-        back into header mode. */
-        if (mime_check_boundary(line,boundaries) == 1) {
-          mime_demux_mode = MIME_DEMUX_MODE_MIME_HEADERS;
-        };
-
-      };
-      /* ------------------------------------------------ */
-    };
-  };
-  /* ----------------------- end demux loop ----------------------- */
-
-  /* close files, they could still be open */
-  if (mime_dump_file != NULL)
-    (void)fclose(mime_dump_file);
-  if (uu_dump_file != NULL)
-    (void)fclose(uu_dump_file);
-
-  /* release line buffer */
-  free(line);
-
-  /* FIXME: release boundary buffers.
-  Not too much of a problem since
-  this instance of exim is not resident. */
-
-  if (has_tnef) {
-    uschar file_name[1024];
-    /* at least one file could be TNEF encoded.
-    attempt to send all decoded files thru the TNEF decoder */
-
-    (void)string_format(file_name,1024,"%s/scan/%s",spool_directory,message_id);
-    /* Removed FTTB. We need to decide on TNEF inclusion */
-    /* mime_unpack_tnef(file_name); */
-  };
-
-  return 0;
-}
-
-#endif
diff --git a/src/src/demime.h b/src/src/demime.h
deleted file mode 100644 (file)
index 0fec5be..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/*************************************************
-*     Exim - an Internet mail transport agent    *
-*************************************************/
-
-/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
-/* License: GPL */
-
-/* demime defines */
-
-#ifdef WITH_OLD_DEMIME
-
-#define MIME_DEMUX_MODE_SCANNING     0
-#define MIME_DEMUX_MODE_MIME_HEADERS 1
-#define MIME_DEMUX_MODE_BASE64       2
-#define MIME_DEMUX_MODE_QP           3
-#define MIME_DEMUX_MODE_PLAIN        4
-
-#define MIME_UU_MODE_OFF             0
-#define MIME_UU_MODE_UNCONFIRMED     1
-#define MIME_UU_MODE_CONFIRMED       2
-
-#define MIME_MAX_EXTENSION 128
-
-#define MIME_READ_LINE_EOF 0
-#define MIME_READ_LINE_OK 1
-#define MIME_READ_LINE_OVERFLOW 2
-
-#define MIME_SANITY_MAX_LINE_LENGTH 131071
-#define MIME_SANITY_MAX_FILENAME 512
-#define MIME_SANITY_MAX_HEADER_OPTION_VALUE 1024
-#define MIME_SANITY_MAX_B64_LINE_LENGTH 76
-#define MIME_SANITY_MAX_BOUNDARY_LENGTH 1024
-#define MIME_SANITY_MAX_DUMP_FILES 1024
-
-
-
-/* MIME errorlevel settings */
-
-#define MIME_ERRORLEVEL_LONG_LINE        3,US"line length in message or single header size exceeds %u bytes",MIME_SANITY_MAX_LINE_LENGTH
-#define MIME_ERRORLEVEL_TOO_MANY_PARTS   3,US"too many MIME parts (max %u)",MIME_SANITY_MAX_DUMP_FILES
-#define MIME_ERRORLEVEL_MESSAGE_PARTIAL  3,US"'message/partial' MIME type"
-#define MIME_ERRORLEVEL_FILENAME_LENGTH  3,US"proposed filename exceeds %u characters",MIME_SANITY_MAX_FILENAME
-#define MIME_ERRORLEVEL_BOUNDARY_LENGTH  3,US"boundary length exceeds %u characters",MIME_SANITY_MAX_BOUNDARY_LENGTH
-#define MIME_ERRORLEVEL_DOUBLE_HEADERS   2,US"double headers (content-type, content-disposition or content-transfer-encoding)"
-#define MIME_ERRORLEVEL_UU_MISALIGNED    1,US"uuencoded line length is not a multiple of 4 characters"
-#define MIME_ERRORLEVEL_UU_LINE_LENGTH   1,US"uuencoded line length does not match advertised number of bytes"
-#define MIME_ERRORLEVEL_B64_LINE_LENGTH  1,US"base64 line length exceeds %u characters",MIME_SANITY_MAX_B64_LINE_LENGTH
-#define MIME_ERRORLEVEL_B64_ILLEGAL_CHAR 2,US"base64 line contains illegal character"
-#define MIME_ERRORLEVEL_B64_MISALIGNED   1,US"base64 line length is not a multiple of 4 characters"
-#define MIME_ERRORLEVEL_QP_ILLEGAL_CHAR  1,US"quoted-printable encoding contains illegal character"
-
-
-/* demime structures */
-
-typedef struct mime_part {
-  /* true if there was a content-type header */
-  int seen_content_type;
-  /* true if there was a content-transfer-encoding header
-     contains the encoding type */
-  int seen_content_transfer_encoding;
-  /* true if there was a content-disposition header */
-  int seen_content_disposition;
-  /* pointer to a buffer with the proposed file extension */
-  uschar *extension;
-} mime_part;
-
-typedef struct boundary {
-  struct boundary *next;
-  uschar *boundary_string;
-} boundary;
-
-typedef struct file_extension {
-  struct file_extension *next;
-  uschar *file_extension_string;
-} file_extension;
-
-/* demime.c prototypes */
-
-unsigned int mime_hstr_i(uschar *);
-uschar      *mime_decode_qp(uschar *, int *);
-int          mime_get_dump_file(uschar *, FILE **, uschar *);
-int          mime_header_find(uschar *, uschar *, uschar **);
-int          mime_read_line(FILE *, int, uschar *, long *);
-int          mime_check_boundary(uschar *, struct boundary *);
-int          mime_check_uu_start(uschar *, uschar *, int *);
-long         uu_decode_line(uschar *, uschar **, long, uschar *);
-long         mime_decode_line(int ,uschar *, uschar **, long, uschar *);
-void         mime_trigger_error(int, uschar *, ...);
-int          mime_demux(FILE *, uschar *);
-
-
-
-/* BASE64 decoder matrix */
-static unsigned char b64[256]={
-/*   0 */ 128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,
-/*  16 */ 128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,
-/*  32 */ 128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,   62,  128,  128,  128,   63,
-/*  48 */  52,   53,   54,   55,   56,   57,   58,   59,   60,   61,  128,  128,  128,  255,  128,  128,
-/*  64 */ 128,    0,    1,    2,    3,    4,    5,    6,    7,    8,    9,   10,   11,   12,   13,   14,
-/*  80 */  15,   16,   17,   18,   19,   20,   21,   22,   23,   24,   25,  128,  128,  128,  128,  128,
-/*  96 */ 128,   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,  128,  128,  128,  128,  128,
- 128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,
- 128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,
- 128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,
- 128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,
- 128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,
- 128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,
- 128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,
- 128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128,  128
-};
-
-
-/* Microsoft-Style uudecode matrix */
-static unsigned char uudec[256]={
-/*   0 */   0,   33,   34,   35,   36,   37,   38,   39,   40,   41,   42,   43,   44,   45,   46,   47,
-/*  16 */  48,   49,   50,   51,   52,   53,   54,   55,   56,   57,   58,   59,   60,   61,   62,   63,
-/*  32 */   0,    1,    2,    3,    4,    5,    6,    7,    8,    9,   10,   11,   12,   13,   14,   15,
-/*  48 */  16,   17,   18,   19,   20,   21,   22,   23,   24,   25,   26,   27,   28,   29,   30,   31,
-/*  64 */  32,   33,   34,   35,   36,   37,   38,   39,   40,   41,   42,   43,   44,   45,   46,   47,
-/*  80 */  48,   49,   50,   51,   52,   53,   54,   55,   56,   57,   58,   59,   60,   61,   62,   63,
-/*  96 */   0,    1,    2,    3,    4,    5,    6,    7,    8,    9,   10,   11,   12,   13,   14,   15,
-/* 112 */  16,   17,   18,   19,   20,   21,   22,   23,   24,   25,   26,   27,   28,   29,   30,   31,
-/* 128 */  32,   33,   34,   35,   36,   37,   38,   39,   40,   41,   42,   43,   44,   45,   46,   47,
-/* 144 */  48,   49,   50,   51,   52,   53,   54,   55,   56,   57,   58,   59,   60,   61,   62,   63,
-/* 160 */   0,    1,    2,    3,    4,    5,    6,    7,    8,    9,   10,   11,   12,   13,   14,   15,
-/* 176 */  16,   17,   18,   19,   20,   21,   22,   23,   24,   25,   26,   27,   28,   29,   30,   31,
-/* 192 */  32,   33,   34,   35,   36,   37,   38,   39,   40,   41,   42,   43,   44,   45,   46,   47,
-/* 208 */  48,   49,   50,   51,   52,   53,   54,   55,   56,   57,   58,   59,   60,   61,   62,   63,
-/* 224 */   0,    1,    2,    3,    4,    5,    6,    7,    8,    9,   10,   11,   12,   13,   14,   15,
-/* 240 */  16,   17,   18,   19,   20,   21,   22,   23,   24,   25,   26,   27,   28,   29,   30,   31
-};
-
-#endif
index 81db2c2..487ac1a 100644 (file)
@@ -814,9 +814,6 @@ fprintf(f, "Support for:");
 #ifdef WITH_CONTENT_SCAN
   fprintf(f, " Content_Scanning");
 #endif
-#ifdef WITH_OLD_DEMIME
-  fprintf(f, " Old_Demime");
-#endif
 #ifndef DISABLE_DKIM
   fprintf(f, " DKIM");
 #endif
index 73cb99e..1c9a3be 100644 (file)
@@ -480,10 +480,6 @@ static var_entry var_table[] = {
   { "dcc_header",          vtype_stringptr,   &dcc_header },
   { "dcc_result",          vtype_stringptr,   &dcc_result },
 #endif
-#ifdef WITH_OLD_DEMIME
-  { "demime_errorlevel",   vtype_int,         &demime_errorlevel },
-  { "demime_reason",       vtype_stringptr,   &demime_reason },
-#endif
 #ifndef DISABLE_DKIM
   { "dkim_algo",           vtype_dkim,        (void *)DKIM_ALGO },
   { "dkim_bodylength",     vtype_dkim,        (void *)DKIM_BODYLENGTH },
@@ -532,9 +528,6 @@ static var_entry var_table[] = {
   { "exim_path",           vtype_stringptr,   &exim_path },
   { "exim_uid",            vtype_uid,         &exim_uid },
   { "exim_version",        vtype_stringptr,   &version_string },
-#ifdef WITH_OLD_DEMIME
-  { "found_extension",     vtype_stringptr,   &found_extension },
-#endif
   { "headers_added",       vtype_string_func, &fn_hdrs_added },
   { "home",                vtype_stringptr,   &deliver_home },
   { "host",                vtype_stringptr,   &deliver_host },
index 63ea3f8..beae009 100644 (file)
@@ -141,9 +141,6 @@ extern void    deliver_succeeded(address_item *);
 
 extern uschar *deliver_get_sender_address (uschar *id);
 
-#ifdef WITH_OLD_DEMIME
-extern int     demime(const uschar **);
-#endif
 extern BOOL    directory_make(const uschar *, const uschar *, int, BOOL);
 #ifndef DISABLE_DKIM
 extern BOOL    dkim_transport_write_message(address_item *, int, int,
index ec2685b..8e5a4df 100644 (file)
@@ -625,11 +625,6 @@ uschar *deliver_selectstring   = NULL;
 BOOL    deliver_selectstring_regex = FALSE;
 uschar *deliver_selectstring_sender = NULL;
 BOOL    deliver_selectstring_sender_regex = FALSE;
-#ifdef WITH_OLD_DEMIME
-int     demime_errorlevel      = 0;
-int     demime_ok              = 0;
-uschar *demime_reason          = NULL;
-#endif
 BOOL    disable_callout_flush  = FALSE;
 BOOL    disable_delay_flush    = FALSE;
 #ifdef ENABLE_DISABLE_FSYNC
@@ -728,9 +723,6 @@ uschar *filter_test_sfile      = NULL;
 uschar *filter_test_ufile      = NULL;
 uschar *filter_thisaddress     = NULL;
 int     finduser_retries       = 0;
-#ifdef WITH_OLD_DEMIME
-uschar *found_extension        = NULL;
-#endif
 uid_t   fixed_never_users[]    = { FIXED_NEVER_USERS };
 uschar *freeze_tell            = NULL;
 uschar *freeze_tell_config     = NULL;
index 57a5695..5a0b79e 100644 (file)
@@ -362,11 +362,6 @@ extern uschar *deliver_selectstring;   /* For selecting by recipient */
 extern BOOL    deliver_selectstring_regex; /* String is regex */
 extern uschar *deliver_selectstring_sender; /* For selecting by sender */
 extern BOOL    deliver_selectstring_sender_regex; /* String is regex */
-#ifdef WITH_OLD_DEMIME
-extern int     demime_errorlevel;      /* Severity of MIME error */
-extern int     demime_ok;              /* Nonzero if message has been demimed */
-extern uschar *demime_reason;          /* Reason for broken MIME container */
-#endif
 extern BOOL    disable_callout_flush;  /* Don't flush before callouts */
 extern BOOL    disable_delay_flush;    /* Don't flush before "delay" in ACL */
 #ifdef ENABLE_DISABLE_FSYNC
@@ -465,9 +460,6 @@ extern uschar *filter_test_ufile;      /* User filter test file */
 extern uschar *filter_thisaddress;     /* For address looping */
 extern int     finduser_retries;       /* Retry count for getpwnam() */
 extern uid_t   fixed_never_users[];    /* Can't be overridden */
-#ifdef WITH_OLD_DEMIME
-extern uschar *found_extension;        /* demime acl condition: file extension found */
-#endif
 extern uschar *freeze_tell;            /* Message on (some) freezings */
 extern uschar *freeze_tell_config;     /* The configured setting */
 extern uschar *fudged_queue_times;     /* For use in test harness */
index 357eba9..ada3f36 100644 (file)
@@ -13,12 +13,6 @@ sub directory of exim's spool directory. */
 #include "exim.h"
 #ifdef WITH_CONTENT_SCAN
 
-/* externals, we must reset them on unspooling */
-#ifdef WITH_OLD_DEMIME
-extern int demime_ok;
-extern struct file_extension *file_extensions;
-#endif
-
 extern int malware_ok;
 extern int spam_ok;
 
@@ -193,20 +187,11 @@ return yield;
 
 
 
-/* remove mbox spool file, demimed files and temp directory */
 
+/* remove mbox spool file and temp directory */
 void
 unspool_mbox(void)
 {
-
-/* reset all exiscan state variables */
-#ifdef WITH_OLD_DEMIME
-demime_ok = 0;
-demime_errorlevel = 0;
-demime_reason = NULL;
-file_extensions = NULL;
-#endif
-
 spam_ok = 0;
 malware_ok = 0;