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