src/message_api.c
author Volker Birk <vb@pep-project.org>
Wed, 25 Mar 2015 15:20:25 +0100
changeset 125 5119178815d8
parent 119 cf32295fd797
child 130 507895068f83
permissions -rw-r--r--
Windoze fixes
vb@125
     1
#include "pEp_internal.h"
vb@37
     2
#include "message_api.h"
vb@37
     3
vb@85
     4
#ifndef WIN32 // POSIX
vb@85
     5
#define _POSIX_C_SOURCE 200809L
vb@85
     6
#include <strings.h>
vb@85
     7
#else
vb@85
     8
#include "platform_windows.h"
vb@85
     9
#endif
vb@85
    10
vb@37
    11
#include <assert.h>
vb@37
    12
#include <string.h>
vb@39
    13
#include <stdlib.h>
vb@39
    14
vb@83
    15
static char * combine_short_and_long(const char *shortmsg, const char *longmsg)
vb@62
    16
{
vb@62
    17
    char * ptext;
vb@81
    18
vb@83
    19
    assert(shortmsg);
vb@83
    20
    assert(strcmp(shortmsg, "pEp") != 0);
vb@62
    21
vb@83
    22
    if (longmsg == NULL)
vb@63
    23
        longmsg = "";
vb@63
    24
vb@83
    25
    ptext = calloc(1, strlen(shortmsg) + strlen(longmsg) + 12);
vb@109
    26
    assert(ptext);
vb@62
    27
    if (ptext == NULL)
vb@62
    28
        return NULL;
vb@62
    29
vb@85
    30
    strcpy(ptext, "Subject: ");
vb@83
    31
    strcat(ptext, shortmsg);
vb@62
    32
    strcat(ptext, "\n\n");
vb@63
    33
    strcat(ptext, longmsg);
vb@62
    34
vb@62
    35
    return ptext;
vb@62
    36
}
vb@44
    37
vb@82
    38
static int seperate_short_and_long(const char *src, char **shortmsg, char **longmsg)
vb@82
    39
{
vb@82
    40
    char *_shortmsg = NULL;
vb@82
    41
    char *_longmsg = NULL;
vb@82
    42
vb@82
    43
    assert(src);
vb@82
    44
    assert(shortmsg);
vb@82
    45
    assert(longmsg);
vb@82
    46
vb@82
    47
    *shortmsg = NULL;
vb@82
    48
    *longmsg = NULL;
vb@82
    49
vb@85
    50
    if (strncasecmp(src, "subject: ", 9) == 0) {
vb@82
    51
        char *line_end = strchr(src, '\n');
vb@82
    52
        
vb@82
    53
        if (line_end == NULL) {
vb@82
    54
            _shortmsg = strdup(src + 9);
vb@82
    55
            if (_shortmsg == NULL)
vb@82
    56
                goto enomem;
vb@82
    57
            // _longmsg = NULL;
vb@82
    58
        }
vb@82
    59
        else {
vb@82
    60
            size_t n = line_end - src;
vb@82
    61
            if (*(line_end - 1) == '\r')
vb@82
    62
                _shortmsg = strndup(src + 9, n - 1);
vb@82
    63
            else
vb@82
    64
                _shortmsg = strndup(src + 9, n);
vb@82
    65
            if (_shortmsg == NULL)
vb@82
    66
                goto enomem;
vb@82
    67
            _longmsg = strdup(src + n);
vb@82
    68
            if (_longmsg == NULL)
vb@82
    69
                goto enomem;
vb@82
    70
        }
vb@82
    71
    }
vb@82
    72
    else {
vb@113
    73
        _shortmsg = strdup("");
vb@82
    74
        if (_shortmsg == NULL)
vb@82
    75
            goto enomem;
vb@82
    76
        _longmsg = strdup(src);
vb@82
    77
        if (_longmsg == NULL)
vb@82
    78
            goto enomem;
vb@82
    79
    }
vb@82
    80
    
vb@82
    81
    *shortmsg = _shortmsg;
vb@82
    82
    *longmsg = _longmsg;
vb@82
    83
vb@82
    84
    return 0;
vb@82
    85
vb@82
    86
enomem:
vb@82
    87
    free(_shortmsg);
vb@82
    88
    free(_longmsg);
vb@82
    89
vb@82
    90
    return -1;
vb@82
    91
}
vb@82
    92
