src/message_api.c
author krista
Mon, 08 May 2017 15:48:46 +0200
branchENGINE-207
changeset 1893 9e648c792083
parent 1756 f46ce946ede9
child 1896 bd4d52d8a71f
permissions -rw-r--r--
ENGINE-207: fixed verification problem - for some unknown reason, post libetpan parse, Outlook has CRLFs in the next, whereas Linux, Android, etc, appear not to. Tricky. We now handle both around boundary delimiters, and sig verification of AppleMail works!
vb@1513
     1
// This file is under GNU General Public License 3.0
vb@1513
     2
// see LICENSE.txt
vb@1513
     3
vb@125
     4
#include "pEp_internal.h"
vb@37
     5
#include "message_api.h"
vb@37
     6
vb@130
     7
#include "platform.h"
vb@220
     8
#include "mime.h"
vb@952
     9
#include "sync_fsm.h"
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@926
    15
vb@951
    16
#ifndef _MIN
vb@951
    17
#define _MIN(A, B) ((B) > (A) ? (A) : (B))
vb@190
    18
#endif
vb@951
    19
#ifndef _MAX
vb@951
    20
#define _MAX(A, B) ((B) > (A) ? (B) : (A))
vb@300
    21
#endif
vb@190
    22
vb@235
    23
vb@235
    24
static bool string_equality(const char *s1, const char *s2)
vb@235
    25
{
vb@235
    26
    if (s1 == NULL || s2 == NULL)
vb@235
    27
        return false;
vb@235
    28
vb@235
    29
    assert(s1 && s2);
vb@235
    30
vb@235
    31
    return strcmp(s1, s2) == 0;
vb@235
    32
}
vb@235
    33
vb@235
    34
static bool is_mime_type(const bloblist_t *bl, const char *mt)
vb@235
    35
{
vb@235
    36
    assert(mt);
vb@235
    37
vb@235
    38
    return bl && string_equality(bl->mime_type, mt);
vb@235
    39
}
vb@235
    40
krista@854
    41
//
krista@854
    42
// This function presumes the file ending is a proper substring of the
krista@854
    43
// filename (i.e. if bl->filename is "a.pgp" and fe is ".pgp", it will
krista@854
    44
// return true, but if bl->filename is ".pgp" and fe is ".pgp", it will
krista@854
    45
// return false. This is desired behaviour.
krista@854
    46
//
vb@235
    47
static bool is_fileending(const bloblist_t *bl, const char *fe)
vb@235
    48
{
vb@235
    49
    assert(fe);
krista@1427
    50
krista@853
    51
    if (bl == NULL || bl->filename == NULL || fe == NULL)
vb@235
    52
        return false;
vb@235
    53
vb@235
    54
    assert(bl && bl->filename);
vb@235
    55
vb@235
    56
    size_t fe_len = strlen(fe);
vb@235
    57
    size_t fn_len = strlen(bl->filename);
vb@235
    58
vb@235
    59
    if (fn_len <= fe_len)
vb@235
    60
        return false;
vb@235
    61
vb@235
    62
    assert(fn_len > fe_len);
vb@235
    63
vb@235
    64
    return strcmp(bl->filename + (fn_len - fe_len), fe) == 0;
vb@235
    65
}
vb@235
    66
vb@952
    67
void add_opt_field(message *msg, const char *name, const char *value)
vb@284
    68
{
vb@952
    69
    assert(msg && name && value);
vb@284
    70
vb@284
    71
    if (msg && name && value) {
vb@284
    72
        stringpair_t *pair = new_stringpair(name, value);
vb@284
    73
        if (pair == NULL)
vb@284
    74
            return;
vb@284
    75
vb@284
    76
        stringpair_list_t *field = stringpair_list_add(msg->opt_fields, pair);
vb@284
    77
        if (field == NULL)
Edouard@833
    78
        {
Edouard@833
    79
            free_stringpair(pair);
vb@284
    80
            return;
Edouard@833
    81
        }
vb@284
    82
vb@284
    83
        if (msg->opt_fields == NULL)
vb@284
    84
            msg->opt_fields = field;
vb@284
    85
    }
vb@284
    86
}
vb@284
    87
vb@83
    88
static char * combine_short_and_long(const char *shortmsg, const char *longmsg)
vb@62
    89
{
vb@83
    90
    assert(shortmsg);
vb@83
    91
    assert(strcmp(shortmsg, "pEp") != 0);
vb@855
    92
vb@857
    93
    if (!shortmsg || strcmp(shortmsg, "pEp") == 0) {
vb@857
    94
        if (!longmsg) {
vb@857
    95
            return NULL;
vb@857
    96
        }
vb@857
    97
        else {
vb@857
    98
            char *result = strdup(longmsg);
vb@857
    99
            assert(result);
vb@857
   100
            return result;
vb@857
   101
        }
vb@857
   102
    }
krista@1427
   103
vb@83
   104
    if (longmsg == NULL)
vb@63
   105
        longmsg = "";
vb@63
   106
krista@935
   107
    const char * const subject = "Subject: ";
krista@935
   108
    const size_t SUBJ_LEN = 9;
krista@935
   109
    const char * const newlines = "\n\n";
krista@935
   110
    const size_t NL_LEN = 2;
krista@935
   111
roker@1559
   112
    const size_t bufsize = SUBJ_LEN + strlen(shortmsg) + NL_LEN + strlen(longmsg) + 1;
roker@1559
   113
    char * ptext = calloc(1, bufsize);
vb@109
   114
    assert(ptext);
vb@62
   115
    if (ptext == NULL)
vb@62
   116
        return NULL;
vb@62
   117
krista@935
   118
    strlcpy(ptext, subject, bufsize);
krista@918
   119
    strlcat(ptext, shortmsg, bufsize);
krista@935
   120
    strlcat(ptext, newlines, bufsize);
krista@918
   121
    strlcat(ptext, longmsg, bufsize);
vb@62
   122
vb@62
   123
    return ptext;
vb@62
   124
}
vb@44
   125
krista@853
   126
static int separate_short_and_long(const char *src, char **shortmsg, char **longmsg)
vb@82
   127
{
vb@82
   128
    char *_shortmsg = NULL;
vb@82
   129
    char *_longmsg = NULL;
vb@82
   130
vb@82
   131
    assert(src);
vb@82
   132
    assert(shortmsg);
vb@82
   133
    assert(longmsg);
krista@1427
   134
krista@853
   135
    if (src == NULL || shortmsg == NULL || longmsg == NULL)
krista@853
   136
        return -1;
vb@82
   137
vb@82
   138
    *shortmsg = NULL;
vb@82
   139
    *longmsg = NULL;
vb@82
   140
vb@85
   141
    if (strncasecmp(src, "subject: ", 9) == 0) {
vb@82
   142
        char *line_end = strchr(src, '\n');
vb@311
   143
vb@82
   144
        if (line_end == NULL) {
vb@82
   145
            _shortmsg = strdup(src + 9);
vb@469
   146
            assert(_shortmsg);
vb@82
   147
            if (_shortmsg == NULL)
vb@82
   148
                goto enomem;
vb@82
   149
            // _longmsg = NULL;
vb@82
   150
        }
vb@82
   151
        else {
vb@82
   152
            size_t n = line_end - src;
vb@166
   153
vb@82
   154
            if (*(line_end - 1) == '\r')
vb@166
   155
                _shortmsg = strndup(src + 9, n - 10);
vb@82
   156
            else
vb@166
   157
                _shortmsg = strndup(src + 9, n - 9);
vb@469
   158
            assert(_shortmsg);
vb@82
   159
            if (_shortmsg == NULL)
vb@82
   160
                goto enomem;
vb@166
   161
vb@166
   162
            while (*(src + n) && (*(src + n) == '\n' || *(src + n) == '\r'))
vb@166
   163
                ++n;
vb@166
   164
vb@166
   165
            if (*(src + n)) {
vb@166
   166
                _longmsg = strdup(src + n);
vb@469
   167
                assert(_longmsg);
vb@166
   168
                if (_longmsg == NULL)
vb@166
   169
                    goto enomem;
vb@166
   170
            }
vb@82
   171
        }
vb@82
   172
    }
vb@82
   173
    else {
vb@113
   174
        _shortmsg = strdup("");
vb@469
   175
        assert(_shortmsg);
vb@82
   176
        if (_shortmsg == NULL)
vb@82
   177
            goto enomem;
vb@82
   178
        _longmsg = strdup(src);
vb@469
   179
        assert(_longmsg);
vb@82
   180
        if (_longmsg == NULL)
vb@82
   181
            goto enomem;
vb@82
   182
    }
vb@311
   183
vb@82
   184
    *shortmsg = _shortmsg;
vb@82
   185
    *longmsg = _longmsg;
vb@82
   186
vb@82
   187
    return 0;
vb@82
   188
vb@82
   189
enomem:
vb@82
   190
    free(_shortmsg);
vb@82
   191
    free(_longmsg);
vb@82
   192
vb@82
   193
    return -1;
vb@82
   194
}
vb@82
   195
vb@113
   196
static PEP_STATUS copy_fields(message *dst, const message *src)
vb@113
   197
{
vb@164
   198
    assert(dst);
vb@164
   199
    assert(src);
vb@164
   200
Edouard@840
   201
    if(!(dst && src))
Edouard@840
   202
        return PEP_ILLEGAL_VALUE;
Edouard@840
   203
vb@113
   204
    free_timestamp(dst->sent);
vb@113
   205
    dst->sent = NULL;
vb@113
   206
    if (src->sent) {
vb@113
   207
        dst->sent = timestamp_dup(src->sent);
vb@113
   208
        if (dst->sent == NULL)
vb@113
   209
            return PEP_OUT_OF_MEMORY;
vb@113
   210
    }
vb@113
   211
vb@113
   212
    free_timestamp(dst->recv);
vb@113
   213
    dst->recv = NULL;
vb@113
   214
    if (src->recv) {
vb@113
   215
        dst->recv = timestamp_dup(src->recv);
vb@113
   216
        if (dst->recv == NULL)
vb@113
   217
            return PEP_OUT_OF_MEMORY;
vb@113
   218
    }
vb@113
   219
vb@113
   220
    free_identity(dst->from);
vb@113
   221
    dst->from = NULL;
vb@113
   222
    if (src->from) {
vb@113
   223
        dst->from = identity_dup(src->from);
vb@113
   224
        if (dst->from == NULL)
vb@113
   225
            return PEP_OUT_OF_MEMORY;
vb@113
   226
    }
vb@113
   227
vb@113
   228
    free_identity_list(dst->to);
vb@113
   229
    dst->to = NULL;
vb@274
   230
    if (src->to && src->to->ident) {
vb@113
   231
        dst->to = identity_list_dup(src->to);
vb@113
   232
        if (dst->to == NULL)
vb@113
   233
            return PEP_OUT_OF_MEMORY;
vb@113
   234
    }
vb@113
   235
vb@113
   236
    free_identity(dst->recv_by);
vb@113
   237
    dst->recv_by = NULL;
vb@113
   238
    if (src->recv_by) {
vb@113
   239
        dst->recv_by = identity_dup(src->recv_by);
vb@113
   240
        if (dst->recv_by == NULL)
vb@113
   241
            return PEP_OUT_OF_MEMORY;
vb@113
   242
    }
vb@113
   243
vb@113
   244
    free_identity_list(dst->cc);
vb@113
   245
    dst->cc = NULL;
vb@274
   246
    if (src->cc && src->cc->ident) {
vb@113
   247
        dst->cc = identity_list_dup(src->cc);
vb@113
   248
        if (dst->cc == NULL)
vb@113
   249
            return PEP_OUT_OF_MEMORY;
vb@113
   250
    }
vb@113
   251
vb@113
   252
    free_identity_list(dst->bcc);
vb@113
   253
    dst->bcc = NULL;
vb@274
   254
    if (src->bcc && src->bcc->ident) {
vb@113
   255
        dst->bcc = identity_list_dup(src->bcc);
vb@113
   256
        if (dst->bcc == NULL)
vb@113
   257
            return PEP_OUT_OF_MEMORY;
vb@113
   258
    }
vb@113
   259
vb@113
   260
    free_identity_list(dst->reply_to);
vb@113
   261
    dst->reply_to = NULL;
vb@274
   262
    if (src->reply_to && src->reply_to->ident) {
vb@113
   263
        dst->reply_to = identity_list_dup(src->reply_to);
vb@113
   264
        if (dst->reply_to == NULL)
vb@113
   265
            return PEP_OUT_OF_MEMORY;
vb@113
   266
    }
vb@113
   267
vb@113
   268
    free_stringlist(dst->in_reply_to);
vb@113
   269
    dst->in_reply_to = NULL;
vb@274
   270
    if (src->in_reply_to && src->in_reply_to->value) {
vb@113
   271
        dst->in_reply_to = stringlist_dup(src->in_reply_to);
vb@113
   272
        if (dst->in_reply_to == NULL)
vb@113
   273
            return PEP_OUT_OF_MEMORY;
vb@113
   274
    }
vb@113
   275
vb@113
   276
    free_stringlist(dst->references);
vb@113
   277
    dst->references = NULL;
vb@113
   278
    if (src->references) {
vb@113
   279
        dst->references = stringlist_dup(src->references);
vb@113
   280
        if (dst->references == NULL)
vb@113
   281
            return PEP_OUT_OF_MEMORY;
vb@113
   282
    }
vb@113
   283
vb@113
   284
    free_stringlist(dst->keywords);
vb@113
   285
    dst->keywords = NULL;
vb@274
   286
    if (src->keywords && src->keywords->value) {
vb@113
   287
        dst->keywords = stringlist_dup(src->keywords);
vb@113
   288
        if (dst->keywords == NULL)
vb@113
   289
            return PEP_OUT_OF_MEMORY;
vb@113
   290
    }
vb@113
   291
vb@113
   292
    free(dst->comments);
vb@113
   293
    dst->comments = NULL;
vb@113
   294
    if (src->comments) {
vb@113
   295
        dst->comments = strdup(src->comments);
vb@113
   296
        assert(dst->comments);
vb@113
   297
        if (dst->comments == NULL)
vb@113
   298
            return PEP_OUT_OF_MEMORY;
vb@113
   299
    }
vb@113
   300
vb@1092
   301
    free_stringpair_list(dst->opt_fields);
vb@1092
   302
    dst->opt_fields = NULL;
vb@1092
   303
    if (src->opt_fields) {
vb@1092
   304
        dst->opt_fields = stringpair_list_dup(src->opt_fields);
vb@1092
   305
        if (dst->opt_fields == NULL)
vb@1092
   306
            return PEP_OUT_OF_MEMORY;
vb@1092
   307
    }
vb@1092
   308
vb@113
   309
    return PEP_STATUS_OK;
vb@113
   310
}
vb@113
   311
vb@81
   312
static message * clone_to_empty_message(const message * src)
vb@80
   313
{
vb@113
   314
    PEP_STATUS status;
vb@80
   315
    message * msg = NULL;
vb@80
   316
vb@81
   317
    assert(src);
krista@853
   318
    if (src == NULL)
krista@853
   319
        return NULL;
vb@81
   320
vb@113
   321
    msg = calloc(1, sizeof(message));
vb@113
   322
    assert(msg);
vb@80
   323
    if (msg == NULL)
vb@80
   324
        goto enomem;
vb@80
   325
vb@82
   326
    msg->dir = src->dir;
vb@82
   327
vb@113
   328
    status = copy_fields(msg, src);
vb@113
   329
    if (status != PEP_STATUS_OK)
vb@113
   330
        goto enomem;
vb@81
   331
vb@80
   332
    return msg;
vb@80
   333
vb@80
   334
enomem:
vb@113
   335
    free_message(msg);
vb@80
   336
    return NULL;
vb@80
   337
}
vb@80
   338
vb@260
   339
static PEP_STATUS encrypt_PGP_MIME(
vb@311
   340
    PEP_SESSION session,
vb@311
   341
    const message *src,
vb@311
   342
    stringlist_t *keys,
krista@1639
   343
    message *dst,
krista@1639
   344
    PEP_encrypt_flags_t flags
vb@260
   345
    )
