Commit eae41894 eae41894c2614ddc2c3732014cb62bf68ab4e16a by Sergey Poznyakoff

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
1 parent 7dee238e
...@@ -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, &param);
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 (&param);
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;
......