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