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