1 // This file is under GNU General Public License 3.0
4 #include "etpan_mime.h"
5 #ifndef mailmime_param_new_with_data
6 #include <libetpan/mailprivacy_tools.h>
16 #define MAX_MESSAGE_ID 128
18 static char * generate_boundary(void)
20 char id[MAX_MESSAGE_ID];
22 // no cryptographically strong random needed here
23 const long value1 = random();
24 const long value2 = random();
25 const long value3 = random();
26 const long value4 = random();
28 snprintf(id, MAX_MESSAGE_ID, "%.4lx%.4lx%.4lx%.4lx", value1, value2,
34 struct mailmime * part_new_empty(
35 struct mailmime_content * content,
36 struct mailmime_fields * mime_fields,
40 struct mailmime * build_info;
44 char * attr_name = NULL;
45 char * attr_value = NULL;
46 struct mailmime_parameter * param = NULL;
47 clist * parameters = NULL;
48 char *boundary = NULL;
53 mime_type = MAILMIME_SINGLE;
56 switch (content->ct_type->tp_type) {
57 case MAILMIME_TYPE_DISCRETE_TYPE:
58 mime_type = MAILMIME_SINGLE;
61 case MAILMIME_TYPE_COMPOSITE_TYPE:
62 switch (content->ct_type->tp_data.tp_composite_type->ct_type) {
63 case MAILMIME_COMPOSITE_TYPE_MULTIPART:
64 mime_type = MAILMIME_MULTIPLE;
67 case MAILMIME_COMPOSITE_TYPE_MESSAGE:
68 if (strcasecmp(content->ct_subtype, "rfc822") == 0)
69 mime_type = MAILMIME_MESSAGE;
71 mime_type = MAILMIME_SINGLE;
84 if (mime_type == MAILMIME_MULTIPLE) {
90 attr_name = strdup("boundary");
92 if (attr_name == NULL)
95 boundary = generate_boundary();
97 attr_value = boundary;
98 if (attr_value == NULL)
101 param = mailmime_parameter_new(attr_name, attr_value);
108 if (content->ct_parameters == NULL) {
109 parameters = clist_new();
111 if (parameters == NULL)
115 parameters = content->ct_parameters;
118 r = clist_append(parameters, param);
123 if (content->ct_parameters == NULL)
124 content->ct_parameters = parameters;
127 build_info = mailmime_new(mime_type, NULL, 0, mime_fields, content, NULL,
128 NULL, NULL, list, NULL, NULL);
129 if (build_info == NULL)
139 if (content->ct_parameters == NULL)
141 clist_free(parameters);
143 mailmime_parameter_free(param);
147 struct mailmime * get_pgp_encrypted_part(void)
149 struct mailmime * mime = NULL;
150 struct mailmime_fields * mime_fields = NULL;
151 struct mailmime_content * content = NULL;
154 content = mailmime_content_new_with_str("application/pgp-encrypted");
158 mime_fields = mailmime_fields_new_empty();
159 if (mime_fields == NULL)
162 mime = part_new_empty(content, mime_fields, 1);
168 r = mailmime_set_body_text(mime, "Version: 1\n", 10);
176 mailmime_content_free(content);
178 mailmime_fields_free(mime_fields);
185 struct mailmime * get_text_part(
186 const char * filename,
187 const char * mime_type,
193 char * disposition_name = NULL;
194 struct mailmime_fields * mime_fields = NULL;
195 struct mailmime * mime = NULL;
196 struct mailmime_content * content = NULL;
197 struct mailmime_parameter * param = NULL;
198 struct mailmime_disposition * disposition = NULL;
199 struct mailmime_mechanism * encoding = NULL;
202 if (filename != NULL) {
203 disposition_name = strdup(filename);
204 if (disposition_name == NULL)
209 encoding = mailmime_mechanism_new(encoding_type, NULL);
210 if (encoding == NULL)
215 mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
216 disposition_name, NULL, NULL, NULL, (size_t) -1);
217 if (disposition == NULL)
219 disposition_name = NULL;
221 mime_fields = mailmime_fields_new_with_data(encoding, NULL, NULL,
223 if (mime_fields == NULL)
228 content = mailmime_content_new_with_str(mime_type);
232 if (encoding_type != MAILMIME_MECHANISM_7BIT) {
233 param = mailmime_param_new_with_data("charset", "utf-8");
234 r = clist_append(content->ct_parameters, param);
239 mime = part_new_empty(content, mime_fields, 1);
246 r = mailmime_set_body_text(mime, (char *) text, length);
254 free(disposition_name);
256 mailmime_fields_free(mime_fields);
260 mailmime_content_free(content);
262 mailmime_parameter_free(param);
264 mailmime_disposition_free(disposition);
266 mailmime_mechanism_free(encoding);
271 struct mailmime * get_file_part(
272 const char * filename,
273 const char * mime_type,
278 char * disposition_name = NULL;
280 struct mailmime_disposition * disposition = NULL;
281 struct mailmime_mechanism * encoding = NULL;
282 struct mailmime_content * content = NULL;
283 struct mailmime * mime = NULL;
284 struct mailmime_fields * mime_fields = NULL;
287 if (filename != NULL) {
288 disposition_name = strdup(filename);
289 if (disposition_name == NULL)
294 mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_ATTACHMENT,
295 disposition_name, NULL, NULL, NULL, (size_t) -1);
296 if (disposition == NULL)
298 disposition_name = NULL;
300 content = mailmime_content_new_with_str(mime_type);
304 encoding_type = MAILMIME_MECHANISM_BASE64;
305 encoding = mailmime_mechanism_new(encoding_type, NULL);
306 if (encoding == NULL)
309 mime_fields = mailmime_fields_new_with_data(encoding, NULL, NULL,
311 if (mime_fields == NULL)
316 mime = part_new_empty(content, mime_fields, 1);
324 r = mailmime_set_body_text(mime, data, length);
332 free(disposition_name);
334 mailmime_disposition_free(disposition);
336 mailmime_mechanism_free(encoding);
338 mailmime_content_free(content);
340 mailmime_fields_free(mime_fields);
347 struct mailmime * part_multiple_new(const char *type)
349 struct mailmime_fields *mime_fields = NULL;
350 struct mailmime_content *content = NULL;
351 struct mailmime *mp = NULL;
353 mime_fields = mailmime_fields_new_empty();
354 if (mime_fields == NULL)
357 content = mailmime_content_new_with_str(type);
361 mp = part_new_empty(content, mime_fields, 0);
369 mailmime_content_free(content);
371 mailmime_fields_free(mime_fields);
376 struct mailimf_field * _new_field(
378 _new_func_t new_func,
382 void *data = new_func(value);
387 struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
389 if (result == NULL) {
394 result->fld_type = type;
395 result->fld_data.fld_return_path = data;
400 void _free_field(struct mailimf_field *field)
403 free(field->fld_data.fld_return_path);
410 _new_func_t new_func,
415 struct mailimf_field * field;
421 field = _new_field(type, new_func, value);
425 r = clist_append(list, field);
432 // http://media2.giga.de/2014/02/Image-28.jpg
434 struct mailimf_date_time * timestamp_to_etpantime(const struct tm *ts)
436 struct mailimf_date_time * result = calloc(1,
437 sizeof(struct mailimf_date_time));
444 result->dt_sec = ts->tm_sec;
445 result->dt_min = ts->tm_min;
446 result->dt_hour = ts->tm_hour;
447 result->dt_day = ts->tm_mday;
448 result->dt_month = ts->tm_mon + 1;
449 result->dt_year = ts->tm_year + 1900;
451 result->dt_zone = (int) (ts->tm_gmtoff / 36L);
456 struct tm * etpantime_to_timestamp(const struct mailimf_date_time *et)
458 struct tm * result = calloc(1, sizeof(struct tm));
465 result->tm_sec = et->dt_sec;
466 result->tm_min = et->dt_min;
467 result->tm_hour = et->dt_hour;
468 result->tm_mday = et->dt_day;
469 result->tm_mon = et->dt_month - 1;
470 result->tm_year = et->dt_year - 1900;
472 result->tm_gmtoff = 36L * (long) et->dt_zone;
477 struct mailimf_mailbox * mailbox_from_string(
482 struct mailimf_mailbox *mb = NULL;
484 char *_address = NULL;
488 _name = name ? strdup(name) : strdup("");
492 _address = strdup(address);
493 if (_address == NULL)
496 mb = mailimf_mailbox_new(_name, _address);
510 struct mailimf_field * create_optional_field(
517 struct mailimf_optional_field *optional_field = NULL;
519 _field = strdup(field);
523 _value = mailmime_encode_subject_header("utf-8", value, 0);
527 optional_field = mailimf_optional_field_new(_field, _value);
528 if (optional_field == NULL)
531 struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
536 result->fld_type = MAILIMF_FIELD_OPTIONAL_FIELD;
537 result->fld_data.fld_optional_field = optional_field;
542 if (optional_field) {
543 mailimf_optional_field_free(optional_field);
553 int _append_optional_field(
560 struct mailimf_field * optional_field =
561 create_optional_field(field, value);
563 if (optional_field == NULL)
566 r = clist_append(list, optional_field);
568 mailimf_field_free(optional_field);
573 clist * _get_fields(struct mailmime * mime)
575 clist * _fieldlist = NULL;
579 if (mime->mm_data.mm_message.mm_fields &&
580 mime->mm_data.mm_message.mm_fields->fld_list) {
581 _fieldlist = mime->mm_data.mm_message.mm_fields->fld_list;
587 struct mailmime_content * _get_content(struct mailmime * mime)
589 struct mailmime_content * content = NULL;
593 if (mime->mm_data.mm_message.mm_msg_mime)
594 content = mime->mm_data.mm_message.mm_msg_mime->mm_content_type;
599 char * _get_filename(struct mailmime *mime)
601 clist * _fieldlist = NULL;
605 if (mime->mm_mime_fields && mime->mm_mime_fields->fld_list)
606 _fieldlist = mime->mm_mime_fields->fld_list;
611 for (cur = clist_begin(_fieldlist); cur; cur = clist_next(cur)) {
612 struct mailmime_field * _field = clist_content(cur);
613 if (_field && _field->fld_type == MAILMIME_FIELD_DISPOSITION) {
614 if (_field->fld_data.fld_disposition &&
615 _field->fld_data.fld_disposition->dsp_parms) {
617 _field->fld_data.fld_disposition->dsp_parms;
619 for (cur2 = clist_begin(_parmlist); cur2; cur2 =
621 struct mailmime_disposition_parm * param =
623 if (param->pa_type == MAILMIME_DISPOSITION_PARM_FILENAME)
624 return param->pa_data.pa_filename;
633 static bool parameter_has_value(
634 struct mailmime_content *content,
644 clist * list = content->ct_parameters;
648 for (cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
649 struct mailmime_parameter * param = clist_content(cur);
651 param->pa_name && strcasecmp(name, param->pa_name) == 0 &&
652 param->pa_value && strcasecmp(value, param->pa_value) == 0)
659 bool _is_multipart(struct mailmime_content *content, const char *subtype)
663 if (content->ct_type && content->ct_type->tp_type ==
664 MAILMIME_TYPE_COMPOSITE_TYPE &&
665 content->ct_type->tp_data.tp_composite_type &&
666 content->ct_type->tp_data.tp_composite_type->ct_type ==
667 MAILMIME_COMPOSITE_TYPE_MULTIPART) {
669 return content->ct_subtype &&
670 strcasecmp(content->ct_subtype, subtype) == 0;
678 bool _is_PGP_MIME(struct mailmime_content *content)
682 if (_is_multipart(content, "encrypted") &&
683 parameter_has_value(content, "protocol",
684 "application/pgp-encrypted"))
690 bool _is_text_part(struct mailmime_content *content, const char *subtype)
694 if (content->ct_type && content->ct_type->tp_type ==
695 MAILMIME_TYPE_DISCRETE_TYPE &&
696 content->ct_type->tp_data.tp_discrete_type &&
697 content->ct_type->tp_data.tp_discrete_type->dt_type ==
698 MAILMIME_DISCRETE_TYPE_TEXT) {
700 return content->ct_subtype &&
701 strcasecmp(content->ct_subtype, subtype) == 0;
709 int _get_content_type(
710 const struct mailmime_content *content,
716 char *_charset = NULL;
725 if (content->ct_subtype == NULL)
728 if (content->ct_type && content->ct_type->tp_data.tp_discrete_type) {
730 const char *_main_type;
732 switch (content->ct_type->tp_data.tp_discrete_type->dt_type) {
733 case MAILMIME_DISCRETE_TYPE_TEXT:
736 case MAILMIME_DISCRETE_TYPE_IMAGE:
737 _main_type = "image";
739 case MAILMIME_DISCRETE_TYPE_AUDIO:
740 _main_type = "audio";
742 case MAILMIME_DISCRETE_TYPE_VIDEO:
743 _main_type = "video";
745 case MAILMIME_DISCRETE_TYPE_APPLICATION:
746 _main_type = "application";
748 case MAILMIME_DISCRETE_TYPE_EXTENSION:
749 _main_type = "extension";
755 len = strlen(_main_type) + 1 + strlen(content->ct_subtype) + 1;
756 _type = calloc(1, len);
761 strncpy(_type, _main_type, len);
762 len -= strlen(_main_type);
763 strncat(_type, "/", len--);
764 strncat(_type, content->ct_subtype, len);
766 if (content->ct_parameters) {
768 for (cur = clist_begin(content->ct_parameters); cur; cur =
770 struct mailmime_parameter * param = clist_content(cur);
771 if (param && param->pa_name && strcasecmp(param->pa_name,
773 _charset = param->pa_value;
778 *charset = strdup(_charset);