src/message_api.c
author Volker Birk <vb@pep-project.org>
Fri, 01 May 2015 00:23:03 +0200
changeset 232 3d44d9bb18e5
parent 220 9234c753e2cf
child 235 8b7468ca8034
permissions -rw-r--r--
slighly renaming
vb@125
     1
#include "pEp_internal.h"
vb@37
     2
#include "message_api.h"
vb@37
     3
vb@130
     4
#include "platform.h"
vb@220
     5
#include "mime.h"
vb@85
     6
vb@37
     7
#include <assert.h>
vb@37
     8
#include <string.h>
vb@39
     9
#include <stdlib.h>
vb@39
    10
vb@190
    11
#ifndef MIN
vb@190
    12
#define MIN(A, B) ((B) > (A) ? (A) : (B))
vb@190
    13
#endif
vb@190
    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@166
    61
vb@82
    62
            if (*(line_end - 1) == '\r')
vb@166
    63
                _shortmsg = strndup(src + 9, n - 10);
vb@82
    64
            else
vb@166
    65
                _shortmsg = strndup(src + 9, n - 9);
vb@166
    66
vb@82
    67
            if (_shortmsg == NULL)
vb@82
    68
                goto enomem;
vb@166
    69
vb@166
    70
            while (*(src + n) && (*(src + n) == '\n' || *(src + n) == '\r'))
vb@166
    71
                ++n;
vb@166
    72
vb@166
    73
            if (*(src + n)) {
vb@166
    74
                _longmsg = strdup(src + n);
vb@166
    75
                if (_longmsg == NULL)
vb@166
    76
                    goto enomem;
vb@166
    77
            }
vb@82
    78
        }
vb@82
    79
    }
vb@82
    80
    else {
vb@113
    81
        _shortmsg = strdup("");
vb@82
    82
        if (_shortmsg == NULL)
vb@82
    83
            goto enomem;
vb@82
    84
        _longmsg = strdup(src);
vb@82
    85
        if (_longmsg == NULL)
vb@82
    86
            goto enomem;
vb@82
    87
    }
vb@82
    88
    
vb@82
    89
    *shortmsg = _shortmsg;
vb@82
    90
    *longmsg = _longmsg;
vb@82
    91
vb@82
    92
    return 0;
vb@82
    93
vb@82
    94
enomem:
vb@82
    95
    free(_shortmsg);
vb@82
    96
    free(_longmsg);
vb@82
    97
vb@82
    98
    return -1;
vb@82
    99
}
vb@82
   100
vb@113
   101