vb@113
    93
static PEP_STATUS copy_fields(message *dst, const message *src)
vb@113
    94
{
vb@113
    95
    free_timestamp(dst->sent);
vb@113
    96
    dst->sent = NULL;
vb@113
    97
    if (src->sent) {
vb@113
    98
        dst->sent = timestamp_dup(src->sent);
vb@113
    99
        if (dst->sent == NULL)
vb@113
   100
            return PEP_OUT_OF_MEMORY;
vb@113
   101
    }
vb@113
   102
vb@113
   103
    free_timestamp(dst->recv);
vb@113
   104
    dst->recv = NULL;
vb@113
   105
    if (src->recv) {
vb@113
   106
        dst->recv = timestamp_dup(src->recv);
vb@113
   107
        if (dst->recv == NULL)
vb@113
   108
            return PEP_OUT_OF_MEMORY;
vb@113
   109
    }
vb@113
   110
vb@113
   111
    free_identity(dst->from);
vb@113
   112
    dst->from = NULL;
vb@113
   113
    if (src->from) {
vb@113
   114
        dst->from = identity_dup(src->from);
vb@113
   115
        if (dst->from == NULL)
vb@113
   116
            return PEP_OUT_OF_MEMORY;
vb@113
   117
    }
vb@113
   118
vb@113
   119
    free_identity_list(dst->to);
vb@113
   120
    dst->to = NULL;
vb@113
   121
    if (src->to) {
vb@113
   122
        dst->to = identity_list_dup(src->to);
vb@113
   123
        if (dst->to == NULL)
vb@113
   124
            return PEP_OUT_OF_MEMORY;
vb@113
   125
    }
vb@113
   126
vb@113
   127
    free_identity(dst->recv_by);
vb@113
   128
    dst->recv_by = NULL;
vb@113
   129
    if (src->recv_by) {
vb@113
   130
        dst->recv_by = identity_dup(src->recv_by);
vb@113
   131
        if (dst->recv_by == NULL)
vb@113
   132
            return PEP_OUT_OF_MEMORY;
vb@113
   133
    }
vb@113
   134
vb@113
   135
    free_identity_list(dst->cc);
vb@113
   136
    dst->cc = NULL;
vb@113
   137
    if (src->cc) {
vb@113
   138
        dst->cc = identity_list_dup(src->cc);
vb@113
   139
        if (dst->cc == NULL)
vb@113
   140
            return PEP_OUT_OF_MEMORY;
vb@113
   141
    }
vb@113
   142
vb@113
   143
    free_identity_list(dst->bcc);
vb@113
   144
    dst->bcc = NULL;
vb@113
   145
    if (src->bcc) {
vb@113
   146
        dst->bcc = identity_list_dup(src->bcc);
vb@113
   147
        if (dst->bcc == NULL)
vb@113
   148
            return PEP_OUT_OF_MEMORY;
vb@113
   149
    }
vb@113
   150
vb@113
   151
    free_identity_list(dst->reply_to);
vb@113
   152
    dst->reply_to = NULL;
vb@113
   153
    if (src->reply_to) {
vb@113
   154
        dst->reply_to = identity_list_dup(src->reply_to);
vb@113
   155
        if (dst->reply_to == NULL)
vb@113
   156
            return PEP_OUT_OF_MEMORY;
vb@113
   157
    }
vb@113
   158
vb@113
   159
    free_stringlist(dst->in_reply_to);
vb@113
   160
    dst->in_reply_to = NULL;
vb@113
   161
    if (src->in_reply_to) {
vb@113
   162
        dst->in_reply_to = stringlist_dup(src->in_reply_to);
vb@113
   163
        if (dst->in_reply_to == NULL)
vb@113
   164
            return PEP_OUT_OF_MEMORY;
vb@113
   165
    }
vb@113
   166
vb@113
   167
    free_stringlist(dst->references);
vb@113
   168
    dst->references = NULL;
vb@113
   169
    if (src->references) {
vb@113
   170
        dst->references = stringlist_dup(src->references);
vb@113
   171
        if (dst->references == NULL)
vb@113
   172
            return PEP_OUT_OF_MEMORY;
vb@113
   173
    }
vb@113
   174
vb@113
   175
    free_stringlist(dst->keywords);
vb@113
   176
    dst->keywords = NULL;
vb@113
   177
    if (src->keywords) {
vb@113
   178
        dst->keywords = stringlist_dup(src->keywords);
vb@113
   179
        if (dst->keywords == NULL)
vb@113
   180
            return PEP_OUT_OF_MEMORY;
vb@113
   181
    }
vb@113
   182
vb@113
   183
    free(dst->comments);
vb@113
   184
    dst->comments = NULL;
vb@113
   185
    if (src->comments) {
vb@113
   186
        dst->comments = strdup(src->comments);
vb@113
   187
        assert(dst->comments);
vb@113
   188
        if (dst->comments == NULL)
vb@113
   189
            return PEP_OUT_OF_MEMORY;
vb@113
   190
    }
vb@113
   191
vb@113
   192
    return PEP_STATUS_OK;
vb@113
   193
}
vb@113
   194