vb@260
   346
{
vb@260
   347
    PEP_STATUS status = PEP_STATUS_OK;
vb@260
   348
    bool free_ptext = false;
vb@468
   349
    char *ptext = NULL;
Edouard@882
   350
    char *ctext = NULL;
vb@260
   351
    char *mimetext = NULL;
vb@260
   352
    size_t csize;
vb@260
   353
    assert(dst->longmsg == NULL);
vb@260
   354
    dst->enc_format = PEP_enc_PGP_MIME;
vb@260
   355
vb@260
   356
    if (src->shortmsg && strcmp(src->shortmsg, "pEp") != 0) {
vb@466
   357
        if (session->unencrypted_subject) {
vb@466
   358
            dst->shortmsg = strdup(src->shortmsg);
vb@469
   359
            assert(dst->shortmsg);
vb@466
   360
            if (dst->shortmsg == NULL)
vb@466
   361
                goto enomem;
vb@466
   362
            ptext = src->longmsg;
vb@466
   363
        }
vb@466
   364
        else {
vb@466
   365
            ptext = combine_short_and_long(src->shortmsg, src->longmsg);
vb@466
   366
            if (ptext == NULL)
vb@466
   367
                goto enomem;
vb@466
   368
            free_ptext = true;
vb@466
   369
        }
vb@260
   370
    }
vb@260
   371
    else if (src->longmsg) {
vb@260
   372
        ptext = src->longmsg;
vb@260
   373
    }
vb@260
   374
    else {
vb@260
   375
        ptext = "pEp";
vb@260
   376
    }
vb@260
   377
vb@260
   378
    message *_src = calloc(1, sizeof(message));
vb@260
   379
    assert(_src);
vb@260
   380
    if (_src == NULL)
vb@260
   381
        goto enomem;
vb@260
   382
    _src->longmsg = ptext;
vb@260
   383
    _src->longmsg_formatted = src->longmsg_formatted;
vb@260
   384
    _src->attachments = src->attachments;
vb@260
   385
    _src->enc_format = PEP_enc_none;
vb@260
   386
    status = mime_encode_message(_src, true, &mimetext);
vb@260
   387
    assert(status == PEP_STATUS_OK);
krista@853
   388
    if (status != PEP_STATUS_OK)
krista@853
   389
        goto pep_error;
krista@1427
   390
Edouard@371
   391
    if (free_ptext){
vb@260
   392
        free(ptext);
Edouard@371
   393
        free_ptext=0;
Edouard@371
   394
    }
vb@260
   395
    free(_src);
vb@260
   396
    assert(mimetext);
vb@260
   397
    if (mimetext == NULL)
vb@260
   398
        goto pep_error;
vb@260
   399
krista@1639
   400
    if (flags & PEP_encrypt_flag_force_unsigned)
krista@1639
   401
        status = encrypt_only(session, keys, mimetext, strlen(mimetext),
krista@1639
   402
            &ctext, &csize);
krista@1639
   403
    else
krista@1639
   404
        status = encrypt_and_sign(session, keys, mimetext, strlen(mimetext),
krista@1639
   405
            &ctext, &csize);
vb@260
   406
    free(mimetext);
vb@260
   407
    if (ctext == NULL)
vb@260
   408
        goto pep_error;
vb@260
   409
vb@260
   410
    dst->longmsg = strdup("this message was encrypted with p≡p "
lix@487
   411
        "https://pEp-project.org");
vb@469
   412
    assert(dst->longmsg);
vb@260
   413
    if (dst->longmsg == NULL)
vb@260
   414
        goto enomem;
vb@260
   415
vb@260
   416
    char *v = strdup("Version: 1");
vb@469
   417
    assert(v);
vb@260
   418
    if (v == NULL)
vb@260
   419
        goto enomem;
vb@260
   420
roker@801
   421
    bloblist_t *_a = new_bloblist(v, strlen(v), "application/pgp-encrypted", NULL);
vb@260
   422
    if (_a == NULL)
vb@260
   423
        goto enomem;
vb@260
   424
    dst->attachments = _a;
vb@288
   425
Edouard@882
   426
    _a = bloblist_add(_a, ctext, csize, "application/octet-stream",
Edouard@427
   427
        "msg.asc");
vb@260
   428
    if (_a == NULL)
vb@260
   429
        goto enomem;
vb@260
   430
vb@260
   431
    return PEP_STATUS_OK;
vb@260
   432
vb@260
   433
enomem:
vb@260
   434
    status = PEP_OUT_OF_MEMORY;
vb@260
   435
vb@260
   436
pep_error:
vb@260
   437
    if (free_ptext)
vb@260
   438
        free(ptext);
Edouard@882
   439
    free(ctext);
vb@260
   440
    return status;
vb@260
   441
}
vb@260
   442
vb@260
   443
static PEP_STATUS encrypt_PGP_in_pieces(
vb@311
   444
    PEP_SESSION session,
vb@311
   445
    const message *src,
vb@311
   446
    stringlist_t *keys,
krista@1639
   447
    message *dst,
krista@1639
   448
    PEP_encrypt_flags_t flags
vb@260
   449
    )
vb@260
   450
{
vb@260
   451
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@882
   452
    char *ctext = NULL;
vb@260
   453
    size_t csize;
vb@468
   454
    char *ptext = NULL;
vb@466
   455
    bool free_ptext = false;
vb@260
   456
vb@260
   457
    assert(dst->longmsg == NULL);
vb@260
   458
    assert(dst->attachments == NULL);
vb@260
   459
vb@260
   460
    dst->enc_format = PEP_enc_pieces;
vb@260
   461
krista@1639
   462
    bool nosign = (flags & PEP_encrypt_flag_force_unsigned);
krista@1639
   463
vb@320
   464
    if (src->shortmsg && src->shortmsg[0] && strcmp(src->shortmsg, "pEp") != 0) {
vb@466
   465
        if (session->unencrypted_subject) {
vb@466
   466
            dst->shortmsg = strdup(src->shortmsg);
vb@469
   467
            assert(dst->shortmsg);
vb@466
   468
            if (dst->shortmsg == NULL)
vb@466
   469
                goto enomem;
vb@466
   470
            ptext = src->longmsg;
vb@466
   471
        }
vb@466
   472
        else {
vb@466
   473
            ptext = combine_short_and_long(src->shortmsg, src->longmsg);
vb@466
   474
            if (ptext == NULL)
vb@466
   475
                goto enomem;
vb@466
   476
            free_ptext = true;
vb@466
   477
        }
vb@260
   478
krista@1639
   479
        if (nosign)
krista@1639
   480
            status = encrypt_only(session, keys, ptext, strlen(ptext), &ctext,
krista@1639
   481
                &csize);
krista@1639
   482
        else 
krista@1639
   483
            status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
krista@1639
   484
                &csize);
vb@466
   485
        if (free_ptext)
vb@466
   486
            free(ptext);
vb@466
   487
        free_ptext = false;
vb@288
   488
        if (ctext) {
Edouard@882
   489
            dst->longmsg = ctext;
vb@288
   490
        }
vb@288
   491
        else {
vb@260
   492
            goto pep_error;
vb@288
   493
        }
vb@260
   494
    }
vb@320
   495
    else if (src->longmsg && src->longmsg[0]) {
vb@466
   496
        ptext = src->longmsg;
krista@1639
   497
        if (nosign)
krista@1639
   498
            status = encrypt_only(session, keys, ptext, strlen(ptext), &ctext,
krista@1639
   499
                &csize);
krista@1639
   500
        else 
krista@1639
   501
            status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
krista@1639
   502
                &csize);
vb@288
   503
        if (ctext) {
Edouard@882
   504
            dst->longmsg = ctext;
vb@288
   505
        }
vb@288
   506
        else {
vb@260
   507
            goto pep_error;
vb@288
   508
        }
vb@284
   509
    }
vb@284
   510
    else {
vb@284
   511
        dst->longmsg = strdup("");
vb@469
   512
        assert(dst->longmsg);
vb@284
   513
        if (dst->longmsg == NULL)
vb@284
   514
            goto enomem;
vb@260
   515
    }
vb@260
   516
vb@320
   517
    if (src->longmsg_formatted && src->longmsg_formatted[0]) {
vb@466
   518
        ptext = src->longmsg_formatted;
krista@1639
   519
        if (nosign)
krista@1639
   520
            status = encrypt_only(session, keys, ptext, strlen(ptext), &ctext,
krista@1639
   521
                &csize);
krista@1639
   522
        else 
krista@1639
   523
            status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
krista@1639
   524
                &csize);
vb@260
   525
        if (ctext) {
vb@288
   526
Edouard@882
   527
            bloblist_t *_a = bloblist_add(dst->attachments, ctext, csize,
vb@311
   528
                "application/octet-stream", "PGPexch.htm.pgp");
vb@284
   529
            if (_a == NULL)
vb@260
   530
                goto enomem;
vb@284
   531
            if (dst->attachments == NULL)
vb@284
   532
                dst->attachments = _a;
vb@260
   533
        }
vb@260
   534
        else {
vb@260
   535
            goto pep_error;
vb@260
   536
        }
vb@260
   537
    }
vb@260
   538
vb@260
   539
    if (src->attachments) {
vb@284
   540
        if (dst->attachments == NULL) {
vb@284
   541
            dst->attachments = new_bloblist(NULL, 0, NULL, NULL);
vb@284
   542
            if (dst->attachments == NULL)
vb@284
   543
                goto enomem;
vb@284
   544
        }
vb@260
   545
vb@284
   546
        bloblist_t *_s = src->attachments;
vb@284
   547
        bloblist_t *_d = dst->attachments;
vb@284
   548
Edouard@754
   549
        for (int n = 0; _s; _s = _s->next) {
Edouard@754
   550
            if (_s->value == NULL && _s->size == 0) {
Edouard@754
   551
                _d = bloblist_add(_d, NULL, 0, _s->mime_type, _s->filename);
vb@260
   552
                if (_d == NULL)
vb@260
   553
                    goto enomem;
vb@260
   554
            }
vb@260
   555
            else {
Edouard@754
   556
                size_t psize = _s->size;
Edouard@754
   557
                ptext = _s->value;
krista@1639
   558
                if (nosign)
krista@1639
   559
                    status = encrypt_only(session, keys, ptext, psize, &ctext,
krista@1639
   560
                        &csize);
krista@1639
   561
                else 
krista@1639
   562
                    status = encrypt_and_sign(session, keys, ptext, psize, &ctext,
krista@1639
   563
                        &csize);
Edouard@754
   564
                if (ctext) {
Edouard@754
   565
                    char *filename = NULL;
Edouard@754
   566
Edouard@754
   567
                    if (_s->filename) {
Edouard@754
   568
                        size_t len = strlen(_s->filename);
krista@975
   569
                        size_t bufsize = len + 5; // length of .pgp extension + NUL
krista@975
   570
                        filename = calloc(1, bufsize);
Edouard@754
   571
                        if (filename == NULL)
Edouard@754
   572
                            goto enomem;
Edouard@754
   573
krista@975
   574
                        strlcpy(filename, _s->filename, bufsize);
krista@975
   575
                        strlcat(filename, ".pgp", bufsize);
Edouard@754
   576
                    }
Edouard@754
   577
                    else {
Edouard@754
   578
                        filename = calloc(1, 20);
Edouard@754
   579
                        if (filename == NULL)
Edouard@754
   580
                            goto enomem;
Edouard@754
   581
Edouard@754
   582
                        ++n;
Edouard@754
   583
                        n &= 0xffff;
Edouard@754
   584
                        snprintf(filename, 20, "Attachment%d.pgp", n);
Edouard@754
   585
                    }
Edouard@754
   586
Edouard@882
   587
                    _d = bloblist_add(_d, ctext, csize, "application/octet-stream",
Edouard@754
   588
                        filename);
roker@866
   589
                    free(filename);
Edouard@754
   590
                    if (_d == NULL)
Edouard@754
   591
                        goto enomem;
Edouard@754
   592
                }
Edouard@754
   593
                else {
Edouard@754
   594
                    goto pep_error;
Edouard@754
   595
                }
vb@260
   596
            }
vb@260
   597
        }
vb@260
   598
    }
vb@260
   599
vb@260
   600
    return PEP_STATUS_OK;
vb@260
   601
vb@260
   602
enomem:
vb@260
   603
    status = PEP_OUT_OF_MEMORY;
vb@260
   604
vb@260
   605
pep_error:
vb@466
   606
    if (free_ptext)
vb@466
   607
        free(ptext);
vb@260
   608
    return status;
vb@260
   609
}
vb@260
   610
vb@311
   611
static char * keylist_to_string(const stringlist_t *keylist)
vb@311
   612
{
vb@311
   613
    if (keylist) {
vb@311
   614
        size_t size = stringlist_length(keylist);
vb@311
   615
vb@311
   616
        const stringlist_t *_kl;
vb@311
   617
        for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
vb@311
   618
            size += strlen(_kl->value);
vb@311
   619
        }
vb@311
   620
vb@311
   621
        char *result = calloc(1, size);
vb@311
   622
        if (result == NULL)
vb@311
   623
            return NULL;
vb@311
   624
vb@311
   625
        char *_r = result;
vb@311
   626
        for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
vb@311
   627
            _r = stpcpy(_r, _kl->value);
vb@311
   628
            if (_kl->next && _kl->next->value)
vb@311
   629
                _r = stpcpy(_r, ",");
vb@311
   630
        }
vb@311
   631
vb@311
   632
        return result;
vb@311
   633
    }
vb@311
   634
    else {
vb@311
   635
        return NULL;
vb@311
   636
    }
vb@311
   637
}
vb@311
   638
vb@1004
   639
static const char * rating_to_string(PEP_rating rating)
vb@311
   640
{
vb@1004
   641
    switch (rating) {
vb@311
   642
    case PEP_rating_cannot_decrypt:
vb@311
   643
        return "cannot_decrypt";
vb@311
   644
    case PEP_rating_have_no_key:
vb@311
   645
        return "have_no_key";
vb@311
   646
    case PEP_rating_unencrypted:
vb@311
   647
        return "unencrypted";
vb@486
   648
    case PEP_rating_unencrypted_for_some:
vb@486
   649
        return "unencrypted_for_some";
vb@311
   650
    case PEP_rating_unreliable:
vb@311
   651
        return "unreliable";
vb@311
   652
    case PEP_rating_reliable:
vb@311
   653
        return "reliable";
vb@311
   654
    case PEP_rating_trusted:
vb@311
   655
        return "trusted";
vb@311
   656
    case PEP_rating_trusted_and_anonymized:
vb@311
   657
        return "trusted_and_anonymized";
vb@311
   658
    case PEP_rating_fully_anonymous:
vb@311
   659
        return "fully_anonymous";
Edouard@442
   660
    case PEP_rating_mistrust:
Edouard@442
   661
        return "mistrust";
Edouard@442
   662
    case PEP_rating_b0rken:
Edouard@442
   663
        return "b0rken";
vb@311
   664
    case PEP_rating_under_attack:
krista@961
   665
        return "under_attack";
vb@311
   666
    default:
vb@311
   667
        return "undefined";
vb@311
   668
    }
vb@311
   669
}
vb@311
   670
vb@311
   671
static void decorate_message(
vb@311
   672
    message *msg,
vb@1004
   673
    PEP_rating rating,
vb@311
   674
    stringlist_t *keylist
vb@311
   675
    )
vb@311
   676
{
vb@311
   677
    assert(msg);
vb@311
   678
krista@942
   679
    add_opt_field(msg, "X-pEp-Version", PEP_VERSION);
krista@1427
   680
vb@1004
   681
    if (rating != PEP_rating_undefined)
vb@1004
   682
        add_opt_field(msg, "X-EncStatus", rating_to_string(rating));
vb@311
   683
vb@311
   684
    if (keylist) {
vb@311
   685
        char *_keylist = keylist_to_string(keylist);
vb@311
   686
        add_opt_field(msg, "X-KeyList", _keylist);
vb@311
   687
        free(_keylist);
vb@311
   688
    }
vb@311
   689
}
vb@311
   690
vb@1004
   691
