src/message_api.c
author vb
Sun, 01 Mar 2015 21:51:53 +0100
changeset 82 d0ad5655688a
parent 81 044ce1c7fc9c
child 83 c5d82f11689a
permissions -rw-r--r--
go on...
vb@37
     1
#include "message_api.h"
vb@37
     2
#include "keymanagement.h"
vb@62
     3
#include "mime.h"
vb@37
     4
vb@37
     5
#include <assert.h>
vb@37
     6
#include <string.h>
vb@39
     7
#include <stdlib.h>
vb@39
     8
vb@76
     9
#define NOT_IMPLEMENTED assert(0); return PEP_UNKNOWN_ERROR;
vb@37
    10
vb@62
    11
static char * combine_short_and_long(const message * src)
vb@62
    12
{
vb@62
    13
    char * ptext;
vb@63
    14
    char * longmsg;
vb@81
    15
vb@62
    16
    assert(src);
vb@63
    17
    assert(src->shortmsg && strcmp(src->shortmsg, "pEp") != 0);
vb@62
    18
vb@63
    19
    if (src->longmsg)
vb@63
    20
        longmsg = src->longmsg;
vb@63
    21
    else
vb@63
    22
        longmsg = "";
vb@63
    23
vb@63
    24
    ptext = calloc(1, strlen(src->shortmsg) + strlen(longmsg) + 12);
vb@62
    25
    if (ptext == NULL)
vb@62
    26
        return NULL;
vb@62
    27
vb@62
    28
    strcpy(ptext, "subject: ");
vb@62
    29
    strcat(ptext, src->shortmsg);
vb@62
    30
    strcat(ptext, "\n\n");
vb@63
    31
    strcat(ptext, longmsg);
vb@62
    32
vb@62
    33
    return ptext;
vb@62
    34
}
vb@44
    35
vb@82
    36
static int seperate_short_and_long(const char *src, char **shortmsg, char **longmsg)
vb@82
    37
{
vb@82
    38
    char *_shortmsg = NULL;
vb@82
    39
    char *_longmsg = NULL;
vb@82
    40
vb@82
    41
    assert(src);
vb@82
    42
    assert(shortmsg);
vb@82
    43
    assert(longmsg);
vb@82
    44
vb@82
    45
    *shortmsg = NULL;
vb@82
    46
    *longmsg = NULL;
vb@82
    47
vb@82
    48
    if (strncmp(src, "subject: ", 9) == 0) {
vb@82
    49
        char *line_end = strchr(src, '\n');
vb@82
    50
        
vb@82
    51
        if (line_end == NULL) {
vb@82
    52
            _shortmsg = strdup(src + 9);
vb@82
    53
            if (_shortmsg == NULL)
vb@82
    54
                goto enomem;
vb@82
    55
            // _longmsg = NULL;
vb@82
    56
        }
vb@82
    57
        else {
vb@82
    58
            size_t n = line_end - src;
vb@82
    59
            if (*(line_end - 1) == '\r')
vb@82
    60
                _shortmsg = strndup(src + 9, n - 1);
vb@82
    61
            else
vb@82
    62
                _shortmsg = strndup(src + 9, n);
vb@82
    63
            if (_shortmsg == NULL)
vb@82
    64
                goto enomem;
vb@82
    65
            _longmsg = strdup(src + n);
vb@82
    66
            if (_longmsg == NULL)
vb@82
    67
                goto enomem;
vb@82
    68
        }
vb@82
    69
    }
vb@82
    70
    else {
vb@82
    71
        _shortmsg = strdup("pEp");
vb@82
    72
        if (_shortmsg == NULL)
vb@82
    73
            goto enomem;
vb@82
    74
        _longmsg = strdup(src);
vb@82
    75
        if (_longmsg == NULL)
vb@82
    76
            goto enomem;
vb@82
    77
    }
vb@82
    78
    
vb@82
    79
    *shortmsg = _shortmsg;
vb@82
    80
    *longmsg = _longmsg;
vb@82
    81
vb@82
    82
    return 0;
vb@82
    83
vb@82
    84
enomem:
vb@82
    85
    free(_shortmsg);
vb@82
    86
    free(_longmsg);
vb@82
    87
vb@82
    88
    return -1;
vb@82
    89
}
vb@82
    90
vb@81
    91
