src/mime.c
author vb
Wed, 11 Mar 2015 11:52:14 +0100
changeset 98 9e3d28932e7b
parent 94 9ec29aa10b58
child 108 be7d5a542952
permissions -rw-r--r--
reorga
vb@48
     1
#include "mime.h"
vb@48
     2
vb@48
     3
#include <string.h>
vb@48
     4
#include <stdlib.h>
vb@48
     5
#include <assert.h>
vb@48
     6
#include <errno.h>
vb@48
     7
#include <unistd.h>
vb@48
     8
vb@48
     9
#include "etpan_mime.h"
vb@63
    10
#include "wrappers.h"
vb@48
    11
vb@94
    12
#define NOT_IMPLEMENTED assert(0);
vb@94
    13
vb@89
    14
static PEP_STATUS render_mime(struct mailmime *mime, char **mimetext)
vb@48
    15
{
vb@89
    16
    PEP_STATUS status = PEP_STATUS_OK;
vb@48
    17
    int fd;
vb@48
    18
    FILE *file = NULL;
vb@48
    19
    size_t size;
vb@48
    20
    char *buf = NULL;
vb@89
    21
    int col;
vb@89
    22
    int r;
vb@51
    23
    char *template = strdup("/tmp/pEp.XXXXXXXXXXXXXXXXXXXX");
vb@48
    24
    assert(template);
vb@48
    25
    if (template == NULL)
vb@48
    26
        goto enomem;
vb@48
    27
vb@89
    28
    *mimetext = NULL;
vb@89
    29
vb@63
    30
    fd = Mkstemp(template);
vb@48
    31
    assert(fd != -1);
vb@48
    32
    if (fd == -1)
vb@48
    33
        goto err_file;
vb@48
    34
vb@48
    35
    r = unlink(template);
vb@48
    36
    assert(r == 0);
vb@90
    37
    if (r)
vb@48
    38
        goto err_file;
vb@48
    39
vb@48
    40
    free(template);
vb@48
    41
    template = NULL;
vb@48
    42
vb@63
    43
    file = Fdopen(fd, "w+");
vb@48
    44
    assert(file);
vb@48
    45
    if (file == NULL) {
vb@48
    46
        switch (errno) {
vb@48
    47
            case ENOMEM:
vb@48
    48
                goto enomem;
vb@48
    49
            default:
vb@48
    50
                goto err_file;
vb@48
    51
        }
vb@48
    52
    }
vb@48
    53
vb@48
    54
    fd = -1;
vb@48
    55
vb@48
    56
    col = 0;
vb@48
    57
    r = mailmime_write_file(file, &col, mime);
vb@48
    58
    assert(r == MAILIMF_NO_ERROR);
vb@48
    59
    if (r == MAILIMF_ERROR_MEMORY)
vb@48
    60
        goto enomem;
vb@48
    61
    else if (r != MAILIMF_NO_ERROR)
vb@48
    62
        goto err_file;
vb@48
    63
vb@48
    64
    off_t len = ftello(file);
vb@48
    65
    assert(len != -1);
vb@48
    66
    if (len == -1 && errno == EOVERFLOW)
vb@48
    67
        goto err_file;
vb@48
    68
Edouard@70
    69
    if (len + 1 > SIZE_MAX)
vb@48
    70
        goto err_buffer;
vb@48
    71
vb@48
    72
    size = (size_t) len;
vb@48
    73
vb@51
    74
    errno = 0;
vb@48
    75
    rewind(file);
vb@51
    76
    assert(errno == 0);
vb@62
    77
    switch (errno) {
vb@63
    78
        case 0:
vb@63
    79
            break;
vb@62
    80
        case ENOMEM:
vb@62
    81
            goto enomem;
vb@62
    82
        default:
vb@62
    83
            goto err_file;
vb@62
    84
    }
vb@48
    85
vb@48
    86
    buf = calloc(1, size + 1);
vb@48
    87
    assert(buf);
vb@48
    88
    if (buf == NULL)
vb@48
    89
        goto enomem;
vb@63
    90
 
vb@63
    91
    size_t _read;
vb@89
    92
    _read = Fread(buf, size, 1, file);
vb@63
    93
    assert(_read == size);
vb@62
    94
vb@63
    95
    r = Fclose(file);
vb@62
    96
    assert(r == 0);
vb@62
    97
vb@87
    98
    *mimetext = buf;
vb@48
    99
    return PEP_STATUS_OK;
vb@48
   100
vb@48
   101
err_buffer:
vb@88
   102
    status = PEP_BUFFER_TOO_SMALL;
vb@88
   103
    goto pep_error;
vb@48
   104
vb@48
   105
err_file:
vb@88
   106
    status = PEP_CANNOT_CREATE_TEMP_FILE;
vb@88
   107
    goto pep_error;
vb@48
   108
vb@48
   109
enomem:
vb@88
   110
    status = PEP_OUT_OF_MEMORY;
vb@52
   111
vb@88
   112
pep_error:
vb@48
   113
    free(buf);
vb@48
   114
    free(template);
vb@48
   115
vb@62
   116
    if (file) {
vb@63
   117
        r = Fclose(file);
vb@62
   118
        assert(r == 0);
vb@62
   119
    }
vb@62
   120
    else if (fd != -1) {
vb@63
   121
        r = Close(fd);
vb@62
   122
        assert(r == 0);
vb@62
   123
    }
vb@48
   124
vb@89
   125
    return status;
vb@89
   126
}
vb@89
   127
vb@89
   128
static PEP_STATUS mime_html_text(
vb@89
   129
        const char *plaintext,
vb@89
   130
        const char *htmltext,
vb@89
   131
        struct mailmime **result
vb@89
   132
    )
