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