static PEP_STATUS copy_fields(message *dst, const message *src)
vb@113
   102
{
vb@164
   103
    assert(dst);
vb@164
   104
    assert(src);
vb@164
   105
vb@113
   106
    free_timestamp(dst->sent);
vb@113
   107
    dst->sent = NULL;
vb@113
   108
    if (src->sent) {
vb@113
   109
        dst->sent = timestamp_dup(src->sent);
vb@113
   110
        if (dst->sent == NULL)
vb@113
   111
            return PEP_OUT_OF_MEMORY;
vb@113
   112
    }
vb@113
   113
vb@113
   114
    free_timestamp(dst->recv);
vb@113
   115
    dst->recv = NULL;
vb@113
   116
    if (src->recv) {
vb@113
   117
        dst->recv = timestamp_dup(src->recv);
vb@113
   118
        if (dst->recv == NULL)
vb@113
   119
            return PEP_OUT_OF_MEMORY;
vb@113
   120
    }
vb@113
   121
vb@113
   122
    free_identity(dst->from);
vb@113
   123
    dst->from = NULL;
vb@113
   124
    if (src->from) {
vb@113
   125
        dst->from = identity_dup(src->from);
vb@113
   126
        if (dst->from == NULL)
vb@113
   127
            return PEP_OUT_OF_MEMORY;
vb@113
   128
    }
vb@113
   129
vb@113
   130
    free_identity_list(dst->to);
vb@113
   131
    dst->to = NULL;
vb@113
   132
    if (src->to) {
vb@113
   133
        dst->to = identity_list_dup(src->to);
vb@113
   134
        if (dst->to == NULL)
vb@113
   135
            return PEP_OUT_OF_MEMORY;
vb@113
   136
    }
vb@113
   137
vb@113
   138
    free_identity(dst->recv_by);
vb@113
   139
    dst->recv_by = NULL;
vb@113
   140
    if (src->recv_by) {
vb@113
   141
        dst->recv_by = identity_dup(src->recv_by);
vb@113
   142
        if (dst->recv_by == NULL)
vb@113
   143
            return PEP_OUT_OF_MEMORY;
vb@113
   144
    }
vb@113
   145
vb@113
   146
    free_identity_list(dst->cc);
vb@113
   147
    dst->cc = NULL;
vb@113
   148
    if (src->cc) {
vb@113
   149
        dst->cc = identity_list_dup(src->cc);
vb@113
   150
        if (dst->cc == NULL)
vb@113
   151
            return PEP_OUT_OF_MEMORY;
vb@113
   152
    }
vb@113
   153
vb@113
   154
    free_identity_list(dst->bcc);
vb@113
   155
    dst->bcc = NULL;
vb@113
   156
    if (src->bcc) {
vb@113
   157
        dst->bcc = identity_list_dup(src->bcc);
vb@113
   158
        if (dst->bcc == NULL)
vb@113
   159
            return PEP_OUT_OF_MEMORY;
vb@113
   160
    }
vb@113
   161
vb@113
   162
    free_identity_list(dst->reply_to);
vb@113
   163
    dst->reply_to = NULL;
vb@113
   164
    if (src->reply_to) {
vb@113
   165
        dst->reply_to = identity_list_dup(src->reply_to);
vb@113
   166
        if (dst->reply_to == NULL)
vb@113
   167
            return PEP_OUT_OF_MEMORY;
vb@113
   168
    }
vb@113
   169
vb@113
   170
    free_stringlist(dst->in_reply_to);
vb@113
   171
    dst->in_reply_to = NULL;
vb@113
   172
    if (src->in_reply_to) {
vb@113
   173
        dst->in_reply_to = stringlist_dup(src->in_reply_to);
vb@113
   174
        if (dst->in_reply_to == NULL)
vb@113
   175
            return PEP_OUT_OF_MEMORY;
vb@113
   176
    }
vb@113
   177
vb@113
   178
    free_stringlist(dst->references);
vb@113
   179
    dst->references = NULL;
vb@113
   180
    if (src->references) {
vb@113
   181
        dst->references = stringlist_dup(src->references);
vb@113
   182
        if (dst->references == NULL)
vb@113
   183
            return PEP_OUT_OF_MEMORY;
vb@113
   184
    }
vb@113
   185
vb@113
   186
    free_stringlist(dst->keywords);
vb@113
   187
    dst->keywords = NULL;
vb@113
   188
    if (src->keywords) {
vb@113
   189
        dst->keywords = stringlist_dup(src->keywords);
vb@113
   190
        if (dst->keywords == NULL)
vb@113
   191
            return PEP_OUT_OF_MEMORY;
vb@113
   192
    }
vb@113
   193
vb@113
   194
    free(dst->comments);
vb@113
   195
    dst->comments = NULL;
vb@113
   196
    if (src->comments) {
vb@113
   197
        dst->comments = strdup(src->comments);
vb@113
   198
        assert(dst->comments);
vb@113
   199
        if (dst->comments == NULL)
vb@113
   200
            return PEP_OUT_OF_MEMORY;
vb@113
   201
    }
vb@113
   202
vb@113
   203
    return PEP_STATUS_OK;
vb@113
   204
}
vb@113
   205
vb@81
   206
static message * clone_to_empty_message(const message * src)
vb@80
   207
{
vb@113
   208
    PEP_STATUS status;
vb@80
   209
    message * msg = NULL;
vb@80
   210
vb@81
   211
    assert(src);
vb@81
   212
vb@113
   213
    msg = calloc(1, sizeof(message));
vb@113
   214
    assert(msg);
vb@80
   215
    if (msg == NULL)
vb@80
   216
        goto enomem;
vb@80
   217
vb@82
   218
    msg->dir = src->dir;
vb@82
   219
vb@113
   220
    status = copy_fields(msg, src);
vb@113
   221
    if (status != PEP_STATUS_OK)
vb@113
   222
        goto enomem;
vb@81
   223
vb@80
   224
    return msg;
vb@80
   225
vb@80
   226
enomem:
vb@113
   227
    free_message(msg);
vb@80
   228
    return NULL;
vb@80
   229
}
vb@80
   230
vb@48
   231
DYNAMIC_API PEP_STATUS encrypt_message(
vb@37
   232
        PEP_SESSION session,
vb@113
   233
        message *src,
vb@37
   234
        stringlist_t * extra,
vb@38
   235
        message **dst,
vb@81
   236
        PEP_enc_format enc_format
vb@37
   237
    )