vb@89
   133
{
vb@89
   134
    PEP_STATUS status = PEP_STATUS_OK;
vb@89
   135
    struct mailmime * mime = NULL;
vb@89
   136
    struct mailmime * submime = NULL;
vb@89
   137
    int r;
vb@89
   138
vb@89
   139
    assert(plaintext);
vb@89
   140
    assert(htmltext);
vb@89
   141
    assert(result);
vb@89
   142
vb@89
   143
    *result = NULL;
vb@89
   144
vb@89
   145
    mime = part_multiple_new("multipart/alternative", NULL);
vb@89
   146
    assert(mime);
vb@89
   147
    if (mime == NULL)
vb@89
   148
        goto enomem;
vb@89
   149
vb@89
   150
    submime = get_text_part("text/plain", plaintext, strlen(plaintext),
vb@89
   151
            MAILMIME_MECHANISM_QUOTED_PRINTABLE);
vb@89
   152
    assert(submime);
vb@89
   153
    if (submime == NULL)
vb@89
   154
        goto enomem;
vb@89
   155
vb@89
   156
    r = mailmime_smart_add_part(mime, submime);
vb@89
   157
    assert(r == MAILIMF_NO_ERROR);
vb@89
   158
    if (r == MAILIMF_ERROR_MEMORY) {
vb@89
   159
        goto enomem;
vb@89
   160
    }
vb@89
   161
    else {
vb@89
   162
        // mailmime_smart_add_part() takes ownership of submime
vb@89
   163
        submime = NULL;
vb@89
   164
    }
vb@89
   165
vb@89
   166
    submime = get_text_part("text/html", htmltext, strlen(htmltext),
vb@89
   167
            MAILMIME_MECHANISM_QUOTED_PRINTABLE);
vb@89
   168
    assert(submime);
vb@89
   169
    if (submime == NULL)
vb@89
   170
        goto enomem;
vb@89
   171
vb@89
   172
    r = mailmime_smart_add_part(mime, submime);
vb@89
   173
    assert(r == MAILIMF_NO_ERROR);
vb@89
   174
    if (r == MAILIMF_ERROR_MEMORY)
vb@89
   175
        goto enomem;
vb@89
   176
    else {
vb@89
   177
        // mailmime_smart_add_part() takes ownership of submime
vb@89
   178
        submime = NULL;
vb@89
   179
    }
vb@89
   180
vb@89
   181
    *result = mime;
vb@89
   182
    return PEP_STATUS_OK;
vb@89
   183
vb@89
   184
enomem:
vb@89
   185
    status = PEP_OUT_OF_MEMORY;
vb@89
   186
vb@89
   187
pep_error:
vb@59
   188
    if (mime)
vb@59
   189
        mailmime_free(mime);
vb@89
   190
vb@48
   191
    if (submime)
vb@48
   192
        mailmime_free(submime);
vb@48
   193
vb@88
   194
    return status;
vb@48
   195
}
vb@88
   196
vb@89
   197
static PEP_STATUS mime_attachment(
vb@89
   198
        bloblist_t *blob,
vb@89
   199
        struct mailmime **result
vb@88
   200
    )
vb@88
   201
{
vb@88
   202
    PEP_STATUS status = PEP_STATUS_OK;
vb@89
   203
    struct mailmime * mime = NULL;
vb@89
   204
    char * mime_type;
vb@88
   205
vb@89
   206
    assert(blob);
vb@89
   207
    assert(result);
vb@88
   208
vb@89
   209
    *result = NULL;
vb@88
   210
vb@89
   211
    if (blob->mime_type == NULL)
vb@89
   212
        mime_type = "application/octet-stream";
vb@89
   213
    else
vb@89
   214
        mime_type = blob->mime_type;
vb@89
   215
vb@89
   216
    mime = get_file_part(blob->file_name, mime_type, blob->data, blob->size);
vb@89
   217
    assert(mime);
vb@89
   218
    if (mime == NULL)
vb@89
   219
        goto enomem;
vb@89
   220
vb@89
   221
    *result = mime;
vb@89
   222
    return PEP_STATUS_OK;
vb@88
   223
vb@88
   224
enomem:
vb@88
   225
    status = PEP_OUT_OF_MEMORY;
vb@88
   226
vb@88
   227
pep_error:
vb@89
   228
    if (mime)
vb@89
   229
        mailmime_free(mime);
vb@89
   230
vb@88
   231
    return status;
vb@88
   232
}
vb@88
   233
vb@94
   234
static struct mailimf_mailbox * identity_to_mailbox(const pEp_identity *ident)
vb@94
   235
{
vb@94
   236
    char *_username = NULL;
vb@94
   237
    struct mailimf_mailbox *mb;
vb@94
   238
vb@94
   239
    _username = mailmime_encode_subject_header("utf-8", ident->username, 0);
vb@94
   240
    if (_username == NULL)
vb@94
   241
        goto enomem;
vb@94
   242
vb@94
   243
    mb = mailbox_from_string(_username, ident->address);
vb@94
   244
    if (mb == NULL)
vb@94
   245
        goto enomem;
vb@94
   246
vb@94
   247
    free(_username);
vb@94
   248
    _username = NULL;
vb@94
   249
vb@94
   250
    return mb;
vb@94
   251
vb@94
   252
enomem:
vb@94
   253
    free(_username);
vb@94
   254
    return NULL;
vb@94
   255
}
vb@94
   256
vb@94
   257
static struct mailimf_mailbox_list * identity_to_mbl(
vb@94
   258
        const pEp_identity *ident)