vb@81
   195
static message * clone_to_empty_message(const message * src)
vb@80
   196
{
vb@113
   197
    PEP_STATUS status;
vb@80
   198
    message * msg = NULL;
vb@80
   199
vb@81
   200
    assert(src);
vb@81
   201
vb@113
   202
    msg = calloc(1, sizeof(message));
vb@113
   203
    assert(msg);
vb@80
   204
    if (msg == NULL)
vb@80
   205
        goto enomem;
vb@80
   206
vb@82
   207
    msg->dir = src->dir;
vb@82
   208
vb@113
   209
    status = copy_fields(msg, src);
vb@113
   210
    if (status != PEP_STATUS_OK)
vb@113
   211
        goto enomem;
vb@81
   212
vb@80
   213
    return msg;
vb@80
   214
vb@80
   215
enomem:
vb@113
   216
    free_message(msg);
vb@80
   217
    return NULL;
vb@80
   218
}
vb@80
   219
vb@48
   220
DYNAMIC_API PEP_STATUS encrypt_message(
vb@37
   221
        PEP_SESSION session,
vb@113
   222
        message *src,
vb@37
   223
        stringlist_t * extra,
vb@38
   224
        message **dst,
vb@81
   225
        PEP_enc_format enc_format
vb@37
   226
    )
