1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* GMime
3 * Copyright (C) 2000-2014 Jeffrey Stedfast
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,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <gmime/gmime.h>
26
27 #include <stdio.h>
28 #include <stdlib.h>
29
30 #include "testsuite.h"
31
32 extern int verbose;
33
34 #define d(x)
35 #define v(x) if (verbose > 3) x
36
37 typedef struct {
38 const char *name;
39 const char *value;
40 } Header;
41
42 static Header initial[] = {
43 { "Received", "first received header" },
44 { "Received", "second received header" },
45 { "Received", "third received header" },
46 { "Date", "Sat, 31 May 2008 08:56:43 EST" },
47 { "From", "someone@somewhere.com" },
48 { "Sender", "someoneelse@somewhere.com" },
49 { "To", "coworker@somewhere.com" },
50 { "Subject", "hey, check this out" },
51 { "Message-Id", "<136734928.123728@localhost.com>" },
52 };
53
54 static GMimeHeaderList *
header_list_new(void)55 header_list_new (void)
56 {
57 GMimeHeaderList *list;
58 guint i;
59
60 list = g_mime_header_list_new ();
61 for (i = 0; i < G_N_ELEMENTS (initial); i++)
62 g_mime_header_list_append (list, initial[i].name, initial[i].value);
63
64 return list;
65 }
66
67 static void
test_iter_forward_back(void)68 test_iter_forward_back (void)
69 {
70 const char *name, *value;
71 GMimeHeaderList *list;
72 GMimeHeaderIter iter;
73 guint i;
74
75 list = header_list_new ();
76
77 /* make sure initial iter is valid */
78 testsuite_check ("initial iter");
79 try {
80 if (!g_mime_header_list_get_iter (list, &iter))
81 throw (exception_new ("get_iter() failed"));
82
83 if (!g_mime_header_iter_is_valid (&iter))
84 throw (exception_new ("invalid iter"));
85
86 name = g_mime_header_iter_get_name (&iter);
87 value = g_mime_header_iter_get_value (&iter);
88
89 if (strcmp (initial[0].name, name) != 0 || strcmp (initial[0].value, value) != 0)
90 throw (exception_new ("resulted in unexpected header"));
91 testsuite_check_passed ();
92 } catch (ex) {
93 testsuite_check_failed ("initial iter: %s", ex->message);
94 } finally;
95
96 /* make sure iter->next works as expected */
97 for (i = 1; i < G_N_ELEMENTS (initial); i++) {
98 testsuite_check ("next iter[%u]", i);
99 try {
100 if (!g_mime_header_iter_next (&iter))
101 throw (exception_new ("failed to advance"));
102
103 if (!g_mime_header_iter_is_valid (&iter))
104 throw (exception_new ("advanced but is invalid"));
105
106 name = g_mime_header_iter_get_name (&iter);
107 value = g_mime_header_iter_get_value (&iter);
108
109 if (strcmp (initial[i].name, name) != 0 ||
110 strcmp (initial[i].value, value) != 0)
111 throw (exception_new ("resulted in unexpected header"));
112 testsuite_check_passed ();
113 } catch (ex) {
114 testsuite_check_failed ("next iter[%u]: %s", i, ex->message);
115 } finally;
116 }
117
118 /* make sure trying to advance past the last header fails */
119 testsuite_check ("iter->next past end of headers");
120 try {
121 if (g_mime_header_iter_next (&iter))
122 throw (exception_new ("should not have worked"));
123 testsuite_check_passed ();
124 } catch (ex) {
125 testsuite_check_failed ("iter->next past end of headers: %s", ex->message);
126 } finally;
127
128 /* make sure iter->prev works as expected */
129 i--;
130 while (i > 0) {
131 testsuite_check ("prev iter[%u]", i);
132 try {
133 if (!g_mime_header_iter_prev (&iter))
134 throw (exception_new ("failed to advance"));
135
136 if (!g_mime_header_iter_is_valid (&iter))
137 throw (exception_new ("advanced but is invalid"));
138
139 name = g_mime_header_iter_get_name (&iter);
140 value = g_mime_header_iter_get_value (&iter);
141
142 if (strcmp (initial[i - 1].name, name) != 0 ||
143 strcmp (initial[i - 1].value, value) != 0)
144 throw (exception_new ("resulted in unexpected header"));
145 testsuite_check_passed ();
146 } catch (ex) {
147 testsuite_check_failed ("prev iter[%u]: %s", i, ex->message);
148 } finally;
149
150 i--;
151 }
152
153 /* make sure trying to advance prev of the first header fails */
154 testsuite_check ("iter->prev past beginning of headers");
155 try {
156 if (g_mime_header_iter_prev (&iter))
157 throw (exception_new ("should not have worked"));
158 testsuite_check_passed ();
159 } catch (ex) {
160 testsuite_check_failed ("iter->prev past beginning of headers: %s", ex->message);
161 } finally;
162
163 g_mime_header_list_destroy (list);
164 }
165
166 static void
test_iter_remove_all(void)167 test_iter_remove_all (void)
168 {
169 GMimeHeaderList *list;
170 GMimeHeaderIter iter;
171 guint i = 0;
172
173 list = header_list_new ();
174
175 g_mime_header_list_get_iter (list, &iter);
176
177 testsuite_check ("removing all headers");
178 try {
179 while (g_mime_header_iter_remove (&iter))
180 i++;
181
182 if (i != G_N_ELEMENTS (initial))
183 throw (exception_new ("only removed %u of %u", i, G_N_ELEMENTS (initial)));
184
185 if (g_mime_header_iter_is_valid (&iter))
186 throw (exception_new ("expected invalid iter"));
187
188 testsuite_check_passed ();
189 } catch (ex) {
190 testsuite_check_failed ("removing all headers: %s", ex->message);
191 } finally;
192
193 g_mime_header_list_get_iter (list, &iter);
194
195 testsuite_check ("empty list iter");
196 try {
197 if (g_mime_header_iter_is_valid (&iter))
198 throw (exception_new ("expected invalid iter"));
199
200 testsuite_check_passed ();
201 } catch (ex) {
202 testsuite_check_failed ("empty list iter: %s", ex->message);
203 } finally;
204
205 g_mime_header_list_destroy (list);
206 }
207
208 static void
test_iter_remove(void)209 test_iter_remove (void)
210 {
211 GMimeHeaderIter iter, iter1, iter2, iter3;
212 const char *name, *value;
213 GMimeHeaderList *list;
214 guint i;
215
216 list = header_list_new ();
217
218 g_mime_header_list_get_iter (list, &iter1);
219
220 testsuite_check ("iter copying");
221 try {
222 /* make iter2 point to the second header */
223 g_mime_header_iter_copy_to (&iter1, &iter2);
224 if (!g_mime_header_iter_next (&iter2))
225 throw (exception_new ("iter2->next failed"));
226
227 name = g_mime_header_iter_get_name (&iter2);
228 value = g_mime_header_iter_get_value (&iter2);
229
230 if (strcmp (initial[1].name, name) != 0 ||
231 strcmp (initial[1].value, value) != 0)
232 throw (exception_new ("iter2 resulted in unexpected header"));
233
234 /* make iter3 point to the third header */
235 g_mime_header_iter_copy_to (&iter2, &iter3);
236 if (!g_mime_header_iter_next (&iter3))
237 throw (exception_new ("iter3->next failed"));
238
239 name = g_mime_header_iter_get_name (&iter3);
240 value = g_mime_header_iter_get_value (&iter3);
241
242 if (strcmp (initial[2].name, name) != 0 ||
243 strcmp (initial[2].value, value) != 0)
244 throw (exception_new ("iter3 resulted in unexpected header"));
245
246 testsuite_check_passed ();
247 } catch (ex) {
248 testsuite_check_failed ("iter copying: %s", ex->message);
249 } finally;
250
251 testsuite_check ("remove first header");
252 try {
253 /* remove the first header */
254 g_mime_header_iter_copy_to (&iter1, &iter);
255 if (!g_mime_header_iter_remove (&iter))
256 throw (exception_new ("iter::remove() failed"));
257
258 /* make sure iter now points to the 2nd header */
259 name = g_mime_header_iter_get_name (&iter);
260 value = g_mime_header_iter_get_value (&iter);
261
262 if (strcmp (initial[1].name, name) != 0 ||
263 strcmp (initial[1].value, value) != 0)
264 throw (exception_new ("iter doesn't point to 2nd header as expected"));
265
266 /* make sure that the other iters have been invalidated */
267 if (g_mime_header_iter_is_valid (&iter1))
268 throw (exception_new ("iter::remove() iter1::isvalid() incorrect"));
269 if (g_mime_header_iter_is_valid (&iter2))
270 throw (exception_new ("iter::remove() iter2::isvalid() incorrect"));
271 if (g_mime_header_iter_is_valid (&iter3))
272 throw (exception_new ("iter::remove() iter3::isvalid() incorrect"));
273
274 testsuite_check_passed ();
275 } catch (ex) {
276 testsuite_check_failed ("remove first header: %s", ex->message);
277 } finally;
278
279 testsuite_check ("remove last header");
280 try {
281 /* remove the last header */
282 g_mime_header_iter_last (&iter);
283
284 if (!g_mime_header_iter_remove (&iter))
285 throw (exception_new ("iter::remove() failed"));
286
287 /* iter should be invalid now because it couldn't advance to a header beyond the last */
288 if (g_mime_header_iter_is_valid (&iter))
289 throw (exception_new ("iter::remove() iter is valid when it shouldn't be"));
290
291 testsuite_check_passed ();
292 } catch (ex) {
293 testsuite_check_failed ("remove last header: %s", ex->message);
294 } finally;
295
296 testsuite_check ("remove middle header");
297 try {
298 g_mime_header_list_get_iter (list, &iter);
299
300 /* advance to a header in the middle somewhere... */
301 g_mime_header_iter_next (&iter);
302 g_mime_header_iter_next (&iter);
303
304 /* we should now be pointing to the 3rd header (4th from the initial headers) */
305 name = g_mime_header_iter_get_name (&iter);
306 value = g_mime_header_iter_get_value (&iter);
307
308 if (strcmp (initial[3].name, name) != 0 ||
309 strcmp (initial[3].value, value) != 0)
310 throw (exception_new ("iter doesn't point to 3rd header as expected"));
311
312 /* remove it */
313 if (!g_mime_header_iter_remove (&iter))
314 throw (exception_new ("iter::remove() failed"));
315
316 /* make sure the iter is still valid */
317 if (!g_mime_header_iter_is_valid (&iter))
318 throw (exception_new ("iter::remove() iter isn't valid when it should be"));
319
320 /* make sure iter now points to the 4th header */
321 name = g_mime_header_iter_get_name (&iter);
322 value = g_mime_header_iter_get_value (&iter);
323
324 if (strcmp (initial[4].name, name) != 0 ||
325 strcmp (initial[4].value, value) != 0)
326 throw (exception_new ("iter doesn't point to 4th header as expected"));
327
328 testsuite_check_passed ();
329 } catch (ex) {
330 testsuite_check_failed ("remove first header: %s", ex->message);
331 } finally;
332
333 testsuite_check ("resulting lists match");
334 try {
335 g_mime_header_list_get_iter (list, &iter);
336 i = 1;
337
338 do {
339 name = g_mime_header_iter_get_name (&iter);
340 value = g_mime_header_iter_get_value (&iter);
341
342 if (i == 3)
343 i++;
344
345 if (strcmp (initial[i].name, name) != 0 ||
346 strcmp (initial[i].value, value) != 0)
347 throw (exception_new ("iter vs array mismatch @ index %u", i));
348
349 i++;
350 } while (g_mime_header_iter_next (&iter));
351
352 if (++i != G_N_ELEMENTS (initial))
353 throw (exception_new ("iter didn't have as many headers as expected"));
354
355 testsuite_check_passed ();
356 } catch (ex) {
357 testsuite_check_failed ("resulting lists match: %s", ex->message);
358 } finally;
359
360 g_mime_header_list_destroy (list);
361 }
362
363 static void
test_header_sync(void)364 test_header_sync (void)
365 {
366 InternetAddressList *list;
367 InternetAddress *addr, *ia;
368 GMimeMessage *message;
369 GMimeObject *object;
370 const char *value;
371 GMimePart *part;
372
373 part = g_mime_part_new_with_type ("application", "octet-stream");
374 object = (GMimeObject *) part;
375
376 testsuite_check ("content-type synchronization");
377 try {
378 /* first, check that the current Content-Type header
379 * value is "application/octet-stream" as expected */
380 if (!(value = g_mime_object_get_header (object, "Content-Type")))
381 throw (exception_new ("initial content-type header was unexpectedly null"));
382
383 if (strcmp ("application/octet-stream", value) != 0)
384 throw (exception_new ("initial content-type header had unexpected value"));
385
386 /* now change the content-type's media type... */
387 g_mime_content_type_set_media_type (object->content_type, "text");
388 if (!(value = g_mime_object_get_header (object, "Content-Type")))
389 throw (exception_new ("content-type header was unexpectedly null after changing type"));
390 if (strcmp ("text/octet-stream", value) != 0)
391 throw (exception_new ("content-type header had unexpected value after changing type"));
392
393 /* now change the content-type's media subtype... */
394 g_mime_content_type_set_media_subtype (object->content_type, "plain");
395 if (!(value = g_mime_object_get_header (object, "Content-Type")))
396 throw (exception_new ("content-type header was unexpectedly null after changing subtype"));
397 if (strcmp ("text/plain", value) != 0)
398 throw (exception_new ("content-type header had unexpected value after changing subtype"));
399
400 /* now change the content-type's parameters by setting a param */
401 g_mime_content_type_set_parameter (object->content_type, "format", "flowed");
402 if (!(value = g_mime_object_get_header (object, "Content-Type")))
403 throw (exception_new ("content-type header was unexpectedly null after setting a param"));
404 if (strcmp ("text/plain; format=flowed", value) != 0)
405 throw (exception_new ("content-type header had unexpected value after setting a param"));
406
407 /* now change the content-type's parameters by setting a param list */
408 g_mime_content_type_set_params (object->content_type, NULL);
409 if (!(value = g_mime_object_get_header (object, "Content-Type")))
410 throw (exception_new ("content-type header was unexpectedly null after setting params"));
411 if (strcmp ("text/plain", value) != 0)
412 throw (exception_new ("content-type header had unexpected value after setting params"));
413
414 testsuite_check_passed ();
415 } catch (ex) {
416 testsuite_check_failed ("content-type header not synchronized: %s", ex->message);
417 } finally;
418
419 testsuite_check ("content-disposition synchronization");
420 try {
421 g_mime_object_set_disposition (object, "attachment");
422
423 /* first, check that the current Content-Disposition header
424 * value is "application/octet-stream" as expected */
425 if (!(value = g_mime_object_get_header (object, "Content-Disposition")))
426 throw (exception_new ("initial content-disposition header was unexpectedly null"));
427
428 if (strcmp ("attachment", value) != 0)
429 throw (exception_new ("initial content-disposition header had unexpected value"));
430
431 /* now change the content-disposition's disposition */
432 g_mime_content_disposition_set_disposition (object->disposition, "inline");
433 if (!(value = g_mime_object_get_header (object, "Content-Disposition")))
434 throw (exception_new ("content-disposition header was unexpectedly null after changing type"));
435 if (strcmp ("inline", value) != 0)
436 throw (exception_new ("content-disposition header had unexpected value after changing type"));
437
438 /* now change the content-disposition's parameters by setting a param */
439 g_mime_content_disposition_set_parameter (object->disposition, "filename", "hello.txt");
440 if (!(value = g_mime_object_get_header (object, "Content-Disposition")))
441 throw (exception_new ("content-disposition header was unexpectedly null after setting a param"));
442 if (strcmp ("inline; filename=hello.txt", value) != 0)
443 throw (exception_new ("content-disposition header had unexpected value after setting a param"));
444
445 /* now change the content-disposition's parameters by setting a param list */
446 g_mime_content_disposition_set_params (object->disposition, NULL);
447 if (!(value = g_mime_object_get_header (object, "Content-Disposition")))
448 throw (exception_new ("content-disposition header was unexpectedly null after setting params"));
449 if (strcmp ("inline", value) != 0)
450 throw (exception_new ("content-disposition header had unexpected value after setting params"));
451
452 testsuite_check_passed ();
453 } catch (ex) {
454 testsuite_check_failed ("content-disposition header not synchronized: %s", ex->message);
455 } finally;
456
457 g_object_unref (part);
458
459 message = g_mime_message_new (TRUE);
460 list = g_mime_message_get_recipients (message, GMIME_RECIPIENT_TYPE_TO);
461 object = (GMimeObject *) message;
462
463 testsuite_check ("address header synchronization");
464 try {
465 /* first, check that the To recipients are empty */
466 if (list == NULL || internet_address_list_length (list) != 0)
467 throw (exception_new ("unexpected initial internet address list"));
468
469 /* now check that the initial header value is null */
470 if ((value = g_mime_object_get_header (object, "To")) != NULL)
471 throw (exception_new ("unexpected initial address list header"));
472
473 /* now try adding an address */
474 addr = internet_address_mailbox_new ("Tester", "tester@localhost.com");
475 internet_address_list_add (list, addr);
476
477 if (!(value = g_mime_object_get_header (object, "To")))
478 throw (exception_new ("address list header unexpectedly null after adding recipient"));
479
480 if (strcmp ("Tester <tester@localhost.com>", value) != 0)
481 throw (exception_new ("unexpected address list header after adding recipient"));
482
483 /* now let's try changing the address name to make sure signals properly chain up */
484 internet_address_set_name (addr, "Eva Lucy-Ann Tester");
485 if (!(value = g_mime_object_get_header (object, "To")))
486 throw (exception_new ("address list header unexpectedly null after changing name"));
487
488 if (strcmp ("Eva Lucy-Ann Tester <tester@localhost.com>", value) != 0)
489 throw (exception_new ("unexpected address list header after changing name"));
490
491 /* now let's try changing the address mailbox... */
492 internet_address_mailbox_set_addr ((InternetAddressMailbox *) addr,
493 "evalucyann@ximian.com");
494 if (!(value = g_mime_object_get_header (object, "To")))
495 throw (exception_new ("address list header unexpectedly null after changing mailbox"));
496
497 if (strcmp ("Eva Lucy-Ann Tester <evalucyann@ximian.com>", value) != 0)
498 throw (exception_new ("unexpected address list header after changing mailbox"));
499
500 /* now let's try inserting a group address */
501 g_object_unref (addr);
502 addr = internet_address_group_new ("Group");
503 internet_address_list_insert (list, 0, addr);
504
505 if (!(value = g_mime_object_get_header (object, "To")))
506 throw (exception_new ("address list header unexpectedly null after inserting group"));
507
508 if (strcmp ("Group: ;, Eva Lucy-Ann Tester <evalucyann@ximian.com>", value) != 0)
509 throw (exception_new ("unexpected address list header after inserting group"));
510
511 /* now let's try removing the original recipient */
512 internet_address_list_remove_at (list, 1);
513 if (!(value = g_mime_object_get_header (object, "To")))
514 throw (exception_new ("address list header unexpectedly null after removing recipient"));
515
516 if (strcmp ("Group: ;", value) != 0)
517 throw (exception_new ("unexpected address list header after removing recipient"));
518
519 /* now let's try adding an address to the group... */
520 ia = internet_address_mailbox_new ("Tester", "tester@hotmail.com");
521 internet_address_list_add (((InternetAddressGroup *) addr)->members, ia);
522 if (!(value = g_mime_object_get_header (object, "To")))
523 throw (exception_new ("address list header unexpectedly null after adding addr to group"));
524
525 if (strcmp ("Group: Tester <tester@hotmail.com>;", value) != 0)
526 throw (exception_new ("unexpected address list header after adding addr to group"));
527
528 testsuite_check_passed ();
529 } catch (ex) {
530 testsuite_check_failed ("address header not synchronized: %s", ex->message);
531 } finally;
532
533 g_object_unref (message);
534 }
535
main(int argc,char ** argv)536 int main (int argc, char **argv)
537 {
538 g_mime_init (0);
539
540 testsuite_init (argc, argv);
541
542 testsuite_start ("iterating forward and backward");
543 test_iter_forward_back ();
544 testsuite_end ();
545
546 testsuite_start ("removing all headers");
547 test_iter_remove_all ();
548 testsuite_end ();
549
550 testsuite_start ("removing individual headers");
551 test_iter_remove ();
552 testsuite_end ();
553
554 testsuite_start ("header synchronization");
555 test_header_sync ();
556 testsuite_end ();
557
558 g_mime_shutdown ();
559
560 return testsuite_exit ();
561 }
562