vb@90
   259
{
vb@90
   260
    struct mailimf_mailbox_list *mbl = NULL;
vb@90
   261
    struct mailimf_mailbox *mb = NULL;
vb@90
   262
    clist *list = NULL;
vb@90
   263
    int r;
vb@90
   264
vb@90
   265
    assert(ident);
vb@90
   266
vb@90
   267
    list = clist_new();
vb@90
   268
    if (list == NULL)
vb@90
   269
        goto enomem;
vb@90
   270
vb@94
   271
    mb = identity_to_mailbox(ident);
vb@90
   272
    if (mb == NULL)
vb@90
   273
        goto enomem;
vb@90
   274
vb@90
   275
    r = clist_append(list, mb);
vb@90
   276
    if (r)
vb@90
   277
        goto enomem;
vb@90
   278
vb@90
   279
    mbl = mailimf_mailbox_list_new(list);
vb@90
   280
    if (mbl == NULL)
vb@90
   281
        goto enomem;
vb@90
   282
vb@90
   283
    return mbl;
vb@90
   284
vb@90
   285
enomem:
vb@90
   286
    if (mb)
vb@90
   287
        mailimf_mailbox_free(mb);
vb@90
   288
vb@90
   289
    if (list)
vb@90
   290
        clist_free(list);
vb@90
   291
vb@90
   292
    return NULL;
vb@90
   293
}
vb@90
   294
vb@94
   295
static struct mailimf_address_list * identity_list_to_mal(identity_list *il)
vb@90
   296
{
vb@93
   297
    struct mailimf_address_list *mal = NULL;
vb@90
   298
    struct mailimf_mailbox *mb = NULL;
vb@93
   299
    struct mailimf_address * addr = NULL;
vb@90
   300
    clist *list = NULL;
vb@90
   301
    int r;
vb@90
   302
vb@90
   303
    assert(il);
vb@90
   304
vb@90
   305
    list = clist_new();
vb@90
   306
    if (list == NULL)
vb@90
   307
        goto enomem;
vb@90
   308
vb@90
   309
    identity_list *_il;
vb@90
   310
    for (_il = il; _il; _il = _il->next) {
vb@94
   311
        mb = identity_to_mailbox(_il->ident);
vb@90
   312
        if (mb == NULL)
vb@90
   313
            goto enomem;
vb@90
   314
vb@93
   315
        addr = mailimf_address_new(MAILIMF_ADDRESS_MAILBOX, mb, NULL);
vb@93
   316
        if (addr == NULL)
vb@93
   317
            goto enomem;
vb@93
   318
        mb = NULL;
vb@93
   319
vb@93
   320
        r = clist_append(list, addr);
vb@90
   321
        if (r)
vb@90
   322
            goto enomem;
vb@93
   323
        addr = NULL;
vb@90
   324
    }
vb@93
   325
    mal = mailimf_address_list_new(list);
vb@93
   326
    if (mal == NULL)
vb@90
   327
        goto enomem;
vb@90
   328
vb@93
   329
    return mal;
vb@90
   330
vb@90
   331
enomem:
vb@90
   332
    if (mb)
vb@90
   333
        mailimf_mailbox_free(mb);
vb@90
   334
vb@93
   335
    if (addr)
vb@93
   336
        mailimf_address_free(addr);
vb@93
   337
vb@90
   338
    if (list)
vb@90
   339
        clist_free(list);
vb@90
   340
vb@90
   341
    return NULL;
vb@90
   342
}
vb@90
   343
vb@94
   344
static clist * stringlist_to_clist(stringlist_t *sl)
vb@91
   345
{
vb@91
   346
    clist * cl = clist_new();
vb@91
   347
    assert(cl);
vb@91
   348
    if (cl == NULL)
vb@91
   349
        return NULL;
vb@91
   350
vb@91
   351
    stringlist_t *_sl;
vb@91
   352
    for (_sl = sl; _sl; _sl = _sl->next) {
vb@91
   353
        int r;
vb@94
   354
        char * value = mailmime_encode_subject_header("utf-8", _sl->value, 0);
vb@91
   355
        assert(value);
vb@91
   356
        if (value == NULL) {
vb@91
   357
            clist_free(cl);
vb@91
   358
            return NULL;
vb@91
   359
        }
vb@91
   360
        r = clist_append(cl, value);
vb@91
   361
        assert(r == 0);
vb@91
   362
        if (r) {
vb@91
   363
            free(value);
vb@91
   364
            clist_free(cl);
vb@91
   365
            return NULL;
vb@91
   366
        }
vb@91
   367
    }
vb@91
   368
vb@91
   369
    return cl;
vb@91
   370
}
vb@91
   371
vb@89
   372