vb@37
   227
{
vb@37
   228
    PEP_STATUS status = PEP_STATUS_OK;
vb@63
   229
    message * msg = NULL;
vb@63
   230
    stringlist_t * keys = NULL;
vb@113
   231
    bool free_src = false;
vb@37
   232
vb@37
   233
    assert(session);
vb@37
   234
    assert(src);
vb@37
   235
    assert(dst);
vb@81
   236
    assert(enc_format >= PEP_enc_pieces);
vb@81
   237
vb@37
   238
    *dst = NULL;
vb@67
   239
vb@81
   240
    if (src->enc_format >= PEP_enc_pieces) {
vb@81
   241
        if (src->enc_format == enc_format) {
vb@113
   242
            assert(0); // the message is encrypted this way already
vb@81
   243
            msg = message_dup(src);
vb@81
   244
            if (msg == NULL)
vb@81
   245
                goto enomem;
vb@81
   246
            *dst = msg;
vb@81
   247
            return PEP_STATUS_OK;
vb@81
   248
        }
vb@81
   249
        else {
vb@113
   250
            // decrypt and re-encrypt again
vb@113
   251
            message * _dst = NULL;
vb@113
   252
            PEP_MIME_format mime = (enc_format == PEP_enc_PEP) ? PEP_MIME :
vb@113
   253
                    PEP_MIME_fields_omitted;
vb@113
   254
vb@113
   255
            status = decrypt_message(session, src, mime, &_dst);
vb@113
   256
            if (status != PEP_STATUS_OK)
vb@113
   257
                goto pep_error;
vb@113
   258
vb@113
   259
            src = _dst;
vb@113
   260
            free_src = true;
vb@81
   261
        }
vb@67
   262
    }
vb@37
   263
vb@81
   264
    msg = clone_to_empty_message(src);
vb@80
   265
    if (msg == NULL)
vb@63
   266
        goto enomem;
vb@40
   267
vb@80
   268
    status = myself(session, src->from);
vb@63
   269
    if (status != PEP_STATUS_OK)
vb@63
   270
        goto pep_error;
vb@37
   271
vb@80
   272
    keys = new_stringlist(src->from->fpr);
vb@63
   273
    if (keys == NULL)
vb@63
   274
        goto enomem;
vb@37
   275
vb@39
   276
    stringlist_t *_k = keys;
vb@39
   277
vb@39
   278
    if (extra) {
vb@39
   279
        _k = stringlist_append(_k, extra);
vb@63
   280
        if (_k == NULL)
vb@63
   281
            goto enomem;
vb@37
   282
    }
vb@39
   283
vb@39
   284
    bool dest_keys_found = false;
vb@37
   285
    identity_list * _il;
vb@80
   286
    for (_il = msg->to; _il && _il->ident; _il = _il->next) {
vb@63
   287
        PEP_STATUS status = update_identity(session, _il->ident);
vb@63
   288
        if (status != PEP_STATUS_OK)
vb@63
   289
            goto pep_error;
vb@63
   290
vb@37
   291
        if (_il->ident->fpr) {
vb@39
   292
            dest_keys_found = true;
vb@39
   293
            _k = stringlist_add(_k, _il->ident->fpr);
vb@63
   294
            if (_k == NULL)
vb@63
   295
                goto enomem;
vb@37
   296
        }
vb@37
   297
        else
vb@37
   298
            status = PEP_KEY_NOT_FOUND;
vb@37
   299
    }
vb@37
   300
vb@39
   301
    if (dest_keys_found) {
vb@38
   302
        char *ptext;
vb@37
   303
        char *ctext = NULL;
vb@37
   304
        size_t csize = 0;
vb@37
   305
vb@81
   306
        switch (enc_format) {
vb@112
   307
        case PEP_enc_PGP_MIME: {
vb@62
   308
            bool free_ptext = false;
vb@64
   309
vb@112
   310
            msg->enc_format = PEP_enc_PGP_MIME;
vb@37
   311
vb@113
   312
            if (src->mime == PEP_MIME) {
vb@113
   313
                message *_src = NULL;
vb@113
   314
                assert(src->longmsg);
vb@113
   315
                status = mime_decode_message(src->longmsg, &_src);
vb@113
   316
                if (status != PEP_STATUS_OK)
vb@113
   317
                    goto pep_error;
vb@113
   318
                if (free_src)
vb@113
   319
                    free_message(src);
vb@113
   320
                src = _src;
vb@113
   321
                free_src = true;
vb@62
   322
            }
vb@62
   323
vb@113
   324
            if (src->mime == PEP_MIME_none) {
vb@113
   325
                if (src->shortmsg && strcmp(src->shortmsg, "pEp") != 0) {
vb@113
   326
                    ptext = combine_short_and_long(src->shortmsg, src->longmsg);
vb@113
   327
                    if (ptext == NULL)
vb@113
   328
                        goto enomem;
vb@113
   329
                    free_ptext = true;
vb@113
   330
                }
vb@113
   331
                else if (src->longmsg) {
vb@113
   332
                    ptext = src->longmsg;
vb@113
   333
                }
vb@125
   334
                else {
vb@125
   335
                    ptext = "pEp";
vb@125
   336
                }
vb@113
   337
vb@113
   338
                message *_src = calloc(1, sizeof(message));
vb@89
   339
                assert(_src);
vb@89
   340
                if (_src == NULL)
vb@89
   341
                    goto enomem;
vb@89
   342
                _src->longmsg = ptext;
vb@113
   343
                _src->longmsg_formatted = src->longmsg_formatted;
vb@113
   344
                _src->attachments = src->attachments;
vb@113
   345
                _src->enc_format = PEP_enc_PGP_MIME;
vb@113
   346
                status = mime_encode_message(_src, true, &ptext);
vb@67
   347
                assert(status == PEP_STATUS_OK);
vb@67
   348
                if (free_ptext)
vb@89
   349
                    free(_src->longmsg);
vb@89
   350
                free(_src);
vb@67
   351
                assert(ptext);
vb@67
   352
                if (ptext == NULL)
vb@67
   353
                    goto pep_error;
vb@67
   354
                free_ptext = true;
vb@67
   355
            }
vb@113
   356
            else /* if (src->mime == PEP_MIME_fields_omitted) */ {
vb@67
   357
                ptext = src->longmsg;
vb@67
   358
            }
vb@67
   359
vb@67
   360
            status = encrypt_and_sign(session, keys, ptext, strlen(ptext),
vb@67
   361
                    &ctext, &csize);
vb@62
   362
            if (free_ptext)
vb@62
   363
                free(ptext);
vb@113
   364
            if (ctext == NULL)
vb@63
   365
                goto pep_error;
vb@113
   366
vb@113
   367
            msg->longmsg = strdup(ctext);
vb@113
   368
            if (msg->longmsg == NULL)
vb@113
   369
                goto enomem;
vb@62
   370
        }
vb@63
   371
        break;
vb@62
   372
vb@62
   373
        case PEP_enc_pieces:
vb@64
   374
            msg->enc_format = PEP_enc_pieces;
vb@64
   375
vb@63
   376
            if (src->shortmsg && strcmp(src->shortmsg, "pEp") != 0) {
vb@83
   377
                ptext = combine_short_and_long(src->shortmsg, src->longmsg);
vb@63
   378
                if (ptext == NULL)
vb@63
   379
                    goto enomem;
vb@63
   380
vb@39
   381
                status = encrypt_and_sign(session, keys, ptext, strlen(ptext),
vb@39
   382
                        &ctext, &csize);
vb@40
   383
                free(ptext);
vb@38
   384
                if (ctext) {
vb@40
   385
                    msg->longmsg = strdup(ctext);
vb@64
   386
                    if (msg->longmsg == NULL)
vb@63
   387
                        goto enomem;
vb@38
   388
                }
vb@38
   389
                else {
vb@63
   390
                    goto pep_error;
vb@38
   391
                }
vb@38
   392
            }
vb@38
   393
            else if (src->longmsg) {
vb@38
   394
                ptext = src->longmsg;
vb@39
   395
                status = encrypt_and_sign(session, keys, ptext, strlen(ptext),
vb@39
   396
                        &ctext, &csize);
vb@38
   397
                if (ctext) {
vb@40
   398
                    msg->longmsg = strdup(ctext);
vb@64
   399
                    if (msg->longmsg == NULL)
vb@63
   400
                        goto enomem;
vb@38
   401
                }
vb@38
   402
                else {
vb@63
   403
                    goto pep_error;
vb@38
   404
                }
vb@38
   405
            }
vb@63
   406
vb@63
   407
            if (msg->longmsg_formatted) {
vb@38
   408
                ptext = src->longmsg_formatted;
vb@39
   409
                status = encrypt_and_sign(session, keys, ptext, strlen(ptext),
vb@39
   410
                        &ctext, &csize);
vb@38
   411
                if (ctext) {
vb@40
   412
                    msg->longmsg_formatted = strdup(ctext);
vb@63
   413
                    if (msg->longmsg_formatted == NULL)
vb@63
   414
                        goto enomem;
vb@63
   415
                }
vb@63
   416
                else {
vb@63
   417
                    goto pep_error;
vb@63
   418
                }
vb@63
   419
            }
vb@63
   420
vb@63
   421
            if (src->attachments) {
vb@63
   422
                bloblist_t *_s;
vb@63
   423
                bloblist_t *_d = new_bloblist(NULL, 0, NULL, NULL);
vb@63
   424
                if (_d == NULL)
vb@63
   425
                    goto enomem;
vb@63
   426
vb@63
   427
                msg->attachments = _d;
vb@63
   428
                for (_s = src->attachments; _s && _s->data; _s = _s->next) {
vb@63
   429
                    int psize = _s->size;
vb@63
   430
                    ptext = _s->data;
vb@63
   431
                    status = encrypt_and_sign(session, keys, ptext, psize,
vb@63
   432
                            &ctext, &csize);
vb@63
   433
                    if (ctext) {
vb@63
   434
                        char * _c = strdup(ctext);
vb@63
   435
                        if (_c == NULL)
vb@63
   436
                            goto enomem;
vb@63
   437
vb@63
   438
                        _d = bloblist_add(_d, _c, csize, _s->mime_type,
vb@113
   439
                                _s->filename);
vb@63
   440
                        if (_d == NULL)
vb@63
   441
                            goto enomem;
vb@63
   442
                    }
vb@63
   443
                    else {
vb@63
   444
                        goto pep_error;
vb@40
   445
                    }
vb@38
   446
                }
vb@38
   447
            }
vb@38
   448
            break;
vb@38
   449
vb@81
   450
        case PEP_enc_PEP:
vb@81
   451
            // TODO: implement
vb@81
   452
            NOT_IMPLEMENTED
vb@81
   453
vb@38
   454
        default:
vb@38
   455
            assert(0);
vb@63
   456
            status = PEP_ILLEGAL_VALUE;
vb@63
   457
            goto pep_error;
vb@37
   458
        }
vb@37
   459
    }
vb@37
   460
vb@37
   461
    free_stringlist(keys);
vb@113
   462
    if (free_src)
vb@113
   463
        free_message(src);
vb@63
   464
vb@64
   465
    if (msg->shortmsg == NULL)
vb@64
   466
        msg->shortmsg = strdup("pEp");
vb@64
   467
vb@63
   468
    *dst = msg;
vb@63
   469
    return PEP_STATUS_OK;
vb@63
   470
vb@63
   471
enomem:
vb@63
   472
    status = PEP_OUT_OF_MEMORY;
vb@63
   473
vb@63
   474
pep_error:
vb@63
   475
    free_stringlist(keys);
vb@63
   476
    free_message(msg);
vb@113
   477
    if (free_src)
vb@113
   478
        free_message(src);
vb@63
   479
vb@37
   480
    return status;
vb@37
   481
}
vb@37
   482