vb@37
   238
{
vb@37
   239
    PEP_STATUS status = PEP_STATUS_OK;
vb@63
   240
    message * msg = NULL;
vb@63
   241
    stringlist_t * keys = NULL;
vb@113
   242
    bool free_src = false;
vb@37
   243
vb@37
   244
    assert(session);
vb@37
   245
    assert(src);
vb@37
   246
    assert(dst);
vb@81
   247
    assert(enc_format >= PEP_enc_pieces);
vb@81
   248
vb@191
   249
    if (!(session && src && dst && (enc_format >= PEP_enc_pieces)))
vb@191
   250
        return PEP_ILLEGAL_VALUE;
vb@191
   251
vb@37
   252
    *dst = NULL;
vb@67
   253
vb@81
   254
    if (src->enc_format >= PEP_enc_pieces) {
vb@81
   255
        if (src->enc_format == enc_format) {
vb@113
   256
            assert(0); // the message is encrypted this way already
vb@81
   257
            msg = message_dup(src);
vb@81
   258
            if (msg == NULL)
vb@81
   259
                goto enomem;
vb@81
   260
            *dst = msg;
vb@81
   261
            return PEP_STATUS_OK;
vb@81
   262
        }
vb@81
   263
        else {
vb@113
   264
            // decrypt and re-encrypt again
vb@113
   265
            message * _dst = NULL;
vb@113
   266
            PEP_MIME_format mime = (enc_format == PEP_enc_PEP) ? PEP_MIME :
vb@113
   267
                    PEP_MIME_fields_omitted;
vb@113
   268
vb@113
   269
            status = decrypt_message(session, src, mime, &_dst);
vb@113
   270
            if (status != PEP_STATUS_OK)
vb@113
   271
                goto pep_error;
vb@113
   272
vb@113
   273
            src = _dst;
vb@113
   274
            free_src = true;
vb@81
   275
        }
vb@67
   276
    }
vb@37
   277
vb@81
   278
    msg = clone_to_empty_message(src);
vb@80
   279
    if (msg == NULL)
vb@63
   280
        goto enomem;
vb@40
   281
vb@80
   282
    status = myself(session, src->from);
vb@63
   283
    if (status != PEP_STATUS_OK)
vb@63
   284
        goto pep_error;
vb@37
   285
vb@80
   286
    keys = new_stringlist(src->from->fpr);
vb@63
   287
    if (keys == NULL)
vb@63
   288
        goto enomem;
vb@37
   289
vb@39
   290
    stringlist_t *_k = keys;
vb@39
   291
vb@39
   292
    if (extra) {
vb@39
   293
        _k = stringlist_append(_k, extra);
vb@63
   294
        if (_k == NULL)
vb@63
   295
            goto enomem;
vb@37
   296
    }
vb@39
   297
vb@39
   298
    bool dest_keys_found = false;
vb@37
   299
    identity_list * _il;
vb@80
   300
    for (_il = msg->to; _il && _il->ident; _il = _il->next) {
vb@63
   301
        PEP_STATUS status = update_identity(session, _il->ident);
vb@63
   302
        if (status != PEP_STATUS_OK)
vb@63
   303
            goto pep_error;
vb@63
   304
vb@37
   305
        if (_il->ident->fpr) {
vb@39
   306
            dest_keys_found = true;
vb@39
   307
            _k = stringlist_add(_k, _il->ident->fpr);
vb@63
   308
            if (_k == NULL)
vb@63
   309
                goto enomem;
vb@37
   310
        }
vb@37
   311
        else
vb@37
   312
            status = PEP_KEY_NOT_FOUND;
vb@37
   313
    }
vb@37
   314
vb@39
   315
    if (dest_keys_found) {
vb@38
   316
        char *ptext;
vb@37
   317
        char *ctext = NULL;
vb@37
   318
        size_t csize = 0;
vb@37
   319
vb@81
   320
        switch (enc_format) {
vb@112
   321
        case PEP_enc_PGP_MIME: {
vb@62
   322
            bool free_ptext = false;
vb@64
   323
vb@112
   324
            msg->enc_format = PEP_enc_PGP_MIME;
vb@37
   325
vb@113
   326
            if (src->mime == PEP_MIME) {
vb@113
   327
                message *_src = NULL;
vb@113
   328
                assert(src->longmsg);
vb@113
   329
                status = mime_decode_message(src->longmsg, &_src);
vb@113
   330
                if (status != PEP_STATUS_OK)
vb@113
   331
                    goto pep_error;
vb@113
   332
                if (free_src)
vb@113
   333
                    free_message(src);
vb@113
   334
                src = _src;
vb@113
   335
                free_src = true;
vb@62
   336
            }
vb@62
   337
vb@113
   338
            if (src->mime == PEP_MIME_none) {
vb@113
   339
                if (src->shortmsg && strcmp(src->shortmsg, "pEp") != 0) {
vb@113
   340
                    ptext = combine_short_and_long(src->shortmsg, src->longmsg);
vb@113
   341
                    if (ptext == NULL)
vb@113
   342
                        goto enomem;
vb@113
   343
                    free_ptext = true;
vb@113
   344
                }
vb@113
   345
                else if (src->longmsg) {
vb@113
   346
                    ptext = src->longmsg;
vb@113
   347
                }
vb@125
   348
                else {
vb@125
   349
                    ptext = "pEp";
vb@125
   350
                }
vb@113
   351
vb@113
   352
                message *_src = calloc(1, sizeof(message));
vb@89
   353
                assert(_src);
vb@89
   354
                if (_src == NULL)
vb@89
   355
                    goto enomem;
vb@89
   356
                _src->longmsg = ptext;
vb@113
   357
                _src->longmsg_formatted = src->longmsg_formatted;
vb@113
   358
                _src->attachments = src->attachments;
vb@113
   359
                _src->enc_format = PEP_enc_PGP_MIME;
vb@113
   360
                status = mime_encode_message(_src, true, &ptext);
vb@67
   361
                assert(status == PEP_STATUS_OK);
vb@67
   362
                if (free_ptext)
vb@89
   363
                    free(_src->longmsg);
vb@89
   364
                free(_src);
vb@67
   365
                assert(ptext);
vb@67
   366
                if (ptext == NULL)
vb@67
   367
                    goto pep_error;
vb@67
   368
                free_ptext = true;
vb@67
   369
            }
vb@113
   370
            else /* if (src->mime == PEP_MIME_fields_omitted) */ {
vb@67
   371
                ptext = src->longmsg;
vb@67
   372
            }
vb@67
   373
vb@67
   374
            status = encrypt_and_sign(session, keys, ptext, strlen(ptext),
vb@67
   375
                    &ctext, &csize);
vb@62
   376
            if (free_ptext)
vb@62
   377
                free(ptext);
vb@113
   378
            if (ctext == NULL)
vb@63
   379
                goto pep_error;
vb@113
   380
vb@113
   381
            msg->longmsg = strdup(ctext);
vb@113
   382
            if (msg->longmsg == NULL)
vb@113
   383
                goto enomem;
vb@62
   384
        }
vb@63
   385
        break;
vb@62
   386
vb@62
   387
        case PEP_enc_pieces:
vb@64
   388
            msg->enc_format = PEP_enc_pieces;
vb@64
   389
vb@63
   390
            if (src->shortmsg && strcmp(src->shortmsg, "pEp") != 0) {
vb@83
   391
                ptext = combine_short_and_long(src->shortmsg, src->longmsg);
vb@63
   392
                if (ptext == NULL)
vb@63
   393
                    goto enomem;
vb@63
   394
vb@39
   395
                status = encrypt_and_sign(session, keys, ptext, strlen(ptext),
vb@39
   396
                        &ctext, &csize);
vb@40
   397
                free(ptext);
vb@38
   398
                if (ctext) {
vb@40
   399
                    msg->longmsg = strdup(ctext);
vb@64
   400
                    if (msg->longmsg == NULL)
vb@63
   401
                        goto enomem;
vb@38
   402
                }
vb@38
   403
                else {
vb@63
   404
                    goto pep_error;
vb@38
   405
                }
vb@38
   406
            }
vb@38
   407
            else if (src->longmsg) {
vb@38
   408
                ptext = src->longmsg;
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 = strdup(ctext);
vb@64
   413
                    if (msg->longmsg == NULL)
vb@63
   414
                        goto enomem;
vb@38
   415
                }
vb@38
   416
                else {
vb@63
   417
                    goto pep_error;
vb@38
   418
                }
vb@38
   419
            }
vb@63
   420
vb@63
   421
            if (msg->longmsg_formatted) {
vb@38
   422
                ptext = src->longmsg_formatted;
vb@39
   423
                status = encrypt_and_sign(session, keys, ptext, strlen(ptext),
vb@39
   424
                        &ctext, &csize);
vb@38
   425
                if (ctext) {
vb@40
   426
                    msg->longmsg_formatted = strdup(ctext);
vb@63
   427
                    if (msg->longmsg_formatted == NULL)
vb@63
   428
                        goto enomem;
vb@63
   429
                }
vb@63
   430
                else {
vb@63
   431
                    goto pep_error;
vb@63
   432
                }
vb@63
   433
            }
vb@63
   434
vb@63
   435
            if (src->attachments) {
vb@63
   436
                bloblist_t *_s;
vb@63
   437
                bloblist_t *_d = new_bloblist(NULL, 0, NULL, NULL);
vb@63
   438
                if (_d == NULL)
vb@63
   439
                    goto enomem;
vb@63
   440
vb@63
   441
                msg->attachments = _d;
vb@63
   442
                for (_s = src->attachments; _s && _s->data; _s = _s->next) {
vb@63
   443
                    int psize = _s->size;
vb@63
   444
                    ptext = _s->data;
vb@63
   445
                    status = encrypt_and_sign(session, keys, ptext, psize,
vb@63
   446
                            &ctext, &csize);
vb@63
   447
                    if (ctext) {
vb@63
   448
                        char * _c = strdup(ctext);
vb@63
   449
                        if (_c == NULL)
vb@63
   450
                            goto enomem;
vb@63
   451
vb@63
   452
                        _d = bloblist_add(_d, _c, csize, _s->mime_type,
vb@113
   453
                                _s->filename);
vb@63
   454
                        if (_d == NULL)
vb@63
   455
                            goto enomem;
vb@63
   456
                    }
vb@63
   457
                    else {
vb@63
   458
                        goto pep_error;
vb@40
   459
                    }
vb@38
   460
                }
vb@38
   461
            }
vb@38
   462
            break;
vb@38
   463
vb@81
   464
        case PEP_enc_PEP:
vb@81
   465
            // TODO: implement
vb@81
   466
            NOT_IMPLEMENTED
vb@81
   467
vb@38
   468
        default:
vb@38
   469
            assert(0);
vb@63
   470
            status = PEP_ILLEGAL_VALUE;
vb@63
   471
            goto pep_error;
vb@37
   472
        }
vb@37
   473
    }
