src/message_api.c
author vb
Sun, 01 Mar 2015 15:32:16 +0100
changeset 81 044ce1c7fc9c
parent 80 b12ce95403a1
child 82 d0ad5655688a
permissions -rw-r--r--
...
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@81
    36
static message * clone_to_empty_message(const message * src)
vb@80
    37
{
vb@80
    38
    pEp_identity *from = NULL;
vb@80
    39
    identity_list *to = NULL;
vb@81
    40
vb@80
    41
    message * msg = NULL;
vb@80
    42
vb@81
    43
    assert(src);
vb@81
    44
    assert(src->from);
vb@81
    45
    assert(src->to);
vb@81
    46
vb@81
    47
    msg->dir = src->dir;
vb@81
    48
vb@80
    49
    from = identity_dup(src->from);
vb@80
    50
    if (from == NULL)
vb@80
    51
        goto enomem;
vb@80
    52
vb@80
    53
    from->me = true;
vb@80
    54
vb@80
    55
    to = identity_list_dup(src->to);
vb@80
    56
    if (to == NULL)
vb@80
    57
        goto enomem;
vb@80
    58
vb@80
    59
    msg = new_message(src->dir, from, to, NULL);
vb@80
    60
    if (msg == NULL)
vb@80
    61
        goto enomem;
vb@80
    62
vb@81
    63
    if (src->cc) {
vb@81
    64
        msg->cc = identity_list_dup(src->cc);
vb@81
    65
        if (msg->cc == NULL)
vb@81
    66
            goto enomem;
vb@81
    67
    }
vb@81
    68
vb@81
    69
    if (src->bcc) {
vb@81
    70
        msg->bcc = identity_list_dup(src->bcc);
vb@81
    71
        if (msg->bcc == NULL)
vb@81
    72
            goto enomem;
vb@81
    73
    }
vb@81
    74
vb@81
    75
    if (src->reply_to) {
vb@81
    76
        msg->reply_to = identity_dup(src->reply_to);
vb@81
    77
        if (msg->reply_to == NULL)
vb@81
    78
            goto enomem;
vb@81
    79
    }
vb@81
    80
vb@81
    81
    msg->sent = src->sent;
vb@81
    82
    msg->recv = src->recv;
vb@81
    83
vb@80
    84
    return msg;
vb@80
    85
vb@80
    86
enomem:
vb@81
    87
    if (msg) {
vb@81
    88
        free_message(msg);
vb@81
    89
    }
vb@81
    90
    else {
vb@81
    91
        free_identity(from);
vb@81
    92
        free_identity_list(to);
vb@81
    93
    }
vb@81
    94
vb@80
    95
    return NULL;
vb@80
    96
}
vb@80
    97
vb@48
    98
DYNAMIC_API PEP_STATUS encrypt_message(
vb@37
    99
        PEP_SESSION session,
vb@37
   100
        const message *src,
vb@37
   101
        stringlist_t * extra,
vb@38
   102
        message **dst,
vb@81
   103
        PEP_enc_format enc_format
vb@37
   104
    )
