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