static message * clone_to_empty_message(const message * src)
vb@80
    92
{
vb@80
    93
    pEp_identity *from = NULL;
vb@80
    94
    identity_list *to = NULL;
vb@81
    95
vb@80
    96
    message * msg = NULL;
vb@80
    97
vb@81
    98
    assert(src);
vb@81
    99
    assert(src->from);
vb@81
   100
    assert(src->to);
vb@81
   101
vb@80
   102
    from = identity_dup(src->from);
vb@80
   103
    if (from == NULL)
vb@80
   104
        goto enomem;
vb@80
   105
vb@80
   106
    from->me = true;
vb@80
   107
vb@80
   108
    to = identity_list_dup(src->to);
vb@80
   109
    if (to == NULL)
vb@80
   110
        goto enomem;
vb@80
   111
vb@80
   112
    msg = new_message(src->dir, from, to, NULL);
vb@80
   113
    if (msg == NULL)
vb@80
   114
        goto enomem;
vb@80
   115
vb@82
   116
    msg->dir = src->dir;
vb@82
   117
vb@81
   118
    if (src->cc) {
vb@81
   119
        msg->cc = identity_list_dup(src->cc);
vb@81
   120
        if (msg->cc == NULL)
vb@81
   121
            goto enomem;
vb@81
   122
    }
vb@81
   123
vb@81
   124
    if (src->bcc) {
vb@81
   125
        msg->bcc = identity_list_dup(src->bcc);
vb@81
   126
        if (msg->bcc == NULL)
vb@81
   127
            goto enomem;
vb@81
   128
    }
vb@81
   129
vb@81
   130
    if (src->reply_to) {
vb@81
   131
        msg->reply_to = identity_dup(src->reply_to);
vb@81
   132
        if (msg->reply_to == NULL)
vb@81
   133
            goto enomem;
vb@81
   134
    }
vb@81
   135
vb@81
   136
    msg->sent = src->sent;
vb@81
   137
    msg->recv = src->recv;
vb@81
   138
vb@80
   139
    return msg;
vb@80
   140
vb@80
   141
enomem:
vb@81
   142
    if (msg) {
vb@81
   143
        free_message(msg);
vb@81
   144
    }
vb@81
   145
    else {
vb@81
   146
        free_identity(from);
vb@81
   147
        free_identity_list(to);
vb@81
   148
    }
vb@81
   149
vb@80
   150
    return NULL;
vb@80
   151
}
vb@80
   152
vb@48
   153
DYNAMIC_API PEP_STATUS encrypt_message(
vb@37
   154
        PEP_SESSION session,
vb@37
   155
        const message *src,
vb@37
   156
        stringlist_t * extra,
vb@38
   157
        message **dst,
vb@81
   158
        PEP_enc_format enc_format
vb@37
   159
    )
