]> code.citadel.org Git - citadel.git/blob - webcit/mime_parser.c
* wildmat.c, braindamage.c: added
[citadel.git] / webcit / mime_parser.c
1 /*
2  * mime_parser.c
3  *
4  * This is a really bad attempt at writing a parser to handle multipart
5  * messages -- in the case of WebCit, a form containing uploaded files.
6  */
7
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <stdio.h>
11 #include <signal.h>
12 #include <sys/types.h>
13 #include <ctype.h>
14 #include <string.h>
15 #include "mime_parser.h"
16 #include "webcit.h"
17 #include "child.h"
18
19
20
21 void extract_key(char *target, char *source, char *key)
22 {
23         int a, b;
24
25         strcpy(target, source);
26         for (a = 0; a < strlen(target); ++a) {
27                 if ((!strncasecmp(&target[a], key, strlen(key)))
28                     && (target[a + strlen(key)] == '=')) {
29                         strcpy(target, &target[a + strlen(key) + 1]);
30                         if (target[0] == 34)
31                                 strcpy(target, &target[1]);
32                         for (b = 0; b < strlen(target); ++b)
33                                 if (target[b] == 34)
34                                         target[b] = 0;
35                         return;
36                 }
37         }
38         strcpy(target, "");
39 }
40
41
42
43 /*
44  * The very back end for the component handler
45  * (This function expects to be fed CONTENT ONLY, no headers)
46  */
47 void do_something_with_it(char *content,
48                           int length,
49                           char *content_type,
50                           char *content_disposition,
51                           void (*CallBack)
52                            (char *cbname,
53                             char *cbfilename,
54                             char *cbencoding,
55                             void *cbcontent,
56                             char *cbtype,
57                             size_t cblength)
58 )
59 {
60         char name[256];
61         char filename[256];
62
63         extract_key(name, content_disposition, " name");
64         extract_key(filename, content_disposition, "filename");
65
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);
69         }
70 /**** OTHERWISE, HERE'S WHERE WE HANDLE THE STUFF!! *****/
71
72         CallBack(name, filename, "", content, content_type, length);
73
74 /**** END OF STUFF-HANDLER ****/
75
76 }
77
78
79 /*
80  * Take a part, figure out its length, and do something with it
81  * (This function expects to be fed HEADERS+CONTENT)
82  */
83 void handle_part(char *content,
84                  int part_length,
85                  char *supplied_content_type,
86                  void (*CallBack)
87                   (char *cbname,
88                    char *cbfilename,
89                    char *cbencoding,
90                    void *cbcontent,
91                    char *cbtype,
92                    size_t cblength)
93 )
94 {
95         char content_type[256];
96         char content_disposition[256];
97         char *start;
98         char buf[512];
99         int crlf = 0;           /* set to 1 for crlf-style newlines */
100         int actual_length;
101
102         strcpy(content_type, supplied_content_type);
103
104         /* Strip off any leading blank lines. */
105         start = content;
106         while ((!strncmp(start, "\r", 1)) || (!strncmp(start, "\n", 1))) {
107                 ++start;
108                 --part_length;
109         }
110
111         /* At this point all we have left is the headers and the content. */
112         do {
113                 strcpy(buf, "");
114                 do {
115                         buf[strlen(buf) + 1] = 0;
116                         if (strlen(buf) < ((sizeof buf) - 1)) {
117                                 strncpy(&buf[strlen(buf)], start, 1);
118                         }
119                         ++start;
120                         --part_length;
121                 } while ((buf[strlen(buf) - 1] != 10) && (part_length > 0));
122                 if (part_length <= 0)
123                         return;
124                 buf[strlen(buf) - 1] = 0;
125                 if (buf[strlen(buf) - 1] == 13) {
126                         buf[strlen(buf) - 1] = 0;
127                         crlf = 1;
128                 }
129                 if (!strncasecmp(buf, "Content-type: ", 14)) {
130                         strcpy(content_type, &buf[14]);
131                 }
132                 if (!strncasecmp(buf, "Content-disposition: ", 21)) {
133                         strcpy(content_disposition, &buf[21]);
134                 }
135         } while (strlen(buf) > 0);
136
137         if (crlf)
138                 actual_length = part_length - 2;
139         else
140                 actual_length = part_length - 1;
141
142         /* Now that we've got this component isolated, what to do with it? */
143         do_something_with_it(start, actual_length,
144                              content_type, content_disposition, CallBack);
145
146 }
147
148
149 /*
150  * Break out the components of a multipart message
151  * (This function expects to be fed CONTENT ONLY, no headers)
152  */
153
154
155 void mime_parser(char *content,
156                  int ContentLength,
157                  char *ContentType,
158                  void (*CallBack)
159                   (char *cbname,
160                    char *cbfilename,
161                    char *cbencoding,
162                    void *cbcontent,
163                    char *cbtype,
164                    size_t cblength)
165 )
166 {
167         char boundary[256];
168         char endary[256];
169         int have_boundary = 0;
170         int a;
171         char *ptr;
172         char *beginning;
173         int bytes_processed = 0;
174         int part_length;
175
176         /* If it's not multipart, don't process it as multipart */
177         if (strncasecmp(ContentType, "multipart", 9)) {
178                 do_something_with_it(content, ContentLength,
179                                      ContentType, "", CallBack);
180                 return;
181         }
182         /* Figure out what the boundary is */
183         strcpy(boundary, ContentType);
184         for (a = 0; a < strlen(boundary); ++a) {
185                 if (!strncasecmp(&boundary[a], "boundary=", 9)) {
186                         boundary[0] = '-';
187                         boundary[1] = '-';
188                         strcpy(&boundary[2], &boundary[a + 9]);
189                         have_boundary = 1;
190                         a = 0;
191                 }
192                 if ((boundary[a] == 13) || (boundary[a] == 10)) {
193                         boundary[a] = 0;
194                 }
195         }
196
197         /* We can't process multipart messages without a boundary. */
198         if (have_boundary == 0)
199                 return;
200         strcpy(endary, boundary);
201         strcat(endary, "--");
202
203         ptr = content;
204
205         /* Seek to the beginning of the next boundary */
206         while (bytes_processed < ContentLength) {
207                 /* && (strncasecmp(ptr, boundary, strlen(boundary))) ) { */
208
209                 if (strncasecmp(ptr, boundary, strlen(boundary))) {
210                         ++ptr;
211                         ++bytes_processed;
212                 }
213                 /* See if we're at the end */
214                 if (!strncasecmp(ptr, endary, strlen(endary))) {
215                         return;
216                 }
217                 /* Seek to the end of the boundary string */
218                 if (!strncasecmp(ptr, boundary, strlen(boundary))) {
219                         while ((bytes_processed < ContentLength)
220                                && (strncasecmp(ptr, "\n", 1))) {
221                                 ++ptr;
222                                 ++bytes_processed;
223                         }
224                         beginning = ptr;
225                         part_length = 0;
226                         while ((bytes_processed < ContentLength)
227                                && (strncasecmp(ptr, boundary, strlen(boundary)))) {
228                                 ++ptr;
229                                 ++bytes_processed;
230                                 ++part_length;
231                         }
232                         handle_part(beginning, part_length, "", CallBack);
233                         /* Back off so we can see the next boundary */
234                         --ptr;
235                         --bytes_processed;
236                 }
237         }
238 }