static PEP_rating _rating(PEP_comm_type ct, PEP_rating rating)
vb@311
   692
{
vb@311
   693
    if (ct == PEP_ct_unknown)
vb@311
   694
        return PEP_rating_undefined;
krista@1427
   695
krista@1243
   696
    else if (ct == PEP_ct_key_not_found)
krista@1243
   697
        return PEP_rating_have_no_key;
krista@1427
   698
vb@311
   699
    else if (ct == PEP_ct_compromized)
vb@311
   700
        return PEP_rating_under_attack;
vb@311
   701
Edouard@442
   702
    else if (ct == PEP_ct_mistrusted)
Edouard@442
   703
        return PEP_rating_mistrust;
krista@1427
   704
vb@1004
   705
    if (rating == PEP_rating_unencrypted_for_some)
vb@486
   706
        return PEP_rating_unencrypted_for_some;
vb@486
   707
vb@486
   708
    if (ct == PEP_ct_no_encryption || ct == PEP_ct_no_encrypted_channel ||
vb@486
   709
            ct == PEP_ct_my_key_not_included) {
vb@1004
   710
        if (rating > PEP_rating_unencrypted_for_some)
vb@486
   711
            return PEP_rating_unencrypted_for_some;
vb@486
   712
        else
vb@486
   713
            return PEP_rating_unencrypted;
vb@486
   714
    }
vb@486
   715
vb@1004
   716
    if (rating == PEP_rating_unencrypted)
vb@486
   717
        return PEP_rating_unencrypted_for_some;
vb@486
   718
vb@486
   719
    if (ct >= PEP_ct_confirmed_enc_anon)
vb@311
   720
        return PEP_rating_trusted_and_anonymized;
vb@311
   721
vb@311
   722
    else if (ct >= PEP_ct_strong_encryption)
vb@311
   723
        return PEP_rating_trusted;
vb@311
   724
vb@311
   725
    else if (ct >= PEP_ct_strong_but_unconfirmed && ct < PEP_ct_confirmed)
vb@311
   726
        return PEP_rating_reliable;
vb@311
   727
vb@311
   728
    else
vb@311
   729
        return PEP_rating_unreliable;
vb@311
   730
}
vb@311
   731
vb@311
   732
static bool is_encrypted_attachment(const bloblist_t *blob)
vb@311
   733
{
vb@311
   734
    assert(blob);
vb@311
   735
krista@853
   736
    if (blob == NULL || blob->filename == NULL)
vb@311
   737
        return false;
krista@1427
   738
roker@1559
   739
    char *ext = strrchr(blob->filename, '.');
vb@311
   740
    if (ext == NULL)
vb@311
   741
        return false;
vb@311
   742
vb@320
   743
    if (strcmp(blob->mime_type, "application/octet-stream") == 0) {
vb@311
   744
        if (strcmp(ext, ".pgp") == 0 || strcmp(ext, ".gpg") == 0 ||
vb@311
   745
            strcmp(ext, ".asc") == 0)
vb@311
   746
            return true;
vb@311
   747
    }
vb@320
   748
    else if (strcmp(blob->mime_type, "text/plain") == 0) {
vb@311
   749
        if (strcmp(ext, ".asc") == 0)
vb@311
   750
            return true;
vb@311
   751
    }
vb@311
   752
vb@311
   753
    return false;
vb@311
   754
}
vb@311
   755
vb@311
   756
static bool is_encrypted_html_attachment(const bloblist_t *blob)
vb@311
   757
{
vb@311
   758
    assert(blob);
vb@311
   759
    assert(blob->filename);
krista@853
   760
    if (blob == NULL || blob->filename == NULL)
krista@853
   761
        return false;
vb@311
   762
vb@311
   763
    if (strncmp(blob->filename, "PGPexch.htm.", 12) == 0) {
vb@311
   764
        if (strcmp(blob->filename + 11, ".pgp") == 0 ||
vb@311
   765
            strcmp(blob->filename + 11, ".asc") == 0)
vb@311
   766
            return true;
vb@311
   767
    }
vb@311
   768
vb@311
   769
    return false;
vb@311
   770
}
vb@311
   771
vb@311
   772
static char * without_double_ending(const char *filename)
vb@311
   773
{
vb@311
   774
    assert(filename);
krista@853
   775
    if (filename == NULL)
krista@853
   776
        return NULL;
krista@1427
   777
roker@862
   778
    char *ext = strrchr(filename, '.');
vb@311
   779
    if (ext == NULL)
vb@311
   780
        return NULL;
vb@311
   781
vb@469
   782
    char *result = strndup(filename, ext - filename);
vb@469
   783
    assert(result);
vb@469
   784
    return result;
vb@311
   785
}
vb@311
   786
vb@1004
   787
static PEP_rating decrypt_rating(PEP_STATUS status)
vb@311
   788
{
vb@311
   789
    switch (status) {
vb@311
   790
    case PEP_UNENCRYPTED:
vb@311
   791
    case PEP_VERIFIED:
vb@311
   792
    case PEP_VERIFY_NO_KEY:
vb@311
   793
    case PEP_VERIFIED_AND_TRUSTED:
vb@311
   794
        return PEP_rating_unencrypted;
vb@311
   795
vb@311
   796
    case PEP_DECRYPTED:
krista@1748
   797
    case PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH:
vb@311
   798
        return PEP_rating_unreliable;
vb@311
   799
vb@311
   800
    case PEP_DECRYPTED_AND_VERIFIED:
vb@311
   801
        return PEP_rating_reliable;
vb@311
   802
vb@311
   803
    case PEP_DECRYPT_NO_KEY:
vb@311
   804
        return PEP_rating_have_no_key;
vb@311
   805
vb@311
   806
    case PEP_DECRYPT_WRONG_FORMAT:
vb@311
   807
    case PEP_CANNOT_DECRYPT_UNKNOWN:
vb@311
   808
        return PEP_rating_cannot_decrypt;
vb@311
   809
vb@311
   810
    default:
vb@311
   811
        return PEP_rating_undefined;
vb@311
   812
    }
vb@311
   813
}
vb@311
   814
vb@1004
   815
static PEP_rating key_rating(PEP_SESSION session, const char *fpr)
vb@311
   816
{
vb@311
   817
vb@311
   818
    assert(session);
vb@311
   819
    assert(fpr);
krista@1427
   820
krista@853
   821
    if (session == NULL || fpr == NULL)
krista@853
   822
        return PEP_rating_undefined;
vb@311
   823
edouard@1632
   824
edouard@1632
   825
    PEP_comm_type bare_comm_type = PEP_ct_unknown;
krista@1615
   826
    PEP_STATUS status = get_key_rating(session, fpr, &bare_comm_type);
vb@311
   827
    if (status != PEP_STATUS_OK)
vb@311
   828
        return PEP_rating_undefined;
vb@311
   829
krista@1615
   830
    PEP_comm_type least_trust_type = PEP_ct_unknown;
edouard@1632
   831
    least_trust(session, fpr, &least_trust_type);
edouard@1632
   832
edouard@1632
   833
    if (least_trust_type == PEP_ct_unknown) {
edouard@1632
   834
        return _rating(bare_comm_type, PEP_rating_undefined);
edouard@1632
   835
    } else {
edouard@1632
   836
        return _rating(least_trust_type, PEP_rating_undefined);
edouard@1632
   837
    }
vb@311
   838
}
vb@311
   839
krista@1579
   840
static PEP_rating worst_rating(PEP_rating rating1, PEP_rating rating2) {
krista@1579
   841
    return ((rating1 < rating2) ? rating1 : rating2);
krista@1579
   842
}
krista@1579
   843
vb@1004
   844
static PEP_rating keylist_rating(PEP_SESSION session, stringlist_t *keylist)
vb@311
   845
{
krista@1610
   846
    PEP_rating rating = PEP_rating_undefined;
vb@311
   847
vb@311
   848
    assert(keylist && keylist->value);
vb@311
   849
    if (keylist == NULL || keylist->value == NULL)
vb@486
   850
        return PEP_rating_undefined;
vb@311
   851
vb@311
   852
    stringlist_t *_kl;
krista@1610
   853
    bool first = true;
vb@311
   854
    for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
vb@311
   855
        PEP_comm_type ct;
vb@311
   856
        PEP_STATUS status;
vb@311
   857
vb@1004
   858
        PEP_rating _rating_ = key_rating(session, _kl->value);
krista@1579
   859
         
vb@1004
   860
        if (_rating_ <= PEP_rating_mistrust)
vb@1004
   861
            return _rating_;
krista@1610
   862
            
krista@1610
   863
        if (first) {
krista@1610
   864
            rating = _rating_;
krista@1610
   865
            first = false;
krista@1610
   866
        }
krista@1610
   867
        else if (rating == PEP_rating_undefined)
krista@1579
   868
            rating = worst_rating(rating, _rating_);
vb@486
   869
vb@1004
   870
        if (_rating_ >= PEP_rating_reliable) {
vb@311
   871
            status = least_trust(session, _kl->value, &ct);
vb@311
   872
            if (status != PEP_STATUS_OK)
vb@311
   873
                return PEP_rating_undefined;
edouard@1156
   874
            if (ct == PEP_ct_unknown){
krista@1615
   875
                /* per edouard, we reduce reliable+ ratings to reliable because
krista@1615
   876
                   ct unknown */
edouard@1156
   877
                if (rating >= PEP_rating_reliable){
krista@1615
   878
                    rating = PEP_rating_reliable; 
edouard@1156
   879
                }
edouard@1156
   880
            }
edouard@1156
   881
            else{
krista@1579
   882
                rating = worst_rating(rating, _rating(ct, rating));
edouard@1156
   883
            }
vb@486
   884
        }
vb@1004
   885
        else if (_rating_ == PEP_rating_unencrypted) {
vb@1004
   886
            if (rating > PEP_rating_unencrypted_for_some)
krista@1579
   887
                rating = worst_rating(rating, PEP_rating_unencrypted_for_some);
vb@311
   888
        }
vb@311
   889
    }
vb@311
   890
vb@1004
   891
    return rating;
vb@311
   892
}
vb@311
   893
vb@311
   894
static PEP_comm_type _get_comm_type(
vb@311
   895
    PEP_SESSION session,
vb@311
   896
    PEP_comm_type max_comm_type,
vb@311
   897
    pEp_identity *ident
vb@311
   898
    )
vb@311
   899
{
vb@311
   900
    PEP_STATUS status = update_identity(session, ident);
vb@311
   901
vb@311
   902
    if (max_comm_type == PEP_ct_compromized)
vb@311
   903
        return PEP_ct_compromized;
krista@1427
   904
Edouard@510
   905
    if (max_comm_type == PEP_ct_mistrusted)
Edouard@510
   906
        return PEP_ct_mistrusted;
vb@311
   907
vb@311
   908
    if (status == PEP_STATUS_OK) {
vb@311
   909
        if (ident->comm_type == PEP_ct_compromized)
vb@311
   910
            return PEP_ct_compromized;
Edouard@510
   911
        else if (ident->comm_type == PEP_ct_mistrusted)
Edouard@510
   912
            return PEP_ct_mistrusted;
vb@311
   913
        else
vb@951
   914
            return _MIN(max_comm_type, ident->comm_type);
vb@311
   915
    }
vb@311
   916
    else {
vb@311
   917
        return PEP_ct_unknown;
vb@311
   918
    }
vb@311
   919
}
vb@311
   920
vb@731
   921
static void free_bl_entry(bloblist_t *bl)
vb@731
   922
{
vb@731
   923
    if (bl) {
vb@731
   924
        free(bl->value);
vb@731
   925
        free(bl->mime_type);
vb@731
   926
        free(bl->filename);
vb@731
   927
        free(bl);
vb@731
   928
    }
vb@731
   929
}
vb@731
   930
vb@731
   931
static bool is_key(const bloblist_t *bl)
vb@731
   932
{
Edouard@728
   933
    return (// workaround for Apple Mail bugs
Edouard@728
   934
            (is_mime_type(bl, "application/x-apple-msg-attachment") &&
Edouard@728
   935
             is_fileending(bl, ".asc")) ||
Edouard@728
   936
            // as binary, by file name
Edouard@728
   937
            ((bl->mime_type == NULL ||
Edouard@728
   938
              is_mime_type(bl, "application/octet-stream")) &&
Edouard@728
   939
             (is_fileending(bl, ".pgp") || is_fileending(bl, ".gpg") ||
Edouard@728
   940
                    is_fileending(bl, ".key") || is_fileending(bl, ".asc"))) ||
krista@1427
   941
            // explicit mime type
Edouard@728
   942
            is_mime_type(bl, "application/pgp-keys") ||
Edouard@728
   943
            // as text, by file name
Edouard@728
   944
            (is_mime_type(bl, "text/plain") &&
Edouard@728
   945
             (is_fileending(bl, ".pgp") || is_fileending(bl, ".gpg") ||
Edouard@728
   946
                    is_fileending(bl, ".key") || is_fileending(bl, ".asc")))
Edouard@728
   947
           );
vb@731
   948
}
vb@731
   949
vb@731
   950
static void remove_attached_keys(message *msg)
vb@731
   951
{
vb@731
   952
    if (msg) {
vb@731
   953
        bloblist_t *last = NULL;
vb@731
   954
        for (bloblist_t *bl = msg->attachments; bl && bl->value; ) {
vb@731
   955
            bloblist_t *next = bl->next;
vb@731
   956
vb@731
   957
            if (is_key(bl)) {
vb@731
   958
                if (last) {
vb@731
   959
                    last->next = next;
vb@731
   960
                }
vb@731
   961
                else {
vb@731
   962
                    msg->attachments = next;
vb@731
   963
                }
vb@731
   964
                free_bl_entry(bl);
vb@731
   965
            }
vb@731
   966
            else {
vb@731
   967
                last = bl;
vb@731
   968
            }
vb@731
   969
            bl = next;
vb@731
   970
        }
vb@731
   971
    }
vb@731
   972
}
vb@731
   973
Edouard@734
   974
bool import_attached_keys(
krista@1427
   975
        PEP_SESSION session,
Edouard@728
   976
        const message *msg,
Edouard@728
   977
        identity_list **private_idents
Edouard@728
   978
    )
vb@311
   979
{
vb@311
   980
    assert(session);
vb@311
   981
    assert(msg);
krista@1427
   982
krista@853
   983
    if (session == NULL || msg == NULL)
krista@853
   984
        return false;
vb@311
   985
vb@731
   986
    bool remove = false;
vb@731
   987
vb@908
   988
    int i = 0;
roker@1559
   989
    for (bloblist_t *bl = msg->attachments; i < MAX_KEYS_TO_IMPORT && bl && bl->value;
krista@1427
   990
            bl = bl->next, i++)
Edouard@747
   991
    {
vb@908
   992
        if (bl && bl->value && bl->size && bl->size < MAX_KEY_SIZE
krista@1427
   993
                && is_key(bl))
Edouard@728
   994
        {
Edouard@728
   995
            import_key(session, bl->value, bl->size, private_idents);
vb@731
   996
            remove = true;
vb@311
   997
        }
vb@311
   998
    }
vb@731
   999
    return remove;
vb@311
  1000
}
vb@311
  1001
Edouard@694
  1002
Edouard@694
  1003
PEP_STATUS _attach_key(PEP_SESSION session, const char* fpr, message *msg)
vb@311
  1004
{
roker@1559
  1005
    char *keydata = NULL;
vb@311
  1006
    size_t size;
vb@311
  1007
Edouard@694
  1008
    PEP_STATUS status = export_key(session, fpr, &keydata, &size);
Edouard@694
  1009
    assert(status == PEP_STATUS_OK);
Edouard@694
  1010
    if (status != PEP_STATUS_OK)
Edouard@694
  1011
        return status;
Edouard@694
  1012
    assert(size);
krista@1427
  1013
roker@1559
  1014
     bloblist_t *bl = bloblist_add(msg->attachments, keydata, size, "application/pgp-keys",
Edouard@694
  1015
                      "pEpkey.asc");
krista@1427
  1016
Edouard@694
  1017
    if (msg->attachments == NULL && bl)
Edouard@694
  1018
        msg->attachments = bl;
Edouard@694
  1019
Edouard@694
  1020
    return PEP_STATUS_OK;
Edouard@694
  1021
}
Edouard@694
  1022
Edouard@694
  1023
#define ONE_WEEK (7*24*3600)
Edouard@694
  1024
Edouard@694
  1025
