src/etpan_mime.c
author Krista Bennett <krista@pep-project.org>
Mon, 12 Mar 2018 02:57:10 +0100
branchENGINE-400
changeset 2563 95183ae74227
parent 2562 a381a9bd101c
child 2579 cc878b3193a6
permissions -rw-r--r--
Fixed bug in unicode byte detection
vb@1513
     1
// This file is under GNU General Public License 3.0
vb@1513
     2
// see LICENSE.txt
vb@1513
     3
vb@48
     4
#include "etpan_mime.h"
vb@62
     5
#ifndef mailmime_param_new_with_data
vb@62
     6
#include <libetpan/mailprivacy_tools.h>
vb@62
     7
#endif
vb@48
     8
vb@130
     9
#include "platform.h"
vb@130
    10
vb@130
    11
#include <string.h>
vb@130
    12
#include <stdlib.h>
vb@130
    13
#include <assert.h>
vb@157
    14
#include <errno.h>
vb@89
    15
roker@438
    16
#define MAX_MESSAGE_ID 128
vb@48
    17
vb@116
    18
static char * generate_boundary(void)
vb@48
    19
{
vb@48
    20
    char id[MAX_MESSAGE_ID];
vb@54
    21
roker@438
    22
    // no cryptographically strong random needed here
roker@438
    23
    const long value1 = random();
roker@438
    24
    const long value2 = random();
roker@438
    25
    const long value3 = random();
roker@438
    26
    const long value4 = random();
vb@90
    27
vb@116
    28
    snprintf(id, MAX_MESSAGE_ID, "%.4lx%.4lx%.4lx%.4lx", value1, value2,
vb@116
    29
            value3, value4);
vb@48
    30
    
vb@48
    31
    return strdup(id);
vb@48
    32
}
vb@48
    33
vb@48
    34
struct mailmime * part_new_empty(
vb@48
    35
        struct mailmime_content * content,
vb@48
    36
        struct mailmime_fields * mime_fields,
vb@48
    37
        int force_single
vb@48
    38
    )
vb@48
    39
{
vb@48
    40
	struct mailmime * build_info;
vb@115
    41
	clist * list = NULL;
vb@48
    42
	int r;
vb@48
    43
	int mime_type;
vb@115
    44
    char * attr_name = NULL;
vb@115
    45
    char * attr_value = NULL;
vb@115
    46
    struct mailmime_parameter * param = NULL;
vb@115
    47
    clist * parameters = NULL;
vb@116
    48
    char *boundary = NULL;
vb@48
    49
vb@48
    50
	list = NULL;
vb@48
    51
vb@48
    52
	if (force_single) {
vb@48
    53
		mime_type = MAILMIME_SINGLE;
vb@48
    54
	}
vb@48
    55
	else {
vb@48
    56
		switch (content->ct_type->tp_type) {
vb@48
    57
			case MAILMIME_TYPE_DISCRETE_TYPE:
vb@115
    58
                mime_type = MAILMIME_SINGLE;
vb@115
    59
                break;
vb@48
    60
vb@48
    61
			case MAILMIME_TYPE_COMPOSITE_TYPE:
vb@115
    62
                switch (content->ct_type->tp_data.tp_composite_type->ct_type) {
vb@115
    63
                    case MAILMIME_COMPOSITE_TYPE_MULTIPART:
vb@115
    64
                        mime_type = MAILMIME_MULTIPLE;
vb@115
    65
                        break;
vb@48
    66
vb@115
    67
                    case MAILMIME_COMPOSITE_TYPE_MESSAGE:
vb@115
    68
                        if (strcasecmp(content->ct_subtype, "rfc822") == 0)
vb@115
    69
                            mime_type = MAILMIME_MESSAGE;
vb@115
    70
                        else
vb@115
    71
                            mime_type = MAILMIME_SINGLE;
vb@115
    72
                        break;
vb@48
    73
vb@115
    74
                    default:
vb@115
    75
                        goto enomem;
vb@115
    76
                }
vb@115
    77
                break;
vb@48
    78
vb@48
    79
			default:
vb@115
    80
                goto enomem;
vb@48
    81
		}
vb@48
    82
	}
vb@48
    83
vb@48
    84
	if (mime_type == MAILMIME_MULTIPLE) {
vb@48
    85
		list = clist_new();
vb@115
    86
        assert(list);
vb@48
    87
		if (list == NULL)
vb@115
    88
			goto enomem;
vb@48
    89
vb@48
    90
		attr_name = strdup("boundary");
vb@115
    91
        assert(attr_name);
vb@115
    92
        if (attr_name == NULL)
vb@115
    93
            goto enomem;
vb@115
    94
vb@116
    95
		boundary = generate_boundary();
vb@115
    96
        assert(boundary);
vb@48
    97
		attr_value = boundary;
vb@115
    98
		if (attr_value == NULL)
vb@115
    99
			goto enomem;
vb@48
   100
vb@48
   101
		param = mailmime_parameter_new(attr_name, attr_value);
vb@115
   102
        assert(param);
vb@115
   103
		if (param == NULL)
vb@115
   104
			goto enomem;
vb@115
   105
        attr_name = NULL;
vb@115
   106
        attr_value = NULL;
vb@48
   107
vb@48
   108
		if (content->ct_parameters == NULL) {
vb@48
   109
			parameters = clist_new();
vb@115
   110
            assert(parameters);
vb@115
   111
			if (parameters == NULL)
vb@115
   112
				goto enomem;
vb@48
   113
		}
vb@115
   114
		else {
vb@48
   115
			parameters = content->ct_parameters;
vb@115
   116
        }
vb@48
   117
vb@48
   118
		r = clist_append(parameters, param);
vb@115
   119
		if (r)
vb@115
   120
			goto enomem;
vb@115
   121
        param = NULL;
vb@48
   122
vb@48
   123
		if (content->ct_parameters == NULL)
vb@48
   124
			content->ct_parameters = parameters;
vb@48
   125
	}
vb@48
   126
vb@115
   127
    build_info = mailmime_new(mime_type, NULL, 0, mime_fields, content, NULL,
vb@115
   128
            NULL, NULL, list, NULL, NULL);
vb@115
   129
	if (build_info == NULL)
vb@115
   130
		goto enomem;
vb@48
   131
vb@48
   132
	return build_info;
vb@48
   133
vb@115
   134
enomem:
vb@115
   135
    if (list)
vb@115
   136
        clist_free(list);
vb@115
   137
    free(attr_name);
vb@115
   138
    free(attr_value);
vb@115
   139
    if (content->ct_parameters == NULL)
vb@115
   140
        if (parameters)
vb@115
   141
            clist_free(parameters);
krista@819
   142
    if (param)
krista@819
   143
        mailmime_parameter_free(param);
vb@48
   144
	return NULL;
vb@48
   145
}
vb@48
   146