vb@37
   160
{
vb@37
   161
    PEP_STATUS status = PEP_STATUS_OK;
vb@63
   162
    message * msg = NULL;
vb@63
   163
    stringlist_t * keys = NULL;
vb@37
   164
vb@37
   165
    assert(session);
vb@37
   166
    assert(src);
vb@37
   167
    assert(dst);
vb@81
   168
    assert(enc_format >= PEP_enc_pieces);
vb@81
   169
vb@37
   170
    *dst = NULL;
vb@67
   171
vb@81
   172
    if (src->enc_format >= PEP_enc_pieces) {
vb@81
   173
        if (src->enc_format == enc_format) {
vb@81
   174
            msg = message_dup(src);
vb@81
   175
            if (msg == NULL)
vb@81
   176
                goto enomem;
vb@81
   177
            *dst = msg;
vb@81
   178
            return PEP_STATUS_OK;
vb@81
   179
        }
vb@81
   180
        else {
vb@81
   181
            // TODO: we don't re-encrypt yet
vb@81
   182
            NOT_IMPLEMENTED
vb@81
   183
        }
vb@67
   184
    }
vb@37
   185
vb@81
   186
    msg = clone_to_empty_message(src);
vb@80
   187
    if (msg == NULL)
vb@63
   188
        goto enomem;
vb@40
   189
vb@48
   190
    msg->enc_format = PEP_enc_pieces;
vb@37
   191
vb@80
   192
    status = myself(session, src->from);
vb@63
   193
    if (status != PEP_STATUS_OK)
vb@63
   194
        goto pep_error;
vb@37
   195
vb@80
   196
    keys = new_stringlist(src->from->fpr);
vb@63
   197
    if (keys == NULL)
vb@63
   198
        goto enomem;
vb@37
   199
vb@39
   200
    stringlist_t *_k = keys;
vb@39
   201
vb@39
   202
    if (extra) {
vb@39
   203
        _k = stringlist_append(_k, extra);
vb@63
   204
        if (_k == NULL)
vb@63
   205
            goto enomem;
vb@37
   206
    }
vb@39
   207
vb@39
   208
    bool dest_keys_found = false;
vb@37
   209
    identity_list * _il;
vb@80
   210
    for (_il = msg->to; _il && _il->ident; _il = _il->next) {
vb@63
   211
        PEP_STATUS status = update_identity(session, _il->ident);
vb@63
   212
        if (status != PEP_STATUS_OK)
vb@63
   213
            goto pep_error;
vb@63
   214
vb@37
   215
        if (_il->ident->fpr) {
vb@39
   216
            dest_keys_found = true;
vb@39
   217
            _k = stringlist_add(_k, _il->ident->fpr);
vb@63
   218
            if (_k == NULL)
vb@63
   219
                goto enomem;
vb@37
   220
        }
vb@37
   221
        else
vb@37
   222
            status = PEP_KEY_NOT_FOUND;
vb@37
   223
    }
vb@37
   224
vb@39
   225
    if (dest_keys_found) {
vb@38
   226
        char *ptext;
vb@37
   227
        char *ctext = NULL;
vb@37
   228
        size_t csize = 0;
vb@37
   229
vb@81
   230
        switch (enc_format) {
vb@44
   231
        case PEP_enc_MIME_multipart: {
vb@62
   232
            bool free_ptext = false;
vb@64
   233
vb@48
   234
            msg->enc_format = PEP_enc_MIME_multipart;
vb@37
   235
vb@63
   236
            if (src->shortmsg && strcmp(src->shortmsg, "pEp") != 0) {
vb@62
   237
                ptext = combine_short_and_long(src);
vb@63
   238
                if (ptext == NULL)
vb@63
   239
                    goto enomem;
vb@62
   240
                free_ptext = true;
vb@62
   241
            }
vb@62
   242
            else if (src->longmsg) {
vb@62
   243
                ptext = src->longmsg;
vb@62
   244
            }
vb@62
   245
vb@81
   246
            if (src->enc_format == PEP_enc_none) {
vb@67
   247
                char *_ptext = ptext;
vb@67
   248
                status = mime_encode_text(_ptext, src->longmsg_formatted,
vb@67
   249
                        src->attachments, &ptext);
vb@67
   250
                assert(status == PEP_STATUS_OK);
vb@67
   251
                if (free_ptext)
vb@67
   252
                    free(_ptext);
vb@67
   253
                assert(ptext);
vb@67
   254
                if (ptext == NULL)
vb@67
   255
                    goto pep_error;
vb@67
   256
                free_ptext = true;
vb@67
   257
            }
vb@81
   258
            else if (src->enc_format == PEP_enc_none_MIME) {
vb@67
   259
                assert(src->longmsg);
vb@67
   260
                if (src->longmsg == NULL) {
vb@67
   261
                    status = PEP_ILLEGAL_VALUE;
vb@67
   262
                    goto pep_error;
vb@67
   263
                }
vb@67
   264
                ptext = src->longmsg;
vb@67
   265
            }
vb@67
   266
vb@67
   267
            status = encrypt_and_sign(session, keys, ptext, strlen(ptext),
vb@67
   268
                    &ctext, &csize);
vb@62
   269
            if (free_ptext)
vb@62
   270
                free(ptext);
vb@62
   271
            if (ctext) {
vb@62
   272
                msg->longmsg = strdup(ctext);
vb@64
   273
                if (msg->longmsg == NULL)
vb@63
   274
                    goto enomem;
vb@63
   275
            }
vb@63
   276
            else {
vb@63
   277
                goto pep_error;
vb@62
   278
            }
vb@62
   279
        }
vb@63
   280
        break;
vb@62
   281
vb@62
   282
        case PEP_enc_pieces:
vb@64
   283
            msg->enc_format = PEP_enc_pieces;
vb@64
   284
vb@67
   285
            // TODO: decoding MIME
vb@81
   286
            if (src->enc_format == PEP_enc_none_MIME) {
vb@67
   287
                NOT_IMPLEMENTED
vb@67
   288
            }
vb@67
   289
vb@63
   290
            if (src->shortmsg && strcmp(src->shortmsg, "pEp") != 0) {
vb@62
   291
                ptext = combine_short_and_long(src);
vb@63
   292
                if (ptext == NULL)
vb@63
   293
                    goto enomem;
vb@63
   294
vb@39
   295
                status = encrypt_and_sign(session, keys, ptext, strlen(ptext),
vb@39
   296
                        &ctext, &csize);
vb@40
   297
                free(ptext);
vb@38
   298
                if (ctext) {
vb@40
   299
                    msg->longmsg = strdup(ctext);
vb@64
   300
                    if (msg->longmsg == NULL)
vb@63
   301
                        goto enomem;
vb@38
   302
                }
vb@38
   303
                else {
vb@63
   304
                    goto pep_error;
vb@38
   305
                }
vb@38
   306
            }
vb@38
   307
            else if (src->longmsg) {
vb@38
   308
                ptext = src->longmsg;
vb@39
   309
                status = encrypt_and_sign(session, keys, ptext, strlen(ptext),
vb@39
   310
                        &ctext, &csize);
vb@38
   311
                if (ctext) {
vb@40
   312
                    msg->longmsg = strdup(ctext);
vb@64
   313
                    if (msg->longmsg == NULL)
vb@63
   314
                        goto enomem;
vb@38
   315
                }
vb@38
   316
                else {
vb@63
   317
                    goto pep_error;
vb@38
   318
                }
vb@38
   319
            }
vb@63
   320
vb@63
   321
            if (msg->longmsg_formatted) {
vb@38
   322
                ptext = src->longmsg_formatted;
vb@39
   323
                status = encrypt_and_sign(session, keys, ptext, strlen(ptext),
vb@39
   324
                        &ctext, &csize);
vb@38
   325
                if (ctext) {
vb@40
   326
                    msg->longmsg_formatted = strdup(ctext);
vb@63
   327
                    if (msg->longmsg_formatted == NULL)
vb@63
   328
                        goto enomem;
vb@63
   329
                }
vb@63
   330
                else {
vb@63
   331
                    goto pep_error;
vb@63
   332
                }
vb@63
   333
            }
vb@63
   334
vb@63
   335
            if (src->attachments) {
vb@63
   336
                bloblist_t *_s;
vb@63
   337
                bloblist_t *_d = new_bloblist(NULL, 0, NULL, NULL);
vb@63
   338
                if (_d == NULL)
vb@63
   339
                    goto enomem;
vb@63
   340
vb@63
   341
                msg->attachments = _d;
vb@63
   342
                for (_s = src->attachments; _s && _s->data; _s = _s->next) {
vb@63
   343
                    int psize = _s->size;
vb@63
   344
                    ptext = _s->data;
vb@63
   345
                    status = encrypt_and_sign(session, keys, ptext, psize,
vb@63
   346
                            &ctext, &csize);
vb@63
   347
                    if (ctext) {
vb@63
   348
                        char * _c = strdup(ctext);
vb@63
   349
                        if (_c == NULL)
vb@63
   350
                            goto enomem;
vb@63
   351
vb@63
   352
                        _d = bloblist_add(_d, _c, csize, _s->mime_type,
vb@63
   353
                                _s->file_name);
vb@63
   354
                        if (_d == NULL)
vb@63
   355
                            goto enomem;
vb@63
   356
                    }
vb@63
   357
                    else {
vb@63
   358
                        goto pep_error;
vb@40
   359
                    }
vb@38
   360
                }
vb@38
   361
            }
vb@38
   362
            break;
vb@38
   363
vb@81
   364
        case PEP_enc_PEP:
vb@81
   365
            // TODO: implement
vb@81
   366
            NOT_IMPLEMENTED
vb@81
   367
vb@38
   368
        default:
vb@38
   369
            assert(0);
vb@63
   370
            status = PEP_ILLEGAL_VALUE;
vb@63
   371
            goto pep_error;
vb@37
   372
        }
vb@37
   373
    }
vb@37
   374
vb@37
   375
    free_stringlist(keys);
vb@63
   376
vb@64
   377
    if (msg->shortmsg == NULL)
vb@64
   378
        msg->shortmsg = strdup("pEp");
vb@64
   379
vb@63
   380
    *dst = msg;
vb@63
   381
    return PEP_STATUS_OK;
vb@63
   382
vb@63
   383
enomem:
vb@63
   384
    status = PEP_OUT_OF_MEMORY;
vb@63
   385
vb@63
   386
pep_error:
vb@63
   387
    free_stringlist(keys);
vb@63
   388
    free_message(msg);
vb@63
   389
vb@37
   390
    return status;
vb@37
   391
}
vb@37
   392
