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