void attach_own_key(PEP_SESSION session, message *msg)
Edouard@694
  1026
{
vb@311
  1027
    assert(session);
vb@311
  1028
    assert(msg);
krista@1427
  1029
Edouard@558
  1030
    if (msg->dir == PEP_dir_incoming)
Edouard@558
  1031
        return;
Edouard@558
  1032
vb@311
  1033
    assert(msg->from && msg->from->fpr);
vb@311
  1034
    if (msg->from == NULL || msg->from->fpr == NULL)
vb@311
  1035
        return;
vb@311
  1036
Edouard@694
  1037
    if(_attach_key(session, msg->from->fpr, msg) != PEP_STATUS_OK)
vb@311
  1038
        return;
krista@1427
  1039
Edouard@694
  1040
    char *revoked_fpr = NULL;
Edouard@694
  1041
    uint64_t revocation_date = 0;
krista@1427
  1042
Edouard@694
  1043
    if(get_revoked(session, msg->from->fpr,
Edouard@694
  1044
                   &revoked_fpr, &revocation_date) == PEP_STATUS_OK &&
Edouard@694
  1045
       revoked_fpr != NULL)
Edouard@694
  1046
    {
Edouard@694
  1047
        time_t now = time(NULL);
krista@1427
  1048
Edouard@694
  1049
        if (now < (time_t)revocation_date + ONE_WEEK)
Edouard@694
  1050
        {
Edouard@694
  1051
            _attach_key(session, revoked_fpr, msg);
Edouard@694
  1052
        }
Edouard@694
  1053
    }
Edouard@694
  1054
    free(revoked_fpr);
vb@311
  1055
}
vb@311
  1056
vb@311
  1057
PEP_cryptotech determine_encryption_format(message *msg)
vb@311
  1058
{
vb@311
  1059
    assert(msg);
krista@1427
  1060
vb@311
  1061
    if (is_PGP_message_text(msg->longmsg)) {
vb@311
  1062
        msg->enc_format = PEP_enc_pieces;
vb@311
  1063
        return PEP_crypt_OpenPGP;
vb@311
  1064
    }
vb@311
  1065
    else if (msg->attachments && msg->attachments->next &&
vb@311
  1066
            is_mime_type(msg->attachments, "application/pgp-encrypted") &&
vb@311
  1067
            is_PGP_message_text(msg->attachments->next->value)
vb@311
  1068
        ) {
vb@311
  1069
        msg->enc_format = PEP_enc_PGP_MIME;
vb@311
  1070
        return PEP_crypt_OpenPGP;
vb@311
  1071
    }
edouard@1557
  1072
    else if (msg->attachments && msg->attachments->next &&
edouard@1557
  1073
            is_mime_type(msg->attachments->next, "application/pgp-encrypted") &&
edouard@1557
  1074
            is_PGP_message_text(msg->attachments->value)
edouard@1557
  1075
        ) {
edouard@1557
  1076
        msg->enc_format = PEP_enc_PGP_MIME_Outlook1;
edouard@1557
  1077
        return PEP_crypt_OpenPGP;
edouard@1557
  1078
    }
vb@311
  1079
    else {
vb@311
  1080
        msg->enc_format = PEP_enc_none;
vb@311
  1081
        return PEP_crypt_none;
vb@311
  1082
    }
vb@311
  1083
}
vb@311
  1084
vb@48
  1085
DYNAMIC_API PEP_STATUS encrypt_message(
vb@37
  1086
        PEP_SESSION session,
vb@113
  1087
        message *src,
vb@37
  1088
        stringlist_t * extra,
vb@38
  1089
        message **dst,
vb@939
  1090
        PEP_enc_format enc_format,
vb@939
  1091
        PEP_encrypt_flags_t flags
vb@37
  1092
    )
vb@37
  1093
{
vb@37
  1094
    PEP_STATUS status = PEP_STATUS_OK;
vb@63
  1095
    message * msg = NULL;
vb@63
  1096
    stringlist_t * keys = NULL;
vb@37
  1097
vb@37
  1098
    assert(session);
vb@37
  1099
    assert(src);
vb@37
  1100
    assert(dst);
Edouard@558
  1101
    assert(enc_format != PEP_enc_none);
vb@81
  1102
Edouard@558
  1103
    if (!(session && src && dst && enc_format != PEP_enc_none))
vb@191
  1104
        return PEP_ILLEGAL_VALUE;
vb@191
  1105
Edouard@550
  1106
    if (src->dir == PEP_dir_incoming)
Edouard@550
  1107
        return PEP_ILLEGAL_VALUE;
krista@1427
  1108
vb@259
  1109
    determine_encryption_format(src);
vb@260
  1110
    if (src->enc_format != PEP_enc_none)
vb@260
  1111
        return PEP_ILLEGAL_VALUE;
vb@259
  1112
vb@37
  1113
    *dst = NULL;
vb@67
  1114
vb@236
  1115
    status = myself(session, src->from);
vb@236
  1116
    if (status != PEP_STATUS_OK)
vb@236
  1117
        goto pep_error;
Edouard@558
  1118
vb@80
  1119
    keys = new_stringlist(src->from->fpr);
vb@63
  1120
    if (keys == NULL)
vb@63
  1121
        goto enomem;
vb@37
  1122
vb@39
  1123
    stringlist_t *_k = keys;
vb@39
  1124
vb@39
  1125
    if (extra) {
vb@39
  1126
        _k = stringlist_append(_k, extra);
vb@63
  1127
        if (_k == NULL)
vb@63
  1128
            goto enomem;
vb@37
  1129
    }
vb@39
  1130
vb@299
  1131
    bool dest_keys_found = true;
Edouard@510
  1132
    PEP_comm_type max_comm_type = PEP_ct_pEp;
vb@299
  1133
vb@37
  1134
    identity_list * _il;
krista@1427
  1135
Edouard@545
  1136
    if ((_il = src->bcc) && _il->ident)
Edouard@545
  1137
    {
Edouard@545
  1138
        // BCC limited support:
Edouard@545
  1139
        //     - App splits mails with BCC in multiple mails.
Edouard@545
  1140
        //     - Each email is encrypted separately
krista@1427
  1141
Edouard@789
  1142
        if(_il->next || (src->to && src->to->ident) || (src->cc && src->cc->ident))
Edouard@545
  1143
        {
Edouard@545
  1144
            // Only one Bcc with no other recipient allowed for now
Edouard@545
  1145
            return PEP_ILLEGAL_VALUE;
Edouard@545
  1146
        }
krista@1427
  1147
vb@299
  1148
        PEP_STATUS _status = update_identity(session, _il->ident);
vb@299
  1149
        if (_status != PEP_STATUS_OK) {
vb@299
  1150
            status = _status;
vb@63
  1151
            goto pep_error;
vb@299
  1152
        }
krista@1427
  1153
vb@299
  1154
        if (_il->ident->fpr && _il->ident->fpr[0]) {
vb@39
  1155
            _k = stringlist_add(_k, _il->ident->fpr);
vb@63
  1156
            if (_k == NULL)
vb@63
  1157
                goto enomem;
Edouard@510
  1158
            max_comm_type = _get_comm_type(session, max_comm_type,
Edouard@510
  1159
                                           _il->ident);
vb@37
  1160
        }
vb@299
  1161
        else {
vb@299
  1162
            dest_keys_found = false;
vb@37
  1163
            status = PEP_KEY_NOT_FOUND;
krista@1427
  1164
        }
vb@299
  1165
    }
Edouard@545
  1166
    else
Edouard@545
  1167
    {
Edouard@545
  1168
        for (_il = src->to; _il && _il->ident; _il = _il->next) {
Edouard@545
  1169
            PEP_STATUS _status = update_identity(session, _il->ident);
Edouard@545
  1170
            if (_status != PEP_STATUS_OK) {
Edouard@545
  1171
                status = _status;
Edouard@545
  1172
                goto pep_error;
Edouard@545
  1173
            }
vb@299
  1174
Edouard@545
  1175
            if (_il->ident->fpr && _il->ident->fpr[0]) {
Edouard@545
  1176
                _k = stringlist_add(_k, _il->ident->fpr);
Edouard@545
  1177
                if (_k == NULL)
Edouard@545
  1178
                    goto enomem;
Edouard@545
  1179
                max_comm_type = _get_comm_type(session, max_comm_type,
Edouard@545
  1180
                                               _il->ident);
Edouard@545
  1181
            }
Edouard@545
  1182
            else {
Edouard@545
  1183
                dest_keys_found = false;
Edouard@545
  1184
                status = PEP_KEY_NOT_FOUND;
Edouard@545
  1185
            }
vb@299
  1186
        }
vb@299
  1187
Edouard@545
  1188
        for (_il = src->cc; _il && _il->ident; _il = _il->next) {
Edouard@545
  1189
            PEP_STATUS _status = update_identity(session, _il->ident);
Edouard@545
  1190
            if (_status != PEP_STATUS_OK)
Edouard@545
  1191
            {
Edouard@545
  1192
                status = _status;
Edouard@545
  1193
                goto pep_error;
Edouard@545
  1194
            }
Edouard@545
  1195
Edouard@545
  1196
            if (_il->ident->fpr && _il->ident->fpr[0]) {
Edouard@545
  1197
                _k = stringlist_add(_k, _il->ident->fpr);
Edouard@545
  1198
                if (_k == NULL)
Edouard@545
  1199
                    goto enomem;
Edouard@545
  1200
                max_comm_type = _get_comm_type(session, max_comm_type,
Edouard@545
  1201
                                               _il->ident);
Edouard@545
  1202
            }
Edouard@545
  1203
            else {
Edouard@545
  1204
                dest_keys_found = false;
Edouard@545
  1205
                status = PEP_KEY_NOT_FOUND;
Edouard@545
  1206
            }
vb@299
  1207
        }
vb@37
  1208
    }
krista@1427
  1209
Edouard@510
  1210
    if (!dest_keys_found ||
krista@1640
  1211
        stringlist_length(keys)  == 0 ||
Edouard@510
  1212
        _rating(max_comm_type,
Edouard@510
  1213
                PEP_rating_undefined) < PEP_rating_reliable)
Edouard@510
  1214
    {
vb@301
  1215
        free_stringlist(keys);
krista@1640
  1216
        if (!session->passive_mode && !(flags & PEP_encrypt_flag_force_no_attached_key))
vb@465
  1217
            attach_own_key(session, src);
vb@301
  1218
        return PEP_UNENCRYPTED;
vb@301
  1219
    }
vb@301
  1220
    else {
vb@299
  1221
        msg = clone_to_empty_message(src);
vb@299
  1222
        if (msg == NULL)
vb@299
  1223
            goto enomem;
vb@299
  1224
krista@1640
  1225
        if (!(flags & PEP_encrypt_flag_force_no_attached_key))
krista@1640
  1226
            attach_own_key(session, src);
Edouard@428
  1227
vb@81
  1228
        switch (enc_format) {
vb@260
  1229
        case PEP_enc_PGP_MIME:
vb@336
  1230
        case PEP_enc_PEP: // BUG: should be implemented extra
krista@1639
  1231
            status = encrypt_PGP_MIME(session, src, keys, msg, flags);
vb@260
  1232
            break;
vb@62
  1233
vb@62
  1234
        case PEP_enc_pieces:
krista@1639
  1235
            status = encrypt_PGP_in_pieces(session, src, keys, msg, flags);
vb@38
  1236
            break;
vb@38
  1237
vb@336
  1238
        /* case PEP_enc_PEP:
vb@81
  1239
            // TODO: implement
vb@336
  1240
            NOT_IMPLEMENTED */
vb@81
  1241
vb@38
  1242
        default:
vb@38
  1243
            assert(0);
vb@63
  1244
            status = PEP_ILLEGAL_VALUE;
vb@63
  1245
            goto pep_error;
vb@37
  1246
        }
krista@1427
  1247
Edouard@392
  1248
        if (status == PEP_OUT_OF_MEMORY)
Edouard@392
  1249
            goto enomem;
krista@1427
  1250
vb@480
  1251
        if (status != PEP_STATUS_OK)
Edouard@392
  1252
            goto pep_error;
vb@37
  1253
    }
vb@37
  1254
vb@37
  1255
    free_stringlist(keys);
vb@63
  1256
vb@469
  1257
    if (msg && msg->shortmsg == NULL) {
vb@64
  1258
        msg->shortmsg = strdup("pEp");
vb@469
  1259
        assert(msg->shortmsg);
krista@853
  1260
        if (msg->shortmsg == NULL)
krista@853
  1261
            goto enomem;
vb@469
  1262
    }
vb@64
  1263
edouard@1542
  1264
    if (msg) {
vb@311
  1265
        decorate_message(msg, PEP_rating_undefined, NULL);
edouard@1542
  1266
        if (src->id) {
edouard@1542
  1267
            msg->id = strdup(src->id);
edouard@1542
  1268
            assert(msg->id);
edouard@1542
  1269
            if (msg->id == NULL)
edouard@1542
  1270
                goto enomem;
edouard@1542
  1271
        }
edouard@1542
  1272
    }
vb@311
  1273
vb@63
  1274
    *dst = msg;
vb@299
  1275
    return status;
vb@63
  1276
vb@63
  1277
enomem:
vb@63
  1278
    status = PEP_OUT_OF_MEMORY;
vb@63
  1279
vb@63
  1280
pep_error:
vb@63
  1281
    free_stringlist(keys);
vb@63
  1282
    free_message(msg);
vb@63
  1283
vb@37
  1284
    return status;
vb@37
  1285
}
vb@37
  1286
krista@995
  1287
DYNAMIC_API PEP_STATUS encrypt_message_for_self(
krista@992
  1288
        PEP_SESSION session,
krista@992
  1289
        pEp_identity* target_id,
krista@992
  1290
        message *src,
krista@992
  1291
        message **dst,
markus@1633
  1292
        PEP_enc_format enc_format,
markus@1633
  1293
        PEP_encrypt_flags_t flags
krista@992
  1294
    )
krista@992
  1295
{
krista@992
  1296
    PEP_STATUS status = PEP_STATUS_OK;
krista@992
  1297
    message * msg = NULL;
krista@992
  1298
    stringlist_t * keys = NULL;
krista@992
  1299
krista@992
  1300
    assert(session);
krista@992
  1301
    assert(src);
krista@992
  1302
    assert(dst);
krista@992
  1303
    assert(enc_format != PEP_enc_none);
krista@992
  1304
krista@992
  1305
    if (!(session && src && dst && enc_format != PEP_enc_none))
krista@992
  1306
        return PEP_ILLEGAL_VALUE;
krista@992
  1307
krista@992
  1308
    if (src->dir == PEP_dir_incoming)
krista@992
  1309
        return PEP_ILLEGAL_VALUE;
krista@1427
  1310
krista@992
  1311
    determine_encryption_format(src);
krista@992
  1312
    if (src->enc_format != PEP_enc_none)
krista@992
  1313
        return PEP_ILLEGAL_VALUE;
krista@992
  1314
krista@995
  1315
    status = myself(session, target_id);
krista@995
  1316
    if (status != PEP_STATUS_OK)
krista@995
  1317
        goto pep_error;
krista@995
  1318
krista@992
  1319
    *dst = NULL;
krista@992
  1320
krista@1427
  1321
krista@992
  1322
    PEP_STATUS _status = update_identity(session, target_id);
krista@992
  1323
    if (_status != PEP_STATUS_OK) {
krista@992
  1324
        status = _status;
krista@992
  1325
        goto pep_error;
krista@992
  1326
    }
krista@992
  1327
krista@994
  1328
    char* target_fpr = target_id->fpr;
krista@994
  1329
    if (!target_fpr)
krista@994
  1330
        return PEP_KEY_NOT_FOUND; // FIXME: Error condition
krista@1685
  1331
 
krista@994
  1332
    keys = new_stringlist(target_fpr);
krista@1685
  1333
    
krista@1640
  1334
    /* KG: did we ever do this??? */
krista@1640
  1335
    if (!(flags & PEP_encrypt_flag_force_no_attached_key))
krista@1685
  1336
        _attach_key(session, target_fpr, src);
krista@1427
  1337
krista@992
  1338
    msg = clone_to_empty_message(src);
krista@992
  1339
    if (msg == NULL)
krista@992
  1340
        goto enomem;
krista@992
  1341
krista@992
  1342
    switch (enc_format) {
krista@992
  1343
        case PEP_enc_PGP_MIME:
krista@992
  1344
        case PEP_enc_PEP: // BUG: should be implemented extra
krista@1639
  1345
            status = encrypt_PGP_MIME(session, src, keys, msg, flags);
krista@992
  1346
            break;
krista@992
  1347
krista@992
  1348
        case PEP_enc_pieces:
krista@1639
  1349
            status = encrypt_PGP_in_pieces(session, src, keys, msg, flags);
krista@992
  1350
            break;
krista@992
  1351
krista@992
  1352
        /* case PEP_enc_PEP:
krista@1641
  1353
            NOT_IMPLEMENTED */
krista@992
  1354
            // TODO: implement
krista@992
  1355
krista@992
  1356
        default:
krista@992
  1357
            assert(0);
krista@992
  1358
            status = PEP_ILLEGAL_VALUE;
krista@992
  1359
            goto pep_error;
krista@992
  1360
    }
krista@1427
  1361
krista@992
  1362
    if (status == PEP_OUT_OF_MEMORY)
krista@992
  1363
        goto enomem;
krista@1427
  1364
krista@992
  1365
    if (status != PEP_STATUS_OK)
krista@992
  1366
        goto pep_error;
krista@992
  1367
krista@994
  1368
     if (msg && msg->shortmsg == NULL) {
krista@994
  1369
         msg->shortmsg = strdup("pEp");
krista@994
  1370
         assert(msg->shortmsg);
krista@994
  1371
         if (msg->shortmsg == NULL)
krista@994
  1372
             goto enomem;
krista@994
  1373
     }
krista@992
  1374
edouard@1542
  1375
     if (msg) {
edouard@1542
  1376
         if (src->id) {
edouard@1542
  1377
             msg->id = strdup(src->id);
edouard@1542
  1378
             assert(msg->id);
edouard@1542
  1379
             if (msg->id == NULL)
edouard@1542
  1380
                 goto enomem;
edouard@1542
  1381
         }
edouard@1542
  1382
     }
edouard@1542
  1383
krista@992
  1384
    *dst = msg;
krista@992
  1385
    return status;
krista@992
  1386
krista@992
  1387
enomem:
krista@992
  1388
    status = PEP_OUT_OF_MEMORY;
krista@992
  1389
krista@992
  1390
pep_error:
krista@992
  1391
    free_stringlist(keys);
krista@992
  1392
    free_message(msg);
krista@992
  1393
krista@992
  1394
    return status;
krista@992
  1395
}
krista@992
  1396
