src/etpan_mime.c
author Jorg Knobloch
Thu, 30 Jul 2020 22:50:42 +0200
branchENGINE-780-take2
changeset 4910 347f8b793204
parent 4907 86b71e72bc2b
child 4931 32b67d57d6ef
child 4943 c239a39e34e3
child 5203 409acbc8b230
permissions -rw-r--r--
ENGINE-780, take 2: After normalizing to UTC, forget the offset.
vb@1513
     1
// This file is under GNU General Public License 3.0
vb@1513
     2
// see LICENSE.txt
vb@1513
     3
vb@48
     4
#include "etpan_mime.h"
vb@62
     5
#ifndef mailmime_param_new_with_data
vb@62
     6
#include <libetpan/mailprivacy_tools.h>
vb@62
     7
#endif
vb@48
     8
vb@3439
     9
#include "pEp_internal.h"
vb@130
    10
#include "platform.h"
vb@3439
    11
#include "mime.h"
vb@3439
    12
#include "wrappers.h"
vb@3439
    13
#include "resource_id.h"
vb@130
    14
vb@130
    15
#include <string.h>
vb@130
    16
#include <stdlib.h>
vb@130
    17
#include <assert.h>
vb@157
    18
#include <errno.h>
vb@89
    19
roker@438
    20
#define MAX_MESSAGE_ID 128
vb@48
    21
vb@116
    22
static char * generate_boundary(void)
vb@48
    23
{
vb@48
    24
    char id[MAX_MESSAGE_ID];
vb@54
    25
roker@438
    26
    // no cryptographically strong random needed here
roker@438
    27
    const long value1 = random();
roker@438
    28
    const long value2 = random();
roker@438
    29
    const long value3 = random();
roker@438
    30
    const long value4 = random();
vb@90
    31
vb@116
    32
    snprintf(id, MAX_MESSAGE_ID, "%.4lx%.4lx%.4lx%.4lx", value1, value2,
vb@116
    33
            value3, value4);
vb@48
    34
    
vb@48
    35
    return strdup(id);
vb@48
    36
}
vb@48
    37
vb@48
    38
struct mailmime * part_new_empty(
vb@48
    39
        struct mailmime_content * content,
vb@48
    40
        struct mailmime_fields * mime_fields,
krista@3710
    41
        stringpair_list_t* param_keyvals,
vb@48
    42
        int force_single
vb@48
    43
    )
vb@48
    44
{
krista@2688
    45
    struct mailmime * build_info;
krista@2688
    46
    clist * list = NULL;
krista@2688
    47
    int r;
krista@2688
    48
    int mime_type;
vb@115
    49
    char * attr_name = NULL;
vb@115
    50
    char * attr_value = NULL;
vb@115
    51
    struct mailmime_parameter * param = NULL;
vb@115
    52
    clist * parameters = NULL;
vb@116
    53
    char *boundary = NULL;
vb@48
    54
krista@2688
    55
    list = NULL;
vb@48
    56
krista@2688
    57
    if (force_single) {
krista@2688
    58
        mime_type = MAILMIME_SINGLE;
krista@2688
    59
    }
krista@2688
    60
    else {
krista@2688
    61
        switch (content->ct_type->tp_type) {
krista@2688
    62
            case MAILMIME_TYPE_DISCRETE_TYPE:
vb@115
    63
                mime_type = MAILMIME_SINGLE;
vb@115
    64
                break;
vb@48
    65
krista@2688
    66
            case MAILMIME_TYPE_COMPOSITE_TYPE:
vb@115
    67
                switch (content->ct_type->tp_data.tp_composite_type->ct_type) {
vb@115
    68
                    case MAILMIME_COMPOSITE_TYPE_MULTIPART:
vb@115
    69
                        mime_type = MAILMIME_MULTIPLE;
vb@115
    70
                        break;
vb@48
    71
vb@115
    72
                    case MAILMIME_COMPOSITE_TYPE_MESSAGE:
vb@115
    73
                        if (strcasecmp(content->ct_subtype, "rfc822") == 0)
vb@115
    74
                            mime_type = MAILMIME_MESSAGE;
vb@115
    75
                        else
vb@115
    76
                            mime_type = MAILMIME_SINGLE;
vb@115
    77
                        break;
vb@48
    78
vb@115
    79
                    default:
vb@115
    80
                        goto enomem;
vb@115
    81
                }
vb@115
    82
                break;
vb@48
    83
krista@2688
    84
            default:
vb@115
    85
                goto enomem;
krista@2688
    86
        }
krista@2688
    87
    }
vb@48
    88
krista@2688
    89
    if (mime_type == MAILMIME_MULTIPLE) {
krista@2688
    90
        list = clist_new();
vb@115
    91
        assert(list);
krista@2688
    92
        if (list == NULL)
krista@2688
    93
            goto enomem;
vb@48
    94
krista@2688
    95
        attr_name = strdup("boundary");
vb@115
    96
        assert(attr_name);
vb@115
    97
        if (attr_name == NULL)
vb@115
    98
            goto enomem;
vb@115
    99
krista@2688
   100
        boundary = generate_boundary();
vb@115
   101
        assert(boundary);
krista@2688
   102
        attr_value = boundary;
krista@2688
   103
        if (attr_value == NULL)
krista@2688
   104
            goto enomem;
vb@48
   105
krista@2688
   106
        param = mailmime_parameter_new(attr_name, attr_value);
vb@115
   107
        assert(param);
krista@2688
   108
        if (param == NULL)
krista@2688
   109
            goto enomem;
vb@115
   110
        attr_name = NULL;
vb@115
   111
        attr_value = NULL;
vb@48
   112
krista@2688
   113
        if (content->ct_parameters == NULL) {
krista@2688
   114
            parameters = clist_new();
vb@115
   115
            assert(parameters);
krista@2688
   116
            if (parameters == NULL)
krista@2688
   117
                goto enomem;
krista@2688
   118
        }
krista@2688
   119
        else {
krista@2688
   120
            parameters = content->ct_parameters;
vb@115
   121
        }
vb@48
   122
krista@2688
   123
        r = clist_append(parameters, param);
krista@2688
   124
        if (r)
krista@2688
   125
            goto enomem;
vb@115
   126
        param = NULL;
vb@48
   127
krista@2688
   128
        if (content->ct_parameters == NULL)
krista@2688
   129
            content->ct_parameters = parameters;
krista@2688
   130
    }
krista@3710
   131
    
krista@3710
   132
    if (param_keyvals) {
krista@3710
   133
        stringpair_list_t* cur;
krista@3710
   134
        for (cur = param_keyvals; cur; cur = cur->next) {
krista@3710
   135
            attr_name = strdup(cur->value->key);
krista@3710
   136
            attr_value = strdup(cur->value->value);
krista@3710
   137
            
krista@3710
   138
            param = mailmime_parameter_new(attr_name, attr_value);
krista@3710
   139
            assert(param);
krista@3710
   140
            if (param == NULL)
krista@3710
   141
                goto enomem;
krista@3710
   142
                
krista@3710
   143
            attr_name = NULL;
krista@3710
   144
            attr_value = NULL;
krista@3710
   145
krista@3710
   146
            if (content->ct_parameters == NULL) {
krista@3710
   147
                parameters = clist_new();
krista@3710
   148
                assert(parameters);
krista@3710
   149
                if (parameters == NULL)
krista@3710
   150
                    goto enomem;
krista@3710
   151
            }
krista@3710
   152
            else {
krista@3710
   153
                parameters = content->ct_parameters;
krista@3710
   154
            }
krista@3710
   155
krista@3710
   156
            r = clist_append(parameters, param);
krista@3710
   157
            if (r)
krista@3710
   158
                goto enomem;
krista@3710
   159
            param = NULL;
krista@3710
   160
krista@3710
   161
            if (content->ct_parameters == NULL)
krista@3710
   162
                content->ct_parameters = parameters;            
krista@3710
   163
        }
krista@3710
   164
    }
vb@48
   165
vb@115
   166
    build_info = mailmime_new(mime_type, NULL, 0, mime_fields, content, NULL,
vb@115
   167
            NULL, NULL, list, NULL, NULL);
krista@2688
   168
    if (build_info == NULL)
krista@2688
   169
        goto enomem;
vb@48
   170
krista@2688
   171
    return build_info;
vb@48
   172
vb@115
   173
enomem:
vb@115
   174
    if (list)
vb@115
   175
        clist_free(list);
vb@115
   176
    free(attr_name);
vb@115
   177
    free(attr_value);
vb@115
   178
    if (content->ct_parameters == NULL)
vb@115
   179
        if (parameters)
vb@115
   180
            clist_free(parameters);
krista@819
   181
    if (param)
krista@819
   182
        mailmime_parameter_free(param);
krista@2688
   183
    return NULL;
vb@48
   184
}
vb@48
   185
vb@114
   186
struct mailmime * get_pgp_encrypted_part(void)
vb@114
   187
{
krista@2688
   188
    struct mailmime * mime = NULL;
krista@2688
   189
    struct mailmime_fields * mime_fields = NULL;
krista@2688
   190
    struct mailmime_content * content = NULL;
vb@115
   191
    int r;
vb@114
   192
krista@2688
   193
    content = mailmime_content_new_with_str("application/pgp-encrypted");
vb@115
   194
    if (content == NULL)
vb@115
   195
        goto enomem;
vb@115
   196
vb@114
   197
    mime_fields = mailmime_fields_new_empty();
vb@115
   198
    if (mime_fields == NULL)
vb@115
   199
        goto enomem;
vb@115
   200
krista@3710
   201
    mime = part_new_empty(content, mime_fields, NULL, 1);
vb@115
   202
    if (mime == NULL)
vb@115
   203
        goto enomem;
vb@115
   204
    mime_fields = NULL;
vb@115
   205
    content = NULL;
vb@115
   206
vb@115
   207
    r = mailmime_set_body_text(mime, "Version: 1\n", 10);
vb@115
   208
    if (r != 0)
vb@115
   209
        goto enomem;
vb@114
   210
krista@2688
   211
    return mime;
vb@115
   212
vb@115
   213
enomem:
vb@115
   214
    if (content)
vb@115
   215
        mailmime_content_free(content);
vb@115
   216
    if (mime_fields)
vb@115
   217
        mailmime_fields_free(mime_fields);
vb@115
   218
    if (mime)
vb@115
   219
        mailmime_free(mime);
vb@115
   220
vb@115
   221
    return NULL;
vb@114
   222
}
vb@114
   223
vb@48
   224
struct mailmime * get_text_part(
krista@1878
   225
        pEp_rid_list_t* resource,
vb@48
   226
        const char * mime_type,
vb@48
   227
        const char * text,
vb@48
   228
        size_t length,
vb@48
   229
        int encoding_type
vb@48
   230
    )
vb@48
   231
{
vb@114
   232
    char * disposition_name = NULL;
krista@2688
   233
    struct mailmime_fields * mime_fields = NULL;
krista@2688
   234
    struct mailmime * mime = NULL;
krista@2688
   235
    struct mailmime_content * content = NULL;
krista@2688
   236
    struct mailmime_parameter * param = NULL;
krista@2688
   237
    struct mailmime_disposition * disposition = NULL;
krista@2688
   238
    struct mailmime_mechanism * encoding = NULL;
krista@1878
   239
    char* content_id = NULL;
vb@115
   240
    int r;
krista@1878
   241
                
krista@1878
   242
    if (resource != NULL && resource->rid != NULL) {
krista@1878
   243
        switch (resource->rid_type) {
krista@1878
   244
            case PEP_RID_CID:
krista@1878
   245
                content_id = strdup(resource->rid);
krista@1878
   246
                break;
krista@1878
   247
            case PEP_RID_FILENAME:
krista@1878
   248
            default:
krista@1878
   249
                disposition_name = strdup(resource->rid);
krista@1878
   250
                if (disposition_name == NULL)
krista@1878
   251
                    goto enomem;
krista@1878
   252
                    
krista@1878
   253
                disposition =
krista@1878
   254
                        mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
krista@1878
   255
                                disposition_name, NULL, NULL, NULL, (size_t) -1);
krista@1878
   256
krista@1878
   257
                if (disposition == NULL)
krista@1878
   258
                    goto enomem;
krista@1878
   259
krista@1878
   260
                disposition_name = NULL;                
krista@1878
   261
                break;
krista@1878
   262
        }    
krista@1878
   263
    }
vb@48
   264
    
vb@115
   265
    if (encoding_type) {
vb@114
   266
        encoding = mailmime_mechanism_new(encoding_type, NULL);
vb@115
   267
        if (encoding == NULL)
vb@115
   268
            goto enomem;
vb@115
   269
    }
vb@114
   270
krista@1878
   271
    mime_fields = mailmime_fields_new_with_data(encoding, content_id, NULL,
vb@115
   272
            disposition, NULL);
vb@115
   273
    if (mime_fields == NULL)
vb@115
   274
        goto enomem;
vb@115
   275
    encoding = NULL;
vb@115
   276
    disposition = NULL;
krista@1878
   277
    content_id = NULL;
vb@48
   278
krista@2688
   279
    content = mailmime_content_new_with_str(mime_type);
vb@115
   280
    if (content == NULL)
vb@115
   281
        goto enomem;
vb@114
   282
    
vb@114
   283
    if (encoding_type != MAILMIME_MECHANISM_7BIT) {
vb@114
   284
        param = mailmime_param_new_with_data("charset", "utf-8");
vb@115
   285
        r = clist_append(content->ct_parameters, param);
vb@115
   286
        if (r != 0)
vb@115
   287
            goto enomem;
vb@114
   288
    }
vb@114
   289
krista@3710
   290
    mime = part_new_empty(content, mime_fields, NULL, 1);
vb@115
   291
    if (mime == NULL)
vb@115
   292
        goto enomem;
vb@115
   293
    content = NULL;
vb@115
   294
    mime_fields = NULL;
vb@114
   295
vb@115
   296
    if (text) {
vb@115
   297
        r = mailmime_set_body_text(mime, (char *) text, length);
vb@115
   298
        if (r != 0)
vb@115
   299
            goto enomem;
vb@115
   300
    }
krista@2688
   301
    
krista@2688
   302
    return mime;
vb@115
   303
vb@115
   304
enomem:
vb@115
   305
    free(disposition_name);
vb@115
   306
    if (mime_fields)
vb@115
   307
        mailmime_fields_free(mime_fields);
vb@115
   308
    if (mime)
vb@115
   309
        mailmime_free(mime);
vb@115
   310
    if (content)
vb@115
   311
        mailmime_content_free(content);
vb@115
   312
    if (param)
vb@115
   313
        mailmime_parameter_free(param);
vb@115
   314
    if (disposition)
vb@115
   315
        mailmime_disposition_free(disposition);
vb@115
   316
    if (encoding)
vb@115
   317
        mailmime_mechanism_free(encoding);
vb@115
   318
vb@115
   319
    return NULL;
vb@48
   320
}
vb@48
   321
vb@59
   322
struct mailmime * get_file_part(
krista@1878
   323
        pEp_rid_list_t* resource,
vb@59
   324
        const char * mime_type,
vb@59
   325
        char * data,
krista@2200
   326
        size_t length,
krista@4590
   327
        bool is_nf_message_attachment // non-forwarded msg as att
vb@59
   328
    )
vb@59
   329
{
vb@115
   330
    char * disposition_name = NULL;
vb@59
   331
    int encoding_type;
vb@115
   332
    struct mailmime_disposition * disposition = NULL;
vb@115
   333
    struct mailmime_mechanism * encoding = NULL;
vb@115
   334
    struct mailmime_content * content = NULL;
vb@115
   335
    struct mailmime * mime = NULL;
vb@115
   336
    struct mailmime_fields * mime_fields = NULL;
krista@1878
   337
    char* content_id = NULL;
vb@115
   338
    int r;
krista@1878
   339
                
krista@1878
   340
    if (resource != NULL && resource->rid != NULL) {
krista@1878
   341
        switch (resource->rid_type) {
krista@1878
   342
            case PEP_RID_CID:
krista@1878
   343
                content_id = strdup(resource->rid);
krista@2011
   344
                disposition =
krista@2011
   345
                    mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_INLINE,
krista@2011
   346
                                                       NULL, NULL, NULL, NULL, (size_t) -1);
krista@2011
   347
                    if (disposition == NULL)
krista@2011
   348
                        goto enomem;
krista@1878
   349
                break;
krista@1878
   350
            case PEP_RID_FILENAME:
krista@1878
   351
            default:
krista@1878
   352
                disposition_name = strdup(resource->rid);
krista@1878
   353
                if (disposition_name == NULL)
krista@1878
   354
                    goto enomem;
krista@1878
   355
                    
krista@1878
   356
                disposition =
krista@1878
   357
                        mailmime_disposition_new_with_data(MAILMIME_DISPOSITION_TYPE_ATTACHMENT,
krista@1878
   358
                                disposition_name, NULL, NULL, NULL, (size_t) -1);
krista@1878
   359
                                
krista@1878
   360
                if (disposition == NULL)
krista@1878
   361
                    goto enomem;
krista@1878
   362
                disposition_name = NULL;
krista@1878
   363
                
krista@1878
   364
                break;
krista@1878
   365
        }    
vb@59
   366
    }
