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