/**---------------------------------------------------------------------------*/ // File: hudmail\mime.c // A component of the Workflow system of subsidized contract administration. // Copyright (c) 2001, Richard Heurtley. All rights reserved. /**---------------------------------------------------------------------------*/ #include "common.h" #include "mime.h" /**---------------------------------------------------------------------------*/ #define DISPOSITION_NONE (1) #define DISPOSITION_INLINE (2) #define DISPOSITION_ATTACHMENT (3) #define ENCODING_7BIT (1) #define ENCODING_QUOTED (2) #define ENCODING_BASE64 (3) #define TYPE_TEXTPLAIN (1) #define TYPE_MESSAGERFC822 (2) /**---------------------------------------------------------------------------*/ typedef struct { int type; int disposition; int encoding; char *fromp; } LOCAL; /**---------------------------------------------------------------------------*/ static LOCAL l; /**---------------------------------------------------------------------------*/ // reset message coding attributes static void Defaults(void) { l.type = TYPE_TEXTPLAIN; l.encoding = ENCODING_7BIT; l.disposition = DISPOSITION_NONE; RETURNVOID; } /**---------------------------------------------------------------------------*/ static int MessageParse ( LIST *linelistp, char *begboundp, char *endboundp, char *inboxpathp, char *recvpathp, int *ascnump ) { int rv = 0; int nlines; unsigned char c0; unsigned char c1; unsigned char c2; unsigned char c3; unsigned char b0; unsigned char b1; unsigned char b2; unsigned char b3; unsigned char ch; unsigned char bytes[3]; int byte; int nbytes; int i; unsigned char *p; FILE *filep; char *linep; char *line0p; char *line1p; char *line2p; char *line3p; LIST linelist; LISTLOOP lineloop; char filename[8+1+3+1]; static char inboxpathfile[256]; static unsigned char back[256]; static unsigned char forward[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" // 26 "abcdefghijklmnopqrstuvwxyz" // 52 "0123456789" // 62 "+/"; // 64 if (!back[0]) { memset(back, 0xff, sizeof(back)); for (i = 0; i < 64; i++) back[forward[i]] = i; back['='] = 0; // '=' maps to zero } ListZero(&linelist, 8); filep = 0; /**---------------------------------------------------------------------------*/ // get attachment for (;;) { linep = ListCurObjGet(linelistp); if (!linep) break; if (begboundp && streq(linep, begboundp)) break; if (endboundp && streq(linep, endboundp)) break; ListObjAppend(&linelist, linep); ListNextObjGet(linelistp); } if ( l.disposition != DISPOSITION_ATTACHMENT && l.disposition != DISPOSITION_INLINE ) goto EGRESS; // nuke trailing blank lines for (;;) { linep = ListLastObjGet(&linelist); if (!linep) break; if (linep[0]) break; ListObjDelete(&linelist, linep); } // delete trailing "..Y" lines line0p = ListLastObjGet(&linelist); if (line0p && streq(line0p, "Y ")) { line1p = ListPrevObjGet(&linelist); if (line1p && streq(line1p, ". ")) { line2p = ListPrevObjGet(&linelist); if (line2p && streq(line2p, ". ")) { ListObjDelete(&linelist, line0p); ListObjDelete(&linelist, line1p); ListObjDelete(&linelist, line2p); } } } // nuke trailing blank lines again for (;;) { linep = ListLastObjGet(&linelist); if (!linep) break; if (linep[0]) break; ListObjDelete(&linelist, linep); } /**---------------------------------------------------------------------------*/ // delete destination and subject lines // Posted: Mon, 12 Nov 2001 11:00:01 -0500 (EST) // From: TRACMTEST // To: TRACM08941 // Subj: HUD CFS TRACS DATA 011112 124373 // // TRACM08941 // // HUD CFS TRACS DATA 011112 124373 // // PROCESSING MAILBOX ID: @*@ TRACM08941TRACM00105MATTV2.0.1.A000011004200108040211122001101227COLNYSQ11KATHY RICHARDS P O BOX 467 IRONWOOD MI49938000000 ListFirstObj(&linelist); linep = ListNextObjGet(&linelist); if (!linep || !strieqz(linep, "posted:")) goto NODELETE; linep = ListNextObjGet(&linelist); if (!linep || !strieqz(linep, "from:")) goto NODELETE; linep = ListNextObjGet(&linelist); if (!linep || !strieqz(linep, "to:")) goto NODELETE; linep = ListNextObjGet(&linelist); if (!linep || !strieqz(linep, "subj:")) goto NODELETE; linep = ListNextObjGet(&linelist); if (!linep || !streq(linep, "")) goto NODELETE; line0p = ListNextObjGet(&linelist); if (!line0p || !streqz(line0p, "TRACM")) // destination goto NODELETE; line1p = ListNextObjGet(&linelist); if (!line1p || !streq(line1p, " ")) goto NODELETE; line2p = ListNextObjGet(&linelist); if (!line2p || !streqz(line2p, "HUD")) // subject goto NODELETE; line3p = ListNextObjGet(&linelist); if (!line3p || !streq(line3p, " ")) goto NODELETE; ListObjDelete(&linelist, line0p); ListObjDelete(&linelist, line1p); ListObjDelete(&linelist, line2p); ListObjDelete(&linelist, line3p); NODELETE: /**---------------------------------------------------------------------------*/ // ignore HUD attached message if (linelist.nnodes == 2) { line0p = ListFirstObjGet(&linelist); line1p = ListNextObjGet(&linelist); if ( stristr(line0p, "mailbox") && stristr(line0p, "tracmhelp") && stristr(line1p, "right-click") && stristr(line1p, "attachment") ) goto EGRESS; } if (!linelist.nnodes) // if no data goto EGRESS; // skip attachment /**---------------------------------------------------------------------------*/ // save the attachment for (;;) // get the next filename { sprintf(filename, "%5.5d.asc", *ascnump); strbuild(inboxpathfile, inboxpathp, SEP, filename, 0); (*ascnump)++; if (*ascnump >= 100000) *ascnump = 0; if (!FileExist(inboxpathfile)) break; } filep = fopen(inboxpathfile, "wb"); IF(!filep,Unable to create file.); nlines = 0; if (l.encoding == ENCODING_7BIT) { LISTLOOPL(line) fprintf(filep, "%s\r\n", linep); nlines = linelist.nnodes; } else if (l.encoding == ENCODING_QUOTED) { p = ListFirstObjGet(&linelist); for (;;) // infinite loop { if (!*p) // hard break { fprintf(filep, "%s", "\r\n"); nlines++; goto LINENEXT; } else if (*p != '=') // regular character { fprintf(filep, "%c", *p); p++; continue; } else { p++; // skip '=' if (*(p+0) && *(p+1)) // if two digits { c0 = *p++; c0 = toupper(c0); if (c0 >= 'A') c0 -= 'A' - ('9' + 1); c0 &= 0x0f; c1 = *p++; c1 = toupper(c1); if (c1 >= 'A') c1 -= 'A' - ('9' + 1); c1 &= 0x0f; ch = (c0 << 4) | c1; if (ch == '\n') { fprintf(filep, "%c", '\r'); nlines++; } fprintf(filep, "%c", ch); continue; } } // soft breaks fall through LINENEXT: p = ListNextObjGet(&linelist); // get next line if (!p) // if no more data break; // break out of infinite loop } // for (;;) } else if (l.encoding == ENCODING_BASE64) { p = ListFirstObjGet(&linelist); for (;;) // infinite loop { if (*(p+0) && *(p+1) && *(p+2) && *(p+3)) // if there's a quad { c0 = *p++; c1 = *p++; c2 = *p++; c3 = *p++; b0 = back[c0]; b1 = back[c1]; b2 = back[c2]; b3 = back[c3]; bytes[0] = (b0 << 2) | (b1 >> 4); bytes[1] = (b1 << 4) | (b2 >> 2); bytes[2] = (b2 << 6) | (b3 >> 0); nbytes = 3; if (c2 == '=') nbytes--; if (c3 == '=') nbytes--; fwrite(bytes, 1, nbytes, filep); for (byte = 0; byte < nbytes; byte++) { if (bytes[byte] == '\n') nlines++; } } else // no quad, get next line { p = ListNextObjGet(&linelist); // get next line if (!p) // if no more data break; // break out of infinite loop } } // for (;;) } fclose(filep); filep = 0; LOGF("Saved %d lines from %s as %s", nlines, l.fromp, filename); rv = FileCopy(inboxpathp, filename, recvpathp); IF(rv,Unable to copy file to receive directory.); EGRESS: if (filep) fclose(filep); ListFree(&linelist); Defaults(); // reset message coding attributes RETURN(rv); } /**---------------------------------------------------------------------------*/ int MIMEParse ( LIST *linelistp, char *begboundp, char *endboundp, char *inboxpathp, char *recvpathp, int *ascnump ) { int rv = 0; char *linep; char *p; char *fromp; char *boundp; static int nest; Defaults(); nest++; if (nest == 1) l.fromp = ""; fromp = l.fromp; for (;;) { linep = ListCurObjGet(linelistp); if (!linep) goto EGRESS; // this must be first because a null line matches strieqz() // start parsing message on a blank line if (!linep[0]) { ListNextObjGet(linelistp); rv = MessageParse ( linelistp, begboundp, endboundp, inboxpathp, recvpathp, ascnump ); continue; } // if end boundary then exit if (endboundp && streq(linep, endboundp)) { ListNextObjGet(linelistp); // get next line goto EGRESS; } // get parameters if (strieqz(linep, "content-type: text/plain")) { l.type = TYPE_TEXTPLAIN; goto LINENEXT; } if (strieqz(linep, "content-type: message/rfc822")) { l.type = TYPE_MESSAGERFC822; goto LINENEXT; } if (strieqz(linep, "content-transfer-encoding: 7bit")) { l.encoding = ENCODING_7BIT; goto LINENEXT; } if (strieqz(linep, "content-transfer-encoding: base64")) { l.encoding = ENCODING_BASE64; goto LINENEXT; } if (strieqz(linep, "content-transfer-encoding: quoted-printable")) { l.encoding = ENCODING_QUOTED; goto LINENEXT; } if (strieqz(linep, "content-disposition: inline")) { l.disposition = DISPOSITION_INLINE; goto LINENEXT; } if (strieqz(linep, "content-disposition: attachment")) { l.disposition = DISPOSITION_ATTACHMENT; goto LINENEXT; } if (strieqz(linep, "from")) { l.fromp = ""; p = strchr(linep, ':'); if (!p) goto LINENEXT; for (p++; *p && isspace(*p); p++); // find beginning of string if (!*p) goto LINENEXT; l.fromp = p; goto LINENEXT; } /**---------------------------------------------------------------------------*/ // nest on boundary strings if (stristr(linep, "boundary=\"")) { char *begboundp; char *endboundp; p = stristr(linep, "boundary=\""); p = strchr(p, '\"'); if (!p) goto LINENEXT; boundp = ++p; p = strchr(boundp, '\"'); if (!p) goto LINENEXT; *p = 0; begboundp = MemGet(2 + strlen(boundp) + 1); endboundp = MemGet(2 + strlen(boundp) + 2 + 1); strcpy(begboundp, "--"); strcat(begboundp, boundp); strcpy(endboundp, begboundp); strcat(endboundp, "--"); ListNextObjGet(linelistp); // get next line rv = MIMEParse // returns at EOF or endboundp ( linelistp, begboundp, endboundp, inboxpathp, recvpathp, ascnump ); MemFree(begboundp); MemFree(endboundp); goto LINENEXT; } /**---------------------------------------------------------------------------*/ LINENEXT: ListNextObjGet(linelistp); } // for (;;) EGRESS: l.fromp = fromp; nest--; RETURN(rv); }