src/etpan_mime.c
author vb
Sun, 08 Mar 2015 00:35:18 +0100
changeset 90 42b5eb9d5af2
parent 89 aef5a4bc78f3
child 92 c9be62386ffb
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@48
   149
struct mailmime * get_text_part(
vb@48
   150
        const char * mime_type,
vb@48
   151
        const char * text,
vb@48
   152
        size_t length,
vb@48
   153
        int encoding_type
vb@48
   154
    )
vb@48
   155
{
vb@48
   156
	struct mailmime_fields * mime_fields;
vb@48
   157
	struct mailmime * mime;
vb@48
   158
	struct mailmime_content * content;
vb@48
   159
	struct mailmime_parameter * param;
vb@48
   160
	struct mailmime_disposition * disposition;
vb@48
   161
	struct mailmime_mechanism * encoding;
vb@48
   162
    
vb@48
   163
	encoding = mailmime_mechanism_new(encoding_type, NULL);
vb@48
   164
	disposition = mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
vb@48
   165
		NULL, NULL, NULL, NULL, (size_t) -1);
vb@48
   166
	mime_fields = mailmime_fields_new_with_data(encoding,
vb@48
   167
		NULL, NULL, disposition, NULL);
vb@48
   168
vb@48
   169
	content = mailmime_content_new_with_str(mime_type);
vb@48
   170
	param = mailmime_param_new_with_data("charset", "utf-8");
vb@48
   171
	clist_append(content->ct_parameters, param);
vb@48
   172
	mime = part_new_empty(content, mime_fields, NULL, 1);
vb@48
   173
	mailmime_set_body_text(mime, (char *) text, length);
vb@48
   174
	
vb@48
   175
	return mime;
vb@48
   176
}
vb@48
   177
vb@59
   178
struct mailmime * get_file_part(
vb@59
   179
        const char * filename,
vb@59
   180
        const char * mime_type,
vb@59
   181
        char * data,
vb@59
   182
        size_t length
vb@59
   183
    )
vb@59
   184
{
vb@59
   185
    char * disposition_name;
vb@59
   186
    int encoding_type;
vb@59
   187
    struct mailmime_disposition * disposition;
vb@59
   188
    struct mailmime_mechanism * encoding;
vb@59
   189
    struct mailmime_content * content;
vb@59
   190
    struct mailmime * mime;
vb@59
   191
    struct mailmime_fields * mime_fields;
vb@59
   192
vb@59
   193
    disposition_name = NULL;
vb@59
   194
    if (filename != NULL) {
vb@59
   195
        disposition_name = strdup(filename);
vb@59
   196
    }
vb@59
   197
    disposition =
vb@59
   198
        mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_ATTACHMENT,
vb@59
   199
                disposition_name, NULL, NULL, NULL, (size_t) -1);
vb@59
   200
    content = mailmime_content_new_with_str(mime_type);
vb@59
   201
vb@59
   202
    encoding_type = MAILMIME_MECHANISM_BASE64;
vb@59
   203
    encoding = mailmime_mechanism_new(encoding_type, NULL);
vb@59
   204
    mime_fields = mailmime_fields_new_with_data(encoding,
vb@59
   205
        NULL, NULL, disposition, NULL);
vb@59
   206
    mime = part_new_empty(content, mime_fields, NULL, 1);
vb@59
   207
    mailmime_set_body_text(mime, data, length);
vb@59
   208
vb@59
   209
    return mime;
vb@59
   210
}
vb@59
   211
vb@48
   212
struct mailmime * part_multiple_new(
vb@48
   213
        const char * type,
vb@48
   214
        const char * boundary_prefix
vb@48
   215
    )
vb@48
   216
{
vb@48
   217
    struct mailmime_fields * mime_fields;
vb@48
   218
    struct mailmime_content * content;
vb@48
   219
    struct mailmime * mp;
vb@48
   220
    
vb@48
   221
    mime_fields = mailmime_fields_new_empty();
vb@48
   222
    if (mime_fields == NULL)
vb@48
   223
        goto err;
vb@48
   224
    
vb@48
   225
    content = mailmime_content_new_with_str(type);
vb@48
   226
    if (content == NULL)
vb@48
   227
        goto free_fields;
vb@48
   228
    
vb@48
   229
    mp = part_new_empty(content, mime_fields, boundary_prefix, 0);
vb@48
   230
    if (mp == NULL)
vb@48
   231
        goto free_content;
vb@48
   232
    
vb@48
   233
    return mp;
vb@48
   234
    
vb@48
   235
free_content:
vb@48
   236
    mailmime_content_free(content);
vb@48
   237
free_fields:
vb@48
   238
    mailmime_fields_free(mime_fields);
vb@48
   239
err:
vb@48
   240
    return NULL;
vb@48
   241
}
vb@48
   242
vb@89
   243
struct mailimf_field * _new_field(
vb@89
   244
        int type,
vb@89
   245
        _new_func_t new_func,
vb@89
   246
        void *value
vb@89
   247
    )