vb@48
   393
DYNAMIC_API PEP_STATUS decrypt_message(
vb@37
   394
        PEP_SESSION session,
vb@37
   395
        const message *src,
vb@81
   396
        message **dst,
vb@81
   397
        PEP_enc_format enc_format
vb@37
   398
    )
vb@37
   399
{
vb@37
   400
    PEP_STATUS status = PEP_STATUS_OK;
vb@73
   401
    message *msg = NULL;
vb@37
   402
vb@74
   403
    assert(session);
vb@74
   404
    assert(src);
vb@81
   405
    assert(src->dir == PEP_dir_incoming);
vb@74
   406
    assert(dst);
vb@81
   407
    assert(enc_format < PEP_enc_pieces);
vb@73
   408
vb@74
   409
    *dst = NULL;
vb@81
   410
 
vb@81
   411
    if (src->enc_format < PEP_enc_pieces) {
vb@81
   412
        if (enc_format == src->enc_format) {
vb@81
   413
            msg = message_dup(src);
vb@81
   414
            if (msg == NULL)
vb@81
   415
                goto enomem;
vb@81
   416
            *dst = msg;
vb@81
   417
            return PEP_STATUS_OK;
vb@81
   418
        }
vb@81
   419
        else {
vb@81
   420
            // TODO: we don't re-encode yet
vb@81
   421
            NOT_IMPLEMENTED
vb@81
   422
        }
vb@81
   423
    }
vb@81
   424
vb@81
   425
    msg = clone_to_empty_message(src);
vb@81
   426
    if (msg == NULL)
vb@81
   427
        goto enomem;
vb@81
   428
vb@81
   429
    switch (enc_format) {
vb@81
   430
        case PEP_enc_none:
vb@82
   431
            if (src->enc_format == PEP_enc_PEP) {
vb@82
   432
                // TODO: implement
vb@82
   433
                NOT_IMPLEMENTED
vb@82
   434
            }
vb@82
   435
vb@81
   436
            break;
vb@81
   437
vb@81
   438
        case PEP_enc_none_MIME:
vb@82
   439
            if (src->enc_format == PEP_enc_PEP) {
vb@82
   440
                // TODO: implement
vb@82
   441
                NOT_IMPLEMENTED
vb@82
   442
            }
vb@82
   443
vb@82
   444
            char *ctext = src->longmsg;
vb@82
   445
            size_t csize = strlen(src->longmsg);
vb@82
   446
            char *ptext;
vb@82
   447
            size_t psize;
vb@82
   448
            stringlist_t *keylist;
vb@82
   449
vb@82
   450
            status = decrypt_and_verify(session, ctext, csize, &ptext, &psize,
vb@82
   451
                    &keylist);
vb@82
   452
            if (ptext == NULL)
vb@82
   453
                goto pep_error;
vb@82
   454
vb@82
   455
            if (src->enc_format == PEP_enc_MIME_multipart) {
vb@82
   456
                if (src->shortmsg == NULL || strcmp(src->shortmsg, "pEp") == 0)
vb@82
   457
                {
vb@82
   458
                    char * shortmsg;
vb@82
   459
                    char * longmsg;
vb@82
   460
vb@82
   461
                    int r = seperate_short_and_long(ptext, &shortmsg,
vb@82
   462
                            &longmsg);
vb@82
   463
                    free(ptext);
vb@82
   464
                    if (r == -1)
vb@82
   465
                        goto enomem;
vb@82
   466
vb@82
   467
                    msg->shortmsg = shortmsg;
vb@82
   468
                    msg->longmsg = longmsg;
vb@82
   469
                }
vb@82
   470
                else {
vb@82
   471
                    msg->shortmsg = strdup(src->shortmsg);
vb@82
   472
                    if (msg->shortmsg == NULL)
vb@82
   473
                        goto enomem;
vb@82
   474
                    msg->longmsg = ptext;
vb@82
   475
                }
vb@82
   476
            }
vb@82
   477
            else {
vb@82
   478
                
vb@82
   479
            }
vb@81
   480
            break;
vb@81
   481
vb@81
   482
        default:
vb@81
   483
            assert(0);
vb@81
   484
            status = PEP_ILLEGAL_VALUE;
vb@81
   485
            goto pep_error;
vb@81
   486
    }
vb@74
   487
vb@74
   488
    *dst = msg;
vb@74
   489
    return PEP_STATUS_OK;
vb@73
   490
vb@73
   491
enomem:
vb@73
   492
    status = PEP_OUT_OF_MEMORY;
vb@73
   493
vb@73
   494
pep_error:
vb@73
   495
    free_message(msg);
vb@39
   496
vb@37
   497
    return status;
vb@37
   498
}
vb@37
   499