4 * This is a really bad attempt at writing a parser to handle MIME-encoded
5 * data, including multipart messages. In the case of WebCit, the input data
6 * might be a form containing uploaded files. In the Citadel server, the data
7 * is more likely to be an actual MIME-encoded message.
9 * Copyright (c) 1998-1999 by Art Cancro
10 * This code is distributed under the terms of the GNU General Public License.
18 #include <sys/types.h>
21 #include "mime_parser.h"
25 void extract_key(char *target, char *source, char *key) {
28 strcpy(target, source);
29 for (a=0; a<strlen(target); ++a) {
30 if ((!strncasecmp(&target[a], key, strlen(key)))
31 && (target[a+strlen(key)]=='=')) {
32 strcpy(target, &target[a+strlen(key)+1]);
33 if (target[0]==34) strcpy(target, &target[1]);
34 for (b=0; b<strlen(target); ++b)
35 if (target[b]==34) target[b]=0;
45 * The very back end for the component handler
46 * (This function expects to be fed CONTENT ONLY, no headers)
48 void do_something_with_it(char *content,
51 char *content_disposition,
63 extract_key(name, content_disposition, " name");
64 extract_key(filename, content_disposition, "filename");
66 /* Nested multipart gets recursively fed back into the parser */
67 if (!strncasecmp(content_type, "multipart", 9)) {
68 mime_parser(content, length, content_type, CallBack);
71 /**** OTHERWISE, HERE'S WHERE WE HANDLE THE STUFF!! *****/
73 CallBack(name, filename, "", content, content_type, length);
75 /**** END OF STUFF-HANDLER ****/
81 * Take a part, figure out its length, and do something with it
82 * (This function expects to be fed HEADERS+CONTENT)
84 void handle_part(char *content,
86 char *supplied_content_type,
95 char content_type[256];
96 char content_disposition[256];
99 int crlf = 0; /* set to 1 for crlf-style newlines */
102 strcpy(content_type, supplied_content_type);
104 /* Strip off any leading blank lines. */
106 while ((!strncmp(start, "\r", 1)) || (!strncmp(start, "\n", 1))) {
111 /* At this point all we have left is the headers and the content. */
115 buf[strlen(buf)+1] = 0;
116 if (strlen(buf)<((sizeof buf)-1)) {
117 strncpy(&buf[strlen(buf)], start, 1);
121 } while((buf[strlen(buf)-1] != 10) && (part_length>0));
122 if (part_length <= 0) return;
123 buf[strlen(buf)-1] = 0;
124 if (buf[strlen(buf)-1]==13) {
125 buf[strlen(buf)-1] = 0;
128 if (!strncasecmp(buf, "Content-type: ", 14)) {
129 strcpy(content_type, &buf[14]);
131 if (!strncasecmp(buf, "Content-disposition: ", 21)) {
132 strcpy(content_disposition, &buf[21]);
134 } while (strlen(buf)>0);
136 if (crlf) actual_length = part_length - 2;
137 else actual_length = part_length - 1;
139 /* Now that we've got this component isolated, what to do with it? */
140 do_something_with_it(start, actual_length,
141 content_type, content_disposition, CallBack);
147 * Break out the components of a multipart message
148 * (This function expects to be fed CONTENT ONLY, no headers)
152 void mime_parser(char *content,
165 int have_boundary = 0;
169 int bytes_processed = 0;
172 /* If it's not multipart, don't process it as multipart */
173 if (strncasecmp(ContentType, "multipart", 9)) {
174 do_something_with_it(content, ContentLength,
175 ContentType, "", CallBack);
179 /* Figure out what the boundary is */
180 strcpy(boundary, ContentType);
181 for (a=0; a<strlen(boundary); ++a) {
182 if (!strncasecmp(&boundary[a], "boundary=", 9)) {
185 strcpy(&boundary[2], &boundary[a+9]);
189 if ((boundary[a]==13) || (boundary[a]==10)) {
193 if (boundary[2]==34) {
194 strcpy(&boundary[2], &boundary[3]);
195 for (a=2; a<strlen(boundary); ++a)
196 if (boundary[a]==34) boundary[a]=0;
199 /* We can't process multipart messages without a boundary. */
200 if (have_boundary == 0) return;
201 strcpy(endary, boundary);
202 strcat(endary, "--");
203 fprintf(stderr, "BOUNDARY: %s\n", boundary);
207 /* Seek to the beginning of the next boundary */
208 while (bytes_processed < ContentLength) {
209 /* && (strncasecmp(ptr, boundary, strlen(boundary))) ) { */
211 if (strncasecmp(ptr, boundary, strlen(boundary))) {
216 /* See if we're at the end */
217 if (!strncasecmp(ptr, endary, strlen(endary))) {
221 /* Seek to the end of the boundary string */
222 if (!strncasecmp(ptr, boundary, strlen(boundary))) {
223 fprintf(stderr, "FOUNDA BOUNDA\n");
224 while ( (bytes_processed < ContentLength)
225 && (strncasecmp(ptr, "\n", 1)) ) {
231 while ( (bytes_processed < ContentLength)
232 && (strncasecmp(ptr, boundary, strlen(boundary))) ) {
237 handle_part(beginning, part_length, "", CallBack);
238 /* Back off so we can see the next boundary */