vb@89
   248
{
vb@89
   249
    void *data = new_func(value);
vb@89
   250
    assert(data);
vb@89
   251
    if (data == NULL)
vb@89
   252
        return NULL;
vb@89
   253
vb@89
   254
    struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
vb@89
   255
    assert(result);
vb@89
   256
    if (result == NULL) {
vb@89
   257
        free(data);
vb@89
   258
        return NULL;
vb@89
   259
    }
vb@89
   260
vb@89
   261
    result->fld_type = type;
vb@89
   262
    result->fld_data.fld_return_path = data;
vb@89
   263
vb@89
   264
    return result;
vb@89
   265
}
vb@89
   266
vb@89
   267
void _free_field(struct mailimf_field *field)
vb@89
   268
{
vb@89
   269
    if (field)
vb@89
   270
        free(field->fld_data.fld_return_path);
vb@89
   271
    free(field);
vb@89
   272
}
vb@89
   273
vb@89
   274
int _append_field(
vb@89
   275
        clist *list,
vb@89
   276
        int type,
vb@89
   277
        _new_func_t new_func,
vb@89
   278
        void *value
vb@89
   279
    )
vb@89
   280
{
vb@89
   281
    int r;
vb@89
   282
    struct mailimf_field * field;
vb@89
   283
vb@89
   284
    assert(list);
vb@89
   285
    assert(new_func);
vb@89
   286
    assert(value);
vb@89
   287
vb@89
   288
    field = _new_field(type, new_func, value);
vb@89
   289
    if (field == NULL)
vb@89
   290
        return -1;
vb@89
   291
vb@89
   292
    r = clist_append(list, field);
vb@90
   293
    if (r)
vb@89
   294
        _free_field(field);
vb@89
   295
vb@89
   296
    return r;
vb@89
   297
}
vb@89
   298
vb@89
   299
struct mailimf_date_time * timestamp_to_etpantime(const struct tm *ts)
vb@89
   300
{
vb@89
   301
    struct mailimf_date_time * result = calloc(1,
vb@89
   302
            sizeof(struct mailimf_date_time));
vb@89
   303
    assert(result);
vb@89
   304
    if (result == NULL)
vb@89
   305
        return NULL;
vb@89
   306
vb@89
   307
    assert(ts);
vb@89
   308
vb@89
   309
    result->dt_sec = ts->tm_sec;
vb@89
   310
    result->dt_min = ts->tm_min;
vb@89
   311
    result->dt_hour = ts->tm_hour;
vb@89
   312
    result->dt_day = ts->tm_mday;
vb@89
   313
    result->dt_month = ts->tm_mon + 1;
vb@89
   314
    result->dt_year = ts->tm_year + 1900;
vb@89
   315
    result->dt_zone = (int) (ts->tm_gmtoff / 36L);
vb@89
   316
vb@89
   317
    return result;
vb@89
   318
}
vb@89
   319
vb@89
   320
struct tm * etpantime_to_timestamp(const struct mailimf_date_time *et)
vb@89
   321
{
vb@89
   322
    struct tm * result = calloc(1, sizeof(struct tm));
vb@89
   323
    assert(result);
vb@89
   324
    if (result == NULL)
vb@89
   325
        return NULL;
vb@89
   326
vb@89
   327
    assert(et);
vb@89
   328
vb@89
   329
    result->tm_sec = et->dt_sec;
vb@89
   330
    result->tm_min = et->dt_min;
vb@89
   331
    result->tm_hour = et->dt_hour;
vb@89
   332
    result->tm_mday = et->dt_day;
vb@89
   333
    result->tm_mon = et->dt_month - 1;
vb@89
   334
    result->tm_year = et->dt_year - 1900;
vb@89
   335
    result->tm_gmtoff = 36L * (long) et->dt_zone;
vb@89
   336
vb@89
   337
    return result;
vb@89
   338
}
vb@89
   339
vb@90
   340
struct mailimf_mailbox * mailbox_from_string(
vb@90
   341
        const char *name,
vb@90
   342
        const char *address
vb@90
   343
    )
vb@90
   344
{
vb@90
   345
    struct mailimf_mailbox *mb = NULL;
vb@90
   346
    char *_name = NULL;
vb@90
   347
    char *_address = NULL;
vb@90
   348
vb@90
   349
    assert(address);
vb@90
   350
vb@90
   351
    _name = name ? strdup(name) : strdup("");
vb@90
   352
    if (_name == NULL)
vb@90
   353
        goto enomem;
vb@90
   354
vb@90
   355
    _address = strdup(address);
vb@90
   356
    if (_address == NULL)
vb@90
   357
        goto enomem;
vb@90
   358
vb@90
   359
    mb = mailimf_mailbox_new(_name, _address);
vb@90
   360
    assert(mb);
vb@90
   361
    if (mb == NULL)
vb@90
   362
        goto enomem;
vb@90
   363
vb@90
   364
    return mb;
vb@90
   365
vb@90
   366
enomem:
vb@90
   367
    free(_name);
vb@90
   368
    free(_address);
vb@90
   369
vb@90
   370
    return NULL;
vb@90
   371
}
vb@90
   372