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