static PEP_STATUS build_fields(const message *msg, struct mailimf_fields **result)
vb@89
   373
{
vb@89
   374
    PEP_STATUS status = PEP_STATUS_OK;
vb@89
   375
    struct mailimf_fields * fields = NULL;
vb@89
   376
    int r;
vb@89
   377
    clist * fields_list = NULL;
vb@89
   378
    char *subject = msg->shortmsg ? msg->shortmsg : "pEp";
vb@89
   379
vb@89
   380
    assert(msg);
vb@89
   381
    assert(msg->from);
vb@89
   382
    assert(msg->from->address);
vb@89
   383
    assert(result);
vb@89
   384
vb@89
   385
    *result = NULL;
vb@89
   386
vb@89
   387
    fields_list = clist_new();
vb@89
   388
    assert(fields_list);
vb@89
   389
    if (fields_list == NULL)
vb@89
   390
        goto enomem;
vb@89
   391
vb@90
   392
    if (msg->id) {
vb@90
   393
        char *_msgid = strdup(msg->id);
vb@90
   394
        if (_msgid == NULL)
vb@90
   395
            goto enomem;
vb@89
   396
vb@90
   397
        r = _append_field(fields_list, MAILIMF_FIELD_MESSAGE_ID,
vb@90
   398
                (_new_func_t) mailimf_message_id_new, _msgid);
vb@90
   399
        if (r) {
vb@90
   400
            free(_msgid);
vb@90
   401
            goto enomem;
vb@90
   402
        }
vb@90
   403
    }
vb@90
   404
vb@90
   405
    /* if (subject) */ {
vb@94
   406
        char *_subject = mailmime_encode_subject_header("utf-8", subject, 1);
vb@90
   407
        if (_subject == NULL)
vb@90
   408
            goto enomem;
vb@90
   409
vb@90
   410
        r = _append_field(fields_list, MAILIMF_FIELD_SUBJECT,
vb@90
   411
                (_new_func_t) mailimf_subject_new, _subject);
vb@90
   412
        if (r) {
vb@90
   413
            free(_subject);
vb@90
   414
            goto enomem;
vb@90
   415
        }
vb@90
   416
    }
vb@90
   417
vb@90
   418
    if (msg->sent) {
vb@90
   419
        struct mailimf_date_time * dt = timestamp_to_etpantime(msg->sent);
vb@90
   420
        if (dt == NULL)
vb@90
   421
            goto enomem;
vb@90
   422
vb@90
   423
        r = _append_field(fields_list, MAILIMF_FIELD_ORIG_DATE,
vb@90
   424
                (_new_func_t) mailimf_orig_date_new, dt);
vb@90
   425
        if (r) {
vb@90
   426
            mailimf_date_time_free(dt);
vb@90
   427
            goto enomem;
vb@90
   428
        }
vb@90
   429
        dt = NULL;
vb@90
   430
    }
vb@90
   431
vb@91
   432
    /* if (msg->from) */ {
vb@94
   433
        struct mailimf_mailbox_list *from = identity_to_mbl(msg->from);
vb@90
   434
        if (from == NULL)
vb@90
   435
            goto enomem;
vb@90
   436
vb@90
   437
        r = _append_field(fields_list, MAILIMF_FIELD_FROM,
vb@90
   438
                (_new_func_t) mailimf_from_new, from);
vb@90
   439
        if (r) {
vb@90
   440
            mailimf_mailbox_list_free(from);
vb@90
   441
            goto enomem;
vb@90
   442
        }
vb@90
   443
    }
vb@90
   444
vb@90
   445
    if (msg->to) {
vb@94
   446
        struct mailimf_address_list *to = identity_list_to_mal(msg->to);
vb@90
   447
        if (to == NULL)
vb@90
   448
            goto enomem;
vb@90
   449
vb@91
   450
        r = _append_field(fields_list, MAILIMF_FIELD_TO,
vb@90
   451
                (_new_func_t) mailimf_to_new, to);
vb@90
   452
        if (r) {
vb@93
   453
            mailimf_address_list_free(to);
vb@90
   454
            goto enomem;
vb@90
   455
        }
vb@90
   456
    }
vb@89
   457
vb@91
   458
    if (msg->cc) {
vb@94
   459
        struct mailimf_address_list *cc = identity_list_to_mal(msg->cc);
vb@91
   460
        if (cc == NULL)
vb@91
   461
            goto enomem;
vb@91
   462
vb@91
   463
        r = _append_field(fields_list, MAILIMF_FIELD_CC,
vb@91
   464
                (_new_func_t) mailimf_cc_new, cc);
vb@91
   465
        if (r) {
vb@93
   466
            mailimf_address_list_free(cc);
vb@91
   467
            goto enomem;
vb@91
   468
        }
vb@91
   469
    }
vb@91
   470
    
vb@91
   471
    if (msg->bcc) {
vb@94
   472
        struct mailimf_address_list *bcc = identity_list_to_mal(msg->bcc);
vb@91
   473
        if (bcc == NULL)
vb@91
   474
            goto enomem;
vb@91
   475
vb@91
   476
        r = _append_field(fields_list, MAILIMF_FIELD_BCC,
vb@91
   477
                (_new_func_t) mailimf_bcc_new, bcc);
vb@91
   478
        if (r) {
vb@93
   479
            mailimf_address_list_free(bcc);
vb@91
   480
            goto enomem;
vb@91
   481
        }
vb@91
   482
    }
vb@91
   483
    
vb@91
   484
    if (msg->reply_to) {
vb@94
   485
        struct mailimf_address_list *reply_to = identity_list_to_mal(msg->reply_to);
vb@91
   486
        if (reply_to == NULL)
vb@91
   487
            goto enomem;
vb@91
   488
vb@91
   489
        r = _append_field(fields_list, MAILIMF_FIELD_REPLY_TO,
vb@91
   490
                (_new_func_t) mailimf_reply_to_new, reply_to);
vb@91
   491
        if (r) {
vb@94
   492
            mailimf_address_list_free(reply_to);
vb@91
   493
            goto enomem;
vb@91
   494
        }
vb@91
   495
    }
vb@91
   496
vb@91
   497
    if (msg->in_reply_to) {
vb@94
   498
        clist *in_reply_to = stringlist_to_clist(msg->in_reply_to);
vb@91
   499
        if (in_reply_to == NULL)
vb@91
   500
            goto enomem;
vb@91
   501
vb@91
   502
        r = _append_field(fields_list, MAILIMF_FIELD_IN_REPLY_TO,
vb@91
   503
                (_new_func_t) mailimf_in_reply_to_new, in_reply_to);
vb@91
   504
        if (r) {
vb@94
   505
            clist_free(in_reply_to);
vb@91
   506
            goto enomem;
vb@91
   507
        }
vb@91
   508
    }
vb@91
   509
vb@91
   510
    if (msg->references) {
vb@94
   511
        clist *references = stringlist_to_clist(msg->references);
vb@91
   512
        if (references == NULL)
vb@91
   513
            goto enomem;
vb@91
   514
vb@91
   515
        r = _append_field(fields_list, MAILIMF_FIELD_REFERENCES,
vb@91
   516
                (_new_func_t) mailimf_references_new, references);
vb@91
   517
        if (r) {
vb@91
   518
            clist_free(references);
vb@91
   519
            goto enomem;
vb@91
   520
        }
vb@91
   521
    }
vb@91
   522
vb@91
   523
    if (msg->keywords) {
vb@94
   524
        clist *keywords = stringlist_to_clist(msg->keywords);
vb@91
   525
        if (keywords == NULL)
vb@91
   526
            goto enomem;
vb@91
   527
vb@91
   528
        r = _append_field(fields_list, MAILIMF_FIELD_KEYWORDS,
vb@91
   529
                (_new_func_t) mailimf_keywords_new, keywords);
vb@91
   530
        if (r) {
vb@91
   531
            clist_free(keywords);
vb@91
   532
            goto enomem;
vb@91
   533
        }
vb@91
   534
    }
vb@91
   535
vb@91
   536
    if (msg->comments) {
vb@94
   537
        char *comments = mailmime_encode_subject_header("utf-8", msg->comments,
vb@94
   538
                0);
vb@91
   539
        if (comments == NULL)
vb@91
   540
            goto enomem;
vb@91
   541
vb@91
   542
        r = _append_field(fields_list, MAILIMF_FIELD_COMMENTS,
vb@91
   543
                (_new_func_t) mailimf_comments_new, comments);
vb@91
   544
        if (r) {
vb@91
   545
            free(comments);
vb@91
   546
            goto enomem;
vb@91
   547
        }
vb@91
   548
    }
vb@91
   549
vb@98
   550
    if (msg->opt_fields) {
vb@98
   551
        r = _append_optional_field(fields_list, "X-pEp-Version", PEP_VERSION);
vb@98
   552
        if (r)
vb@98
   553
            goto enomem;
vb@98
   554
    }
vb@94
   555
vb@89
   556
    fields = mailimf_fields_new(fields_list);
vb@89
   557
    assert(fields);
vb@89
   558
    if (fields == NULL)
vb@89
   559
        goto enomem;
vb@89
   560
vb@89
   561
    *result = fields;
vb@89
   562
vb@89
   563
    return PEP_STATUS_OK;
vb@89
   564
vb@89
   565
enomem:
vb@89
   566
    status = PEP_OUT_OF_MEMORY;
vb@89
   567
vb@89
   568
pep_error:
vb@89
   569
    if (fields_list)
vb@89
   570
        clist_free(fields_list);
vb@89
   571
vb@89
   572
    if (fields)
vb@89
   573
        mailimf_fields_free(fields);
vb@89
   574
vb@89
   575
    return status;
vb@89
   576
}
vb@89
   577
