.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$& &&&
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
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"
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
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
&%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
&*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
+++ /dev/null
-/*************************************************
-* 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
+++ /dev/null
-/*************************************************
-* 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