vb@37
   105
{
vb@37
   106
    PEP_STATUS status = PEP_STATUS_OK;
vb@63
   107
    message * msg = NULL;
vb@63
   108
    stringlist_t * keys = NULL;
vb@37
   109
vb@37
   110
    assert(session);
vb@37
   111
    assert(src);
vb@37
   112
    assert(dst);
vb@81
   113
    assert(enc_format >= PEP_enc_pieces);
vb@81
   114
vb@37
   115
    *dst = NULL;
vb@67
   116
vb@81
   117
    if (src->enc_format >= PEP_enc_pieces) {
vb@81
   118
        if (src->enc_format == enc_format) {
vb@81
   119
            msg = message_dup(src);
vb@81
   120
            if (msg == NULL)
vb@81
   121
                goto enomem;
vb@81
   122
            *dst = msg;
vb@81
   123
            return PEP_STATUS_OK;
vb@81
   124
        }
vb@81
   125
        else {
vb@81
   126
            // TODO: we don't re-encrypt yet
vb@81
   127
            NOT_IMPLEMENTED
vb@81
   128
        }
vb@67
   129
    }
vb@37
   130
vb@81
   131
    msg = clone_to_empty_message(src);
vb@80
   132
    if (msg == NULL)
vb@63
   133
        goto enomem;
vb@40
   134
vb@48
   135
    msg->enc_format = PEP_enc_pieces;
vb@37
   136
vb@80
   137
    status = myself(session, src->from);
vb@63
   138
    if (status != PEP_STATUS_OK)
vb@63
   139
        goto pep_error;
vb@37
   140
vb@80
   141
    keys = new_stringlist(src->from->fpr);
vb@63
   142
    if (keys == NULL)
vb@63
   143
        goto enomem;
vb@37
   144
vb@39
   145
    stringlist_t *_k = keys;
vb@39
   146
vb@39
   147
    if (extra) {
vb@39
   148
        _k = stringlist_append(_k, extra);
vb@63
   149
        if (_k == NULL)
vb@63
   150
            goto enomem;
vb@37
   151
    }
vb@39
   152
vb@39
   153
    bool dest_keys_found = false;
vb@37
   154
    identity_list * _il;
vb@80
   155
    for (_il = msg->to; _il && _il->ident; _il = _il->next) {
vb@63
   156
        PEP_STATUS status = update_identity(session, _il->ident);
vb@63
   157
        if (status != PEP_STATUS_OK)
vb@63
   158
            goto pep_error;
vb@63
   159
vb@37
   160
        if (_il->ident->fpr) {
vb@39
   161
            dest_keys_found = true;
vb@39
   162
            _k = stringlist_add(_k, _il->ident->fpr);
vb@63
   163
            if (_k == NULL)
vb@63
   164
                goto enomem;
vb@37
   165
        }
vb@37
   166
        else
vb@37
   167
            status = PEP_KEY_NOT_FOUND;
vb@37
   168
    }
vb@37
   169
vb@39
   170
    if (dest_keys_found) {
vb@38
   171
        char *ptext;
vb@37
   172
        char *ctext = NULL;
vb@37
   173
        size_t csize = 0;
vb@37
   174
vb@81
   175
        switch (enc_format) {
vb@44
   176
        case PEP_enc_MIME_multipart: {
vb@62
   177
            bool free_ptext = false;
vb@64
   178
vb@48
   179
            msg->enc_format = PEP_enc_MIME_multipart;
vb@37
   180
vb@63
   181
            if (src->shortmsg && strcmp(src->shortmsg, "pEp") != 0) {
vb@62
   182
                ptext = combine_short_and_long(src);
vb@63
   183
                if (ptext == NULL)
vb@63
   184
                    goto enomem;
vb@62
   185
                free_ptext = true;
vb@62
   186
            }
vb@62
   187
            else if (src->longmsg) {
vb@62
   188
                ptext = src->longmsg;
vb@62
   189
            }
vb@62
   190
vb@81
   191
            if (src->enc_format == PEP_enc_none) {
vb@67
   192
                char *_ptext = ptext;
vb@67
   193
                status = mime_encode_text(_ptext, src->longmsg_formatted,
vb@67
   194
                        src->attachments, &ptext);
vb@67
   195
                assert(status == PEP_STATUS_OK);
vb@67
   196
                if (free_ptext)
vb@67
   197
                    free(_ptext);
vb@67
   198
                assert(ptext);
vb@67
   199
                if (ptext == NULL)
vb@67
   200
                    goto pep_error;
vb@67
   201
                free_ptext = true;
vb@67
   202
            }
vb@81
   203
            else if (src->enc_format == PEP_enc_none_MIME) {
vb@67
   204
                assert(src->longmsg);
vb@67
   205
                if (src->longmsg == NULL) {
vb@67
   206
                    status = PEP_ILLEGAL_VALUE;
vb@67
   207
                    goto pep_error;
vb@67
   208
                }
vb@67
   209
                ptext = src->longmsg;
vb@67
   210
            }
vb@67
   211
vb@67
   212
            status = encrypt_and_sign(session, keys, ptext, strlen(ptext),
vb@67
   213
                    &ctext, &csize);
vb@62
   214
            if (free_ptext)
vb@62
   215
                free(ptext);
vb@62
   216
            if (ctext) {
vb@62
   217
                msg->longmsg = strdup(ctext);
vb@64
   218
                if (msg->longmsg == NULL)
vb@63
   219
                    goto enomem;
vb@63
   220
            }
vb@63
   221
            else {
vb@63
   222
                goto pep_error;
vb@62
   223
            }
vb@62
   224
        }
vb@63
   225
        break;
vb@62
   226
vb@62
   227
        case PEP_enc_pieces:
vb@64
   228
            msg->enc_format = PEP_enc_pieces;
vb@64
   229
vb@67
   230
            // TODO: decoding MIME
vb@81
   231
            if (src->enc_format == PEP_enc_none_MIME) {
vb@67
   232
                NOT_IMPLEMENTED
vb@67
   233
            }
vb@67
   234
vb@63
   235
            if (src->shortmsg && strcmp(src->shortmsg, "pEp") != 0) {
vb@62
   236
                ptext = combine_short_and_long(src);
vb@63
   237
                if (ptext == NULL)
vb@63
   238
                    goto enomem;
vb@63
   239
vb@39
   240
                status = encrypt_and_sign(session, keys, ptext, strlen(ptext),
vb@39
   241
                        &ctext, &csize);
vb@40
   242
                free(ptext);
vb@38
   243
                if (ctext) {
vb@40
   244
                    msg->longmsg = strdup(ctext);
vb@64
   245
                    if (msg->longmsg == NULL)
vb@63
   246
                        goto enomem;
vb@38
   247
                }
vb@38
   248
                else {
vb@63
   249
                    goto pep_error;
vb@38
   250
                }
vb@38
   251
            }
vb@38
   252
            else if (src->longmsg) {
vb@38
   253
                ptext = src->longmsg;
vb@39
   254
                status = encrypt_and_sign(session, keys, ptext, strlen(ptext),
vb@39
   255
                        &ctext, &csize);
vb@38
   256
                if (ctext) {
vb@40
   257
                    msg->longmsg = strdup(ctext);
vb@64
   258
                    if (msg->longmsg == NULL)
vb@63
   259
                        goto enomem;
vb@38
   260
                }
vb@38
   261
                else {
vb@63
   262
                    goto pep_error;
vb@38
   263
                }
vb@38
   264
            }
vb@63
   265
vb@63
   266
            if (msg->longmsg_formatted) {
vb@38
   267
                ptext = src->longmsg_formatted;
vb@39
   268
                status = encrypt_and_sign(session, keys, ptext, strlen(ptext),
vb@39
   269
                        &ctext, &csize);
vb@38
   270
                if (ctext) {
vb@40
   271
                    msg->longmsg_formatted = strdup(ctext);
vb@63
   272
                    if (msg->longmsg_formatted == NULL)
vb@63
   273
                        goto enomem;
vb@63
   274
                }
vb@63
   275
                else {
vb@63
   276
                    goto pep_error;
vb@63
   277
                }
vb@63
   278
            }
vb@63
   279
vb@63
   280
            if (src->attachments) {
vb@63
   281
                bloblist_t *_s;
vb@63
   282
                bloblist_t *_d = new_bloblist(NULL, 0, NULL, NULL);
vb@63
   283
                if (_d == NULL)
vb@63
   284
                    goto enomem;
vb@63
   285
vb@63
   286
                msg->attachments = _d;
vb@63
   287
                for (_s = src->attachments; _s && _s->data; _s = _s->next) {
vb@63
   288
                    int psize = _s->size;
vb@63
   289
                    ptext = _s->data;
vb@63
   290
                    status = encrypt_and_sign(session, keys, ptext, psize,
vb@63
   291
                            &ctext, &csize);
vb@63
   292
                    if (ctext) {
vb@63
   293
                        char * _c = strdup(ctext);
vb@63
   294
                        if (_c == NULL)
vb@63
   295
                            goto enomem;
vb@63
   296
vb@63
   297
                        _d = bloblist_add(_d, _c, csize, _s->mime_type,
vb@63
   298
                                _s->file_name);
vb@63
   299
                        if (_d == NULL)
vb@63
   300
                            goto enomem;
vb@63
   301
                    }
vb@63
   302
                    else {
vb@63
   303
                        goto pep_error;
vb@40
   304
                    }
vb@38
   305
                }
vb@38
   306
            }
vb@38
   307
            break;
vb@38
   308
vb@81
   309
        case PEP_enc_PEP:
vb@81
   310
            // TODO: implement
vb@81
   311
            NOT_IMPLEMENTED
vb@81
   312
vb@38
   313
        default:
vb@38
   314
            assert(0);
vb@63
   315
            status = PEP_ILLEGAL_VALUE;
vb@63
   316
            goto pep_error;
vb@37
   317
        }
vb@37
   318
    }
vb@37
   319
vb@37
   320
    free_stringlist(keys);
vb@63
   321
vb@64
   322
    if (msg->shortmsg == NULL)
vb@64
   323
        msg->shortmsg = strdup("pEp");
vb@64
   324
vb@63
   325
    *dst = msg;
vb@63
   326
    return PEP_STATUS_OK;
vb@63
   327
vb@63
   328
enomem:
vb@63
   329
    status = PEP_OUT_OF_MEMORY;
vb@63
   330
vb@63
   331
pep_error:
vb@63
   332
    free_stringlist(keys);
vb@63
   333
    free_message(msg);
vb@63
   334
vb@37
   335
    return status;
vb@37
   336
}
vb@37
   337
