- };
-
- DECODE_HEADERS:
- /* parse headers, set up expansion variables */
- while(mime_get_header(f,header)) {
- int i;
- /* loop through header list */
- for (i = 0; i < mime_header_list_size; i++) {
- uschar *header_value = NULL;
- int header_value_len = 0;
-
- /* found an interesting header? */
- if (strncmpic(mime_header_list[i].name,header,mime_header_list[i].namelen) == 0) {
- uschar *p = header + mime_header_list[i].namelen;
- /* yes, grab the value (normalize to lower case)
- and copy to its corresponding expansion variable */
- while(*p != ';') {
- *p = tolower(*p);
- p++;
- };
- header_value_len = (p - (header + mime_header_list[i].namelen));
- header_value = (uschar *)malloc(header_value_len+1);
- memset(header_value,0,header_value_len+1);
- p = header + mime_header_list[i].namelen;
- Ustrncpy(header_value, p, header_value_len);
- debug_printf("Found %s MIME header, value is '%s'\n", mime_header_list[i].name, header_value);
- *((uschar **)(mime_header_list[i].value)) = header_value;
-
- /* make p point to the next character after the closing ';' */
- p += (header_value_len+1);
-
- /* grab all param=value tags on the remaining line, check if they are interesting */
- NEXT_PARAM_SEARCH: while (*p != 0) {
- int j;
- for (j = 0; j < mime_parameter_list_size; j++) {
- uschar *param_value = NULL;
- int param_value_len = 0;
-
- /* found an interesting parameter? */
- if (strncmpic(mime_parameter_list[j].name,p,mime_parameter_list[j].namelen) == 0) {
- uschar *q = p + mime_parameter_list[j].namelen;
- /* yes, grab the value and copy to its corresponding expansion variable */
- while(*q != ';') q++;
- param_value_len = (q - (p + mime_parameter_list[j].namelen));
- param_value = (uschar *)malloc(param_value_len+1);
- memset(param_value,0,param_value_len+1);
- q = p + mime_parameter_list[j].namelen;
- Ustrncpy(param_value, q, param_value_len);
- param_value = rfc2047_decode(param_value, check_rfc2047_length, NULL, 32, ¶m_value_len, &q);
- debug_printf("Found %s MIME parameter in %s header, value is '%s'\n", mime_parameter_list[j].name, mime_header_list[i].name, param_value);
- *((uschar **)(mime_parameter_list[j].value)) = param_value;
- p += (mime_parameter_list[j].namelen + param_value_len + 1);
- goto NEXT_PARAM_SEARCH;
- };
- }
- /* There is something, but not one of our interesting parameters.
- Advance to the next semicolon */
- while(*p != ';') p++;
- p++;
- };
- };
- };
- };
-
- /* set additional flag variables (easier access) */
- if ( (mime_content_type != NULL) &&
- (Ustrncmp(mime_content_type,"multipart",9) == 0) )
- mime_is_multipart = 1;
-
- /* Make a copy of the boundary pointer.
- Required since mime_boundary is global
- and can be overwritten further down in recursion */
- nested_context.boundary = mime_boundary;
-
- /* raise global counter */
- mime_part_count++;
-
- /* copy current file handle to global variable */
- mime_stream = f;
- mime_current_boundary = context ? context->boundary : 0;
+ }
+
+ /* boundary line must start with 2 dashes */
+ if ( Ustrncmp(header, "--", 2) == 0
+ && Ustrncmp(header+2, context->boundary, Ustrlen(context->boundary)) == 0
+ )
+ { /* found boundary */
+ if (Ustrncmp((header+2+Ustrlen(context->boundary)), "--", 2) == 0)
+ {
+ /* END boundary found */
+ DEBUG(D_acl) debug_printf_indent("MIME: End boundary found %s\n",
+ context->boundary);
+ return rc;
+ }
+
+ DEBUG(D_acl) debug_printf_indent("MIME: Next part with boundary %s\n",
+ context->boundary);
+ break;
+ }
+ }
+
+ /* parse headers, set up expansion variables */
+ while (mime_get_header(f, header))
+ {
+ struct mime_header * mh;
+
+ /* look for interesting headers */
+ for (mh = mime_header_list;
+ mh < mime_header_list + mime_header_list_size;
+ mh++) if (strncmpic(mh->name, header, mh->namelen) == 0)
+ {
+ uschar * p = header + mh->namelen;
+ uschar * q;
+
+ /* grab the value (normalize to lower case)
+ and copy to its corresponding expansion variable */
+
+ for (q = p; *q != ';' && *q; q++) ;
+ *mh->value = string_copynlc(p, q-p);
+ DEBUG(D_acl) debug_printf_indent("MIME: found %s header, value is '%s'\n",
+ mh->name, *mh->value);
+
+ if (*(p = q)) p++; /* jump past the ; */
+
+ {
+ uschar * mime_fname = NULL;
+ uschar * mime_fname_rfc2231 = NULL;
+ uschar * mime_filename_charset = NULL;
+ BOOL decoding_failed = FALSE;
+
+ /* grab all param=value tags on the remaining line,
+ check if they are interesting */
+
+ while (*p)
+ {
+ mime_parameter * mp;
+
+ DEBUG(D_acl) debug_printf_indent("MIME: considering paramlist '%s'\n", p);
+
+ if ( !mime_filename
+ && strncmpic(CUS"content-disposition:", header, 20) == 0
+ && strncmpic(CUS"filename*", p, 9) == 0
+ )
+ { /* RFC 2231 filename */
+ uschar * q;
+
+ /* find value of the filename */
+ p += 9;
+ while(*p != '=' && *p) p++;
+ if (*p) p++; /* p is filename or NUL */
+ q = mime_param_val(&p); /* p now trailing ; or NUL */
+
+ if (q && *q)
+ {
+ uschar * temp_string, * err_msg;
+ int slen;
+
+ /* build up an un-decoded filename over successive
+ filename*= parameters (for use when 2047 decode fails) */
+
+ mime_fname_rfc2231 = string_sprintf("%#s%s",
+ mime_fname_rfc2231, q);
+
+ if (!decoding_failed)
+ {
+ int size;
+ if (!mime_filename_charset)
+ {
+ uschar * s = q;
+
+ /* look for a ' in the "filename" */
+ while(*s != '\'' && *s) s++; /* s is 1st ' or NUL */
+
+ if ((size = s-q) > 0)
+ mime_filename_charset = string_copyn(q, size);
+
+ if (*(p = s)) p++;
+ while(*p == '\'') p++; /* p is after 2nd ' */
+ }
+ else
+ p = q;
+
+ DEBUG(D_acl) debug_printf_indent("MIME: charset %s fname '%s'\n",
+ mime_filename_charset ? mime_filename_charset : US"<NULL>", p);
+
+ temp_string = rfc2231_to_2047(p, mime_filename_charset, &slen);
+ DEBUG(D_acl) debug_printf_indent("MIME: 2047-name %s\n", temp_string);
+
+ temp_string = rfc2047_decode(temp_string, FALSE, NULL, ' ',
+ NULL, &err_msg);
+ DEBUG(D_acl) debug_printf_indent("MIME: plain-name %s\n", temp_string);
+
+ if (!temp_string || (size = Ustrlen(temp_string)) == slen)
+ decoding_failed = TRUE;
+ else
+ /* build up a decoded filename over successive
+ filename*= parameters */
+
+ mime_filename = mime_fname = mime_fname
+ ? string_sprintf("%s%s", mime_fname, temp_string)
+ : temp_string;
+ }
+ }
+ }
+
+ else
+ /* look for interesting parameters */
+ for (mp = mime_parameter_list;
+ mp < mime_parameter_list + nelem(mime_parameter_list);
+ mp++
+ ) if (strncmpic(mp->name, p, mp->namelen) == 0)
+ {
+ uschar * q;
+ uschar * dummy_errstr;
+
+ /* grab the value and copy to its expansion variable */
+ p += mp->namelen;
+ q = mime_param_val(&p); /* p now trailing ; or NUL */
+
+ *mp->value = q && *q
+ ? rfc2047_decode(q, check_rfc2047_length, NULL, 32, NULL,
+ &dummy_errstr)
+ : NULL;
+ DEBUG(D_acl) debug_printf_indent(
+ "MIME: found %s parameter in %s header, value '%s'\n",
+ mp->name, mh->name, *mp->value);
+
+ break; /* done matching param names */
+ }
+
+
+ /* There is something, but not one of our interesting parameters.
+ Advance past the next semicolon */
+ p = mime_next_semicolon(p);
+ if (*p) p++;
+ } /* param scan on line */
+
+ if (strncmpic(CUS"content-disposition:", header, 20) == 0)
+ {
+ if (decoding_failed) mime_filename = mime_fname_rfc2231;
+
+ DEBUG(D_acl) debug_printf_indent(
+ "MIME: found %s parameter in %s header, value is '%s'\n",
+ "filename", mh->name, mime_filename);
+ }
+ }
+ }
+ }
+
+ /* set additional flag variables (easier access) */
+ if ( mime_content_type
+ && Ustrncmp(mime_content_type,"multipart",9) == 0
+ )
+ mime_is_multipart = 1;
+
+ /* Make a copy of the boundary pointer.
+ Required since mime_boundary is global
+ and can be overwritten further down in recursion */
+ nested_context.boundary = mime_boundary;
+
+ /* raise global counter */
+ mime_part_count++;
+
+ /* copy current file handle to global variable */
+ mime_stream = f;
+ mime_current_boundary = context ? context->boundary : 0;
+
+ /* Note the context */
+ mime_is_coverletter = !(context && context->context == MBC_ATTACHMENT);
+
+ /* call ACL handling function */
+ rc = acl_check(ACL_WHERE_MIME, NULL, acl, user_msgptr, log_msgptr);
+
+ mime_stream = NULL;
+ mime_current_boundary = NULL;
+
+ if (rc != OK) break;
+
+ /* If we have a multipart entity and a boundary, go recursive */
+ if ( (mime_content_type != NULL) &&
+ (nested_context.boundary != NULL) &&
+ (Ustrncmp(mime_content_type,"multipart",9) == 0) )
+ {
+ DEBUG(D_acl)
+ debug_printf_indent("MIME: Entering multipart recursion, boundary '%s'\n",
+ nested_context.boundary);
+
+ nested_context.context =
+ context && context->context == MBC_ATTACHMENT
+ ? MBC_ATTACHMENT
+ : Ustrcmp(mime_content_type,"multipart/alternative") == 0
+ || Ustrcmp(mime_content_type,"multipart/related") == 0
+ ? MBC_COVERLETTER_ALL
+ : MBC_COVERLETTER_ONESHOT;
+
+ rc = mime_acl_check(acl, f, &nested_context, user_msgptr, log_msgptr);
+ if (rc != OK) break;
+ }
+ else if ( (mime_content_type != NULL) &&
+ (Ustrncmp(mime_content_type,"message/rfc822",14) == 0) )
+ {
+ const uschar *rfc822name = NULL;
+ uschar filename[2048];
+ int file_nr = 0;
+ int result = 0;