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