vb@114
   147
struct mailmime * get_pgp_encrypted_part(void)
vb@114
   148
{
vb@115
   149
	struct mailmime * mime = NULL;
vb@115
   150
	struct mailmime_fields * mime_fields = NULL;
vb@115
   151
	struct mailmime_content * content = NULL;
vb@115
   152
    int r;
vb@114
   153
vb@114
   154
	content = mailmime_content_new_with_str("application/pgp-encrypted");
vb@115
   155
    if (content == NULL)
vb@115
   156
        goto enomem;
vb@115
   157
vb@114
   158
    mime_fields = mailmime_fields_new_empty();
vb@115
   159
    if (mime_fields == NULL)
vb@115
   160
        goto enomem;
vb@115
   161
vb@116
   162
	mime = part_new_empty(content, mime_fields, 1);
vb@115
   163
    if (mime == NULL)
vb@115
   164
        goto enomem;
vb@115
   165
    mime_fields = NULL;
vb@115
   166
    content = NULL;
vb@115
   167
vb@115
   168
    r = mailmime_set_body_text(mime, "Version: 1\n", 10);
vb@115
   169
    if (r != 0)
vb@115
   170
        goto enomem;
vb@114
   171
vb@114
   172
	return mime;
vb@115
   173
vb@115
   174
enomem:
vb@115
   175
    if (content)
vb@115
   176
        mailmime_content_free(content);
vb@115
   177
    if (mime_fields)
vb@115
   178
        mailmime_fields_free(mime_fields);
vb@115
   179
    if (mime)
vb@115
   180
        mailmime_free(mime);
vb@115
   181
vb@115
   182
    return NULL;
vb@114
   183
}
vb@114
   184
vb@48
   185
struct mailmime * get_text_part(
krista@1878
   186
        pEp_rid_list_t* resource,
vb@48
   187
        const char * mime_type,
vb@48
   188
        const char * text,
vb@48
   189
        size_t length,
vb@48
   190
        int encoding_type
vb@48
   191
    )
vb@48
   192
{
vb@114
   193
    char * disposition_name = NULL;
vb@115
   194
	struct mailmime_fields * mime_fields = NULL;
vb@115
   195
	struct mailmime * mime = NULL;
vb@115
   196
	struct mailmime_content * content = NULL;
vb@115
   197
	struct mailmime_parameter * param = NULL;
vb@115
   198
	struct mailmime_disposition * disposition = NULL;
vb@114
   199
	struct mailmime_mechanism * encoding = NULL;
krista@1878
   200
    char* content_id = NULL;
vb@115
   201
    int r;
krista@1878
   202
                
krista@1878
   203
    if (resource != NULL && resource->rid != NULL) {
krista@1878
   204
        switch (resource->rid_type) {
krista@1878
   205
            case PEP_RID_CID:
krista@1878
   206
                content_id = strdup(resource->rid);
krista@1878
   207
                break;
krista@1878
   208
            case PEP_RID_FILENAME:
krista@1878
   209
            default:
krista@1878
   210
                disposition_name = strdup(resource->rid);
krista@1878
   211
                if (disposition_name == NULL)
krista@1878
   212
                    goto enomem;
krista@1878
   213
                    
krista@1878
   214
                disposition =
krista@1878
   215
                        mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
krista@1878
   216
                                disposition_name, NULL, NULL, NULL, (size_t) -1);
krista@1878
   217
krista@1878
   218
                if (disposition == NULL)
krista@1878
   219
                    goto enomem;
krista@1878
   220
krista@1878
   221
                disposition_name = NULL;                
krista@1878
   222
                break;
krista@1878
   223
        }    
krista@1878
   224
    }
vb@48
   225
    
vb@115
   226
    if (encoding_type) {
vb@114
   227
        encoding = mailmime_mechanism_new(encoding_type, NULL);
vb@115
   228
        if (encoding == NULL)
vb@115
   229
            goto enomem;
vb@115
   230
    }
vb@114
   231
krista@1878
   232
    mime_fields = mailmime_fields_new_with_data(encoding, content_id, NULL,
vb@115
   233
            disposition, NULL);