krista@1878
   367
    
vb@115
   368
vb@59
   369
    content = mailmime_content_new_with_str(mime_type);
vb@115
   370
    if (content == NULL)
vb@115
   371
        goto enomem;
vb@59
   372
krista@2200
   373
    encoding = NULL;
krista@2200
   374
krista@4590
   375
    bool already_ascii = !(must_chunk_be_encoded(data, length, true));
krista@4590
   376
    
krista@4590
   377
    if (!is_nf_message_attachment && !already_ascii) {
krista@2200
   378
        encoding_type = MAILMIME_MECHANISM_BASE64;
krista@2200
   379
        encoding = mailmime_mechanism_new(encoding_type, NULL);
krista@2200
   380
        if (encoding == NULL)
krista@2200
   381
            goto enomem;
krista@2200
   382
    }
vb@115
   383
krista@1878
   384
    mime_fields = mailmime_fields_new_with_data(encoding, content_id, NULL,
vb@115
   385
            disposition, NULL);
vb@115
   386
    if (mime_fields == NULL)
vb@115
   387
        goto enomem;
vb@115
   388
    encoding = NULL;
vb@115
   389
    disposition = NULL;
vb@115
   390
krista@3710
   391
    stringpair_list_t* extra_params = NULL;
krista@3710
   392
    
krista@4590
   393
    if (is_nf_message_attachment)
krista@3729
   394
        extra_params = new_stringpair_list(new_stringpair("forwarded", "no"));
krista@3710
   395
    
krista@3710
   396
    mime = part_new_empty(content, mime_fields, extra_params, 1);
krista@3710
   397
    free_stringpair_list(extra_params);
vb@115
   398
    if (mime == NULL)
vb@115
   399
        goto enomem;
vb@115
   400
    content = NULL;
vb@115
   401
    mime_fields = NULL;
vb@115
   402
Edouard@747
   403
    if(length > 0)
Edouard@747
   404
    {
Edouard@747
   405
        r = mailmime_set_body_text(mime, data, length);
Edouard@747
   406
        if (r != 0)
Edouard@747
   407
            goto enomem;
Edouard@747
   408
    }
vb@59
   409
vb@59
   410
    return mime;
vb@115
   411
vb@115
   412
enomem:
vb@115
   413
    free(disposition_name);
vb@115
   414
    if (disposition)
vb@115
   415
        mailmime_disposition_free(disposition);
vb@115
   416
    if (encoding)
vb@115
   417
        mailmime_mechanism_free(encoding);
vb@115
   418
    if (content)
vb@115
   419
        mailmime_content_free(content);
vb@115
   420
    if (mime_fields)
vb@115
   421
        mailmime_fields_free(mime_fields);
vb@115
   422
    if (mime)
vb@115
   423
        mailmime_free(mime);
krista@1878
   424
    
vb@115
   425
    return NULL;
vb@59
   426
}
vb@59
   427
vb@116
   428
struct mailmime * part_multiple_new(const char *type)
vb@48
   429
{
vb@115
   430
    struct mailmime_fields *mime_fields = NULL;
vb@115
   431
    struct mailmime_content *content = NULL;
vb@115
   432
    struct mailmime *mp = NULL;
vb@48
   433
    
vb@48
   434
    mime_fields = mailmime_fields_new_empty();
vb@48
   435
    if (mime_fields == NULL)
vb@115
   436
        goto enomem;
vb@48
   437
    
vb@48
   438
    content = mailmime_content_new_with_str(type);
vb@48
   439
    if (content == NULL)
vb@115
   440
        goto enomem;
vb@48
   441
    
krista@3710
   442
    mp = part_new_empty(content, mime_fields, NULL, 0);
vb@48
   443
    if (mp == NULL)
vb@115
   444
        goto enomem;
vb@48
   445
    
vb@48
   446
    return mp;
vb@48
   447
    
vb@115
   448
enomem:
vb@115
   449
    if (content)
vb@115
   450
        mailmime_content_free(content);
vb@115
   451
    if (mime_fields)
vb@115
   452
        mailmime_fields_free(mime_fields);
vb@115
   453
vb@48
   454
    return NULL;
vb@48
   455
}
vb@48
   456
vb@89
   457
struct mailimf_field * _new_field(
vb@89
   458
        int type,
vb@89
   459
        _new_func_t new_func,
vb@89
   460
        void *value
vb@89
   461
    )
vb@89
   462
{
vb@89
   463
    void *data = new_func(value);
vb@89
   464
    assert(data);
vb@89
   465
    if (data == NULL)
vb@89
   466
        return NULL;
vb@89
   467
vb@89
   468
    struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
vb@89
   469
    assert(result);
vb@89
   470
    if (result == NULL) {
vb@89
   471
        free(data);
vb@89
   472
        return NULL;
vb@89
   473
    }
vb@89
   474
vb@89
   475
    result->fld_type = type;
vb@89
   476
    result->fld_data.fld_return_path = data;
vb@89
   477
vb@89
   478
    return result;
vb@89
   479
}
vb@89
   480
vb@89
   481
void _free_field(struct mailimf_field *field)
vb@89
   482
{
vb@89
   483
    if (field)
vb@89
   484
        free(field->fld_data.fld_return_path);
vb@89
   485
    free(field);
vb@89
   486
}
vb@89
   487
vb@89
   488
int _append_field(
vb@89
   489
        clist *list,
vb@89
   490
        int type,
vb@89
   491
        _new_func_t new_func,
vb@89
   492
        void *value
vb@89
   493
    )
vb@89
   494
{
vb@89
   495
    int r;
vb@89
   496
    struct mailimf_field * field;
vb@89
   497
vb@89
   498
    assert(list);
vb@89
   499
    assert(new_func);
vb@89
   500
    assert(value);
vb@89
   501
vb@89
   502
    field = _new_field(type, new_func, value);
vb@89
   503
    if (field == NULL)
vb@89
   504
        return -1;
vb@89
   505
vb@89
   506
    r = clist_append(list, field);
vb@90
   507
    if (r)
vb@89
   508
        _free_field(field);
vb@89
   509
vb@89
   510
    return r;
vb@89
   511
}
vb@89
   512
vb@92
   513
// http://media2.giga.de/2014/02/Image-28.jpg
vb@92
   514
vb@4550
   515
struct mailimf_date_time * timestamp_to_etpantime(const timestamp *ts)
vb@89
   516
{
vb@89
   517
    struct mailimf_date_time * result = calloc(1,
vb@89
   518
            sizeof(struct mailimf_date_time));
vb@89
   519
    assert(result);
vb@89
   520
    if (result == NULL)
vb@89
   521
        return NULL;
vb@89
   522
vb@89
   523
    assert(ts);
vb@89
   524
vb@89
   525
    result->dt_sec = ts->tm_sec;
vb@89
   526
    result->dt_min = ts->tm_min;
vb@89
   527
    result->dt_hour = ts->tm_hour;
vb@89
   528
    result->dt_day = ts->tm_mday;
vb@89
   529
    result->dt_month = ts->tm_mon + 1;
vb@89
   530
    result->dt_year = ts->tm_year + 1900;
vb@89
   531
    result->dt_zone = (int) (ts->tm_gmtoff / 36L);
vb@89
   532
    return result;
vb@89
   533
}
vb@89
   534
vb@4550
   535
timestamp * etpantime_to_timestamp(const struct mailimf_date_time *et)
vb@89
   536
{
vb@4550
   537
    timestamp * result = calloc(1, sizeof(timestamp));
vb@89
   538
    assert(result);
vb@89
   539
    if (result == NULL)
vb@89
   540
        return NULL;
vb@89
   541
vb@89
   542
    assert(et);
vb@89
   543
vb@89
   544
    result->tm_sec = et->dt_sec;
vb@89
   545
    result->tm_min = et->dt_min;
vb@89
   546
    result->tm_hour = et->dt_hour;
vb@89
   547
    result->tm_mday = et->dt_day;
vb@89
   548
    result->tm_mon = et->dt_month - 1;
vb@89
   549
    result->tm_year = et->dt_year - 1900;
vb@89
   550
    result->tm_gmtoff = 36L * (long) et->dt_zone;
vb@4907
   551
Jorg@4910
   552
    // Normalize to UTC and then forget the offset.
vb@4907
   553
    time_t t = timegm_with_gmtoff(result);
vb@4907
   554
    gmtime_r(&t, result);
Jorg@4910
   555
    result->tm_gmtoff = 0;
vb@4907
   556
vb@89
   557
    return result;
vb@89
   558
}
vb@89
   559
vb@90
   560
struct mailimf_mailbox * mailbox_from_string(
vb@90
   561
        const char *name,
vb@90
   562
        const char *address
vb@90
   563
    )
vb@90
   564
{
vb@4771
   565
    assert(address);
vb@4771
   566
    if (!address)
vb@4771
   567
        return NULL;
vb@4771
   568
vb@90
   569
    struct mailimf_mailbox *mb = NULL;
vb@90
   570
    char *_name = NULL;
vb@90
   571
    char *_address = NULL;
vb@90
   572
vb@90
   573
    _name = name ? strdup(name) : strdup("");
vb@90
   574
    if (_name == NULL)
vb@90
   575
        goto enomem;
vb@90
   576
krista@4719
   577
    char* at = strstr(address, "@");
krista@4719
   578
    if (!at) {
krista@4719
   579
        // Presumed URI
krista@4719
   580
        int added_char_len = 6; // " " @URI 
krista@4719
   581
        int new_addr_len = strlen(address) + added_char_len + 1;
krista@4719
   582
        _address = calloc(new_addr_len, 1);
krista@4719
   583
        if (_address == NULL)
krista@4719
   584
            goto enomem;
krista@4719
   585
        
krista@4719
   586
        _address[0] = '"';
krista@4719
   587
        strlcat(_address, address, new_addr_len);
krista@4719
   588
        strlcat(_address, "\"@URI", new_addr_len);
krista@4719
   589
    }
krista@4719
   590
    else {
krista@4719
   591
        _address = strdup(address);
krista@4719
   592
        if (_address == NULL)
krista@4719
   593
            goto enomem;
krista@4719
   594
    }
krista@4719
   595
            
vb@90
   596
    mb = mailimf_mailbox_new(_name, _address);
vb@90
   597
    assert(mb);
vb@90
   598
    if (mb == NULL)
vb@90
   599
        goto enomem;
vb@90
   600
vb@90
   601
    return mb;
vb@90
   602
vb@90
   603
enomem:
vb@90
   604
    free(_name);
vb@90
   605
    free(_address);
vb@90
   606
vb@90
   607
    return NULL;
vb@90
   608
}
vb@90
   609
krista@2562
   610
vb@94
   611
struct mailimf_field * create_optional_field(
vb@94
   612
        const char *field,
vb@94
   613
        const char *value
vb@94
   614
    )
vb@94
   615
{
vb@94
   616
    char *_field = NULL;
vb@94
   617
    char *_value = NULL;
vb@94
   618
    struct mailimf_optional_field *optional_field = NULL;
vb@94
   619
vb@94
   620
    _field = strdup(field);
vb@94
   621
    if (_field == NULL)
vb@94
   622
        goto enomem;
vb@94
   623
krista@2562
   624
    if (!must_field_value_be_encoded(value))
krista@2562
   625
        _value = strdup(value);
krista@2562
   626
    else    
krista@2562
   627
        _value = mailmime_encode_subject_header("utf-8", value, 0);
vb@94
   628
    if (_value == NULL)
vb@94
   629
        goto enomem;
vb@94
   630
vb@94
   631
    optional_field = mailimf_optional_field_new(_field, _value);
vb@94
   632
    if (optional_field == NULL)
vb@94
   633
        goto enomem;
vb@94
   634
vb@94
   635
    struct mailimf_field * result = calloc(1, sizeof(struct mailimf_field));
vb@94
   636
    assert(result);
vb@94
   637
    if (result == NULL)
vb@94
   638
        goto enomem;
vb@94
   639
vb@94
   640
    result->fld_type = MAILIMF_FIELD_OPTIONAL_FIELD;
vb@94
   641
    result->fld_data.fld_optional_field = optional_field;
vb@94
   642
vb@94
   643
    return result;
vb@94
   644
vb@94
   645
enomem:
vb@94
   646
    if (optional_field) {
vb@94
   647
        mailimf_optional_field_free(optional_field);
vb@94
   648
    }
vb@94
   649
    else {
vb@94
   650
        free(_field);
vb@94
   651
        free(_value);
vb@94
   652
    }
vb@94
   653
vb@94
   654
    return NULL;
vb@94
   655
}
vb@94
   656
vb@94
   657
int _append_optional_field(
vb@94
   658
        clist *list,
vb@94
   659
        const char *field,
vb@94
   660
        const char *value
vb@94
   661
    )
vb@94
   662
{
vb@94
   663
    int r;
vb@94
   664
    struct mailimf_field * optional_field =
vb@94
   665
            create_optional_field(field, value);
vb@94
   666
vb@94
   667
    if (optional_field == NULL)
vb@94
   668
        return -1;
vb@94
   669
vb@94
   670
    r = clist_append(list, optional_field);
vb@94
   671
    if (r)
vb@94
   672
        mailimf_field_free(optional_field);
vb@94
   673
vb@94
   674
    return r;
vb@94
   675
}
vb@94
   676
vb@147
   677
clist * _get_fields(struct mailmime * mime)
vb@147
   678
{
vb@147
   679
    clist * _fieldlist = NULL;
vb@147
   680
vb@147
   681
    assert(mime);
vb@147
   682
vb@147
   683
    if (mime->mm_data.mm_message.mm_fields &&
vb@147
   684
            mime->mm_data.mm_message.mm_fields->fld_list) {
vb@147
   685
        _fieldlist = mime->mm_data.mm_message.mm_fields->fld_list;
vb@147
   686
    }
vb@147
   687
vb@147
   688
    return _fieldlist;
vb@147
   689
}
vb@147
   690
vb@147
   691
struct mailmime_content * _get_content(struct mailmime * mime)
vb@147
   692
{
vb@147
   693
    struct mailmime_content * content = NULL;
vb@147
   694
vb@147
   695
    assert(mime);
vb@147
   696
vb@147
   697
    if (mime->mm_data.mm_message.mm_msg_mime)
vb@147
   698
        content = mime->mm_data.mm_message.mm_msg_mime->mm_content_type;
vb@147
   699
vb@147
   700
    return content;
vb@147
   701
}
vb@147
   702
krista@1872
   703
krista@1873
   704
/* Return a list of identifier_type and resource id (filename, cid, etc) */
krista@1873
   705
