/* 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 */