vb@781
  1397
static bool is_a_pEpmessage(const message *msg)
vb@781
  1398
{
vb@781
  1399
    for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
vb@781
  1400
        if (strcasecmp(i->value->key, "X-pEp-Version") == 0)
vb@781
  1401
            return true;
vb@781
  1402
    }
vb@781
  1403
    return false;
vb@781
  1404
}
vb@781
  1405
vb@781
  1406
// update comm_type to pEp_ct_pEp if needed
vb@781
  1407
Edouard@858
  1408
static PEP_STATUS _update_identity_for_incoming_message(
vb@781
  1409
        PEP_SESSION session,
vb@781
  1410
        const message *src
vb@781
  1411
    )
vb@781
  1412
{
Edouard@858
  1413
    PEP_STATUS status;
Edouard@858
  1414
    if (src->from && src->from->address) {
Edouard@858
  1415
        status = update_identity(session, src->from);
krista@1192
  1416
        if (status == PEP_STATUS_OK
Edouard@858
  1417
                && is_a_pEpmessage(src)
vb@781
  1418
                && src->from->comm_type >= PEP_ct_OpenPGP_unconfirmed
vb@781
  1419
                && src->from->comm_type != PEP_ct_pEp_unconfirmed
vb@781
  1420
                && src->from->comm_type != PEP_ct_pEp)
vb@781
  1421
        {
vb@781
  1422
            src->from->comm_type |= PEP_ct_pEp_unconfirmed;
Edouard@858
  1423
            status = update_identity(session, src->from);
vb@781
  1424
        }
Edouard@858
  1425
        return status;
vb@781
  1426
    }
Edouard@858
  1427
    return PEP_ILLEGAL_VALUE;
vb@781
  1428
}
vb@781
  1429
krista@1397
  1430
krista@1397
  1431
PEP_STATUS _get_detached_signature(message* msg, bloblist_t** signature_blob) {
krista@1397
  1432
    bloblist_t* attach_curr = msg->attachments;
krista@1427
  1433
krista@1427
  1434
    *signature_blob = NULL;
krista@1427
  1435
krista@1397
  1436
    while (attach_curr) {
krista@1427
  1437
        if (strcasecmp(attach_curr->mime_type, "application/pgp-signature") == 0) {
krista@1397
  1438
            *signature_blob = attach_curr;
krista@1397
  1439
            break;
krista@1397
  1440
        }
krista@1397
  1441
        attach_curr = attach_curr->next;
krista@1397
  1442
    }
krista@1427
  1443
krista@1427
  1444
    return PEP_STATUS_OK;
krista@1427
  1445
}
krista@1427
  1446
krista@1427
  1447
PEP_STATUS _get_signed_text(const char* ptext, const size_t psize,
krista@1427
  1448
                            char** stext, size_t* ssize) {
krista@1427
  1449
krista@1427
  1450
    char* signed_boundary = NULL;
krista@1427
  1451
    char* signpost = strstr(ptext, "Content-Type: multipart/signed");
krista@1427
  1452
krista@1427
  1453
    *ssize = 0;
krista@1427
  1454
    *stext = NULL;
krista@1427
  1455
krista@1427
  1456
    if (!signpost)
krista@1427
  1457
        return PEP_UNKNOWN_ERROR;
krista@1427
  1458
krista@1427
  1459
    char* curr_line = signpost;
krista@1427
  1460
//    const char* end_text = ptext + psize;
krista@1755
  1461
    const char* boundary_key = "boundary=";
krista@1755
  1462
    const size_t BOUNDARY_KEY_SIZE = 9;
krista@1427
  1463
krista@1427
  1464
    char* start_boundary = strstr(curr_line, boundary_key);
krista@1427
  1465
    if (!start_boundary)
krista@1427
  1466
        return PEP_UNKNOWN_ERROR;
krista@1427
  1467
krista@1427
  1468
    start_boundary += BOUNDARY_KEY_SIZE;
krista@1427
  1469
krista@1755
  1470
    bool quoted = (*start_boundary == '"');
krista@1755
  1471
krista@1755
  1472
    if (quoted)
krista@1755
  1473
        start_boundary++;
krista@1755
  1474
        
krista@1755
  1475
    char* end_boundary = (quoted ? strstr(start_boundary, "\"") : strstr(start_boundary, ";")); // FIXME: third possiblity is CRLF, or?
krista@1427
  1476
krista@1427
  1477
    if (!end_boundary)
krista@1427
  1478
        return PEP_UNKNOWN_ERROR;
krista@1427
  1479
krista@1755
  1480
    // Add space for the "--"
krista@1427
  1481
    size_t boundary_strlen = (end_boundary - start_boundary) + 2;
krista@1427
  1482
krista@1427
  1483
    signed_boundary = calloc(1, boundary_strlen + 1);
krista@1427
  1484
    strlcpy(signed_boundary, "--", boundary_strlen + 1);
krista@1427
  1485
    strlcat(signed_boundary, start_boundary, boundary_strlen + 1);
krista@1427
  1486
krista@1427
  1487
    start_boundary = strstr(end_boundary, signed_boundary);
krista@1427
  1488
krista@1427
  1489
    if (!start_boundary)
krista@1427
  1490
        return PEP_UNKNOWN_ERROR;
krista@1427
  1491
krista@1427
  1492
    start_boundary += boundary_strlen;
krista@1427
  1493
krista@1756
  1494
    if (*start_boundary == '\r') {
krista@1756
  1495
        if (*(start_boundary + 1) == '\n')
krista@1756
  1496
            start_boundary += 2;
krista@1756
  1497
    }
krista@1756
  1498
    else if (*start_boundary == '\n')
krista@1427
  1499
        start_boundary++;
krista@1427
  1500
krista@1427
  1501
    end_boundary = strstr(start_boundary + boundary_strlen, signed_boundary);
krista@1427
  1502
krista@1427
  1503
    if (!end_boundary)
krista@1427
  1504
        return PEP_UNKNOWN_ERROR;
krista@1427
  1505
krista@1893
  1506
    end_boundary--; // See RFC3156 section 5...
krista@1893
  1507
	if (*(end_boundary - 1) == '\r')
krista@1893
  1508
		end_boundary--;
krista@1427
  1509
krista@1427
  1510
    *ssize = end_boundary - start_boundary;
krista@1427
  1511
    *stext = start_boundary;
krista@1427
  1512
    free(signed_boundary);
krista@1427
  1513
krista@1397
  1514
    return PEP_STATUS_OK;
krista@1397
  1515
}
krista@1397
  1516
krista@1484
  1517
PEP_STATUS combine_keylists(PEP_SESSION session, stringlist_t** verify_in, 
krista@1484
  1518
                            stringlist_t** keylist_in_out, 
krista@1484
  1519
                            pEp_identity* from) {
krista@1484
  1520
    
krista@1484
  1521
    if (!verify_in || !(*verify_in)) // this isn't really a problem.
krista@1484
  1522
        return PEP_STATUS_OK;
krista@1484
  1523
    
krista@1484
  1524
    stringlist_t* orig_verify = *verify_in;
krista@1484
  1525
    
roker@1559
  1526
    stringlist_t* verify_curr = NULL;
roker@1559
  1527
    stringlist_t* from_keys = NULL;
krista@1484
  1528
    
krista@1484
  1529
    /* FIXME: what to do if head needs to be null */
krista@1484
  1530
    PEP_STATUS status = find_keys(session, from->address, &from_keys);
krista@1484
  1531
    
krista@1484
  1532
    stringlist_t* from_fpr_node = NULL;
krista@1484
  1533
    stringlist_t* from_curr;
krista@1484
  1534
    
krista@1484
  1535
    for (from_curr = from_keys; from_curr; from_curr = from_curr->next) {
krista@1484
  1536
        for (verify_curr = orig_verify; verify_curr; verify_curr = verify_curr->next) {
krista@1484
  1537
            if (from_curr->value && verify_curr->value &&
edouard@1573
  1538
                _same_fpr(from_curr->value, strlen(from_curr->value),
edouard@1573
  1539
                          verify_curr->value, strlen(verify_curr->value))) {
krista@1484
  1540
                from_fpr_node = from_curr;
krista@1484
  1541
                break;
krista@1484
  1542
            }
krista@1484
  1543
        }
krista@1484
  1544
    }
krista@1484
  1545
    
krista@1484
  1546
    if (!from_fpr_node) {
krista@1484
  1547
        status = PEP_KEY_NOT_FOUND;
krista@1484
  1548
        goto free;
krista@1484
  1549
    }
krista@1484
  1550
krista@1484
  1551
    verify_curr = orig_verify;
krista@1484
  1552
    
krista@1484
  1553
    /* put "from" signer at the beginning of the list */
edouard@1573
  1554
    if (!_same_fpr(orig_verify->value, strlen(orig_verify->value),
edouard@1573
  1555
                   from_fpr_node->value, strlen(from_fpr_node->value))) {
krista@1484
  1556
        orig_verify = stringlist_delete(orig_verify, from_fpr_node->value);
krista@1484
  1557
        verify_curr = new_stringlist(from_fpr_node->value);
krista@1484
  1558
        verify_curr->next = orig_verify;
krista@1484
  1559
    }
krista@1484
  1560
krista@1484
  1561
    /* append keylist to signers */
krista@1484
  1562
    if (keylist_in_out && *keylist_in_out && (*keylist_in_out)->value) {
krista@1484
  1563
        stringlist_t** tail_pp = &verify_curr->next;
krista@1484
  1564
        
krista@1484
  1565
        while (*tail_pp) {
krista@1484
  1566
            tail_pp = &((*tail_pp)->next);
krista@1484
  1567
        }
krista@1615
  1568
        stringlist_t* second_list = *keylist_in_out;
krista@1615
  1569
        if (second_list) {
krista@1615
  1570
            char* listhead_val = second_list->value;
krista@1615
  1571
            if (!listhead_val || listhead_val[0] == '\0') {
krista@1615
  1572
                /* remove head, basically. This can happen when,
krista@1615
  1573
                   for example, the signature is detached and
krista@1615
  1574
                   verification is not seen directly after
krista@1615
  1575
                   decryption, so no signer is presumed in
krista@1615
  1576
                   the first construction of the keylist */
krista@1615
  1577
                *keylist_in_out = (*keylist_in_out)->next;
krista@1615
  1578
                second_list->next = NULL;
krista@1615
  1579
                free_stringlist(second_list);
krista@1615
  1580
            }
krista@1615
  1581
        }
krista@1484
  1582
        *tail_pp = *keylist_in_out;
krista@1484
  1583
    }
krista@1484
  1584
    
krista@1484
  1585
    *keylist_in_out = verify_curr;
krista@1484
  1586
    
krista@1484
  1587
    status = PEP_STATUS_OK;
krista@1484
  1588
    
krista@1484
  1589
free:
krista@1484
  1590
    free_stringlist(from_keys);
roker@1559
  1591
    return status;
krista@1484
  1592
}
krista@1484
  1593
krista@1484
  1594
Edouard@741
  1595
DYNAMIC_API PEP_STATUS _decrypt_message(
vb@37
  1596
        PEP_SESSION session,
vb@113
  1597
        message *src,
vb@241
  1598
        message **dst,
vb@251
  1599
        stringlist_t **keylist,
vb@1004
  1600
        PEP_rating *rating,
krista@1427
  1601
        PEP_decrypt_flags_t *flags,
Edouard@741
  1602
        identity_list **private_il
vb@37
  1603
    )