vb@115
   234
    if (mime_fields == NULL)
vb@115
   235
        goto enomem;
vb@115
   236
    encoding = NULL;
vb@115
   237
    disposition = NULL;
krista@1878
   238
    content_id = NULL;
vb@48
   239
vb@48
   240
	content = mailmime_content_new_with_str(mime_type);
vb@115
   241
    if (content == NULL)
vb@115
   242
        goto enomem;
vb@114
   243
    
vb@114
   244
    if (encoding_type != MAILMIME_MECHANISM_7BIT) {
vb@114
   245
        param = mailmime_param_new_with_data("charset", "utf-8");
vb@115
   246
        r = clist_append(content->ct_parameters, param);
vb@115
   247
        if (r != 0)
vb@115
   248
            goto enomem;
vb@114
   249
    }
vb@114
   250
vb@116
   251
	mime = part_new_empty(content, mime_fields, 1);
vb@115
   252
    if (mime == NULL)
vb@115
   253
        goto enomem;
vb@115
   254
    content = NULL;
vb@115
   255
    mime_fields = NULL;
vb@114
   256
vb@115
   257
    if (text) {
vb@115
   258
        r = mailmime_set_body_text(mime, (char *) text, length);
vb@115
   259
        if (r != 0)
vb@115
   260
            goto enomem;
vb@115
   261
    }
vb@48
   262
	
vb@48
   263
	return mime;
vb@115
   264
vb@115
   265
enomem:
vb@115
   266
    free(disposition_name);
vb@115
   267
    if (mime_fields)
vb@115
   268
        mailmime_fields_free(mime_fields);
vb@115
   269
    if (mime)
vb@115
   270
        mailmime_free(mime);
vb@115
   271
    if (content)
vb@115
   272
        mailmime_content_free(content);
vb@115
   273
    if (param)
vb@115
   274
        mailmime_parameter_free(param);
vb@115
   275
    if (disposition)
vb@115
   276
        mailmime_disposition_free(disposition);
vb@115
   277
    if (encoding)
vb@115
   278
        mailmime_mechanism_free(encoding);
vb@115
   279
vb@115
   280
    return NULL;
vb@48
   281
}
vb@48
   282
vb@59
   283
struct mailmime * get_file_part(
krista@1878
   284
        pEp_rid_list_t* resource,
vb@59
   285
        const char * mime_type,
vb@59
   286
        char * data,
krista@2200
   287
        size_t length,
krista@2200
   288
        bool transport_encode
vb@59
   289
    )
vb@59
   290
{
vb@115
   291
    char * disposition_name = NULL;
vb@59
   292
    int encoding_type;
vb@115
   293
    struct mailmime_disposition * disposition = NULL;
vb@115
   294
    struct mailmime_mechanism * encoding = NULL;
vb@115
   295
    struct mailmime_content * content = NULL;
vb@115
   296
    struct mailmime * mime = NULL;
vb@115
   297
    struct mailmime_fields * mime_fields = NULL;
krista@1878
   298
    char* content_id = NULL;
vb@115
   299
    int r;
krista@1878
   300
                
krista@1878
   301
    if (resource != NULL && resource->rid != NULL) {
krista@1878
   302
        switch (resource->rid_type) {
krista@1878
   303
            case PEP_RID_CID:
krista@1878
   304
                content_id = strdup(resource->rid);
krista@2011
   305
                disposition =
krista@2011
   306
                    mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
krista@2011
   307
                                                       NULL, NULL, NULL, NULL, (size_t) -1);
krista@2011
   308
                    if (disposition == NULL)
krista@2011
   309
                        goto enomem;
krista@1878
   310
                break;
krista@1878
   311
            case PEP_RID_FILENAME:
krista@1878
   312
            default:
krista@1878
   313
                disposition_name = strdup(resource->rid);
krista@1878
   314
                if (disposition_name == NULL)
krista@1878
   315
                    goto enomem;
krista@1878
   316
                    
krista@1878
   317
                disposition =
krista@1878
   318
                        mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_ATTACHMENT,
krista@1878
   319
                                disposition_name, NULL, NULL, NULL, (size_t) -1);
krista@1878
   320
                                
krista@1878
   321
                if (disposition == NULL)
krista@1878
   322
                    goto enomem;
krista@1878
   323
                disposition_name = NULL;
krista@1878
   324
                
krista@1878
   325
                break;
krista@1878
   326
        }    
vb@59
   327
    }
krista@1878
   328
    
vb@115
   329
vb@59
   330
    content = mailmime_content_new_with_str(mime_type);
vb@115
   331
    if (content == NULL)
vb@115
   332
        goto enomem;
vb@59
   333
krista@2200
   334
    encoding = NULL;
krista@2200
   335
krista@2200
   336
    if (transport_encode) {
krista@2200
   337
        encoding_type = MAILMIME_MECHANISM_BASE64;
krista@2200
   338
        encoding = mailmime_mechanism_new(encoding_type, NULL);
krista@2200
   339
        if (encoding == NULL)
krista@2200
   340
            goto enomem;
krista@2200
   341
    }
vb@115
   342
krista@1878
   343
    mime_fields = mailmime_fields_new_with_data(encoding, content_id, NULL,
vb@115
   344
            disposition, NULL);
vb@115
   345
    if (mime_fields == NULL)
vb@115
   346
        goto enomem;
vb@115
   347
    encoding = NULL;
vb@115
   348
    disposition = NULL;
vb@115
   349