pEp_rid_list_t* _get_resource_id_list(struct mailmime *mime)
krista@1873
   706
{
krista@1873
   707
    clist * _fieldlist = NULL;
krista@1872
   708
krista@1873
   709
    assert(mime);
krista@1873
   710
krista@1873
   711
    if (mime->mm_mime_fields && mime->mm_mime_fields->fld_list)
krista@1873
   712
        _fieldlist = mime->mm_mime_fields->fld_list;
krista@1873
   713
    else
krista@1873
   714
        return NULL;
krista@1873
   715
krista@1873
   716
    clistiter *cur;
krista@1873
   717
krista@1873
   718
    pEp_rid_list_t* rid_list = NULL; 
krista@1873
   719
    pEp_rid_list_t** rid_list_curr_p = &rid_list; 
krista@1873
   720
        
krista@1873
   721
    for (cur = clist_begin(_fieldlist); cur; cur = clist_next(cur)) {
krista@1873
   722
        struct mailmime_field * _field = clist_content(cur);
krista@1873
   723
        /* content_id */
krista@1873
   724
        if (_field && _field->fld_type == MAILMIME_FIELD_ID) {
krista@1900
   725
            pEp_rid_list_t* new_rid = (pEp_rid_list_t*)calloc(1, sizeof(pEp_rid_list_t));
krista@1873
   726
            new_rid->rid_type = PEP_RID_CID;
krista@1900
   727
            new_rid->rid = strdup(_field->fld_data.fld_id);
krista@1873
   728
            *rid_list_curr_p = new_rid;
krista@1873
   729
            rid_list_curr_p = &new_rid->next;
krista@1873
   730
        }
krista@1873
   731
        else if (_field && _field->fld_type == MAILMIME_FIELD_DISPOSITION) {
krista@1873
   732
            /* filename */
krista@1873
   733
            if (_field->fld_data.fld_disposition &&
krista@1873
   734
                    _field->fld_data.fld_disposition->dsp_parms) {
krista@1873
   735
                clist * _parmlist =
krista@1873
   736
                        _field->fld_data.fld_disposition->dsp_parms;
krista@1873
   737
                clistiter *cur2;
krista@1873
   738
                for (cur2 = clist_begin(_parmlist); cur2; cur2 =
krista@1873
   739
                        clist_next(cur2)) {
krista@1873
   740
                    struct mailmime_disposition_parm * param =
krista@1873
   741
                            clist_content(cur2);
krista@1873
   742
                    if (param->pa_type == MAILMIME_DISPOSITION_PARM_FILENAME) {
krista@1900
   743
                        pEp_rid_list_t* new_rid = (pEp_rid_list_t*)calloc(1, sizeof(pEp_rid_list_t));
krista@1873
   744
                        new_rid->rid_type = PEP_RID_FILENAME;
krista@1900
   745
                        new_rid->rid = strdup(param->pa_data.pa_filename);
krista@1873
   746
                        *rid_list_curr_p = new_rid;
krista@1873
   747
                        rid_list_curr_p = &new_rid->next;
krista@1873
   748
                    }                
krista@1873
   749
                }
krista@1873
   750
            }
krista@1873
   751
        }
krista@1873
   752
    }
krista@1873
   753
    /* Will almost certainly usually be a singleton, but we need to be able to decide */
krista@1873
   754
    return rid_list;
krista@1873
   755
}
krista@1873
   756
krista@1873
   757
krista@1873
   758
/* FIXME: about to be obsoleted? */
krista@1872
   759
char * _get_filename_or_cid(struct mailmime *mime)
vb@154
   760
{
vb@154
   761
    clist * _fieldlist = NULL;
vb@154
   762
vb@154
   763
    assert(mime);
vb@154
   764
vb@154
   765
    if (mime->mm_mime_fields && mime->mm_mime_fields->fld_list)
vb@154
   766
        _fieldlist = mime->mm_mime_fields->fld_list;
vb@154
   767
    else
vb@154
   768
        return NULL;
vb@154
   769
vb@154
   770
    clistiter *cur;
krista@1873
   771
    
krista@1873
   772
    char* _temp_filename_ptr = NULL;
krista@1873
   773
    
vb@154
   774
    for (cur = clist_begin(_fieldlist); cur; cur = clist_next(cur)) {
vb@154
   775
        struct mailmime_field * _field = clist_content(cur);
krista@1873
   776
        if (_field && _field->fld_type == MAILMIME_FIELD_ID) {
krista@1873
   777
            /* We prefer CIDs to filenames when both are present */
krista@1873
   778
            free(_temp_filename_ptr); /* can be null, it's ok */
krista@1881
   779
            return build_uri("cid", _field->fld_data.fld_id); 
krista@1873
   780
        }
krista@1873
   781
        else if (_field && _field->fld_type == MAILMIME_FIELD_DISPOSITION) {
vb@154
   782
            if (_field->fld_data.fld_disposition &&
krista@1873
   783
                    _field->fld_data.fld_disposition->dsp_parms &&
krista@1873
   784
                    !_temp_filename_ptr) {
vb@154
   785
                clist * _parmlist =
vb@154
   786
                        _field->fld_data.fld_disposition->dsp_parms;
vb@154
   787
                clistiter *cur2;
vb@154
   788
                for (cur2 = clist_begin(_parmlist); cur2; cur2 =
vb@154
   789
                        clist_next(cur2)) {
vb@156
   790
                    struct mailmime_disposition_parm * param =
vb@156
   791
                            clist_content(cur2);
krista@1873
   792
                    if (param->pa_type == MAILMIME_DISPOSITION_PARM_FILENAME) {
krista@1881
   793
                        _temp_filename_ptr = build_uri("file", param->pa_data.pa_filename);
krista@1873
   794
                        break;
krista@1873
   795
                    }                
vb@154
   796
                }
vb@154
   797
            }
vb@154
   798
        }
vb@154
   799
    }
krista@1873
   800
    /* Ok, it wasn't a CID */
krista@1873
   801
    return _temp_filename_ptr;
vb@154
   802
}
vb@154
   803
vb@157
   804
static bool parameter_has_value(
vb@152
   805
        struct mailmime_content *content,       
vb@152
   806
        const char *name,
vb@152
   807
        const char *value
vb@152
   808
    )
vb@152
   809
{
vb@152
   810
    clistiter *cur;
vb@152
   811
vb@152
   812
    assert(name);
vb@152
   813
    assert(value);
vb@152
   814
vb@152
   815
    clist * list = content->ct_parameters;
vb@152
   816
    if (list == NULL)
vb@152
   817
        return false;
vb@152
   818
vb@152
   819
    for (cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
vb@152
   820
        struct mailmime_parameter * param = clist_content(cur);
vb@152
   821
        if (param &&
vb@165
   822
                param->pa_name && strcasecmp(name, param->pa_name) == 0 &&
vb@165
   823
                param->pa_value && strcasecmp(value, param->pa_value) == 0)
vb@152
   824
            return true;
vb@152
   825
    }
vb@152
   826
vb@152
   827
    return false;
vb@152
   828
}
vb@152
   829
vb@151
   830
bool _is_multipart(struct mailmime_content *content, const char *subtype)
vb@147
   831
{
vb@147
   832
    assert(content);
vb@147
   833
vb@147
   834
    if (content->ct_type && content->ct_type->tp_type ==
vb@147
   835
            MAILMIME_TYPE_COMPOSITE_TYPE &&
vb@147
   836
            content->ct_type->tp_data.tp_composite_type &&
vb@147
   837
            content->ct_type->tp_data.tp_composite_type->ct_type ==
vb@151
   838
            MAILMIME_COMPOSITE_TYPE_MULTIPART) {
vb@151
   839
        if (subtype)
vb@151
   840
            return content->ct_subtype &&
vb@165
   841
                    strcasecmp(content->ct_subtype, subtype) == 0;
vb@151
   842
        else
vb@151
   843
            return true;
vb@151
   844
    }
vb@147
   845
vb@151
   846
    return false;
vb@147
   847
}
vb@147
   848
vb@147
   849
bool _is_PGP_MIME(struct mailmime_content *content)
vb@147
   850
{
vb@147
   851
    assert(content);
vb@147
   852
vb@151
   853
    if (_is_multipart(content, "encrypted") &&
vb@152
   854
            parameter_has_value(content, "protocol",
vb@147
   855
                    "application/pgp-encrypted"))
vb@151
   856
        return true;
vb@147
   857
vb@151
   858
    return false;
vb@147
   859
}
vb@147
   860
vb@152
   861
bool _is_text_part(struct mailmime_content *content, const char *subtype)
vb@152
   862
{
vb@152
   863
    assert(content);
vb@152
   864
vb@153
   865
    if (content->ct_type && content->ct_type->tp_type ==
vb@153
   866
            MAILMIME_TYPE_DISCRETE_TYPE &&
vb@153
   867
            content->ct_type->tp_data.tp_discrete_type &&
vb@152
   868
            content->ct_type->tp_data.tp_discrete_type->dt_type ==
vb@152
   869
            MAILMIME_DISCRETE_TYPE_TEXT) {
vb@152
   870
        if (subtype)
vb@152
   871
            return content->ct_subtype &&
vb@165
   872
                    strcasecmp(content->ct_subtype, subtype) == 0;
vb@152
   873
        else
vb@152
   874
            return true;
vb@152
   875
    }
vb@152
   876
vb@152
   877
    return false;
vb@152
   878
}
vb@152
   879
krista@3710
   880
bool _is_message_part(struct mailmime_content *content, const char* subtype) {
krista@3710
   881
    assert(content);
krista@3710
   882
    if (content->ct_type && content->ct_type->tp_type == MAILMIME_TYPE_COMPOSITE_TYPE &&
krista@3710
   883
            content->ct_type->tp_data.tp_composite_type &&
krista@3710
   884
            content->ct_type->tp_data.tp_composite_type->ct_type ==
krista@3710
   885
            MAILMIME_COMPOSITE_TYPE_MESSAGE) {
krista@3710
   886
        if (subtype)
krista@3710
   887
            return content->ct_subtype &&
krista@3710
   888
                    strcasecmp(content->ct_subtype, subtype) == 0;
krista@3710
   889
        else
krista@3710
   890
            return true;                
krista@3710
   891
    }
krista@3710
   892
    
krista@3710
   893
    return false;
krista@3710
   894
}
krista@3710
   895
vb@159
   896
int _get_content_type(
vb@159
   897
        const struct mailmime_content *content,
vb@159
   898
        char **type,
vb@159
   899
        char **charset
vb@159
   900
    )
vb@154
   901
{
vb@159
   902
    char *_type = NULL;
vb@159
   903
    char *_charset = NULL;
vb@154
   904
vb@154
   905
    assert(content);
vb@159
   906
    assert(type);
vb@159
   907
    assert(charset);
vb@154
   908
vb@159
   909
    *type = NULL;
vb@159
   910
    *charset = NULL;
vb@159
   911
vb@159
   912
    if (content->ct_subtype == NULL)
vb@159
   913
        return EINVAL;
vb@154
   914
vb@154
   915
    if (content->ct_type && content->ct_type->tp_data.tp_discrete_type) {
vb@154
   916
        size_t len;
vb@159
   917
        const char *_main_type;
vb@154
   918
vb@154
   919
        switch  (content->ct_type->tp_data.tp_discrete_type->dt_type) {
vb@154
   920
            case MAILMIME_DISCRETE_TYPE_TEXT:
krista@4540
   921
                _main_type = (content->ct_subtype && 
krista@4540
   922
                              strcasecmp(content->ct_subtype, "rfc822") == 0 ?
krista@4540
   923
                              "message" : "text");
vb@154
   924
                break;
vb@154
   925
            case MAILMIME_DISCRETE_TYPE_IMAGE:
vb@159
   926
                _main_type = "image";
vb@154
   927
                break;
vb@154
   928
            case MAILMIME_DISCRETE_TYPE_AUDIO:
vb@159
   929
                _main_type = "audio";
vb@154
   930
                break;
vb@154
   931
            case MAILMIME_DISCRETE_TYPE_VIDEO:
vb@159
   932
                _main_type = "video";
vb@154
   933
                break;
vb@154
   934
            case MAILMIME_DISCRETE_TYPE_APPLICATION:
vb@159
   935
                _main_type = "application";
vb@154
   936
                break;
vb@154
   937
            case MAILMIME_DISCRETE_TYPE_EXTENSION:
vb@159
   938
                _main_type = "extension";
vb@154
   939
                break;
vb@154
   940
            default:
vb@159
   941
                return EINVAL;
vb@154
   942
        }
vb@154
   943
vb@159
   944
        len = strlen(_main_type) + 1 + strlen(content->ct_subtype) + 1;
vb@159
   945
        _type = calloc(1, len);
vb@159
   946
        assert(_type);
vb@159
   947
        if (_type == NULL)
vb@159
   948
            return ENOMEM;
vb@159
   949
krista@903
   950
        strncpy(_type, _main_type, len);
krista@903
   951
        len -= strlen(_main_type);
krista@903
   952
        strncat(_type, "/", len--);
krista@903
   953
        strncat(_type, content->ct_subtype, len);
vb@159
   954
vb@159
   955
        if (content->ct_parameters) {
vb@159
   956
            clistiter *cur;
vb@159
   957
            for (cur = clist_begin(content->ct_parameters); cur; cur =
vb@159
   958
                    clist_next(cur)) {
vb@159
   959
                struct mailmime_parameter * param = clist_content(cur);
vb@165
   960
                if (param && param->pa_name && strcasecmp(param->pa_name,
vb@159
   961
                            "charset") == 0) {
vb@159
   962
                    _charset = param->pa_value;
vb@159
   963
                    break;
vb@159
   964
                }
vb@159
   965
            }
vb@159
   966
            if (_charset)
vb@159
   967
                *charset = strdup(_charset);
vb@157
   968
        }
vb@154
   969
vb@159
   970
        *type = _type;
vb@159
   971
        return 0;
vb@154
   972
    }
vb@154
   973
vb@159
   974
    return EINVAL;
vb@154
   975
}
krista@2562
   976
krista@2562
   977
// Only for null-terminated field strings.
krista@2562
   978
// can this field be transported as is without modification?)
krista@2562
   979
// (See rfc2822, section 2.2.3 - libetpan's handling isn't quite what
krista@2562
   980
// we need here.)
krista@2562
   981
bool must_field_value_be_encoded(const char* field_value) {
krista@2579
   982
    if (!field_value)
krista@2579
   983
        return false;
krista@2579
   984
        
krista@2581
   985
    return must_chunk_be_encoded((const void*)field_value, strlen(field_value), false);    
krista@2579
   986
}
krista@2562
   987
krista@2581
   988
bool must_chunk_be_encoded(const void* value, size_t size, bool ignore_fws) {
krista@2579
   989
krista@2579
   990
    const char* begin_ptr = (const char*)value;    
krista@2579
   991
krista@2579
   992
    const char* end_ptr = begin_ptr + size;
krista@2579
   993
krista@2579
   994
    const char* cur_char_ptr = begin_ptr;
krista@2562
   995
    while (cur_char_ptr < end_ptr) {
krista@2562
   996
        char cur_char = *cur_char_ptr;
krista@2563
   997
        if (cur_char > 127 || cur_char < 0)
krista@2562
   998
            return true;
krista@2562
   999
        // FIXME - do we need to deal with CRCRLF here?
krista@2562
  1000
        //         I guess in the worst case, it gets encoded, which
krista@2562
  1001
        //         is *supposed* to be harmless...
krista@2581
  1002
        if (!ignore_fws) {
krista@2581
  1003
            if (cur_char == '\r') {
krista@2581
  1004
                const char* next = cur_char_ptr + 1;
krista@2581
  1005
                const char* nextnext = next + 1;
krista@2581
  1006
                if (next >= end_ptr || nextnext >= end_ptr
krista@2581
  1007
                    || *next != '\n'
krista@2581
  1008
                    || (*nextnext != ' ' && *nextnext != '\t')) {
krista@2581
  1009
                    return true;
krista@2581
  1010
                }            
krista@2581
  1011
            }
krista@2581
  1012
            else if (cur_char == '\n') {
krista@2581
  1013
                const char* prev = cur_char_ptr - 1;
krista@2581
  1014
                if (prev == begin_ptr || *prev != '\r')
krista@2581
  1015
                    return true;
krista@2581
  1016
            }
krista@2562
  1017
        }
krista@2562
  1018
        cur_char_ptr++;
krista@2562
  1019
    }    
krista@2562
  1020
    return false;
krista@2562
  1021
}
vb@3439
  1022
vb@3439
  1023
#define TMP_TEMPLATE "pEp.XXXXXXXXXXXXXXXXXXXX"
vb@3439
  1024
#ifdef _WIN32
vb@3439
  1025
#define PATH_SEP '\\'
vb@3439
  1026
#else
vb@3439
  1027
#define PATH_SEP '/'
vb@3439
  1028
#endif
vb@3439
  1029
vb@3439
  1030
static PEP_STATUS interpret_MIME(struct mailmime *mime,
krista@3710
  1031
                                 message *msg,
krista@4592
  1032
                                 bool* has_possible_pEp_msg);
vb@3439
  1033
vb@3439
  1034
// This function was rewritten to use in-memory buffers instead of
vb@3439
  1035
// temporary files when the pgp/mime support was implemented for
vb@3439
  1036
// outlook, as the existing code did not work well on windows.
vb@3439
  1037
vb@3439
  1038
