1 /*
2
3 silcmime.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 2005 - 2007 Pekka Riikonen
8
9 The contents of this file are subject to one of the Licenses specified
10 in the COPYING file; You may not use this file except in compliance
11 with the License.
12
13 The software distributed under the License is distributed on an "AS IS"
14 basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY
15 KIND, either expressed or implied. See the COPYING file for more
16 information.
17
18 */
19
20 #include "silc.h"
21
22 /************************ Static utility functions **************************/
23
24 /* MIME fields destructor */
25
silc_mime_field_dest(void * key,void * context,void * user_context)26 static void silc_mime_field_dest(void *key, void *context, void *user_context)
27 {
28 silc_free(key);
29 silc_free(context);
30 }
31
32 /* Assembler fragment destructor */
33
silc_mime_assembler_dest(void * key,void * context,void * user_context)34 static void silc_mime_assembler_dest(void *key, void *context,
35 void *user_context)
36 {
37 silc_free(key);
38 silc_hash_table_free(context);
39 }
40
41 /* Assembler partial MIME destructor */
42
silc_mime_assemble_dest(void * key,void * context,void * user_context)43 static void silc_mime_assemble_dest(void *key, void *context,
44 void *user_context)
45 {
46 silc_mime_free(context);
47 }
48
49
50 /******************************* Public API *********************************/
51
52 /* Allocate MIME context */
53
silc_mime_alloc(void)54 SilcMime silc_mime_alloc(void)
55 {
56 SilcMime mime;
57
58 mime = silc_calloc(1, sizeof(*mime));
59 if (!mime)
60 return NULL;
61
62 mime->fields = silc_hash_table_alloc(0, silc_hash_string, mime,
63 silc_hash_string_compare, mime,
64 silc_mime_field_dest, mime, TRUE);
65 if (!mime->fields) {
66 silc_mime_free(mime);
67 return NULL;
68 }
69
70 return mime;
71 }
72
73 /* Free MIME context */
74
silc_mime_free(SilcMime mime)75 void silc_mime_free(SilcMime mime)
76 {
77 SilcMime m;
78
79 if (mime->fields)
80 silc_hash_table_free(mime->fields);
81
82 if (mime->multiparts) {
83 silc_dlist_start(mime->multiparts);
84 while ((m = silc_dlist_get(mime->multiparts)) != SILC_LIST_END)
85 silc_mime_free(m);
86 silc_dlist_uninit(mime->multiparts);
87 }
88 silc_free(mime->boundary);
89 silc_free(mime->multitype);
90 silc_free(mime->data);
91 silc_free(mime);
92 }
93
94 /* Allocate MIME assembler */
95
silc_mime_assembler_alloc(void)96 SilcMimeAssembler silc_mime_assembler_alloc(void)
97 {
98 SilcMimeAssembler assembler;
99
100 assembler = silc_calloc(1, sizeof(*assembler));
101 if (!assembler)
102 return NULL;
103
104 assembler->fragments =
105 silc_hash_table_alloc(0, silc_hash_string, NULL,
106 silc_hash_string_compare, NULL,
107 silc_mime_assembler_dest, assembler, TRUE);
108 if (!assembler->fragments) {
109 silc_mime_assembler_free(assembler);
110 return NULL;
111 }
112
113 return assembler;
114 }
115
116 /* Free MIME assembler */
117
silc_mime_assembler_free(SilcMimeAssembler assembler)118 void silc_mime_assembler_free(SilcMimeAssembler assembler)
119 {
120 silc_hash_table_free(assembler->fragments);
121 silc_free(assembler);
122 }
123
124 /* Decode MIME message */
125
silc_mime_decode(SilcMime mime,const unsigned char * data,SilcUInt32 data_len)126 SilcMime silc_mime_decode(SilcMime mime, const unsigned char *data,
127 SilcUInt32 data_len)
128 {
129 SilcMime m = NULL;
130 int i, k;
131 char *tmp, *field, *value, *line;
132
133 SILC_LOG_DEBUG(("Parsing MIME message"));
134
135 if (!data)
136 return NULL;
137
138 if (!mime) {
139 mime = silc_mime_alloc();
140 if (!mime)
141 return NULL;
142 m = mime;
143 }
144
145 /* Parse the fields */
146 line = tmp = (char *)data;
147 for (i = 0; i < data_len; i++) {
148 /* Get field line */
149 if (data_len - i >= 2 && tmp[i] == '\r' && tmp[i + 1] == '\n') {
150 /* Get field */
151 field = strchr(line, ':');
152 if (!field)
153 goto err;
154 field = silc_memdup(line, field - line);
155 if (!field)
156 goto err;
157
158 /* Get value. Remove whitespaces too. */
159 value = strchr(line, ':');
160 if ((tmp + i) - value < 2)
161 goto err;
162 value++;
163 for (k = 0; k < (tmp + i) - value; k++) {
164 if (value[k] == '\r')
165 goto err;
166 if (value[k] != ' ' && value[k] != '\t')
167 break;
168 }
169 value += k;
170 if ((tmp + i) - value < 1)
171 goto err;
172 value = silc_memdup(value, (tmp + i) - value);
173 if (!value)
174 goto err;
175
176 SILC_LOG_DEBUG(("Header '%s' '%s'", field, value));
177
178 /* Add field and value */
179 silc_mime_add_field(mime, field, value);
180 silc_free(field);
181 silc_free(value);
182
183 /* Mark start of next line */
184 line = (tmp + i) + 2;
185 i += 2;
186
187 /* Break if this is last header */
188 if (data_len - i >= 2 &&
189 tmp[i] == '\r' && tmp[i + 1] == '\n') {
190 i += 2;
191 break;
192 }
193 }
194 }
195
196 /* Parse multiparts if present */
197 field = (char *)silc_mime_get_field(mime, "Content-Type");
198 if (field && strstr(field, "multipart")) {
199 char b[1024];
200 SilcMime p;
201 unsigned int len;
202
203 mime->multiparts = silc_dlist_init();
204 if (!mime->multiparts)
205 goto err;
206
207 /* Get multipart type */
208 value = strchr(field, '/');
209 if (!value)
210 goto err;
211 value++;
212 if (strchr(field, '"'))
213 value++;
214 if (!strchr(field, ';'))
215 goto err;
216 memset(b, 0, sizeof(b));
217 len = (unsigned int)(strchr(field, ';') - value);
218 if (len > sizeof(b) - 1)
219 goto err;
220 strncpy(b, value, len);
221 if (strchr(b, '"'))
222 *strchr(b, '"') = '\0';
223 mime->multitype = silc_memdup(b, strlen(b));
224
225 /* Get boundary */
226 value = strrchr(field, '=');
227 if (value && strlen(value) > 1) {
228 value++;
229
230 SILC_LOG_DEBUG(("Boundary '%s'", value));
231
232 memset(b, 0, sizeof(b));
233 line = strdup(value);
234 if (strrchr(line, '"')) {
235 *strrchr(line, '"') = '\0';
236 silc_snprintf(b, sizeof(b) - 1, "--%s", line + 1);
237 mime->boundary = strdup(line + 1);
238 } else {
239 silc_snprintf(b, sizeof(b) - 1, "--%s", line);
240 mime->boundary = strdup(line);
241 }
242 silc_free(line);
243
244 for ( ; i < data_len; i++) {
245 /* Get boundary data */
246 if (data_len - i >= strlen(b) &&
247 tmp[i] == '-' && tmp[i + 1] == '-') {
248 if (memcmp(tmp + i, b, strlen(b)))
249 continue;
250
251 i += strlen(b);
252
253 if (data_len - i >= 4 &&
254 tmp[i ] == '\r' && tmp[i + 1] == '\n' &&
255 tmp[i + 2] == '\r' && tmp[i + 3] == '\n')
256 i += 4;
257 else if (data_len - i >= 2 &&
258 tmp[i] == '\r' && tmp[i + 1] == '\n')
259 i += 2;
260 else if (data_len - i >= 2 &&
261 tmp[i] == '-' && tmp[i + 1] == '-')
262 break;
263
264 line = tmp + i;
265
266 /* Find end of boundary */
267 for (k = i; k < data_len; k++)
268 if (data_len - k >= strlen(b) &&
269 tmp[k] == '-' && tmp[k + 1] == '-')
270 if (!memcmp(tmp + k, b, strlen(b)))
271 break;
272 if (k >= data_len)
273 goto err;
274
275 /* Remove preceding CRLF */
276 k -= 2;
277
278 /* Parse the part */
279 p = silc_mime_decode(NULL, line, k - i);
280 if (!p)
281 goto err;
282
283 silc_dlist_add(mime->multiparts, p);
284 i += (k - i);
285 }
286 }
287 }
288 } else {
289 /* Get data area. If we are at the end and we have fields present
290 there is no data area present, but, if fields are not present we
291 only have data area. */
292 if (i >= data_len && !silc_hash_table_count(mime->fields))
293 i = 0;
294 SILC_LOG_DEBUG(("Data len %d", data_len - i));
295 if (data_len - i)
296 silc_mime_add_data(mime, tmp + i, data_len - i);
297 }
298
299 return mime;
300
301 err:
302 if (m)
303 silc_mime_free(m);
304 return NULL;
305 }
306
307 /* Encode MIME message */
308
silc_mime_encode(SilcMime mime,SilcUInt32 * encoded_len)309 unsigned char *silc_mime_encode(SilcMime mime, SilcUInt32 *encoded_len)
310 {
311 SilcMime part;
312 SilcHashTableList htl;
313 SilcBufferStruct buf;
314 SilcBuffer buffer;
315 char *field, *value, tmp[1024], tmp2[4];
316 unsigned char *ret;
317 int i;
318
319 SILC_LOG_DEBUG(("Encoding MIME message"));
320
321 if (!mime)
322 return NULL;
323
324 memset(&buf, 0, sizeof(buf));
325
326 /* Encode the headers. Order doesn't matter */
327 i = 0;
328 silc_hash_table_list(mime->fields, &htl);
329 while (silc_hash_table_get(&htl, (void *)&field, (void *)&value)) {
330 memset(tmp, 0, sizeof(tmp));
331 SILC_LOG_DEBUG(("Header %s: %s", field, value));
332 silc_snprintf(tmp, sizeof(tmp) - 1, "%s: %s\r\n", field, value);
333 silc_buffer_strformat(&buf, tmp, SILC_STRFMT_END);
334 i++;
335 }
336 silc_hash_table_list_reset(&htl);
337 if (i)
338 silc_buffer_strformat(&buf, "\r\n", SILC_STRFMT_END);
339
340 /* Assemble the whole buffer */
341 buffer = silc_buffer_alloc_size(mime->data_len + silc_buffer_len(&buf));
342 if (!buffer)
343 return NULL;
344
345 /* Add headers */
346 if (silc_buffer_len(&buf)) {
347 silc_buffer_put(buffer, buf.head, silc_buffer_len(&buf));
348 silc_buffer_pull(buffer, silc_buffer_len(&buf));
349 silc_buffer_purge(&buf);
350 }
351
352 /* Add data */
353 if (mime->data) {
354 SILC_LOG_DEBUG(("Data len %d", mime->data_len));
355 silc_buffer_put(buffer, mime->data, mime->data_len);
356 }
357
358 /* Add multiparts */
359 if (mime->multiparts) {
360 SILC_LOG_DEBUG(("Encoding multiparts"));
361
362 silc_dlist_start(mime->multiparts);
363 i = 0;
364 while ((part = silc_dlist_get(mime->multiparts)) != SILC_LIST_END) {
365 unsigned char *pd;
366 SilcUInt32 pd_len;
367
368 /* Recursive encoding */
369 pd = silc_mime_encode(part, &pd_len);
370 if (!pd)
371 return NULL;
372
373 memset(tmp, 0, sizeof(tmp));
374 memset(tmp2, 0, sizeof(tmp2));
375
376 /* If fields are not present, add extra CRLF */
377 if (!silc_hash_table_count(part->fields))
378 silc_snprintf(tmp2, sizeof(tmp2) - 1, "\r\n");
379 silc_snprintf(tmp, sizeof(tmp) - 1, "%s--%s\r\n%s",
380 i != 0 ? "\r\n" : "", mime->boundary, tmp2);
381 i = 1;
382
383 buffer = silc_buffer_realloc(buffer, silc_buffer_truelen(buffer) +
384 pd_len + strlen(tmp));
385 if (!buffer)
386 return NULL;
387 silc_buffer_put_tail(buffer, tmp, strlen(tmp));
388 silc_buffer_pull_tail(buffer, strlen(tmp));
389 silc_buffer_put_tail(buffer, pd, pd_len);
390 silc_buffer_pull_tail(buffer, pd_len);
391 silc_free(pd);
392 }
393
394 memset(tmp, 0, sizeof(tmp));
395 silc_snprintf(tmp, sizeof(tmp) - 1, "\r\n--%s--\r\n", mime->boundary);
396 buffer = silc_buffer_realloc(buffer, silc_buffer_truelen(buffer) +
397 strlen(tmp));
398 if (!buffer)
399 return NULL;
400 silc_buffer_put_tail(buffer, tmp, strlen(tmp));
401 silc_buffer_pull_tail(buffer, strlen(tmp));
402 }
403
404 ret = silc_buffer_steal(buffer, encoded_len);
405 silc_buffer_free(buffer);
406
407 return ret;
408 }
409
410 /* Assembles MIME message from partial MIME messages */
411
silc_mime_assemble(SilcMimeAssembler assembler,SilcMime partial)412 SilcMime silc_mime_assemble(SilcMimeAssembler assembler, SilcMime partial)
413 {
414 char *type, *id = NULL, *tmp;
415 SilcHashTable f;
416 SilcMime p, complete;
417 int i, number, total = -1;
418 const unsigned char *data;
419 SilcUInt32 data_len;
420 SilcBuffer compbuf = NULL;
421
422 SILC_LOG_DEBUG(("Assembling MIME fragments"));
423
424 if (!assembler || !partial)
425 goto err;
426
427 type = (char *)silc_mime_get_field(partial, "Content-Type");
428 if (!type)
429 goto err;
430
431 /* Get ID */
432 tmp = strstr(type, "id=");
433 if (!tmp)
434 goto err;
435 if (strlen(tmp) <= 4)
436 goto err;
437 tmp += 3;
438 if (*tmp == '"')
439 tmp++;
440 id = strdup(tmp);
441 if (strchr(id, ';'))
442 *strchr(id, ';') = '\0';
443 if (strrchr(id, '"'))
444 *strrchr(id, '"') = '\0';
445
446 SILC_LOG_DEBUG(("Fragment ID %s", id));
447
448 /* Get fragment number */
449 tmp = strstr(type, "number=");
450 if (!tmp)
451 goto err;
452 tmp = strchr(tmp, '=');
453 if (strlen(tmp) < 2)
454 goto err;
455 tmp++;
456 if (strchr(tmp, ';')) {
457 tmp = strdup(tmp);
458 *strchr(tmp, ';') = '\0';
459 number = atoi(tmp);
460 silc_free(tmp);
461 } else {
462 number = atoi(tmp);
463 }
464
465 SILC_LOG_DEBUG(("Fragment number %d", number));
466
467 /* Find fragments with this ID. */
468 if (!silc_hash_table_find(assembler->fragments, (void *)id,
469 NULL, (void *)&f)) {
470 /* This is new fragment to new message. Add to hash table and return. */
471 f = silc_hash_table_alloc(0, silc_hash_uint, NULL, NULL, NULL,
472 silc_mime_assemble_dest, NULL, TRUE);
473 if (!f)
474 goto err;
475 silc_hash_table_add(f, SILC_32_TO_PTR(number), partial);
476 silc_hash_table_add(assembler->fragments, id, f);
477 return NULL;
478 }
479
480 /* Try to get total number */
481 tmp = strstr(type, "total=");
482 if (tmp) {
483 tmp = strchr(tmp, '=');
484 if (strlen(tmp) < 2)
485 goto err;
486 tmp++;
487 if (strchr(tmp, ';')) {
488 tmp = strdup(tmp);
489 *strchr(tmp, ';') = '\0';
490 total = atoi(tmp);
491 silc_free(tmp);
492 } else {
493 total = atoi(tmp);
494 }
495
496 SILC_LOG_DEBUG(("Fragment total %d", total));
497 }
498
499 /* If more fragments to come, add to hash table */
500 if (number != total) {
501 silc_hash_table_add(f, SILC_32_TO_PTR(number), partial);
502 return NULL;
503 }
504
505 silc_hash_table_add(f, SILC_32_TO_PTR(number), partial);
506
507 /* Verify that we really have all the fragments */
508 if (silc_hash_table_count(f) < total)
509 return NULL;
510
511 /* Assemble the complete MIME message now. We get them in order from
512 the hash table. */
513 for (i = 1; i <= total; i++) {
514 if (!silc_hash_table_find(f, SILC_32_TO_PTR(i), NULL, (void *)&p))
515 goto err;
516
517 /* The fragment is in the data portion of the partial message */
518 data = silc_mime_get_data(p, &data_len);
519 if (!data)
520 goto err;
521
522 /* Assemble */
523 if (!compbuf) {
524 compbuf = silc_buffer_alloc_size(data_len);
525 if (!compbuf)
526 goto err;
527 silc_buffer_put(compbuf, data, data_len);
528 } else {
529 compbuf = silc_buffer_realloc(compbuf, silc_buffer_truelen(compbuf) +
530 data_len);
531 if (!compbuf)
532 goto err;
533 silc_buffer_put_tail(compbuf, data, data_len);
534 silc_buffer_pull_tail(compbuf, data_len);
535 }
536 }
537
538 if (!compbuf)
539 goto err;
540
541 /* Now parse the complete MIME message and deliver it */
542 complete = silc_mime_decode(NULL, (const unsigned char *)compbuf->head,
543 silc_buffer_truelen(compbuf));
544 if (!complete)
545 goto err;
546
547 /* Delete the hash table entry. Destructors will free memory */
548 silc_hash_table_del(assembler->fragments, (void *)id);
549 silc_free(id);
550 silc_buffer_free(compbuf);
551
552 return complete;
553
554 err:
555 silc_free(id);
556 if (compbuf)
557 silc_buffer_free(compbuf);
558 silc_mime_free(partial);
559 return NULL;
560 }
561
562 /* Encodes partial MIME messages */
563
silc_mime_encode_partial(SilcMime mime,int max_size)564 SilcDList silc_mime_encode_partial(SilcMime mime, int max_size)
565 {
566 unsigned char *buf, *tmp;
567 SilcUInt32 buf_len, len, tmp_len, off;
568 SilcDList list;
569 SilcBuffer buffer;
570 SilcMime partial;
571 char type[128], id[64];
572 int num;
573
574 SILC_LOG_DEBUG(("Fragmenting MIME message"));
575
576 /* Encode as normal */
577 buf = silc_mime_encode(mime, &buf_len);
578 if (!buf)
579 return NULL;
580
581 list = silc_dlist_init();
582
583 /* Fragment if it is too large */
584 if (buf_len > max_size) {
585 memset(id, 0, sizeof(id));
586 memset(type, 0, sizeof(type));
587 gethostname(type, sizeof(type) - 1);
588 srand((time(NULL) + buf_len) ^ rand());
589 silc_snprintf(id, sizeof(id) - 1, "%X%X%X%s",
590 (unsigned int)rand(), (unsigned int)time(NULL),
591 (unsigned int)buf_len, type);
592
593 SILC_LOG_DEBUG(("Fragment ID %s", id));
594
595 partial = silc_mime_alloc();
596 if (!partial)
597 return NULL;
598
599 silc_mime_add_field(partial, "MIME-Version", "1.0");
600 memset(type, 0, sizeof(type));
601 silc_snprintf(type, sizeof(type) - 1,
602 "message/partial; id=\"%s\"; number=1", id);
603 silc_mime_add_field(partial, "Content-Type", type);
604 silc_mime_add_data(partial, buf, max_size);
605
606 tmp = silc_mime_encode(partial, &tmp_len);
607 if (!tmp)
608 return NULL;
609 silc_mime_free(partial);
610
611 /* Add to list */
612 buffer = silc_buffer_alloc_size(tmp_len);
613 if (!buffer)
614 return NULL;
615 silc_buffer_put(buffer, tmp, tmp_len);
616 silc_dlist_add(list, buffer);
617 silc_free(tmp);
618
619 len = buf_len - max_size;
620 off = max_size;
621 num = 2;
622 while (len > 0) {
623 partial = silc_mime_alloc();
624 if (!partial)
625 return NULL;
626
627 memset(type, 0, sizeof(type));
628 silc_mime_add_field(partial, "MIME-Version", "1.0");
629
630 if (len > max_size) {
631 silc_snprintf(type, sizeof(type) - 1,
632 "message/partial; id=\"%s\"; number=%d",
633 id, num++);
634 silc_mime_add_data(partial, buf + off, max_size);
635 off += max_size;
636 len -= max_size;
637 } else {
638 silc_snprintf(type, sizeof(type) - 1,
639 "message/partial; id=\"%s\"; number=%d; total=%d",
640 id, num, num);
641 silc_mime_add_data(partial, buf + off, len);
642 len = 0;
643 }
644
645 silc_mime_add_field(partial, "Content-Type", type);
646
647 tmp = silc_mime_encode(partial, &tmp_len);
648 if (!tmp)
649 return NULL;
650 silc_mime_free(partial);
651
652 /* Add to list */
653 buffer = silc_buffer_alloc_size(tmp_len);
654 if (!buffer)
655 return NULL;
656 silc_buffer_put(buffer, tmp, tmp_len);
657 silc_dlist_add(list, buffer);
658 silc_free(tmp);
659 }
660 } else {
661 /* No need to fragment */
662 buffer = silc_buffer_alloc_size(buf_len);
663 if (!buffer)
664 return NULL;
665 silc_buffer_put(buffer, buf, buf_len);
666 silc_dlist_add(list, buffer);
667 }
668
669 silc_free(buf);
670
671 return list;
672 }
673
674 /* Free partial MIME list */
675
silc_mime_partial_free(SilcDList partials)676 void silc_mime_partial_free(SilcDList partials)
677 {
678 SilcBuffer buf;
679
680 if (!partials)
681 return;
682
683 silc_dlist_start(partials);
684 while ((buf = silc_dlist_get(partials)) != SILC_LIST_END)
685 silc_buffer_free(buf);
686 silc_dlist_uninit(partials);
687 }
688
689 /* Add field */
690
silc_mime_add_field(SilcMime mime,const char * field,const char * value)691 void silc_mime_add_field(SilcMime mime, const char *field, const char *value)
692 {
693 if (!mime || !field || !value)
694 return;
695
696 silc_hash_table_add(mime->fields, strdup(field), strdup(value));
697 }
698
699 /* Get field */
700
silc_mime_get_field(SilcMime mime,const char * field)701 const char *silc_mime_get_field(SilcMime mime, const char *field)
702 {
703 char *value;
704
705 if (!mime || !field)
706 return NULL;
707
708 if (!silc_hash_table_find(mime->fields, (void *)field,
709 NULL, (void *)&value))
710 return NULL;
711
712 return (const char *)value;
713 }
714
715 /* Add data */
716
silc_mime_add_data(SilcMime mime,const unsigned char * data,SilcUInt32 data_len)717 void silc_mime_add_data(SilcMime mime, const unsigned char *data,
718 SilcUInt32 data_len)
719 {
720 if (!mime || !data)
721 return;
722
723 if (mime->data)
724 silc_free(mime->data);
725
726 mime->data = silc_memdup(data, data_len);
727 mime->data_len = data_len;
728 }
729
730 /* Get data */
731
silc_mime_get_data(SilcMime mime,SilcUInt32 * data_len)732 const unsigned char *silc_mime_get_data(SilcMime mime, SilcUInt32 *data_len)
733 {
734 if (!mime)
735 return NULL;
736
737 if (data_len)
738 *data_len = mime->data_len;
739
740 return mime->data;
741 }
742
743 /* Steal data */
744
silc_mime_steal_data(SilcMime mime,SilcUInt32 * data_len)745 unsigned char *silc_mime_steal_data(SilcMime mime, SilcUInt32 *data_len)
746 {
747 unsigned char *data;
748
749 if (!mime)
750 return NULL;
751
752 if (data_len)
753 *data_len = mime->data_len;
754
755 data = mime->data;
756
757 mime->data = NULL;
758 mime->data_len = 0;
759
760 return data;
761 }
762
763 /* Returns TRUE if partial message */
764
silc_mime_is_partial(SilcMime mime)765 SilcBool silc_mime_is_partial(SilcMime mime)
766 {
767 const char *type = silc_mime_get_field(mime, "Content-Type");
768 if (!type)
769 return FALSE;
770
771 if (!strstr(type, "message/partial"))
772 return FALSE;
773
774 return TRUE;
775 }
776
777 /* Set as multipart message */
778
silc_mime_set_multipart(SilcMime mime,const char * type,const char * boundary)779 void silc_mime_set_multipart(SilcMime mime, const char *type,
780 const char *boundary)
781 {
782 char tmp[1024];
783
784 if (!mime || !type || !boundary)
785 return;
786
787 memset(tmp, 0, sizeof(tmp));
788 silc_snprintf(tmp, sizeof(tmp) - 1, "multipart/%s; boundary=%s", type, boundary);
789 silc_mime_add_field(mime, "Content-Type", tmp);
790 silc_free(mime->boundary);
791 mime->boundary = strdup(boundary);
792
793 if (mime->multiparts)
794 return;
795 mime->multiparts = silc_dlist_init();
796 }
797
798 /* Add multipart */
799
silc_mime_add_multipart(SilcMime mime,SilcMime part)800 SilcBool silc_mime_add_multipart(SilcMime mime, SilcMime part)
801 {
802 if (!mime || !mime->multiparts || !part)
803 return FALSE;
804
805 silc_dlist_add(mime->multiparts, part);
806 return TRUE;
807 }
808
809 /* Return TRUE if has multiparts */
810
silc_mime_is_multipart(SilcMime mime)811 SilcBool silc_mime_is_multipart(SilcMime mime)
812 {
813 if (!mime)
814 return FALSE;
815
816 return mime->multiparts != NULL;
817 }
818
819 /* Returns multiparts */
820
silc_mime_get_multiparts(SilcMime mime,const char ** type)821 SilcDList silc_mime_get_multiparts(SilcMime mime, const char **type)
822 {
823 if (!mime)
824 return NULL;
825
826 if (type)
827 *type = (const char *)mime->multitype;
828
829 return mime->multiparts;
830 }
831