2 * This file is part of DisOrder.
3 * Copyright (C) 2005, 2007, 2008 Richard Kettlewell
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 static int test_multipart_callback(const char *s
, void *u
) {
23 struct vector
*parts
= u
;
25 vector_append(parts
, (char *)s
);
29 static int header_callback(const char *name
, const char *value
,
33 hash_add(h
, name
, &value
, HASH_INSERT
);
37 static void test_mime(void) {
39 struct vector parts
[1];
41 const char *s
, *cs
, *enc
;
46 insist(!mime_content_type("text/plain", &t
, &k
));
47 check_string(t
, "text/plain");
50 insist(mime_content_type("TEXT ((broken) comment", &t
, &k
) < 0);
51 insist(mime_content_type("TEXT ((broken) comment\\", &t
, &k
) < 0);
55 insist(!mime_content_type("TEXT ((nested)\\ comment) /plain", &t
, &k
));
56 check_string(t
, "text/plain");
61 insist(!mime_content_type(" text/plain ; Charset=\"utf-\\8\"", &t
, &k
));
62 check_string(t
, "text/plain");
65 check_string(k
->name
, "charset");
66 check_string(k
->value
, "utf-8");
70 insist(!mime_content_type("text/plain;charset = ISO-8859-1 ", &t
, &k
));
73 check_string(t
, "text/plain");
74 check_string(k
->name
, "charset");
75 check_string(k
->value
, "ISO-8859-1");
78 insist(!mime_rfc2388_content_disposition("form-data; name=\"field1\"", &t
, &n
, &v
));
79 check_string(t
, "form-data");
80 check_string(n
, "name");
81 check_string(v
, "field1");
83 insist(!mime_rfc2388_content_disposition("inline", &t
, &n
, &v
));
84 check_string(t
, "inline");
88 /* Current versions of the code only understand a single arg to these
89 * headers. This is a bug at the level they work at but suffices for
90 * DisOrder's current purposes. */
92 insist(!mime_rfc2388_content_disposition(
93 "attachment; filename=genome.jpeg;\n"
94 "modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\"",
96 check_string(t
, "attachment");
97 check_string(n
, "filename");
98 check_string(v
, "genome.jpeg");
101 insist(mime_multipart("--outer\r\n"
102 "Content-Type: text/plain\r\n"
103 "Content-Disposition: inline\r\n"
104 "Content-Description: text-part-1\r\n"
106 "Some text goes here\r\n"
109 "Content-Type: multipart/mixed; boundary=inner\r\n"
110 "Content-Disposition: attachment\r\n"
111 "Content-Description: multipart-2\r\n"
114 "Content-Type: text/plain\r\n"
115 "Content-Disposition: inline\r\n"
116 "Content-Description: text-part-2\r\n"
118 "Some more text here.\r\n"
121 "Content-Type: image/jpeg\r\n"
122 "Content-Disposition: attachment\r\n"
123 "Content-Description: jpeg-1\r\n"
128 test_multipart_callback
,
131 check_integer(parts
->nvec
, 2);
132 check_string(parts
->vec
[0],
133 "Content-Type: text/plain\r\n"
134 "Content-Disposition: inline\r\n"
135 "Content-Description: text-part-1\r\n"
137 "Some text goes here\r\n");
138 check_string(parts
->vec
[1],
139 "Content-Type: multipart/mixed; boundary=inner\r\n"
140 "Content-Disposition: attachment\r\n"
141 "Content-Description: multipart-2\r\n"
144 "Content-Type: text/plain\r\n"
145 "Content-Disposition: inline\r\n"
146 "Content-Description: text-part-2\r\n"
148 "Some more text here.\r\n"
151 "Content-Type: image/jpeg\r\n"
152 "Content-Disposition: attachment\r\n"
153 "Content-Description: jpeg-1\r\n"
157 /* No trailing CRLF is _correct_ - see RFC2046 5.1.1 note regarding CRLF
158 * preceding the boundary delimiter line. An implication of this is that we
159 * must cope with partial lines at the end of the input when recursively
160 * decomposing a multipart message. */
162 insist(mime_multipart("--inner\r\n"
163 "Content-Type: text/plain\r\n"
164 "Content-Disposition: inline\r\n"
165 "Content-Description: text-part-2\r\n"
167 "Some more text here.\r\n"
170 "Content-Type: image/jpeg\r\n"
171 "Content-Disposition: attachment\r\n"
172 "Content-Description: jpeg-1\r\n"
176 test_multipart_callback
,
179 check_integer(parts
->nvec
, 2);
180 check_string(parts
->vec
[0],
181 "Content-Type: text/plain\r\n"
182 "Content-Disposition: inline\r\n"
183 "Content-Description: text-part-2\r\n"
185 "Some more text here.\r\n");
186 check_string(parts
->vec
[1],
187 "Content-Type: image/jpeg\r\n"
188 "Content-Disposition: attachment\r\n"
189 "Content-Description: jpeg-1\r\n"
193 /* Bogus inputs to mime_multipart() */
194 fprintf(stderr
, "expect two mime_multipart errors:\n");
195 insist(mime_multipart("--inner\r\n"
196 "Content-Type: text/plain\r\n"
197 "Content-Disposition: inline\r\n"
198 "Content-Description: text-part-2\r\n"
200 "Some more text here.\r\n"
203 "Content-Type: image/jpeg\r\n"
204 "Content-Disposition: attachment\r\n"
205 "Content-Description: jpeg-1\r\n"
208 test_multipart_callback
,
211 insist(mime_multipart("--wrong\r\n"
212 "Content-Type: text/plain\r\n"
213 "Content-Disposition: inline\r\n"
214 "Content-Description: text-part-2\r\n"
216 "Some more text here.\r\n"
219 test_multipart_callback
,
225 check_string(mime_qp(""), "");
226 check_string(mime_qp("foobar"), "foobar");
227 check_string(mime_qp("foo=20bar"), "foo bar");
228 check_string(mime_qp("x \r\ny"), "x\r\ny");
229 check_string(mime_qp("x=\r\ny"), "xy");
230 check_string(mime_qp("x= \r\ny"), "xy");
231 check_string(mime_qp("x =\r\ny"), "x y");
232 check_string(mime_qp("x = \r\ny"), "x y");
234 check_string(mime_to_qp(""), "");
235 check_string(mime_to_qp("foobar\n"), "foobar\n");
236 check_string(mime_to_qp("foobar \n"), "foobar=20\n");
237 check_string(mime_to_qp("foobar\t\n"), "foobar=09\n");
238 check_string(mime_to_qp("foobar \t \n"), "foobar=20=09=20\n");
239 check_string(mime_to_qp(" foo=bar"), " foo=3Dbar\n");
240 check_string(mime_to_qp("copyright \xC2\xA9"), "copyright =C2=A9\n");
241 check_string(mime_to_qp("foo\nbar\nbaz\n"), "foo\nbar\nbaz\n");
242 check_string(mime_to_qp("wibble wobble wibble wobble wibble wobble wibble wobble wibble wobble wibble"), "wibble wobble wibble wobble wibble wobble wibble wobble wibble wobble wibb=\nle\n");
245 check_string(mime_qp("Now's the time =\r\n"
246 "for all folk to come=\r\n"
247 " to the aid of their country."),
248 "Now's the time for all folk to come to the aid of their country.");
250 #define check_base64(encoded, decoded) do { \
252 check_string(mime_base64(encoded, &ns), decoded); \
253 insist(ns == (sizeof decoded) - 1); \
254 check_string(mime_to_base64((const uint8_t *)decoded, \
255 (sizeof decoded) - 1), \
260 check_base64("", "");
261 check_base64("BBBB", "\x04\x10\x41");
262 check_base64("////", "\xFF\xFF\xFF");
263 check_base64("//BB", "\xFF\xF0\x41");
264 check_base64("BBBB//BB////",
265 "\x04\x10\x41" "\xFF\xF0\x41" "\xFF\xFF\xFF");
266 check_base64("BBBBBA==",
267 "\x04\x10\x41" "\x04");
268 check_base64("BBBBBBA=",
269 "\x04\x10\x41" "\x04\x10");
271 /* Check that decoding handles various kinds of rubbish OK */
272 check_string(mime_base64("B B B B / / B B / / / /", 0),
273 "\x04\x10\x41" "\xFF\xF0\x41" "\xFF\xFF\xFF");
274 check_string(mime_base64("B\r\nBBB.// B-B//~//", 0),
275 "\x04\x10\x41" "\xFF\xF0\x41" "\xFF\xFF\xFF");
276 check_string(mime_base64("BBBB BB==", 0),
277 "\x04\x10\x41" "\x04");
278 check_string(mime_base64("BBBB BB = =", 0),
279 "\x04\x10\x41" "\x04");
280 check_string(mime_base64("BBBB BBB=", 0),
281 "\x04\x10\x41" "\x04\x10");
282 check_string(mime_base64("BBBB BBB = ", 0),
283 "\x04\x10\x41" "\x04\x10");
284 check_string(mime_base64("BBBB=", 0),
286 check_string(mime_base64("BBBBBB==", 0),
287 "\x04\x10\x41" "\x04");
288 check_string(mime_base64("BBBBBBB=", 0),
289 "\x04\x10\x41" "\x04\x10");
290 /* Not actually valid base64 */
291 check_string(mime_base64("BBBBx=", 0),
294 h
= hash_new(sizeof (char *));
295 s
= mime_parse("From: sender@example.com\r\n"
296 "To: rcpt@example.com\r\n"
297 "Subject: test #1\r\n"
302 check_string(*(char **)hash_find(h
, "from"), "sender@example.com");
303 check_string(*(char **)hash_find(h
, "to"), "rcpt@example.com");
304 check_string(*(char **)hash_find(h
, "subject"), "test #1");
305 check_string(s
, "body\r\n");
307 h
= hash_new(sizeof (char *));
308 s
= mime_parse("FROM: sender@example.com\r\n"
309 "TO: rcpt@example.com\r\n"
310 "SUBJECT: test #1\r\n"
311 "CONTENT-TRANSFER-ENCODING: 7bit\r\n"
316 check_string(*(char **)hash_find(h
, "from"), "sender@example.com");
317 check_string(*(char **)hash_find(h
, "to"), "rcpt@example.com");
318 check_string(*(char **)hash_find(h
, "subject"), "test #1");
319 check_string(*(char **)hash_find(h
, "content-transfer-encoding"), "7bit");
320 check_string(s
, "body\r\n");
322 h
= hash_new(sizeof (char *));
323 s
= mime_parse("From: sender@example.com\r\n"
325 " rcpt@example.com\r\n"
326 "Subject: test #1\r\n"
327 "MIME-Version: 1.0\r\n"
328 "Content-Type: text/plain\r\n"
329 "Content-Transfer-Encoding: BASE64\r\n"
334 check_string(*(char **)hash_find(h
, "from"), "sender@example.com");
335 check_string(*(char **)hash_find(h
, "to"), "rcpt@example.com");
336 check_string(*(char **)hash_find(h
, "subject"), "test #1");
337 check_string(*(char **)hash_find(h
, "mime-version"), "1.0");
338 check_string(*(char **)hash_find(h
, "content-type"), "text/plain");
339 check_string(*(char **)hash_find(h
, "content-transfer-encoding"), "BASE64");
340 check_string(s
, "wibble\r\n");
342 #define CHECK_QUOTE(INPUT, EXPECT) do { \
343 s = quote822(INPUT, 0); \
345 check_string(s, EXPECT); \
346 s = mime_parse_word(s, &t, mime_http_separator); \
347 check_string(t, INPUT); \
349 CHECK_QUOTE("wibble", "wibble");
350 CHECK_QUOTE("wibble spong", "\"wibble spong\"");
351 CHECK_QUOTE("wibble\\spong", "\"wibble\\\\spong\"");
352 CHECK_QUOTE("wibble\"spong", "\"wibble\\\"spong\"");
353 CHECK_QUOTE("(wibble)", "\"(wibble)\"");
355 s
= mime_encode_text("wibble\n", &cs
, &enc
);
357 check_string(s
, "wibble\n");
358 check_string(cs
, "us-ascii");
359 check_string(enc
, "7bit");
361 s
= mime_encode_text("wibble\xC3\xB7\n", &cs
, &enc
);
363 check_string(s
, "wibble=C3=B7\n");
364 check_string(cs
, "utf-8");
365 check_string(enc
, "quoted-printable");