static PEP_STATUS render_mime(struct mailmime *mime, char **mimetext)
vb@3439
  1039
{
vb@3439
  1040
    PEP_STATUS status = PEP_STATUS_OK;
vb@3439
  1041
    int col;
vb@3439
  1042
    int r;
vb@3439
  1043
	size_t len;
vb@3439
  1044
	char* buf = NULL;
vb@3439
  1045
vb@3439
  1046
	MMAPString* buffer;
vb@3439
  1047
vb@3439
  1048
	buffer = mmap_string_new(NULL);
vb@3439
  1049
	if (buffer == NULL)
vb@3439
  1050
		goto enomem;
vb@3439
  1051
	
vb@3439
  1052
	col = 0;
vb@3439
  1053
	r = mailmime_write_mem(buffer, &col, mime);
vb@3439
  1054
	assert(r == MAILIMF_NO_ERROR);
vb@3439
  1055
	if (r == MAILIMF_ERROR_MEMORY)
vb@3439
  1056
		goto enomem;
vb@3439
  1057
	else if (r != MAILIMF_NO_ERROR)
vb@3439
  1058
		goto err_file;
vb@3439
  1059
vb@3439
  1060
	// we overallocate by 1 byte, so we have a terminating 0.
vb@3439
  1061
	len = buffer->len;
vb@3439
  1062
	buf = calloc(len + 1, 1);
vb@3439
  1063
	if (buf == NULL)
vb@3439
  1064
		goto enomem;
vb@3439
  1065
vb@3439
  1066
	memcpy(buf, buffer->str, len);
vb@3439
  1067
	mmap_string_free(buffer);
vb@3439
  1068
vb@3439
  1069
    *mimetext = buf;
vb@3439
  1070
    return PEP_STATUS_OK;
vb@3439
  1071
vb@3439
  1072
err_file:
vb@3439
  1073
    status = PEP_CANNOT_CREATE_TEMP_FILE;
vb@3439
  1074
    goto pEp_error;
vb@3439
  1075
vb@3439
  1076
enomem:
vb@3439
  1077
    status = PEP_OUT_OF_MEMORY;
vb@3439
  1078
vb@3439
  1079
pEp_error:
vb@3439
  1080
	if (buffer)
vb@3439
  1081
		mmap_string_free(buffer);
vb@3439
  1082
	if (buf)
vb@3439
  1083
		free(buf);
vb@3439
  1084
    return status;
vb@3439
  1085
}
vb@3439
  1086
vb@3439
  1087
static PEP_STATUS mime_attachment(
vb@3439
  1088
        bloblist_t *blob,
vb@3439
  1089
        struct mailmime **result,
krista@4590
  1090
        bool is_nf_message_attachment // non-forwarded msg as att
vb@3439
  1091
    )
vb@3439
  1092
{
vb@3439
  1093
    PEP_STATUS status = PEP_STATUS_OK;
vb@3439
  1094
    struct mailmime * mime = NULL;
vb@3439
  1095
    char * mime_type;
vb@3439
  1096
    assert(blob);
vb@3439
  1097
    assert(result);
vb@3439
  1098
vb@3439
  1099
    *result = NULL;
vb@3439
  1100
vb@3439
  1101
// TODO: It seems the pEp COM server adapter sends an empty string here,
vb@3439
  1102
// which leads to a crash later. Thus, we workaround here by treating an
vb@3439
  1103
// empty string as NULL. We need to check whether the bug really is here,
vb@3439
  1104
// or the pEp COM server adapter needs to be changed.
vb@3439
  1105
    if (blob->mime_type == NULL || blob->mime_type[0] == '\0')
vb@3439
  1106
        mime_type = "application/octet-stream";
vb@3439
  1107
    else
vb@3439
  1108
        mime_type = blob->mime_type;
vb@3439
  1109
vb@3439
  1110
    pEp_rid_list_t* resource = parse_uri(blob->filename);
vb@3439
  1111
vb@3439
  1112
    mime = get_file_part(resource, mime_type, blob->value, blob->size, 
krista@4590
  1113
                         is_nf_message_attachment);
vb@3439
  1114
    free_rid_list(resource);
vb@3439
  1115
    
vb@3439
  1116
    assert(mime);
vb@3439
  1117
    if (mime == NULL)
vb@3439
  1118
        goto enomem;
vb@3439
  1119
vb@3439
  1120
    *result = mime;
vb@3439
  1121
    return PEP_STATUS_OK;
vb@3439
  1122
vb@3439
  1123
enomem:
vb@3439
  1124
    status = PEP_OUT_OF_MEMORY;
vb@3439
  1125
vb@3439
  1126
    if (mime)
vb@3439
  1127
        mailmime_free(mime);
vb@3439
  1128
vb@3439
  1129
    return status;
vb@3439
  1130
}
vb@3439
  1131
krista@4590
  1132
krista@4590
  1133
// This ONLY deals with handling the body 
krista@4590
  1134
// content when html parts are present - thus,
krista@4590
  1135
// text/plain and text/html of the body, and 
krista@4590
  1136
// related inline attachments for the html 
krista@4590
  1137
// part. Non-inline attachments are handled 
krista@4590
  1138
// outside this call!!!!
krista@4590
  1139
//
krista@4590
  1140
// N.B. As a result, this will only touch the 
krista@4590
  1141
// "contained message" of pEp 2.x messages 
krista@4590
  1142
// on the initial encoding where it is turned 
krista@4590
  1143
// into attachment data!!
vb@3439
  1144
static PEP_STATUS mime_html_text(
vb@3439
  1145
        const char *plaintext,
vb@3439
  1146
        const char *htmltext,
vb@3439
  1147
        bloblist_t *attachments,
krista@4590
  1148
        struct mailmime **result
vb@3439
  1149
    )
vb@3439
  1150
{
vb@3439
  1151
    PEP_STATUS status = PEP_STATUS_OK;
vb@3439
  1152
    struct mailmime * top_level_html_mime = NULL;
vb@3439
  1153
    struct mailmime * mime = NULL;
vb@3439
  1154
    struct mailmime * submime = NULL;
vb@3439
  1155
    int r;
vb@3439
  1156
vb@3439
  1157
    assert(plaintext);
vb@3439
  1158
    assert(htmltext);
vb@3439
  1159
    assert(result);
vb@3439
  1160
vb@3439
  1161
    *result = NULL;
vb@3439
  1162
vb@4502
  1163
    pEp_rid_list_t* resource = NULL;
krista@4578
  1164
        
krista@4590
  1165
    bool already_ascii = false;
krista@4590
  1166
    int encoding_type = 0;    
krista@4578
  1167
    if (*plaintext != '\0') {
krista@4578
  1168
        mime = part_multiple_new("multipart/alternative");
krista@4578
  1169
        assert(mime);
krista@4578
  1170
        if (mime == NULL)
krista@4578
  1171
            goto enomem;
krista@4590
  1172
            
krista@4590
  1173
        // KB: pEpMIME transition comment - if we start getting 
krista@4590
  1174
        // underencoding errors here, the change to checking 
krista@4590
  1175
        // for ASCII and then encoding - or not - is one place 
krista@4590
  1176
        // to start looking.
krista@4590
  1177
        int pt_length = strlen(plaintext);
krista@4590
  1178
        already_ascii = !(must_chunk_be_encoded(plaintext, pt_length, true));                
krista@4590
  1179
        encoding_type = (already_ascii ? 0 : MAILMIME_MECHANISM_QUOTED_PRINTABLE);
krista@4590
  1180
                
krista@4590
  1181
        submime = get_text_part(NULL, "text/plain", plaintext, 
krista@4590
  1182
                                pt_length,
krista@4590
  1183
                                encoding_type);
krista@4578
  1184
        
krista@4590
  1185
        // reset                        
krista@4590
  1186
        already_ascii = false;
krista@4590
  1187
        encoding_type = 0;
krista@4590
  1188
                                    
krista@4578
  1189
        free_rid_list(resource);
krista@4578
  1190
        resource = NULL;
krista@4578
  1191
        
krista@4578
  1192
        assert(submime);
krista@4578
  1193
        if (submime == NULL)
krista@4578
  1194
            goto enomem;
krista@4578
  1195
krista@4578
  1196
        r = mailmime_smart_add_part(mime, submime);
krista@4578
  1197
        assert(r == MAILIMF_NO_ERROR);
krista@4578
  1198
        if (r == MAILIMF_ERROR_MEMORY) {
krista@4578
  1199
            goto enomem;
krista@4578
  1200
        }
krista@4578
  1201
        else {
krista@4578
  1202
            // mailmime_smart_add_part() takes ownership of submime
krista@4578
  1203
            submime = NULL;
krista@4578
  1204
        }
krista@4578
  1205
    }
vb@3439
  1206
    
vb@3439
  1207
    bool inlined_attachments = false;
vb@3439
  1208
    
vb@3439
  1209
    bloblist_t* traversal_ptr = attachments;
vb@3439
  1210
    
vb@3439
  1211
    while (traversal_ptr) {
vb@3439
  1212
        if (traversal_ptr->disposition == PEP_CONTENT_DISP_INLINE) {
vb@3439
  1213
            inlined_attachments = true;
vb@3439
  1214
            break;
vb@3439
  1215
        }
vb@3439
  1216
        traversal_ptr = traversal_ptr->next;
vb@3439
  1217
    }
vb@3439
  1218
vb@3439
  1219
    if (inlined_attachments) {
vb@3439
  1220
        /* Noooooo... dirk, why do you do this to me? */
vb@3439
  1221
        submime = part_multiple_new("multipart/related");
vb@3439
  1222
        assert(submime);
vb@3439
  1223
        if (submime == NULL)
vb@3439
  1224
            goto enomem;
vb@3439
  1225
krista@4578
  1226
        // This is where all of the html MIME stuff will go
vb@3439
  1227
        top_level_html_mime = submime;
vb@3439
  1228
        
krista@4578
  1229
        if (!mime)
krista@4578
  1230
            mime = top_level_html_mime;
krista@4578
  1231
        else {    
krista@4578
  1232
            r = mailmime_smart_add_part(mime, top_level_html_mime);
krista@4578
  1233
            assert(r == MAILIMF_NO_ERROR);
krista@4578
  1234
            if (r == MAILIMF_ERROR_MEMORY) {
krista@4578
  1235
                goto enomem;
krista@4578
  1236
            }
krista@4578
  1237
            else {
krista@4578
  1238
                // mailmime_smart_add_part() takes ownership of submime
krista@4578
  1239
                submime = NULL;
krista@4578
  1240
            }
krista@4578
  1241
        }    
vb@3439
  1242
    }
vb@3439
  1243
    else {
krista@4578
  1244
        // Otherwise, html MIME stuff gets added to the top node 
krista@4578
  1245
        // - may be NULL if there's no multipart!
vb@3439
  1246
        top_level_html_mime = mime;
vb@3439
  1247
    }
vb@3439
  1248
vb@3439
  1249
//    resource = new_rid_node(PEP_RID_FILENAME, "msg.html");
krista@4590
  1250
    int ht_length = strlen(htmltext);
krista@4590
  1251
    already_ascii = !(must_chunk_be_encoded(htmltext, ht_length, true));                
krista@4590
  1252
    encoding_type = (already_ascii ? 0 : MAILMIME_MECHANISM_QUOTED_PRINTABLE);
krista@4590
  1253
            
krista@4590
  1254
    submime = get_text_part(NULL, "text/html", htmltext, 
krista@4590
  1255
                            ht_length,
krista@4590
  1256
                            encoding_type);
krista@4590
  1257
vb@3439
  1258
    free_rid_list(resource);
vb@3439
  1259
    resource = NULL;
vb@3439
  1260
    
vb@3439
  1261
    assert(submime);
vb@3439
  1262
    if (submime == NULL)
vb@3439
  1263
        goto enomem;
krista@4578
  1264
        
krista@4578
  1265
    // IF there are no inlined attachments AND mime is NULL, then 
krista@4578
  1266
    // we just have an HTML body here and won't need to 
krista@4578
  1267
    // process inlined attachments - submime will actually be 
krista@4578
  1268
    // the mime root of from this function, at least.    
krista@4578
  1269
krista@4578
  1270
    if (!top_level_html_mime) {
krista@4578
  1271
        mime = submime;
vb@3439
  1272
        submime = NULL;
vb@3439
  1273
    }
krista@4578
  1274
    else {    
vb@3439
  1275
        r = mailmime_smart_add_part(top_level_html_mime, submime);
vb@3439
  1276
        assert(r == MAILIMF_NO_ERROR);
krista@4578
  1277
        if (r == MAILIMF_ERROR_MEMORY)
vb@3439
  1278
            goto enomem;
vb@3439
  1279
        else {
vb@3439
  1280
            // mailmime_smart_add_part() takes ownership of submime
vb@3439
  1281
            submime = NULL;
vb@3439
  1282
        }
krista@4578
  1283
krista@4578
  1284
        bloblist_t *_a;
krista@4590
  1285
krista@4590
  1286
        // This will never have an embedded pEp message attachment 
krista@4590
  1287
        // sent for encoding here, so we don't need to pass down 
krista@4590
  1288
        // "(don't) transport encode this" info. If it's here and 
krista@4590
  1289
        // it's not an ASCII "text/*" attachment, it'll get encoded
krista@4578
  1290
        for (_a = attachments; _a != NULL; _a = _a->next) {
krista@4578
  1291
            if (_a->disposition != PEP_CONTENT_DISP_INLINE)
krista@4578
  1292
                continue;
krista@4590
  1293
            status = mime_attachment(_a, &submime, false);
krista@4578
  1294
            if (status != PEP_STATUS_OK)
krista@4578
  1295
                return PEP_UNKNOWN_ERROR; // FIXME
krista@4578
  1296
krista@4578
  1297
            r = mailmime_smart_add_part(top_level_html_mime, submime);
krista@4578
  1298
            assert(r == MAILIMF_NO_ERROR);
krista@4578
  1299
            if (r == MAILIMF_ERROR_MEMORY) {
krista@4578
  1300
                goto enomem;
krista@4578
  1301
            }
krista@4578
  1302
            else {
krista@4578
  1303
                // mailmime_smart_add_part() takes ownership of submime
krista@4578
  1304
                submime = NULL;
krista@4578
  1305
            }
krista@4578
  1306
        }
krista@4578
  1307
    }    
vb@3439
  1308
    *result = mime;
vb@3439
  1309
    return PEP_STATUS_OK;
vb@3439
  1310
vb@3439
  1311
enomem:
vb@3439
  1312
    status = PEP_OUT_OF_MEMORY;
vb@3439
  1313
vb@3439
  1314
    if (mime)
vb@3439
  1315
        mailmime_free(mime);
vb@3439
  1316
vb@3439
  1317
    if (submime)
vb@3439
  1318
        mailmime_free(submime);
vb@3439
  1319
vb@3439
  1320
    return status;
vb@3439
  1321
}
vb@3439
  1322
vb@3439
  1323
vb@3439
  1324
static struct mailimf_mailbox * identity_to_mailbox(const pEp_identity *ident)
vb@3439
  1325
{
vb@3439
  1326
    char *_username = NULL;
vb@3439
  1327
    struct mailimf_mailbox *mb;
vb@3439
  1328
vb@3439
  1329
    if (!ident->username)
vb@3439
  1330
        _username = strdup("");
vb@3439
  1331
    else
vb@3439
  1332
        _username = must_field_value_be_encoded(ident->username) ?
vb@3439
  1333
                    mailmime_encode_subject_header("utf-8", ident->username, 0) : 
vb@3439
  1334
                    strdup(ident->username);
vb@3439
  1335
                  
vb@3439
  1336
    assert(_username);
vb@3439
  1337
    if (_username == NULL)
vb@3439
  1338
        goto enomem;
vb@3439
  1339
vb@3439
  1340
    mb = mailbox_from_string(_username, ident->address);
vb@3439
  1341
    if (mb == NULL)
vb@3439
  1342
        goto enomem;
vb@3439
  1343
vb@3439
  1344
    free(_username);
vb@3439
  1345
    _username = NULL;
vb@3439
  1346
vb@3439
  1347
    return mb;
vb@3439
  1348
vb@3439
  1349
enomem:
vb@3439
  1350
    free(_username);
vb@3439
  1351
    return NULL;
vb@3439
  1352
}
vb@3439
  1353
vb@3439
  1354
static struct mailimf_mailbox_list * identity_to_mbl(
vb@3439
  1355
        const pEp_identity *ident)