vb@116
   350
    mime = part_new_empty(content, mime_fields, 1);
vb@115
   351
    if (mime == NULL)
vb@115
   352
        goto enomem;
vb@115
   353
    content = NULL;
vb@115
   354
    mime_fields = NULL;
vb@115
   355
Edouard@747
   356
    if(length > 0)
Edouard@747
   357
    {
Edouard@747
   358
        r = mailmime_set_body_text(mime, data, length);
Edouard@747
   359
        if (r != 0)
Edouard@747
   360
            goto enomem;
Edouard@747
   361
    }
vb@59
   362
vb@59
   363
    return mime;
vb@115
   364
vb@115
   365
enomem:
vb@115
   366
    free(disposition_name);
vb@115
   367
    if (disposition)
vb@115
   368
        mailmime_disposition_free(disposition);
vb@115
   369
    if (encoding)
vb@115
   370
        mailmime_mechanism_free(encoding);
vb@115
   371
    if (content)
vb@115
   372
        mailmime_content_free(content);
vb@115
   373
    if (mime_fields)
vb@115
   374
        mailmime_fields_free(mime_fields);
vb@115
   375
    if (mime)
vb@115
   376
        mailmime_free(mime);
krista@1878
   377
    
vb@115
   378
    return NULL;
vb@59
   379
}
vb@59
   380
vb@116
   381
struct mailmime * part_multiple_new(const char *type)
vb@48
   382
{
vb@115
   383
    struct mailmime_fields *mime_fields = NULL;
vb@115
   384
    struct mailmime_content *content = NULL;
vb@115
   385
    struct mailmime *mp = NULL;
vb@48
   386
    
vb@48
   387
    mime_fields = mailmime_fields_new_empty();
vb@48
   388
    if (mime_fields == NULL)
vb@115
   389
        goto enomem;
vb@48
   390
    
vb@48
   391
    content = mailmime_content_new_with_str(type);
vb@48
   392
    if (content == NULL)
vb@115
   393
        goto enomem;
vb@48
   394
    
vb@116
   395
    mp = part_new_empty(content, mime_fields, 0);
vb@48
   396
    if (mp == NULL)
vb@115
   397
        goto enomem;
vb@48
   398
    
vb@48
   399
    return mp;
vb@48
   400
    
vb@115
   401
enomem:
vb@115
   402
    if (content)
vb@115
   403
        mailmime_content_free(content);
vb@115
   404
    if (mime_fields)
vb@115
   405
        mailmime_fields_free(mime_fields);
vb@115
   406
vb@48
   407
    return NULL;
vb@48
   408
}
vb@48
   409
vb@89
   410
struct mailimf_field * _new_field(
vb@89
   411
        int type,
vb@89
   412
        _new_func_t new_func,
vb@89
   413
        void *value
vb@89
   414
    )
vb@89
   415
{
vb@89
   416
    void *data = new_func(value);
vb@89
   417
    assert(data);
vb@89
   418
    if (data == NULL)
vb@89
   419
        return NULL;
vb@89
   420
vb@89
   421
    struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
vb@89
   422
    assert(result);
vb@89
   423
    if (result == NULL) {
vb@89
   424
        free(data);
vb@89
   425
        return NULL;
vb@89
   426
    }
vb@89
   427
vb@89
   428
    result->fld_type = type;
vb@89
   429
    result->fld_data.fld_return_path = data;
vb@89
   430
vb@89
   431
    return result;
vb@89
   432
}
vb@89
   433
vb@89
   434
void _free_field(struct mailimf_field *field)
vb@89
   435
{
vb@89
   436
    if (field)
vb@89
   437
        free(field->fld_data.fld_return_path);
vb@89
   438
    free(field);
vb@89
   439
}
vb@89
   440
vb@89
   441
int _append_field(
vb@89
   442
        clist *list,
vb@89
   443
        int type,
vb@89
   444
        _new_func_t new_func,
vb@89
   445
        void *value
vb@89
   446
    )
vb@89
   447
{
vb@89
   448
    int r;
vb@89
   449
    struct mailimf_field * field;
vb@89
   450
vb@89
   451
    assert(list);
vb@89
   452
    assert(new_func);
vb@89
   453
    assert(value);
vb@89
   454
vb@89
   455
    field = _new_field(type, new_func, value);
vb@89
   456
    if (field == NULL)
vb@89
   457
        return -1;
vb@89
   458
vb@89
   459
    r = clist_append(list, field);
vb@90
   460
    if (r)
vb@89
   461
        _free_field(field);
vb@89
   462
vb@89
   463
    return r;
vb@89
   464
}
vb@89
   465
vb@92
   466
// http://media2.giga.de/2014/02/Image-28.jpg
vb@92
   467
vb@89
   468
struct mailimf_date_time * timestamp_to_etpantime(const struct tm *ts)
vb@89
   469
{
vb@89
   470
    struct mailimf_date_time * result = calloc(1,
vb@89
   471
            sizeof(struct mailimf_date_time));
vb@89
   472
    assert(result);
vb@89
   473
    if (result == NULL)
vb@89
   474
        return NULL;
vb@89
   475
vb@89
   476
    assert(ts);
vb@89
   477
vb@89
   478
    result->dt_sec = ts->tm_sec;
vb@89
   479
    result->dt_min = ts->tm_min;
vb@89
   480
    result->dt_hour = ts->tm_hour;
vb@89
   481
    result->dt_day = ts->tm_mday;
vb@89
   482
    result->dt_month = ts->tm_mon + 1;
vb@89
   483
    result->dt_year = ts->tm_year + 1900;
vb@130
   484
#ifndef WIN32
vb@89
   485
    result->dt_zone = (int) (ts->tm_gmtoff / 36L);
vb@130
   486
#endif
vb@89
   487
    return result;
vb@89
   488
}
vb@89
   489