vb@37
   474
vb@37
   475
    free_stringlist(keys);
vb@113
   476
    if (free_src)
vb@113
   477
        free_message(src);
vb@63
   478
vb@64
   479
    if (msg->shortmsg == NULL)
vb@64
   480
        msg->shortmsg = strdup("pEp");
vb@64
   481
vb@63
   482
    *dst = msg;
vb@63
   483
    return PEP_STATUS_OK;
vb@63
   484
vb@63
   485
enomem:
vb@63
   486
    status = PEP_OUT_OF_MEMORY;
vb@63
   487
vb@63
   488
pep_error:
vb@63
   489
    free_stringlist(keys);
vb@63
   490
    free_message(msg);
vb@113
   491
    if (free_src)
vb@113
   492
        free_message(src);
vb@63
   493
vb@37
   494
    return status;
vb@37
   495
}
vb@37
   496
vb@113
   497
static bool is_encrypted_attachment(const bloblist_t *blob)
vb@113
   498
{
vb@113
   499
    char *ext;
vb@113
   500
 
vb@113
   501
    assert(blob);
vb@113
   502
vb@113
   503
    if (blob->filename == NULL)
vb@113
   504
        return false;
vb@113
   505
vb@113
   506
    ext = strrchr(blob->filename, '.');
vb@113
   507
    if (ext == NULL)
vb@113
   508
        return false;
vb@113
   509
vb@113
   510
    if (strcmp(blob->mime_type, "application/octet-stream")) {
vb@113
   511
        if (strcmp(ext, ".pgp") == 0 || strcmp(ext, ".gpg") == 0 ||
vb@113
   512
                strcmp(ext, ".asc") == 0)
vb@113
   513
            return true;
vb@113
   514
    }
vb@164
   515
    else if (strcmp(blob->mime_type, "text/plain")) {
vb@113
   516
        if (strcmp(ext, ".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
static bool is_encrypted_html_attachment(const bloblist_t *blob)
vb@113
   524
{
vb@113
   525
    assert(blob);
vb@113
   526
    assert(blob->filename);
vb@113
   527
vb@113
   528
    if (strncmp(blob->filename, "PGPexch.htm.", 12) == 0) {
vb@113
   529
        if (strcmp(blob->filename + 11, ".pgp") == 0 ||
vb@113
   530
                strcmp(blob->filename + 11, ".asc") == 0)
vb@113
   531
            return true;
vb@113
   532
    }
vb@113
   533
vb@113
   534
    return false;
vb@113
   535
}
vb@113
   536
vb@159
   537
static char * without_double_ending(const char *filename)
vb@113
   538
{
vb@113
   539
    char *ext;
vb@113
   540
vb@113
   541
    assert(filename);
vb@113
   542
vb@113
   543
    ext = strrchr(filename, '.');
vb@113
   544
    if (ext == NULL)
vb@113
   545
        return NULL;
vb@113
   546
vb@113
   547
    return strndup(filename, ext - filename);
vb@113
   548
}
vb@113
   549
vb@48
   550
DYNAMIC_API PEP_STATUS decrypt_message(
vb@37
   551
        PEP_SESSION session,
vb@113
   552
        message *src,
vb@113
   553
        PEP_MIME_format mime,
vb@113
   554
        message **dst
vb@37
   555
    )
vb@37
   556
{
vb@37
   557
    PEP_STATUS status = PEP_STATUS_OK;
vb@73
   558
    message *msg = NULL;
vb@112
   559
    char *ctext;
vb@112
   560
    size_t csize;
vb@112
   561
    char *ptext;
vb@112
   562
    size_t psize;
vb@112
   563
    stringlist_t *keylist;
vb@113
   564
    bool free_src = false;
vb@37
   565
vb@74
   566
    assert(session);
vb@74
   567
    assert(src);
vb@74
   568
    assert(dst);
vb@73
   569
vb@191
   570
    if (!(session && src && dst))
vb@191
   571
        return PEP_ILLEGAL_VALUE;
vb@191
   572
vb@74
   573
    *dst = NULL;
vb@81
   574
 
vb@113
   575
    if (src->mime == PEP_MIME_fields_omitted || src->mime == PEP_MIME) {
vb@113
   576
        message *_src = NULL;
vb@113
   577
        status = mime_decode_message(src->longmsg, &_src);
vb@113
   578
        if (status != PEP_STATUS_OK)
vb@113
   579
            goto pep_error;
vb@81
   580
vb@113
   581
        if ( src->mime == PEP_MIME_fields_omitted) {
vb@113
   582
            status = copy_fields(_src, src);
vb@113
   583
            if (status != PEP_STATUS_OK) {
vb@113
   584
                free_message(_src);
vb@113
   585
                goto pep_error;
vb@113
   586
            }
vb@113
   587
        }
vb@113
   588
vb@113
   589
        src = _src;
vb@113
   590
        free_src = true;
vb@113
   591
    }
vb@113
   592
vb@119
   593
    // src message is not MIME encoded (any more)
vb@113
   594
    assert(src->mime == PEP_MIME_none);
vb@113
   595
vb@117
   596
    if (!is_PGP_message_text(src->longmsg)) {
vb@117
   597
        status = PEP_UNENCRYPTED;
vb@117
   598
        goto pep_error;
vb@117
   599
    }
vb@117
   600
vb@113
   601
    ctext = src->longmsg;
vb@113
   602
    csize = strlen(src->longmsg);
vb@113
   603
vb@113
   604
    status = decrypt_and_verify(session, ctext, csize, &ptext, &psize,
vb@113
   605
            &keylist);
vb@113
   606
    if (ptext == NULL)
vb@113
   607
        goto pep_error;
vb@113
   608
vb@113
   609
    switch (src->enc_format) {
vb@113
   610
        case PEP_enc_PGP_MIME:
vb@113
   611
            status = mime_decode_message(ptext, &msg);
vb@113
   612
            if (status != PEP_STATUS_OK)
vb@113
   613
                goto pep_error;
vb@113
   614
vb@113
   615
            break;
vb@113
   616
vb@113
   617
        case PEP_enc_pieces:
vb@113
   618
            msg = clone_to_empty_message(src);
vb@113
   619
            if (msg == NULL)
vb@113
   620
                goto enomem;
vb@113
   621
vb@113
   622
            msg->longmsg = strdup(ptext);
vb@113
   623
            if (msg->longmsg == NULL)
vb@113
   624
                goto enomem;
vb@113
   625
vb@113
   626
            bloblist_t *_m = msg->attachments;
vb@113
   627
            bloblist_t *_s;
vb@113
   628
            for (_s = src->attachments; _s; _s = _s->next) {
vb@113
   629
                if (is_encrypted_attachment(_s)) {
vb@113
   630
                    ctext = _s->data;
vb@113
   631
                    csize = _s->size;
vb@113
   632
vb@113
   633
                    status = decrypt_and_verify(session, ctext, csize, &ptext,
vb@113
   634
                            &psize, &keylist);
vb@113
   635
                    if (ptext == NULL)
vb@113
   636
                        goto pep_error;
vb@113
   637
                    
vb@113
   638
                    if (is_encrypted_html_attachment(_s)) {
vb@113
   639
                        msg->longmsg_formatted = strdup(ptext);
vb@113
   640
                        if (msg->longmsg_formatted == NULL)
vb@113
   641
                            goto pep_error;
vb@113
   642
                    }
vb@113
   643
                    else {
vb@113
   644
                        char * mime_type = "application/octet-stream";
vb@113
   645
                        char * filename = without_double_ending(_s->filename);
vb@113
   646
                        if (filename == NULL)
vb@113
   647
                            goto enomem;
vb@113
   648
vb@113
   649
                        _m = bloblist_add(_m, ptext, psize, mime_type, filename);
vb@113
   650
                        if (_m == NULL)
vb@113
   651
                            goto enomem;
vb@113
   652
vb@113
   653
                       if (msg->attachments == NULL)
vb@113
   654
                            msg->attachments = _m;
vb@113
   655
                    }
vb@113
   656
                }
vb@82
   657
            }
vb@82
   658
vb@81
   659
            break;
vb@81
   660
vb@81
   661
        default:
vb@113
   662
            // BUG: must implement more
vb@113
   663
            NOT_IMPLEMENTED
vb@81
   664
    }
vb@74
   665
vb@113
   666
    switch (src->enc_format) {
vb@113
   667
        case PEP_enc_PGP_MIME:
vb@113
   668
        case PEP_enc_pieces:
vb@113
   669
            status = copy_fields(msg, src);
vb@113
   670
            if (status != PEP_STATUS_OK)
vb@113
   671
                goto pep_error;
vb@113
   672
vb@166
   673
            if (src->shortmsg && strcmp(src->shortmsg, "pEp") != 0) {
vb@113
   674
                free(msg->shortmsg);
vb@113
   675
                msg->shortmsg = strdup(src->shortmsg);
vb@113
   676
                if (msg->shortmsg == NULL)
vb@113
   677
                    goto enomem;
vb@113
   678
            }
vb@113
   679
vb@113
   680
            if (msg->shortmsg == NULL || strcmp(msg->shortmsg, "pEp") == 0)
vb@113
   681
            {
vb@113
   682
                char * shortmsg;
vb@113
   683
                char * longmsg;
vb@113
   684
vb@113
   685
                int r = seperate_short_and_long(msg->longmsg, &shortmsg,
vb@113
   686
                        &longmsg);
vb@113
   687
                if (r == -1)
vb@113
   688
                    goto enomem;
vb@113
   689
vb@113
   690
                free(msg->shortmsg);
vb@113
   691
                free(msg->longmsg);
vb@113
   692
vb@113
   693
                msg->shortmsg = shortmsg;
vb@113
   694
                msg->longmsg = longmsg;
vb@113
   695
            }
vb@113
   696
            else {
vb@113
   697
                msg->shortmsg = strdup(src->shortmsg);
vb@113
   698
                if (msg->shortmsg == NULL)
vb@113
   699
                    goto enomem;
vb@113
   700
                msg->longmsg = ptext;
vb@113
   701
            }
vb@166
   702
            break;
vb@113
   703
vb@113
   704
        default:
vb@113
   705
            // BUG: must implement more
vb@113
   706
            NOT_IMPLEMENTED
vb@113
   707
    }
vb@113
   708
vb@113
   709
    switch (mime) {
vb@113
   710
        case PEP_MIME_none:
vb@113
   711
            break;
vb@113
   712
vb@113
   713
        case PEP_MIME:
vb@113
   714
        case PEP_MIME_fields_omitted:
vb@113
   715
            {
vb@113
   716
                char *text = NULL;
vb@113
   717
                status = mime_encode_message(msg,
vb@113
   718
                        mime == PEP_MIME_fields_omitted, &text);
vb@113
   719
                if (status != PEP_STATUS_OK)
vb@113
   720
                    goto pep_error;
vb@113
   721
vb@113
   722
                message *_msg = clone_to_empty_message(msg);
vb@113
   723
                if (_msg == NULL) {
vb@113
   724
                    free(text);
vb@113
   725
                    goto enomem;
vb@113
   726
                }
vb@113
   727
                _msg->longmsg = text;
vb@113
   728
                _msg->shortmsg = strdup(msg->shortmsg);
vb@113
   729
                if (msg->shortmsg == NULL)
vb@113
   730
                    goto enomem;
vb@113
   731
vb@113
   732
                free_message(msg);
vb@113
   733
                msg = _msg;
vb@113
   734
            }
vb@167
   735
            break;
vb@113
   736
    }
vb@113
   737
vb@113
   738
    if (free_src)
vb@113
   739
        free_message(src);
vb@74
   740
    *dst = msg;
vb@74
   741
    return PEP_STATUS_OK;
vb@73
   742
vb@73
   743
enomem:
vb@73
   744
    status = PEP_OUT_OF_MEMORY;
vb@73
   745
vb@73
   746
pep_error:
vb@73
   747
    free_message(msg);
vb@113
   748
    if (free_src)
vb@113
   749
        free_message(src);
vb@39
   750
vb@37
   751
    return status;
vb@37
   752
}
vb@37
   753
vb@190
   754
static PEP_comm_type _get_comm_type(
vb@190
   755
        PEP_SESSION session,
vb@190
   756
        PEP_comm_type max_comm_type,
vb@190
   757
        pEp_identity *ident
vb@190
   758
    )
vb@190
   759
{
vb@190
   760
    PEP_STATUS status = update_identity(session, ident);
vb@190
   761
vb@190
   762
    if (max_comm_type == PEP_ct_compromized)
vb@190
   763
        return PEP_ct_compromized;
vb@190
   764
vb@190
   765
    if (status == PEP_STATUS_OK) {
vb@190
   766
        if (ident->comm_type == PEP_ct_compromized)
vb@190
   767
            return PEP_ct_compromized;
vb@190
   768
        else
vb@190
   769
            return MIN(max_comm_type, ident->comm_type);
vb@190
   770
    }
vb@190
   771
    else {
vb@190
   772
        return PEP_ct_unknown;
vb@190
   773
    }
vb@190
   774
}
vb@190
   775
vb@193
   776
DYNAMIC_API PEP_STATUS get_message_color(
vb@190
   777
        PEP_SESSION session,
vb@190
   778
        message *msg,
vb@232
   779
        PEP_color *color
vb@190
   780
    )
vb@190
   781
{
vb@190
   782
    PEP_STATUS status = PEP_STATUS_OK;
vb@190
   783
    PEP_comm_type max_comm_type = PEP_ct_pEp;
vb@190
   784
    bool comm_type_determined = false;
vb@190
   785
    identity_list * il;
vb@190
   786
vb@190
   787
    assert(session);
vb@190
   788
    assert(msg);
vb@190
   789
    assert(color);
vb@190
   790
vb@191
   791
    if (!(session && msg && color))
vb@191
   792
        return PEP_ILLEGAL_VALUE;
vb@191
   793
vb@232
   794
    *color = PEP_undefined;
vb@190
   795
vb@190
   796
    assert(msg->from);
vb@190
   797
    if (msg->from == NULL)
vb@190
   798
        return PEP_ILLEGAL_VALUE;
vb@190
   799
vb@190
   800
    switch (msg->dir) {
vb@190
   801
        case PEP_dir_incoming:
vb@190
   802
            status = update_identity(session, msg->from);
vb@190
   803
            if (status != PEP_STATUS_OK)
vb@190
   804
                return status;
vb@190
   805
            max_comm_type = msg->from->comm_type;
vb@190
   806
            comm_type_determined = true;
vb@190
   807
            break;
vb@190
   808
        
vb@190
   809
        case PEP_dir_outgoing:
vb@190
   810
            status = myself(session, msg->from);
vb@190
   811
            if (status != PEP_STATUS_OK)
vb@190
   812
                return status;
vb@190
   813
vb@195
   814
            for (il = msg->to; il != NULL; il = il->next) {
vb@195
   815
                if (il->ident) {
vb@195
   816
                    max_comm_type = _get_comm_type(session, max_comm_type,
vb@195
   817
                            il->ident);
vb@195
   818
                    comm_type_determined = true;
vb@190
   819
                }
vb@190
   820
            }
vb@190
   821
vb@195
   822
            for (il = msg->cc; il != NULL; il = il->next) {
vb@195
   823
                if (il->ident) {
vb@195
   824
                    max_comm_type = _get_comm_type(session, max_comm_type,
vb@195
   825
                            il->ident);
vb@195
   826
                    comm_type_determined = true;
vb@190
   827
                }
vb@190
   828
            }
vb@190
   829
vb@195
   830
            for (il = msg->bcc; il != NULL; il = il->next) {
vb@195
   831
                if (il->ident) {
vb@195
   832
                    max_comm_type = _get_comm_type(session, max_comm_type,
vb@195
   833
                            il->ident);
vb@195
   834
                    comm_type_determined = true;
vb@190
   835
                }
vb@190
   836
            }
vb@190
   837
            break;
vb@190
   838
vb@190
   839
        default:
vb@190
   840
            return PEP_ILLEGAL_VALUE;
vb@190
   841
    }
vb@190
   842
vb@190
   843
    if (comm_type_determined == false)
vb@232
   844
        *color = PEP_undefined;
vb@190
   845
vb@190
   846
    else if (max_comm_type == PEP_ct_compromized)
vb@232
   847
        *color = PEP_under_attack;
vb@190
   848
vb@190
   849
    else if (max_comm_type >= PEP_ct_confirmed_enc_anon)
vb@232
   850
        *color = PEP_trusted_and_anonymized;
vb@190
   851
vb@190
   852
    else if (max_comm_type >= PEP_ct_strong_encryption)
vb@232
   853
        *color = PEP_trusted;
vb@190
   854
vb@190
   855
    else if (max_comm_type >= PEP_ct_strong_but_unconfirmed &&
vb@190
   856
            max_comm_type < PEP_ct_confirmed)
vb@232
   857
        *color = PEP_reliable;
vb@190
   858
    
vb@190
   859
    else if (max_comm_type == PEP_ct_no_encryption ||
vb@190
   860
            max_comm_type == PEP_ct_no_encrypted_channel)
vb@232
   861
        *color = PEP_unencrypted;
vb@190
   862
vb@190
   863
    else if (max_comm_type == PEP_ct_unknown)
vb@232
   864
        *color = PEP_undefined;
vb@190
   865
vb@190
   866
    else
vb@232
   867
        *color = PEP_unreliable;
vb@190
   868
vb@190
   869
    return PEP_STATUS_OK;
vb@190
   870
}
vb@190
   871