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