Fix parsing of Content-Type and Content-Disposition headers
Correctly handle character set and language info embedded in parameter values, and eventual parameter value continuations as per RFC 2231, Section 3. * include/mailutils/assoc.h (mu_assoc_is_empty): New proto. * libmailutils/base/assoc.c (mu_assoc_is_empty): New function. * include/mailutils/mime.h (mu_mime_header_parse): Output charset is char const *. * libmailutils/mime/mimehdr.c (mu_mime_header_parse): Likewise. * include/mailutils/util.h (mu_content_type) <param>: Change type to mu_assoc_t (mu_param): Remove structure declaration. (mu_content_type_parse): Take an optional output charset. * libmailutils/base/ctparse.c (mu_content_type_parse): Rewrite using mu_mime_header_parse. * imap4d/fetch.c (send_parameter_list): Rewrite using mu_mime_header_parse. (format_param): Use base64 for parameter values with explicit charsets. * libmailutils/tests/conttype.c: Reflect the changes to struct mu_content_type
Showing
8 changed files
with
108 additions
and
276 deletions
... | @@ -17,7 +17,7 @@ | ... | @@ -17,7 +17,7 @@ |
17 | 17 | ||
18 | #include "imap4d.h" | 18 | #include "imap4d.h" |
19 | #include <ctype.h> | 19 | #include <ctype.h> |
20 | #include <mailutils/argcv.h> | 20 | #include <mailutils/assoc.h> |
21 | 21 | ||
22 | /* Taken from RFC2060 | 22 | /* Taken from RFC2060 |
23 | fetch ::= "FETCH" SPACE set SPACE ("ALL" / "FULL" / | 23 | fetch ::= "FETCH" SPACE set SPACE ("ALL" / "FULL" / |
... | @@ -164,95 +164,47 @@ fetch_send_header_address (mu_header_t header, const char *name, | ... | @@ -164,95 +164,47 @@ fetch_send_header_address (mu_header_t header, const char *name, |
164 | fetch_send_address (defval); | 164 | fetch_send_address (defval); |
165 | } | 165 | } |
166 | 166 | ||
167 | static void | 167 | static int format_param (char const *name, void *item, void *data); |
168 | imap4d_ws_alloc_die (struct mu_wordsplit *wsp) | ||
169 | { | ||
170 | imap4d_bye (ERR_NO_MEM); | ||
171 | } | ||
172 | |||
173 | #define IMAP4D_WS_FLAGS \ | ||
174 | (MU_WRDSF_DEFFLAGS | MU_WRDSF_DELIM | \ | ||
175 | MU_WRDSF_ENOMEMABRT | MU_WRDSF_ALLOC_DIE) | ||
176 | 168 | ||
177 | /* Send parameter list for the bodystructure. */ | 169 | /* Send parameter list for the bodystructure. */ |
178 | static void | 170 | static void |
179 | send_parameter_list (const char *buffer) | 171 | send_parameter_list (const char *buffer) |
180 | { | 172 | { |
181 | struct mu_wordsplit ws; | 173 | int rc; |
174 | char *value; | ||
175 | mu_assoc_t param; | ||
182 | 176 | ||
183 | if (!buffer) | 177 | if (!buffer || mu_str_skip_class (buffer, MU_CTYPE_BLANK)[0] == 0) |
184 | { | 178 | { |
185 | io_sendf ("NIL"); | 179 | io_sendf ("NIL"); |
186 | return; | 180 | return; |
187 | } | 181 | } |
188 | 182 | ||
189 | ws.ws_delim = " \t\r\n;="; | 183 | rc = mu_mime_header_parse (buffer, NULL, &value, ¶m); |
190 | ws.ws_alloc_die = imap4d_ws_alloc_die; | 184 | if (rc) |
191 | if (mu_wordsplit (buffer, &ws, IMAP4D_WS_FLAGS)) | ||
192 | { | 185 | { |
193 | mu_error (_("%s failed: %s"), "mu_wordsplit", | 186 | mu_diag_funcall (MU_DIAG_ERROR, "mu_content_type_parse", buffer, rc); |
194 | mu_wordsplit_strerror (&ws)); | 187 | io_sendf ("NIL"); |
195 | return; /* FIXME: a better error handling, maybe? */ | 188 | return; |
196 | } | 189 | } |
197 | 190 | ||
198 | if (ws.ws_wordc == 0) | 191 | io_sendf ("("); |
199 | io_sendf ("NIL"); | 192 | io_send_qstring (value); |
193 | io_sendf (" "); | ||
194 | if (mu_assoc_is_empty (param)) | ||
195 | { | ||
196 | io_sendf ("NIL"); | ||
197 | } | ||
200 | else | 198 | else |
201 | { | 199 | { |
202 | char *p; | 200 | int first = 1; |
203 | |||
204 | io_sendf ("("); | 201 | io_sendf ("("); |
205 | 202 | mu_assoc_foreach (param, format_param, &first); | |
206 | p = ws.ws_wordv[0]; | ||
207 | io_send_qstring (p); | ||
208 | |||
209 | if (ws.ws_wordc > 1) | ||
210 | { | ||
211 | int i, space = 0; | ||
212 | char *lvalue = NULL; | ||
213 | |||
214 | io_sendf ("("); | ||
215 | for (i = 1; i < ws.ws_wordc; i++) | ||
216 | { | ||
217 | if (lvalue) | ||
218 | { | ||
219 | if (space) | ||
220 | io_sendf (" "); | ||
221 | io_send_qstring (lvalue); | ||
222 | lvalue = NULL; | ||
223 | space = 1; | ||
224 | } | ||
225 | |||
226 | switch (ws.ws_wordv[i][0]) | ||
227 | { | ||
228 | case ';': | ||
229 | continue; | ||
230 | |||
231 | case '=': | ||
232 | if (++i < ws.ws_wordc) | ||
233 | { | ||
234 | io_sendf (" "); | ||
235 | io_send_qstring (ws.ws_wordv[i]); | ||
236 | } | ||
237 | break; | ||
238 | |||
239 | default: | ||
240 | lvalue = ws.ws_wordv[i]; | ||
241 | } | ||
242 | } | ||
243 | if (lvalue) | ||
244 | { | ||
245 | if (space) | ||
246 | io_sendf (" "); | ||
247 | io_send_qstring (lvalue); | ||
248 | } | ||
249 | io_sendf (")"); | ||
250 | } | ||
251 | else | ||
252 | io_sendf (" NIL"); | ||
253 | io_sendf (")"); | 203 | io_sendf (")"); |
254 | } | 204 | } |
255 | mu_wordsplit_free (&ws); | 205 | io_sendf (")"); |
206 | free (value); | ||
207 | mu_assoc_destroy (¶m); | ||
256 | } | 208 | } |
257 | 209 | ||
258 | static void | 210 | static void |
... | @@ -263,7 +215,7 @@ fetch_send_header_list (mu_header_t header, const char *name, | ... | @@ -263,7 +215,7 @@ fetch_send_header_list (mu_header_t header, const char *name, |
263 | 215 | ||
264 | if (space) | 216 | if (space) |
265 | io_sendf (" "); | 217 | io_sendf (" "); |
266 | if (mu_header_aget_value (header, name, &buffer) == 0) | 218 | if (mu_header_aget_value_unfold (header, name, &buffer) == 0) |
267 | { | 219 | { |
268 | send_parameter_list (buffer); | 220 | send_parameter_list (buffer); |
269 | free (buffer); | 221 | free (buffer); |
... | @@ -315,16 +267,32 @@ fetch_envelope0 (mu_message_t msg) | ... | @@ -315,16 +267,32 @@ fetch_envelope0 (mu_message_t msg) |
315 | static int fetch_bodystructure0 (mu_message_t message, int extension); | 267 | static int fetch_bodystructure0 (mu_message_t message, int extension); |
316 | 268 | ||
317 | static int | 269 | static int |
318 | format_param (void *item, void *data) | 270 | format_param (char const *name, void *item, void *data) |
319 | { | 271 | { |
320 | struct mu_param *p = item; | 272 | struct mu_mime_param *p = item; |
321 | int *first = data; | 273 | int *first = data; |
322 | 274 | ||
323 | if (!*first) | 275 | if (!*first) |
324 | io_sendf (" "); | 276 | io_sendf (" "); |
325 | io_send_qstring (p->name); | 277 | io_send_qstring (name); |
326 | io_sendf (" "); | 278 | io_sendf (" "); |
327 | io_send_qstring (p->value); | 279 | if (p->cset) |
280 | { | ||
281 | char *text; | ||
282 | int rc = mu_rfc2047_encode (p->cset, "base64", p->value, &text); | ||
283 | if (rc == 0) | ||
284 | { | ||
285 | io_send_qstring (text); | ||
286 | free (text); | ||
287 | } | ||
288 | else | ||
289 | { | ||
290 | mu_diag_funcall (MU_DIAG_ERROR, "mu_rfc2047_encode", p->value, rc); | ||
291 | io_send_qstring (p->value); | ||
292 | } | ||
293 | } | ||
294 | else | ||
295 | io_send_qstring (p->value); | ||
328 | *first = 0; | 296 | *first = 0; |
329 | return 0; | 297 | return 0; |
330 | } | 298 | } |
... | @@ -338,19 +306,19 @@ get_content_type (mu_header_t hdr, mu_content_type_t *ctp, char const *dfl) | ... | @@ -338,19 +306,19 @@ get_content_type (mu_header_t hdr, mu_content_type_t *ctp, char const *dfl) |
338 | rc = mu_header_aget_value_unfold (hdr, MU_HEADER_CONTENT_TYPE, &buffer); | 306 | rc = mu_header_aget_value_unfold (hdr, MU_HEADER_CONTENT_TYPE, &buffer); |
339 | if (rc == 0) | 307 | if (rc == 0) |
340 | { | 308 | { |
341 | rc = mu_content_type_parse (buffer, ctp); | 309 | rc = mu_content_type_parse (buffer, NULL, ctp); |
342 | if (rc == MU_ERR_PARSE) | 310 | if (rc == MU_ERR_PARSE) |
343 | { | 311 | { |
344 | mu_error (_("malformed content type: %s"), buffer); | 312 | mu_error (_("malformed content type: %s"), buffer); |
345 | if (dfl) | 313 | if (dfl) |
346 | rc = mu_content_type_parse (dfl, ctp); | 314 | rc = mu_content_type_parse (dfl, NULL, ctp); |
347 | } | 315 | } |
348 | else if (rc) | 316 | else if (rc) |
349 | mu_diag_funcall (MU_DIAG_ERROR, "mu_content_type_parse", buffer, rc); | 317 | mu_diag_funcall (MU_DIAG_ERROR, "mu_content_type_parse", buffer, rc); |
350 | free (buffer); | 318 | free (buffer); |
351 | } | 319 | } |
352 | else if (rc == MU_ERR_NOENT && dfl) | 320 | else if (rc == MU_ERR_NOENT && dfl) |
353 | rc = mu_content_type_parse (dfl, ctp); | 321 | rc = mu_content_type_parse (dfl, NULL, ctp); |
354 | return rc; | 322 | return rc; |
355 | } | 323 | } |
356 | 324 | ||
... | @@ -424,13 +392,13 @@ bodystructure (mu_message_t msg, int extension) | ... | @@ -424,13 +392,13 @@ bodystructure (mu_message_t msg, int extension) |
424 | io_send_qstring (ct->subtype); | 392 | io_send_qstring (ct->subtype); |
425 | 393 | ||
426 | /* body parameter parenthesized list: Content-type attributes */ | 394 | /* body parameter parenthesized list: Content-type attributes */ |
427 | if (mu_list_is_empty (ct->param)) | 395 | if (mu_assoc_is_empty (ct->param)) |
428 | io_sendf (" NIL"); | 396 | io_sendf (" NIL"); |
429 | else | 397 | else |
430 | { | 398 | { |
431 | int first = 1; | 399 | int first = 1; |
432 | io_sendf (" ("); | 400 | io_sendf (" ("); |
433 | mu_list_foreach (ct->param, format_param, &first); | 401 | mu_assoc_foreach (ct->param, format_param, &first); |
434 | io_sendf (")"); | 402 | io_sendf (")"); |
435 | } | 403 | } |
436 | mu_content_type_destroy (&ct); | 404 | mu_content_type_destroy (&ct); |
... | @@ -557,11 +525,11 @@ fetch_bodystructure0 (mu_message_t message, int extension) | ... | @@ -557,11 +525,11 @@ fetch_bodystructure0 (mu_message_t message, int extension) |
557 | io_send_qstring (ct->subtype); | 525 | io_send_qstring (ct->subtype); |
558 | 526 | ||
559 | /* The extension data for multipart. */ | 527 | /* The extension data for multipart. */ |
560 | if (extension && !mu_list_is_empty (ct->param)) | 528 | if (extension && !mu_assoc_is_empty (ct->param)) |
561 | { | 529 | { |
562 | int first = 1; | 530 | int first = 1; |
563 | io_sendf (" ("); | 531 | io_sendf (" ("); |
564 | mu_list_foreach (ct->param, format_param, &first); | 532 | mu_assoc_foreach (ct->param, format_param, &first); |
565 | io_sendf (")"); | 533 | io_sendf (")"); |
566 | } | 534 | } |
567 | else | 535 | else |
... | @@ -581,8 +549,8 @@ fetch_bodystructure0 (mu_message_t message, int extension) | ... | @@ -581,8 +549,8 @@ fetch_bodystructure0 (mu_message_t message, int extension) |
581 | fetch_send_header_list (header, MU_HEADER_CONTENT_DISPOSITION, | 549 | fetch_send_header_list (header, MU_HEADER_CONTENT_DISPOSITION, |
582 | NULL, 1); | 550 | NULL, 1); |
583 | /* body language: Content-Language. */ | 551 | /* body language: Content-Language. */ |
584 | fetch_send_header_list (header, MU_HEADER_CONTENT_LANGUAGE, | 552 | fetch_send_header_value (header, MU_HEADER_CONTENT_LANGUAGE, |
585 | NULL, 1); | 553 | NULL, 1); |
586 | } | 554 | } |
587 | else | 555 | else |
588 | bodystructure (message, extension); | 556 | bodystructure (message, extension); | ... | ... |
... | @@ -42,6 +42,7 @@ int mu_assoc_get_iterator (mu_assoc_t assoc, mu_iterator_t *piterator); | ... | @@ -42,6 +42,7 @@ int mu_assoc_get_iterator (mu_assoc_t assoc, mu_iterator_t *piterator); |
42 | int mu_assoc_remove (mu_assoc_t assoc, const char *name); | 42 | int mu_assoc_remove (mu_assoc_t assoc, const char *name); |
43 | int mu_assoc_set_destroy_item (mu_assoc_t assoc, mu_deallocator_t fn); | 43 | int mu_assoc_set_destroy_item (mu_assoc_t assoc, mu_deallocator_t fn); |
44 | int mu_assoc_count (mu_assoc_t assoc, size_t *pcount); | 44 | int mu_assoc_count (mu_assoc_t assoc, size_t *pcount); |
45 | int mu_assoc_is_empty (mu_assoc_t assoc); | ||
45 | 46 | ||
46 | typedef int (*mu_assoc_action_t) (char const *, void *, void *); | 47 | typedef int (*mu_assoc_action_t) (char const *, void *, void *); |
47 | int mu_assoc_foreach (mu_assoc_t assoc, mu_assoc_action_t action, void *data); | 48 | int mu_assoc_foreach (mu_assoc_t assoc, mu_assoc_action_t action, void *data); | ... | ... |
... | @@ -70,7 +70,7 @@ int mu_base64_decode (const unsigned char *input, size_t input_len, | ... | @@ -70,7 +70,7 @@ int mu_base64_decode (const unsigned char *input, size_t input_len, |
70 | int mu_mime_param_assoc_create (mu_assoc_t *passoc); | 70 | int mu_mime_param_assoc_create (mu_assoc_t *passoc); |
71 | int mu_mime_param_assoc_add (mu_assoc_t assoc, const char *name); | 71 | int mu_mime_param_assoc_add (mu_assoc_t assoc, const char *name); |
72 | 72 | ||
73 | int mu_mime_header_parse (const char *text, char *charset, char **pvalue, | 73 | int mu_mime_header_parse (const char *text, const char *charset, char **pvalue, |
74 | mu_assoc_t *paramtab); | 74 | mu_assoc_t *paramtab); |
75 | int mu_mime_header_parse_subset (const char *text, const char *charset, | 75 | int mu_mime_header_parse_subset (const char *text, const char *charset, |
76 | char **pvalue, | 76 | char **pvalue, | ... | ... |
... | @@ -131,18 +131,13 @@ struct mu_content_type | ... | @@ -131,18 +131,13 @@ struct mu_content_type |
131 | char *type; | 131 | char *type; |
132 | char *subtype; | 132 | char *subtype; |
133 | char *trailer; | 133 | char *trailer; |
134 | mu_list_t param; | 134 | mu_assoc_t param; |
135 | }; | 135 | }; |
136 | 136 | ||
137 | typedef struct mu_content_type *mu_content_type_t; | 137 | typedef struct mu_content_type *mu_content_type_t; |
138 | |||
139 | struct mu_param | ||
140 | { | ||
141 | char *name; | ||
142 | char *value; | ||
143 | }; | ||
144 | 138 | ||
145 | int mu_content_type_parse (const char *input, mu_content_type_t *retct); | 139 | int mu_content_type_parse (const char *input, const char *charset, |
140 | mu_content_type_t *retct); | ||
146 | void mu_content_type_destroy (mu_content_type_t *pptr); | 141 | void mu_content_type_destroy (mu_content_type_t *pptr); |
147 | 142 | ||
148 | /* ----------------------- */ | 143 | /* ----------------------- */ | ... | ... |
... | @@ -643,6 +643,12 @@ mu_assoc_count (mu_assoc_t assoc, size_t *pcount) | ... | @@ -643,6 +643,12 @@ mu_assoc_count (mu_assoc_t assoc, size_t *pcount) |
643 | } | 643 | } |
644 | 644 | ||
645 | int | 645 | int |
646 | mu_assoc_is_empty (mu_assoc_t assoc) | ||
647 | { | ||
648 | return assoc == NULL || assoc->head == NULL; | ||
649 | } | ||
650 | |||
651 | int | ||
646 | mu_assoc_foreach (mu_assoc_t assoc, mu_assoc_action_t action, void *data) | 652 | mu_assoc_foreach (mu_assoc_t assoc, mu_assoc_action_t action, void *data) |
647 | { | 653 | { |
648 | mu_iterator_t itr; | 654 | mu_iterator_t itr; | ... | ... |
... | @@ -21,206 +21,68 @@ | ... | @@ -21,206 +21,68 @@ |
21 | #include <stdlib.h> | 21 | #include <stdlib.h> |
22 | #include <string.h> | 22 | #include <string.h> |
23 | #include <mailutils/types.h> | 23 | #include <mailutils/types.h> |
24 | #include <mailutils/cstr.h> | 24 | #include <mailutils/mime.h> |
25 | #include <mailutils/cctype.h> | 25 | #include <mailutils/assoc.h> |
26 | #include <mailutils/util.h> | 26 | #include <mailutils/util.h> |
27 | #include <mailutils/errno.h> | 27 | #include <mailutils/errno.h> |
28 | 28 | ||
29 | void | 29 | |
30 | mu_param_free (void *data) | ||
31 | { | ||
32 | struct mu_param *p = data; | ||
33 | free (p->name); | ||
34 | free (p->value); | ||
35 | free (p); | ||
36 | } | ||
37 | |||
38 | int | ||
39 | mu_param_cmp (void const *a, void const *b) | ||
40 | { | ||
41 | struct mu_param const *p1 = a; | ||
42 | struct mu_param const *p2 = b; | ||
43 | |||
44 | return mu_c_strcasecmp (p1->name, p2->name); | ||
45 | } | ||
46 | |||
47 | static int parse_param (const char **input_ptr, mu_content_type_t ct); | ||
48 | static int parse_params (const char *input, mu_content_type_t ct); | ||
49 | static int parse_subtype (const char *input, mu_content_type_t ct); | ||
50 | static int parse_type (const char *input, mu_content_type_t ct); | ||
51 | |||
52 | static int | ||
53 | parse_type (const char *input, mu_content_type_t ct) | ||
54 | { | ||
55 | size_t i; | ||
56 | |||
57 | for (i = 0; input[i] != '/'; i++) | ||
58 | { | ||
59 | if (input[i] == 0 | ||
60 | || !(mu_isalnum (input[i]) || input[i] == '-' || input[i] == '_')) | ||
61 | return MU_ERR_PARSE; | ||
62 | } | ||
63 | ct->type = malloc (i + 1); | ||
64 | if (!ct->type) | ||
65 | return ENOMEM; | ||
66 | memcpy (ct->type, input, i); | ||
67 | ct->type[i] = 0; | ||
68 | |||
69 | return parse_subtype (input + i + 1, ct); | ||
70 | } | ||
71 | |||
72 | static char tspecials[] = "()<>@,;:\\\"/[]?="; | ||
73 | |||
74 | #define ISTOKEN(c) ((unsigned char)(c) > ' ' && !strchr (tspecials, c)) | ||
75 | |||
76 | static int | ||
77 | parse_subtype (const char *input, mu_content_type_t ct) | ||
78 | { | ||
79 | size_t i; | ||
80 | |||
81 | for (i = 0; !(input[i] == 0 || input[i] == ';'); i++) | ||
82 | { | ||
83 | if (!ISTOKEN (input[i])) | ||
84 | return MU_ERR_PARSE; | ||
85 | } | ||
86 | ct->subtype = malloc (i + 1); | ||
87 | if (!ct->subtype) | ||
88 | return ENOMEM; | ||
89 | memcpy (ct->subtype, input, i); | ||
90 | ct->subtype[i] = 0; | ||
91 | |||
92 | return parse_params (input + i, ct); | ||
93 | } | ||
94 | |||
95 | static int | 30 | static int |
96 | parse_params (const char *input, mu_content_type_t ct) | 31 | content_type_parse (const char *input, const char *charset, |
32 | mu_content_type_t ct) | ||
97 | { | 33 | { |
98 | int rc; | 34 | int rc; |
99 | 35 | char *value, *p; | |
100 | rc = mu_list_create (&ct->param); | 36 | |
37 | rc = mu_mime_header_parse (input, charset, &value, &ct->param); | ||
101 | if (rc) | 38 | if (rc) |
102 | return rc; | 39 | return rc; |
103 | mu_list_set_destroy_item (ct->param, mu_param_free); | 40 | p = strchr (value, '/'); |
104 | mu_list_set_comparator (ct->param, mu_param_cmp); | 41 | if (p) |
105 | |||
106 | while (*input == ';') | ||
107 | { | 42 | { |
108 | input = mu_str_skip_class (input + 1, MU_CTYPE_SPACE); | 43 | size_t len = p - value; |
109 | rc = parse_param (&input, ct); | 44 | ct->type = malloc (len + 1); |
110 | if (rc) | 45 | if (!ct->type) |
111 | return rc; | ||
112 | } | ||
113 | |||
114 | if (*input) | ||
115 | { | ||
116 | input = mu_str_skip_class (input, MU_CTYPE_SPACE); | ||
117 | ct->trailer = strdup (input); | ||
118 | if (!ct->trailer) | ||
119 | return ENOMEM; | ||
120 | } | ||
121 | |||
122 | return rc; | ||
123 | } | ||
124 | |||
125 | static int | ||
126 | parse_param (const char **input_ptr, mu_content_type_t ct) | ||
127 | { | ||
128 | const char *input = *input_ptr; | ||
129 | size_t i = 0; | ||
130 | size_t namelen; | ||
131 | size_t valstart, vallen; | ||
132 | struct mu_param *p; | ||
133 | int rc; | ||
134 | unsigned quotechar = 0; | ||
135 | |||
136 | while (ISTOKEN (input[i])) | ||
137 | i++; | ||
138 | namelen = i; | ||
139 | |||
140 | if (input[i] != '=') | ||
141 | return MU_ERR_PARSE; | ||
142 | i++; | ||
143 | if (input[i] == '"') | ||
144 | { | ||
145 | i++; | ||
146 | valstart = i; | ||
147 | while (input[i] != '"') | ||
148 | { | 46 | { |
149 | if (input[i] == '\\') | 47 | rc = errno; |
150 | { | 48 | free (value); |
151 | quotechar++; | 49 | return rc; |
152 | i++; | ||
153 | } | ||
154 | if (!input[i]) | ||
155 | return MU_ERR_PARSE; | ||
156 | i++; | ||
157 | } | 50 | } |
158 | vallen = i - valstart - quotechar; | 51 | memcpy (ct->type, value, len); |
159 | i++; | 52 | ct->type[len] = 0; |
160 | } | ||
161 | else | ||
162 | { | ||
163 | valstart = i; | ||
164 | while (ISTOKEN (input[i])) | ||
165 | i++; | ||
166 | vallen = i - valstart; | ||
167 | } | ||
168 | 53 | ||
169 | p = malloc (sizeof (*p)); | 54 | ct->subtype = strdup (p + 1); |
170 | if (!p) | 55 | if (!ct->subtype) |
171 | return ENOMEM; | ||
172 | p->name = malloc (namelen + 1); | ||
173 | p->value = malloc (vallen + 1); | ||
174 | if (!p->name || !p->value) | ||
175 | { | ||
176 | mu_param_free (p); | ||
177 | return ENOMEM; | ||
178 | } | ||
179 | |||
180 | memcpy (p->name, input, namelen); | ||
181 | p->name[namelen] = 0; | ||
182 | if (quotechar) | ||
183 | { | ||
184 | size_t j; | ||
185 | const char *src = input + valstart; | ||
186 | |||
187 | for (i = j = 0; j < vallen; i++, j++) | ||
188 | { | 56 | { |
189 | if (src[j] == '\\') | 57 | rc = errno; |
190 | j++; | 58 | free (value); |
191 | p->value[i] = src[j]; | 59 | return rc; |
192 | } | 60 | } |
193 | p->value[i] = 0; | ||
194 | } | 61 | } |
195 | else | 62 | else |
196 | { | 63 | { |
197 | memcpy (p->value, input + valstart, vallen); | 64 | ct->type = value; |
198 | p->value[vallen] = 0; | 65 | ct->subtype = NULL; |
199 | } | ||
200 | |||
201 | rc = mu_list_append (ct->param, p); | ||
202 | if (rc) | ||
203 | { | ||
204 | mu_param_free (p); | ||
205 | return rc; | ||
206 | } | 66 | } |
207 | |||
208 | *input_ptr = input + i; | ||
209 | |||
210 | return 0; | 67 | return 0; |
211 | } | 68 | } |
212 | 69 | ||
213 | int | 70 | int |
214 | mu_content_type_parse (const char *input, mu_content_type_t *retct) | 71 | mu_content_type_parse (const char *input, const char *charset, |
72 | mu_content_type_t *retct) | ||
215 | { | 73 | { |
216 | int rc; | 74 | int rc; |
217 | mu_content_type_t ct; | 75 | mu_content_type_t ct; |
76 | |||
77 | if (!input) | ||
78 | return EINVAL; | ||
79 | if (!retct) | ||
80 | return MU_ERR_OUT_PTR_NULL; | ||
218 | 81 | ||
219 | ct = calloc (1, sizeof (*ct)); | 82 | ct = calloc (1, sizeof (*ct)); |
220 | if (!ct) | 83 | if (!ct) |
221 | return errno; | 84 | return errno; |
222 | 85 | rc = content_type_parse (input, charset, ct); | |
223 | rc = parse_type (mu_str_skip_class (input, MU_CTYPE_SPACE), ct); | ||
224 | if (rc) | 86 | if (rc) |
225 | mu_content_type_destroy (&ct); | 87 | mu_content_type_destroy (&ct); |
226 | else | 88 | else |
... | @@ -238,7 +100,7 @@ mu_content_type_destroy (mu_content_type_t *pptr) | ... | @@ -238,7 +100,7 @@ mu_content_type_destroy (mu_content_type_t *pptr) |
238 | free (ct->type); | 100 | free (ct->type); |
239 | free (ct->subtype); | 101 | free (ct->subtype); |
240 | free (ct->trailer); | 102 | free (ct->trailer); |
241 | mu_list_destroy (&ct->param); | 103 | mu_assoc_destroy (&ct->param); |
242 | free (ct); | 104 | free (ct); |
243 | *pptr = NULL; | 105 | *pptr = NULL; |
244 | } | 106 | } | ... | ... |
... | @@ -639,7 +639,7 @@ mu_mime_header_parse_subset (const char *text, const char *cset, | ... | @@ -639,7 +639,7 @@ mu_mime_header_parse_subset (const char *text, const char *cset, |
639 | corresponding data are of no interest to the caller. | 639 | corresponding data are of no interest to the caller. |
640 | */ | 640 | */ |
641 | int | 641 | int |
642 | mu_mime_header_parse (const char *text, char *cset, char **pvalue, | 642 | mu_mime_header_parse (const char *text, char const *cset, char **pvalue, |
643 | mu_assoc_t *passoc) | 643 | mu_assoc_t *passoc) |
644 | { | 644 | { |
645 | int rc; | 645 | int rc; | ... | ... |
... | @@ -3,11 +3,11 @@ | ... | @@ -3,11 +3,11 @@ |
3 | #include <assert.h> | 3 | #include <assert.h> |
4 | 4 | ||
5 | static int | 5 | static int |
6 | print_param (void *item, void *data) | 6 | print_param (char const *name, void *item, void *data) |
7 | { | 7 | { |
8 | size_t *n = data; | 8 | size_t *n = data; |
9 | struct mu_param *p = item; | 9 | struct mu_mime_param *p = item; |
10 | printf ("%2zu: %s=%s\n", *n, p->name, p->value); | 10 | printf ("%2zu: %s=%s\n", *n, name, p->value); |
11 | ++*n; | 11 | ++*n; |
12 | return 0; | 12 | return 0; |
13 | } | 13 | } |
... | @@ -18,7 +18,7 @@ parse (char const *input) | ... | @@ -18,7 +18,7 @@ parse (char const *input) |
18 | mu_content_type_t ct; | 18 | mu_content_type_t ct; |
19 | int rc; | 19 | int rc; |
20 | 20 | ||
21 | rc = mu_content_type_parse (input, &ct); | 21 | rc = mu_content_type_parse (input, NULL, &ct); |
22 | if (rc) | 22 | if (rc) |
23 | { | 23 | { |
24 | mu_error ("%s", mu_strerror (rc)); | 24 | mu_error ("%s", mu_strerror (rc)); |
... | @@ -29,10 +29,10 @@ parse (char const *input) | ... | @@ -29,10 +29,10 @@ parse (char const *input) |
29 | printf ("subtype = %s\n", ct->subtype); | 29 | printf ("subtype = %s\n", ct->subtype); |
30 | if (ct->trailer) | 30 | if (ct->trailer) |
31 | printf ("trailer = %s\n", ct->trailer); | 31 | printf ("trailer = %s\n", ct->trailer); |
32 | if (!mu_list_is_empty (ct->param)) | 32 | if (!mu_assoc_is_empty (ct->param)) |
33 | { | 33 | { |
34 | size_t n = 0; | 34 | size_t n = 0; |
35 | mu_list_foreach (ct->param, print_param, &n); | 35 | mu_assoc_foreach (ct->param, print_param, &n); |
36 | } | 36 | } |
37 | mu_content_type_destroy (&ct); | 37 | mu_content_type_destroy (&ct); |
38 | return 0; | 38 | return 0; | ... | ... |
-
Please register or sign in to post a comment