vb@89
   578
DYNAMIC_API PEP_STATUS mime_encode_message(
vb@89
   579
        const message *msg,
vb@89
   580
        char **mimetext
vb@89
   581
    )
vb@89
   582
{
vb@89
   583
    struct mailmime * msg_mime = NULL;
vb@89
   584
    struct mailmime * mime = NULL;
vb@89
   585
    struct mailmime * submime = NULL;
vb@90
   586
    struct mailimf_fields * fields = NULL;
vb@89
   587
    char *buf = NULL;
vb@89
   588
    int r;
vb@89
   589
    PEP_STATUS status;
vb@89
   590
    char *subject;
vb@89
   591
    char *plaintext;
vb@89
   592
    char *htmltext;
vb@89
   593
vb@89
   594
    assert(msg);
vb@89
   595
    assert(mimetext);
vb@89
   596
vb@89
   597
    *mimetext = NULL;
vb@89
   598
vb@89
   599
    subject = (msg->shortmsg) ? msg->shortmsg : "pEp";
vb@89
   600
    plaintext = (msg->longmsg) ? msg->longmsg : "";
vb@89
   601
    htmltext = msg->longmsg_formatted;
vb@89
   602
vb@89
   603
    if (htmltext) {
vb@89
   604
        status = mime_html_text(plaintext, htmltext, &mime);
vb@89
   605
        if (status != PEP_STATUS_OK)
vb@89
   606
            goto pep_error;
vb@89
   607
    }
vb@89
   608
    else {
vb@90
   609
        mime = get_text_part("text/plain", plaintext, strlen(plaintext),
vb@89
   610
                MAILMIME_MECHANISM_QUOTED_PRINTABLE);
vb@89
   611
        assert(mime);
vb@89
   612
        if (mime == NULL)
vb@89
   613
            goto enomem;
vb@89
   614
    }
vb@89
   615
vb@89
   616
    if (msg->attachments) {
vb@89
   617
        submime = mime;
vb@89
   618
        mime = part_multiple_new("multipart/mixed", NULL);
vb@89
   619
        assert(mime);
vb@89
   620
        if (mime == NULL)
vb@89
   621
            goto enomem;
vb@89
   622
vb@89
   623
        r = mailmime_smart_add_part(mime, submime);
vb@89
   624
        assert(r == MAILIMF_NO_ERROR);
vb@89
   625
        if (r == MAILIMF_ERROR_MEMORY) {
vb@89
   626
            goto enomem;
vb@89
   627
        }
vb@89
   628
        else {
vb@89
   629
            // mailmime_smart_add_part() takes ownership of submime
vb@89
   630
            submime = NULL;
vb@89
   631
        }
vb@89
   632
vb@89
   633
        bloblist_t *_a;
vb@89
   634
        for (_a = msg->attachments; _a != NULL; _a = _a->next) {
vb@89
   635
            char * mime_type;
vb@89
   636
vb@89
   637
            assert(_a->data);
vb@89
   638
            assert(_a->size);
vb@89
   639
vb@89
   640
            status = mime_attachment(_a, &submime);
vb@89
   641
            if (status != PEP_STATUS_OK)
vb@89
   642
                goto pep_error;
vb@89
   643
vb@89
   644
            r = mailmime_smart_add_part(mime, submime);
vb@89
   645
            assert(r == MAILIMF_NO_ERROR);
vb@89
   646
            if (r == MAILIMF_ERROR_MEMORY) {
vb@89
   647
                goto enomem;
vb@89
   648
            }
vb@89
   649
            else {
vb@89
   650
                // mailmime_smart_add_part() takes ownership of submime
vb@89
   651
                submime = NULL;
vb@89
   652
            }
vb@89
   653
        }
vb@89
   654
    }
vb@89
   655
vb@89
   656
    msg_mime = mailmime_new_message_data(NULL);
vb@90
   657
    assert(msg_mime);
vb@90
   658
    if (msg_mime == NULL)
vb@90
   659
        goto enomem;
vb@89
   660
vb@90
   661
    r = mailmime_add_part(msg_mime, mime);
vb@90
   662
    if (r) {
vb@90
   663
        mailmime_free(mime);
vb@90
   664
        goto enomem;
vb@90
   665
    }
vb@90
   666
vb@90
   667
    status = build_fields(msg, &fields);
vb@90
   668
    if (status != PEP_STATUS_OK)
vb@90
   669
        goto pep_error;
vb@90
   670
vb@90
   671
    mailmime_set_imf_fields(msg_mime, fields);
vb@90
   672
vb@90
   673
    status = render_mime(msg_mime, &buf);
vb@89
   674
    if (status != PEP_STATUS_OK)
vb@89
   675
        goto pep_error;
vb@89
   676
vb@89
   677
    mailmime_free(msg_mime);
vb@89
   678
    *mimetext = buf;
vb@90
   679
vb@89
   680
    return PEP_STATUS_OK;
vb@89
   681
vb@89
   682
enomem:
vb@89
   683
    status = PEP_OUT_OF_MEMORY;
vb@89
   684
vb@89
   685
pep_error:
vb@89
   686
    if (msg_mime)
vb@90
   687
        mailmime_free(msg_mime);
vb@89
   688
    else
vb@89
   689
        if (mime)
vb@89
   690
            mailmime_free(mime);
vb@89
   691
vb@89
   692
    if (submime)
vb@89
   693
        mailmime_free(submime);
vb@89
   694
vb@89
   695
    return status;
vb@89
   696
}
vb@89
   697