vb@89
   490
struct tm * etpantime_to_timestamp(const struct mailimf_date_time *et)
vb@89
   491
{
vb@89
   492
    struct tm * result = calloc(1, sizeof(struct tm));
vb@89
   493
    assert(result);
vb@89
   494
    if (result == NULL)
vb@89
   495
        return NULL;
vb@89
   496
vb@89
   497
    assert(et);
vb@89
   498
vb@89
   499
    result->tm_sec = et->dt_sec;
vb@89
   500
    result->tm_min = et->dt_min;
vb@89
   501
    result->tm_hour = et->dt_hour;
vb@89
   502
    result->tm_mday = et->dt_day;
vb@89
   503
    result->tm_mon = et->dt_month - 1;
vb@89
   504
    result->tm_year = et->dt_year - 1900;
vb@130
   505
#ifndef WIN32
vb@89
   506
    result->tm_gmtoff = 36L * (long) et->dt_zone;
vb@130
   507
#endif
vb@89
   508
    return result;
vb@89
   509
}
vb@89
   510
vb@90
   511
struct mailimf_mailbox * mailbox_from_string(
vb@90
   512
        const char *name,
vb@90
   513
        const char *address
vb@90
   514
    )
vb@90
   515
{
vb@90
   516
    struct mailimf_mailbox *mb = NULL;
vb@90
   517
    char *_name = NULL;
vb@90
   518
    char *_address = NULL;
vb@90
   519
vb@90
   520
    assert(address);
vb@90
   521
vb@90
   522
    _name = name ? strdup(name) : strdup("");
vb@90
   523
    if (_name == NULL)
vb@90
   524
        goto enomem;
vb@90
   525
vb@90
   526
    _address = strdup(address);
vb@90
   527
    if (_address == NULL)
vb@90
   528
        goto enomem;
vb@90
   529
vb@90
   530
    mb = mailimf_mailbox_new(_name, _address);
vb@90
   531
    assert(mb);
vb@90
   532
    if (mb == NULL)
vb@90
   533
        goto enomem;
vb@90
   534
vb@90
   535
    return mb;
vb@90
   536
vb@90
   537
enomem:
vb@90
   538
    free(_name);
vb@90
   539
    free(_address);
vb@90
   540
vb@90
   541
    return NULL;
vb@90
   542
}
vb@90
   543
krista@2562
   544
vb@94
   545
struct mailimf_field * create_optional_field(
vb@94
   546
        const char *field,
vb@94
   547
        const char *value
vb@94
   548
    )
vb@94
   549
{
vb@94
   550
    char *_field = NULL;
vb@94
   551
    char *_value = NULL;
vb@94
   552
    struct mailimf_optional_field *optional_field = NULL;
vb@94
   553
vb@94
   554
    _field = strdup(field);
vb@94
   555
    if (_field == NULL)
vb@94
   556
        goto enomem;
vb@94
   557
krista@2562
   558
    if (!must_field_value_be_encoded(value))
krista@2562
   559
        _value = strdup(value);
krista@2562
   560
    else    
krista@2562
   561
        _value = mailmime_encode_subject_header("utf-8", value, 0);
vb@94
   562
    if (_value == NULL)
vb@94
   563
        goto enomem;
vb@94
   564
vb@94
   565
    optional_field = mailimf_optional_field_new(_field, _value);
vb@94
   566
    if (optional_field == NULL)
vb@94
   567
        goto enomem;
vb@94
   568
vb@94
   569
    struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
vb@94
   570
    assert(result);
vb@94
   571
    if (result == NULL)
vb@94
   572
        goto enomem;
vb@94
   573
vb@94
   574
    result->fld_type = MAILIMF_FIELD_OPTIONAL_FIELD;
vb@94
   575
    result->fld_data.fld_optional_field = optional_field;
vb@94
   576
vb@94
   577
    return result;
vb@94
   578
vb@94
   579
enomem:
vb@94
   580
    if (optional_field) {
vb@94
   581
        mailimf_optional_field_free(optional_field);
vb@94
   582
    }
vb@94
   583
    else {
vb@94
   584
        free(_field);
vb@94
   585
        free(_value);
vb@94
   586
    }
vb@94
   587
vb@94
   588
    return NULL;
vb@94
   589
}
vb@94
   590
vb@94
   591
int _append_optional_field(
vb@94
   592
        clist *list,
vb@94
   593
        const char *field,
vb@94
   594
        const char *value
vb@94
   595
    )
vb@94
   596
{
vb@94
   597
    int r;
vb@94
   598
    struct mailimf_field * optional_field =
vb@94
   599
            create_optional_field(field, value);
vb@94
   600
vb@94
   601
    if (optional_field == NULL)
vb@94
   602
        return -1;
vb@94
   603
vb@94
   604
    r = clist_append(list, optional_field);
vb@94
   605
    if (r)
vb@94
   606
        mailimf_field_free(optional_field);
vb@94
   607
vb@94
   608
    return r;
vb@94
   609
}
vb@94
   610
vb@147
   611
clist * _get_fields(struct mailmime * mime)
vb@147
   612
{
vb@147
   613
    clist * _fieldlist = NULL;
vb@147
   614
vb@147
   615
    assert(mime);
vb@147
   616
vb@147
   617
    if (mime->mm_data.mm_message.mm_fields &&
vb@147
   618
            mime->mm_data.mm_message.mm_fields->fld_list) {
vb@147
   619
        _fieldlist = mime->mm_data.mm_message.mm_fields->fld_list;
vb@147
   620
    }
vb@147
   621
vb@147
   622
    return _fieldlist;
vb@147
   623
}
vb@147
   624
vb@147
   625
struct mailmime_content * _get_content(struct mailmime * mime)
vb@147
   626
{
vb@147
   627
    struct mailmime_content * content = NULL;
vb@147
   628
vb@147
   629
    assert(mime);
vb@147
   630
vb@147
   631
    if (mime->mm_data.mm_message.mm_msg_mime)
vb@147
   632
        content = mime->mm_data.mm_message.mm_msg_mime->mm_content_type;
vb@147
   633
vb@147
   634
    return content;
vb@147
   635
}
vb@147
   636
krista@1872
   637
krista@1873
   638
/* Return a list of identifier_type and resource id (filename, cid, etc) */
krista@1873
   639
pEp_rid_list_t* _get_resource_id_list(struct mailmime *mime)
krista@1873
   640
{
krista@1873
   641
    clist * _fieldlist = NULL;
krista@1872
   642
krista@1873
   643
    assert(mime);
krista@1873
   644
krista@1873
   645
    if (mime->mm_mime_fields && mime->mm_mime_fields->fld_list)
krista@1873
   646
        _fieldlist = mime->mm_mime_fields->fld_list;
krista@1873
   647
    else
krista@1873
   648
        return NULL;
krista@1873
   649
krista@1873
   650
    clistiter *cur;
krista@1873
   651
krista@1873
   652
    pEp_rid_list_t* rid_list = NULL; 
krista@1873
   653
    pEp_rid_list_t** rid_list_curr_p = &rid_list; 
krista@1873
   654
        
krista@1873
   655
    for (cur = clist_begin(_fieldlist); cur; cur = clist_next(cur)) {
krista@1873
   656
        struct mailmime_field * _field = clist_content(cur);
krista@1873
   657
        /* content_id */
krista@1873
   658
        if (_field && _field->fld_type == MAILMIME_FIELD_ID) {
krista@1900
   659
            pEp_rid_list_t* new_rid = (pEp_rid_list_t*)calloc(1, sizeof(pEp_rid_list_t));
krista@1873
   660
            new_rid->rid_type = PEP_RID_CID;
krista@1900
   661
            new_rid->rid = strdup(_field->fld_data.fld_id);
krista@1873
   662
            *rid_list_curr_p = new_rid;
krista@1873
   663
            rid_list_curr_p = &new_rid->next;
krista@1873
   664
        }
krista@1873
   665
        else if (_field && _field->fld_type == MAILMIME_FIELD_DISPOSITION) {
krista@1873
   666
            /* filename */
krista@1873
   667
            if (_field->fld_data.fld_disposition &&
krista@1873
   668
                    _field->fld_data.fld_disposition->dsp_parms) {
krista@1873
   669
                clist * _parmlist =
krista@1873
   670
                        _field->fld_data.fld_disposition->dsp_parms;
krista@1873
   671
                clistiter *cur2;
krista@1873
   672
                for (cur2 = clist_begin(_parmlist); cur2; cur2 =
krista@1873
   673
                        clist_next(cur2)) {
krista@1873
   674
                    struct mailmime_disposition_parm * param =
krista@1873
   675
                            clist_content(cur2);
krista@1873
   676
                    if (param->pa_type == MAILMIME_DISPOSITION_PARM_FILENAME) {
krista@1900
   677
                        pEp_rid_list_t* new_rid = (pEp_rid_list_t*)calloc(1, sizeof(pEp_rid_list_t));
krista@1873
   678
                        new_rid->rid_type = PEP_RID_FILENAME;
krista@1900
   679
                        new_rid->rid = strdup(param->pa_data.pa_filename);
krista@1873
   680
                        *rid_list_curr_p = new_rid;
krista@1873
   681
                        rid_list_curr_p = &new_rid->next;
krista@1873
   682
                    }                
krista@1873
   683
                }
krista@1873
   684
            }
krista@1873
   685
        }
krista@1873
   686
    }
krista@1873
   687
    /* Will almost certainly usually be a singleton, but we need to be able to decide */
krista@1873
   688
    return rid_list;
krista@1873
   689
}
krista@1873
   690
krista@1873
   691
krista@1873
   692
/* FIXME: about to be obsoleted? */
krista@1872
   693
char * _get_filename_or_cid(struct mailmime *mime)
vb@154
   694
{
vb@154
   695
    clist * _fieldlist = NULL;
vb@154
   696
vb@154
   697
    assert(mime);
vb@154
   698
vb@154
   699
    if (mime->mm_mime_fields && mime->mm_mime_fields->fld_list)
vb@154
   700
        _fieldlist = mime->mm_mime_fields->fld_list;
vb@154
   701
    else
vb@154
   702
        return NULL;
vb@154
   703
vb@154
   704
    clistiter *cur;
krista@1873
   705
    
krista@1873
   706
    char* _temp_filename_ptr = NULL;
krista@1873
   707
    
vb@154
   708
    for (cur = clist_begin(_fieldlist); cur; cur = clist_next(cur)) {
vb@154
   709
        struct mailmime_field * _field = clist_content(cur);
krista@1873
   710
        if (_field && _field->fld_type == MAILMIME_FIELD_ID) {
krista@1873
   711
            /* We prefer CIDs to filenames when both are present */
krista@1873
   712
            free(_temp_filename_ptr); /* can be null, it's ok */
krista@1881
   713
            return build_uri("cid", _field->fld_data.fld_id); 
krista@1873
   714
        }
krista@1873
   715
        else if (_field && _field->fld_type == MAILMIME_FIELD_DISPOSITION) {
vb@154
   716
            if (_field->fld_data.fld_disposition &&
krista@1873
   717
                    _field->fld_data.fld_disposition->dsp_parms &&
krista@1873
   718
                    !_temp_filename_ptr) {
vb@154
   719
                clist * _parmlist =
vb@154
   720
                        _field->fld_data.fld_disposition->dsp_parms;
vb@154
   721
                clistiter *cur2;
vb@154
   722
                for (cur2 = clist_begin(_parmlist); cur2; cur2 =
vb@154
   723
                        clist_next(cur2)) {
vb@156
   724
                    struct mailmime_disposition_parm * param =
vb@156
   725
                            clist_content(cur2);
krista@1873
   726
                    if (param->pa_type == MAILMIME_DISPOSITION_PARM_FILENAME) {
krista@1881
   727
                        _temp_filename_ptr = build_uri("file", param->pa_data.pa_filename);
krista@1873
   728
                        break;
krista@1873
   729
                    }                
vb@154
   730
                }
vb@154
   731
            }
vb@154
   732
        }
vb@154
   733
    }
krista@1873
   734
    /* Ok, it wasn't a CID */
krista@1873
   735
    return _temp_filename_ptr;
vb@154
   736
}
vb@154
   737
vb@157
   738
static bool parameter_has_value(
vb@152
   739
        struct mailmime_content *content,       
vb@152
   740
        const char *name,
vb@152
   741
        const char *value
vb@152
   742
    )
vb@152
   743
{
vb@152
   744
    clistiter *cur;
vb@152
   745
vb@152
   746
    assert(name);
vb@152
   747
    assert(value);
vb@152
   748
vb@152
   749
    clist * list = content->ct_parameters;
vb@152
   750
    if (list == NULL)
vb@152
   751
        return false;
vb@152
   752
vb@152
   753
    for (cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
vb@152
   754
        struct mailmime_parameter * param = clist_content(cur);
vb@152
   755
        if (param &&
vb@165
   756
                param->pa_name && strcasecmp(name, param->pa_name) == 0 &&
vb@165
   757
                param->pa_value && strcasecmp(value, param->pa_value) == 0)
vb@152
   758
            return true;
vb@152
   759
    }
vb@152
   760
vb@152
   761
    return false;
vb@152
   762
}
vb@152
   763
vb@151
   764
bool _is_multipart(struct mailmime_content *content, const char *subtype)
vb@147
   765
{
vb@147
   766
    assert(content);
vb@147
   767
vb@147
   768
    if (content->ct_type && content->ct_type->tp_type ==
vb@147
   769
            MAILMIME_TYPE_COMPOSITE_TYPE &&
vb@147
   770
            content->ct_type->tp_data.tp_composite_type &&
vb@147
   771
            content->ct_type->tp_data.tp_composite_type->ct_type ==
vb@151
   772
            MAILMIME_COMPOSITE_TYPE_MULTIPART) {
vb@151
   773
        if (subtype)
vb@151
   774
            return content->ct_subtype &&
vb@165
   775
                    strcasecmp(content->ct_subtype, subtype) == 0;
vb@151
   776
        else
vb@151
   777
            return true;
vb@151
   778
    }
vb@147
   779
vb@151
   780
    return false;
vb@147
   781
}
vb@147
   782
vb@147
   783
bool _is_PGP_MIME(struct mailmime_content *content)
vb@147
   784
{
vb@147
   785
    assert(content);
vb@147
   786
vb@151
   787
    if (_is_multipart(content, "encrypted") &&
vb@152
   788
            parameter_has_value(content, "protocol",
vb@147
   789
                    "application/pgp-encrypted"))
vb@151
   790
        return true;
vb@147
   791
vb@151
   792
    return false;
vb@147
   793
}
vb@147
   794
vb@152
   795
bool _is_text_part(struct mailmime_content *content, const char *subtype)
vb@152
   796
{
vb@152
   797
    assert(content);
vb@152
   798
vb@153
   799
    if (content->ct_type && content->ct_type->tp_type ==
vb@153
   800
            MAILMIME_TYPE_DISCRETE_TYPE &&
vb@153
   801
            content->ct_type->tp_data.tp_discrete_type &&
vb@152
   802
            content->ct_type->tp_data.tp_discrete_type->dt_type ==
vb@152
   803
            MAILMIME_DISCRETE_TYPE_TEXT) {
vb@152
   804
        if (subtype)
vb@152
   805
            return content->ct_subtype &&
vb@165
   806
                    strcasecmp(content->ct_subtype, subtype) == 0;
vb@152
   807
        else
vb@152
   808
            return true;
vb@152
   809
    }
vb@152
   810
vb@152
   811
    return false;
vb@152
   812
}
vb@152
   813
vb@159
   814
int _get_content_type(
vb@159
   815
        const struct mailmime_content *content,
vb@159
   816
        char **type,
vb@159
   817
        char **charset
vb@159
   818
    )
vb@154
   819
{
vb@159
   820
    char *_type = NULL;
vb@159
   821
    char *_charset = NULL;
vb@154
   822
vb@154
   823
    assert(content);
vb@159
   824
    assert(type);
vb@159
   825
    assert(charset);
vb@154
   826
vb@159
   827
    *type = NULL;
vb@159
   828
    *charset = NULL;
vb@159
   829
vb@159
   830
    if (content->ct_subtype == NULL)
vb@159
   831
        return EINVAL;
vb@154
   832
vb@154
   833
    if (content->ct_type && content->ct_type->tp_data.tp_discrete_type) {
vb@154
   834
        size_t len;
vb@159
   835
        const char *_main_type;
vb@154
   836
vb@154
   837
        switch  (content->ct_type->tp_data.tp_discrete_type->dt_type) {
vb@154
   838
            case MAILMIME_DISCRETE_TYPE_TEXT:
vb@159
   839
                _main_type = "text";
vb@154
   840
                break;
vb@154
   841
            case MAILMIME_DISCRETE_TYPE_IMAGE:
vb@159
   842
                _main_type = "image";
vb@154
   843
                break;
vb@154
   844
            case MAILMIME_DISCRETE_TYPE_AUDIO:
vb@159
   845
                _main_type = "audio";
vb@154
   846
                break;
vb@154
   847
            case MAILMIME_DISCRETE_TYPE_VIDEO:
vb@159
   848
                _main_type = "video";
vb@154
   849
                break;
vb@154
   850
            case MAILMIME_DISCRETE_TYPE_APPLICATION:
vb@159
   851
                _main_type = "application";
vb@154
   852
                break;
vb@154
   853
            case MAILMIME_DISCRETE_TYPE_EXTENSION:
vb@159
   854
                _main_type = "extension";
vb@154
   855
                break;
vb@154
   856
            default:
vb@159
   857
                return EINVAL;
vb@154
   858
        }
vb@154
   859
vb@159
   860
        len = strlen(_main_type) + 1 + strlen(content->ct_subtype) + 1;
vb@159
   861
        _type = calloc(1, len);
vb@159
   862
        assert(_type);
vb@159
   863
        if (_type == NULL)
vb@159
   864
            return ENOMEM;
vb@159
   865
krista@903
   866
        strncpy(_type, _main_type, len);
krista@903
   867
        len -= strlen(_main_type);
krista@903
   868
        strncat(_type, "/", len--);
krista@903
   869
        strncat(_type, content->ct_subtype, len);
vb@159
   870
vb@159
   871
        if (content->ct_parameters) {
vb@159
   872
            clistiter *cur;
vb@159
   873
            for (cur = clist_begin(content->ct_parameters); cur; cur =
vb@159
   874
                    clist_next(cur)) {
vb@159
   875
                struct mailmime_parameter * param = clist_content(cur);
vb@165
   876
                if (param && param->pa_name && strcasecmp(param->pa_name,
vb@159
   877
                            "charset") == 0) {
vb@159
   878
                    _charset = param->pa_value;
vb@159
   879
                    break;
vb@159
   880
                }
vb@159
   881
            }
vb@159
   882
            if (_charset)
vb@159
   883
                *charset = strdup(_charset);
vb@157
   884
        }
vb@154
   885
vb@159
   886
        *type = _type;
vb@159
   887
        return 0;
vb@154
   888
    }
vb@154
   889
vb@159
   890
    return EINVAL;
vb@154
   891
}
krista@2562
   892
krista@2562
   893
// Only for null-terminated field strings.
krista@2562
   894
// can this field be transported as is without modification?)
krista@2562
   895
// (See rfc2822, section 2.2.3 - libetpan's handling isn't quite what
krista@2562
   896
// we need here.)
krista@2562
   897
bool must_field_value_be_encoded(const char* field_value) {
krista@2562
   898
    
krista@2562
   899
    int val_len = strlen(field_value);
krista@2562
   900
    const char* end_ptr = field_value + val_len;
krista@2562
   901
krista@2562
   902
    const char* cur_char_ptr = field_value;
krista@2562
   903
    while (cur_char_ptr < end_ptr) {
krista@2562
   904
        char cur_char = *cur_char_ptr;
krista@2563
   905
        if (cur_char > 127 || cur_char < 0)
krista@2562
   906
            return true;
krista@2562
   907
        // FIXME - do we need to deal with CRCRLF here?
krista@2562
   908
        //         I guess in the worst case, it gets encoded, which
krista@2562
   909
        //         is *supposed* to be harmless...
krista@2562
   910
        if (cur_char == '\r') {
krista@2562
   911
            const char* next = cur_char_ptr + 1;
krista@2562
   912
            const char* nextnext = next + 1;
krista@2562
   913
            if (next >= end_ptr || nextnext >= end_ptr
krista@2562
   914
                || *next != '\n'
krista@2562
   915
                || (*nextnext != ' ' && *nextnext != '\t')) {
krista@2562
   916
                return true;
krista@2562
   917
            }            
krista@2562
   918
        }
krista@2562
   919
        else if (cur_char == '\n') {
krista@2562
   920
            const char* prev = cur_char_ptr - 1;
krista@2562
   921
            if (prev == field_value || *prev != '\r')
krista@2562
   922
                return true;
krista@2562
   923
        }
krista@2562
   924
        cur_char_ptr++;
krista@2562
   925
    }    
krista@2562
   926
    return false;
krista@2562
   927
}