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