vb@3439
  1356
{
vb@3439
  1357
    struct mailimf_mailbox_list *mbl = NULL;
vb@3439
  1358
    struct mailimf_mailbox *mb = NULL;
vb@3439
  1359
    clist *list = NULL;
vb@3439
  1360
    int r;
vb@3439
  1361
vb@3439
  1362
    assert(ident);
vb@3439
  1363
vb@3439
  1364
    list = clist_new();
vb@3439
  1365
    if (list == NULL)
vb@3439
  1366
        goto enomem;
vb@3439
  1367
vb@3439
  1368
    mb = identity_to_mailbox(ident);
vb@3439
  1369
    if (mb == NULL)
vb@3439
  1370
        goto enomem;
vb@3439
  1371
vb@3439
  1372
    r = clist_append(list, mb);
vb@3439
  1373
    if (r)
vb@3439
  1374
        goto enomem;
vb@3439
  1375
vb@3439
  1376
    mbl = mailimf_mailbox_list_new(list);
vb@3439
  1377
    if (mbl == NULL)
vb@3439
  1378
        goto enomem;
vb@3439
  1379
vb@3439
  1380
    return mbl;
vb@3439
  1381
vb@3439
  1382
enomem:
vb@3439
  1383
    if (mb)
vb@3439
  1384
        mailimf_mailbox_free(mb);
vb@3439
  1385
vb@3439
  1386
    if (list)
vb@3439
  1387
        clist_free(list);
vb@3439
  1388
vb@3439
  1389
    return NULL;
vb@3439
  1390
}
vb@3439
  1391
vb@3439
  1392
static struct mailimf_address_list * identity_list_to_mal(identity_list *il)
vb@3439
  1393
{
vb@3439
  1394
    struct mailimf_address_list *mal = NULL;
vb@3439
  1395
    struct mailimf_mailbox *mb = NULL;
vb@3439
  1396
    struct mailimf_address * addr = NULL;
vb@3439
  1397
    clist *list = NULL;
vb@3439
  1398
    int r;
vb@3439
  1399
vb@3439
  1400
    assert(il);
vb@3439
  1401
vb@3439
  1402
    list = clist_new();
vb@3439
  1403
    if (list == NULL)
vb@3439
  1404
        goto enomem;
vb@3439
  1405
vb@3439
  1406
    identity_list *_il;
vb@3439
  1407
    for (_il = il; _il && _il->ident; _il = _il->next) {
vb@3439
  1408
        mb = identity_to_mailbox(_il->ident);
vb@3439
  1409
        if (mb == NULL)
vb@3439
  1410
            goto enomem;
vb@3439
  1411
vb@3439
  1412
        addr = mailimf_address_new(MAILIMF_ADDRESS_MAILBOX, mb, NULL);
vb@3439
  1413
        if (addr == NULL)
vb@3439
  1414
            goto enomem;
vb@3439
  1415
        mb = NULL;
vb@3439
  1416
vb@3439
  1417
        r = clist_append(list, addr);
vb@3439
  1418
        if (r)
vb@3439
  1419
            goto enomem;
vb@3439
  1420
        addr = NULL;
vb@3439
  1421
    }
vb@3439
  1422
    mal = mailimf_address_list_new(list);
vb@3439
  1423
    if (mal == NULL)
vb@3439
  1424
        goto enomem;
vb@3439
  1425
vb@3439
  1426
    return mal;
vb@3439
  1427
vb@3439
  1428
enomem:
vb@3439
  1429
    if (mb)
vb@3439
  1430
        mailimf_mailbox_free(mb);
vb@3439
  1431
vb@3439
  1432
    if (addr)
vb@3439
  1433
        mailimf_address_free(addr);
vb@3439
  1434
vb@3439
  1435
    if (list)
vb@3439
  1436
        clist_free(list);
vb@3439
  1437
vb@3439
  1438
    return NULL;
vb@3439
  1439
}
vb@3439
  1440
krista@4590
  1441
// KB: This seems to be always called with "true",
krista@4590
  1442
//     but there was probably a reason for this. So 
krista@4590
  1443
//     leave it for now.
vb@3439
  1444
static clist * stringlist_to_clist(stringlist_t *sl, bool transport_encode)
vb@3439
  1445
{
vb@3439
  1446
    clist * cl = clist_new();
vb@3439
  1447
    assert(cl);
vb@3439
  1448
    if (cl == NULL)
vb@3439
  1449
        return NULL;
vb@3439
  1450
vb@3439
  1451
    if (!sl || ((!sl->value || sl->value[0] == '\0') && sl->next == NULL))
vb@3439
  1452
        return cl;
vb@3439
  1453
        
vb@3439
  1454
    stringlist_t *_sl;
vb@3439
  1455
    for (_sl = sl; _sl; _sl = _sl->next) {
vb@3439
  1456
        int r;
vb@3439
  1457
        char * value = ((transport_encode && must_field_value_be_encoded(_sl->value)) ?
vb@3439
  1458
                        mailmime_encode_subject_header("utf-8", _sl->value, 0) :
vb@3439
  1459
                        strdup(_sl->value));
vb@3439
  1460
        assert(value);
vb@3439
  1461
        if (value == NULL) {
vb@3439
  1462
            clist_free(cl);
vb@3439
  1463
            return NULL;
vb@3439
  1464
        }
vb@3439
  1465
        r = clist_append(cl, value);
vb@3439
  1466
        assert(r == 0);
vb@3439
  1467
        if (r) {
vb@3439
  1468
            free(value);
vb@3439
  1469
            clist_free(cl);
vb@3439
  1470
            return NULL;
vb@3439
  1471
        }
vb@3439
  1472
    }
vb@3439
  1473
vb@3439
  1474
    return cl;
vb@3439
  1475
}
vb@3439
  1476
vb@3439
  1477
static PEP_STATUS build_fields(const message *msg, struct mailimf_fields **result)
vb@3439
  1478
{
vb@3439
  1479
    PEP_STATUS status = PEP_STATUS_OK;
vb@3439
  1480
    struct mailimf_fields * fields = NULL;
vb@3439
  1481
    int r;
vb@3439
  1482
    clist * fields_list = NULL;
vb@3439
  1483
    unsigned char pEpstr[] = PEP_SUBJ_STRING; // unsigned due to UTF-8 byte fun
vb@3439
  1484
#ifdef WIN32
vb@3439
  1485
    char* altstr = "pEp";
vb@3439
  1486
#else
vb@3439
  1487
    char* altstr = (char*)pEpstr;
vb@3439
  1488
#endif        
vb@4534
  1489
    char *subject = msg->shortmsg && msg->shortmsg[0] ? msg->shortmsg : altstr;
vb@3439
  1490
vb@3439
  1491
    assert(msg);
vb@3439
  1492
    assert(result);
vb@3439
  1493
vb@3439
  1494
    *result = NULL;
vb@3439
  1495
vb@3439
  1496
    fields_list = clist_new();
vb@3439
  1497
    assert(fields_list);
vb@3439
  1498
    if (fields_list == NULL)
vb@3439
  1499
        goto enomem;
vb@3439
  1500
vb@4534
  1501
    if (msg->id && msg->id[0]) {
vb@3439
  1502
        char *_msgid = strdup(msg->id);
vb@3439
  1503
        assert(_msgid);
vb@3439
  1504
        if (_msgid == NULL)
vb@3439
  1505
            goto enomem;
vb@3439
  1506
vb@3439
  1507
        r = _append_field(fields_list, MAILIMF_FIELD_MESSAGE_ID,
vb@3439
  1508
                (_new_func_t) mailimf_message_id_new, _msgid);
vb@3439
  1509
        if (r) {
vb@3439
  1510
            free(_msgid);
vb@3439
  1511
            goto enomem;
vb@3439
  1512
        }
vb@3439
  1513
    }
vb@3439
  1514
vb@3439
  1515
    if (msg->sent) {
vb@3439
  1516
        struct mailimf_date_time * dt = timestamp_to_etpantime(msg->sent);
vb@3439
  1517
        if (dt == NULL)
vb@3439
  1518
            goto enomem;
vb@3439
  1519
vb@3439
  1520
        r = _append_field(fields_list, MAILIMF_FIELD_ORIG_DATE,
vb@3439
  1521
                (_new_func_t) mailimf_orig_date_new, dt);
vb@3439
  1522
        if (r) {
vb@3439
  1523
            mailimf_date_time_free(dt);
vb@3439
  1524
            goto enomem;
vb@3439
  1525
        }
vb@3439
  1526
        dt = NULL;
vb@3439
  1527
    }
vb@3439
  1528
vb@3439
  1529
     if (msg->from) {
vb@3439
  1530
        struct mailimf_mailbox_list *from = identity_to_mbl(msg->from);
vb@3439
  1531
        if (from == NULL)
vb@3439
  1532
            goto enomem;
vb@3439
  1533
vb@3439
  1534
        r = _append_field(fields_list, MAILIMF_FIELD_FROM,
vb@3439
  1535
                (_new_func_t) mailimf_from_new, from);
vb@3439
  1536
        if (r) {
vb@3439
  1537
            mailimf_mailbox_list_free(from);
vb@3439
  1538
            goto enomem;
vb@3439
  1539
        }
vb@3439
  1540
    }
vb@3439
  1541
vb@4534
  1542
    if (msg->to && msg->to->ident) {
vb@3439
  1543
        struct mailimf_address_list *to = identity_list_to_mal(msg->to);
vb@3439
  1544
        if (to == NULL)
vb@3439
  1545
            goto enomem;
vb@3439
  1546
vb@3439
  1547
        r = _append_field(fields_list, MAILIMF_FIELD_TO,
vb@3439
  1548
                (_new_func_t) mailimf_to_new, to);
vb@3439
  1549
        if (r) {
vb@3439
  1550
            mailimf_address_list_free(to);
vb@3439
  1551
            goto enomem;
vb@3439
  1552
        }
vb@3439
  1553
    }
vb@3439
  1554
vb@3439
  1555
    char* _subject = NULL;
vb@3439
  1556
    if (!must_field_value_be_encoded(subject)) {
vb@3439
  1557
        _subject = strdup(subject);
vb@3439
  1558
        assert(_subject);
vb@3439
  1559
    }
vb@3439
  1560
    else {
vb@3439
  1561
        _subject = mailmime_encode_subject_header("utf-8", subject, 1);
vb@3439
  1562
    }
vb@3439
  1563
    if (_subject == NULL)
vb@3439
  1564
        goto enomem;
vb@3439
  1565
vb@3439
  1566
    r = _append_field(fields_list, MAILIMF_FIELD_SUBJECT,
vb@3439
  1567
            (_new_func_t) mailimf_subject_new, _subject);
vb@3439
  1568
    if (r) {
vb@3439
  1569
        free(_subject);
vb@3439
  1570
        goto enomem;
vb@3439
  1571
    }
vb@3439
  1572
vb@4534
  1573
    if (msg->cc && msg->cc->ident) {
vb@3439
  1574
        struct mailimf_address_list *cc = identity_list_to_mal(msg->cc);
vb@3439
  1575
        if (cc == NULL)
vb@3439
  1576
            goto enomem;
vb@3439
  1577
vb@3439
  1578
        r = _append_field(fields_list, MAILIMF_FIELD_CC,
vb@3439
  1579
                (_new_func_t) mailimf_cc_new, cc);
vb@3439
  1580
        if (r) {
vb@3439
  1581
            mailimf_address_list_free(cc);
vb@3439
  1582
            goto enomem;
vb@3439
  1583
        }
vb@3439
  1584
    }
vb@3439
  1585
    
vb@4534
  1586
    if (msg->bcc && msg->bcc->ident) {
vb@3439
  1587
        struct mailimf_address_list *bcc = identity_list_to_mal(msg->bcc);
vb@3439
  1588
        if (bcc == NULL)
vb@3439
  1589
            goto enomem;
vb@3439
  1590
vb@3439
  1591
        r = _append_field(fields_list, MAILIMF_FIELD_BCC,
vb@3439
  1592
                (_new_func_t) mailimf_bcc_new, bcc);
vb@3439
  1593
        if (r) {
vb@3439
  1594
            mailimf_address_list_free(bcc);
vb@3439
  1595
            goto enomem;
vb@3439
  1596
        }
vb@3439
  1597
    }
vb@3439
  1598
    
vb@4534
  1599
    if (msg->reply_to && msg->reply_to->ident) {
vb@3439
  1600
        struct mailimf_address_list *reply_to = identity_list_to_mal(msg->reply_to);
vb@3439
  1601
        if (reply_to == NULL)
vb@3439
  1602
            goto enomem;
vb@3439
  1603
vb@3439
  1604
        r = _append_field(fields_list, MAILIMF_FIELD_REPLY_TO,
vb@3439
  1605
                (_new_func_t) mailimf_reply_to_new, reply_to);
vb@3439
  1606
        if (r) {
vb@3439
  1607
            mailimf_address_list_free(reply_to);
vb@3439
  1608
            goto enomem;
vb@3439
  1609
        }
vb@3439
  1610
    }
vb@3439
  1611
vb@4534
  1612
    if (msg->in_reply_to && msg->in_reply_to->value) {
vb@3439
  1613
        clist *in_reply_to = stringlist_to_clist(msg->in_reply_to, true);
vb@3439
  1614
        if (in_reply_to == NULL)
vb@3439
  1615
            goto enomem;
vb@3439
  1616
vb@3439
  1617
        r = _append_field(fields_list, MAILIMF_FIELD_IN_REPLY_TO,
vb@3439
  1618
                (_new_func_t) mailimf_in_reply_to_new, in_reply_to);
vb@3439
  1619
        if (r) {
vb@3439
  1620
            clist_free(in_reply_to);
vb@3439
  1621
            goto enomem;
vb@3439
  1622
        }
vb@3439
  1623
    }
vb@3439
  1624
vb@4534
  1625
    if (msg->references && msg->references->value) {
vb@3439
  1626
        clist *references = stringlist_to_clist(msg->references, true);
vb@3439
  1627
        if (references == NULL)
vb@3439
  1628
            goto enomem;
vb@3439
  1629
vb@3439
  1630
        r = _append_field(fields_list, MAILIMF_FIELD_REFERENCES,
vb@3439
  1631
                (_new_func_t) mailimf_references_new, references);
vb@3439
  1632
        if (r) {
vb@3439
  1633
            clist_free(references);
vb@3439
  1634
            goto enomem;
vb@3439
  1635
        }
vb@3439
  1636
    }
vb@3439
  1637
vb@4534
  1638
    if (msg->keywords && msg->keywords->value) {
vb@3439
  1639
        clist *keywords = stringlist_to_clist(msg->keywords, true);
vb@3439
  1640
        if (keywords == NULL)
vb@3439
  1641
            goto enomem;
vb@3439
  1642
vb@3439
  1643
        r = _append_field(fields_list, MAILIMF_FIELD_KEYWORDS,
vb@3439
  1644
                (_new_func_t) mailimf_keywords_new, keywords);
vb@3439
  1645
        if (r) {
vb@3439
  1646
            clist_free(keywords);
vb@3439
  1647
            goto enomem;
vb@3439
  1648
        }
vb@3439
  1649
    }
vb@3439
  1650
vb@4534
  1651
    if (msg->comments && msg->comments[0]) {
vb@3439
  1652
        char *comments = NULL;
vb@3439
  1653
        if (!must_field_value_be_encoded(msg->comments)) {
vb@3439
  1654
            comments = strdup(msg->comments);
vb@3439
  1655
            assert(comments);
vb@3439
  1656
        }
vb@3439
  1657
        else  {
vb@3439
  1658
            comments = mailmime_encode_subject_header("utf-8", msg->comments, 0);
vb@3439
  1659
        }
vb@3439
  1660
        if (comments == NULL)
vb@3439
  1661
            goto enomem;
vb@3439
  1662
vb@3439
  1663
        r = _append_field(fields_list, MAILIMF_FIELD_COMMENTS,
vb@3439
  1664
                (_new_func_t) mailimf_comments_new, comments);
vb@3439
  1665
        if (r) {
vb@3439
  1666
            free(comments);
vb@3439
  1667
            goto enomem;
vb@3439
  1668
        }
vb@3439
  1669
    }
vb@3439
  1670
vb@4534
  1671
    if (msg->opt_fields && msg->opt_fields->value) {
vb@3439
  1672
        stringpair_list_t *_l;
vb@3439
  1673
        for (_l = msg->opt_fields; _l && _l->value; _l = _l->next) {
vb@3439
  1674
            char *key = _l->value->key;
vb@3439
  1675
            char *value = _l->value->value;
vb@3439
  1676
            if (key && value) {
vb@3439
  1677
                r = _append_optional_field(fields_list, key, value);
vb@3439
  1678
vb@3439
  1679
                if (r)
vb@3439
  1680
                    goto enomem;
vb@3439
  1681
            }
vb@3439
  1682
        }
vb@3439
  1683
    }
vb@3439
  1684
vb@3439
  1685
    fields = mailimf_fields_new(fields_list);
vb@3439
  1686
    assert(fields);
vb@3439
  1687
    if (fields == NULL)
vb@3439
  1688
        goto enomem;
vb@3439
  1689
vb@3439
  1690
    *result = fields;
vb@3439
  1691
vb@3439
  1692
    return PEP_STATUS_OK;
vb@3439
  1693
vb@3439
  1694
enomem:
vb@3439
  1695
    status = PEP_OUT_OF_MEMORY;
vb@3439
  1696
vb@3439
  1697
    if (fields_list)
vb@3439
  1698
        clist_free(fields_list);
vb@3439
  1699
vb@3439
  1700
    if (fields)
vb@3439
  1701
        mailimf_fields_free(fields);
vb@3439
  1702
vb@3439
  1703
    return status;
vb@3439
  1704
}
vb@3439
  1705
