📄 unmime.c
字号:
int MimeBodyType(unsigned char *hdrs, int WantDecode)
{
unsigned char *NxtHdr = hdrs;
unsigned char *XferEnc, *XferEncOfs, *CntType, *MimeVer, *p;
int HdrsFound = 0; /* We only look for three headers */
int BodyType; /* Return value */
/* Setup for a standard (no MIME, no QP, 7-bit US-ASCII) message */
MultipartDelimiter[0] = '\0';
CurrEncodingIsQP = 0;
BodyState = S_BODY_DATA;
BodyType = 0;
/* Just in case ... */
if (hdrs == NULL)
return BodyType;
XferEnc = XferEncOfs = CntType = MimeVer = NULL;
do {
if (strncasecmp("Content-Transfer-Encoding:", NxtHdr, 26) == 0) {
XferEncOfs = NxtHdr;
p = nxtaddr(NxtHdr);
if (p != NULL) {
xalloca(XferEnc, char *, strlen(p) + 1);
strcpy(XferEnc, p);
HdrsFound++;
}
}
else if (strncasecmp("Content-Type:", NxtHdr, 13) == 0) {
/*
* This one is difficult. We cannot use the standard
* nxtaddr() routine, since the boundary-delimiter is
* (probably) enclosed in quotes - and thus appears
* as an rfc822 comment, and nxtaddr() "eats" up any
* spaces in the delimiter. So, we have to do this
* by hand.
*/
/* Skip the "Content-Type:" part and whitespace after it */
for (NxtHdr += 13; ((*NxtHdr == ' ') || (*NxtHdr == '\t')); NxtHdr++);
/*
* Get the full value of the Content-Type header;
* it might span multiple lines. So search for
* a newline char, but ignore those that have a
* have a TAB or space just after the NL (continued
* lines).
*/
p = NxtHdr-1;
do {
p=strchr((p+1),'\n');
} while ( (p != NULL) && ((*(p+1) == '\t') || (*(p+1) == ' ')) );
if (p == NULL) p = NxtHdr + strlen(NxtHdr);
xalloca(CntType, char *, p-NxtHdr+2);
strncpy(CntType, NxtHdr, (p-NxtHdr));
*(CntType+(p-NxtHdr)) = '\0';
HdrsFound++;
}
else if (strncasecmp("MIME-Version:", NxtHdr, 13) == 0) {
p = nxtaddr(NxtHdr);
if (p != NULL) {
xalloca(MimeVer, char *, strlen(p) + 1);
strcpy(MimeVer, p);
HdrsFound++;
}
}
NxtHdr = (strchr(NxtHdr, '\n'));
if (NxtHdr != NULL) NxtHdr++;
} while ((NxtHdr != NULL) && (*NxtHdr) && (HdrsFound != 3));
/* Done looking through the headers, now check what they say */
if ((MimeVer != NULL) && (strcmp(MimeVer, "1.0") == 0)) {
/* Check Content-Type to see if this is a multipart message */
if ( (CntType != NULL) &&
((strncasecmp(CntType, "multipart/", 10) == 0) ||
(strncasecmp(CntType, "message/", 8) == 0)) ) {
char *p1 = GetBoundary(CntType);
if (p1 != NULL) {
/* The actual delimiter is "--" followed by
the boundary string */
strcpy(MultipartDelimiter, "--");
strncat(MultipartDelimiter, p1, MAX_DELIM_LEN);
BodyType = (MSG_IS_8BIT | MSG_NEEDS_DECODE);
}
}
/*
* Check Content-Transfer-Encoding, but
* ONLY for non-multipart messages (BodyType == 0).
*/
if ((XferEnc != NULL) && (BodyType == 0)) {
if (strcasecmp(XferEnc, "quoted-printable") == 0) {
CurrEncodingIsQP = 1;
BodyType = (MSG_IS_8BIT | MSG_NEEDS_DECODE);
if (WantDecode) {
SetEncoding8bit(XferEncOfs);
}
}
else if (strcasecmp(XferEnc, "7bit") == 0) {
CurrEncodingIsQP = 0;
BodyType = (MSG_IS_7BIT);
}
else if (strcasecmp(XferEnc, "8bit") == 0) {
CurrEncodingIsQP = 0;
BodyType = (MSG_IS_8BIT);
}
}
}
return BodyType;
}
/*
* Decode one line of data containing QP data.
* Return flag set if this line ends with a soft line-break.
* 'bufp' is modified to point to the end of the output buffer.
*/
static int DoOneQPLine(unsigned char **bufp, int collapsedoubledot)
{
unsigned char *buf = *bufp;
unsigned char *p_in, *p_out, *p;
int n;
int ret = 0;
p_in = buf;
if (collapsedoubledot && (strncmp(buf, "..", 2) == 0))
p_in++;
for (p_out = buf; (*p_in); ) {
p = strchr(p_in, '=');
if (p == NULL) {
/* No more QP data, just move remainder into place */
n = strlen(p_in);
memmove(p_out, p_in, n);
p_in += n; p_out += n;
}
else {
if (p > p_in) {
/* There are some uncoded chars at the beginning. */
n = (p - p_in);
memmove(p_out, p_in, n);
p_out += n;
}
switch (*(p+1)) {
case '\0': case '\r': case '\n':
/* Soft line break, skip '=' */
p_in = p+1;
if (*p_in == '\r') p_in++;
if (*p_in == '\n') p_in++;
ret = 1;
break;
default:
/* There is a QP encoded byte */
if (qp_char(*(p+1), *(p+2), p_out) == 0) {
p_in = p+3;
}
else {
/* Invalid QP data - pass through unchanged. */
*p_out = '=';
p_in = p+1;
}
p_out++;
break;
}
}
}
*p_out = '\0';
*bufp = p_out;
return ret;
}
/* This is called once per line in the message body. We need to scan
* all lines in the message body for the multipart delimiter string,
* and handle any body-part headers in such messages (these can toggle
* qp-decoding on and off).
*
* Note: Messages that are NOT multipart-messages go through this
* routine quickly, since BodyState will always be S_BODY_DATA,
* and MultipartDelimiter is NULL.
*
* Return flag set if this line ends with a soft line-break.
* 'bufp' is modified to point to the end of the output buffer.
*/
int UnMimeBodyline(unsigned char **bufp, int collapsedoubledot)
{
unsigned char *buf = *bufp;
int ret = 0;
switch (BodyState) {
case S_BODY_HDR:
UnMimeHeader(buf); /* Headers in body-parts can be encoded, too! */
if (strncasecmp("Content-Transfer-Encoding:", buf, 26) == 0) {
char *XferEnc;
XferEnc = nxtaddr(buf);
if ((XferEnc != NULL) && (strcasecmp(XferEnc, "quoted-printable") == 0)) {
CurrEncodingIsQP = 1;
SetEncoding8bit(buf);
}
}
else if ((*buf == '\0') || (*buf == '\n') || (strcmp(buf, "\r\n") == 0))
BodyState = S_BODY_DATA;
*bufp = (buf + strlen(buf));
break;
case S_BODY_DATA:
if ((*MultipartDelimiter) &&
(strncmp(buf, MultipartDelimiter, strlen(MultipartDelimiter)) == 0)) {
BodyState = S_BODY_HDR;
CurrEncodingIsQP = 0;
}
if (CurrEncodingIsQP)
ret = DoOneQPLine(bufp, collapsedoubledot);
else
*bufp = (buf + strlen(buf));
break;
}
return ret;
}
#ifdef STANDALONE
#include <stdio.h>
#include <unistd.h>
char *program_name = "unmime";
#define BUFSIZE_INCREMENT 4096
#ifdef DEBUG
#define DBG_FWRITE(B,L,BS,FD) fwrite(B, L, BS, FD)
#else
#define DBG_FWRITE(B,L,BS,FD)
#endif
int main(int argc, char *argv[])
{
unsigned int BufSize;
unsigned char *buffer, *buf_p;
int nl_count, i, bodytype;
#ifdef DEBUG
pid_t pid;
FILE *fd_orig, *fd_conv;
char fnam[100];
pid = getpid();
sprintf(fnam, "/tmp/i_unmime.%x", pid);
fd_orig = fopen(fnam, "w");
sprintf(fnam, "/tmp/o_unmime.%x", pid);
fd_conv = fopen(fnam, "w");
#endif
BufSize = BUFSIZE_INCREMENT; /* Initial size of buffer */
buf_p = buffer = (unsigned char *) xmalloc(BufSize);
nl_count = 0;
do {
i = fread(buf_p, 1, 1, stdin);
switch (*buf_p) {
case '\n':
nl_count++;
break;
case '\r':
break;
default:
nl_count = 0;
break;
}
buf_p++;
if ((buf_p - buffer) == BufSize) {
/* Buffer is full! Get more room. */
buffer = xrealloc(buffer, BufSize+BUFSIZE_INCREMENT);
buf_p = buffer + BufSize;
BufSize += BUFSIZE_INCREMENT;
}
} while ((i > 0) && (nl_count < 2));
*buf_p = '\0';
DBG_FWRITE(buffer, strlen(buffer), 1, fd_orig);
UnMimeHeader(buffer);
bodytype = MimeBodyType(buffer, 1);
i = strlen(buffer);
fwrite(buffer, i, 1, stdout);
DBG_FWRITE(buffer, i, 1, fd_conv);
do {
buf_p = (buffer - 1);
do {
buf_p++;
i = fread(buf_p, 1, 1, stdin);
} while ((i == 1) && (*buf_p != '\n'));
if (i == 1) buf_p++;
*buf_p = '\0';
DBG_FWRITE(buf, (buf_p - buffer), 1, fd_orig);
if (buf_p > buffer) {
if (bodytype & MSG_NEEDS_DECODE) {
buf_p = buffer;
UnMimeBodyline(&buf_p, 0);
}
fwrite(buffer, (buf_p - buffer), 1, stdout);
DBG_FWRITE(buffer, (buf_p - buffer), 1, fd_conv);
}
} while (buf_p > buffer);
free(buffer);
fflush(stdout);
#ifdef DEBUG
fclose(fd_orig);
fclose(fd_conv);
#endif
return 0;
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -