/* multi.c -- local hacks at UNINETT by Sigmund Austigard 1992 */ /* * COPYRIGHT 1992 * UNINETT * TRONDHEIM, NORWAY * ALL RIGHTS RESERVED. * * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY UNINETT. UNINETT MAKES NO * REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. * IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. * * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT * RIGHTS, APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN * ADDITION TO THAT SET FORTH ABOVE. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Uninett not be used in advertising * or publicity pertaining to distribution of the software without specific, * written prior permission. * */ /* * Some parts of this file is code modified from code copyright 1987, 1989 * Digital Equipment Corporation, and copyright 1991 Carnegie Mellon * University, Software Engineering Institute. */ #ifdef MULTI #include <malloc.h> #include <strings.h> #include <sys/types.h> #include <sys/stat.h> #include <X11/Xaw/Cardinals.h> #include "xmh.h" #include "multi.h" #include "tocintrnl.h" static Switches *InitSwitches() { Switches *switches = (Switches *)XtMalloc(sizeof(Switches)); switches->contentType = text; switches->contentSub = plain; switches->encoding = bit7; switches->charset = usascii; switches->needBoundary = FALSE; switches->boundary = NULL; return switches; } static void parseHeaders(buf, switches) String buf; Switches *switches; { String here = buf; String help; Boolean doublequote; Boolean singlequote; while (*here) { doublequote = singlequote = FALSE; /* Is this line a Content-Type or Content-Transfer-Encoding? */ if (!strncasecmp(here, "Content-", 8)) { /* More spesific, Content-Type */ if (!strncasecmp(here + 8, "Type:", 5)) { here += strspn(here + 13, " ") + 13; if (!strncasecmp(here, "text/", 5)) { switches->contentType = text; here += 5; if (!strncasecmp(here, "plain", 5)) { here = &here[strspn(here+5, " ")+5]; switches->contentSub = plain; } else if (!strncasecmp(here, "richtext", 8)) { here += strspn(here+8, " ") + 8; switches->contentSub = richtext; } while (*here && *here != '0) switch (here[0]) { case ';': here = &here[strspn(here+1, " ")+1]; if (!strncasecmp(here, "charset=", 8)) { here += 8; if (*here == '"') { doublequote = TRUE; here++; } if (!strncasecmp(here, "us-ascii", 8)) { switches->charset = usascii; here += 8; } else if (!strncasecmp(here, "iso-8859-", 9) && (here[10] == '0 || here[10] == ' ' || here[10] == ' ' || here[10] == '' || (here[10] == '"' && doublequote) || (here[10] == ''' && singlequote))) { if (here[10] == '"') doublequote = FALSE; else if (here[10] == ''') singlequote = FALSE; here += 9; switch (*here) { case '0: case ' ': printf("invalid charset0); break; /* ERROR */ case '1': switches->charset = iso88591; here++; break; case '2': switches->charset = iso88592; here++; break; case '3': switches->charset = iso88593; here++; break; case '4': switches->charset = iso88594; here++; break; case '5': switches->charset = iso88595; here++; break; case '6': switches->charset = iso88596; here++; break; case '7': switches->charset = iso88597; here++; break; case '8': switches->charset = iso88598; here++; break; case '9': switches->charset = iso88599; here++; break; default: printf("unknown iso set %c0, *here); here++; break; /* ERROR */ } } /* else ERROR */ if (*here == '"') here++; } else { printf("not charset=, but %s0, here); here = " "; } break; default: { char *eoln; char tmp; eoln = strchr(here, '0); if (eoln) { tmp = *eoln; *eoln = ' '; printf("unrecognized string <%s>0, here); *eoln = tmp; here = eoln; } } break; } if (*here) here++; } else if (!strncasecmp(here, "multipart/", 10)) { switches->contentType = multipart; switches->needBoundary = TRUE; here += 10; if (!strncasecmp(here, "mixed", 5)) { here = &here[strspn(here+5, " ")+5]; switches->contentSub = mixed; } else if (!strncasecmp(here, "alternative", 11)) { here += strspn(here+8, " ") + 11; switches->contentSub = alternative; } else if (!strncasecmp(here, "digest", 6)) { here += strspn(here+8, " ") + 6; switches->contentSub = digest; } else if (!strncasecmp(here, "parallel", 8)) { here += strspn(here+8, " ") + 8; switches->contentSub = parallel; } while (*here && *here != '0) switch (here[0]) { case ';': here += strspn(here+1, " ") + 1; if (!strncasecmp(here, "boundary=", 9)) { here += 9; for (help = here; *help && *help != ';' && *help != '0; help++) ; help--; if (*help) { int left = help-here+1; Boolean dquoted = FALSE; switches->boundary = XtMalloc(left+1); for (help = switches->boundary; left; here++) { switch (*here) { case '"': if (dquoted) dquoted = FALSE; else dquoted = TRUE; break; case '\': if (*(here+1)) { here++; left--; *help++ = *here; } else *help++ = *here; break; default: *help++ = *here; break; } left--; } *help = ' '; /* *(switches->boundary + (help-here)) = ' '; here = help+2; */ } else printf("error reading boundary0); } else { printf("not boundary=, but %s0, here); here = " "; } break; default: printf("unrecognized string <%s>0, here); here = " "; break; } if (*here) here++; } else if (!strncasecmp(here, "message/", 8)) { switches->contentType = message; } else if (!strncasecmp(here, "application/", 12)) { switches->contentType = application; } else if (!strncasecmp(here, "image/", 6)) { switches->contentType = image; } else if (!strncasecmp(here, "audio/", 6)) { switches->contentType = audio; } else if (!strncasecmp(here, "video/", 6)) { switches->contentType = video; } } /* Well, perhaps Content-Transfer-Encoding? */ else if (!strncasecmp(&here[8], "Transfer-Encoding:", 18)) { here = &here[strspn(&here[26], " ")+26]; if (!strncasecmp(here, "7bit", 4)) { here += 4; switches->encoding = bit7; } else if (!strncasecmp(here, "8bit", 4)) { here += 4; switches->encoding = bit8; } else if (!strncasecmp(here, "binary", 6)) { here += 6; switches->encoding = binary; } else if (!strncasecmp(here, "base64", 6)) { here += 6; switches->encoding = base64; } else if (!strncasecmp(here, "quoted-printable", 16)) { here += 16; switches->encoding = quoted; } else printf("unknown encoding %s0, here); } else while (*here && *here++ != '0) ; } else { while (*here && *here++ != '0) ; } } return; } static UString ReadFileIntoBuffer(filename) String filename; { FILEPTR fid; UString buf; size_t size, ret; struct stat statstruct; stat(filename, &statstruct); size = statstruct.st_size; fid = fopen(filename, "r"); buf = (UString)XtMalloc(size+1); ret = fread(buf, sizeof(u_char), size+1, fid); *(buf+size) = ' '; fclose(fid); return (buf); } /* * SplitBufferInto4(); * * Splits a message as read from disk into four separate strings. * * Arguments: * hdr: On entry, a pointer to a string * (i.e. 'unsigned char **hdr') * containing the buffer that is to be split. * On return, the same pointer, but the string is now * containing the unmodified headers of the message only. * The 'msg' string resides in the same buffer, see below. * hdr2: On entry a pointer to a pointer to NULL (hopefully) * On return, a pointer to a string containing * the headers, where all continuated headers have been * joined. This makes the parsing in parseHeaders() * easier. * bdr: On entry a pointer to a pointer to NULL * On return, a pointer to a string containing * the line separating the headers and the body * msg: On entry a pointer to a pointer to NULL * On return, a pointer to a string containing * the body of the message. * * Returns: * Void, but leaves the results in the memomry locations pointed to * by the arguments. * * WARNING: * This version splits the 'msg' part inplace, i.e. it is never malloc'ed * memory for a copy nor actually copied, but it is returned as a part of * the 'hdr' buffer. This should be considered when freeing 'hdr', and * when attempting to free 'msg'. THE RESULTS OF THIS OPERATION IS VERY * UNPREDICTABLE AND SHOULD NOT BE ATTEMPTED. Free 'hdr' instead, if * you don't need them anymore. * * The major benefit of implementing it this way is that you don't waste * cpu cycles and memory duplicating the possibly large body part of the * message yet another time. This is important, as MIME messages * tend to be large. * We have to duplicate this buffer a few times later on, anyhow :( */ static void SplitBufferInto4(hdr, hdr2, bdr, msg) UString *hdr, *hdr2, *bdr, *msg; { UString buf = *hdr; UString hdrbuf, hdr2buf, bdrbuf, msgbuf, help, help2; u_char temp; for (help = buf; *help; help++) if (*help == '0) if (*(help + 1) == '0 || (*(help+1) == '-' && *(help+2) == '-' && *(help+3) == '-')) { for (help2 = ++help; *help2 && *help2 != '0; help2++) ; help2++; temp = *help2; *help2 = ' '; bdrbuf = (UString)XtNewString((String)help); *help2 = temp; *help = ' '; break; } hdrbuf = buf; hdr2buf = (UString)XtNewString((String)hdrbuf); for (help = hdr2buf; *help; help++) if (*help == '0) if (*(help + 1) == ' ' || *(help + 1) == '') *help = ' '; *hdr = hdrbuf; *hdr2 = hdr2buf; *bdr = bdrbuf; *msg = help2; return; } #undef D #define D(s) s void ParseMimeMessage(filename) String filename; { UString border, buf, hdrbuf2, msgbuf, out; int fd; Switches *switches = NULL; u_char tmp; if (!strcmp(filename, "/dev/null")) return; switches = InitSwitches(); buf = ReadFileIntoBuffer(filename); SplitBufferInto4(&buf, &hdrbuf2, &border, &msgbuf); parseHeaders(hdrbuf2, switches); XtFree((String)hdrbuf2); switch (switches->contentType) { case text: D(printf("Contents: text0)); switch (switches->contentSub) { case plain: D(printf("Subtype: plain0)); break; case richtext: D(printf("Subtype: richtext0)); break; default: D(printf("Unknown subtype0)); break; } break; case multipart: D(printf("Contents: multipart0)); switch (switches->contentSub) { case mixed: D(printf("Subtype: mixed0)); break; case alternative: D(printf("Subtype: alternative0)); break; case digest: D(printf("Subtype: digest0)); break; case parallel: D(printf("Subtype: parallel0)); break; default: D(printf("Unknown subtype0)); break; } break; case message: D(printf("Contents: message0)); switch (switches->contentSub) { case rfc822: D(printf("Subtype: rfc8220)); break; case partial: D(printf("Subtype: partial0)); break; case externalbody: D(printf("Subtype: externalbody0)); break; default: D(printf("Unknown subtype0)); break; } break; case application: D(printf("Contents: application0)); switch (switches->contentSub) { case octetstream: D(printf("Subtype: octetstream0)); break; case postscript: D(printf("Subtype: postscript0)); break; case oda: D(printf("Subtype: oda0)); break; default: D(printf("Unknown subtype0)); break; } break; case image: D(printf("Contents: image0)); switch (switches->contentSub) { case jpeg: D(printf("Subtype: jpeg0)); break; case gif: D(printf("Subtype: gif0)); break; default: D(printf("Unknown subtype0)); break; } break; case audio: D(printf("Contents: audio0)); switch (switches->contentSub) { case basic: D(printf("Subtype: basic0)); break; default: D(printf("Unknown subtype0)); break; } break; case video: D(printf("Contents: video0)); switch (switches->contentSub) { case mpeg: D(printf("Subtype: mpeg0)); break; default: D(printf("Unknown subtype0)); break; } break; default: D(printf("Unknown contents0)); break; } switch (switches->encoding) { case bit7: D(printf("Encoding: 7 bit0)); break; case bit8: D(printf("Encoding: 8 bit0)); break; case binary: D(printf("Encoding: binary0)); break; case base64: D(printf("Encoding: base640)); break; case quoted: D(printf("Encoding: quoted-printable0)); break; default: D(printf("Unknown encoding0)); break; } switch (switches->charset) { case usascii: D(printf("Charset: us-ascii0)); break; case iso88591: D(printf("Charset: iso-8859-10)); break; case iso88592: D(printf("Charset: iso-8859-20)); break; case iso88593: D(printf("Charset: iso-8859-30)); break; case iso88594: D(printf("Charset: iso-8859-40)); break; case iso88595: D(printf("Charset: iso-8859-50)); break; case iso88596: D(printf("Charset: iso-8859-60)); break; case iso88597: D(printf("Charset: iso-8859-70)); break; case iso88598: D(printf("Charset: iso-8859-80)); break; case iso88599: D(printf("Charset: iso-8859-90)); break; default: D(printf("Unknown charset0)); break; } if (switches->needBoundary) D(printf("Need boundary0)); else D(printf("Don't need boundary0)); if (switches->boundary) D(printf("Boundary: ->%s<-0, switches- >boundary)); else D(printf("No boundary found0)); out = (UString)XtMalloc(strlen(buf) + strlen(border) + strlen(msgbuf) + 1); strcpy(out, buf); strcat(out, border); strcat(out, msgbuf); XtFree((String)buf); XtFree((String)border); if (switches->boundary) XtFree(switches->boundary); XtFree((String)switches); return; } #endif /* MULTI */