vb@3439
  1706
static bool has_exceptional_extension(char* filename) {
vb@3439
  1707
    if (!filename)
vb@3439
  1708
        return false;
vb@3439
  1709
    int len = strlen(filename);
vb@3439
  1710
    if (len < 4)
vb@3439
  1711
        return false;
vb@3439
  1712
    char* ext_start = filename + (len - 4);
vb@3439
  1713
    if (strcmp(ext_start, ".pgp") == 0 || strcmp(ext_start, ".gpg") == 0 ||
vb@3439
  1714
        strcmp(ext_start, ".asc") == 0 || strcmp(ext_start, ".pEp") == 0)
vb@3439
  1715
        return true;
vb@3439
  1716
    return false;
vb@3439
  1717
}
vb@3439
  1718
vb@3439
  1719
static pEp_rid_list_t* choose_resource_id(pEp_rid_list_t* rid_list) {
vb@3439
  1720
    pEp_rid_list_t* retval = rid_list;
vb@3439
  1721
    
vb@3439
  1722
    /* multiple elements - least common case */
vb@3439
  1723
    if (rid_list && rid_list->next) {
vb@3439
  1724
        pEp_rid_list_t* rid_list_curr = rid_list;
vb@3439
  1725
        retval = rid_list; 
vb@3439
  1726
        
vb@3439
  1727
        while (rid_list_curr) {
vb@3439
  1728
            pEp_resource_id_type rid_type = rid_list_curr->rid_type;
vb@3439
  1729
            if (rid_type == PEP_RID_CID)
vb@3439
  1730
                retval = rid_list_curr;
vb@3439
  1731
            else if (rid_type == PEP_RID_FILENAME && has_exceptional_extension(rid_list_curr->rid))
vb@3439
  1732
                return rid_list_curr;
vb@3439
  1733
            rid_list_curr = rid_list_curr->next;
vb@3439
  1734
        }
vb@3439
  1735
    } 
vb@3439
  1736
    return retval;
vb@3439
  1737
}
vb@3439
  1738
vb@3439
  1739
// static void split_inlined_and_attached(bloblist_t** inlined, bloblist_t** attached) {
vb@3439
  1740
//     bloblist_t** curr_pp = attached;
vb@3439
  1741
//     bloblist_t* curr = *curr_pp;
vb@3439
  1742
//     
vb@3439
  1743
//     bloblist_t* inline_ret = NULL;
vb@3439
  1744
//     bloblist_t** inline_curr_pp = &inline_ret;
vb@3439
  1745
//     
vb@3439
  1746
//     bloblist_t* att_ret = NULL;
vb@3439
  1747
//     bloblist_t** att_curr_pp = &att_ret;
vb@3439
  1748
//     
vb@3439
  1749
//     while (curr) {
vb@3439
  1750
//         if (curr->disposition == PEP_CONTENT_DISP_INLINE) {
vb@3439
  1751
//             *inline_curr_pp = curr;
vb@3439
  1752
//             inline_curr_pp = &(curr->next);
vb@3439
  1753
//         }
vb@3439
  1754
//         else {
vb@3439
  1755
//             *att_curr_pp = curr;
vb@3439
  1756
//             att_curr_pp = &(curr->next);            
vb@3439
  1757
//         }
vb@3439
  1758
//         *curr_pp = curr->next;
vb@3439
  1759
//         curr->next = NULL;
vb@3439
  1760
//         curr = *curr_pp;
vb@3439
  1761
//     }
vb@3439
  1762
//     
vb@3439
  1763
//     *inlined = inline_ret;
vb@3439
  1764
//     *attached = att_ret;
vb@3439
  1765
// }
vb@3439
  1766
vb@3439
  1767
vb@3439
  1768
static PEP_STATUS mime_encode_message_plain(
vb@3439
  1769
        const message *msg,
vb@3439
  1770
        bool omit_fields,
vb@3439
  1771
        struct mailmime **result,
krista@4591
  1772
        bool has_pEp_msg_attachment
vb@3439
  1773
    )
vb@3439
  1774
{
vb@3439
  1775
    struct mailmime * mime = NULL;
vb@3439
  1776
    struct mailmime * submime = NULL;
vb@3439
  1777
    int r;
vb@3439
  1778
    PEP_STATUS status;
vb@3439
  1779
    //char *subject;
krista@4578
  1780
    const char *plaintext;
vb@3439
  1781
    char *htmltext;
vb@3439
  1782
vb@3439
  1783
    assert(msg);
vb@3439
  1784
    assert(result);
krista@4590
  1785
krista@4590
  1786
    // * Process body content, including html's inlined attachments *
vb@3439
  1787
    plaintext = (msg->longmsg) ? msg->longmsg : "";
vb@3439
  1788
    htmltext = msg->longmsg_formatted;
vb@3439
  1789
vb@3439
  1790
    if (htmltext && (htmltext[0] != '\0')) {
vb@3439
  1791
        /* first, we need to strip out the inlined attachments to ensure this
vb@3439
  1792
           gets set up correctly */
vb@3439
  1793
           
krista@4590
  1794
        // Note: this only, regardless of whether this is being done 
krista@4590
  1795
        // for the to-be-embedded message attachment generation or 
krista@4590
  1796
        // an encapsulating message which contains this, touches 
krista@4590
  1797
        // the body text of this input message. So transport encoding 
krista@4590
  1798
        // only refers to the body content here and inlined-attachments, and 
krista@4590
  1799
        // is decided WITHIN this function, not as an argument. 
krista@4590
  1800
        status = mime_html_text(plaintext, htmltext, msg->attachments, &mime);
vb@3439
  1801
                
vb@3439
  1802
        if (status != PEP_STATUS_OK)
vb@3439
  1803
            goto pEp_error;
vb@3439
  1804
    }
krista@4590
  1805
    else { /* body content only consists of a plaintext block */
vb@3439
  1806
        pEp_rid_list_t* resource = NULL;
krista@4590
  1807
krista@4590
  1808
        int pt_length = strlen(plaintext);
krista@4590
  1809
vb@3439
  1810
        if (is_PGP_message_text(plaintext)) {
vb@4502
  1811
            resource = NULL;
krista@4590
  1812
            
krista@4590
  1813
            // So... I think we got overencoding here once, which would be a bug 
krista@4590
  1814
            // in libetpan, unless it had to do with whitespace. If removing
krista@4590
  1815
            // transport encoding as a calculation here somehow leads to overencoding,
krista@4590
  1816
            // either we or libetpan are doing something bad.
krista@4590
  1817
//            int encoding_type = (transport_encode ? MAILMIME_MECHANISM_7BIT : 0);
vb@3439
  1818
            mime = get_text_part(resource, "application/octet-stream", plaintext,
krista@4590
  1819
                                 pt_length, MAILMIME_MECHANISM_7BIT);
vb@3439
  1820
        }
vb@3439
  1821
        else {
vb@4502
  1822
            resource = NULL;
krista@4590
  1823
            bool already_ascii = !(must_chunk_be_encoded(plaintext, pt_length, true));                
krista@4590
  1824
            int encoding_type = (already_ascii ? MAILMIME_MECHANISM_7BIT : MAILMIME_MECHANISM_QUOTED_PRINTABLE);
vb@3439
  1825
            mime = get_text_part(resource, "text/plain", plaintext, strlen(plaintext),
vb@3439
  1826
                    encoding_type);
vb@3439
  1827
        }
vb@3439
  1828
        free_rid_list(resource);
vb@3439
  1829
        
vb@3439
  1830
        assert(mime);
vb@3439
  1831
        if (mime == NULL)
vb@3439
  1832
            goto enomem;
vb@3439
  1833
    }
vb@3439
  1834
krista@4590
  1835
    /* Body content processed, now process normal attachments */
krista@4590
  1836
    
vb@3439
  1837
    bool normal_attachments = false;
vb@3439
  1838
    
vb@3439
  1839
    bloblist_t* traversal_ptr = msg->attachments;
vb@3439
  1840
    
krista@4581
  1841
    // If there were any inline attachments, they should have 
krista@4581
  1842
    // been stripped out in mime_html_text and dealt with. 
krista@4581
  1843
    // I'm not entirely sure what the alternative case 
krista@4581
  1844
    // is here. But basically, if there are any non-inlined 
krista@4581
  1845
    // attachments to deal with, this is designed to 
krista@4581
  1846
    // make sure we process them. So flag it for 
krista@4581
  1847
    // "hey, Bob, you got some regular attachments here"
krista@4581
  1848
    // so Bob (obviously, the MIME engine is called Bob)
krista@4581
  1849
    // can do the right thing in the next block.
vb@3439
  1850
    while (traversal_ptr) {
vb@3439
  1851
        if (traversal_ptr->disposition != PEP_CONTENT_DISP_INLINE) {
vb@3439
  1852
            normal_attachments = true;
vb@3439
  1853
            break;
vb@3439
  1854
        }
vb@3439
  1855
        traversal_ptr = traversal_ptr->next;
vb@3439
  1856
    }
vb@3439
  1857
vb@3439
  1858
    if (normal_attachments) {
vb@3439
  1859
        submime = mime;
vb@3439
  1860
        mime = part_multiple_new("multipart/mixed");
vb@3439
  1861
        assert(mime);
vb@3439
  1862
        if (mime == NULL)
vb@3439
  1863
            goto enomem;
vb@3439
  1864
vb@3439
  1865
        r = mailmime_smart_add_part(mime, submime);
vb@3439
  1866
        assert(r == MAILIMF_NO_ERROR);
vb@3439
  1867
        if (r == MAILIMF_ERROR_MEMORY) {
vb@3439
  1868
            goto enomem;
vb@3439
  1869
        }
vb@3439
  1870
        else {
vb@3439
  1871
            // mailmime_smart_add_part() takes ownership of submime
vb@3439
  1872
            submime = NULL;
vb@3439
  1873
        }
vb@3439
  1874
vb@3439
  1875
        bloblist_t *_a;
krista@3710
  1876
        bool first_one = true;
krista@3710
  1877
        
krista@4581
  1878
        // Go through the non-inline attachments and add em.
vb@3439
  1879
        for (_a = msg->attachments; _a != NULL; _a = _a->next) {
vb@3439
  1880
vb@3439
  1881
            if (_a->disposition == PEP_CONTENT_DISP_INLINE)
vb@3439
  1882
                continue;
vb@3439
  1883
krista@4590
  1884
            // solely for readability.
krista@4591
  1885
            bool is_pEp_msg_attachment = (first_one && has_pEp_msg_attachment);
krista@4590
  1886
krista@4590
  1887
            status = mime_attachment(_a, &submime, 
krista@4590
  1888
                                     is_pEp_msg_attachment);                         
krista@4590
  1889
vb@3439
  1890
            if (status != PEP_STATUS_OK)
vb@3439
  1891
                goto pEp_error;
krista@3710
  1892
            
krista@3710
  1893
            first_one = false;    
vb@3439
  1894
vb@3439
  1895
            r = mailmime_smart_add_part(mime, submime);
vb@3439
  1896
            assert(r == MAILIMF_NO_ERROR);
vb@3439
  1897
            if (r == MAILIMF_ERROR_MEMORY) {
vb@3439
  1898
                goto enomem;
vb@3439
  1899
            }
vb@3439
  1900
            else {
vb@3439
  1901
                // mailmime_smart_add_part() takes ownership of submime
vb@3439
  1902
                submime = NULL;
vb@3439
  1903
            }
vb@3439
  1904
        }
vb@3439
  1905
    }
vb@3439
  1906
vb@3439
  1907
    *result = mime;
vb@3439
  1908
    return PEP_STATUS_OK;
vb@3439
  1909
vb@3439
  1910
enomem:
vb@3439
  1911
    status = PEP_OUT_OF_MEMORY;
vb@3439
  1912
vb@3439
  1913
pEp_error:
vb@3439
  1914
    if (mime)
vb@3439
  1915
        mailmime_free(mime);
vb@3439
  1916
vb@3439
  1917
    if (submime)
vb@3439
  1918
        mailmime_free(submime);
vb@3439
  1919
vb@3439
  1920
    return status;
vb@3439
  1921
}
vb@3439
  1922
vb@3439
  1923
static PEP_STATUS mime_encode_message_PGP_MIME(
vb@3439
  1924
        const message * msg,
vb@3439
  1925
        bool omit_fields,
vb@3439
  1926
        struct mailmime **result
vb@3439
  1927
    )
vb@3439
  1928
{
vb@3439
  1929
    struct mailmime * mime = NULL;
vb@3439
  1930
    struct mailmime * submime = NULL;
vb@3439
  1931
	struct mailmime_parameter * param;
vb@3439
  1932
    int r;
vb@3439
  1933
    PEP_STATUS status;
vb@3439
  1934
    char *plaintext;
vb@3439
  1935
    size_t plaintext_size;
vb@3439
  1936
vb@3439
  1937
    assert(msg->attachments && msg->attachments->next &&
vb@3439
  1938
            msg->attachments->next->value);
vb@3439
  1939
vb@3439
  1940
    plaintext = msg->attachments->next->value;
vb@3439
  1941
    plaintext_size = msg->attachments->next->size;
vb@3439
  1942
vb@3439
  1943
    mime = part_multiple_new("multipart/encrypted");
vb@3439
  1944
    assert(mime);
vb@3439
  1945
    if (mime == NULL)
vb@3439
  1946
        goto enomem;
vb@3439
  1947
vb@3439
  1948
    param = mailmime_param_new_with_data("protocol", "application/pgp-encrypted");
vb@3439
  1949
    clist_append(mime->mm_content_type->ct_parameters, param);
vb@3439
  1950
vb@3439
  1951
    submime = get_pgp_encrypted_part();
vb@3439
  1952
    assert(submime);
vb@3439
  1953
    if (submime == NULL)
vb@3439
  1954
        goto enomem;
vb@3439
  1955
vb@3439
  1956
    r = mailmime_smart_add_part(mime, submime);
vb@3439
  1957
    assert(r == MAILIMF_NO_ERROR);
vb@3439
  1958
    if (r == MAILIMF_ERROR_MEMORY) {
vb@3439
  1959
        goto enomem;
vb@3439
  1960
    }
vb@3439
  1961
    else {
vb@3439
  1962
        // mailmime_smart_add_part() takes ownership of submime
vb@3439
  1963
        submime = NULL;
vb@3439
  1964
    }
vb@3439
  1965
vb@3439
  1966
    pEp_rid_list_t* resource = new_rid_node(PEP_RID_FILENAME, "msg.asc");
vb@3439
  1967
    submime = get_text_part(resource, "application/octet-stream", plaintext,
vb@3439
  1968
            plaintext_size, MAILMIME_MECHANISM_7BIT);
vb@3439
  1969
            
vb@3439
  1970
    free_rid_list(resource);
vb@3439
  1971
    
vb@3439
  1972
    assert(submime);
vb@3439
  1973
    if (submime == NULL)
vb@3439
  1974
        goto enomem;
vb@3439
  1975
vb@3439
  1976
    r = mailmime_smart_add_part(mime, submime);
vb@3439
  1977
    assert(r == MAILIMF_NO_ERROR);
vb@3439
  1978
    if (r == MAILIMF_ERROR_MEMORY) {
vb@3439
  1979
        goto enomem;
vb@3439
  1980
    }
vb@3439
  1981
    else {
vb@3439
  1982
        // mailmime_smart_add_part() takes ownership of submime
vb@3439
  1983
        submime = NULL;
vb@3439
  1984
    }
vb@3439
  1985
vb@3439
  1986
    *result = mime;
vb@3439
  1987
    return PEP_STATUS_OK;
vb@3439
  1988
vb@3439
  1989
enomem:
vb@3439
  1990
    status = PEP_OUT_OF_MEMORY;
vb@3439
  1991
vb@3439
  1992
    if (mime)
vb@3439
  1993
        mailmime_free(mime);
vb@3439
  1994
vb@3439
  1995
    if (submime)
vb@3439
  1996
        mailmime_free(submime);
vb@3439
  1997
vb@3439
  1998
    return status;
vb@3439
  1999
}
vb@3439
  2000