vb@48
   338
DYNAMIC_API PEP_STATUS decrypt_message(
vb@37
   339
        PEP_SESSION session,
vb@37
   340
        const message *src,
vb@81
   341
        message **dst,
vb@81
   342
        PEP_enc_format enc_format
vb@37
   343
    )
vb@37
   344
{
vb@37
   345
    PEP_STATUS status = PEP_STATUS_OK;
vb@73
   346
    message *msg = NULL;
vb@37
   347
vb@74
   348
    assert(session);
vb@74
   349
    assert(src);
vb@81
   350
    assert(src->dir == PEP_dir_incoming);
vb@74
   351
    assert(dst);
vb@81
   352
    assert(enc_format < PEP_enc_pieces);
vb@73
   353
vb@74
   354
    *dst = NULL;
vb@81
   355
 
vb@81
   356
    if (src->enc_format < PEP_enc_pieces) {
vb@81
   357
        if (enc_format == src->enc_format) {
vb@81
   358
            msg = message_dup(src);
vb@81
   359
            if (msg == NULL)
vb@81
   360
                goto enomem;
vb@81
   361
            *dst = msg;
vb@81
   362
            return PEP_STATUS_OK;
vb@81
   363
        }
vb@81
   364
        else {
vb@81
   365
            // TODO: we don't re-encode yet
vb@81
   366
            NOT_IMPLEMENTED
vb@81
   367
        }
vb@81
   368
    }
vb@81
   369
vb@81
   370
    msg = clone_to_empty_message(src);
vb@81
   371
    if (msg == NULL)
vb@81
   372
        goto enomem;
vb@81
   373
vb@81
   374
    switch (enc_format) {
vb@81
   375
        case PEP_enc_none:
vb@81
   376
            break;
vb@81
   377
vb@81
   378
        case PEP_enc_none_MIME:
vb@81
   379
            break;
vb@81
   380
vb@81
   381
        default:
vb@81
   382
            assert(0);
vb@81
   383
            status = PEP_ILLEGAL_VALUE;
vb@81
   384
            goto pep_error;
vb@81
   385
    }
vb@74
   386
vb@74
   387
    *dst = msg;
vb@74
   388
    return PEP_STATUS_OK;
vb@73
   389
vb@73
   390
enomem:
vb@73
   391
    status = PEP_OUT_OF_MEMORY;
vb@73
   392
vb@73
   393
pep_error:
vb@73
   394
    free_message(msg);
vb@39
   395
vb@37
   396
    return status;
vb@37
   397
}
vb@37
   398