vb@37
  1604
{
vb@37
  1605
    PEP_STATUS status = PEP_STATUS_OK;
vb@261
  1606
    PEP_STATUS decrypt_status = PEP_CANNOT_DECRYPT_UNKNOWN;
vb@73
  1607
    message *msg = NULL;
vb@112
  1608
    char *ctext;
vb@112
  1609
    size_t csize;
vb@269
  1610
    char *ptext = NULL;
vb@112
  1611
    size_t psize;
vb@241
  1612
    stringlist_t *_keylist = NULL;
vb@37
  1613
vb@74
  1614
    assert(session);
vb@74
  1615
    assert(src);
vb@74
  1616
    assert(dst);
vb@241
  1617
    assert(keylist);
vb@1004
  1618
    assert(rating);
Edouard@739
  1619
    assert(flags);
vb@73
  1620
vb@1004
  1621
    if (!(session && src && dst && keylist && rating && flags))
vb@191
  1622
        return PEP_ILLEGAL_VALUE;
vb@191
  1623
Edouard@739
  1624
    *flags = 0;
Edouard@739
  1625
Edouard@734
  1626
    // Private key in unencrypted mail are ignored -> NULL
Edouard@734
  1627
    bool imported_keys = import_attached_keys(session, src, NULL);
Edouard@728
  1628
Edouard@728
  1629
    // Update src->from in case we just imported a key
Edouard@728
  1630
    // we would need to check signature
Edouard@858
  1631
    status = _update_identity_for_incoming_message(session, src);
Edouard@858
  1632
    if(status != PEP_STATUS_OK)
Edouard@858
  1633
        return status;
Edouard@858
  1634
krista@1397
  1635
    // Get detached signature, if any
krista@1397
  1636
    bloblist_t* detached_sig = NULL;
krista@1397
  1637
    char* dsig_text = NULL;
krista@1397
  1638
    size_t dsig_size = 0;
krista@1397
  1639
    status = _get_detached_signature(src, &detached_sig);
krista@1397
  1640
    if (detached_sig) {
krista@1397
  1641
        dsig_text = detached_sig->value;
krista@1397
  1642
        dsig_size = detached_sig->size;
krista@1397
  1643
    }
krista@1427
  1644
vb@259
  1645
    PEP_cryptotech crypto = determine_encryption_format(src);
vb@259
  1646
vb@74
  1647
    *dst = NULL;
vb@251
  1648
    *keylist = NULL;
vb@1004
  1649
    *rating = PEP_rating_undefined;
krista@1427
  1650
vb@261
  1651
    switch (src->enc_format) {
vb@269
  1652
        case PEP_enc_none:
vb@1004
  1653
            *rating = PEP_rating_unencrypted;
vb@731
  1654
            if (imported_keys)
vb@731
  1655
                remove_attached_keys(src);
edouard@1603
  1656
            if(session->sync_session->inject_sync_msg){
edouard@1165
  1657
                status = receive_DeviceState_msg(session, src, *rating, *keylist);
krista@1427
  1658
                if (status == PEP_MESSAGE_CONSUME ||
edouard@1369
  1659
                    status == PEP_MESSAGE_IGNORE) {
vb@1134
  1660
                    free_message(msg);
vb@1134
  1661
                    msg = NULL;
edouard@1369
  1662
                    *flags |= (status == PEP_MESSAGE_IGNORE) ?
edouard@1369
  1663
                                PEP_decrypt_flag_ignore :
edouard@1369
  1664
                                PEP_decrypt_flag_consume;
vb@1134
  1665
                }
vb@1134
  1666
                else if (status != PEP_STATUS_OK) {
vb@1134
  1667
                    return status;
vb@1134
  1668
                }
vb@1099
  1669
            }
krista@1484
  1670
            
krista@1484
  1671
            char* slong = src->longmsg;
krista@1484
  1672
            char* sform = src->longmsg_formatted;
krista@1484
  1673
            bloblist_t* satt = src->attachments;
roker@1563
  1674
            
krista@1484
  1675
            if ((!slong || slong[0] == '\0')
krista@1484
  1676
                 && (!sform || sform[0] == '\0')) {
krista@1484
  1677
                if (satt) {
krista@1484
  1678
                    const char* inner_mime_type = satt->mime_type;
krista@1484
  1679
                    if (strcasecmp(inner_mime_type, "text/plain") == 0) {
krista@1484
  1680
                        free(slong); /* in case of "" */
roker@1563
  1681
                        src->longmsg = strndup(satt->value, satt->size); // N.B.: longmsg might be shorter, if attachment contains NUL bytes which are not allowed in text/plain!
roker@1563
  1682
                        
krista@1484
  1683
                        bloblist_t* next_node = satt->next;
krista@1484
  1684
                        if (next_node) {
krista@1484
  1685
                            inner_mime_type = next_node->mime_type;
krista@1484
  1686
                            if (strcasecmp(inner_mime_type, "text/html") == 0) {
krista@1484
  1687
                                free(sform);
roker@1563
  1688
                                src->longmsg_formatted = strndup(next_node->value, next_node->size);  // N.B.: longmsg might be shorter, if attachment contains NUL bytes which are not allowed in text/plain!
krista@1484
  1689
                            }
krista@1484
  1690
                        }
krista@1484
  1691
                    }
krista@1484
  1692
                    else if (strcasecmp(inner_mime_type, "text/html") == 0) {
krista@1484
  1693
                        free(sform);
roker@1563
  1694
                        src->longmsg_formatted = strndup(satt->value, satt->size);  // N.B.: longmsg might be shorter, if attachment contains NUL bytes which are not allowed in text/plain!
roker@1563
  1695
                    }
krista@1484
  1696
                }
roker@1563
  1697
            }
krista@1484
  1698
            
vb@301
  1699
            return PEP_UNENCRYPTED;
vb@269
  1700
vb@261
  1701
        case PEP_enc_PGP_MIME:
vb@301
  1702
            ctext = src->attachments->next->value;
vb@269
  1703
            csize = src->attachments->next->size;
vb@261
  1704
            break;
vb@261
  1705
edouard@1557
  1706
        case PEP_enc_PGP_MIME_Outlook1:
edouard@1557
  1707
            ctext = src->attachments->value;
edouard@1557
  1708
            csize = src->attachments->size;
edouard@1557
  1709
            break;
edouard@1557
  1710
vb@261
  1711
        case PEP_enc_pieces:
vb@261
  1712
            ctext = src->longmsg;
vb@261
  1713
            csize = strlen(ctext);
vb@261
  1714
            break;
vb@261
  1715
vb@261
  1716
        default:
vb@261
  1717
            NOT_IMPLEMENTED
vb@259
  1718
    }
Edouard@431
  1719
    status = cryptotech[crypto].decrypt_and_verify(session, ctext,
krista@1427
  1720
                                                   csize, dsig_text, dsig_size,
krista@1397
  1721
                                                   &ptext, &psize, &_keylist);
edouard@1195
  1722
    if (status > PEP_CANNOT_DECRYPT_UNKNOWN){
edouard@1271
  1723
        goto pep_error;
edouard@1271
  1724
    }
edouard@1271
  1725
edouard@1273
  1726
    decrypt_status = status;
edouard@1273
  1727
edouard@1271
  1728
    if (status == PEP_DECRYPT_NO_KEY){
edouard@1299
  1729
        PEP_STATUS sync_status = inject_DeviceState_event(session, CannotDecrypt, NULL, NULL);
edouard@1299
  1730
        if (sync_status == PEP_OUT_OF_MEMORY){
edouard@1299
  1731
            status = PEP_OUT_OF_MEMORY;
edouard@1273
  1732
            goto pep_error;
edouard@1299
  1733
        }
edouard@1195
  1734
    }
vb@113
  1735
krista@1427
  1736
    bool imported_private_key_address = false;
Edouard@728
  1737
vb@256
  1738
    if (ptext) {
vb@256
  1739
        switch (src->enc_format) {
vb@256
  1740
            case PEP_enc_PGP_MIME:
edouard@1557
  1741
            case PEP_enc_PGP_MIME_Outlook1:
vb@269
  1742
                status = mime_decode_message(ptext, psize, &msg);
vb@113
  1743
                if (status != PEP_STATUS_OK)
roker@1563
  1744
                    goto pep_error;
krista@1484
  1745
                
krista@1484
  1746
                char* mlong = msg->longmsg;
krista@1484
  1747
                char* mform = msg->longmsg_formatted;
krista@1484
  1748
                bloblist_t* matt = msg->attachments;
roker@1563
  1749
                
krista@1484
  1750
                if ((!mlong || mlong[0] == '\0')
krista@1484
  1751
                     && (!mform || mform[0] == '\0')) {
krista@1484
  1752
                    if (matt) {
krista@1484
  1753
                        const char* inner_mime_type = matt->mime_type;
krista@1484
  1754
                        if (strcasecmp(inner_mime_type, "text/plain") == 0) {
krista@1484
  1755
                            free(mlong); /* in case of "" */
roker@1563
  1756
                            msg->longmsg = strndup(matt->value, matt->size);
roker@1563
  1757
                            
krista@1484
  1758
                            bloblist_t* next_node = matt->next;
krista@1484
  1759
                            if (next_node) {
krista@1484
  1760
                                inner_mime_type = next_node->mime_type;
krista@1484
  1761
                                if (strcasecmp(inner_mime_type, "text/html") == 0) {
krista@1484
  1762
                                    free(mform);
roker@1563
  1763
                                    msg->longmsg_formatted = strndup(next_node->value, next_node->size);
krista@1484
  1764
                                }
krista@1484
  1765
                            }
krista@1484
  1766
                        }
krista@1484
  1767
                        else if (strcasecmp(inner_mime_type, "text/html") == 0) {
krista@1484
  1768
                            free(mform);
roker@1563
  1769
                            msg->longmsg_formatted = strndup(matt->value, matt->size);
roker@1563
  1770
                        }
krista@1484
  1771
                    }
krista@1484
  1772
                    if (msg->shortmsg) {
krista@1484
  1773
                        free(src->shortmsg);
krista@1484
  1774
                        src->shortmsg = strdup(msg->shortmsg);
krista@1484
  1775
                    }
roker@1563
  1776
                }
krista@1484
  1777
krista@1484
  1778
                if (decrypt_status != PEP_DECRYPTED_AND_VERIFIED) {
krista@1484
  1779
                    status = _get_detached_signature(msg, &detached_sig);
krista@1484
  1780
                    if (decrypt_status == PEP_DECRYPTED && detached_sig) {
krista@1484
  1781
                        dsig_text = detached_sig->value;
krista@1484
  1782
                        dsig_size = detached_sig->size;
krista@1484
  1783
                        size_t ssize = 0;
krista@1484
  1784
                        char* stext = NULL;
krista@1484
  1785
krista@1484
  1786
                        status = _get_signed_text(ptext, psize, &stext, &ssize);
krista@1484
  1787
                        stringlist_t *_verify_keylist = NULL;
krista@1484
  1788
krista@1484
  1789
                        if (ssize > 0 && stext) {
krista@1484
  1790
                            status = cryptotech[crypto].verify_text(session, stext,
krista@1484
  1791
                                                                    ssize, dsig_text, dsig_size,
krista@1484
  1792
                                                                    &_verify_keylist);
krista@1484
  1793
krista@1484
  1794
                            if (status == PEP_VERIFIED || status == PEP_VERIFIED_AND_TRUSTED)
krista@1484
  1795
                                decrypt_status = PEP_DECRYPTED_AND_VERIFIED;
krista@1484
  1796
                            
krista@1484
  1797
                                status = combine_keylists(session, &_verify_keylist, &_keylist, src->from);
krista@1484
  1798
                        }
krista@1427
  1799
                    }
krista@1427
  1800
                }
vb@256
  1801
                break;
vb@256
  1802
vb@256
  1803
            case PEP_enc_pieces:
vb@256
  1804
                msg = clone_to_empty_message(src);
vb@256
  1805
                if (msg == NULL)
vb@113
  1806
                    goto enomem;
vb@113
  1807
Edouard@882
  1808
                msg->longmsg = ptext;
Edouard@882
  1809
                ptext = NULL;
vb@256
  1810
vb@256
  1811
                bloblist_t *_m = msg->attachments;
vb@320
  1812
                if (_m == NULL && src->attachments && src->attachments->value) {
vb@320
  1813
                    msg->attachments = new_bloblist(NULL, 0, NULL, NULL);
vb@320
  1814
                    _m = msg->attachments;
vb@320
  1815
                }
vb@320
  1816
vb@256
  1817
                bloblist_t *_s;
Edouard@754
  1818
                for (_s = src->attachments; _s; _s = _s->next) {
Edouard@754
  1819
                    if (_s->value == NULL && _s->size == 0){
Edouard@754
  1820
                        _m = bloblist_add(_m, NULL, 0, _s->mime_type, _s->filename);
Edouard@754
  1821
                        if (_m == NULL)
Edouard@754
  1822
                            goto enomem;
Edouard@754
  1823
Edouard@754
  1824
                    }
Edouard@754
  1825
                    else if (is_encrypted_attachment(_s)) {
vb@256
  1826
                        stringlist_t *_keylist = NULL;
roker@862
  1827
                        char *attctext  = _s->value;
roker@862
  1828
                        size_t attcsize = _s->size;
Edouard@431
  1829
Edouard@842
  1830
                        free(ptext);
Edouard@842
  1831
                        ptext = NULL;
Edouard@842
  1832
krista@1397
  1833
                        // FIXME: What about attachments with separate sigs???
Edouard@431
  1834
                        status = decrypt_and_verify(session, attctext, attcsize,
krista@1397
  1835
                                                    NULL, 0,
krista@1397
  1836
                                                    &ptext, &psize, &_keylist);
krista@1484
  1837
                        free_stringlist(_keylist); // FIXME: Why do we do this?
vb@256
  1838
vb@289
  1839
                        if (ptext) {
vb@289
  1840
                            if (is_encrypted_html_attachment(_s)) {
Edouard@882
  1841
                                msg->longmsg_formatted = ptext;
Edouard@882
  1842
                                ptext = NULL;
vb@289
  1843
                            }
vb@289
  1844
                            else {
roker@862
  1845
                                static const char * const mime_type = "application/octet-stream";
roker@864
  1846
                                char * const filename =
vb@289
  1847
                                    without_double_ending(_s->filename);
vb@289
  1848
                                if (filename == NULL)
vb@289
  1849
                                    goto enomem;
vb@289
  1850
Edouard@882
  1851
                                _m = bloblist_add(_m, ptext, psize, mime_type,
vb@289
  1852
                                    filename);
roker@862
  1853
                                free(filename);
vb@290
  1854
                                if (_m == NULL)
vb@289
  1855
                                    goto enomem;
vb@290
  1856
Edouard@882
  1857
                                ptext = NULL;
Edouard@882
  1858
vb@290
  1859
                                if (msg->attachments == NULL)
vb@290
  1860
                                    msg->attachments = _m;
vb@289
  1861
                            }
vb@256
  1862
                        }
vb@256
  1863
                        else {
vb@320
  1864
                            char *copy = malloc(_s->size);
vb@350
  1865
                            assert(copy);
vb@350
  1866
                            if (copy == NULL)
vb@350
  1867
                                goto enomem;
vb@320
  1868
                            memcpy(copy, _s->value, _s->size);
vb@320
  1869
                            _m = bloblist_add(_m, copy, _s->size, _s->mime_type, _s->filename);
vb@256
  1870
                            if (_m == NULL)
vb@256
  1871
                                goto enomem;
vb@256
  1872
                        }
vb@256
  1873
                    }
vb@320
  1874
                    else {
vb@320
  1875
                        char *copy = malloc(_s->size);
vb@350
  1876
                        assert(copy);
vb@350
  1877
                        if (copy == NULL)
vb@350
  1878
                            goto enomem;
vb@320
  1879
                        memcpy(copy, _s->value, _s->size);
vb@320
  1880
                        _m = bloblist_add(_m, copy, _s->size, _s->mime_type, _s->filename);
vb@320
  1881
                        if (_m == NULL)
vb@320
  1882
                            goto enomem;
vb@320
  1883
                    }
vb@256
  1884
                }
vb@256
  1885
vb@256
  1886
                break;
vb@256
  1887
vb@256
  1888
            default:
vb@256
  1889
                // BUG: must implement more
vb@256
  1890
                NOT_IMPLEMENTED
vb@256
  1891
        }
krista@1427
  1892
vb@256
  1893
        switch (src->enc_format) {
vb@256
  1894
            case PEP_enc_PGP_MIME:
vb@256
  1895
            case PEP_enc_pieces:
edouard@1557
  1896
            case PEP_enc_PGP_MIME_Outlook1:
vb@256
  1897
                status = copy_fields(msg, src);
vb@256
  1898
                if (status != PEP_STATUS_OK)
vb@256
  1899
                    goto pep_error;
vb@256
  1900
vb@280
  1901
                if (src->shortmsg == NULL || strcmp(src->shortmsg, "pEp") == 0)
vb@256
  1902
                {
vb@256
  1903
                    char * shortmsg;
vb@256
  1904
                    char * longmsg;
vb@256
  1905
krista@853
  1906
                    int r = separate_short_and_long(msg->longmsg, &shortmsg,
vb@256
  1907
                            &longmsg);
vb@256
  1908
                    if (r == -1)
vb@256
  1909
                        goto enomem;
vb@256
  1910
vb@256
  1911
                    free(msg->shortmsg);
vb@256
  1912
                    free(msg->longmsg);
vb@256
  1913
vb@256
  1914
                    msg->shortmsg = shortmsg;
vb@256
  1915
                    msg->longmsg = longmsg;
vb@256
  1916
                }
vb@256
  1917
                else {
vb@256
  1918
                    msg->shortmsg = strdup(src->shortmsg);
vb@469
  1919
                    assert(msg->shortmsg);
vb@256
  1920
                    if (msg->shortmsg == NULL)
vb@256
  1921
                        goto enomem;
vb@256
  1922
                }
vb@256
  1923
                break;
vb@256
  1924
            default:
krista@1484
  1925
                    // BUG: must implement more
krista@1484
  1926
                    NOT_IMPLEMENTED
vb@256
  1927
        }
krista@1427
  1928
Edouard@734
  1929
        // check for private key in decrypted message attachement while inporting
Edouard@741
  1930
        identity_list *_private_il = NULL;
Edouard@741
  1931
        imported_keys = import_attached_keys(session, msg, &_private_il);
krista@1427
  1932
        if (_private_il &&
Edouard@741
  1933
            identity_list_length(_private_il) == 1 &&
Edouard@741
  1934
            _private_il->ident->address)
Edouard@728
  1935
        {
Edouard@741
  1936
            imported_private_key_address = true;
Edouard@728
  1937
        }
Edouard@741
  1938
Edouard@741
  1939
        if(private_il && imported_private_key_address){
Edouard@741
  1940
            *private_il = _private_il;
Edouard@741
  1941
        }else{
Edouard@741
  1942
            free_identity_list(_private_il);
Edouard@741
  1943
        }
krista@1427
  1944
Edouard@694
  1945
        if(decrypt_status == PEP_DECRYPTED){
Edouard@728
  1946
Edouard@728
  1947
            // TODO optimize if import_attached_keys didn't import any key
krista@1427
  1948
Edouard@431
  1949
            // In case message did decrypt, but no valid signature could be found
Edouard@431
  1950
            // then retry decrypt+verify after importing key.
Edouard@728
  1951
Edouard@728
  1952
            // Update msg->from in case we just imported a key
Edouard@728
  1953
            // we would need to check signature
vb@781
  1954
Edouard@861
  1955
            status = _update_identity_for_incoming_message(session, src);
Edouard@858
  1956
            if(status != PEP_STATUS_OK)
Edouard@858
  1957
                goto pep_error;
krista@1427
  1958
Edouard@431
  1959
            char *re_ptext = NULL;
Edouard@431
  1960
            size_t re_psize;
krista@1427
  1961
Edouard@431
  1962
            free_stringlist(_keylist);
Edouard@431
  1963
            _keylist = NULL;
vb@256
  1964
Edouard@431
  1965
            status = cryptotech[crypto].decrypt_and_verify(session, ctext,
krista@1397
  1966
                csize, dsig_text, dsig_size, &re_ptext, &re_psize, &_keylist);
krista@1427
  1967
Edouard@882
  1968
            free(re_ptext);
krista@1427
  1969
Edouard@431
  1970
            if (status > PEP_CANNOT_DECRYPT_UNKNOWN)
Edouard@431
  1971
                goto pep_error;
krista@1427
  1972
Edouard@431
  1973
            decrypt_status = status;
Edouard@431
  1974
        }
krista@1427
  1975
vb@1004
  1976
        *rating = decrypt_rating(decrypt_status);
krista@1427
  1977
vb@1004
  1978
        if (*rating > PEP_rating_mistrust) {
vb@1004
  1979
            PEP_rating kl_rating = PEP_rating_undefined;
krista@1427
  1980
Edouard@431
  1981
            if (_keylist)
vb@1004
  1982
                kl_rating = keylist_rating(session, _keylist);
krista@1427
  1983
vb@1004
  1984
            if (kl_rating <= PEP_rating_mistrust) {
vb@1004
  1985
                *rating = kl_rating;
Edouard@445
  1986
            }
vb@1004
  1987
            else if (*rating >= PEP_rating_reliable &&
vb@1004
  1988
                     kl_rating < PEP_rating_reliable) {
vb@1004
  1989
                *rating = PEP_rating_unreliable;
Edouard@431
  1990
            }
vb@1004
  1991
            else if (*rating >= PEP_rating_reliable &&
vb@1004
  1992
                     kl_rating >= PEP_rating_reliable) {
Edouard@431
  1993
                if (!(src->from && src->from->user_id && src->from->user_id[0])) {
vb@1004
  1994
                    *rating = PEP_rating_unreliable;
Edouard@431
  1995
                }
Edouard@431
  1996
                else {
Edouard@431
  1997
                    char *fpr = _keylist->value;
Edouard@431
  1998
                    pEp_identity *_from = new_identity(src->from->address, fpr,
Edouard@431
  1999
                                                       src->from->user_id, src->from->username);
Edouard@431
  2000
                    if (_from == NULL)
Edouard@431
  2001
                        goto enomem;
edouard@1156
  2002
                    status = get_trust(session, _from);
krista@1615
  2003
                    if (_from->comm_type != PEP_ct_unknown) {
krista@1615
  2004
                        *rating = worst_rating(_rating(_from->comm_type, PEP_rating_undefined),
krista@1615
  2005
                                  kl_rating);
krista@1615
  2006
                    }
Edouard@431
  2007
                    free_identity(_from);
edouard@1156
  2008
                    if (status == PEP_CANNOT_FIND_IDENTITY)
edouard@1156
  2009
                       status = PEP_STATUS_OK;
Edouard@431
  2010
                    if (status != PEP_STATUS_OK)
Edouard@431
  2011
                        goto pep_error;
Edouard@431
  2012
                }
Edouard@431
  2013
            }
Edouard@431
  2014
        }
vb@113
  2015
    }
Edouard@745
  2016
    else
Edouard@745
  2017
    {
vb@1004
  2018
        *rating = decrypt_rating(decrypt_status);
Edouard@745
  2019
        goto pep_error;
Edouard@745
  2020
    }
vb@731
  2021
Edouard@728
  2022
    // Case of own key imported from own trusted message
krista@1427
  2023
    if (// Message have been reliably decrypted
Edouard@728
  2024
        msg &&
vb@1004
  2025
        *rating >= PEP_rating_trusted &&
Edouard@728
  2026
        imported_private_key_address &&
Edouard@728
  2027
        // to is [own]
Edouard@728
  2028
        msg->to->ident->user_id &&
krista@1427
  2029
        strcmp(msg->to->ident->user_id, PEP_OWN_USERID) == 0
Edouard@729
  2030
        )
Edouard@728
  2031
    {
Edouard@738
  2032
        *flags |= PEP_decrypt_flag_own_private_key;
Edouard@728
  2033
    }
vb@113
  2034
vb@731
  2035
    if (msg) {
vb@1004
  2036
        decorate_message(msg, *rating, _keylist);
vb@731
  2037
        if (imported_keys)
vb@731
  2038
            remove_attached_keys(msg);
edouard@1603
  2039
        if (*rating >= PEP_rating_reliable &&
edouard@1603
  2040
            session->sync_session->inject_sync_msg) {
edouard@1165
  2041
            status = receive_DeviceState_msg(session, msg, *rating, _keylist);
krista@1427
  2042
            if (status == PEP_MESSAGE_CONSUME ||
edouard@1369
  2043
                status == PEP_MESSAGE_IGNORE) {
vb@1099
  2044
                free_message(msg);
vb@1099
  2045
                msg = NULL;
edouard@1369
  2046
                *flags |= (status == PEP_MESSAGE_IGNORE) ?
edouard@1369
  2047
                            PEP_decrypt_flag_ignore :
edouard@1369
  2048
                            PEP_decrypt_flag_consume;
edouard@1355
  2049
edouard@1355
  2050
                status = decrypt_status;
vb@1099
  2051
            }
vb@1099
  2052
            else if (status != PEP_STATUS_OK){
vb@1099
  2053
                goto pep_error;
vb@1099
  2054
            }
vb@1099
  2055
        }
edouard@1558
  2056
    }
edouard@1558
  2057
    if (msg) {
edouard@1542
  2058
        if (src->id) {
edouard@1542
  2059
            msg->id = strdup(src->id);
edouard@1542
  2060
            assert(msg->id);
edouard@1542
  2061
            if (msg->id == NULL)
edouard@1542
  2062
                goto enomem;
edouard@1542
  2063
        }
vb@731
  2064
    }
vb@235
  2065
vb@74
  2066
    *dst = msg;
vb@241
  2067
    *keylist = _keylist;
vb@241
  2068
vb@953
  2069
    return status;
vb@73
  2070
vb@73
  2071
enomem:
vb@73
  2072
    status = PEP_OUT_OF_MEMORY;
vb@73
  2073
vb@73
  2074
pep_error:
Edouard@882
  2075
    free(ptext);
vb@73
  2076
    free_message(msg);
vb@241
  2077
    free_stringlist(_keylist);
vb@39
  2078
vb@37
  2079
    return status;
vb@37
  2080
}
vb@37
  2081