vb@113
   483
static bool is_encrypted_attachment(const bloblist_t *blob)
vb@113
   484
{
vb@113
   485
    char *ext;
vb@113
   486
 
vb@113
   487
    assert(blob);
vb@113
   488
vb@113
   489
    if (blob->filename == NULL)
vb@113
   490
        return false;
vb@113
   491
vb@113
   492
    ext = strrchr(blob->filename, '.');
vb@113
   493
    if (ext == NULL)
vb@113
   494
        return false;
vb@113
   495
vb@113
   496
    if (strcmp(blob->mime_type, "application/octet-stream")) {
vb@113
   497
        if (strcmp(ext, ".pgp") == 0 || strcmp(ext, ".gpg") == 0 ||
vb@113
   498
                strcmp(ext, ".asc") == 0)
vb@113
   499
            return true;
vb@113
   500
    }
vb@113
   501
    else if (strcmp(blob->mime_type, "application/octet-stream")) {
vb@113
   502
        if (strcmp(ext, ".asc") == 0)
vb@113
   503
            return true;
vb@113
   504
    }
vb@113
   505
vb@113
   506
    return false;
vb@113
   507
}
vb@113
   508
vb@113
   509
static bool is_encrypted_html_attachment(const bloblist_t *blob)
vb@113
   510
{
vb@113
   511
    assert(blob);
vb@113
   512
    assert(blob->filename);
vb@113
   513
vb@113
   514
    if (strncmp(blob->filename, "PGPexch.htm.", 12) == 0) {
vb@113
   515
        if (strcmp(blob->filename + 11, ".pgp") == 0 ||
vb@113
   516
                strcmp(blob->filename + 11, ".asc") == 0)
vb@113
   517
            return true;
vb@113
   518
    }
vb@113
   519
vb@113
   520
    return false;
vb@113
   521
}
vb@113
   522