krista@4591
  2001
DYNAMIC_API PEP_STATUS mime_encode_message(
vb@3439
  2002
        const message * msg,
vb@3439
  2003
        bool omit_fields,
vb@3439
  2004
        char **mimetext,
krista@4591
  2005
        bool has_pEp_msg_attachment
vb@3439
  2006
    )
vb@3439
  2007
{
vb@3439
  2008
    PEP_STATUS status = PEP_STATUS_OK;
vb@3439
  2009
    struct mailmime * msg_mime = NULL;
vb@3439
  2010
    struct mailmime * mime = NULL;
vb@3439
  2011
    struct mailimf_fields * fields = NULL;
vb@3439
  2012
    char *buf = NULL;
vb@3439
  2013
    int r;
vb@3439
  2014
vb@3439
  2015
    assert(msg);
vb@3439
  2016
    assert(mimetext);
vb@3439
  2017
vb@3439
  2018
    if (!(msg && mimetext))
vb@3439
  2019
        return PEP_ILLEGAL_VALUE;
vb@3439
  2020
vb@3439
  2021
    *mimetext = NULL;
vb@3439
  2022
vb@3439
  2023
    switch (msg->enc_format) {
vb@3439
  2024
        case PEP_enc_none:
krista@4591
  2025
            status = mime_encode_message_plain(msg, omit_fields, &mime, has_pEp_msg_attachment);
vb@3439
  2026
            break;
vb@3439
  2027
krista@4591
  2028
        // I'm presuming we should hardcore ignoring has_pEp_msg_attachment here...
vb@3678
  2029
        case PEP_enc_inline:
krista@4590
  2030
            status = mime_encode_message_plain(msg, omit_fields, &mime, false);
vb@3439
  2031
            break;
vb@3439
  2032
vb@3439
  2033
        case PEP_enc_S_MIME:
vb@3439
  2034
            NOT_IMPLEMENTED
vb@3439
  2035
                
vb@3439
  2036
        case PEP_enc_PGP_MIME:
vb@3439
  2037
            status = mime_encode_message_PGP_MIME(msg, omit_fields, &mime);
vb@3439
  2038
            break;
vb@3439
  2039
vb@3439
  2040
        case PEP_enc_PEP:
vb@4489
  2041
            // today's pEp message format is PGP/MIME from the outside
vb@4489
  2042
            status = mime_encode_message_PGP_MIME(msg, omit_fields, &mime);
vb@4489
  2043
            break;
vb@3439
  2044
vb@3439
  2045
        default:
vb@3439
  2046
            NOT_IMPLEMENTED
vb@3439
  2047
    }
vb@3439
  2048
vb@3439
  2049
    if (status != PEP_STATUS_OK)
vb@3439
  2050
        goto pEp_error;
vb@3439
  2051
vb@3439
  2052
    msg_mime = mailmime_new_message_data(NULL);
vb@3439
  2053
    assert(msg_mime);
vb@3439
  2054
    if (msg_mime == NULL)
vb@3439
  2055
        goto enomem;
vb@3439
  2056
vb@3439
  2057
    r = mailmime_add_part(msg_mime, mime);
vb@3439
  2058
    if (r) {
vb@3439
  2059
        mailmime_free(mime);
vb@3439
  2060
        goto enomem;
vb@3439
  2061
    }
vb@3439
  2062
    mime = NULL;
vb@3439
  2063
vb@3439
  2064
    if (!omit_fields) {
vb@3439
  2065
        status = build_fields(msg, &fields);
vb@3439
  2066
        if (status != PEP_STATUS_OK)
vb@3439
  2067
            goto pEp_error;
vb@3439
  2068
vb@3439
  2069
        mailmime_set_imf_fields(msg_mime, fields);
vb@3439
  2070
    }
vb@3439
  2071
vb@3439
  2072
    status = render_mime(msg_mime, &buf);
vb@3439
  2073
    if (status != PEP_STATUS_OK)
vb@3439
  2074
        goto pEp_error;
vb@3439
  2075
vb@3439
  2076
    mailmime_free(msg_mime);
vb@3439
  2077
    *mimetext = buf;
vb@3439
  2078
vb@3439
  2079
    return PEP_STATUS_OK;
vb@3439
  2080
vb@3439
  2081
enomem:
vb@3439
  2082
    status = PEP_OUT_OF_MEMORY;
vb@3439
  2083
vb@3439
  2084
pEp_error:
vb@3439
  2085
    if (msg_mime)
vb@3439
  2086
        mailmime_free(msg_mime);
vb@3439
  2087
    else
vb@3439
  2088
        if (mime)
vb@3439
  2089
            mailmime_free(mime);
vb@3439
  2090
vb@3439
  2091
    return status;
vb@3439
  2092
}
vb@3439
  2093
vb@3439
  2094
static pEp_identity *mailbox_to_identity(const struct mailimf_mailbox * mb)
vb@3439
  2095
{
vb@3439
  2096
    char *username = NULL;
krista@4719
  2097
    char *address = NULL;
vb@3439
  2098
vb@3439
  2099
    assert(mb);
vb@3439
  2100
    assert(mb->mb_addr_spec);
vb@3439
  2101
vb@3439
  2102
    if (mb->mb_addr_spec == NULL)
vb@3439
  2103
        return NULL;
vb@3439
  2104
vb@3439
  2105
    if (mb->mb_display_name) {
vb@3439
  2106
        size_t index = 0;
vb@3439
  2107
        const int r = mailmime_encoded_phrase_parse("utf-8", mb->mb_display_name,
vb@3439
  2108
                strlen(mb->mb_display_name), &index, "utf-8", &username);
vb@3439
  2109
        if (r)
vb@3439
  2110
            goto enomem;
vb@3439
  2111
    }
vb@3439
  2112
krista@4719
  2113
    const char* raw_addr = mb->mb_addr_spec;
krista@4719
  2114
    if (raw_addr && raw_addr[0] == '"') {
krista@4719
  2115
        int addr_len = strlen(raw_addr);
krista@4719
  2116
        if (addr_len >= 6) { // ""@URI
krista@4719
  2117
            const char* endcheck = strstr(raw_addr + 1, "\"@URI");
krista@4719
  2118
            if (endcheck && *(endcheck + 5) == '\0') {
krista@4719
  2119
                int actual_size = addr_len - 6;
krista@4719
  2120
                address = calloc(actual_size + 1, 1);
krista@4719
  2121
                if (!address)
krista@4719
  2122
                    goto enomem;
krista@4719
  2123
                strlcpy(address, raw_addr + 1, actual_size + 1);    
krista@4719
  2124
            }
krista@4719
  2125
        }
krista@4719
  2126
    }
krista@4719
  2127
krista@4719
  2128
    pEp_identity *ident = new_identity(address ? address : raw_addr, NULL, NULL, username);
vb@3439
  2129
    if (ident == NULL)
vb@3439
  2130
        goto enomem;
vb@3439
  2131
    free(username);
krista@4719
  2132
    free(address);
vb@3439
  2133
    return ident;
vb@3439
  2134
vb@3439
  2135
enomem:
krista@4719
  2136
    free(address);
vb@3439
  2137
    free(username);
vb@3439
  2138
    return NULL;
vb@3439
  2139
}
vb@3439
  2140
vb@3439
  2141
static pEp_identity * mbl_to_identity(const struct mailimf_mailbox_list * mbl)
vb@3439
  2142
{
vb@3439
  2143
    struct mailimf_mailbox * mb = clist_content(clist_begin(mbl->mb_list));
vb@3439
  2144
    return mailbox_to_identity(mb);
vb@3439
  2145
}
vb@3439
  2146
vb@3439
  2147
static identity_list * mal_to_identity_list(
vb@3439
  2148
        const struct mailimf_address_list *mal
vb@3439
  2149
    )
vb@3439
  2150
{
vb@3439
  2151
    identity_list *il = new_identity_list(NULL);
vb@3439
  2152
    if (il == NULL)
vb@3439
  2153
        goto enomem;
vb@3439
  2154
vb@4537
  2155
    // if we have nothing to translate then return an empty list
vb@4537
  2156
    if (!mal)
vb@4537
  2157
        return il;
vb@4537
  2158
vb@4537
  2159
    clist *list = mal->ad_list;
vb@4537
  2160
vb@3439
  2161
    identity_list *_il = il;
vb@3439
  2162
    for (clistiter *cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
vb@3439
  2163
        pEp_identity *ident;
vb@3439
  2164
vb@3439
  2165
        struct mailimf_address *addr = clist_content(cur);
vb@3439
  2166
        switch(addr->ad_type) {
vb@3439
  2167
            case MAILIMF_ADDRESS_MAILBOX:
vb@3439
  2168
                ident = mailbox_to_identity(addr->ad_data.ad_mailbox);
vb@3439
  2169
                if (ident == NULL)
vb@3439
  2170
                    goto enomem;
vb@3439
  2171
                _il = identity_list_add(_il, ident);
vb@3439
  2172
                if (_il == NULL)
vb@3439
  2173
                    goto enomem;
vb@3439
  2174
                break;
vb@3439
  2175
vb@3439
  2176
            case MAILIMF_ADDRESS_GROUP:
vb@3439
  2177
                {
vb@3439
  2178
                    struct mailimf_mailbox_list * mbl =
vb@3439
  2179
                            addr->ad_data.ad_group->grp_mb_list;
vb@3439
  2180
                    for (clistiter *cur2 = clist_begin(mbl->mb_list); cur2 != NULL;
vb@3439
  2181
                            cur2 = clist_next(cur2)) {
vb@3439
  2182
                        ident = mailbox_to_identity(clist_content(cur));
vb@3439
  2183
                        if (ident == NULL)
vb@3439
  2184
                            goto enomem;
vb@3439
  2185
                        _il = identity_list_add(_il, ident);
vb@3439
  2186
                        if (_il == NULL)
vb@3439
  2187
                            goto enomem;
vb@3439
  2188
                    }
vb@3439
  2189
                }
vb@3439
  2190
                break;
vb@3439
  2191
vb@3439
  2192
            default:
vb@3439
  2193
                assert(0);
vb@3439
  2194
                goto enomem;
vb@3439
  2195
        }
vb@3439
  2196
    }
vb@3439
  2197
vb@3439
  2198
    return il;
vb@3439
  2199
vb@3439
  2200
enomem:
vb@3439
  2201
    free_identity_list(il);
vb@3439
  2202
    return NULL;
vb@3439
  2203
}
vb@3439
  2204
vb@3439
  2205
static stringlist_t * clist_to_stringlist(const clist *list)
vb@3439
  2206
{
vb@3439
  2207
    char *text = NULL;;
vb@3439
  2208
    stringlist_t * sl = new_stringlist(NULL);
vb@3439
  2209
    if (sl == NULL)
vb@3439
  2210
        return NULL;
vb@3439
  2211
vb@3439
  2212
    stringlist_t *_sl = sl;
vb@3439
  2213
    for (clistiter *cur = clist_begin(list); cur != NULL; cur = clist_next(cur)) {
vb@3439
  2214
        char *phrase = clist_content(cur);
vb@3439
  2215
        size_t index = 0;
vb@3439
  2216
        
vb@3439
  2217
        const int r = mailmime_encoded_phrase_parse("utf-8", phrase, strlen(phrase),
vb@3439
  2218
                &index, "utf-8", &text);
vb@3439
  2219
        if (r)
vb@3439
  2220
            goto enomem;
vb@3439
  2221
vb@3439
  2222
        _sl = stringlist_add(_sl, text);
vb@3439
  2223
        if (_sl == NULL)
vb@3439
  2224
            goto enomem;
vb@3439
  2225
vb@3439
  2226
        free(text);
vb@3439
  2227
        text = NULL;
vb@3439
  2228
    }
vb@3439
  2229
vb@3439
  2230
    return sl;
vb@3439
  2231
vb@3439
  2232
enomem:
vb@3439
  2233
    free_stringlist(sl);
vb@3439
  2234
    free(text);
vb@3439
  2235
vb@3439
  2236
    return NULL;
vb@3439
  2237
}
vb@3439
  2238
vb@3439
  2239
