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