1
#include <stdlib.h>
2
#include <stdio.h>
3
#include <string.h>
4
#include <sys/types.h>
5
#include <sys/stat.h>
6
#include <unistd.h>
7
#include <fcntl.h>
8
#include <errno.h>
9
#include <glib/gstdio.h>
10
11
#include "bodystruct.h"
12
13
#define PRINT_NULL(o)	(o?o:"(null)")
14
15
#ifdef DEBUG
16
#define debug_printf	printf
17
#else
18
#define debug_printf(o, ...)	 
19
#endif
20
21
static void 
22
set_error (GError **err, unsigned char **in)
23
{
24
	if (in) {
25
		g_set_error (err, 0, 1,
26
			"Incorrect response from IMAP server in BODYSTRUCTURE (%s)", *in);
27
	} else {
28
		g_set_error (err, 0, 1,
29
			"Incorrect response from IMAP server in BODYSTRUCTURE");
30
	}
31
}
32
33
34
envelope_t *
35
envelope_new (void)
36
{
37
	return g_slice_new0 (struct _envelope);
38
}
39
40
void 
41
envelope_free (envelope_t *node)
42
{
43
	g_free (node->date);
44
	g_free (node->subject);
45
	g_free (node->from);
46
	g_free (node->sender);
47
	g_free (node->reply_to);
48
	g_free (node->to);
49
	g_free (node->cc);
50
	g_free (node->bcc);
51
	g_free (node->in_reply_to);
52
	g_free (node->message_id);
53
54
	g_slice_free (struct _envelope, node);
55
}
56
57
static struct _mimeparam*
58
mimeparam_new (void)
59
{
60
	return g_slice_new0 (struct _mimeparam);
61
}
62
63
static struct _bodystruct*
64
bodystruct_new (void)
65
{
66
	return g_slice_new0 (struct _bodystruct);
67
}
68
69
static void 
70
mimeparam_destroy (struct _mimeparam *param)
71
{
72
	struct _mimeparam *next;
73
	
74
	while (param) {
75
		next = param->next;
76
		g_free (param->name);
77
		g_free (param->value);
78
		g_slice_free (struct _mimeparam, param);
79
		param = next;
80
	}
81
}
82
83
static void
84
unescape_qstring (char *qstring)
85
{
86
	char *s, *d;
87
	
88
	d = s = qstring;
89
	while (*s != '\0') {
90
		if (*s != '\\')
91
			*d++ = *s++;
92
		else
93
			s++;
94
	}
95
	
96
	*d = '\0';
97
}
98
99
static char *
100
decode_qstring (unsigned char **in, unsigned char *inend, GError **err)
101
{
102
	unsigned char *inptr, *start;
103
	char *qstring = NULL;
104
	
105
	inptr = *in;
106
	
107
	while (inptr < inend && *inptr == ' ')
108
		inptr++;
109
	
110
	if (inptr == inend) {
111
		*in = inptr;
112
		set_error (err, in);
113
		return NULL;
114
	}
115
116
	if (strncmp ((const char *) inptr, "NIL", 3) != 0) {
117
		gboolean quoted = FALSE;
118
119
		if (*inptr == '"') {
120
			inptr++;
121
			quoted = TRUE;
122
		}
123
		start = inptr;
124
		while (inptr < inend) {
125
			if (quoted) {
126
				if (*inptr == '"' && inptr[-1] != '\\')
127
					break;
128
			} else {
129
				if (*inptr == ')' && inptr[-1] != '\\')
130
					break;
131
			}
132
			inptr++;
133
		}
134
		
135
		qstring = g_strndup ((const char *) start, inptr - start);
136
		unescape_qstring (qstring);
137
138
		if (quoted && *inptr != '"') {
139
			g_free (qstring);
140
			*in = inptr;
141
			set_error (err, in);
142
			return NULL;
143
		}
144
		if (quoted)
145
			inptr++;
146
	} else
147
		inptr += 3;
148
149
	*in = inptr;
150
151
	return qstring;
152
}
153
154
155
156
static char *
157
decode_estring (unsigned char **in, unsigned char *inend, GError **err)
158
{
159
	unsigned char *inptr, *start;
160
	char *qstring = NULL;
161
162
	inptr = *in;
163
164
	while (inptr < inend && *inptr == ' ')
165
		inptr++;
166
167
	if (inptr == inend) {
168
		*in = inptr;
169
		set_error (err, in);
170
		return NULL;
171
	}
172
173
	if (strncmp ((const char *) inptr, "NIL", 3) != 0) {
174
		if (*inptr == '(') {
175
			gboolean first = TRUE;
176
			GString *str = NULL;
177
178
			if (*inptr != '(') {
179
				*in = inptr;
180
				set_error (err, in);
181
				return NULL;
182
			}
183
184
			str = g_string_new ("");
185
186
			inptr++; /* My '(' */
187
			while (*inptr == '(') {
188
				char *separator = NULL;
189
				char *name = NULL;
190
				char *user = NULL;
191
				char *server = NULL;
192
193
				inptr++; /* My '(' */
194
195
				if (!first)
196
					g_string_append (str, ", ");
197
				first = FALSE;
198
199
				name = decode_qstring (&inptr, inend, err);
200
				separator = decode_qstring (&inptr, inend, err);
201
				user = decode_qstring (&inptr, inend, err);
202
				server = decode_qstring (&inptr, inend, err);
203
204
				if (name) {
205
					g_string_append (str, name);
206
					g_string_append (str, " <");
207
				}
208
209
				if (user && server) {
210
					g_string_append (str, user);
211
					g_string_append_c (str, '@');
212
				}
213
214
				if (server)
215
					g_string_append (str, server);
216
217
				if (name) 
218
					g_string_append_c (str, '>');
219
220
				if (separator)
221
					g_free (separator);
222
				if (name)
223
					g_free (name);
224
				if (user)
225
					g_free (user);
226
				if (server)
227
					g_free (server);
228
229
230
				if (*inptr != ')') {
231
					*in = inptr;
232
					set_error (err, in);
233
					g_string_free (str, TRUE);
234
					return NULL;
235
				}
236
237
				inptr++; /* My ')' */
238
239
				/* Read spaces */
240
				while (inptr < inend && *inptr == ' ')
241
					inptr++;
242
243
			}
244
245
			/* TODO: check for ')' */
246
			if (*inptr != ')')
247
				g_warning ("strange");
248
			inptr++; /* My ')' */
249
250
			qstring = str->str;
251
			g_string_free (str, FALSE);
252
		} else {
253
			if (strncmp ((const char *) inptr, "NIL", 3) != 0) {
254
				if (*inptr != '"') {
255
					*in = inptr;
256
					set_error (err, in);
257
					return NULL;
258
				}
259
				inptr++;
260
				start = inptr;
261
				while (inptr < inend) {
262
					if (*inptr == '"' && inptr[-1] != '\\')
263
						break;
264
					inptr++;
265
				}
266
				
267
				qstring = g_strndup ((const char *) start, inptr - start);
268
				unescape_qstring (qstring);
269
270
				if (*inptr != '"') {
271
					*in = inptr;
272
					g_free (qstring);
273
					set_error (err, in);
274
					return NULL;
275
				}
276
				inptr++;
277
			} else
278
				inptr += 3;
279
		}
280
281
	} else
282
		inptr += 3;
283
284
	*in = inptr;
285
286
	return qstring;
287
}
288
289
static unsigned int
290
decode_num (unsigned char **in, unsigned char *inend, GError **err)
291
{
292
	unsigned char *inptr;
293
	unsigned int ret = 0;
294
295
	inptr = *in;
296
297
	while (inptr < inend && *inptr == ' ')
298
		inptr++;
299
300
	if (inptr == inend)
301
		return 0;
302
303
	if (strncmp ((const char *) inptr, "NIL", 3) != 0)
304
		ret = strtoul ((const char *) inptr, (char **) &inptr, 10);
305
	else
306
		inptr += 3;
307
308
	*in = inptr;
309
310
	return ret;
311
}
312
313
#if DEBUG
314
static void 
315
print_params (struct _mimeparam *param)
316
{
317
	struct _mimeparam *next;
318
	
319
	while (param) {
320
		next = param->next;
321
		debug_printf ("%s = ", PRINT_NULL (param->name));
322
		debug_printf ("%s\n", PRINT_NULL (param->value));
323
		param = next;
324
	}
325
}
326
#else
327
#define print_params(o)		 
328
#endif
329
330
static struct _mimeparam *
331
decode_param (unsigned char **in, unsigned char *inend, GError **err)
332
{
333
	struct _mimeparam *param;
334
	char *name, *val;
335
	unsigned char *inptr;
336
337
	inptr = *in;
338
	if (!(name = decode_qstring (&inptr, inend, err)))
339
		return NULL; /* This is a NIL */
340
341
	val = decode_qstring (&inptr, inend, err);
342
343
	if (!val) {
344
		param = NULL;
345
		*in = inptr;
346
		g_free (name);
347
	} else {
348
		param = mimeparam_new ();
349
		param->name = name;
350
		param->value = val;
351
	}
352
353
	*in = inptr;
354
355
	return param;
356
}
357
358
static struct _mimeparam *
359
decode_params (unsigned char **in, unsigned char *inend, GError **err)
360
{
361
	/* "TEXT" "PLAIN" -> ("CHARSET" "UTF-8") <- */
362
	/* "TEXT" "PLAIN" -> NIL <- */
363
364
	struct _mimeparam *params, *tail, *n;
365
	unsigned char *inptr;
366
367
	inptr = *in;
368
	params = NULL;
369
	tail = (struct _mimeparam *) &params;
370
371
	while (inptr < inend && *inptr == ' ')
372
		inptr++;
373
374
	if (inptr == inend) {
375
		*in = inptr;
376
		set_error (err, in);
377
		return NULL;
378
	}
379
380
	if (strncmp ((const char *) inptr, "NIL", 3) != 0) {
381
382
		if (*inptr != '(') {
383
			*in = inptr;
384
			set_error (err, in);
385
			return NULL;
386
		}
387
388
		inptr++;
389
390
		while ((n = decode_param (&inptr, inend, err)) != NULL) {
391
			tail->next = n;
392
			tail = n;
393
				
394
			while (inptr < inend && *inptr == ' ')
395
				inptr++;
396
			
397
			if (*inptr == ')')
398
				break;
399
		}
400
401
		if (*inptr != ')') {
402
			*in = inptr;
403
			if (params)
404
				mimeparam_destroy (params);
405
			set_error (err, in);
406
			return NULL;
407
		}
408
409
		inptr++;
410
	} else
411
		inptr += 3;
412
413
	*in = inptr;
414
415
	return params;
416
}
417
418
static void 
419
read_unknown_qstring (unsigned char **in, unsigned char *inend, GError **err)
420
{
421
	unsigned char *inptr;
422
	char *str;
423
424
	inptr = *in;
425
	str = decode_qstring (&inptr, inend, err);
426
	debug_printf ("unknown: %s\n", PRINT_NULL (str));
427
	g_free (str);
428
	*in = inptr;
429
430
	return;
431
}
432
433
434
435
static struct _envelope *
436
decode_envelope (unsigned char **in, unsigned char *inend, GError **err)
437
{
438
	struct _envelope *node;
439
	unsigned char *inptr;
440
	
441
	inptr = *in;
442
443
	while (inptr < inend && *inptr == ' ')
444
		inptr++;
445
446
	if (inptr == inend || *inptr != '(') {
447
		*in = inptr;
448
		set_error (err, in);
449
		return NULL;
450
	}
451
452
	inptr++;
453
454
	node = envelope_new ();
455
456
	node->date = decode_qstring (&inptr, inend, err);
457
	debug_printf ("env date: %s\n", PRINT_NULL (node->date));
458
	node->subject = decode_qstring (&inptr, inend, err);
459
	debug_printf ("env subject: %s\n", PRINT_NULL (node->subject));
460
461
	node->from = decode_estring (&inptr, inend, err);
462
	debug_printf ("env from: %s\n", PRINT_NULL (node->from));
463
464
	node->sender = decode_estring (&inptr, inend, err);
465
	debug_printf ("env sender: %s\n", PRINT_NULL (node->sender));
466
467
	node->reply_to = decode_estring (&inptr, inend, err);
468
	debug_printf ("env reply_to: %s\n", PRINT_NULL (node->reply_to));
469
470
	node->to = decode_estring (&inptr, inend, err);
471
	debug_printf ("env to: %s\n", PRINT_NULL (node->to));
472
473
	node->cc = decode_estring (&inptr, inend, err);
474
	debug_printf ("env cc: %s\n", PRINT_NULL (node->cc));
475
476
	node->bcc = decode_estring (&inptr, inend, err);
477
	debug_printf ("env bcc: %s\n", PRINT_NULL (node->bcc));
478
479
	node->in_reply_to = decode_estring (&inptr, inend, err);
480
	debug_printf ("env in_reply_to: %s\n", PRINT_NULL (node->in_reply_to));
481
482
	node->message_id = decode_qstring (&inptr, inend, err);
483
	debug_printf ("env message_id: %s\n", PRINT_NULL (node->message_id));
484
485
	while (inptr < inend && *inptr == ' ')
486
		inptr++;
487
488
489
	if (*inptr != ')') {
490
		envelope_free (node);
491
		*in = inptr;
492
		set_error (err, in);
493
		return NULL;
494
	}
495
496
497
	inptr++;
498
499
	*in = inptr;
500
501
	return node;
502
}
503
504
505
506
static void 
507
parse_lang (unsigned char **in, unsigned char *inend, struct _bodystruct *part, GError **err)
508
{
509
	unsigned char *inptr = *in;
510
511
	/* a) NIL 
512
	 * b) ("NL-BE") 
513
	 * c) "NL-BE" */
514
515
	while (inptr < inend && *inptr == ' ')
516
		inptr++;
517
518
	if (*inptr == '(') {
519
520
		inptr++; /* My '(' */
521
522
		/* case b */
523
		part->content.lang = decode_qstring (&inptr, inend, err);
524
		debug_printf ("lang: %s\n", PRINT_NULL (part->content.lang));
525
526
		while (inptr < inend && *inptr == ' ')
527
			inptr++;
528
529
		if (*inptr != ')') {
530
			g_free (part->content.lang);
531
			part->content.lang = NULL;
532
			*in = inptr;
533
			set_error (err, in);
534
			return;
535
		}
536
537
		inptr++; /* My ')' */
538
539
	} else {
540
		if (strncmp ((const char *) inptr, "NIL", 3) != 0) {
541
			/* case c */
542
			part->content.lang = decode_qstring (&inptr, inend, err);
543
			debug_printf ("lang: %s\n", PRINT_NULL (part->content.lang));
544
		} else /* case a */
545
			inptr += 3;
546
	}
547
548
	*in = inptr;
549
550
	return;
551
}
552
553
static void 
554
parse_content_disposition (unsigned char **in, unsigned char *inend, disposition_t *disposition, GError **err)
555
{
556
	unsigned char *inptr = *in;
557
558
	/* a) NIL 
559
	 * b) ("INLINE" NIL) 
560
	 * c) ("ATTACHMENT" ("FILENAME", "myfile.ext")) 
561
	 * d) "ALTERNATIVE" ("BOUNDARY", "---")  */
562
563
	while (inptr < inend && *inptr == ' ')
564
		inptr++;
565
566
	if (*inptr == '(') {
567
		inptr++; /* My '(' */
568
569
		/* cases c & b */
570
		disposition->type = decode_qstring (&inptr, inend, err);
571
		debug_printf ("disposition.type: %s\n", PRINT_NULL (disposition->type));
572
		disposition->params = decode_params (&inptr, inend, err);
573
		print_params (disposition->params);
574
575
		while (inptr < inend && *inptr == ' ')
576
			inptr++;
577
578
		if (*inptr != ')') {
579
			g_free (disposition->type);
580
			disposition->type = NULL;
581
			if (disposition->params)
582
				mimeparam_destroy (disposition->params);
583
			*in = inptr;
584
			set_error (err, in);
585
			return;
586
		}
587
588
		inptr++; /* My ')' */
589
	} else {
590
		if (strncmp ((const char *) inptr, "NIL", 3) != 0) {
591
			/* case d */
592
			disposition->type = decode_qstring (&inptr, inend, err);
593
			debug_printf ("disposition.type: %s\n", PRINT_NULL (disposition->type));
594
			disposition->params = decode_params (&inptr, inend, err);
595
			print_params (disposition->params);
596
		} else /* case a */
597
			inptr += 3;
598
	}
599
600
	*in = inptr;
601
602
	return;
603
}
604
605
606
607
static void
608
end_this_piece (unsigned char **in, unsigned char *inend, GError **err)
609
{
610
	unsigned char *inptr = *in;
611
	gint open = 0;
612
	gboolean noerr = FALSE;
613
614
	while (inptr < inend)
615
	{
616
		if (*inptr == '(')
617
			open++;
618
619
		if (*inptr == ')') {
620
			if (open == 0) {
621
				noerr = TRUE;
622
				break;
623
			}
624
			open--;
625
		}
626
		inptr++;
627
	}
628
629
	if (!noerr) {
630
		*in = inptr;
631
		set_error (err, in);
632
	}
633
634
	*in = inptr;
635
636
	return;
637
}
638
639
static struct _bodystruct *
640
bodystruct_part_decode (unsigned char **in, unsigned char *inend, bodystruct_t *parent, gint num, GError **err)
641
{
642
	struct _bodystruct *part, *list, *tail, *n;
643
	unsigned char *inptr;
644
645
	inptr = *in;
646
647
	while (inptr < inend && *inptr == ' ')
648
		inptr++;
649
650
651
	if (inptr == inend || *inptr != '(') {
652
		*in = inptr;
653
		return NULL;
654
	}
655
656
	inptr++; /* My '(' */
657
658
	part = bodystruct_new ();
659
660
	part->part_spec = NULL;
661
	part->parent = parent;
662
663
	if (parent) {
664
		if (parent->part_spec && *parent->part_spec) {
665
			if (!strcasecmp (parent->content.type, "message") && !strcasecmp (parent->content.subtype, "rfc822")) {
666
				part->part_spec = g_strdup (parent->part_spec);
667
			} else {
668
				part->part_spec = g_strdup_printf ("%s.%d", parent->part_spec, num);
669
			}
670
		} else {
671
			part->part_spec = g_strdup_printf ("%d", num);
672
		}
673
	} else {
674
		part->part_spec = g_strdup ("");
675
	}
676
677
	if (*inptr == '(') {
678
		gint cnt = 1;
679
680
		part->content.type = g_strdup ("MULTIPART");
681
682
		list = NULL;
683
		tail = (struct _bodystruct *) &list;
684
685
		while ((n = bodystruct_part_decode (&inptr, inend, part, cnt, err)) != NULL) 
686
		{
687
			tail->next = n;
688
			tail = n;
689
			cnt++;
690
691
			while (inptr < inend && *inptr == ' ')
692
				inptr++;
693
694
			if (*inptr == ')')
695
				break;
696
		}
697
698
		part->subparts = list;
699
700
		if (*inptr != ')') {
701
			part->content.subtype = decode_qstring (&inptr, inend, err);
702
			debug_printf ("contensubtype: %s\n", PRINT_NULL (part->content.subtype));
703
		}
704
705
		if (*inptr != ')') {
706
			part->content.params = decode_params (&inptr, inend, err);
707
			print_params (part->content.params);
708
		}
709
710
		/* if (*inptr != ')') {
711
		 *	parse_something_unknown (&inptr, inend, err);
712
		 * } */
713
714
		if (*inptr != ')') {
715
			parse_content_disposition (&inptr, inend, &part->disposition, err);
716
		}
717
718
		if (*inptr != ')') {
719
			parse_lang (&inptr, inend, part, err);
720
		}
721
722
		if (*inptr != ')') {
723
			end_this_piece (&inptr, inend, err);
724
		}
725
726
	} else {
727
		part->next = NULL;
728
		part->content.type = decode_qstring (&inptr, inend, err);
729
		if (!part->content.type)
730
			part->content.type = g_strdup ("TEXT");
731
		debug_printf ("contentype: %s\n", PRINT_NULL (part->content.type));
732
733
		part->content.subtype = decode_qstring (&inptr, inend, err);
734
		if (!part->content.subtype)
735
			part->content.subtype = g_strdup ("PLAIN");
736
		debug_printf ("contensubtype: %s\n", PRINT_NULL (part->content.subtype));
737
738
		part->disposition.type = NULL;
739
		part->disposition.params = NULL;
740
		part->encoding = NULL;
741
		part->envelope = NULL;
742
		part->subparts = NULL;
743
744
745
		if (!strcasecmp (part->content.type, "message") && !strcasecmp (part->content.subtype, "rfc822")) {
746
747
			if (*inptr != ')') {
748
				part->content.params = decode_params (&inptr, inend, err);
749
				print_params (part->content.params);
750
			}
751
752
			if (*inptr != ')') {
753
				part->content.cid = decode_qstring (&inptr, inend, err);
754
				debug_printf ("content.cid: %s\n", PRINT_NULL (part->content.cid));
755
			}
756
757
			if (*inptr != ')') {
758
				part->description = decode_qstring (&inptr, inend, err);
759
				debug_printf ("description: %s\n", PRINT_NULL (part->description));
760
			}
761
762
			if (*inptr != ')') {
763
				part->encoding = decode_qstring (&inptr, inend, err);
764
				if (!part->encoding)
765
					part->encoding = g_strdup ("7BIT");
766
				debug_printf ("encoding: %s\n", PRINT_NULL (part->encoding));
767
			}
768
769
			if (*inptr != ')') {
770
				part->octets = decode_num (&inptr, inend, err);
771
				debug_printf ("octets: %d\n", part->octets);
772
			}
773
774
			if (*inptr != ')') {
775
				part->envelope = decode_envelope (&inptr, inend, err);
776
			}
777
778
			if (*inptr != ')') {
779
				part->subparts = bodystruct_part_decode (&inptr, inend, part, 1, err);
780
			}
781
782
			if (*inptr != ')') {
783
				part->lines = decode_num (&inptr, inend, err);
784
				debug_printf ("lines: %d\n", part->lines);
785
			}
786
787
			if (*inptr != ')') {
788
				read_unknown_qstring (&inptr, inend, err);
789
			}
790
791
			if (*inptr != ')') {
792
				parse_content_disposition (&inptr, inend, &part->disposition, err);
793
			}
794
795
			if (*inptr != ')') {
796
				parse_lang (&inptr, inend, part, err);
797
			}
798
799
			if (*inptr != ')') {
800
				end_this_piece (&inptr, inend, err);
801
			}
802
803
		} else if (!strcasecmp (part->content.type, "text")) {
804
805
			if (*inptr != ')') {
806
				part->content.params = decode_params (&inptr, inend, err);
807
				print_params (part->content.params);
808
			}
809
810
			if (*inptr != ')') {
811
				part->content.cid = decode_qstring (&inptr, inend, err);
812
				debug_printf ("content.cid: %s\n", PRINT_NULL (part->content.cid));
813
			}
814
815
			if (*inptr != ')') {
816
				part->description = decode_qstring (&inptr, inend, err);
817
				debug_printf ("description: %s\n", PRINT_NULL (part->description));
818
			}
819
820
			if (*inptr != ')') {
821
				part->encoding = decode_qstring (&inptr, inend, err);
822
				debug_printf ("encoding: %s\n", PRINT_NULL (part->encoding));
823
			}
824
825
			if (*inptr != ')') {
826
				part->octets = decode_num (&inptr, inend, err);
827
				debug_printf ("octets: %d\n", part->octets);
828
			}
829
830
			if (*inptr != ')') {
831
				part->lines = decode_num (&inptr, inend, err);
832
				debug_printf ("lines: %d\n", part->lines);
833
			}
834
835
			if (*inptr != ')') {
836
				read_unknown_qstring (&inptr, inend, err);
837
			}
838
839
			if (*inptr != ')') {
840
				parse_content_disposition (&inptr, inend, &part->disposition, err);
841
			}
842
843
			if (*inptr != ')') {
844
				parse_lang (&inptr, inend, part, err);
845
			}
846
847
			if (*inptr != ')') {
848
				end_this_piece (&inptr, inend, err);
849
			}
850
851
		} else if (!strcasecmp (part->content.type, "APPLICATION")||
852
				!strcasecmp (part->content.type, "IMAGE") ||
853
				!strcasecmp (part->content.type, "VIDEO") ||
854
				!strcasecmp (part->content.type, "AUDIO"))
855
		{
856
857
			if (*inptr != ')') {
858
				part->content.params = decode_params (&inptr, inend, err);
859
				print_params (part->content.params);
860
			}
861
862
			if (*inptr != ')') {
863
				part->content.cid = decode_qstring (&inptr, inend, err);
864
				debug_printf ("content.cid: %s\n", PRINT_NULL (part->content.cid));
865
			}
866
867
			if (*inptr != ')') {
868
				part->description = decode_qstring (&inptr, inend, err);
869
				debug_printf ("description: %s\n", PRINT_NULL (part->description));
870
			}
871
872
			if (*inptr != ')') {
873
				part->encoding = decode_qstring (&inptr, inend, err);
874
				debug_printf ("encoding: %s\n", PRINT_NULL (part->encoding));
875
			}
876
877
			if (*inptr != ')') {
878
				part->octets = decode_num (&inptr, inend, err);
879
				debug_printf ("octets: %d\n", part->octets);
880
			}
881
882
			if (*inptr != ')') {
883
				read_unknown_qstring (&inptr, inend, err);
884
			}
885
886
			if (*inptr != ')') {
887
				parse_content_disposition (&inptr, inend, &part->disposition, err);
888
			}
889
890
			if (*inptr != ')') {
891
				parse_lang (&inptr, inend, part, err);
892
			}
893
894
			if (*inptr != ')') {
895
				end_this_piece (&inptr, inend, err);
896
			}
897
898
		} else {
899
			/* I don't know how it looks, so I just read it away */
900
			end_this_piece (&inptr, inend, err);
901
		}
902
903
904
	}
905
906
	if (*inptr != ')') {
907
		*in = inptr;
908
		set_error (err, in);
909
		bodystruct_free (part);
910
		return NULL;
911
	}
912
913
	inptr++; /* My ')' */
914
915
	*in = inptr;
916
917
	return part;
918
}
919
920
const gchar * 
921
mimeparam_get_value_for (mimeparam_t *mp, const gchar *key)
922
{
923
	struct _mimeparam *param;
924
	param = mp;
925
	gboolean found = FALSE;
926
927
	while (param) {
928
		if (!strcasecmp (param->name, key)) {
929
			found = TRUE;
930
			break;
931
		}
932
		param = param->next;
933
	}
934
935
	if (found)
936
		return param->value;
937
938
	return NULL;
939
}
940
941
#ifdef DEBUG
942
static void
943
bodystruct_dump_r (bodystruct_t *part, gint depth)
944
{
945
	struct _mimeparam *param;
946
	int i;
947
948
	for (i = 0; i < depth; i++)
949
		printf ("  ");
950
951
	printf ("IMAP part specification: %s\n", PRINT_NULL (part->part_spec));
952
953
	for (i = 0; i < depth; i++)
954
		printf ("  ");
955
956
	printf ("Content-Type: %s/%s", PRINT_NULL (part->content.type),
957
		 part->content.subtype);
958
959
	if (part->content.params) {
960
		param = part->content.params;
961
		while (param) {
962
			printf ("; %s=%s", PRINT_NULL (param->name), 
963
				PRINT_NULL (param->value));
964
			param = param->next;
965
		}
966
	}
967
968
	printf ("\n");
969
970
	if (part->content.type && !strcasecmp (part->content.type, "multipart")) {
971
		part = part->subparts;
972
		while (part != NULL) {
973
			bodystruct_dump_r (part, depth + 1);
974
			part = part->next;
975
		}
976
	} else if (part->content.type && !strcasecmp (part->content.type, "message") && part->content.subtype && !strcasecmp (part->content.subtype, "rfc822")) {
977
		depth++;
978
		
979
		for (i = 0; i < depth; i++)
980
			printf ("  ");
981
		printf ( "Date: %s\n", PRINT_NULL (part->envelope->date));
982
		for (i = 0; i < depth; i++)
983
			printf ("  ");
984
		printf ("Subject: %s\n", PRINT_NULL (part->envelope->subject));
985
		for (i = 0; i < depth; i++)
986
			printf ("  ");
987
		printf ("From: %s\n", PRINT_NULL (part->envelope->from));
988
		for (i = 0; i < depth; i++)
989
			printf ("  ");
990
		printf ("Sender: %s\n", PRINT_NULL (part->envelope->sender));
991
		for (i = 0; i < depth; i++)
992
			printf ("  ");
993
		printf ("Reply-To: %s\n", PRINT_NULL (part->envelope->reply_to));
994
		for (i = 0; i < depth; i++)
995
			printf ("  ");
996
		printf ("To: %s\n", PRINT_NULL (part->envelope->to));
997
		for (i = 0; i < depth; i++)
998
			printf ("  ");
999
		printf ("Cc: %s\n", PRINT_NULL (part->envelope->cc));
1000
		for (i = 0; i < depth; i++)
1001
			printf ("  ");
1002
		printf ("Bcc: %s\n", PRINT_NULL (part->envelope->bcc));
1003
		for (i = 0; i < depth; i++)
1004
			printf ("  ");
1005
		printf ("In-Reply-To: %s\n", PRINT_NULL (part->envelope->in_reply_to));
1006
		for (i = 0; i < depth; i++)
1007
			printf ("  ");
1008
		printf ("Message-Id: %s\n", PRINT_NULL (part->envelope->message_id));
1009
		bodystruct_dump_r (part->subparts, depth);
1010
		depth--;
1011
	} else {
1012
		if (part->disposition.type) {
1013
			for (i = 0; i < depth; i++)
1014
				printf ("  ");
1015
			printf ("Content-Disposition: %s", PRINT_NULL (part->disposition.type));
1016
			if (part->disposition.params) {
1017
				param = part->disposition.params;
1018
				while (param) {
1019
					printf ("; %s=%s", PRINT_NULL (param->name), 
1020
						PRINT_NULL (param->value));
1021
					param = param->next;
1022
				}
1023
			}
1024
			
1025
			printf ("\n");
1026
		}
1027
		
1028
		if (part->encoding) {
1029
			for (i = 0; i < depth; i++)
1030
				printf ("  ");
1031
			printf ("Content-Transfer-Encoding: %s\n", PRINT_NULL (part->encoding));
1032
		}
1033
1034
		if (part->description) {
1035
			for (i = 0; i < depth; i++)
1036
				printf ("  ");
1037
			printf ("Description: %s\n", PRINT_NULL (part->description));
1038
		}
1039
1040
		for (i = 0; i < depth; i++)
1041
			printf ("  ");
1042
		printf ("Octets: %d, Lines: %d\n", part->octets, part->lines);
1043
1044
		if (part->content.lang) {
1045
			for (i = 0; i < depth; i++)
1046
				printf ("  ");
1047
			printf ("Language: %s\n", PRINT_NULL (part->content.lang));
1048
		}
1049
1050
		if (part->content.loc) {
1051
			for (i = 0; i < depth; i++)
1052
				printf ("  ");
1053
			printf ("Location: %s\n", PRINT_NULL (part->content.loc));
1054
		}
1055
1056
		if (part->content.cid) {
1057
			for (i = 0; i < depth; i++)
1058
				printf ("  ");
1059
			printf ("Cid: %s\n", PRINT_NULL (part->content.cid));
1060
		}
1061
1062
		if (part->content.md5) {
1063
			for (i = 0; i < depth; i++)
1064
				printf ("  ");
1065
			printf ("MD5: %s\n", PRINT_NULL (part->content.md5));
1066
		}
1067
	}
1068
1069
1070
	printf ("\n");
1071
}
1072
1073
void
1074
bodystruct_dump (bodystruct_t *part)
1075
{
1076
	bodystruct_dump_r (part, 0);
1077
}
1078
#endif
1079
1080
void
1081
bodystruct_free (bodystruct_t *node)
1082
{
1083
	struct _bodystruct *next;
1084
1085
	while (node != NULL) {
1086
		g_free (node->content.type);
1087
		g_free (node->content.subtype);
1088
		g_free (node->content.lang);
1089
		g_free (node->content.loc);
1090
		g_free (node->content.cid);
1091
		g_free (node->content.md5);
1092
1093
		if (node->content.params)
1094
			mimeparam_destroy (node->content.params);
1095
		
1096
		g_free (node->disposition.type);
1097
		if (node->disposition.params)
1098
			mimeparam_destroy (node->disposition.params);
1099
		
1100
		g_free (node->encoding);
1101
		g_free (node->description);
1102
1103
		if (node->envelope)
1104
			envelope_free (node->envelope);
1105
1106
		if (node->subparts)
1107
			bodystruct_free (node->subparts);
1108
1109
		g_free (node->part_spec);
1110
1111
		/* leave node->parent, recursiveness will take care of it */
1112
1113
		next = node->next;
1114
		g_slice_free (struct _bodystruct, node);
1115
		node = next;
1116
	}
1117
}
1118
1119
1120
bodystruct_t *
1121
bodystruct_parse (guchar *inbuf, guint inlen, GError **err)
1122
{
1123
	unsigned char *start = (unsigned char  *) strstr ((const char *) inbuf, "BODYSTRUCTURE");
1124
	int lendif;
1125
	bodystruct_t *r = NULL;
1126
1127
	if (!start) {
1128
		r = bodystruct_part_decode (&inbuf, inbuf + inlen, NULL, 1, err);
1129
	} else {
1130
1131
		start += 13;
1132
		lendif = (int) start - (int) inbuf;
1133
1134
		r = bodystruct_part_decode (&start, (unsigned char *) ( start + (inlen - lendif) ), NULL, 1, err);
1135
	}
1136
	if (!r->part_spec)
1137
		r->part_spec = g_strdup ("");
1138
	return r;
1139
}
1140
1141
envelope_t*
1142
envelope_parse (guchar *inbuf, guchar **end, guint inlen, GError **err)
1143
{
1144
	int lendif;
1145
1146
	*end = (guchar *) strstr ((const char *) inbuf, "ENVELOPE");
1147
1148
	if (*end == NULL) {
1149
		*end = inbuf;
1150
		return decode_envelope (end, inbuf + inlen, err);
1151
	}
1152
1153
	*end += 8;
1154
	lendif = (int) *end - (int) inbuf;
1155
1156
	return decode_envelope (end, (unsigned char *) ( *end + (inlen - lendif) ), err);
1157
}
1158
1159
gboolean
1160
bodystruct_has_attachments (bodystruct_t *bodystructure)
1161
{
1162
	/* If it's neither a multipart nor a text message then we
1163
	   directly consider that it has attachments */
1164
	if (bodystructure->content.type &&
1165
	    g_ascii_strncasecmp (bodystructure->content.type, "text", 4) &&
1166
	    g_ascii_strncasecmp (bodystructure->content.type, "multipart", 9))
1167
		return TRUE;
1168
1169
	if (bodystructure->content.type &&
1170
	    !g_ascii_strncasecmp (bodystructure->content.type, "multipart", 9)) {
1171
		bodystruct_t *subpart = bodystructure->subparts;
1172
		while (subpart) {
1173
			if (bodystruct_has_attachments (subpart))
1174
				return TRUE;
1175
			subpart = subpart->next;
1176
		}
1177
	}
1178
	return FALSE;
1179
}