Edouard@741
  2082
DYNAMIC_API PEP_STATUS decrypt_message(
Edouard@741
  2083
        PEP_SESSION session,
Edouard@741
  2084
        message *src,
Edouard@741
  2085
        message **dst,
Edouard@741
  2086
        stringlist_t **keylist,
vb@1004
  2087
        PEP_rating *rating,
krista@1427
  2088
        PEP_decrypt_flags_t *flags
Edouard@741
  2089
    )
Edouard@741
  2090
{
vb@1004
  2091
    return _decrypt_message( session, src, dst, keylist, rating, flags, NULL );
Edouard@741
  2092
}
Edouard@741
  2093
Edouard@728
  2094
DYNAMIC_API PEP_STATUS own_message_private_key_details(
Edouard@728
  2095
        PEP_SESSION session,
Edouard@728
  2096
        message *msg,
krista@1427
  2097
        pEp_identity **ident
Edouard@728
  2098
    )
Edouard@728
  2099
{
Edouard@728
  2100
    assert(session);
Edouard@728
  2101
    assert(msg);
Edouard@728
  2102
    assert(ident);
Edouard@728
  2103
Edouard@736
  2104
    if (!(session && msg && ident))
Edouard@728
  2105
        return PEP_ILLEGAL_VALUE;
Edouard@728
  2106
krista@1427
  2107
    message *dst = NULL;
krista@956
  2108
    stringlist_t *keylist = NULL;
vb@1004
  2109
    PEP_rating rating;
krista@1427
  2110
    PEP_decrypt_flags_t flags;
Edouard@728
  2111
Edouard@729
  2112
    *ident = NULL;
Edouard@729
  2113
Edouard@740
  2114
    identity_list *private_il = NULL;
vb@1004
  2115
    PEP_STATUS status = _decrypt_message(session, msg,  &dst, &keylist, &rating, &flags, &private_il);
vb@953
  2116
    free_message(dst);
vb@953
  2117
    free_stringlist(keylist);
Edouard@728
  2118
Edouard@729
  2119
    if (status == PEP_STATUS_OK &&
Edouard@741
  2120
        flags & PEP_decrypt_flag_own_private_key &&
Edouard@741
  2121
        private_il)
Edouard@729
  2122
    {
Edouard@740
  2123
        *ident = identity_dup(private_il->ident);
Edouard@729
  2124
    }
Edouard@729
  2125
Edouard@741
  2126
    free_identity_list(private_il);
Edouard@741
  2127
Edouard@728
  2128
    return status;
Edouard@741
  2129
Edouard@728
  2130
}
Edouard@728
  2131
Edouard@858
  2132
static void _max_comm_type_from_identity_list(
krista@1427
  2133
        identity_list *identities,
Edouard@858
  2134
        PEP_SESSION session,
Edouard@858
  2135
        PEP_comm_type *max_comm_type,
Edouard@858
  2136
        bool *comm_type_determined
Edouard@858
  2137
    )
Edouard@858
  2138
{
Edouard@858
  2139
    identity_list * il;
Edouard@858
  2140
    for (il = identities; il != NULL; il = il->next)
Edouard@858
  2141
    {
Edouard@858
  2142
        if (il->ident)
Edouard@858
  2143
        {
edouard@1385
  2144
            PEP_STATUS status = update_identity(session, il->ident);
Edouard@858
  2145
            if (status == PEP_STATUS_OK)
Edouard@858
  2146
            {
Edouard@858
  2147
                *max_comm_type = _get_comm_type(session, *max_comm_type,
Edouard@858
  2148
                        il->ident);
Edouard@858
  2149
                *comm_type_determined = true;
Edouard@858
  2150
            }
Edouard@858
  2151
        }
Edouard@858
  2152
    }
Edouard@858
  2153
}
Edouard@858
  2154
vb@1004
  2155
DYNAMIC_API PEP_STATUS outgoing_message_rating(
vb@190
  2156
        PEP_SESSION session,
vb@190
  2157
        message *msg,
vb@1004
  2158
        PEP_rating *rating
vb@190
  2159
    )
vb@190
  2160
{
vb@190
  2161
    PEP_comm_type max_comm_type = PEP_ct_pEp;
vb@190
  2162
    bool comm_type_determined = false;
vb@190
  2163
vb@190
  2164
    assert(session);
vb@190
  2165
    assert(msg);
vb@251
  2166
    assert(msg->dir == PEP_dir_outgoing);
vb@1004
  2167
    assert(rating);
vb@190
  2168
vb@1004
  2169
    if (!(session && msg && rating))
vb@191
  2170
        return PEP_ILLEGAL_VALUE;
vb@191
  2171
vb@1360
  2172
    if (msg->dir != PEP_dir_outgoing)
vb@251
  2173
        return PEP_ILLEGAL_VALUE;
vb@251
  2174
vb@1004
  2175
    *rating = PEP_rating_undefined;
vb@190
  2176
Edouard@858
  2177
    _max_comm_type_from_identity_list(msg->to, session,
Edouard@858
  2178
                                      &max_comm_type, &comm_type_determined);
vb@190
  2179
Edouard@858
  2180
    _max_comm_type_from_identity_list(msg->cc, session,
Edouard@858
  2181
                                      &max_comm_type, &comm_type_determined);
krista@1427
  2182
Edouard@858
  2183
    _max_comm_type_from_identity_list(msg->bcc, session,
Edouard@858
  2184
                                      &max_comm_type, &comm_type_determined);
vb@190
  2185
vb@190
  2186
    if (comm_type_determined == false)
vb@1004
  2187
        *rating = PEP_rating_undefined;
vb@190
  2188
    else
vb@1004
  2189
        *rating = _MAX(_rating(max_comm_type, PEP_rating_undefined),
vb@486
  2190
                PEP_rating_unencrypted);
vb@190
  2191
vb@190
  2192
    return PEP_STATUS_OK;
vb@190
  2193
}
vb@190
  2194
vb@1004
  2195
DYNAMIC_API PEP_STATUS identity_rating(
vb@239
  2196
        PEP_SESSION session,
vb@239
  2197
        pEp_identity *ident,
vb@1004
  2198
        PEP_rating *rating
vb@239
  2199
    )
vb@239
  2200
{
vb@239
  2201
    PEP_STATUS status = PEP_STATUS_OK;
vb@239
  2202
vb@239
  2203
    assert(session);
vb@239
  2204
    assert(ident);
vb@1004
  2205
    assert(rating);
vb@239
  2206
vb@1004
  2207
    if (!(session && ident && rating))
vb@239
  2208
        return PEP_ILLEGAL_VALUE;
vb@239
  2209
vb@239
  2210
    if (ident->me)
edouard@1406
  2211
        status = _myself(session, ident, false, true);
vb@239
  2212
    else
vb@239
  2213
        status = update_identity(session, ident);
vb@239
  2214
vb@239
  2215
    if (status == PEP_STATUS_OK)
vb@1004
  2216
        *rating = _rating(ident->comm_type, PEP_rating_undefined);
vb@239
  2217
vb@239
  2218
    return status;
vb@239
  2219
}
vb@239
  2220
vb@507
  2221
DYNAMIC_API PEP_STATUS get_binary_path(PEP_cryptotech tech, const char **path)
vb@507
  2222
{
vb@507
  2223
    PEP_STATUS status = PEP_STATUS_OK;
vb@507
  2224
vb@507
  2225
    assert(path);
vb@507
  2226
    if (path == NULL)
vb@507
  2227
        return PEP_ILLEGAL_VALUE;
vb@507
  2228
vb@507
  2229
    if (cryptotech[tech].binary_path == NULL)
vb@507
  2230
        *path = NULL;
vb@507
  2231
    else
vb@507
  2232
        status = cryptotech[tech].binary_path(path);
vb@507
  2233
vb@507
  2234
    return status;
vb@507
  2235
}
vb@507
  2236
vb@1004
  2237
vb@1004
  2238
DYNAMIC_API PEP_color color_from_rating(PEP_rating rating)
vb@1004
  2239
{
krista@1243
  2240
    if (rating == PEP_rating_b0rken || rating == PEP_rating_have_no_key)
vb@1004
  2241
        return PEP_color_no_color;
vb@1004
  2242
vb@1004
  2243
    if (rating < PEP_rating_undefined)
vb@1004
  2244
        return PEP_color_red;
vb@1004
  2245
vb@1004
  2246
    if (rating < PEP_rating_reliable)
vb@1004
  2247
        return PEP_color_no_color;
vb@1004
  2248
vb@1004
  2249
    if (rating < PEP_rating_trusted)
vb@1004
  2250
        return PEP_color_yellow;
vb@1004
  2251
vb@1004
  2252
    if (rating >= PEP_rating_trusted)
vb@1004
  2253
        return PEP_color_green;
vb@1004
  2254
vb@1004
  2255
    // this should never happen
vb@1004
  2256
    assert(false);
vb@1475
  2257
	return PEP_color_no_color;
vb@1004
  2258
}
vb@1004
  2259
krista@1307
  2260
