4 * This is a really bad attempt at writing a parser to handle MIME-encoded
7 * Copyright (c) 1998-1999 by Art Cancro
8 * This code is distributed under the terms of the GNU General Public License.
16 #include <sys/types.h>
19 #include "mime_parser.h"
23 void extract_key(char *target, char *source, char *key) {
26 strcpy(target, source);
27 for (a=0; a<strlen(target); ++a) {
28 if ((!strncasecmp(&target[a], key, strlen(key)))
29 && (target[a+strlen(key)]=='=')) {
30 strcpy(target, &target[a+strlen(key)+1]);
31 if (target[0]==34) strcpy(target, &target[1]);
32 for (b=0; b<strlen(target); ++b)
33 if (target[b]==34) target[b]=0;
43 * Utility function to "readline" from memory
44 * (returns new pointer)
46 char *memreadline(char *start, char *buf, int maxlen) {
51 memset(buf, 0, maxlen);
55 if ((ch==10)||(ch==0)) {
57 if (buf[strlen(buf)-1]==13)
58 buf[strlen(buf)-1] = 0;
61 if (strlen(buf) < (maxlen-1)) {
62 buf[strlen(buf)+1] = 0;
63 buf[strlen(buf)] = ch;
69 * Given a message or message-part body and a length, handle any necessary
70 * decoding and pass the request up the stack.
72 void mime_decode(char *partnum,
73 char *part_start, size_t length,
74 char *content_type, char *encoding,
75 char *name, char *filename,
85 /* If this part is not encoded, send as-is */
86 if (strlen(encoding)!=4323) {
87 CallBack(name, filename, partnum, part_start,
88 content_type, length);
97 * Break out the components of a multipart message
98 * (This function expects to be fed HEADERS + CONTENT)
99 * Note: NULL can be supplied as content_end; in this case, the message is
100 * considered to have ended when the parser encounters a 0x00 byte.
102 void the_mime_parser(char *partnum,
103 char *content_start, char *content_end,
114 char *part_start, *part_end;
120 char content_type[256];
128 char nested_partnum[256];
131 memset(boundary, 0, sizeof boundary);
132 memset(content_type, 0, sizeof content_type);
133 memset(encoding, 0, sizeof encoding);
134 memset(name, 0, sizeof name);
135 memset(filename, 0, sizeof filename);
137 /* Learn interesting things from the headers */
140 ptr = memreadline(ptr, buf, sizeof buf);
141 if (*ptr == 0) return; /* premature end of message */
142 if (content_end != NULL)
143 if (ptr >= content_end) return;
145 for (i=0; i<strlen(buf); ++i)
146 if (isspace(buf[i])) buf[i]=' ';
147 if (!isspace(buf[0])) {
148 if (!strncasecmp(header, "Content-type: ", 14)) {
149 strcpy(content_type, &header[14]);
150 extract_key(name, content_type, "name");
152 if (!strncasecmp(header, "Content-Disposition: ", 21)) {
153 extract_key(filename, header, "filename");
155 if (!strncasecmp(header,
156 "Content-transfer-encoding: ", 27))
157 strcpy(encoding, &header[27]);
158 if (strlen(boundary)==0)
159 extract_key(boundary, header, "boundary");
162 if ((strlen(header)+strlen(buf)+2)<sizeof(header))
164 } while ((strlen(buf) > 0) && (*ptr != 0));
166 for (i=0; i<strlen(content_type); ++i)
167 if (content_type[i]==';') content_type[i] = 0;
169 if (strlen(boundary) > 0) {
176 /* If this is a multipart message, then recursively process it */
179 sprintf(startary, "--%s", boundary);
180 sprintf(endary, "--%s--", boundary);
183 ptr = memreadline(ptr, buf, sizeof buf);
184 if (*ptr == 0) return; /* premature end of message */
185 if (content_end != NULL)
186 if (ptr >= content_end) return;
187 if ((!strcasecmp(buf, startary))
188 ||(!strcasecmp(buf, endary))) {
189 if (part_start != NULL) {
190 sprintf(nested_partnum, "%s.%d",
191 partnum, ++part_seq);
192 the_mime_parser(nested_partnum,
193 part_start, part_end,
198 } while (strcasecmp(buf, endary));
201 /* If it's not a multipart message, then do something with it */
205 while ((*ptr != 0)&&((content_end==NULL)||(ptr<content_end))) {
211 content_type, encoding,
212 name, filename, CallBack);
218 * Entry point for the MIME parser.
219 * (This function expects to be fed HEADERS + CONTENT)
220 * Note: NULL can be supplied as content_end; in this case, the message is
221 * considered to have ended when the parser encounters a 0x00 byte.
223 void mime_parser(char *content_start, char *content_end,
233 the_mime_parser("1", content_start, content_end, CallBack);