vb@94
   698
static pEp_identity *mailbox_to_identity(const struct mailimf_mailbox * mb)
vb@94
   699
{
vb@94
   700
    pEp_identity *ident;
vb@94
   701
    char *username = NULL;
vb@94
   702
    size_t index;
vb@94
   703
    int r;
vb@94
   704
vb@94
   705
    index = 0;
vb@94
   706
    r = mailmime_encoded_phrase_parse("utf-8", mb->mb_display_name,
vb@94
   707
            strlen(mb->mb_display_name), &index, "utf-8", &username);
vb@94
   708
    if (r)
vb@94
   709
        goto enomem;
vb@94
   710
vb@94
   711
    ident = new_identity(mb->mb_addr_spec, NULL, NULL, username);
vb@94
   712
    if (ident == NULL)
vb@94
   713
        goto enomem;
vb@94
   714
    free(username);
vb@94
   715
vb@94
   716
    return ident;
vb@94
   717
vb@94
   718
enomem:
vb@94
   719
    free(username);
vb@94
   720
vb@94
   721
    return NULL;
vb@94
   722
}
vb@94
   723
vb@94
   724
static pEp_identity * mbl_to_identity(const struct mailimf_mailbox_list * mbl)
vb@94
   725
{
vb@94
   726
    struct mailimf_mailbox * mb = clist_content(clist_begin(mbl->mb_list));
vb@94
   727
    return mailbox_to_identity(mb);
vb@94
   728
}
vb@94
   729
vb@94
   730
static identity_list * mal_to_identity_list(
vb@94
   731
        const struct mailimf_address_list *mal
vb@94
   732
    )
vb@94
   733
{
vb@94
   734
    PEP_STATUS status = PEP_STATUS_OK;
vb@94
   735
    identity_list *il = NULL;
vb@94
   736
    clist *list = mal->ad_list;
vb@94
   737
    struct mailimf_address * addr = NULL;
vb@94
   738
    struct mailimf_mailbox *mb = NULL;
vb@94
   739
    clistiter *cur;
vb@94
   740
    int r;
vb@94
   741
vb@94
   742
    assert(mal);
vb@94
   743
vb@94
   744
    il = new_identity_list(NULL);
vb@94
   745
    if (il == NULL)
vb@94
   746
        goto enomem;
vb@94
   747
vb@94
   748
    identity_list *_il = il;
vb@94
   749
    for (cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
vb@94
   750
        pEp_identity *ident;
vb@94
   751
vb@94
   752
        addr = clist_content(cur);
vb@94
   753
        switch(addr->ad_type) {
vb@94
   754
            case MAILIMF_ADDRESS_MAILBOX:
vb@94
   755
                ident = mailbox_to_identity(addr->ad_data.ad_mailbox);
vb@94
   756
                if (ident == NULL)
vb@94
   757
                    goto enomem;
vb@94
   758
                _il = identity_list_add(_il, ident);
vb@94
   759
                if (_il == NULL)
vb@94
   760
                    goto enomem;
vb@94
   761
                break;
vb@94
   762
vb@94
   763
            case MAILIMF_ADDRESS_GROUP:
vb@94
   764
                {
vb@94
   765
                    clistiter *cur2;
vb@94
   766
                    struct mailimf_mailbox_list * mbl =
vb@94
   767
                            addr->ad_data.ad_group->grp_mb_list;
vb@94
   768
                    for (cur2 = clist_begin(mbl->mb_list); cur2 != NULL;
vb@94
   769
                            cur2 = clist_next(cur2)) {
vb@94
   770
                        ident = mailbox_to_identity(clist_content(cur));
vb@94
   771
                        if (ident == NULL)
vb@94
   772
                            goto enomem;
vb@94
   773
                        _il = identity_list_add(_il, ident);
vb@94
   774
                        if (_il == NULL)
vb@94
   775
                            goto enomem;
vb@94
   776
                    }
vb@94
   777
                }
vb@94
   778
                break;
vb@94
   779
vb@94
   780
            default:
vb@94
   781
                assert(0);
vb@94
   782
                goto enomem;
vb@94
   783
        }
vb@94
   784
    }
vb@94
   785
vb@94
   786
    return il;
vb@94
   787
vb@94
   788
enomem:
vb@94
   789
    free_identity_list(il);
vb@94
   790
vb@94
   791
    return NULL;
vb@94
   792
}
vb@94
   793
