src/etpan_mime.c
author Volker Birk <vb@pep-project.org>
Wed, 25 Mar 2015 15:20:25 +0100
changeset 125 5119178815d8
parent 116 e4d286e7b300
child 130 507895068f83
permissions -rw-r--r--
Windoze fixes
     1 #include <string.h>
     2 #include <stdlib.h>
     3 #ifndef WIN32
     4 #include <unistd.h>
     5 #endif
     6 #include <assert.h>
     7 
     8 #include "etpan_mime.h"
     9 #ifndef mailmime_param_new_with_data
    10 #include <libetpan/mailprivacy_tools.h>
    11 #endif
    12 
    13 time_t mail_mkgmtime(struct tm * tmp);
    14 
    15 #define MAX_MESSAGE_ID 512
    16 
    17 static char * generate_boundary(void)
    18 {
    19     char id[MAX_MESSAGE_ID];
    20     long value1;
    21     long value2;
    22     long value3;
    23     long value4;
    24     int r;
    25  
    26     // no random needed here
    27 
    28     value1 = random();
    29     value2 = random();
    30     value3 = random();
    31     value4 = random();
    32 
    33     snprintf(id, MAX_MESSAGE_ID, "%.4lx%.4lx%.4lx%.4lx", value1, value2,
    34             value3, value4);
    35     
    36     return strdup(id);
    37 }
    38 
    39 struct mailmime * part_new_empty(
    40         struct mailmime_content * content,
    41         struct mailmime_fields * mime_fields,
    42         int force_single
    43     )
    44 {
    45 	struct mailmime * build_info;
    46 	clist * list = NULL;
    47 	int r;
    48 	int mime_type;
    49     char * attr_name = NULL;
    50     char * attr_value = NULL;
    51     struct mailmime_parameter * param = NULL;
    52     clist * parameters = NULL;
    53     char *boundary = NULL;
    54 
    55 	list = NULL;
    56 
    57 	if (force_single) {
    58 		mime_type = MAILMIME_SINGLE;
    59 	}
    60 	else {
    61 		switch (content->ct_type->tp_type) {
    62 			case MAILMIME_TYPE_DISCRETE_TYPE:
    63                 mime_type = MAILMIME_SINGLE;
    64                 break;
    65 
    66 			case MAILMIME_TYPE_COMPOSITE_TYPE:
    67                 switch (content->ct_type->tp_data.tp_composite_type->ct_type) {
    68                     case MAILMIME_COMPOSITE_TYPE_MULTIPART:
    69                         mime_type = MAILMIME_MULTIPLE;
    70                         break;
    71 
    72                     case MAILMIME_COMPOSITE_TYPE_MESSAGE:
    73                         if (strcasecmp(content->ct_subtype, "rfc822") == 0)
    74                             mime_type = MAILMIME_MESSAGE;
    75                         else
    76                             mime_type = MAILMIME_SINGLE;
    77                         break;
    78 
    79                     default:
    80                         goto enomem;
    81                 }
    82                 break;
    83 
    84 			default:
    85                 goto enomem;
    86 		}
    87 	}
    88 
    89 	if (mime_type == MAILMIME_MULTIPLE) {
    90 		list = clist_new();
    91         assert(list);
    92 		if (list == NULL)
    93 			goto enomem;
    94 
    95 		attr_name = strdup("boundary");
    96         assert(attr_name);
    97         if (attr_name == NULL)
    98             goto enomem;
    99 
   100 		boundary = generate_boundary();
   101         assert(boundary);
   102 		attr_value = boundary;
   103 		if (attr_value == NULL)
   104 			goto enomem;
   105 
   106 		param = mailmime_parameter_new(attr_name, attr_value);
   107         assert(param);
   108 		if (param == NULL)
   109 			goto enomem;
   110         attr_name = NULL;
   111         attr_value = NULL;
   112 
   113 		if (content->ct_parameters == NULL) {
   114 			parameters = clist_new();
   115             assert(parameters);
   116 			if (parameters == NULL)
   117 				goto enomem;
   118 		}
   119 		else {
   120 			parameters = content->ct_parameters;
   121         }
   122 
   123 		r = clist_append(parameters, param);
   124 		if (r)
   125 			goto enomem;
   126         param = NULL;
   127 
   128 		if (content->ct_parameters == NULL)
   129 			content->ct_parameters = parameters;
   130 	}
   131 
   132     build_info = mailmime_new(mime_type, NULL, 0, mime_fields, content, NULL,
   133             NULL, NULL, list, NULL, NULL);
   134 	if (build_info == NULL)
   135 		goto enomem;
   136 
   137 	return build_info;
   138 
   139 enomem:
   140     if (list)
   141         clist_free(list);
   142     free(attr_name);
   143     free(attr_value);
   144     if (content->ct_parameters == NULL)
   145         if (parameters)
   146             clist_free(parameters);
   147 
   148 	return NULL;
   149 }
   150 
   151 struct mailmime * get_pgp_encrypted_part(void)
   152 {
   153 	struct mailmime * mime = NULL;
   154 	struct mailmime_fields * mime_fields = NULL;
   155 	struct mailmime_content * content = NULL;
   156     int r;
   157 
   158 	content = mailmime_content_new_with_str("application/pgp-encrypted");
   159     if (content == NULL)
   160         goto enomem;
   161 
   162     mime_fields = mailmime_fields_new_empty();
   163     if (mime_fields == NULL)
   164         goto enomem;
   165 
   166 	mime = part_new_empty(content, mime_fields, 1);
   167     if (mime == NULL)
   168         goto enomem;
   169     mime_fields = NULL;
   170     content = NULL;
   171 
   172     r = mailmime_set_body_text(mime, "Version: 1\n", 10);
   173     if (r != 0)
   174         goto enomem;
   175 
   176 	return mime;
   177 
   178 enomem:
   179     if (content)
   180         mailmime_content_free(content);
   181     if (mime_fields)
   182         mailmime_fields_free(mime_fields);
   183     if (mime)
   184         mailmime_free(mime);
   185 
   186     return NULL;
   187 }
   188 
   189 struct mailmime * get_text_part(
   190         const char * filename,
   191         const char * mime_type,
   192         const char * text,
   193         size_t length,
   194         int encoding_type
   195     )
   196 {
   197     char * disposition_name = NULL;
   198 	struct mailmime_fields * mime_fields = NULL;
   199 	struct mailmime * mime = NULL;
   200 	struct mailmime_content * content = NULL;
   201 	struct mailmime_parameter * param = NULL;
   202 	struct mailmime_disposition * disposition = NULL;
   203 	struct mailmime_mechanism * encoding = NULL;
   204     int r;
   205     
   206     if (filename != NULL) {
   207         disposition_name = strdup(filename);
   208         if (disposition_name == NULL)
   209             goto enomem;
   210     }
   211 
   212     if (encoding_type) {
   213         encoding = mailmime_mechanism_new(encoding_type, NULL);
   214         if (encoding == NULL)
   215             goto enomem;
   216     }
   217 
   218     disposition =
   219             mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
   220                     disposition_name, NULL, NULL, NULL, (size_t) -1);
   221     if (disposition == NULL)
   222         goto enomem;
   223     disposition_name = NULL;
   224 
   225     mime_fields = mailmime_fields_new_with_data(encoding, NULL, NULL,
   226             disposition, NULL);
   227     if (mime_fields == NULL)
   228         goto enomem;
   229     encoding = NULL;
   230     disposition = NULL;
   231 
   232 	content = mailmime_content_new_with_str(mime_type);
   233     if (content == NULL)
   234         goto enomem;
   235     
   236     if (encoding_type != MAILMIME_MECHANISM_7BIT) {
   237         param = mailmime_param_new_with_data("charset", "utf-8");
   238         r = clist_append(content->ct_parameters, param);
   239         if (r != 0)
   240             goto enomem;
   241     }
   242 
   243 	mime = part_new_empty(content, mime_fields, 1);
   244     if (mime == NULL)
   245         goto enomem;
   246     content = NULL;
   247     mime_fields = NULL;
   248 
   249     if (text) {
   250         r = mailmime_set_body_text(mime, (char *) text, length);
   251         if (r != 0)
   252             goto enomem;
   253     }
   254 	
   255 	return mime;
   256 
   257 enomem:
   258     free(disposition_name);
   259     if (mime_fields)
   260         mailmime_fields_free(mime_fields);
   261     if (mime)
   262         mailmime_free(mime);
   263     if (content)
   264         mailmime_content_free(content);
   265     if (param)
   266         mailmime_parameter_free(param);
   267     if (disposition)
   268         mailmime_disposition_free(disposition);
   269     if (encoding)
   270         mailmime_mechanism_free(encoding);
   271 
   272     return NULL;
   273 }
   274 
   275 struct mailmime * get_file_part(
   276         const char * filename,
   277         const char * mime_type,
   278         char * data,
   279         size_t length
   280     )
   281 {
   282     char * disposition_name = NULL;
   283     int encoding_type;
   284     struct mailmime_disposition * disposition = NULL;
   285     struct mailmime_mechanism * encoding = NULL;
   286     struct mailmime_content * content = NULL;
   287     struct mailmime * mime = NULL;
   288     struct mailmime_fields * mime_fields = NULL;
   289     int r;
   290 
   291     if (filename != NULL) {
   292         disposition_name = strdup(filename);
   293         if (disposition_name == NULL)
   294             goto enomem;
   295     }
   296 
   297     disposition =
   298             mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_ATTACHMENT,
   299                     disposition_name, NULL, NULL, NULL, (size_t) -1);
   300     if (disposition == NULL)
   301         goto enomem;
   302     disposition_name = NULL;
   303 
   304     content = mailmime_content_new_with_str(mime_type);
   305     if (content == NULL)
   306         goto enomem;
   307 
   308     encoding_type = MAILMIME_MECHANISM_BASE64;
   309     encoding = mailmime_mechanism_new(encoding_type, NULL);
   310     if (encoding == NULL)
   311         goto enomem;
   312 
   313     mime_fields = mailmime_fields_new_with_data(encoding, NULL, NULL,
   314             disposition, NULL);
   315     if (mime_fields == NULL)
   316         goto enomem;
   317     encoding = NULL;
   318     disposition = NULL;
   319 
   320     mime = part_new_empty(content, mime_fields, 1);
   321     if (mime == NULL)
   322         goto enomem;
   323     content = NULL;
   324     mime_fields = NULL;
   325 
   326     r = mailmime_set_body_text(mime, data, length);
   327     if (r != 0)
   328         goto enomem;
   329 
   330     return mime;
   331 
   332 enomem:
   333     free(disposition_name);
   334     if (disposition)
   335         mailmime_disposition_free(disposition);
   336     if (encoding)
   337         mailmime_mechanism_free(encoding);
   338     if (content)
   339         mailmime_content_free(content);
   340     if (mime_fields)
   341         mailmime_fields_free(mime_fields);
   342     if (mime)
   343         mailmime_free(mime);
   344 
   345     return NULL;
   346 }
   347 
   348 struct mailmime * part_multiple_new(const char *type)
   349 {
   350     struct mailmime_fields *mime_fields = NULL;
   351     struct mailmime_content *content = NULL;
   352     struct mailmime *mp = NULL;
   353     
   354     mime_fields = mailmime_fields_new_empty();
   355     if (mime_fields == NULL)
   356         goto enomem;
   357     
   358     content = mailmime_content_new_with_str(type);
   359     if (content == NULL)
   360         goto enomem;
   361     
   362     mp = part_new_empty(content, mime_fields, 0);
   363     if (mp == NULL)
   364         goto enomem;
   365     
   366     return mp;
   367     
   368 enomem:
   369     if (content)
   370         mailmime_content_free(content);
   371     if (mime_fields)
   372         mailmime_fields_free(mime_fields);
   373 
   374     return NULL;
   375 }
   376 
   377 struct mailimf_field * _new_field(
   378         int type,
   379         _new_func_t new_func,
   380         void *value
   381     )
   382 {
   383     void *data = new_func(value);
   384     assert(data);
   385     if (data == NULL)
   386         return NULL;
   387 
   388     struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
   389     assert(result);
   390     if (result == NULL) {
   391         free(data);
   392         return NULL;
   393     }
   394 
   395     result->fld_type = type;
   396     result->fld_data.fld_return_path = data;
   397 
   398     return result;
   399 }
   400 
   401 void _free_field(struct mailimf_field *field)
   402 {
   403     if (field)
   404         free(field->fld_data.fld_return_path);
   405     free(field);
   406 }
   407 
   408 int _append_field(
   409         clist *list,
   410         int type,
   411         _new_func_t new_func,
   412         void *value
   413     )
   414 {
   415     int r;
   416     struct mailimf_field * field;
   417 
   418     assert(list);
   419     assert(new_func);
   420     assert(value);
   421 
   422     field = _new_field(type, new_func, value);
   423     if (field == NULL)
   424         return -1;
   425 
   426     r = clist_append(list, field);
   427     if (r)
   428         _free_field(field);
   429 
   430     return r;
   431 }
   432 
   433 // http://media2.giga.de/2014/02/Image-28.jpg
   434 
   435 struct mailimf_date_time * timestamp_to_etpantime(const struct tm *ts)
   436 {
   437     struct mailimf_date_time * result = calloc(1,
   438             sizeof(struct mailimf_date_time));
   439     assert(result);
   440     if (result == NULL)
   441         return NULL;
   442 
   443     assert(ts);
   444 
   445     result->dt_sec = ts->tm_sec;
   446     result->dt_min = ts->tm_min;
   447     result->dt_hour = ts->tm_hour;
   448     result->dt_day = ts->tm_mday;
   449     result->dt_month = ts->tm_mon + 1;
   450     result->dt_year = ts->tm_year + 1900;
   451     result->dt_zone = (int) (ts->tm_gmtoff / 36L);
   452 
   453     return result;
   454 }
   455 
   456 struct tm * etpantime_to_timestamp(const struct mailimf_date_time *et)
   457 {
   458     struct tm * result = calloc(1, sizeof(struct tm));
   459     assert(result);
   460     if (result == NULL)
   461         return NULL;
   462 
   463     assert(et);
   464 
   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;
   471     result->tm_gmtoff = 36L * (long) et->dt_zone;
   472 
   473     return result;
   474 }
   475 
   476 struct mailimf_mailbox * mailbox_from_string(
   477         const char *name,
   478         const char *address
   479     )
   480 {
   481     struct mailimf_mailbox *mb = NULL;
   482     char *_name = NULL;
   483     char *_address = NULL;
   484 
   485     assert(address);
   486 
   487     _name = name ? strdup(name) : strdup("");
   488     if (_name == NULL)
   489         goto enomem;
   490 
   491     _address = strdup(address);
   492     if (_address == NULL)
   493         goto enomem;
   494 
   495     mb = mailimf_mailbox_new(_name, _address);
   496     assert(mb);
   497     if (mb == NULL)
   498         goto enomem;
   499 
   500     return mb;
   501 
   502 enomem:
   503     free(_name);
   504     free(_address);
   505 
   506     return NULL;
   507 }
   508 
   509 struct mailimf_field * create_optional_field(
   510         const char *field,
   511         const char *value
   512     )
   513 {
   514     char *_field = NULL;
   515     char *_value = NULL;
   516     struct mailimf_optional_field *optional_field = NULL;
   517 
   518     _field = strdup(field);
   519     if (_field == NULL)
   520         goto enomem;
   521 
   522     _value = mailmime_encode_subject_header("utf-8", value, 0);
   523     if (_value == NULL)
   524         goto enomem;
   525 
   526     optional_field = mailimf_optional_field_new(_field, _value);
   527     if (optional_field == NULL)
   528         goto enomem;
   529 
   530     struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
   531     assert(result);
   532     if (result == NULL)
   533         goto enomem;
   534 
   535     result->fld_type = MAILIMF_FIELD_OPTIONAL_FIELD;
   536     result->fld_data.fld_optional_field = optional_field;
   537 
   538     return result;
   539 
   540 enomem:
   541     if (optional_field) {
   542         mailimf_optional_field_free(optional_field);
   543     }
   544     else {
   545         free(_field);
   546         free(_value);
   547     }
   548 
   549     return NULL;
   550 }
   551 
   552 int _append_optional_field(
   553         clist *list,
   554         const char *field,
   555         const char *value
   556     )
   557 {
   558     int r;
   559     struct mailimf_field * optional_field =
   560             create_optional_field(field, value);
   561 
   562     if (optional_field == NULL)
   563         return -1;
   564 
   565     r = clist_append(list, optional_field);
   566     if (r)
   567         mailimf_field_free(optional_field);
   568 
   569     return r;
   570 }
   571