📄 mimedecode.c
字号:
/* * This program comes with absolutely no guarantees and may * be used for whatever purpose, * * Frederik H. Andersen - 1996 * Dansk Data Elektronik A/S * * fha@dde.dk * *//* * This program performs the decoding of transfer encoded text type * mime messages. The message in its entirety is read from stdin. * The decoded message is written to stdout; hence, this program * behaves as a filter which may be placed wherever convenient. * I particular like it in front of my slocal command in my .forward * file. * * It is assumed that the message has reached its point of final * delivery and at that point 8-bit text types can be handled * natively. Hence, the need for transfer-encodings is not present * any more. * * Only some cases are handled: * - encoded header fields are decoded from QP or B encoding. * The charset is assumed to be iso-8859-1 * - part or subparts of content-type text only are decoded * - all other content-types are passed transparently * *//* extensive changes by Ričardas Čepas <rch@richard.eu.org> * All charsets are converted to UTF-8 */#define _POSIX_C_SOURCE 2#include <stdio.h>#include <string.h>#include <ctype.h>#include <stdlib.h>#include <unistd.h>/* Some defines. Should have gone into a file by itself. */#define MIMED_VERSION "mimedecode version 1.8"#define lower(c) ( isupper(c) ? tolower(c) : (c) )#include "2UTF.h"/* content types: */#define UNDEF 0#define TEXT 1#define MULT 2#define MULT_DIGEST 3#define MULT_PGP 4#define MESG 5/* transfer encodings: */#define QP 1#define B64 2#define BIT7 3#define BIT8 4#define BINARY 5#define UN 255#define LWSP " \t\n"unsigned char b64_map[256] ={ UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, /* 0x00 - 0x0f, NUL - SI */ UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, /* 0x10 - 0x1f, DLE - US */ UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, 62, UN, UN, UN, 63, /* 0x20 - 0x2f, SP - / */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, UN, UN, UN, 0x3d, UN, UN, /* 0x30 - 0x3f, 0 - ? */ UN, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40 - 0x4f, @ - O */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, UN, UN, UN, UN, UN, /* 0x50 - 0x5f, P - _ */ UN, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60 - 0x6f, ` - o */ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, UN, UN, UN, UN, UN, /* 0x70 - 0x7f, p - DEL */ UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, /* 0x80 - 0x8f */ UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, /* 0x90 - 0x9f */ UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, /* 0xA0 - 0xAf */ UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, /* 0xB0 - 0xBf */ UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, /* 0xC0 - 0xCf */ UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, /* 0xD0 - 0xDf */ UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, /* 0xE0 - 0xEf */ UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, /* 0xF0 - 0xFf */};char *especials = "()<>@,;:\\\"/[]?.=";int reserve = 100;/*******************************************************************/intparse_message (boundary)/*******************************************************************/ char *boundary;{ int c, saved_content_type; struct mime_header_type mhead = {0, 0, "\0", "\0", "\0"}; int ret; if (Debug) if (boundary) fprintf (stderr, " - Entry parse_message with boundary=\"%s\" \n", boundary); else fprintf (stderr, " - Entry parse_message without boundary \n"); /* parse header */ if (!(ret = parse_header (&mhead))) { if (Debug) fprintf (stderr, "parse of message header failed: %d\n", ret); return (FALSE); } if (mhead.content_type == MULT || mhead.content_type == MULT_DIGEST) { if (Debug >= 2) { fprintf (stderr, "message is multipart\n"); fprintf (stderr, "search header boundary line: %s\n", mhead.boundary); } /* search for the boundary line before parsing further */ if ((ret = Seek_boundary (stdin, mhead.boundary, PUSH_BOUNDARY)) == TRUE) /* When the message is of type multipart we have to handle each * part as an individual message. * We use the boundary to identify the beginning of each part */ do /* Check if part's own headers are missing */ if ((c = getc (stdin)) == '\n') { putc (c, charset_p->pipe); if (mhead.content_type == MULT_DIGEST) /* default is message/rfc */ ret = parse_message (mhead.boundary); else { /* default is text/plain; charset=us-ascii */ saved_content_type = mhead.content_type; mhead.content_type = TEXT; if (charset_p->USASCII_is_subset == NO) Validate_charset ("us-ascii", 0); ret = parse_body (&mhead, mhead.boundary); mhead.content_type = saved_content_type; } } else { ungetc (c, stdin); ret = parse_message (mhead.boundary); } while (ret == TRUE); if (boundary) /* && ret == END_BOUNDARY) */ /* skip stuff after the last part of inner multipart message */ ret = Seek_boundary (ret < OUTER_BOUNDARY ? stdin : NULL, boundary, 0); } else if (mhead.content_type == MESG) { /* When message is type message we have to handle the body as * an individual message. */ ret = parse_message (boundary); } else /* plain message */ { ret = parse_body (&mhead, boundary); } if (Debug) if (boundary) fprintf (stderr, " - parse_message with boundary=\"%s\" returned %i - \n", boundary, ret); else fprintf (stderr, " - parse_message without boundary returned %i - \n", ret); return (ret);}/*******************************************************************/intparse_body (mime_header_p, boundary)/*******************************************************************//* int type, encoding; */ struct mime_header_type *mime_header_p; char *boundary;{ int c; int ret = FALSE; /* ??? */ /*struct charset_type *old_charset_p; */ if (Debug) fprintf (stderr, " -- Entry parse_body -- \n"); if (Debug >= 2) fprintf (stderr, " -- type: %d, enc: %d\n", mime_header_p->content_type, mime_header_p->transfer_encoding); if ((mime_header_p->content_type == TEXT) && \ ((mime_header_p->transfer_encoding == QP) \ ||(mime_header_p->transfer_encoding == B64) \ ||(mime_header_p->transfer_encoding == BIT8) \ ||(mime_header_p->transfer_encoding == BIT7) \ )) { if (boundary) { if (Debug >= 2) fprintf (stderr, " -- with boundary: %s\n -- decoding -- \n", boundary); if (mime_header_p->transfer_encoding == QP) ret = decode_quoted_printable (stdin, charset_p->pipe, boundary); else if (mime_header_p->transfer_encoding == B64) ret = decode_base64 (stdin, charset_p->pipe, boundary); if (ret == FALSE) ret = Seek_boundary (stdin, boundary, 0); } else /* no boundary */ { if (Debug >= 2) fprintf (stderr, " -- decoding -- \n"); if (mime_header_p->transfer_encoding == QP) ret = decode_quoted_printable (stdin, charset_p->pipe, 0); else if (mime_header_p->transfer_encoding == B64) ret = decode_base64 (stdin, charset_p->pipe, 0); else /*if (mime_header_p->transfer_encoding == BIT8 || mime_header_p->transfer_encoding == BIT7) */ ret = 2, Pipe_to_UTF8 (stdin); } } else if (boundary) { if (Debug >= 2) fprintf (stderr, " -- with boundary: %s\n", boundary); if (Debug >= 2) fprintf (stderr, " -- skipping -- \n"); /* old_charset_p = charset_p; charset_p = &unknown_charset; */ Validate_charset ("'unknown'", 0); ret = Seek_boundary (stdin, boundary, 0); Validate_charset (NULL, 0);/* charset_p = old_charset_p; */ } else { if (Debug >= 2) fprintf (stderr, " -- skipping -- \n"); Validate_charset ("'unknown'", 0); ret = 2; while ((c = getc (stdin)) != EOF) putc (c, charset_p->pipe); } return (ret);}char *Add_to_buffer (struct buffer_type *buffer_p, char *string){/* size_t old_size = buffer_p->end - buffer_p->start + 1; if (Debug >= 9) fprintf (stderr, "2UTF: realloc %i += %i \n", old_size, strlen (string)); buffer_p->start = xrealloc (buffer_p->start, (old_size + strlen (string))); *//* buffer_p->start changes *//* return (buffer_p->end = Stpcpy (buffer_p->start + old_size - 1, string)); */ size_t length; length = strlen (string); if (buffer_p->next + length - buffer_p->end > reserve) { fprintf (stderr, "2UTF: %s %li\n", buffer_overflow, (long)(buffer_p->next + length - buffer_p->end - reserve)); length = buffer_p->end - buffer_p->next - reserve; } memcpy (buffer_p->next, string, length); return (buffer_p->next += length);}/*******************************************************************/intparse_header (mhp)/*******************************************************************/ struct mime_header_type *mhp;{ unsigned char *cp; unsigned char *nlbp; int c; int ct_charset_unknown = FALSE; /* Warning about unknown charset in ct */ size_t ct_header_charset_name_begin = 0, ct_header_charset_name_end = 0; int ct_is_changing = FALSE; /* Content charset parameter needs change */ int ct_read = FALSE; /* Content-type field read */ int ct_written = FALSE; /* Content-type written */ int cte_read = FALSE; /* Content-transfer-encoding read */ int cte_written = FALSE; /* Content-transfer-encoding written */ int headers_8bit = FALSE; /* non-MIME-encrypted headers */ int quoted; struct buffer_type headers_buffer = {NULL, NULL, NULL, NULL};#define REALLOC_CHUNK 4000 line.buf = headers_buffer.next = headers_buffer.start = headers_buffer.header_start = xrealloc (line.buf, line.length += reserve); headers_buffer.end = headers_buffer.start + line.length - reserve;/* = xmalloc (REALLOC_CHUNK * 2 + reserve); headers_buffer.end = headers_buffer.start + REALLOC_CHUNK * 2; */ if (Debug) fprintf (stderr, " -- Entry parse_header - pass 1 -- \n"); mhp->boundary[0] = '\001'; mhp->content_type = UNDEF; mhp->transfer_encoding = BIT8; mhp->headers_charset[0] = '\0'; mhp->content_charset[0] = '\0'; /* first pass */ while (TRUE) { if ((c = getc (stdin)) == EOF) { Validate_charset ("us-ascii", 0); fwrite (headers_buffer.start, 1, headers_buffer.next - headers_buffer.start, charset_p->pipe); return (FALSE); } again: *headers_buffer.next++ = c; while (headers_buffer.next >= headers_buffer.end) { /* realloc more memory */ size_t old_size = headers_buffer.end - headers_buffer.start; size_t next_offset = headers_buffer.next - headers_buffer.start; size_t header_start_offset = headers_buffer.header_start - headers_buffer.start; if (Debug >= 9) fprintf (stderr, "2UTF: realloc %li += %i \n", (long)old_size + reserve, REALLOC_CHUNK); line.buf = headers_buffer.start = xrealloc (headers_buffer.start, old_size + reserve + REALLOC_CHUNK); line.length += REALLOC_CHUNK; headers_buffer.end = headers_buffer.start + old_size + REALLOC_CHUNK; headers_buffer.next = headers_buffer.start + next_offset; headers_buffer.header_start = headers_buffer.start + header_start_offset; if (line.length != old_size + reserve + REALLOC_CHUNK && Debug) fprintf (stderr, "2UTF: memory allocation error: \n %li != %li \n", (long)line.length, (long)old_size + reserve + REALLOC_CHUNK); } if ((c > 0x7F || (c != '\n' && c != '\t' && iscntrl (c))) &&headers_8bit == FALSE) { headers_8bit = TRUE; if (Debug >= 2) fprintf (stderr, " -- 8 bit bytes or control codes in headers detected \n"); } if (c == '\n') /* end of line reached */ { if ((c = getc (stdin)) == EOF) { Add_to_buffer (&headers_buffer, "\n"); Validate_charset ("us-ascii", 0); fwrite (headers_buffer.start, 1, headers_buffer.next - headers_buffer.start, charset_p->pipe); break; } else if (c == ' ' || c == '\t') /* if next line begins with space * it is continuation of the same header */ goto again; else ungetc (c, stdin); *headers_buffer.next = '\0'; /* zero terminate the line buf *//* headers_buffer.header_start = headers_buffer.next; */ if (Debug >= 4) fprintf (stderr, "headers_buffer: %s\n", headers_buffer.header_start); if (!Strcase_has_prefix (headers_buffer.header_start, "content-type:")) { ct_read = TRUE; cp = headers_buffer.header_start + strlen ("Content-Type:"); cp += strspn (cp, LWSP); /* we are only doing decoding of text types */ if (Strcase_has_prefix (cp, "text/") == 0) { if (Debug >= 3) fprintf (stderr, "Content IS text\n"); mhp->content_type = TEXT; if ((cp = strchr (cp, ';'))) while ((cp = strchr (cp, ';'))) if (Strcase_has_prefix (cp += strspn (cp, "; \t\n"), "charset=") == 0) { ct_header_charset_name_begin = (cp += 8) - headers_buffer.header_start; cp += strspn (cp, "'\""); if ((cp[0] == 'x' || cp[0] == 'X') &&cp[1] == '-') cp += 2; ct_header_charset_name_end = cp + strcspn (cp, ";\n\r") - headers_buffer.header_start; strncpy (mhp->content_charset, cp, MIN (79, strcspn (cp, "*'\"; \t\n\r"))); mhp->content_charset[ MIN (79, strcspn (cp, "*'\"; \t\n\r"))] = '\0'; if (Debug) fprintf (stderr, " -- Content charset: %s\n", mhp->content_charset); break; } } else if (Strcase_has_prefix (cp, "multipart/") == 0) { if (Strcase_has_prefix (cp += strlen ("multipart/"), "digest") == 0) mhp->content_type = MULT_DIGEST; else if (Strcase_has_prefix (cp, "pgp") == 0 ||Strcase_has_prefix (cp, "signed") == 0) mhp->content_type = MULT_PGP; else mhp->content_type = MULT; /* search for the boundary parameter */ while ((cp = strchr (cp, ';'))) if (Strcase_has_prefix (cp += 1 + strspn (1 + cp, LWSP), "boundary=") == 0) /* skip ; and remove white space */ { cp += strlen ("boundary="); if (*cp == '"') { quoted = TRUE; cp++; } else quoted = FALSE; *(cp = Stpncpy (mhp->boundary, cp, 78)) = '"'; *++cp = '\0'; *(cp = mhp->boundary + strcspn (mhp->boundary, quoted ? "\"\n" : "\"" LWSP)) = '\0'; /* remove trailing white space */ cp--; while ((char *) cp >= mhp->boundary &&(*cp == ' ' || *cp == '\t')) *cp-- = '\0'; if ((char *) cp <= mhp->boundary ||mhp->boundary[0] == '\0') { mhp->boundary[0] = '\0'; mhp->content_type = UNDEF; } break; } if (cp == NULL) { if (Debug) fprintf (stderr, "boundary parameter missing ! \n"); mhp->content_type = UNDEF; mhp->boundary[0] = '\0'; } } else if (Strcase_has_prefix (cp, "message/") == 0) { mhp->content_type = MESG; } nlbp = headers_buffer.header_start; } else if (!Strcase_has_prefix (headers_buffer.header_start, "content-transfer-encoding:")) { cte_read = TRUE; /* Remember the encoding in mhp! */ cp = headers_buffer.header_start + strlen ("content-transfer-encoding:"); cp += strspn (cp, LWSP); /* remove white space */ { if (!Strcase_has_prefix (cp, "quoted-printable")) { if (Debug >= 3) fprintf (stderr, "Transfer-encoding IS QP\n"); mhp->transfer_encoding = QP; } else if (!Strcase_has_prefix (cp, "base64")) { if (Debug >= 3) fprintf (stderr, "Transfer-encoding IS B64\n"); mhp->transfer_encoding = B64; } else if (!Strcase_has_prefix (cp, "7bit")) { if (Debug >= 3) fprintf (stderr, "Transfer-encoding IS 7bit\n"); mhp->transfer_encoding = BIT7; } else if (!Strcase_has_prefix (cp, "8bit")) { if (Debug >= 3) fprintf (stderr, "Transfer-encoding IS 8bit\n"); mhp->transfer_encoding = BIT8; } else if (!Strcase_has_prefix (cp, "binary")) { if (Debug >= 3) fprintf (stderr, "Transfer-encoding IS BINARY\n"); mhp->transfer_encoding = BINARY; } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -