src/mime.c
author Krista Bennett <krista@pep-project.org>
Tue, 01 Aug 2017 16:40:24 +0200
branchmessage-2.0
changeset 1979 3d0a778d035a
parent 1902 8f8afc97237e
child 1984 06e6c0f1d8fc
permissions -rw-r--r--
Changed name to ENGINE-214 for JIRA tracking - please use that branch instead.
vb@1513
     1
// This file is under GNU General Public License 3.0
vb@1513
     2
// see LICENSE.txt
vb@1513
     3
vb@126
     4
#include "pEp_internal.h"
vb@48
     5
#include "mime.h"
vb@48
     6
vb@48
     7
#include <string.h>
vb@48
     8
#include <stdlib.h>
vb@48
     9
#include <assert.h>
vb@48
    10
#include <errno.h>
vb@130
    11
krista@1878
    12
#include "resource_id.h"
vb@48
    13
#include "etpan_mime.h"
vb@63
    14
#include "wrappers.h"
vb@48
    15
vb@309
    16
static bool is_whitespace(char c)
vb@308
    17
{
vb@308
    18
    switch (c) {
vb@308
    19
        case ' ':
vb@308
    20
        case '\t':
vb@308
    21
        case '\r':
vb@308
    22
        case '\n':
vb@308
    23
            return true;
vb@308
    24
vb@308
    25
        default:
vb@308
    26
            return false;
vb@308
    27
    }
vb@308
    28
}
vb@308
    29
vb@117
    30
DYNAMIC_API bool is_PGP_message_text(const char *text)
vb@117
    31
{
vb@117
    32
    if (text == NULL)
vb@117
    33
        return false;
vb@117
    34
vb@309
    35
    for (; *text && is_whitespace(*text); text++);
vb@308
    36
vb@117
    37
    return strncmp(text, "-----BEGIN PGP MESSAGE-----", 27) == 0;
vb@117
    38
}
vb@117
    39
Edouard@373
    40
#define TMP_TEMPLATE "pEp.XXXXXXXXXXXXXXXXXXXX"
Edouard@373
    41
#ifdef _WIN32
Edouard@373
    42
#define PATH_SEP '\\'
Edouard@373
    43
#else
Edouard@373
    44
#define PATH_SEP '/'
Edouard@373
    45
#endif
Edouard@373
    46
markus@1042
    47
// This function was rewritten to use in-memory buffers instead of
markus@1042
    48
// temporary files when the pgp/mime support was implemented for
markus@1042
    49
// outlook, as the existing code did not work well on windows.
markus@1042
    50
vb@89
    51
static PEP_STATUS render_mime(struct mailmime *mime, char **mimetext)
vb@48
    52
{
vb@89
    53
    PEP_STATUS status = PEP_STATUS_OK;
vb@89
    54
    int col;
vb@89
    55
    int r;
markus@1042
    56
	size_t len;
markus@1042
    57
	char* buf = NULL;
Edouard@373
    58
markus@1042
    59
	MMAPString* buffer;
Edouard@373
    60
markus@1042
    61
	buffer = mmap_string_new(NULL);
markus@1042
    62
	if (buffer == NULL)
markus@1042
    63
		goto enomem;
markus@1042
    64
	
markus@1042
    65
	col = 0;
markus@1042
    66
	r = mailmime_write_mem(buffer, &col, mime);
markus@1042
    67
	assert(r == MAILIMF_NO_ERROR);
markus@1042
    68
	if (r == MAILIMF_ERROR_MEMORY)
markus@1042
    69
		goto enomem;
markus@1042
    70
	else if (r != MAILIMF_NO_ERROR)
markus@1042
    71
		goto err_file;
Edouard@373
    72
markus@1042
    73
	// we overallocate by 1 byte, so we have a terminating 0.
markus@1042
    74
	len = buffer->len;
markus@1042
    75
	buf = calloc(len + 1, 1);
markus@1042
    76
	if (buf == NULL)
markus@1042
    77
		goto enomem;
vb@48
    78
markus@1042
    79
	memcpy(buf, buffer->str, len);
markus@1042
    80
	mmap_string_free(buffer);
vb@62
    81
vb@87
    82
    *mimetext = buf;
vb@48
    83
    return PEP_STATUS_OK;
vb@48
    84
vb@48
    85
err_file:
vb@88
    86
    status = PEP_CANNOT_CREATE_TEMP_FILE;
vb@88
    87
    goto pep_error;
vb@48
    88
vb@48
    89
enomem:
vb@88
    90
    status = PEP_OUT_OF_MEMORY;
vb@52
    91
vb@88
    92
pep_error:
markus@1042
    93
	if (buffer)
markus@1042
    94
		mmap_string_free(buffer);
markus@1042
    95
	if (buf)
markus@1042
    96
		free(buf);
vb@89
    97
    return status;
vb@89
    98
}
vb@89
    99
vb@89
   100
static PEP_STATUS mime_html_text(
vb@89
   101
        const char *plaintext,
vb@89
   102
        const char *htmltext,
vb@89
   103
        struct mailmime **result
vb@89
   104
    )
vb@89
   105
{
vb@89
   106
    PEP_STATUS status = PEP_STATUS_OK;
vb@89
   107
    struct mailmime * mime = NULL;
vb@89
   108
    struct mailmime * submime = NULL;
vb@89
   109
    int r;
vb@89
   110
vb@89
   111
    assert(plaintext);
vb@89
   112
    assert(htmltext);
vb@89
   113
    assert(result);
vb@89
   114
vb@89
   115
    *result = NULL;
vb@89
   116
vb@116
   117
    mime = part_multiple_new("multipart/alternative");
vb@89
   118
    assert(mime);
vb@89
   119
    if (mime == NULL)
vb@89
   120
        goto enomem;
vb@89
   121
krista@1878
   122
    pEp_rid_list_t* resource = new_rid_node(PEP_RID_FILENAME, "msg.txt");
krista@1878
   123
    
krista@1878
   124
    submime = get_text_part(resource, "text/plain", plaintext, strlen(plaintext),
vb@89
   125
            MAILMIME_MECHANISM_QUOTED_PRINTABLE);
krista@1878
   126
    free_rid_list(resource);
krista@1878
   127
    resource = NULL;
krista@1878
   128
    
vb@89
   129
    assert(submime);
vb@89
   130
    if (submime == NULL)
vb@89
   131
        goto enomem;
vb@89
   132
vb@89
   133
    r = mailmime_smart_add_part(mime, submime);
vb@89
   134
    assert(r == MAILIMF_NO_ERROR);
vb@89
   135
    if (r == MAILIMF_ERROR_MEMORY) {
vb@89
   136
        goto enomem;
vb@89
   137
    }
vb@89
   138
    else {
vb@89
   139
        // mailmime_smart_add_part() takes ownership of submime
vb@89
   140
        submime = NULL;
vb@89
   141
    }
vb@89
   142
krista@1878
   143
    resource = new_rid_node(PEP_RID_FILENAME, "msg.html");
krista@1878
   144
    submime = get_text_part(resource, "text/html", htmltext, strlen(htmltext),
vb@89
   145
            MAILMIME_MECHANISM_QUOTED_PRINTABLE);
krista@1878
   146
    free_rid_list(resource);
krista@1878
   147
    resource = NULL;
krista@1878
   148
    
vb@89
   149
    assert(submime);
vb@89
   150
    if (submime == NULL)
vb@89
   151
        goto enomem;
vb@89
   152
vb@89
   153
    r = mailmime_smart_add_part(mime, submime);
vb@89
   154
    assert(r == MAILIMF_NO_ERROR);
vb@89
   155
    if (r == MAILIMF_ERROR_MEMORY)
vb@89
   156
        goto enomem;
vb@89
   157
    else {
vb@89
   158
        // mailmime_smart_add_part() takes ownership of submime
vb@89
   159
        submime = NULL;
vb@89
   160
    }
vb@89
   161
vb@89
   162
    *result = mime;
vb@89
   163
    return PEP_STATUS_OK;
vb@89
   164
vb@89
   165
enomem:
vb@89
   166
    status = PEP_OUT_OF_MEMORY;
vb@89
   167
vb@59
   168
    if (mime)
vb@59
   169
        mailmime_free(mime);
vb@89
   170
vb@48
   171
    if (submime)
vb@48
   172
        mailmime_free(submime);
vb@48
   173
vb@88
   174
    return status;
vb@48
   175
}
vb@88
   176
vb@89
   177
static PEP_STATUS mime_attachment(
vb@89
   178
        bloblist_t *blob,
vb@89
   179
        struct mailmime **result
vb@88
   180
    )
vb@88
   181
{
vb@88
   182
    PEP_STATUS status = PEP_STATUS_OK;
vb@89
   183
    struct mailmime * mime = NULL;
vb@89
   184
    char * mime_type;
vb@89
   185
    assert(blob);
vb@89
   186
    assert(result);
vb@88
   187
vb@89
   188
    *result = NULL;
vb@88
   189
markus@1042
   190
// TODO: It seems the pep com server adapter sends an empty string here,
markus@1042
   191
// which leads to a crash later. Thus, we workaround here by treating an
markus@1042
   192
// empty string as NULL. We need to check whether the bug really is here,
markus@1042
   193
// or the pep com server adapter needs to be changed.
markus@1042
   194
    if (blob->mime_type == NULL || blob->mime_type[0] == '\0')
vb@89
   195
        mime_type = "application/octet-stream";
vb@89
   196
    else
vb@89
   197
        mime_type = blob->mime_type;
vb@89
   198
krista@1878
   199
    pEp_rid_list_t* resource = parse_uri(blob->filename);
krista@1878
   200
    mime = get_file_part(resource, mime_type, blob->value, blob->size);
krista@1878
   201
    free_rid_list(resource);
krista@1878
   202
    
vb@89
   203
    assert(mime);
vb@89
   204
    if (mime == NULL)
vb@89
   205
        goto enomem;
vb@89
   206
vb@89
   207
    *result = mime;
vb@89
   208
    return PEP_STATUS_OK;
vb@88
   209
vb@88
   210
enomem:
vb@88
   211
    status = PEP_OUT_OF_MEMORY;
vb@88
   212
vb@89
   213
    if (mime)
vb@89
   214
        mailmime_free(mime);
vb@89
   215
vb@88
   216
    return status;
vb@88
   217
}
vb@88
   218
vb@94
   219
static struct mailimf_mailbox * identity_to_mailbox(const pEp_identity *ident)
vb@94
   220
{
vb@94
   221
    char *_username = NULL;
vb@94
   222
    struct mailimf_mailbox *mb;
vb@94
   223
vb@977
   224
    _username = ident->username ? mailmime_encode_subject_header("utf-8",
vb@977
   225
            ident->username, 0) : strdup("");
vb@94
   226
    if (_username == NULL)
vb@94
   227
        goto enomem;
vb@94
   228
vb@94
   229
    mb = mailbox_from_string(_username, ident->address);
vb@94
   230
    if (mb == NULL)
vb@94
   231
        goto enomem;
vb@94
   232
vb@94
   233
    free(_username);
vb@94
   234
    _username = NULL;
vb@94
   235
vb@94
   236
    return mb;
vb@94
   237
vb@94
   238
enomem:
vb@94
   239
    free(_username);
vb@94
   240
    return NULL;
vb@94
   241
}
vb@94
   242
vb@94
   243
static struct mailimf_mailbox_list * identity_to_mbl(
vb@94
   244
        const pEp_identity *ident)
vb@90
   245
{
vb@90
   246
    struct mailimf_mailbox_list *mbl = NULL;
vb@90
   247
    struct mailimf_mailbox *mb = NULL;
vb@90
   248
    clist *list = NULL;
vb@90
   249
    int r;
vb@90
   250
vb@90
   251
    assert(ident);
vb@90
   252
vb@90
   253
    list = clist_new();
vb@90
   254
    if (list == NULL)
vb@90
   255
        goto enomem;
vb@90
   256
vb@94
   257
    mb = identity_to_mailbox(ident);
vb@90
   258
    if (mb == NULL)
vb@90
   259
        goto enomem;
vb@90
   260
vb@90
   261
    r = clist_append(list, mb);
vb@90
   262
    if (r)
vb@90
   263
        goto enomem;
vb@90
   264
vb@90
   265
    mbl = mailimf_mailbox_list_new(list);
vb@90
   266
    if (mbl == NULL)
vb@90
   267
        goto enomem;
vb@90
   268
vb@90
   269
    return mbl;
vb@90
   270
vb@90
   271
enomem:
vb@90
   272
    if (mb)
vb@90
   273
        mailimf_mailbox_free(mb);
vb@90
   274
vb@90
   275
    if (list)
vb@90
   276
        clist_free(list);
vb@90
   277
vb@90
   278
    return NULL;
vb@90
   279
}
vb@90
   280
vb@94
   281
static struct mailimf_address_list * identity_list_to_mal(identity_list *il)
vb@90
   282
{
vb@93
   283
    struct mailimf_address_list *mal = NULL;
vb@90
   284
    struct mailimf_mailbox *mb = NULL;
vb@93
   285
    struct mailimf_address * addr = NULL;
vb@90
   286
    clist *list = NULL;
vb@90
   287
    int r;
vb@90
   288
vb@90
   289
    assert(il);
vb@90
   290
vb@90
   291
    list = clist_new();
vb@90
   292
    if (list == NULL)
vb@90
   293
        goto enomem;
vb@90
   294
vb@90
   295
    identity_list *_il;
vb@1016
   296
    for (_il = il; _il && _il->ident; _il = _il->next) {
vb@94
   297
        mb = identity_to_mailbox(_il->ident);
vb@90
   298
        if (mb == NULL)
vb@90
   299
            goto enomem;
vb@90
   300
vb@93
   301
        addr = mailimf_address_new(MAILIMF_ADDRESS_MAILBOX, mb, NULL);
vb@93
   302
        if (addr == NULL)
vb@93
   303
            goto enomem;
vb@93
   304
        mb = NULL;
vb@93
   305
vb@93
   306
        r = clist_append(list, addr);
vb@90
   307
        if (r)
vb@90
   308
            goto enomem;
vb@93
   309
        addr = NULL;
vb@90
   310
    }
vb@93
   311
    mal = mailimf_address_list_new(list);
vb@93
   312
    if (mal == NULL)
vb@90
   313
        goto enomem;
vb@90
   314
vb@93
   315
    return mal;
vb@90
   316
vb@90
   317
enomem:
vb@90
   318
    if (mb)
vb@90
   319
        mailimf_mailbox_free(mb);
vb@90
   320
vb@93
   321
    if (addr)
vb@93
   322
        mailimf_address_free(addr);
vb@93
   323
vb@90
   324
    if (list)
vb@90
   325
        clist_free(list);
vb@90
   326
vb@90
   327
    return NULL;
vb@90
   328
}
vb@90
   329
vb@94
   330
static clist * stringlist_to_clist(stringlist_t *sl)
vb@91
   331
{
vb@91
   332
    clist * cl = clist_new();
vb@91
   333
    assert(cl);
vb@91
   334
    if (cl == NULL)
vb@91
   335
        return NULL;
vb@91
   336
vb@91
   337
    stringlist_t *_sl;
vb@91
   338
    for (_sl = sl; _sl; _sl = _sl->next) {
vb@91
   339
        int r;
vb@94
   340
        char * value = mailmime_encode_subject_header("utf-8", _sl->value, 0);
vb@91
   341
        assert(value);
vb@91
   342
        if (value == NULL) {
vb@91
   343
            clist_free(cl);
vb@91
   344
            return NULL;
vb@91
   345
        }
vb@91
   346
        r = clist_append(cl, value);
vb@91
   347
        assert(r == 0);
vb@91
   348
        if (r) {
vb@91
   349
            free(value);
vb@91
   350
            clist_free(cl);
vb@91
   351
            return NULL;
vb@91
   352
        }
vb@91
   353
    }
vb@91
   354
vb@91
   355
    return cl;
vb@91
   356
}
vb@91
   357
vb@89
   358
static PEP_STATUS build_fields(const message *msg, struct mailimf_fields **result)
vb@89
   359
{
vb@89
   360
    PEP_STATUS status = PEP_STATUS_OK;
vb@89
   361
    struct mailimf_fields * fields = NULL;
vb@89
   362
    int r;
vb@89
   363
    clist * fields_list = NULL;
vb@89
   364
    char *subject = msg->shortmsg ? msg->shortmsg : "pEp";
vb@89
   365
vb@89
   366
    assert(msg);
vb@89
   367
    assert(msg->from);
vb@89
   368
    assert(msg->from->address);
vb@89
   369
    assert(result);
vb@89
   370
vb@89
   371
    *result = NULL;
vb@89
   372
vb@89
   373
    fields_list = clist_new();
vb@89
   374
    assert(fields_list);
vb@89
   375
    if (fields_list == NULL)
vb@89
   376
        goto enomem;
vb@89
   377
vb@90
   378
    if (msg->id) {
vb@90
   379
        char *_msgid = strdup(msg->id);
vb@90
   380
        if (_msgid == NULL)
vb@90
   381
            goto enomem;
vb@89
   382
vb@90
   383
        r = _append_field(fields_list, MAILIMF_FIELD_MESSAGE_ID,
vb@90
   384
                (_new_func_t) mailimf_message_id_new, _msgid);
vb@90
   385
        if (r) {
vb@90
   386
            free(_msgid);
vb@90
   387
            goto enomem;
vb@90
   388
        }
vb@90
   389
    }
vb@90
   390
vb@90
   391
    if (msg->sent) {
vb@90
   392
        struct mailimf_date_time * dt = timestamp_to_etpantime(msg->sent);
vb@90
   393
        if (dt == NULL)
vb@90
   394
            goto enomem;
vb@90
   395
vb@90
   396
        r = _append_field(fields_list, MAILIMF_FIELD_ORIG_DATE,
vb@90
   397
                (_new_func_t) mailimf_orig_date_new, dt);
vb@90
   398
        if (r) {
vb@90
   399
            mailimf_date_time_free(dt);
vb@90
   400
            goto enomem;
vb@90
   401
        }
vb@90
   402
        dt = NULL;
vb@90
   403
    }
vb@90
   404
vb@91
   405
    /* if (msg->from) */ {
vb@94
   406
        struct mailimf_mailbox_list *from = identity_to_mbl(msg->from);
vb@90
   407
        if (from == NULL)
vb@90
   408
            goto enomem;
vb@90
   409
vb@90
   410
        r = _append_field(fields_list, MAILIMF_FIELD_FROM,
vb@90
   411
                (_new_func_t) mailimf_from_new, from);
vb@90
   412
        if (r) {
vb@90
   413
            mailimf_mailbox_list_free(from);
vb@90
   414
            goto enomem;
vb@90
   415
        }
vb@90
   416
    }
vb@90
   417
vb@90
   418
    if (msg->to) {
vb@94
   419
        struct mailimf_address_list *to = identity_list_to_mal(msg->to);
vb@90
   420
        if (to == NULL)
vb@90
   421
            goto enomem;
vb@90
   422
vb@91
   423
        r = _append_field(fields_list, MAILIMF_FIELD_TO,
vb@90
   424
                (_new_func_t) mailimf_to_new, to);
vb@90
   425
        if (r) {
vb@93
   426
            mailimf_address_list_free(to);
vb@90
   427
            goto enomem;
vb@90
   428
        }
vb@90
   429
    }
vb@89
   430
vb@112
   431
    /* if (subject) */ {
vb@112
   432
        char *_subject = mailmime_encode_subject_header("utf-8", subject, 1);
vb@112
   433
        if (_subject == NULL)
vb@112
   434
            goto enomem;
vb@112
   435
vb@112
   436
        r = _append_field(fields_list, MAILIMF_FIELD_SUBJECT,
vb@112
   437
                (_new_func_t) mailimf_subject_new, _subject);
vb@112
   438
        if (r) {
vb@112
   439
            free(_subject);
vb@112
   440
            goto enomem;
vb@112
   441
        }
vb@112
   442
    }
vb@112
   443
vb@91
   444
    if (msg->cc) {
vb@94
   445
        struct mailimf_address_list *cc = identity_list_to_mal(msg->cc);
vb@91
   446
        if (cc == NULL)
vb@91
   447
            goto enomem;
vb@91
   448
vb@91
   449
        r = _append_field(fields_list, MAILIMF_FIELD_CC,
vb@91
   450
                (_new_func_t) mailimf_cc_new, cc);
vb@91
   451
        if (r) {
vb@93
   452
            mailimf_address_list_free(cc);
vb@91
   453
            goto enomem;
vb@91
   454
        }
vb@91
   455
    }
vb@91
   456
    
vb@91
   457
    if (msg->bcc) {
vb@94
   458
        struct mailimf_address_list *bcc = identity_list_to_mal(msg->bcc);
vb@91
   459
        if (bcc == NULL)
vb@91
   460
            goto enomem;
vb@91
   461
vb@91
   462
        r = _append_field(fields_list, MAILIMF_FIELD_BCC,
vb@91
   463
                (_new_func_t) mailimf_bcc_new, bcc);
vb@91
   464
        if (r) {
vb@93
   465
            mailimf_address_list_free(bcc);
vb@91
   466
            goto enomem;
vb@91
   467
        }
vb@91
   468
    }
vb@91
   469
    
vb@91
   470
    if (msg->reply_to) {
vb@94
   471
        struct mailimf_address_list *reply_to = identity_list_to_mal(msg->reply_to);
vb@91
   472
        if (reply_to == NULL)
vb@91
   473
            goto enomem;
vb@91
   474
vb@91
   475
        r = _append_field(fields_list, MAILIMF_FIELD_REPLY_TO,
vb@91
   476
                (_new_func_t) mailimf_reply_to_new, reply_to);
vb@91
   477
        if (r) {
vb@94
   478
            mailimf_address_list_free(reply_to);
vb@91
   479
            goto enomem;
vb@91
   480
        }
vb@91
   481
    }
vb@91
   482
vb@91
   483
    if (msg->in_reply_to) {
vb@94
   484
        clist *in_reply_to = stringlist_to_clist(msg->in_reply_to);
vb@91
   485
        if (in_reply_to == NULL)
vb@91
   486
            goto enomem;
vb@91
   487
vb@91
   488
        r = _append_field(fields_list, MAILIMF_FIELD_IN_REPLY_TO,
vb@91
   489
                (_new_func_t) mailimf_in_reply_to_new, in_reply_to);
vb@91
   490
        if (r) {
vb@94
   491
            clist_free(in_reply_to);
vb@91
   492
            goto enomem;
vb@91
   493
        }
vb@91
   494
    }
vb@91
   495
vb@91
   496
    if (msg->references) {
vb@94
   497
        clist *references = stringlist_to_clist(msg->references);
vb@91
   498
        if (references == NULL)
vb@91
   499
            goto enomem;
vb@91
   500
vb@91
   501
        r = _append_field(fields_list, MAILIMF_FIELD_REFERENCES,
vb@91
   502
                (_new_func_t) mailimf_references_new, references);
vb@91
   503
        if (r) {
vb@91
   504
            clist_free(references);
vb@91
   505
            goto enomem;
vb@91
   506
        }
vb@91
   507
    }
vb@91
   508
vb@91
   509
    if (msg->keywords) {
vb@94
   510
        clist *keywords = stringlist_to_clist(msg->keywords);
vb@91
   511
        if (keywords == NULL)
vb@91
   512
            goto enomem;
vb@91
   513
vb@91
   514
        r = _append_field(fields_list, MAILIMF_FIELD_KEYWORDS,
vb@91
   515
                (_new_func_t) mailimf_keywords_new, keywords);
vb@91
   516
        if (r) {
vb@91
   517
            clist_free(keywords);
vb@91
   518
            goto enomem;
vb@91
   519
        }
vb@91
   520
    }
vb@91
   521
vb@91
   522
    if (msg->comments) {
vb@94
   523
        char *comments = mailmime_encode_subject_header("utf-8", msg->comments,
vb@94
   524
                0);
vb@91
   525
        if (comments == NULL)
vb@91
   526
            goto enomem;
vb@91
   527
vb@91
   528
        r = _append_field(fields_list, MAILIMF_FIELD_COMMENTS,
vb@91
   529
                (_new_func_t) mailimf_comments_new, comments);
vb@91
   530
        if (r) {
vb@91
   531
            free(comments);
vb@91
   532
            goto enomem;
vb@91
   533
        }
vb@91
   534
    }
vb@91
   535
vb@98
   536
    if (msg->opt_fields) {
vb@110
   537
        stringpair_list_t *_l;
vb@281
   538
        for (_l = msg->opt_fields; _l && _l->value; _l = _l->next) {
vb@110
   539
            char *key = _l->value->key;
vb@110
   540
            char *value = _l->value->value;
vb@281
   541
            if (key && value) {
vb@281
   542
                char *_value = mailmime_encode_subject_header("utf-8", value, 0);
vb@281
   543
                if (_value == NULL)
vb@281
   544
                    goto enomem;
vb@110
   545
vb@281
   546
                r = _append_optional_field(fields_list, key, _value);
vb@281
   547
                free(_value);
vb@281
   548
                if (r)
vb@281
   549
                    goto enomem;
vb@281
   550
            }
vb@110
   551
        }
vb@98
   552
    }
vb@94
   553
vb@89
   554
    fields = mailimf_fields_new(fields_list);
vb@89
   555
    assert(fields);
vb@89
   556
    if (fields == NULL)
vb@89
   557
        goto enomem;
vb@89
   558
vb@89
   559
    *result = fields;
vb@89
   560
vb@89
   561
    return PEP_STATUS_OK;
vb@89
   562
vb@89
   563
enomem:
vb@89
   564
    status = PEP_OUT_OF_MEMORY;
vb@89
   565
vb@89
   566
    if (fields_list)
vb@89
   567
        clist_free(fields_list);
vb@89
   568
vb@89
   569
    if (fields)
vb@89
   570
        mailimf_fields_free(fields);
vb@89
   571
vb@89
   572
    return status;
vb@89
   573
}
vb@89
   574
krista@1873
   575
static bool has_exceptional_extension(char* filename) {
krista@1873
   576
    if (!filename)
krista@1873
   577
        return false;
krista@1873
   578
    int len = strlen(filename);
krista@1873
   579
    if (len < 4)
krista@1873
   580
        return false;
krista@1873
   581
    char* ext_start = filename + (len - 4);
krista@1873
   582
    if (strcmp(ext_start, ".pgp") == 0 || strcmp(ext_start, ".gpg") == 0 ||
krista@1873
   583
        strcmp(ext_start, ".asc") == 0 || strcmp(ext_start, ".pEp") == 0)
krista@1873
   584
        return true;
krista@1873
   585
    return false;
krista@1873
   586
}
krista@1873
   587
krista@1873
   588
static pEp_rid_list_t* choose_resource_id(pEp_rid_list_t* rid_list) {
krista@1882
   589
    pEp_rid_list_t* retval = rid_list;
krista@1873
   590
    
krista@1873
   591
    /* multiple elements - least common case */
krista@1873
   592
    if (rid_list && rid_list->next) {
krista@1873
   593
        pEp_rid_list_t* rid_list_curr = rid_list;
krista@1873
   594
        retval = rid_list; 
krista@1873
   595
        
krista@1873
   596
        while (rid_list_curr) {
krista@1873
   597
            pEp_resource_id_type rid_type = rid_list_curr->rid_type;
krista@1873
   598
            if (rid_type == PEP_RID_CID)
krista@1873
   599
                retval = rid_list_curr;
krista@1873
   600
            else if (rid_type == PEP_RID_FILENAME && has_exceptional_extension(rid_list_curr->rid))
krista@1873
   601
                return rid_list_curr;
krista@1873
   602
            rid_list_curr = rid_list_curr->next;
krista@1873
   603
        }
krista@1873
   604
    } 
krista@1873
   605
    return retval;
krista@1873
   606
}
krista@1873
   607
vb@114
   608
static PEP_STATUS mime_encode_message_plain(
vb@89
   609
        const message *msg,
vb@113
   610
        bool omit_fields,
vb@114
   611
        struct mailmime **result
vb@89
   612
    )
vb@89
   613
{
vb@89
   614
    struct mailmime * mime = NULL;
vb@89
   615
    struct mailmime * submime = NULL;
vb@89
   616
    int r;
vb@89
   617
    PEP_STATUS status;
roker@723
   618
    //char *subject;
vb@89
   619
    char *plaintext;
vb@89
   620
    char *htmltext;
vb@89
   621
vb@89
   622
    assert(msg);
vb@114
   623
    assert(result);
vb@112
   624
roker@723
   625
    //subject = (msg->shortmsg) ? msg->shortmsg : "pEp";  // not used, yet.
vb@89
   626
    plaintext = (msg->longmsg) ? msg->longmsg : "";
vb@89
   627
    htmltext = msg->longmsg_formatted;
vb@89
   628
krista@1197
   629
    if (htmltext && (htmltext[0] != '\0')) {
vb@89
   630
        status = mime_html_text(plaintext, htmltext, &mime);
vb@89
   631
        if (status != PEP_STATUS_OK)
vb@89
   632
            goto pep_error;
vb@89
   633
    }
vb@89
   634
    else {
krista@1878
   635
        pEp_rid_list_t* resource = NULL;
krista@1878
   636
        if (is_PGP_message_text(plaintext)) {
krista@1878
   637
            resource = new_rid_node(PEP_RID_FILENAME, "msg.asc");
krista@1878
   638
            mime = get_text_part(resource, "application/octet-stream", plaintext,
vb@114
   639
                    strlen(plaintext), MAILMIME_MECHANISM_7BIT);
krista@1878
   640
        }
krista@1878
   641
        else {
krista@1878
   642
            resource = new_rid_node(PEP_RID_FILENAME, "msg.txt");
krista@1878
   643
            mime = get_text_part(resource, "text/plain", plaintext, strlen(plaintext),
vb@114
   644
                    MAILMIME_MECHANISM_QUOTED_PRINTABLE);
krista@1878
   645
        }
krista@1878
   646
        free_rid_list(resource);
krista@1878
   647
        
vb@89
   648
        assert(mime);
vb@89
   649
        if (mime == NULL)
vb@89
   650
            goto enomem;
vb@89
   651
    }
vb@89
   652
vb@89
   653
    if (msg->attachments) {
vb@89
   654
        submime = mime;
vb@116
   655
        mime = part_multiple_new("multipart/mixed");
vb@89
   656
        assert(mime);
vb@89
   657
        if (mime == NULL)
vb@89
   658
            goto enomem;
vb@89
   659
vb@89
   660
        r = mailmime_smart_add_part(mime, submime);
vb@89
   661
        assert(r == MAILIMF_NO_ERROR);
vb@89
   662
        if (r == MAILIMF_ERROR_MEMORY) {
vb@89
   663
            goto enomem;
vb@89
   664
        }
vb@89
   665
        else {
vb@89
   666
            // mailmime_smart_add_part() takes ownership of submime
vb@89
   667
            submime = NULL;
vb@89
   668
        }
vb@89
   669
vb@89
   670
        bloblist_t *_a;
vb@89
   671
        for (_a = msg->attachments; _a != NULL; _a = _a->next) {
vb@89
   672
vb@89
   673
            status = mime_attachment(_a, &submime);
vb@89
   674
            if (status != PEP_STATUS_OK)
vb@89
   675
                goto pep_error;
vb@89
   676
vb@89
   677
            r = mailmime_smart_add_part(mime, submime);
vb@89
   678
            assert(r == MAILIMF_NO_ERROR);
vb@89
   679
            if (r == MAILIMF_ERROR_MEMORY) {
vb@89
   680
                goto enomem;
vb@89
   681
            }
vb@89
   682
            else {
vb@89
   683
                // mailmime_smart_add_part() takes ownership of submime
vb@89
   684
                submime = NULL;
vb@89
   685
            }
vb@89
   686
        }
vb@89
   687
    }
vb@89
   688
vb@114
   689
    *result = mime;
vb@114
   690
    return PEP_STATUS_OK;
vb@114
   691
vb@114
   692
enomem:
vb@114
   693
    status = PEP_OUT_OF_MEMORY;
vb@114
   694
vb@114
   695
pep_error:
vb@114
   696
    if (mime)
vb@114
   697
        mailmime_free(mime);
vb@114
   698
vb@114
   699
    if (submime)
vb@114
   700
        mailmime_free(submime);
vb@114
   701
vb@114
   702
    return status;
vb@114
   703
}
vb@114
   704
vb@114
   705
static PEP_STATUS mime_encode_message_PGP_MIME(
vb@114
   706
        const message * msg,
vb@114
   707
        bool omit_fields,
vb@114
   708
        struct mailmime **result
vb@114
   709
    )
vb@114
   710
{
vb@114
   711
    struct mailmime * mime = NULL;
vb@114
   712
    struct mailmime * submime = NULL;
vb@114
   713
	struct mailmime_parameter * param;
vb@114
   714
    int r;
vb@114
   715
    PEP_STATUS status;
roker@723
   716
    //char *subject;
vb@114
   717
    char *plaintext;
edouard@1274
   718
    size_t plaintext_size;
vb@114
   719
vb@260
   720
    assert(msg->attachments && msg->attachments->next &&
vb@301
   721
            msg->attachments->next->value);
vb@114
   722
roker@723
   723
    //subject = (msg->shortmsg) ? msg->shortmsg : "pEp"; // not used, yet.
vb@301
   724
    plaintext = msg->attachments->next->value;
edouard@1274
   725
    plaintext_size = msg->attachments->next->size;
vb@114
   726
vb@116
   727
    mime = part_multiple_new("multipart/encrypted");
vb@114
   728
    assert(mime);
vb@114
   729
    if (mime == NULL)
vb@114
   730
        goto enomem;
vb@114
   731
vb@114
   732
    param = mailmime_param_new_with_data("protocol", "application/pgp-encrypted");
vb@114
   733
    clist_append(mime->mm_content_type->ct_parameters, param);
vb@114
   734
vb@114
   735
    submime = get_pgp_encrypted_part();
vb@114
   736
    assert(submime);
vb@114
   737
    if (submime == NULL)
vb@114
   738
        goto enomem;
vb@114
   739
vb@114
   740
    r = mailmime_smart_add_part(mime, submime);
vb@114
   741
    assert(r == MAILIMF_NO_ERROR);
vb@114
   742
    if (r == MAILIMF_ERROR_MEMORY) {
vb@114
   743
        goto enomem;
vb@114
   744
    }
vb@114
   745
    else {
vb@114
   746
        // mailmime_smart_add_part() takes ownership of submime
vb@114
   747
        submime = NULL;
vb@114
   748
    }
vb@114
   749
krista@1878
   750
    pEp_rid_list_t* resource = new_rid_node(PEP_RID_FILENAME, "msg.asc");
krista@1878
   751
    submime = get_text_part(resource, "application/octet-stream", plaintext,
edouard@1274
   752
            plaintext_size, MAILMIME_MECHANISM_7BIT);
krista@1878
   753
            
krista@1878
   754
    free_rid_list(resource);
krista@1878
   755
    
vb@114
   756
    assert(submime);
vb@114
   757
    if (submime == NULL)
vb@114
   758
        goto enomem;
vb@114
   759
vb@114
   760
    r = mailmime_smart_add_part(mime, submime);
vb@114
   761
    assert(r == MAILIMF_NO_ERROR);
vb@114
   762
    if (r == MAILIMF_ERROR_MEMORY) {
vb@114
   763
        goto enomem;
vb@114
   764
    }
vb@114
   765
    else {
vb@114
   766
        // mailmime_smart_add_part() takes ownership of submime
vb@114
   767
        submime = NULL;
vb@114
   768
    }
vb@114
   769
vb@114
   770
    *result = mime;
vb@114
   771
    return PEP_STATUS_OK;
vb@114
   772
vb@114
   773
enomem:
vb@114
   774
    status = PEP_OUT_OF_MEMORY;
vb@114
   775
vb@114
   776
    if (mime)
vb@114
   777
        mailmime_free(mime);
vb@114
   778
vb@114
   779
    if (submime)
vb@114
   780
        mailmime_free(submime);
vb@114
   781
vb@114
   782
    return status;
vb@114
   783
}
vb@114
   784
vb@114
   785
DYNAMIC_API PEP_STATUS mime_encode_message(
vb@114
   786
        const message * msg,
vb@114
   787
        bool omit_fields,
vb@114
   788
        char **mimetext
vb@114
   789
    )
vb@114
   790
{
vb@114
   791
    PEP_STATUS status = PEP_STATUS_OK;
vb@114
   792
    struct mailmime * msg_mime = NULL;
vb@114
   793
    struct mailmime * mime = NULL;
vb@114
   794
    struct mailimf_fields * fields = NULL;
vb@114
   795
    char *buf = NULL;
vb@114
   796
    int r;
vb@114
   797
vb@114
   798
    assert(msg);
vb@114
   799
    assert(mimetext);
vb@114
   800
vb@260
   801
    if (!(msg && mimetext))
vb@191
   802
        return PEP_ILLEGAL_VALUE;
vb@191
   803
vb@114
   804
    *mimetext = NULL;
vb@114
   805
vb@114
   806
    switch (msg->enc_format) {
vb@114
   807
        case PEP_enc_none:
vb@114
   808
            status = mime_encode_message_plain(msg, omit_fields, &mime);
vb@114
   809
            break;
vb@114
   810
vb@114
   811
        case PEP_enc_pieces:
vb@114
   812
            status = mime_encode_message_plain(msg, omit_fields, &mime);
vb@114
   813
            break;
vb@114
   814
vb@114
   815
        case PEP_enc_S_MIME:
vb@114
   816
            NOT_IMPLEMENTED
vb@114
   817
                
vb@114
   818
        case PEP_enc_PGP_MIME:
vb@114
   819
            status = mime_encode_message_PGP_MIME(msg, omit_fields, &mime);
vb@114
   820
            break;
vb@114
   821
vb@114
   822
        case PEP_enc_PEP:
vb@114
   823
            NOT_IMPLEMENTED
edouard@1557
   824
edouard@1557
   825
        default:
edouard@1557
   826
            NOT_IMPLEMENTED
vb@114
   827
    }
vb@114
   828
vb@114
   829
    if (status != PEP_STATUS_OK)
vb@114
   830
        goto pep_error;
vb@114
   831
vb@89
   832
    msg_mime = mailmime_new_message_data(NULL);
vb@90
   833
    assert(msg_mime);
vb@90
   834
    if (msg_mime == NULL)
vb@90
   835
        goto enomem;
vb@89
   836
vb@90
   837
    r = mailmime_add_part(msg_mime, mime);
vb@90
   838
    if (r) {
vb@90
   839
        mailmime_free(mime);
vb@90
   840
        goto enomem;
vb@90
   841
    }
vb@114
   842
    mime = NULL;
vb@90
   843
vb@113
   844
    if (!omit_fields) {
vb@113
   845
        status = build_fields(msg, &fields);
vb@113
   846
        if (status != PEP_STATUS_OK)
vb@113
   847
            goto pep_error;
vb@90
   848
vb@113
   849
        mailmime_set_imf_fields(msg_mime, fields);
vb@113
   850
    }
vb@90
   851
vb@90
   852
    status = render_mime(msg_mime, &buf);
vb@89
   853
    if (status != PEP_STATUS_OK)
vb@89
   854
        goto pep_error;
vb@89
   855
vb@89
   856
    mailmime_free(msg_mime);
vb@89
   857
    *mimetext = buf;
vb@90
   858
vb@89
   859
    return PEP_STATUS_OK;
vb@89
   860
vb@89
   861
enomem:
vb@89
   862
    status = PEP_OUT_OF_MEMORY;
vb@89
   863
vb@89
   864
pep_error:
vb@89
   865
    if (msg_mime)
vb@90
   866
        mailmime_free(msg_mime);
vb@89
   867
    else
vb@89
   868
        if (mime)
vb@89
   869
            mailmime_free(mime);
vb@89
   870
vb@89
   871
    return status;
vb@89
   872
}
vb@89
   873
vb@94
   874
static pEp_identity *mailbox_to_identity(const struct mailimf_mailbox * mb)
vb@94
   875
{
vb@94
   876
    char *username = NULL;
vb@94
   877
vb@159
   878
    assert(mb);
vb@159
   879
    assert(mb->mb_addr_spec);
vb@159
   880
vb@159
   881
    if (mb->mb_addr_spec == NULL)
vb@159
   882
        return NULL;
vb@159
   883
vb@159
   884
    if (mb->mb_display_name) {
roker@871
   885
        size_t index = 0;
roker@871
   886
        const int r = mailmime_encoded_phrase_parse("utf-8", mb->mb_display_name,
vb@159
   887
                strlen(mb->mb_display_name), &index, "utf-8", &username);
vb@159
   888
        if (r)
vb@159
   889
            goto enomem;
vb@159
   890
    }
vb@94
   891
roker@871
   892
    pEp_identity *ident = new_identity(mb->mb_addr_spec, NULL, NULL, username);
vb@94
   893
    if (ident == NULL)
vb@94
   894
        goto enomem;
vb@94
   895
    free(username);
vb@94
   896
vb@94
   897
    return ident;
vb@94
   898
vb@94
   899
enomem:
vb@94
   900
    free(username);
vb@94
   901
    return NULL;
vb@94
   902
}
vb@94
   903
vb@94
   904
static pEp_identity * mbl_to_identity(const struct mailimf_mailbox_list * mbl)
vb@94
   905
{
vb@94
   906
    struct mailimf_mailbox * mb = clist_content(clist_begin(mbl->mb_list));
vb@94
   907
    return mailbox_to_identity(mb);
vb@94
   908
}
vb@94
   909
vb@94
   910
static identity_list * mal_to_identity_list(
vb@94
   911
        const struct mailimf_address_list *mal
vb@94
   912
    )
vb@94
   913
{
roker@871
   914
    assert(mal);
vb@94
   915
    clist *list = mal->ad_list;
vb@94
   916
roker@871
   917
    identity_list *il = new_identity_list(NULL);
vb@94
   918
    if (il == NULL)
vb@94
   919
        goto enomem;
vb@94
   920
vb@94
   921
    identity_list *_il = il;
roker@871
   922
    for (clistiter *cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
vb@94
   923
        pEp_identity *ident;
vb@94
   924
roker@871
   925
        struct mailimf_address *addr = clist_content(cur);
vb@94
   926
        switch(addr->ad_type) {
vb@94
   927
            case MAILIMF_ADDRESS_MAILBOX:
vb@94
   928
                ident = mailbox_to_identity(addr->ad_data.ad_mailbox);
vb@94
   929
                if (ident == NULL)
vb@94
   930
                    goto enomem;
vb@94
   931
                _il = identity_list_add(_il, ident);
vb@94
   932
                if (_il == NULL)
vb@94
   933
                    goto enomem;
vb@94
   934
                break;
vb@94
   935
vb@94
   936
            case MAILIMF_ADDRESS_GROUP:
vb@94
   937
                {
vb@94
   938
                    struct mailimf_mailbox_list * mbl =
vb@94
   939
                            addr->ad_data.ad_group->grp_mb_list;
roker@871
   940
                    for (clistiter *cur2 = clist_begin(mbl->mb_list); cur2 != NULL;
vb@94
   941
                            cur2 = clist_next(cur2)) {
vb@94
   942
                        ident = mailbox_to_identity(clist_content(cur));
vb@94
   943
                        if (ident == NULL)
vb@94
   944
                            goto enomem;
vb@94
   945
                        _il = identity_list_add(_il, ident);
vb@94
   946
                        if (_il == NULL)
vb@94
   947
                            goto enomem;
vb@94
   948
                    }
vb@94
   949
                }
vb@94
   950
                break;
vb@94
   951
vb@94
   952
            default:
vb@94
   953
                assert(0);
vb@94
   954
                goto enomem;
vb@94
   955
        }
vb@94
   956
    }
vb@94
   957
vb@94
   958
    return il;
vb@94
   959
vb@94
   960
enomem:
vb@94
   961
    free_identity_list(il);
vb@94
   962
    return NULL;
vb@94
   963
}
vb@94
   964
vb@94
   965
static stringlist_t * clist_to_stringlist(const clist *list)
vb@94
   966
{
vb@94
   967
    char *text = NULL;;
vb@94
   968
    stringlist_t * sl = new_stringlist(NULL);
vb@94
   969
    if (sl == NULL)
vb@94
   970
        return NULL;
vb@94
   971
vb@94
   972
    stringlist_t *_sl = sl;
roker@871
   973
    for (clistiter *cur = clist_begin(list); cur != NULL; cur = clist_next(cur)) {
vb@94
   974
        char *phrase = clist_content(cur);
roker@871
   975
        size_t index = 0;
roker@871
   976
        
roker@871
   977
        const int r = mailmime_encoded_phrase_parse("utf-8", phrase, strlen(phrase),
vb@94
   978
                &index, "utf-8", &text);
vb@94
   979
        if (r)
vb@94
   980
            goto enomem;
vb@94
   981
vb@94
   982
        _sl = stringlist_add(_sl, text);
vb@94
   983
        if (_sl == NULL)
vb@94
   984
            goto enomem;
vb@94
   985
vb@94
   986
        free(text);
vb@94
   987
        text = NULL;
vb@94
   988
    }
vb@94
   989
vb@94
   990
    return _sl;
vb@94
   991
vb@94
   992
enomem:
vb@94
   993
    free_stringlist(sl);
vb@94
   994
    free(text);
vb@94
   995
vb@94
   996
    return NULL;
vb@94
   997
}
vb@94
   998
vb@94
   999
static PEP_STATUS read_fields(message *msg, clist *fieldlist)
vb@94
  1000
{
vb@94
  1001
    PEP_STATUS status = PEP_STATUS_OK;
vb@94
  1002
    struct mailimf_field * _field;
vb@94
  1003
    clistiter *cur;
vb@94
  1004
    size_t index;
vb@94
  1005
    int r;
vb@110
  1006
    stringpair_list_t *opt = msg->opt_fields;
vb@94
  1007
vb@94
  1008
    for (cur = clist_begin(fieldlist); cur != NULL; cur = clist_next(cur)) {
vb@94
  1009
        _field = clist_content(cur);
vb@94
  1010
vb@94
  1011
        switch (_field->fld_type) {
vb@94
  1012
            case MAILIMF_FIELD_MESSAGE_ID:
vb@94
  1013
                {
vb@94
  1014
                    char * text = _field->fld_data.fld_message_id->mid_value;
vb@116
  1015
vb@116
  1016
                    free(msg->id);
vb@94
  1017
                    index = 0;
vb@94
  1018
                    r = mailmime_encoded_phrase_parse("utf-8", text,
vb@94
  1019
                            strlen(text), &index, "utf-8", &msg->id);
vb@94
  1020
                    if (r)
vb@94
  1021
                        goto enomem;
vb@94
  1022
                }
vb@94
  1023
                break;
vb@94
  1024
vb@94
  1025
            case MAILIMF_FIELD_SUBJECT:
vb@94
  1026
                {
vb@94
  1027
                    char * text = _field->fld_data.fld_subject->sbj_value;
vb@116
  1028
vb@116
  1029
                    free(msg->shortmsg);
vb@94
  1030
                    index = 0;
vb@94
  1031
                    r = mailmime_encoded_phrase_parse("utf-8", text,
vb@94
  1032
                            strlen(text), &index, "utf-8", &msg->shortmsg);
vb@94
  1033
                    if (r)
vb@94
  1034
                        goto enomem;
vb@94
  1035
                }
vb@94
  1036
                break;
vb@94
  1037
vb@94
  1038
            case MAILIMF_FIELD_ORIG_DATE:
vb@94
  1039
                {
vb@94
  1040
                    struct mailimf_date_time *date =
vb@94
  1041
                        _field->fld_data.fld_orig_date->dt_date_time;
vb@116
  1042
vb@116
  1043
                    free_timestamp(msg->sent);
vb@94
  1044
                    msg->sent = etpantime_to_timestamp(date);
vb@94
  1045
                    if (msg->sent == NULL)
vb@94
  1046
                        goto enomem;
vb@94
  1047
                }
vb@94
  1048
                break;
vb@94
  1049
vb@94
  1050
            case MAILIMF_FIELD_FROM:
vb@94
  1051
                {
vb@94
  1052
                    struct mailimf_mailbox_list *mbl =
vb@94
  1053
                            _field->fld_data.fld_from->frm_mb_list;
vb@94
  1054
                    pEp_identity *ident;
vb@94
  1055
vb@94
  1056
                    ident = mbl_to_identity(mbl);
vb@94
  1057
                    if (ident == NULL)
vb@94
  1058
                        goto pep_error;
vb@94
  1059
vb@116
  1060
                    free_identity(msg->from);
vb@94
  1061
                    msg->from = ident;
vb@94
  1062
                }
vb@94
  1063
                break;
vb@94
  1064
vb@94
  1065
            case MAILIMF_FIELD_TO:
vb@94
  1066
                {
vb@94
  1067
                    struct mailimf_address_list *mal =
vb@94
  1068
                            _field->fld_data.fld_to->to_addr_list;
vb@94
  1069
                    identity_list *il = mal_to_identity_list(mal);
vb@94
  1070
                    if (il == NULL)
vb@94
  1071
                        goto enomem;
vb@116
  1072
vb@116
  1073
                    free_identity_list(msg->to);
vb@94
  1074
                    msg->to = il;
vb@94
  1075
                }
vb@94
  1076
                break;
vb@94
  1077
vb@94
  1078
            case MAILIMF_FIELD_CC:
vb@94
  1079
                {
vb@94
  1080
                    struct mailimf_address_list *mal =
vb@94
  1081
                            _field->fld_data.fld_cc->cc_addr_list;
vb@94
  1082
                    identity_list *il = mal_to_identity_list(mal);
vb@94
  1083
                    if (il == NULL)
vb@94
  1084
                        goto enomem;
vb@116
  1085
vb@116
  1086
                    free_identity_list(msg->cc);
vb@94
  1087
                    msg->cc = il;
vb@94
  1088
                }
vb@94
  1089
                break;
vb@94
  1090
vb@94
  1091
            case MAILIMF_FIELD_BCC:
vb@94
  1092
                {
vb@94
  1093
                    struct mailimf_address_list *mal =
vb@94
  1094
                            _field->fld_data.fld_bcc->bcc_addr_list;
vb@94
  1095
                    identity_list *il = mal_to_identity_list(mal);
vb@94
  1096
                    if (il == NULL)
vb@94
  1097
                        goto enomem;
vb@116
  1098
vb@116
  1099
                    free_identity_list(msg->bcc);
vb@94
  1100
                    msg->bcc = il;
vb@94
  1101
                }
vb@94
  1102
                break;
vb@94
  1103
vb@94
  1104
            case MAILIMF_FIELD_REPLY_TO:
vb@94
  1105
                {
vb@94
  1106
                    struct mailimf_address_list *mal =
vb@94
  1107
                            _field->fld_data.fld_reply_to->rt_addr_list;
vb@94
  1108
                    identity_list *il = mal_to_identity_list(mal);
vb@94
  1109
                    if (il == NULL)
vb@94
  1110
                        goto enomem;
vb@116
  1111
vb@116
  1112
                    free_identity_list(msg->reply_to);
vb@94
  1113
                    msg->reply_to = il;
vb@94
  1114
                }
vb@94
  1115
                break;
vb@94
  1116
vb@94
  1117
            case MAILIMF_FIELD_IN_REPLY_TO:
vb@94
  1118
                {
vb@94
  1119
                    clist *list = _field->fld_data.fld_in_reply_to->mid_list;
vb@94
  1120
                    stringlist_t *sl = clist_to_stringlist(list);
vb@94
  1121
                    if (sl == NULL)
vb@94
  1122
                        goto enomem;
vb@116
  1123
vb@116
  1124
                    free_stringlist(msg->in_reply_to);
vb@94
  1125
                    msg->in_reply_to = sl;
vb@94
  1126
                }
vb@94
  1127
                break;
vb@94
  1128
vb@94
  1129
            case MAILIMF_FIELD_REFERENCES:
vb@94
  1130
                {
vb@94
  1131
                    clist *list = _field->fld_data.fld_references->mid_list;
vb@94
  1132
                    stringlist_t *sl = clist_to_stringlist(list);
vb@94
  1133
                    if (sl == NULL)
vb@94
  1134
                        goto enomem;
vb@116
  1135
vb@116
  1136
                    free_stringlist(msg->references);
vb@94
  1137
                    msg->references = sl;
vb@94
  1138
                }
vb@94
  1139
                break;
vb@94
  1140
vb@94
  1141
            case MAILIMF_FIELD_KEYWORDS:
vb@94
  1142
                {
vb@94
  1143
                    clist *list = _field->fld_data.fld_keywords->kw_list;
vb@94
  1144
                    stringlist_t *sl = clist_to_stringlist(list);
vb@94
  1145
                    if (sl == NULL)
vb@94
  1146
                        goto enomem;
vb@116
  1147
vb@116
  1148
                    free_stringlist(msg->keywords);
vb@94
  1149
                    msg->keywords = sl;
vb@94
  1150
                }
vb@94
  1151
                break;
vb@94
  1152
vb@94
  1153
            case MAILIMF_FIELD_COMMENTS:
vb@94
  1154
                {
vb@94
  1155
                    char * text = _field->fld_data.fld_comments->cm_value;
vb@116
  1156
vb@116
  1157
                    free(msg->comments);
vb@94
  1158
                    index = 0;
vb@94
  1159
                    r = mailmime_encoded_phrase_parse("utf-8", text,
vb@94
  1160
                            strlen(text), &index, "utf-8", &msg->comments);
vb@94
  1161
                    if (r)
vb@94
  1162
                        goto enomem;
vb@94
  1163
                }
vb@94
  1164
                break;
vb@110
  1165
vb@110
  1166
            case MAILIMF_FIELD_OPTIONAL_FIELD:
vb@110
  1167
                {
vb@110
  1168
                    char * name =
vb@110
  1169
                            _field->fld_data.fld_optional_field->fld_name;
vb@110
  1170
                    char * value =
vb@110
  1171
                            _field->fld_data.fld_optional_field->fld_value;
vb@110
  1172
                    char *_value;
vb@110
  1173
vb@110
  1174
                    index = 0;
vb@110
  1175
                    r = mailmime_encoded_phrase_parse("utf-8", value,
vb@110
  1176
                            strlen(value), &index, "utf-8", &_value);
vb@110
  1177
                    if (r)
vb@110
  1178
                        goto enomem;
vb@110
  1179
vb@281
  1180
                    stringpair_t *pair = new_stringpair(name, _value);
vb@281
  1181
                    if (pair == NULL)
vb@281
  1182
                        goto enomem;
vb@110
  1183
vb@281
  1184
                    opt = stringpair_list_add(opt, pair);
vb@110
  1185
                    free(_value);
vb@110
  1186
                    if (opt == NULL)
vb@110
  1187
                        goto enomem;
vb@110
  1188
vb@110
  1189
                    if (msg->opt_fields == NULL)
vb@110
  1190
                        msg->opt_fields = opt;
vb@110
  1191
                }
vb@110
  1192
                break;
vb@94
  1193
        }
vb@94
  1194
    }
vb@94
  1195
vb@94
  1196
    return PEP_STATUS_OK;
vb@94
  1197
vb@94
  1198
enomem:
vb@94
  1199
    status = PEP_OUT_OF_MEMORY;
vb@94
  1200
vb@94
  1201
pep_error:
vb@94
  1202
    return status;
vb@94
  1203
}
vb@94
  1204
vb@147
  1205
static PEP_STATUS interpret_body(struct mailmime *part, char **longmsg, size_t *size)
vb@147
  1206
{
vb@147
  1207
    const char *text;
vb@159
  1208
    char *_longmsg;
vb@147
  1209
    size_t length;
vb@159
  1210
    size_t _size;
vb@147
  1211
    int code;
vb@147
  1212
    int r;
vb@147
  1213
    size_t index;
vb@159
  1214
    char *type = NULL;
vb@159
  1215
    char *charset = NULL;
vb@147
  1216
vb@147
  1217
    assert(part);
vb@147
  1218
    assert(longmsg);
vb@147
  1219
vb@147
  1220
    *longmsg = NULL;
vb@147
  1221
    if (size)
vb@147
  1222
        *size = 0;
vb@147
  1223
vb@147
  1224
    if (part->mm_body == NULL)
vb@147
  1225
        return PEP_ILLEGAL_VALUE;
vb@147
  1226
vb@147
  1227
    text = part->mm_body-> dt_data.dt_text.dt_data;
vb@147
  1228
    if (text == NULL)
vb@147
  1229
        return PEP_ILLEGAL_VALUE;
vb@147
  1230
vb@147
  1231
    length = part->mm_body->dt_data.dt_text.dt_length;
vb@147
  1232
vb@147
  1233
    if (part->mm_body->dt_encoded) {
vb@147
  1234
        code = part->mm_body->dt_encoding;
vb@147
  1235
        index = 0;
vb@159
  1236
        r = mailmime_part_parse(text, length, &index, code, &_longmsg, &_size);
vb@147
  1237
        switch (r) {
vb@147
  1238
            case MAILIMF_NO_ERROR:
vb@147
  1239
                break;
vb@147
  1240
            case MAILIMF_ERROR_MEMORY:
vb@147
  1241
                return PEP_OUT_OF_MEMORY;
vb@147
  1242
            default:
vb@147
  1243
                return PEP_ILLEGAL_VALUE;
vb@147
  1244
        }
vb@147
  1245
    }
vb@147
  1246
    else {
vb@289
  1247
        _size = length + 1;
vb@289
  1248
        _longmsg = strndup(text, length);
vb@159
  1249
        if (_longmsg == NULL)
vb@147
  1250
            return PEP_OUT_OF_MEMORY;
vb@147
  1251
    }
vb@147
  1252
vb@159
  1253
    if (part->mm_content_type) {
vb@159
  1254
        if (_get_content_type(part->mm_content_type, &type, &charset) == 0) {
vb@160
  1255
            if (charset && strncasecmp(charset, "utf-8", 5) != 0) {
vb@159
  1256
                char * _text;
vb@159
  1257
                int r = charconv("utf-8", charset, _longmsg, _size, &_text);
vb@159
  1258
                switch (r) {
vb@159
  1259
                    case MAILIMF_NO_ERROR:
vb@159
  1260
                        break;
vb@159
  1261
                    case MAILIMF_ERROR_MEMORY:
vb@159
  1262
                        return PEP_OUT_OF_MEMORY;
vb@159
  1263
                    default:
vb@159
  1264
                        return PEP_ILLEGAL_VALUE;
vb@159
  1265
                }
vb@159
  1266
                free(_longmsg);
vb@159
  1267
                _longmsg = _text;
vb@159
  1268
            }
vb@159
  1269
        }
vb@159
  1270
    }
krista@1536
  1271
    // FIXME: KG - we now have the text we want.
krista@1536
  1272
    // Now we need to strip sigs and process them if they are there..
krista@1536
  1273
    
vb@159
  1274
vb@159
  1275
    *longmsg = _longmsg;
vb@159
  1276
    if (size)
vb@159
  1277
        *size = _size;
vb@159
  1278
vb@147
  1279
    return PEP_STATUS_OK;
vb@147
  1280
}
vb@147
  1281
vb@118
  1282
static PEP_STATUS interpret_MIME(
vb@118
  1283
        struct mailmime *mime,
vb@118
  1284
        message *msg
vb@118
  1285
    )
vb@118
  1286
{
vb@118
  1287
    PEP_STATUS status = PEP_STATUS_OK;
vb@118
  1288
vb@118
  1289
    assert(mime);
vb@118
  1290
    assert(msg);
vb@118
  1291
vb@118
  1292
    struct mailmime_content *content = mime->mm_content_type;
vb@118
  1293
    if (content) {
vb@152
  1294
        if (_is_multipart(content, "alternative")) {
vb@118
  1295
            clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
vb@118
  1296
            if (partlist == NULL)
vb@118
  1297
                return PEP_ILLEGAL_VALUE;
vb@118
  1298
vb@118
  1299
            clistiter *cur;
vb@118
  1300
            for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
vb@120
  1301
                struct mailmime *part = clist_content(cur);
vb@118
  1302
                if (part == NULL)
vb@118
  1303
                    return PEP_ILLEGAL_VALUE;
vb@118
  1304
vb@120
  1305
                content = part->mm_content_type;
vb@120
  1306
                assert(content);
vb@120
  1307
                if (content == NULL)
vb@120
  1308
                    return PEP_ILLEGAL_VALUE;
vb@118
  1309
vb@152
  1310
                if (_is_text_part(content, "plain") && msg->longmsg == NULL) {
vb@152
  1311
                    status = interpret_body(part, &msg->longmsg, NULL);
vb@152
  1312
                    if (status)
vb@152
  1313
                        return status;
vb@152
  1314
                }
vb@152
  1315
                else if (_is_text_part(content, "html") &&
vb@152
  1316
                        msg->longmsg_formatted == NULL) {
vb@152
  1317
                    status = interpret_body(part, &msg->longmsg_formatted,
vb@152
  1318
                            NULL);
vb@152
  1319
                    if (status)
vb@152
  1320
                        return status;
vb@152
  1321
                }
vb@152
  1322
                else /* add as attachment */ {
vb@152
  1323
                    status = interpret_MIME(part, msg);
vb@152
  1324
                    if (status)
vb@152
  1325
                        return status;
vb@120
  1326
                }
vb@118
  1327
            }
vb@118
  1328
        }
vb@260
  1329
        else if (_is_multipart(content, "encrypted")) {
vb@260
  1330
            if (msg->longmsg == NULL)
vb@260
  1331
                msg->longmsg = strdup("");
vb@260
  1332
vb@260
  1333
            clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
vb@260
  1334
            if (partlist == NULL)
vb@260
  1335
                return PEP_ILLEGAL_VALUE;
vb@260
  1336
vb@260
  1337
            clistiter *cur;
vb@260
  1338
            for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
vb@260
  1339
                struct mailmime *part= clist_content(cur);
vb@260
  1340
                if (part == NULL)
vb@260
  1341
                    return PEP_ILLEGAL_VALUE;
vb@260
  1342
vb@260
  1343
                status = interpret_MIME(part, msg);
vb@260
  1344
                if (status != PEP_STATUS_OK)
vb@260
  1345
                    return status;
vb@260
  1346
            }
vb@260
  1347
        }
vb@152
  1348
        else if (_is_multipart(content, NULL)) {
vb@118
  1349
            clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
vb@118
  1350
            if (partlist == NULL)
vb@118
  1351
                return PEP_ILLEGAL_VALUE;
vb@118
  1352
vb@118
  1353
            clistiter *cur;
vb@118
  1354
            for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
vb@118
  1355
                struct mailmime *part= clist_content(cur);
vb@118
  1356
                if (part == NULL)
vb@118
  1357
                    return PEP_ILLEGAL_VALUE;
vb@118
  1358
vb@118
  1359
                status = interpret_MIME(part, msg);
vb@118
  1360
                if (status != PEP_STATUS_OK)
vb@118
  1361
                    return status;
vb@118
  1362
            }
vb@118
  1363
        }
vb@118
  1364
        else {
krista@1229
  1365
            if (_is_text_part(content, "html") &&
krista@1229
  1366
                msg->longmsg_formatted == NULL) {
krista@1229
  1367
                status = interpret_body(mime, &msg->longmsg_formatted,
krista@1229
  1368
                                        NULL);
krista@1229
  1369
                if (status)
krista@1229
  1370
                    return status;
krista@1229
  1371
            }
krista@1229
  1372
            else if (_is_text_part(content, NULL) && msg->longmsg == NULL) {
vb@152
  1373
                status = interpret_body(mime, &msg->longmsg, NULL);
vb@152
  1374
                if (status)
vb@152
  1375
                    return status;
vb@152
  1376
            }
vb@152
  1377
            else {
vb@152
  1378
                char *data = NULL;
vb@157
  1379
                size_t size = 0;
vb@157
  1380
                char * mime_type;
vb@159
  1381
                char * charset;
vb@157
  1382
                char * filename;
vb@159
  1383
                int r;
vb@118
  1384
vb@159
  1385
                r = _get_content_type(content, &mime_type, &charset);
vb@159
  1386
                switch (r) {
vb@159
  1387
                    case 0:
vb@159
  1388
                        break;
vb@159
  1389
                    case EINVAL:
vb@159
  1390
                        return PEP_ILLEGAL_VALUE;
vb@159
  1391
                    case ENOMEM:
vb@159
  1392
                        return PEP_OUT_OF_MEMORY;
vb@159
  1393
                    default:
vb@159
  1394
                        return PEP_UNKNOWN_ERROR;
vb@157
  1395
                }
vb@154
  1396
vb@159
  1397
                assert(mime_type);
vb@159
  1398
vb@152
  1399
                status = interpret_body(mime, &data, &size);
vb@152
  1400
                if (status)
vb@152
  1401
                    return status;
vb@152
  1402
krista@1873
  1403
                pEp_rid_list_t* resource_id_list = _get_resource_id_list(mime);
krista@1873
  1404
                pEp_rid_list_t* chosen_resource_id = choose_resource_id(resource_id_list);
krista@1873
  1405
                
krista@1873
  1406
                //filename = _get_filename_or_cid(mime);
vb@481
  1407
                char *_filename = NULL;
krista@1873
  1408
                
krista@1873
  1409
                if (chosen_resource_id) {
krista@1873
  1410
                    filename = chosen_resource_id->rid;
vb@481
  1411
                    size_t index = 0;
krista@1873
  1412
                    /* NOTA BENE */
krista@1873
  1413
                    /* The prefix we just added shouldn't be a problem - this is about decoding %XX (RFC 2392) */
krista@1873
  1414
                    /* If it becomes one, we have some MESSY fixing to do. :(                                  */
vb@481
  1415
                    r = mailmime_encoded_phrase_parse("utf-8", filename,
vb@481
  1416
                            strlen(filename), &index, "utf-8", &_filename);
krista@1872
  1417
                    if (r) {
vb@481
  1418
                        goto enomem;
krista@1872
  1419
                    }
krista@1873
  1420
                    char* file_prefix = NULL;
krista@1873
  1421
                    
krista@1873
  1422
                    /* in case there are others later */
krista@1873
  1423
                    switch (chosen_resource_id->rid_type) {
krista@1873
  1424
                        case PEP_RID_CID:
krista@1873
  1425
                            file_prefix = "cid";
krista@1873
  1426
                            break;
krista@1873
  1427
                        case PEP_RID_FILENAME:
krista@1873
  1428
                            file_prefix = "file";
krista@1873
  1429
                            break;
krista@1873
  1430
                        default:
krista@1873
  1431
                            break;
krista@1873
  1432
                    }
krista@1873
  1433
krista@1873
  1434
                    
krista@1873
  1435
                    if (file_prefix) {
krista@1881
  1436
                        filename = build_uri(file_prefix, _filename);
krista@1873
  1437
                        free(_filename);
krista@1873
  1438
                        _filename = filename;
krista@1873
  1439
                    }
vb@481
  1440
                }
vb@154
  1441
vb@260
  1442
                bloblist_t *_a = bloblist_add(msg->attachments, data, size,
krista@1871
  1443
                        mime_type, _filename);
vb@481
  1444
                free(_filename);
krista@1902
  1445
                free_rid_list(resource_id_list);
krista@1902
  1446
                resource_id_list = NULL;
vb@260
  1447
                if (_a == NULL)
vb@260
  1448
                    return PEP_OUT_OF_MEMORY;
vb@152
  1449
                if (msg->attachments == NULL)
vb@260
  1450
                    msg->attachments = _a;
vb@152
  1451
            }
vb@118
  1452
        }
vb@118
  1453
    }
vb@118
  1454
vb@118
  1455
    return PEP_STATUS_OK;
vb@481
  1456
vb@481
  1457
enomem:
vb@481
  1458
    return PEP_OUT_OF_MEMORY;
vb@118
  1459
}
vb@118
  1460
vb@89
  1461
DYNAMIC_API PEP_STATUS mime_decode_message(
vb@89
  1462
        const char *mimetext,
vb@269
  1463
        size_t size,
vb@89
  1464
        message **msg
vb@89
  1465
    )
vb@89
  1466
{
vb@89
  1467
    PEP_STATUS status = PEP_STATUS_OK;
vb@89
  1468
    struct mailmime * mime = NULL;
vb@89
  1469
    int r;
vb@94
  1470
    message *_msg = NULL;
vb@94
  1471
    size_t index;
vb@89
  1472
vb@89
  1473
    assert(mimetext);
vb@89
  1474
    assert(msg);
vb@89
  1475
vb@191
  1476
    if (!(mimetext && msg))
vb@191
  1477
        return PEP_ILLEGAL_VALUE;
vb@191
  1478
vb@89
  1479
    *msg = NULL;
vb@113
  1480
vb@94
  1481
    index = 0;
vb@269
  1482
    r = mailmime_parse(mimetext, size, &index, &mime);
vb@89
  1483
    assert(r == 0);
vb@89
  1484
    assert(mime);
vb@90
  1485
    if (r) {
vb@89
  1486
        if (r == MAILIMF_ERROR_MEMORY)
vb@89
  1487
            goto enomem;
vb@89
  1488
        else
vb@89
  1489
            goto err_mime;
vb@89
  1490
    }
vb@89
  1491
vb@117
  1492
    _msg = calloc(1, sizeof(message));
vb@117
  1493
    assert(_msg);
vb@117
  1494
    if (_msg == NULL)
vb@117
  1495
        goto enomem;
vb@116
  1496
vb@147
  1497
    clist * _fieldlist = _get_fields(mime);
vb@147
  1498
    if (_fieldlist) {
vb@117
  1499
        status = read_fields(_msg, _fieldlist);
vb@116
  1500
        if (status != PEP_STATUS_OK)
vb@116
  1501
            goto pep_error;
vb@116
  1502
    }
vb@116
  1503
vb@147
  1504
    struct mailmime_content *content = _get_content(mime);
vb@117
  1505
vb@147
  1506
    if (content) {
vb@260
  1507
        status = interpret_MIME(mime->mm_data.mm_message.mm_msg_mime,
vb@260
  1508
                _msg);
vb@260
  1509
        if (status != PEP_STATUS_OK)
vb@260
  1510
            goto pep_error;
vb@116
  1511
    }
vb@116
  1512
vb@89
  1513
    mailmime_free(mime);
vb@94
  1514
    *msg = _msg;
vb@89
  1515
vb@89
  1516
    return status;
vb@89
  1517
vb@89
  1518
err_mime:
vb@89
  1519
    status = PEP_ILLEGAL_VALUE;
vb@89
  1520
    goto pep_error;
vb@89
  1521
vb@89
  1522
enomem:
vb@89
  1523
    status = PEP_OUT_OF_MEMORY;
vb@89
  1524
vb@89
  1525
pep_error:
vb@94
  1526
    free_message(_msg);
vb@94
  1527
vb@89
  1528
    if (mime)
vb@89
  1529
        mailmime_free(mime);
vb@89
  1530
vb@89
  1531
    return status;
vb@89
  1532
}