src/etpan_mime.c
author vb
Sat, 07 Mar 2015 20:29:13 +0100
changeset 89 aef5a4bc78f3
parent 62 ad5e484720e1
child 90 42b5eb9d5af2
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 #ifndef WIN32
    27     value = random();
    28     
    29     gethostname(name, MAX_MESSAGE_ID - 1);
    30 #else
    31     value = now;
    32     strcpy(name, "WINDOWS");
    33 #endif
    34     
    35     if (boundary_prefix == NULL)
    36         boundary_prefix = "";
    37     
    38     snprintf(id, MAX_MESSAGE_ID, "%s%lx_%lx_%x", boundary_prefix, now, value,
    39             getpid());
    40     
    41     return strdup(id);
    42 }
    43 
    44 struct mailmime * part_new_empty(
    45         struct mailmime_content * content,
    46         struct mailmime_fields * mime_fields,
    47         const char * boundary_prefix,
    48         int force_single
    49     )
    50 {
    51 	struct mailmime * build_info;
    52 	clist * list;
    53 	int r;
    54 	int mime_type;
    55 
    56 	list = NULL;
    57 
    58 	if (force_single) {
    59 		mime_type = MAILMIME_SINGLE;
    60 	}
    61 	else {
    62 		switch (content->ct_type->tp_type) {
    63 			case MAILMIME_TYPE_DISCRETE_TYPE:
    64 			mime_type = MAILMIME_SINGLE;
    65 			break;
    66 
    67 			case MAILMIME_TYPE_COMPOSITE_TYPE:
    68 			switch (content->ct_type->tp_data.tp_composite_type->ct_type) {
    69 				case MAILMIME_COMPOSITE_TYPE_MULTIPART:
    70 				mime_type = MAILMIME_MULTIPLE;
    71 				break;
    72 
    73 				case MAILMIME_COMPOSITE_TYPE_MESSAGE:
    74 				if (strcasecmp(content->ct_subtype, "rfc822") == 0)
    75 					mime_type = MAILMIME_MESSAGE;
    76 				else
    77 					mime_type = MAILMIME_SINGLE;
    78 				break;
    79 
    80 				default:
    81 				goto err;
    82 			}
    83 			break;
    84 
    85 			default:
    86 			goto err;
    87 		}
    88 	}
    89 
    90 	if (mime_type == MAILMIME_MULTIPLE) {
    91 		char * attr_name;
    92 		char * attr_value;
    93 		struct mailmime_parameter * param;
    94 		clist * parameters;
    95 		char * boundary;
    96 
    97 		list = clist_new();
    98 		if (list == NULL)
    99 			goto err;
   100 
   101 		attr_name = strdup("boundary");
   102 		boundary = generate_boundary(boundary_prefix);
   103 		attr_value = boundary;
   104 		if (attr_name == NULL) {
   105 			free(attr_name);
   106 			goto free_list;
   107 		}
   108 
   109 		param = mailmime_parameter_new(attr_name, attr_value);
   110 		if (param == NULL) {
   111 			free(attr_value);
   112 			free(attr_name);
   113 			goto free_list;
   114 		}
   115 
   116 		if (content->ct_parameters == NULL) {
   117 			parameters = clist_new();
   118 			if (parameters == NULL) {
   119 				mailmime_parameter_free(param);
   120 				goto free_list;
   121 			}
   122 		}
   123 		else
   124 			parameters = content->ct_parameters;
   125 
   126 		r = clist_append(parameters, param);
   127 		if (r != 0) {
   128 			clist_free(parameters);
   129 			mailmime_parameter_free(param);
   130 			goto free_list;
   131 		}
   132 
   133 		if (content->ct_parameters == NULL)
   134 			content->ct_parameters = parameters;
   135 	}
   136 
   137 	build_info = mailmime_new(mime_type,
   138 		NULL, 0, mime_fields, content,
   139 		NULL, NULL, NULL, list,
   140 		NULL, NULL);
   141 	if (build_info == NULL) {
   142 		clist_free(list);
   143 		return NULL;
   144 	}
   145 
   146 	return build_info;
   147 
   148 	free_list:
   149 	clist_free(list);
   150 	err:
   151 	return NULL;
   152 }
   153 
   154 struct mailmime * get_text_part(
   155         const char * mime_type,
   156         const char * text,
   157         size_t length,
   158         int encoding_type
   159     )
   160 {
   161 	struct mailmime_fields * mime_fields;
   162 	struct mailmime * mime;
   163 	struct mailmime_content * content;
   164 	struct mailmime_parameter * param;
   165 	struct mailmime_disposition * disposition;
   166 	struct mailmime_mechanism * encoding;
   167     
   168 	encoding = mailmime_mechanism_new(encoding_type, NULL);
   169 	disposition = mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
   170 		NULL, NULL, NULL, NULL, (size_t) -1);
   171 	mime_fields = mailmime_fields_new_with_data(encoding,
   172 		NULL, NULL, disposition, NULL);
   173 
   174 	content = mailmime_content_new_with_str(mime_type);
   175 	param = mailmime_param_new_with_data("charset", "utf-8");
   176 	clist_append(content->ct_parameters, param);
   177 	mime = part_new_empty(content, mime_fields, NULL, 1);
   178 	mailmime_set_body_text(mime, (char *) text, length);
   179 	
   180 	return mime;
   181 }
   182 
   183 struct mailmime * get_file_part(
   184         const char * filename,
   185         const char * mime_type,
   186         char * data,
   187         size_t length
   188     )
   189 {
   190     char * disposition_name;
   191     int encoding_type;
   192     struct mailmime_disposition * disposition;
   193     struct mailmime_mechanism * encoding;
   194     struct mailmime_content * content;
   195     struct mailmime * mime;
   196     struct mailmime_fields * mime_fields;
   197 
   198     disposition_name = NULL;
   199     if (filename != NULL) {
   200         disposition_name = strdup(filename);
   201     }
   202     disposition =
   203         mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_ATTACHMENT,
   204                 disposition_name, NULL, NULL, NULL, (size_t) -1);
   205     content = mailmime_content_new_with_str(mime_type);
   206 
   207     encoding_type = MAILMIME_MECHANISM_BASE64;
   208     encoding = mailmime_mechanism_new(encoding_type, NULL);
   209     mime_fields = mailmime_fields_new_with_data(encoding,
   210         NULL, NULL, disposition, NULL);
   211     mime = part_new_empty(content, mime_fields, NULL, 1);
   212     mailmime_set_body_text(mime, data, length);
   213 
   214     return mime;
   215 }
   216 
   217 struct mailmime * part_multiple_new(
   218         const char * type,
   219         const char * boundary_prefix
   220     )
   221 {
   222     struct mailmime_fields * mime_fields;
   223     struct mailmime_content * content;
   224     struct mailmime * mp;
   225     
   226     mime_fields = mailmime_fields_new_empty();
   227     if (mime_fields == NULL)
   228         goto err;
   229     
   230     content = mailmime_content_new_with_str(type);
   231     if (content == NULL)
   232         goto free_fields;
   233     
   234     mp = part_new_empty(content, mime_fields, boundary_prefix, 0);
   235     if (mp == NULL)
   236         goto free_content;
   237     
   238     return mp;
   239     
   240 free_content:
   241     mailmime_content_free(content);
   242 free_fields:
   243     mailmime_fields_free(mime_fields);
   244 err:
   245     return NULL;
   246 }
   247 
   248 struct mailimf_field * _new_field(
   249         int type,
   250         _new_func_t new_func,
   251         void *value
   252     )
   253 {
   254     void *data = new_func(value);
   255     assert(data);
   256     if (data == NULL)
   257         return NULL;
   258 
   259     struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
   260     assert(result);
   261     if (result == NULL) {
   262         free(data);
   263         return NULL;
   264     }
   265 
   266     result->fld_type = type;
   267     result->fld_data.fld_return_path = data;
   268 
   269     return result;
   270 }
   271 
   272 void _free_field(struct mailimf_field *field)
   273 {
   274     if (field)
   275         free(field->fld_data.fld_return_path);
   276     free(field);
   277 }
   278 
   279 int _append_field(
   280         clist *list,
   281         int type,
   282         _new_func_t new_func,
   283         void *value
   284     )
   285 {
   286     int r;
   287     struct mailimf_field * field;
   288 
   289     assert(list);
   290     assert(new_func);
   291     assert(value);
   292 
   293     field = _new_field(type, new_func, value);
   294     if (field == NULL)
   295         return -1;
   296 
   297 
   298     r = clist_append(list, field);
   299     if (r == -1)
   300         _free_field(field);
   301 
   302     return r;
   303 }
   304 
   305 struct mailimf_date_time * timestamp_to_etpantime(const struct tm *ts)
   306 {
   307     struct mailimf_date_time * result = calloc(1,
   308             sizeof(struct mailimf_date_time));
   309     assert(result);
   310     if (result == NULL)
   311         return NULL;
   312 
   313     assert(ts);
   314 
   315     result->dt_sec = ts->tm_sec;
   316     result->dt_min = ts->tm_min;
   317     result->dt_hour = ts->tm_hour;
   318     result->dt_day = ts->tm_mday;
   319     result->dt_month = ts->tm_mon + 1;
   320     result->dt_year = ts->tm_year + 1900;
   321     result->dt_zone = (int) (ts->tm_gmtoff / 36L);
   322 
   323     return result;
   324 }
   325 
   326 struct tm * etpantime_to_timestamp(const struct mailimf_date_time *et)
   327 {
   328     struct tm * result = calloc(1, sizeof(struct tm));
   329     assert(result);
   330     if (result == NULL)
   331         return NULL;
   332 
   333     assert(et);
   334 
   335     result->tm_sec = et->dt_sec;
   336     result->tm_min = et->dt_min;
   337     result->tm_hour = et->dt_hour;
   338     result->tm_mday = et->dt_day;
   339     result->tm_mon = et->dt_month - 1;
   340     result->tm_year = et->dt_year - 1900;
   341     result->tm_gmtoff = 36L * (long) et->dt_zone;
   342 
   343     return result;
   344 }
   345