chiark / gitweb /
Split up increasingly unwieldy lib/test.c into multiple files.
[disorder] / lib / t-mime.c
1 /*
2  * This file is part of DisOrder.
3  * Copyright (C) 2005, 2007, 2008 Richard Kettlewell
4  *
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.
9  *
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.
14  *
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
18  * USA
19  */
20 #include "test.h"
21
22 static int test_multipart_callback(const char *s, void *u) {
23   struct vector *parts = u;
24
25   vector_append(parts, (char *)s);
26   return 0;
27 }
28
29 void test_mime(void) {
30   char *t, *n, *v;
31   struct vector parts[1];
32   struct kvp *k;
33
34   fprintf(stderr, "test_mime\n");
35
36   t = 0;
37   k = 0;
38   insist(!mime_content_type("text/plain", &t, &k));
39   check_string(t, "text/plain");
40   insist(k == 0);
41
42   insist(mime_content_type("TEXT ((broken) comment", &t, &k) < 0);
43   insist(mime_content_type("TEXT ((broken) comment\\", &t, &k) < 0);
44   
45   t = 0;
46   k = 0;
47   insist(!mime_content_type("TEXT ((nested)\\ comment) /plain", &t, &k));
48   check_string(t, "text/plain");
49   insist(k == 0);
50
51   t = 0;
52   k = 0;
53   insist(!mime_content_type(" text/plain ; Charset=\"utf-\\8\"", &t, &k));
54   check_string(t, "text/plain");
55   insist(k != 0);
56   insist(k->next == 0);
57   check_string(k->name, "charset");
58   check_string(k->value, "utf-8");
59
60   t = 0;
61   k = 0;
62   insist(!mime_content_type("text/plain;charset = ISO-8859-1 ", &t, &k));
63   insist(k != 0);
64   insist(k->next == 0);
65   check_string(t, "text/plain");
66   check_string(k->name, "charset");
67   check_string(k->value, "ISO-8859-1");
68
69   t = n = v = 0;
70   insist(!mime_rfc2388_content_disposition("form-data; name=\"field1\"", &t, &n, &v));
71   check_string(t, "form-data");
72   check_string(n, "name");
73   check_string(v, "field1");
74
75   insist(!mime_rfc2388_content_disposition("inline", &t, &n, &v));
76   check_string(t, "inline");
77   insist(n == 0);
78   insist(v == 0);
79
80   /* Current versions of the code only understand a single arg to these
81    * headers.  This is a bug at the level they work at but suffices for
82    * DisOrder's current purposes. */
83
84   insist(!mime_rfc2388_content_disposition(
85               "attachment; filename=genome.jpeg;\n"
86               "modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\"",
87          &t, &n, &v));
88   check_string(t, "attachment");
89   check_string(n, "filename");
90   check_string(v, "genome.jpeg");
91
92   vector_init(parts);
93   insist(mime_multipart("--outer\r\n"
94                         "Content-Type: text/plain\r\n"
95                         "Content-Disposition: inline\r\n"
96                         "Content-Description: text-part-1\r\n"
97                         "\r\n"
98                         "Some text goes here\r\n"
99                         "\r\n"
100                         "--outer\r\n"
101                         "Content-Type: multipart/mixed; boundary=inner\r\n"
102                         "Content-Disposition: attachment\r\n"
103                         "Content-Description: multipart-2\r\n"
104                         "\r\n"
105                         "--inner\r\n"
106                         "Content-Type: text/plain\r\n"
107                         "Content-Disposition: inline\r\n"
108                         "Content-Description: text-part-2\r\n"
109                         "\r\n"
110                         "Some more text here.\r\n"
111                         "\r\n"
112                         "--inner\r\n"
113                         "Content-Type: image/jpeg\r\n"
114                         "Content-Disposition: attachment\r\n"
115                         "Content-Description: jpeg-1\r\n"
116                         "\r\n"
117                         "<jpeg data>\r\n"
118                         "--inner--\r\n"
119                         "--outer--\r\n",
120                         test_multipart_callback,
121                         "outer",
122                         parts) == 0);
123   check_integer(parts->nvec, 2);
124   check_string(parts->vec[0],
125                "Content-Type: text/plain\r\n"
126                "Content-Disposition: inline\r\n"
127                "Content-Description: text-part-1\r\n"
128                "\r\n"
129                "Some text goes here\r\n");
130   check_string(parts->vec[1],
131                "Content-Type: multipart/mixed; boundary=inner\r\n"
132                "Content-Disposition: attachment\r\n"
133                "Content-Description: multipart-2\r\n"
134                "\r\n"
135                "--inner\r\n"
136                "Content-Type: text/plain\r\n"
137                "Content-Disposition: inline\r\n"
138                "Content-Description: text-part-2\r\n"
139                "\r\n"
140                "Some more text here.\r\n"
141                "\r\n"
142                "--inner\r\n"
143                "Content-Type: image/jpeg\r\n"
144                "Content-Disposition: attachment\r\n"
145                "Content-Description: jpeg-1\r\n"
146                "\r\n"
147                "<jpeg data>\r\n"
148                "--inner--");
149   /* No trailing CRLF is _correct_ - see RFC2046 5.1.1 note regarding CRLF
150    * preceding the boundary delimiter line.  An implication of this is that we
151    * must cope with partial lines at the end of the input when recursively
152    * decomposing a multipart message. */
153   vector_init(parts);
154   insist(mime_multipart("--inner\r\n"
155                         "Content-Type: text/plain\r\n"
156                         "Content-Disposition: inline\r\n"
157                         "Content-Description: text-part-2\r\n"
158                         "\r\n"
159                         "Some more text here.\r\n"
160                         "\r\n"
161                         "--inner\r\n"
162                         "Content-Type: image/jpeg\r\n"
163                         "Content-Disposition: attachment\r\n"
164                         "Content-Description: jpeg-1\r\n"
165                         "\r\n"
166                         "<jpeg data>\r\n"
167                         "--inner--",
168                         test_multipart_callback,
169                         "inner",
170                         parts) == 0);
171   check_integer(parts->nvec, 2);
172   check_string(parts->vec[0],
173                "Content-Type: text/plain\r\n"
174                "Content-Disposition: inline\r\n"
175                "Content-Description: text-part-2\r\n"
176                "\r\n"
177                "Some more text here.\r\n");
178   check_string(parts->vec[1],
179                "Content-Type: image/jpeg\r\n"
180                "Content-Disposition: attachment\r\n"
181                "Content-Description: jpeg-1\r\n"
182                "\r\n"
183                "<jpeg data>");
184  
185   /* XXX mime_parse */
186
187   check_string(mime_qp(""), "");
188   check_string(mime_qp("foobar"), "foobar");
189   check_string(mime_qp("foo=20bar"), "foo bar");
190   check_string(mime_qp("x \r\ny"), "x\r\ny");
191   check_string(mime_qp("x=\r\ny"), "xy");
192   check_string(mime_qp("x= \r\ny"), "xy");
193   check_string(mime_qp("x =\r\ny"), "x y");
194   check_string(mime_qp("x = \r\ny"), "x y");
195
196   check_string(mime_to_qp(""), "");
197   check_string(mime_to_qp("foobar\n"), "foobar\n");
198   check_string(mime_to_qp("foobar \n"), "foobar=20\n");
199   check_string(mime_to_qp("foobar\t\n"), "foobar=09\n"); 
200   check_string(mime_to_qp("foobar \t \n"), "foobar=20=09=20\n");
201   check_string(mime_to_qp(" foo=bar"), " foo=3Dbar\n");
202   check_string(mime_to_qp("copyright \xC2\xA9"), "copyright =C2=A9\n");
203   check_string(mime_to_qp("foo\nbar\nbaz\n"), "foo\nbar\nbaz\n");
204   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");
205  
206   /* from RFC2045 */
207   check_string(mime_qp("Now's the time =\r\n"
208 "for all folk to come=\r\n"
209 " to the aid of their country."),
210                "Now's the time for all folk to come to the aid of their country.");
211
212 #define check_base64(encoded, decoded) do {                     \
213     check_string(mime_base64(encoded, 0), decoded);             \
214     check_string(mime_to_base64((const uint8_t *)decoded,       \
215                                          (sizeof decoded) - 1), \
216                  encoded);                                      \
217   } while(0)
218     
219   
220   check_base64("",  "");
221   check_base64("BBBB", "\x04\x10\x41");
222   check_base64("////", "\xFF\xFF\xFF");
223   check_base64("//BB", "\xFF\xF0\x41");
224   check_base64("BBBB//BB////",
225              "\x04\x10\x41" "\xFF\xF0\x41" "\xFF\xFF\xFF");
226   check_base64("BBBBBA==",
227                "\x04\x10\x41" "\x04");
228   check_base64("BBBBBBA=",
229                "\x04\x10\x41" "\x04\x10");
230
231   /* Check that decoding handles various kinds of rubbish OK */
232   check_string(mime_base64("B B B B  / / B B / / / /", 0),
233              "\x04\x10\x41" "\xFF\xF0\x41" "\xFF\xFF\xFF");
234   check_string(mime_base64("B\r\nBBB.// B-B//~//", 0),
235                "\x04\x10\x41" "\xFF\xF0\x41" "\xFF\xFF\xFF");
236   check_string(mime_base64("BBBB BB==", 0),
237                "\x04\x10\x41" "\x04");
238   check_string(mime_base64("BBBB BB = =", 0),
239                "\x04\x10\x41" "\x04");
240   check_string(mime_base64("BBBB BBB=", 0),
241                "\x04\x10\x41" "\x04\x10");
242   check_string(mime_base64("BBBB BBB = ", 0),
243                "\x04\x10\x41" "\x04\x10");
244   check_string(mime_base64("BBBB=", 0),
245                "\x04\x10\x41");
246   check_string(mime_base64("BBBBBB==", 0),
247                "\x04\x10\x41" "\x04");
248   check_string(mime_base64("BBBBBBB=", 0),
249                "\x04\x10\x41" "\x04\x10");
250   /* Not actually valid base64 */
251   check_string(mime_base64("BBBBx=", 0),
252                "\x04\x10\x41");
253 }
254
255 /*
256 Local Variables:
257 c-basic-offset:2
258 comment-column:40
259 fill-column:79
260 indent-tabs-mode:nil
261 End:
262 */