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