vb@94
   794
static stringlist_t * clist_to_stringlist(const clist *list)
vb@94
   795
{
vb@94
   796
    char *text = NULL;;
vb@94
   797
    stringlist_t * sl = new_stringlist(NULL);
vb@94
   798
    if (sl == NULL)
vb@94
   799
        return NULL;
vb@94
   800
vb@94
   801
    clistiter *cur;
vb@94
   802
    stringlist_t *_sl = sl;
vb@94
   803
    for (cur = clist_begin(list); cur != NULL; cur = clist_next(cur)) {
vb@94
   804
        char *phrase = clist_content(cur);
vb@94
   805
        size_t index;
vb@94
   806
        int r;
vb@94
   807
vb@94
   808
        index = 0;
vb@94
   809
        r = mailmime_encoded_phrase_parse("utf-8", phrase, strlen(phrase),
vb@94
   810
                &index, "utf-8", &text);
vb@94
   811
        if (r)
vb@94
   812
            goto enomem;
vb@94
   813
vb@94
   814
        _sl = stringlist_add(_sl, text);
vb@94
   815
        if (_sl == NULL)
vb@94
   816
            goto enomem;
vb@94
   817
vb@94
   818
        free(text);
vb@94
   819
        text = NULL;
vb@94
   820
    }
vb@94
   821
vb@94
   822
    return _sl;
vb@94
   823
vb@94
   824
enomem:
vb@94
   825
    free_stringlist(sl);
vb@94
   826
    free(text);
vb@94
   827
vb@94
   828
    return NULL;
vb@94
   829
}
vb@94
   830
vb@94
   831
static PEP_STATUS read_fields(message *msg, clist *fieldlist)
vb@94
   832
{
vb@94
   833
    PEP_STATUS status = PEP_STATUS_OK;
vb@94
   834
    struct mailimf_field * _field;
vb@94
   835
    clistiter *cur;
vb@94
   836
    size_t index;
vb@94
   837
    int r;
vb@94
   838
vb@94
   839
    for (cur = clist_begin(fieldlist); cur != NULL; cur = clist_next(cur)) {
vb@94
   840
        _field = clist_content(cur);
vb@94
   841
vb@94
   842
        switch (_field->fld_type) {
vb@94
   843
            case MAILIMF_FIELD_MESSAGE_ID:
vb@94
   844
                {
vb@94
   845
                    char * text = _field->fld_data.fld_message_id->mid_value;
vb@94
   846
                    index = 0;
vb@94
   847
                    r = mailmime_encoded_phrase_parse("utf-8", text,
vb@94
   848
                            strlen(text), &index, "utf-8", &msg->id);
vb@94
   849
                    if (r)
vb@94
   850
                        goto enomem;
vb@94
   851
                }
vb@94
   852
                break;
vb@94
   853
vb@94
   854
            case MAILIMF_FIELD_SUBJECT:
vb@94
   855
                {
vb@94
   856
                    char * text = _field->fld_data.fld_subject->sbj_value;
vb@94
   857
                    index = 0;
vb@94
   858
                    r = mailmime_encoded_phrase_parse("utf-8", text,
vb@94
   859
                            strlen(text), &index, "utf-8", &msg->shortmsg);
vb@94
   860
                    if (r)
vb@94
   861
                        goto enomem;
vb@94
   862
                }
vb@94
   863
                break;
vb@94
   864
vb@94
   865
            case MAILIMF_FIELD_ORIG_DATE:
vb@94
   866
                {
vb@94
   867
                    struct mailimf_date_time *date =
vb@94
   868
                        _field->fld_data.fld_orig_date->dt_date_time;
vb@94
   869
                    msg->sent = etpantime_to_timestamp(date);
vb@94
   870
                    if (msg->sent == NULL)
vb@94
   871
                        goto enomem;
vb@94
   872
                }
vb@94
   873
                break;
vb@94
   874
vb@94
   875
            case MAILIMF_FIELD_FROM:
vb@94
   876
                {
vb@94
   877
                    struct mailimf_mailbox_list *mbl =
vb@94
   878
                            _field->fld_data.fld_from->frm_mb_list;
vb@94
   879
                    pEp_identity *ident;
vb@94
   880
vb@94
   881
                    ident = mbl_to_identity(mbl);
vb@94
   882
                    if (ident == NULL)
vb@94
   883
                        goto pep_error;
vb@94
   884
vb@94
   885
                    msg->from = ident;
vb@94
   886
                }
vb@94
   887
                break;
vb@94
   888
vb@94
   889
            case MAILIMF_FIELD_TO:
vb@94
   890
                {
vb@94
   891
                    struct mailimf_address_list *mal =
vb@94
   892
                            _field->fld_data.fld_to->to_addr_list;
vb@94
   893
                    identity_list *il = mal_to_identity_list(mal);
vb@94
   894
                    if (il == NULL)
vb@94
   895
                        goto enomem;
vb@94
   896
                    msg->to = il;
vb@94
   897
                }
vb@94
   898
                break;
vb@94
   899
vb@94
   900
            case MAILIMF_FIELD_CC:
vb@94
   901
                {
vb@94
   902
                    struct mailimf_address_list *mal =
vb@94
   903
                            _field->fld_data.fld_cc->cc_addr_list;
vb@94
   904
                    identity_list *il = mal_to_identity_list(mal);
vb@94
   905
                    if (il == NULL)
vb@94
   906
                        goto enomem;
vb@94
   907
                    msg->cc = il;
vb@94
   908
                }
vb@94
   909
                break;
vb@94
   910
vb@94
   911
            case MAILIMF_FIELD_BCC:
vb@94
   912
                {
vb@94
   913
                    struct mailimf_address_list *mal =
vb@94
   914
                            _field->fld_data.fld_bcc->bcc_addr_list;
vb@94
   915
                    identity_list *il = mal_to_identity_list(mal);
vb@94
   916
                    if (il == NULL)
vb@94
   917
                        goto enomem;
vb@94
   918
                    msg->bcc = il;
vb@94
   919
                }
vb@94
   920
                break;
vb@94
   921
vb@94
   922
            case MAILIMF_FIELD_REPLY_TO:
vb@94
   923
                {
vb@94
   924
                    struct mailimf_address_list *mal =
vb@94
   925
                            _field->fld_data.fld_reply_to->rt_addr_list;
vb@94
   926
                    identity_list *il = mal_to_identity_list(mal);
vb@94
   927
                    if (il == NULL)
vb@94
   928
                        goto enomem;
vb@94
   929
                    msg->reply_to = il;
vb@94
   930
                }
vb@94
   931
                break;
vb@94
   932
vb@94
   933
            case MAILIMF_FIELD_IN_REPLY_TO:
vb@94
   934
                {
vb@94
   935
                    clist *list = _field->fld_data.fld_in_reply_to->mid_list;
vb@94
   936
                    stringlist_t *sl = clist_to_stringlist(list);
vb@94
   937
                    if (sl == NULL)
vb@94
   938
                        goto enomem;
vb@94
   939
                    msg->in_reply_to = sl;
vb@94
   940
                }
vb@94
   941
                break;
vb@94
   942
vb@94
   943
            case MAILIMF_FIELD_REFERENCES:
vb@94
   944
                {
vb@94
   945
                    clist *list = _field->fld_data.fld_references->mid_list;
vb@94
   946
                    stringlist_t *sl = clist_to_stringlist(list);
vb@94
   947
                    if (sl == NULL)
vb@94
   948
                        goto enomem;
vb@94
   949
                    msg->references = sl;
vb@94
   950
                }
vb@94
   951
                break;
vb@94
   952
vb@94
   953
            case MAILIMF_FIELD_KEYWORDS:
vb@94
   954
                {
vb@94
   955
                    clist *list = _field->fld_data.fld_keywords->kw_list;
vb@94
   956
                    stringlist_t *sl = clist_to_stringlist(list);
vb@94
   957
                    if (sl == NULL)
vb@94
   958
                        goto enomem;
vb@94
   959
                    msg->keywords = sl;
vb@94
   960
                }
vb@94
   961
                break;
vb@94
   962
vb@94
   963
            case MAILIMF_FIELD_COMMENTS:
vb@94
   964
                {
vb@94
   965
                    char * text = _field->fld_data.fld_comments->cm_value;
vb@94
   966
                    index = 0;
vb@94
   967
                    r = mailmime_encoded_phrase_parse("utf-8", text,
vb@94
   968
                            strlen(text), &index, "utf-8", &msg->comments);
vb@94
   969
                    if (r)
vb@94
   970
                        goto enomem;
vb@94
   971
                }
vb@94
   972
                break;
vb@94
   973
        }
vb@94
   974
    }
vb@94
   975
vb@94
   976
    return PEP_STATUS_OK;
vb@94
   977
vb@94
   978
enomem:
vb@94
   979
    status = PEP_OUT_OF_MEMORY;
vb@94
   980
vb@94
   981
pep_error:
vb@94
   982
    return status;
vb@94
   983
}
vb@94
   984