vb@113
   523
char * without_double_ending(const char *filename)
vb@113
   524
{
vb@113
   525
    char *ext;
vb@113
   526
vb@113
   527
    assert(filename);
vb@113
   528
vb@113
   529
    ext = strrchr(filename, '.');
vb@113
   530
    if (ext == NULL)
vb@113
   531
        return NULL;
vb@113
   532
vb@113
   533
    return strndup(filename, ext - filename);
vb@113
   534
}
vb@113
   535
vb@48
   536
DYNAMIC_API PEP_STATUS decrypt_message(
vb@37
   537
        PEP_SESSION session,
vb@113
   538
        message *src,
vb@113
   539
        PEP_MIME_format mime,
vb@113
   540
        message **dst
vb@37
   541
    )
vb@37
   542
{
vb@37
   543
    PEP_STATUS status = PEP_STATUS_OK;
vb@73
   544
    message *msg = NULL;
vb@112
   545
    char *ctext;
vb@112
   546
    size_t csize;
vb@112
   547
    char *ptext;
vb@112
   548
    size_t psize;
vb@112
   549
    stringlist_t *keylist;
vb@113
   550
    bool free_src = false;
vb@37
   551
vb@74
   552
    assert(session);
vb@74
   553
    assert(src);
vb@74
   554
    assert(dst);
vb@73
   555
vb@74
   556
    *dst = NULL;
vb@81
   557
 
vb@113
   558
    if (src->mime == PEP_MIME_fields_omitted || src->mime == PEP_MIME) {
vb@113
   559
        message *_src = NULL;
vb@113
   560
        status = mime_decode_message(src->longmsg, &_src);
vb@113
   561
        if (status != PEP_STATUS_OK)
vb@113
   562
            goto pep_error;
vb@81
   563
vb@113
   564
        if ( src->mime == PEP_MIME_fields_omitted) {
vb@113
   565
            status = copy_fields(_src, src);
vb@113
   566
            if (status != PEP_STATUS_OK) {
vb@113
   567
                free_message(_src);
vb@113
   568
                goto pep_error;
vb@113
   569
            }
vb@113
   570
        }
vb@113
   571
vb@113
   572
        src = _src;
vb@113
   573
        free_src = true;
vb@113
   574
    }
vb@113
   575
vb@119
   576
    // src message is not MIME encoded (any more)
vb@113
   577
    assert(src->mime == PEP_MIME_none);
vb@113
   578
vb@117
   579
    if (!is_PGP_message_text(src->longmsg)) {
vb@117
   580
        status = PEP_UNENCRYPTED;
vb@117
   581
        goto pep_error;
vb@117
   582
    }
vb@117
   583
vb@113
   584
    ctext = src->longmsg;
vb@113
   585
    csize = strlen(src->longmsg);
vb@113
   586
vb@113
   587
    status = decrypt_and_verify(session, ctext, csize, &ptext, &psize,
vb@113
   588
            &keylist);
vb@113
   589
    if (ptext == NULL)
vb@113
   590
        goto pep_error;
vb@113
   591
vb@113
   592
    switch (src->enc_format) {
vb@113
   593
        case PEP_enc_PGP_MIME:
vb@113
   594
            status = mime_decode_message(ptext, &msg);
vb@113
   595
            if (status != PEP_STATUS_OK)
vb@113
   596
                goto pep_error;
vb@113
   597
vb@113
   598
            break;
vb@113
   599
vb@113
   600
        case PEP_enc_pieces:
vb@113
   601
            msg = clone_to_empty_message(src);
vb@113
   602
            if (msg == NULL)
vb@113
   603
                goto enomem;
vb@113
   604
vb@113
   605
            msg->longmsg = strdup(ptext);
vb@113
   606
            if (msg->longmsg == NULL)
vb@113
   607
                goto enomem;
vb@113
   608
vb@113
   609
            bloblist_t *_m = msg->attachments;
vb@113
   610
            bloblist_t *_s;
vb@113
   611
            for (_s = src->attachments; _s; _s = _s->next) {
vb@113
   612
                if (is_encrypted_attachment(_s)) {
vb@113
   613
                    ctext = _s->data;
vb@113
   614
                    csize = _s->size;
vb@113
   615
vb@113
   616
                    status = decrypt_and_verify(session, ctext, csize, &ptext,
vb@113
   617
                            &psize, &keylist);
vb@113
   618
                    if (ptext == NULL)
vb@113
   619
                        goto pep_error;
vb@113
   620
                    
vb@113
   621
                    if (is_encrypted_html_attachment(_s)) {
vb@113
   622
                        msg->longmsg_formatted = strdup(ptext);
vb@113
   623
                        if (msg->longmsg_formatted == NULL)
vb@113
   624
                            goto pep_error;
vb@113
   625
                    }
vb@113
   626
                    else {
vb@113
   627
                        char * mime_type = "application/octet-stream";
vb@113
   628
                        char * filename = without_double_ending(_s->filename);
vb@113
   629
                        if (filename == NULL)
vb@113
   630
                            goto enomem;
vb@113
   631
vb@113
   632
                        _m = bloblist_add(_m, ptext, psize, mime_type, filename);
vb@113
   633
                        if (_m == NULL)
vb@113
   634
                            goto enomem;
vb@113
   635
vb@113
   636
                       if (msg->attachments == NULL)
vb@113
   637
                            msg->attachments = _m;
vb@113
   638
                    }
vb@113
   639
                }
vb@82
   640
            }
vb@82
   641
vb@81
   642
            break;
vb@81
   643
vb@81
   644
        default:
vb@113
   645
            // BUG: must implement more
vb@113
   646
            NOT_IMPLEMENTED
vb@81
   647
    }
vb@74
   648
vb@113
   649
    switch (src->enc_format) {
vb@113
   650
        case PEP_enc_PGP_MIME:
vb@113
   651
        case PEP_enc_pieces:
vb@113
   652
            status = copy_fields(msg, src);
vb@113
   653
            if (status != PEP_STATUS_OK)
vb@113
   654
                goto pep_error;
vb@113
   655
vb@113
   656
            if (src->shortmsg) {
vb@113
   657
                free(msg->shortmsg);
vb@113
   658
                msg->shortmsg = strdup(src->shortmsg);
vb@113
   659
                if (msg->shortmsg == NULL)
vb@113
   660
                    goto enomem;
vb@113
   661
            }
vb@113
   662
vb@113
   663
            if (msg->shortmsg == NULL || strcmp(msg->shortmsg, "pEp") == 0)
vb@113
   664
            {
vb@113
   665
                char * shortmsg;
vb@113
   666
                char * longmsg;
vb@113
   667
vb@113
   668
                int r = seperate_short_and_long(msg->longmsg, &shortmsg,
vb@113
   669
                        &longmsg);
vb@113
   670
                if (r == -1)
vb@113
   671
                    goto enomem;
vb@113
   672
vb@113
   673
                free(msg->shortmsg);
vb@113
   674
                free(msg->longmsg);
vb@113
   675
vb@113
   676
                msg->shortmsg = shortmsg;
vb@113
   677
                msg->longmsg = longmsg;
vb@113
   678
            }
vb@113
   679
            else {
vb@113
   680
                msg->shortmsg = strdup(src->shortmsg);
vb@113
   681
                if (msg->shortmsg == NULL)
vb@113
   682
                    goto enomem;
vb@113
   683
                msg->longmsg = ptext;
vb@113
   684
            }
vb@113
   685
vb@113
   686
        default:
vb@113
   687
            // BUG: must implement more
vb@113
   688
            NOT_IMPLEMENTED
vb@113
   689
    }
vb@113
   690
vb@113
   691
    switch (mime) {
vb@113
   692
        case PEP_MIME_none:
vb@113
   693
            break;
vb@113
   694
vb@113
   695
        case PEP_MIME:
vb@113
   696
        case PEP_MIME_fields_omitted:
vb@113
   697
            {
vb@113
   698
                char *text = NULL;
vb@113
   699
                status = mime_encode_message(msg,
vb@113
   700
                        mime == PEP_MIME_fields_omitted, &text);
vb@113
   701
                if (status != PEP_STATUS_OK)
vb@113
   702
                    goto pep_error;
vb@113
   703
vb@113
   704
                message *_msg = clone_to_empty_message(msg);
vb@113
   705
                if (_msg == NULL) {
vb@113
   706
                    free(text);
vb@113
   707
                    goto enomem;
vb@113
   708
                }
vb@113
   709
                _msg->longmsg = text;
vb@113
   710
                _msg->shortmsg = strdup(msg->shortmsg);
vb@113
   711
                if (msg->shortmsg == NULL)
vb@113
   712
                    goto enomem;
vb@113
   713
vb@113
   714
                free_message(msg);
vb@113
   715
                msg = _msg;
vb@113
   716
            }
vb@113
   717
    }
vb@113
   718
vb@113
   719
    if (free_src)
vb@113
   720
        free_message(src);
vb@74
   721
    *dst = msg;
vb@74
   722
    return PEP_STATUS_OK;
vb@73
   723
vb@73
   724
enomem:
vb@73
   725
    status = PEP_OUT_OF_MEMORY;
vb@73
   726
vb@73
   727
pep_error:
vb@73
   728
    free_message(msg);
vb@113
   729
    if (free_src)
vb@113
   730
        free_message(src);
vb@39
   731
vb@37
   732
    return status;
vb@37
   733
}
vb@37
   734