DYNAMIC_API PEP_STATUS get_trustwords(
roker@1509
  2261
    PEP_SESSION session, const pEp_identity* id1, const pEp_identity* id2,
krista@1307
  2262
    const char* lang, char **words, size_t *wsize, bool full
krista@1307
  2263
)
krista@1307
  2264
{
krista@1307
  2265
    assert(session);
krista@1307
  2266
    assert(id1);
krista@1307
  2267
    assert(id2);
krista@1307
  2268
    assert(id1->fpr);
krista@1307
  2269
    assert(id2->fpr);
krista@1307
  2270
    assert(words);
krista@1307
  2271
    assert(wsize);
krista@1427
  2272
krista@1307
  2273
    if (!(session && id1 && id2 && words && wsize) ||
krista@1307
  2274
        !(id1->fpr) || (!id2->fpr))
krista@1307
  2275
        return PEP_ILLEGAL_VALUE;
krista@1427
  2276
krista@1307
  2277
    const char *source1 = id1->fpr;
krista@1307
  2278
    const char *source2 = id2->fpr;
krista@1427
  2279
krista@1307
  2280
    *words = NULL;
krista@1307
  2281
    *wsize = 0;
krista@1307
  2282
krista@1307
  2283
    const size_t SHORT_NUM_TWORDS = 5;
krista@1427
  2284
krista@1307
  2285
    // N.B. THIS will have to be changed once we start checking trustword entropy.
krista@1307
  2286
    // For now, full is ALL, and otherwise it's 5-per-id.
krista@1307
  2287
    size_t max_words_per_id = (full ? 0 : SHORT_NUM_TWORDS);
krista@1427
  2288
krista@1307
  2289
    char* first_set = NULL;
krista@1307
  2290
    char* second_set = NULL;
krista@1307
  2291
    size_t first_wsize = 0;
krista@1307
  2292
    size_t second_wsize = 0;
krista@1427
  2293
krista@1312
  2294
    int fpr_comparison = -255;
edouard@1746
  2295
    PEP_STATUS status = _compare_fprs(source1, strlen(source1), source2, strlen(source2), &fpr_comparison);
krista@1312
  2296
    if (status != PEP_STATUS_OK)
krista@1312
  2297
        return status;
krista@1312
  2298
krista@1307
  2299
    char* _retstr = NULL;
krista@1312
  2300
krista@1312
  2301
    switch (fpr_comparison) {
krista@1312
  2302
        case 1: // source1 > source2
krista@1312
  2303
            status = trustwords(session, source2, lang, &first_set, &first_wsize, max_words_per_id);
krista@1312
  2304
            if (status != PEP_STATUS_OK)
krista@1312
  2305
                goto error_release;
krista@1427
  2306
            status = trustwords(session, source1, lang, &second_set, &second_wsize, max_words_per_id);
krista@1312
  2307
            if (status != PEP_STATUS_OK)
krista@1312
  2308
                goto error_release;
krista@1312
  2309
            break;
krista@1427
  2310
        case 0:
krista@1312
  2311
        case -1: // source1 <= source2
krista@1312
  2312
            status = trustwords(session, source1, lang, &first_set, &first_wsize, max_words_per_id);
krista@1312
  2313
            if (status != PEP_STATUS_OK)
krista@1312
  2314
                goto error_release;
krista@1427
  2315
            status = trustwords(session, source2, lang, &second_set, &second_wsize, max_words_per_id);
krista@1312
  2316
            if (status != PEP_STATUS_OK)
krista@1312
  2317
                goto error_release;
krista@1315
  2318
            break;
krista@1312
  2319
        default:
krista@1312
  2320
            return PEP_UNKNOWN_ERROR; // shouldn't be possible
krista@1312
  2321
    }
krista@1427
  2322
krista@1307
  2323
    size_t _wsize = first_wsize + second_wsize;
krista@1427
  2324
krista@1315
  2325
    bool needs_space = (first_set[first_wsize - 1] != ' ');
krista@1427
  2326
krista@1315
  2327
    if (needs_space)
krista@1315
  2328
        _wsize++;
krista@1427
  2329
krista@1307
  2330
    _retstr = calloc(1, _wsize + 1);
krista@1427
  2331
krista@1307
  2332
    size_t len = strlcpy(_retstr, first_set, _wsize);
krista@1307
  2333
    if (len >= _wsize) {
krista@1307
  2334
        status = PEP_UNKNOWN_ERROR;
krista@1307
  2335
        goto error_release;
krista@1307
  2336
    }
krista@1315
  2337
    if (needs_space) {
krista@1315
  2338
        strlcat(_retstr, " ", _wsize);
krista@1315
  2339
        if (len >= _wsize) {
krista@1315
  2340
            status = PEP_UNKNOWN_ERROR;
krista@1315
  2341
            goto error_release;
krista@1315
  2342
        }
krista@1315
  2343
    }
krista@1307
  2344
    strlcat(_retstr, second_set, _wsize);
krista@1307
  2345
    if (len >= _wsize){
krista@1307
  2346
        status = PEP_UNKNOWN_ERROR;
krista@1307
  2347
        goto error_release;
krista@1307
  2348
    }
krista@1427
  2349
krista@1307
  2350
    *words = _retstr;
krista@1307
  2351
    *wsize = _wsize;
krista@1307
  2352
    status = PEP_STATUS_OK;
krista@1427
  2353
krista@1307
  2354
    goto the_end;
krista@1427
  2355
krista@1307
  2356
    error_release:
krista@1307
  2357
    free(_retstr);
krista@1427
  2358
krista@1307
  2359
    the_end:
krista@1307
  2360
    free(first_set);
krista@1307
  2361
    free(second_set);
krista@1307
  2362
    return status;
vb@1309
  2363
}
vb@1309
  2364
edouard@1553
  2365
DYNAMIC_API PEP_STATUS get_message_trustwords(
edouard@1553
  2366
    PEP_SESSION session, 
edouard@1553
  2367
    message *msg,
edouard@1553
  2368
    stringlist_t *keylist,
edouard@1553
  2369
    pEp_identity* received_by,
edouard@1553
  2370
    const char* lang, char **words, bool full
edouard@1553
  2371
)
edouard@1553
  2372
{
edouard@1553
  2373
    assert(session);
edouard@1553
  2374
    assert(msg);
edouard@1553
  2375
    assert(received_by);
edouard@1553
  2376
    assert(received_by->address);
edouard@1553
  2377
    assert(lang);
edouard@1553
  2378
    assert(words);
edouard@1553
  2379
edouard@1553
  2380
    if (!(session && 
edouard@1553
  2381
          msg &&
edouard@1553
  2382
          received_by && 
edouard@1553
  2383
          received_by->address && 
edouard@1553
  2384
          lang && 
edouard@1553
  2385
          words))
edouard@1553
  2386
        return PEP_ILLEGAL_VALUE;
edouard@1553
  2387
    
edouard@1557
  2388
    pEp_identity* partner = NULL;
edouard@1553
  2389
     
edouard@1553
  2390
    PEP_STATUS status = PEP_STATUS_OK;
edouard@1553
  2391
    
edouard@1553
  2392
    *words = NULL;
edouard@1553
  2393
edouard@1553
  2394
    // We want fingerprint of key that did sign the message
edouard@1553
  2395
edouard@1553
  2396
    if (keylist == NULL) {
edouard@1553
  2397
edouard@1553
  2398
        // Message is to be decrypted
roker@1554
  2399
        message *dst = NULL;
edouard@1553
  2400
        stringlist_t *_keylist = keylist;
edouard@1553
  2401
        PEP_rating rating;
edouard@1553
  2402
        PEP_decrypt_flags_t flags;
edouard@1553
  2403
        status = decrypt_message( session, msg, &dst, &_keylist, &rating, &flags);
edouard@1553
  2404
edouard@1553
  2405
        if (status != PEP_STATUS_OK) {
edouard@1553
  2406
            free_message(dst);
edouard@1553
  2407
            free_stringlist(_keylist);
edouard@1553
  2408
            return status;
edouard@1553
  2409
        }
edouard@1553
  2410
edouard@1553
  2411
        if (dst && dst->from && _keylist) {
edouard@1553
  2412
            partner = identity_dup(dst->from); 
edouard@1553
  2413
            if(partner){
edouard@1553
  2414
                free(partner->fpr);
edouard@1553
  2415
                partner->fpr = strdup(_keylist->value);
edouard@1553
  2416
                if (partner->fpr == NULL)
edouard@1553
  2417
                    status = PEP_OUT_OF_MEMORY;
edouard@1553
  2418
            } else {
edouard@1553
  2419
                status = PEP_OUT_OF_MEMORY;
edouard@1553
  2420
            }
edouard@1553
  2421
        } else {
edouard@1553
  2422
            status = PEP_UNKNOWN_ERROR;
edouard@1553
  2423
        }
edouard@1553
  2424
edouard@1553
  2425
        free_message(dst);
edouard@1553
  2426
        free_stringlist(_keylist);
edouard@1553
  2427
edouard@1553
  2428
    } else {
edouard@1553
  2429
edouard@1553
  2430
        // Message already decrypted
edouard@1553
  2431
        if (keylist->value) {
edouard@1553
  2432
            partner = identity_dup(msg->from); 
edouard@1553
  2433
            if(partner){
edouard@1553
  2434
                free(partner->fpr);
edouard@1553
  2435
                partner->fpr = strdup(keylist->value);
edouard@1553
  2436
                if (partner->fpr == NULL)
edouard@1553
  2437
                    status = PEP_OUT_OF_MEMORY;
edouard@1553
  2438
            } else {
edouard@1553
  2439
                status = PEP_OUT_OF_MEMORY;
edouard@1553
  2440
            }
edouard@1553
  2441
        } else {
edouard@1553
  2442
            status = PEP_ILLEGAL_VALUE;
edouard@1553
  2443
        }
edouard@1553
  2444
    }
edouard@1553
  2445
edouard@1553
  2446
    if (status != PEP_STATUS_OK) {
edouard@1553
  2447
        free_identity(partner);
edouard@1553
  2448
        return status;
edouard@1553
  2449
    }
edouard@1553
  2450
   
edouard@1553
  2451
    // Find own identity corresponding to given account address.
edouard@1553
  2452
    // In that case we want default key attached to own identity
edouard@1553
  2453
    pEp_identity *stored_identity = NULL;
edouard@1553
  2454
    status = get_identity(session,
edouard@1553
  2455
                          received_by->address,
edouard@1553
  2456
                          PEP_OWN_USERID,
edouard@1553
  2457
                          &stored_identity);
edouard@1553
  2458
edouard@1553
  2459
    if (status != PEP_STATUS_OK) {
edouard@1553
  2460
        free_identity(stored_identity);
edouard@1553
  2461
        return status;
edouard@1553
  2462
    }
edouard@1553
  2463
edouard@1553
  2464
    // get the trustwords
edouard@1553
  2465
    size_t wsize;
edouard@1553
  2466
    status = get_trustwords(session, 
edouard@1553
  2467
                            partner, received_by, 
edouard@1553
  2468
                            lang, words, &wsize, full);
edouard@1553
  2469
edouard@1553
  2470
    return status;
edouard@1553
  2471
}
krista@1325
  2472
krista@1325
  2473
DYNAMIC_API PEP_STATUS MIME_decrypt_message(
krista@1325
  2474
    PEP_SESSION session,
krista@1325
  2475
    const char *mimetext,
krista@1325
  2476
    size_t size,
krista@1325
  2477
    char** mime_plaintext,
krista@1325
  2478
    stringlist_t **keylist,
krista@1325
  2479
    PEP_rating *rating,
krista@1325
  2480
    PEP_decrypt_flags_t *flags
krista@1427
  2481
)
krista@1325
  2482
{
roker@1741
  2483
    assert(mimetext);
roker@1741
  2484
    assert(mime_plaintext);
roker@1741
  2485
    assert(keylist);
roker@1741
  2486
    assert(rating);
roker@1741
  2487
    assert(flags);
roker@1741
  2488
krista@1325
  2489
    PEP_STATUS status = PEP_STATUS_OK;
krista@1325
  2490
    message* tmp_msg = NULL;
krista@1325
  2491
    message* dec_msg = NULL;
krista@1427
  2492
krista@1325
  2493
    status = mime_decode_message(mimetext, size, &tmp_msg);
krista@1325
  2494
    if (status != PEP_STATUS_OK)
krista@1325
  2495
        goto pep_error;
krista@1427
  2496
krista@1644
  2497
    PEP_STATUS decrypt_status = decrypt_message(session,
krista@1644
  2498
                                                tmp_msg,
krista@1644
  2499
                                                &dec_msg,
krista@1644
  2500
                                                keylist,
krista@1644
  2501
                                                rating,
krista@1644
  2502
                                                flags);
krista@1743
  2503
                                                
krista@1743
  2504
    if (!dec_msg && (decrypt_status == PEP_UNENCRYPTED || decrypt_status == PEP_VERIFIED)) {
krista@1743
  2505
        dec_msg = message_dup(tmp_msg);
krista@1743
  2506
    }
krista@1743
  2507
        
krista@1715
  2508
    if (decrypt_status > PEP_CANNOT_DECRYPT_UNKNOWN)
roker@1708
  2509
    {
roker@1708
  2510
        status = decrypt_status;
roker@1708
  2511
        goto pep_error;
roker@1708
  2512
    }
roker@1708
  2513
roker@1741
  2514
    assert(dec_msg);
roker@1741
  2515
    
krista@1742
  2516
    if (!dec_msg) {
krista@1742
  2517
        status = PEP_UNKNOWN_ERROR;
krista@1742
  2518
        goto pep_error;
krista@1742
  2519
    }
krista@1742
  2520
krista@1325
  2521
    status = mime_encode_message(dec_msg, false, mime_plaintext);
krista@1427
  2522
krista@1644
  2523
    if (status == PEP_STATUS_OK)
roker@1708
  2524
    {
roker@1708
  2525
        free(tmp_msg);
krista@1743
  2526
        free(dec_msg);
krista@1644
  2527
        return decrypt_status;
roker@1708
  2528
    }
roker@1708
  2529
    
krista@1325
  2530
pep_error:
krista@1325
  2531
    free_message(tmp_msg);
krista@1325
  2532
    free_message(dec_msg);
krista@1427
  2533
krista@1325
  2534
    return status;
krista@1325
  2535
}
krista@1325
  2536
krista@1641
  2537
krista@1325
  2538
DYNAMIC_API PEP_STATUS MIME_encrypt_message(
krista@1325
  2539
    PEP_SESSION session,
krista@1325
  2540
    const char *mimetext,
krista@1325
  2541
    size_t size,
krista@1325
  2542
    stringlist_t* extra,
krista@1325
  2543
    char** mime_ciphertext,
krista@1325
  2544
    PEP_enc_format enc_format,
krista@1325
  2545
    PEP_encrypt_flags_t flags
krista@1427
  2546
)
krista@1325
  2547
{
krista@1325
  2548
    PEP_STATUS status = PEP_STATUS_OK;
krista@1325
  2549
    message* tmp_msg = NULL;
krista@1325
  2550
    message* enc_msg = NULL;
krista@1427
  2551
krista@1325
  2552
    status = mime_decode_message(mimetext, size, &tmp_msg);
krista@1325
  2553
    if (status != PEP_STATUS_OK)
krista@1325
  2554
        goto pep_error;
krista@1427
  2555
krista@1325
  2556
    // This isn't incoming, though... so we need to reverse the direction
krista@1325
  2557
    tmp_msg->dir = PEP_dir_outgoing;
krista@1325
  2558
    status = encrypt_message(session,
krista@1325
  2559
                             tmp_msg,
krista@1325
  2560
                             extra,
krista@1325
  2561
                             &enc_msg,
krista@1325
  2562
                             enc_format,
krista@1325
  2563
                             flags);
krista@1325
  2564
    if (status != PEP_STATUS_OK)
krista@1325
  2565
        goto pep_error;
krista@1427
  2566
krista@1742
  2567
krista@1742
  2568
    if (!enc_msg) {
krista@1742
  2569
        status = PEP_UNKNOWN_ERROR;
krista@1742
  2570
        goto pep_error;
krista@1742
  2571
    }
krista@1742
  2572
krista@1325
  2573
    status = mime_encode_message(enc_msg, false, mime_ciphertext);
krista@1427
  2574
krista@1325
  2575
pep_error:
krista@1325
  2576
    free_message(tmp_msg);
krista@1325
  2577
    free_message(enc_msg);
krista@1325
  2578
krista@1325
  2579
    return status;
krista@1325
  2580
krista@1325
  2581
}