vb@89
   985
DYNAMIC_API PEP_STATUS mime_decode_message(
vb@89
   986
        const char *mimetext,
vb@89
   987
        message **msg
vb@89
   988
    )
vb@89
   989
{
vb@89
   990
    PEP_STATUS status = PEP_STATUS_OK;
vb@89
   991
    struct mailmime * mime = NULL;
vb@89
   992
    int r;
vb@94
   993
    message *_msg = NULL;
vb@94
   994
    size_t index;
vb@89
   995
vb@89
   996
    assert(mimetext);
vb@89
   997
    assert(msg);
vb@89
   998
vb@89
   999
    *msg = NULL;
vb@89
  1000
    
vb@94
  1001
    index = 0;
vb@89
  1002
    r = mailmime_parse(mimetext, strlen(mimetext), &index, &mime);
vb@89
  1003
    assert(r == 0);
vb@89
  1004
    assert(mime);
vb@90
  1005
    if (r) {
vb@89
  1006
        if (r == MAILIMF_ERROR_MEMORY)
vb@89
  1007
            goto enomem;
vb@89
  1008
        else
vb@89
  1009
            goto err_mime;
vb@89
  1010
    }
vb@89
  1011
vb@94
  1012
    _msg = calloc(1, sizeof(message));
vb@94
  1013
    if (_msg == NULL)
vb@94
  1014
        goto enomem;
vb@94
  1015
vb@94
  1016
    clist * _fieldlist = mime->mm_data.mm_message.mm_fields->fld_list;
vb@94
  1017
    status = read_fields(_msg, _fieldlist);
vb@94
  1018
    if (status != PEP_STATUS_OK)
vb@94
  1019
        goto pep_error;
vb@94
  1020
vb@89
  1021
    mailmime_free(mime);
vb@94
  1022
    *msg = _msg;
vb@89
  1023
vb@89
  1024
    return status;
vb@89
  1025
vb@89
  1026
err_mime:
vb@89
  1027
    status = PEP_ILLEGAL_VALUE;
vb@89
  1028
    goto pep_error;
vb@89
  1029
vb@89
  1030
enomem:
vb@89
  1031
    status = PEP_OUT_OF_MEMORY;
vb@89
  1032
vb@89
  1033
pep_error:
vb@94
  1034
    free_message(_msg);
vb@94
  1035
vb@89
  1036
    if (mime)
vb@89
  1037
        mailmime_free(mime);
vb@89
  1038
vb@89
  1039
    return status;
vb@89
  1040
}
vb@89
  1041