static PEP_STATUS read_fields(message *msg, clist *fieldlist)
vb@3439
  2240
{
vb@3439
  2241
    PEP_STATUS status = PEP_STATUS_OK;
vb@3439
  2242
    struct mailimf_field * _field;
vb@3439
  2243
    clistiter *cur;
vb@3439
  2244
    size_t index;
vb@3439
  2245
    int r;
vb@3439
  2246
    
vb@3439
  2247
    stringpair_list_t *opt = msg->opt_fields;
vb@3439
  2248
vb@3439
  2249
    if (!fieldlist)
vb@3439
  2250
        return PEP_STATUS_OK;
vb@3439
  2251
        
vb@3439
  2252
    for (cur = clist_begin(fieldlist); cur != NULL; cur = clist_next(cur)) {
vb@3439
  2253
        _field = clist_content(cur);
vb@3439
  2254
vb@3439
  2255
        switch (_field->fld_type) {
vb@3439
  2256
            case MAILIMF_FIELD_MESSAGE_ID:
vb@3439
  2257
                {
vb@3439
  2258
                    char * text = _field->fld_data.fld_message_id->mid_value;
vb@3439
  2259
vb@3439
  2260
                    free(msg->id);
vb@3439
  2261
                    index = 0;
vb@3439
  2262
                    r = mailmime_encoded_phrase_parse("utf-8", text,
vb@3439
  2263
                            strlen(text), &index, "utf-8", &msg->id);
vb@3439
  2264
                    if (r)
vb@3439
  2265
                        goto enomem;
vb@3439
  2266
                }
vb@3439
  2267
                break;
vb@3439
  2268
vb@3439
  2269
            case MAILIMF_FIELD_SUBJECT:
vb@3439
  2270
                {
vb@3439
  2271
                    char * text = _field->fld_data.fld_subject->sbj_value;
vb@3439
  2272
vb@3439
  2273
                    free(msg->shortmsg);
vb@3439
  2274
                    index = 0;
vb@3439
  2275
                    r = mailmime_encoded_phrase_parse("utf-8", text,
vb@3439
  2276
                            strlen(text), &index, "utf-8", &msg->shortmsg);
vb@3439
  2277
                    if (r)
vb@3439
  2278
                        goto enomem;
vb@3439
  2279
                }
vb@3439
  2280
                break;
vb@3439
  2281
vb@3439
  2282
            case MAILIMF_FIELD_ORIG_DATE:
vb@3439
  2283
                {
vb@3439
  2284
                    struct mailimf_date_time *date =
vb@3439
  2285
                        _field->fld_data.fld_orig_date->dt_date_time;
vb@3439
  2286
vb@3439
  2287
                    free_timestamp(msg->sent);
vb@3439
  2288
                    msg->sent = etpantime_to_timestamp(date);
vb@3439
  2289
                    if (msg->sent == NULL)
vb@3439
  2290
                        goto enomem;
vb@3439
  2291
                }
vb@3439
  2292
                break;
vb@3439
  2293
vb@3439
  2294
            case MAILIMF_FIELD_FROM:
vb@3439
  2295
                {
vb@3439
  2296
                    struct mailimf_mailbox_list *mbl =
vb@3439
  2297
                            _field->fld_data.fld_from->frm_mb_list;
vb@3439
  2298
                    pEp_identity *ident;
vb@3439
  2299
vb@3439
  2300
                    ident = mbl_to_identity(mbl);
vb@3439
  2301
                    if (ident == NULL)
vb@3439
  2302
                        goto pEp_error;
vb@3439
  2303
vb@3439
  2304
                    free_identity(msg->from);
vb@3439
  2305
                    msg->from = ident;
vb@3439
  2306
                }
vb@3439
  2307
                break;
vb@3439
  2308
vb@3439
  2309
            case MAILIMF_FIELD_TO:
vb@3439
  2310
                {
vb@3439
  2311
                    struct mailimf_address_list *mal =
vb@3439
  2312
                            _field->fld_data.fld_to->to_addr_list;
vb@3439
  2313
                    identity_list *il = mal_to_identity_list(mal);
vb@3439
  2314
                    if (il == NULL)
vb@3439
  2315
                        goto enomem;
vb@3439
  2316
vb@3439
  2317
                    free_identity_list(msg->to);
vb@3439
  2318
                    msg->to = il;
vb@3439
  2319
                }
vb@3439
  2320
                break;
vb@3439
  2321
vb@3439
  2322
            case MAILIMF_FIELD_CC:
vb@3439
  2323
                {
vb@3439
  2324
                    struct mailimf_address_list *mal =
vb@3439
  2325
                            _field->fld_data.fld_cc->cc_addr_list;
vb@3439
  2326
                    identity_list *il = mal_to_identity_list(mal);
vb@3439
  2327
                    if (il == NULL)
vb@3439
  2328
                        goto enomem;
vb@3439
  2329
vb@3439
  2330
                    free_identity_list(msg->cc);
vb@3439
  2331
                    msg->cc = il;
vb@3439
  2332
                }
vb@3439
  2333
                break;
vb@3439
  2334
vb@3439
  2335
            case MAILIMF_FIELD_BCC:
vb@3439
  2336
                {
vb@3439
  2337
                    struct mailimf_address_list *mal =
vb@3439
  2338
                            _field->fld_data.fld_bcc->bcc_addr_list;
vb@3439
  2339
                    identity_list *il = mal_to_identity_list(mal);
vb@3439
  2340
                    if (il == NULL)
vb@3439
  2341
                        goto enomem;
vb@3439
  2342
vb@3439
  2343
                    free_identity_list(msg->bcc);
vb@3439
  2344
                    msg->bcc = il;
vb@3439
  2345
                }
vb@3439
  2346
                break;
vb@3439
  2347
vb@3439
  2348
            case MAILIMF_FIELD_REPLY_TO:
vb@3439
  2349
                {
vb@3439
  2350
                    struct mailimf_address_list *mal =
vb@3439
  2351
                            _field->fld_data.fld_reply_to->rt_addr_list;
vb@3439
  2352
                    identity_list *il = mal_to_identity_list(mal);
vb@3439
  2353
                    if (il == NULL)
vb@3439
  2354
                        goto enomem;
vb@3439
  2355
vb@3439
  2356
                    free_identity_list(msg->reply_to);
vb@3439
  2357
                    msg->reply_to = il;
vb@3439
  2358
                }
vb@3439
  2359
                break;
vb@3439
  2360
vb@3439
  2361
            case MAILIMF_FIELD_IN_REPLY_TO:
vb@3439
  2362
                {
vb@3439
  2363
                    clist *list = _field->fld_data.fld_in_reply_to->mid_list;
vb@3439
  2364
                    stringlist_t *sl = clist_to_stringlist(list);
vb@3439
  2365
                    if (sl == NULL)
vb@3439
  2366
                        goto enomem;
vb@3439
  2367
vb@3439
  2368
                    free_stringlist(msg->in_reply_to);
vb@3439
  2369
                    msg->in_reply_to = sl;
vb@3439
  2370
                }
vb@3439
  2371
                break;
vb@3439
  2372
vb@3439
  2373
            case MAILIMF_FIELD_REFERENCES:
vb@3439
  2374
                {
vb@3439
  2375
                    clist *list = _field->fld_data.fld_references->mid_list;
vb@3439
  2376
                    stringlist_t *sl = clist_to_stringlist(list);
vb@3439
  2377
                    if (sl == NULL)
vb@3439
  2378
                        goto enomem;
vb@3439
  2379
vb@3439
  2380
                    free_stringlist(msg->references);
vb@3439
  2381
                    msg->references = sl;
vb@3439
  2382
                }
vb@3439
  2383
                break;
vb@3439
  2384
vb@3439
  2385
            case MAILIMF_FIELD_KEYWORDS:
vb@3439
  2386
                {
vb@3439
  2387
                    clist *list = _field->fld_data.fld_keywords->kw_list;
vb@3439
  2388
                    stringlist_t *sl = clist_to_stringlist(list);
vb@3439
  2389
                    if (sl == NULL)
vb@3439
  2390
                        goto enomem;
vb@3439
  2391
vb@3439
  2392
                    free_stringlist(msg->keywords);
vb@3439
  2393
                    msg->keywords = sl;
vb@3439
  2394
                }
vb@3439
  2395
                break;
vb@3439
  2396
vb@3439
  2397
            case MAILIMF_FIELD_COMMENTS:
vb@3439
  2398
                {
vb@3439
  2399
                    char * text = _field->fld_data.fld_comments->cm_value;
vb@3439
  2400
vb@3439
  2401
                    free(msg->comments);
vb@3439
  2402
                    index = 0;
vb@3439
  2403
                    r = mailmime_encoded_phrase_parse("utf-8", text,
vb@3439
  2404
                            strlen(text), &index, "utf-8", &msg->comments);
vb@3439
  2405
                    if (r)
vb@3439
  2406
                        goto enomem;
vb@3439
  2407
                }
vb@3439
  2408
                break;
vb@3439
  2409
vb@3439
  2410
            case MAILIMF_FIELD_OPTIONAL_FIELD:
vb@3439
  2411
                {
vb@3439
  2412
                    char * name =
vb@3439
  2413
                            _field->fld_data.fld_optional_field->fld_name;
vb@3439
  2414
                    char * value =
vb@3439
  2415
                            _field->fld_data.fld_optional_field->fld_value;
vb@3439
  2416
                    char *_value;
vb@3439
  2417
vb@3439
  2418
                    index = 0;
vb@3439
  2419
                    r = mailmime_encoded_phrase_parse("utf-8", value,
vb@3439
  2420
                            strlen(value), &index, "utf-8", &_value);
vb@3439
  2421
                    if (r)
vb@3439
  2422
                        goto enomem;
vb@3439
  2423
vb@3439
  2424
                    stringpair_t *pair = new_stringpair(name, _value);
vb@3439
  2425
                    if (pair == NULL)
vb@3439
  2426
                        goto enomem;
vb@3439
  2427
vb@3439
  2428
                    opt = stringpair_list_add(opt, pair);
vb@3439
  2429
                    free(_value);
vb@3439
  2430
                    if (opt == NULL)
vb@3439
  2431
                        goto enomem;
vb@3439
  2432
vb@3439
  2433
                    if (msg->opt_fields == NULL)
vb@3439
  2434
                        msg->opt_fields = opt;
vb@3439
  2435
                }
vb@3439
  2436
                break;
vb@3439
  2437
        }
vb@3439
  2438
    }
vb@3439
  2439
    
vb@3439
  2440
    return PEP_STATUS_OK;
vb@3439
  2441
vb@3439
  2442
enomem:
vb@3439
  2443
    status = PEP_OUT_OF_MEMORY;
vb@3439
  2444
vb@3439
  2445
pEp_error:
vb@3439
  2446
    return status;
vb@3439
  2447
}
vb@3439
  2448
vb@3439
  2449
static PEP_STATUS interpret_body(struct mailmime *part, char **longmsg, size_t *size)
vb@3439
  2450
{
vb@3439
  2451
    const char *text;
vb@3439
  2452
    char *_longmsg;
vb@3439
  2453
    size_t length;
vb@3439
  2454
    size_t _size;
vb@3439
  2455
    size_t index;
vb@3439
  2456
    char *type = NULL;
vb@3439
  2457
    char *charset = NULL;
vb@3439
  2458
vb@3439
  2459
    assert(part);
vb@3439
  2460
    assert(longmsg);
vb@3439
  2461
vb@3439
  2462
    *longmsg = NULL;
vb@3439
  2463
    if (size)
vb@3439
  2464
        *size = 0;
vb@3439
  2465
vb@3439
  2466
    if (part->mm_body == NULL)
vb@3439
  2467
        return PEP_ILLEGAL_VALUE;
vb@3439
  2468
vb@3439
  2469
    text = part->mm_body-> dt_data.dt_text.dt_data;
vb@3439
  2470
    if (text == NULL)
vb@3439
  2471
        return PEP_ILLEGAL_VALUE;
vb@3439
  2472
vb@3439
  2473
    length = part->mm_body->dt_data.dt_text.dt_length;
vb@3439
  2474
vb@3439
  2475
    if (part->mm_body->dt_encoded) {
vb@3439
  2476
        int code = part->mm_body->dt_encoding;
vb@3439
  2477
        index = 0;
vb@3439
  2478
        int r = mailmime_part_parse(text, length, &index, code, &_longmsg, &_size);
vb@3439
  2479
        switch (r) {
vb@3439
  2480
            case MAILIMF_NO_ERROR:
vb@3439
  2481
                break;
vb@3439
  2482
            case MAILIMF_ERROR_MEMORY:
vb@3439
  2483
                return PEP_OUT_OF_MEMORY;
vb@3439
  2484
            default:
vb@3439
  2485
                return PEP_ILLEGAL_VALUE;
vb@3439
  2486
        }
vb@3439
  2487
    }
vb@3439
  2488
    else {
vb@3439
  2489
        _size = length + 1;
vb@3439
  2490
        _longmsg = strndup(text, length);
vb@3439
  2491
        if (_longmsg == NULL)
vb@3439
  2492
            return PEP_OUT_OF_MEMORY;
vb@3439
  2493
    }
vb@3439
  2494
vb@3439
  2495
    if (part->mm_content_type) {
vb@3439
  2496
        if (_get_content_type(part->mm_content_type, &type, &charset) == 0) {
vb@3439
  2497
            if (charset && strncasecmp(charset, "utf-8", 5) != 0) {
vb@3439
  2498
                char * _text;
vb@3439
  2499
                int r = charconv("utf-8", charset, _longmsg, _size, &_text);
vb@3439
  2500
                switch (r) {
vb@3439
  2501
                    case MAILIMF_NO_ERROR:
vb@3439
  2502
                        break;
vb@3439
  2503
                    case MAILIMF_ERROR_MEMORY:
vb@3439
  2504
                        return PEP_OUT_OF_MEMORY;
vb@3439
  2505
                    default:
vb@3439
  2506
                        return PEP_ILLEGAL_VALUE;
vb@3439
  2507
                }
vb@3439
  2508
                free(_longmsg);
vb@3439
  2509
                _longmsg = _text;
vb@3439
  2510
            }
vb@3439
  2511
        }
vb@3439
  2512
    }
vb@3439
  2513
    // FIXME: KG - we now have the text we want.
vb@3439
  2514
    // Now we need to strip sigs and process them if they are there..
vb@3439
  2515
    
vb@3439
  2516
vb@3439
  2517
    *longmsg = _longmsg;
vb@3439
  2518
    if (size)
vb@3439
  2519
        *size = _size;
vb@3439
  2520
vb@3439
  2521
    return PEP_STATUS_OK;
vb@3439
  2522
}
vb@3439
  2523
vb@3439
  2524
// THIS IS A BEST-EFFORT ONLY FUNCTION, AND WE ARE NOT DOING MORE THAN THE
vb@3439
  2525
// SUBJECT FOR NOW.
vb@3439
  2526
static PEP_STATUS interpret_protected_headers(
vb@3439
  2527
        struct mailmime* mime, 
vb@3439
  2528
        message* msg
vb@3439
  2529
    )
vb@3439
  2530
{
vb@3439
  2531
    // N.B. this is *very much* enigmail output specific, and right now,
vb@3439
  2532
    // we only care about subject replacement.
vb@3439
  2533
    const char* header_string = "Content-Type: text/rfc822-headers; protected-headers=\"v1\"\nContent-Disposition: inline\n\n";
vb@3439
  2534
    size_t content_length = mime->mm_length;
vb@3439
  2535
    size_t header_strlen = strlen(header_string);
vb@3439
  2536
    if (header_strlen < content_length) {
vb@3439
  2537
        const char* headerblock = mime->mm_mime_start;
vb@3439
  2538
        size_t subject_len = 0;
vb@3439
  2539
        headerblock = strstr(headerblock, header_string);
vb@3439
  2540
        if (headerblock) {
vb@3439
  2541
            const char* subj_start = "Subject: ";
vb@3439
  2542
            headerblock = strstr(headerblock, subj_start);
vb@3439
  2543
            if (headerblock) {
vb@3439
  2544
                size_t subj_len = strlen(subj_start);
vb@3439
  2545
                headerblock += subj_len;
vb@3439
  2546
                char* end_pt = strstr(headerblock, "\n");
vb@3439
  2547
                if (end_pt) {
vb@3439
  2548
                    if (end_pt != mime->mm_mime_start && *(end_pt - 1) == '\r')
vb@3439
  2549
                        end_pt--;
vb@3439
  2550
                    subject_len = end_pt - headerblock;
vb@3439
  2551
                    char* new_subj = (char*)calloc(subject_len + 1, 1);
vb@3439
  2552
                    if (new_subj) {
vb@3439
  2553
                        strlcpy(new_subj, headerblock, subject_len + 1);
vb@3439
  2554
                        free(msg->shortmsg);
vb@3439
  2555
                        msg->shortmsg = new_subj;
vb@3439
  2556
                    }    
vb@3439
  2557
                } // if there's no endpoint, there's something wrong here so we ignore all
vb@3439
  2558
                  // This is best effort.
vb@3439
  2559
            }
vb@3439
  2560
        }
vb@3439
  2561
    }
vb@3439
  2562
    return PEP_STATUS_OK;
vb@3439
  2563
}
vb@3439
  2564
vb@3439
  2565
// ONLY for main part!!!
vb@3439
  2566
static PEP_STATUS process_multipart_related(struct mailmime *mime,
vb@3439
  2567
                                            message *msg) {
vb@3439
  2568
    PEP_STATUS status = PEP_STATUS_OK;
vb@3439
  2569
vb@3439
  2570
    assert(mime);
vb@3439
  2571
    assert(msg);
vb@3439
  2572
vb@3439
  2573
    clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;                                                
vb@3439
  2574
vb@3439
  2575
    if (partlist == NULL)
vb@3439
  2576
        return PEP_ILLEGAL_VALUE;
vb@3439
  2577
vb@3439
  2578
    clistiter *cur = clist_begin(partlist);
vb@3439
  2579
    struct mailmime *part = clist_content(cur);
vb@3439
  2580
    
vb@3439
  2581
    if (part == NULL)
vb@3439
  2582
        return PEP_ILLEGAL_VALUE;
vb@3439
  2583
vb@3439
  2584
    struct mailmime_content *content = part->mm_content_type;    
vb@3439
  2585
    assert(content);
vb@3439
  2586
    
vb@3439
  2587
    if (content == NULL)
vb@3439
  2588
        return PEP_ILLEGAL_VALUE;
vb@3439
  2589
vb@3439
  2590
    if (_is_text_part(content, "html")) {
vb@3439
  2591
        status = interpret_body(part, &msg->longmsg_formatted,
vb@3439
  2592
                NULL);
vb@3439
  2593
        if (status)
vb@3439
  2594
            return status;
vb@3439
  2595
    }
vb@3439
  2596
    else {
vb@3439
  2597
        // ???
vb@3439
  2598
        // This is what we would have done before, so... no
vb@3439
  2599
        // worse than the status quo. But FIXME!
krista@3710
  2600
        status = interpret_MIME(part, msg, NULL);
vb@3439
  2601
        if (status)
vb@3439
  2602
            return status;
vb@3439
  2603
    }
vb@3439
  2604
    
vb@3439
  2605
    for (cur = clist_next(cur); cur; cur = clist_next(cur)) {
vb@3439
  2606
        part = clist_content(cur);
vb@3439
  2607
        if (part == NULL)
vb@3439
  2608
            return PEP_ILLEGAL_VALUE;
vb@3439
  2609
vb@3439
  2610
        content = part->mm_content_type;
vb@3439
  2611
        assert(content);
vb@3439
  2612
        if (content == NULL)
vb@3439
  2613
            return PEP_ILLEGAL_VALUE;
vb@3439
  2614
krista@3710
  2615
        status = interpret_MIME(part, msg, NULL);
vb@3439
  2616
        if (status)
vb@3439
  2617
            return status;
vb@3439
  2618
    }
vb@3439
  2619
    return status;
vb@3439
  2620
}
vb@3439
  2621
vb@4569
  2622
static bool _is_marked_as_attachment(struct mailmime_fields *fields)
vb@4569
  2623
{
vb@4569
  2624
    if (!(fields && fields->fld_list))
vb@4569
  2625
        return false;
vb@4569
  2626
vb@4569
  2627
    clistiter *cur;
vb@4569
  2628
    for (cur = clist_begin(fields->fld_list); cur != NULL ; cur = clist_next(cur)) {
vb@4569
  2629
        struct mailmime_field * field = clist_content(cur);
vb@4569
  2630
        if (!(field && field->fld_type == MAILMIME_FIELD_DISPOSITION &&
vb@4569
  2631
                    field->fld_data.fld_disposition &&
vb@4569
  2632
                    field->fld_data.fld_disposition->dsp_t