src/mime.c
author vb
Sun, 08 Feb 2015 15:47:51 -0500
changeset 57 03f99659418e
parent 52 a667998cedf1
child 59 88429085f8da
permissions -rw-r--r--
adding support for MIME multipart/alternative with HTML
vb@48
     1
#include "mime.h"
vb@48
     2
vb@48
     3
#include <libetpan/libetpan.h>
vb@48
     4
#include <string.h>
vb@48
     5
#include <stdlib.h>
vb@48
     6
#include <assert.h>
vb@48
     7
#include <errno.h>
vb@48
     8
#include <unistd.h>
vb@48
     9
vb@48
    10
#include "etpan_mime.h"
vb@48
    11
vb@48
    12
DYNAMIC_API PEP_STATUS mime_encode_text(
vb@48
    13
        const char *plaintext,
vb@48
    14
        const char *htmltext,
vb@48
    15
        char **resulttext
vb@48
    16
    )
vb@48
    17
{
vb@48
    18
    struct mailmime * msg_mime = NULL;
vb@48
    19
	struct mailimf_fields * fields = NULL;
vb@48
    20
    struct mailmime * mime = NULL;
vb@48
    21
    struct mailmime * submime = NULL;
vb@48
    22
    int col;
vb@48
    23
    int r;
vb@48
    24
    int fd;
vb@48
    25
    FILE *file = NULL;
vb@48
    26
    size_t size;
vb@48
    27
    char *buf = NULL;
vb@52
    28
    PEP_STATUS error;
vb@48
    29
vb@48
    30
    assert(plaintext);
vb@48
    31
    assert(resulttext);
vb@48
    32
vb@48
    33
    *resulttext = NULL;
vb@48
    34
vb@48
    35
    msg_mime = mailmime_new_message_data(NULL);
vb@48
    36
    assert(msg_mime);
vb@48
    37
    if (msg_mime == NULL)
vb@48
    38
        goto enomem;
vb@48
    39
vb@48
    40
    fields = mailimf_fields_new_empty();
vb@48
    41
    assert(fields);
vb@48
    42
    if (fields == NULL)
vb@48
    43
        goto enomem;
vb@48
    44
vb@48
    45
    mailmime_set_imf_fields(msg_mime, fields);
vb@48
    46
vb@57
    47
    if (htmltext) {
vb@57
    48
        mime = part_multiple_new("multipart/alternative", NULL);
vb@57
    49
        assert(mime);
vb@57
    50
        if (mime == NULL)
vb@57
    51
            goto enomem;
vb@48
    52
vb@57
    53
        submime = get_text_part("text/plain", plaintext, strlen(plaintext),
vb@57
    54
                MAILMIME_MECHANISM_QUOTED_PRINTABLE);
vb@57
    55
        assert(submime);
vb@57
    56
        if (submime == NULL) {
vb@57
    57
            mailmime_free(msg_mime);
vb@57
    58
            goto enomem;
vb@57
    59
        }
vb@48
    60
vb@57
    61
        r = mailmime_smart_add_part(mime, submime);
vb@57
    62
        assert(r == MAILIMF_NO_ERROR);
vb@57
    63
        if (r == MAILIMF_ERROR_MEMORY) {
vb@57
    64
            mailmime_free(msg_mime);
vb@57
    65
            goto enomem;
vb@57
    66
        }
vb@57
    67
        else {
vb@57
    68
            // mailmime_smart_add_part() takes ownership of submime
vb@57
    69
            submime = NULL;
vb@57
    70
        }
vb@57
    71
vb@57
    72
        submime = get_text_part("text/html", htmltext, strlen(htmltext),
vb@57
    73
                MAILMIME_MECHANISM_QUOTED_PRINTABLE);
vb@57
    74
        assert(submime);
vb@57
    75
        if (submime == NULL) {
vb@57
    76
            mailmime_free(msg_mime);
vb@57
    77
            goto enomem;
vb@57
    78
        }
vb@57
    79
vb@57
    80
        r = mailmime_smart_add_part(mime, submime);
vb@57
    81
        assert(r == MAILIMF_NO_ERROR);
vb@57
    82
        if (r == MAILIMF_ERROR_MEMORY) {
vb@57
    83
            mailmime_free(msg_mime);
vb@57
    84
            goto enomem;
vb@57
    85
        }
vb@57
    86
        else {
vb@57
    87
            // mailmime_smart_add_part() takes ownership of submime
vb@57
    88
            submime = NULL;
vb@57
    89
        }
vb@48
    90
    }
vb@48
    91
    else {
vb@57
    92
        mime = get_text_part("text/plain", plaintext, strlen(plaintext),
vb@57
    93
                MAILMIME_MECHANISM_QUOTED_PRINTABLE);
vb@57
    94
        assert(mime);
vb@57
    95
        if (mime == NULL) {
vb@57
    96
            mailmime_free(msg_mime);
vb@57
    97
            goto enomem;
vb@57
    98
        }
vb@48
    99
    }
vb@48
   100
vb@48
   101
    r = mailmime_add_part(msg_mime, mime);
vb@48
   102
    assert(r == MAILIMF_NO_ERROR);
vb@48
   103
    if (r == MAILIMF_ERROR_MEMORY) {
vb@48
   104
        goto enomem;
vb@48
   105
    }
vb@48
   106
    // mailmime_add_part() takes ownership of mime
vb@48
   107
vb@51
   108
    char *template = strdup("/tmp/pEp.XXXXXXXXXXXXXXXXXXXX");
vb@48
   109
    assert(template);
vb@48
   110
    if (template == NULL)
vb@48
   111
        goto enomem;
vb@48
   112
vb@48
   113
    do {
vb@48
   114
        fd = mkstemp(template);
vb@48
   115
    } while (fd == -1 && errno == EINTR);
vb@48
   116
vb@48
   117
    assert(fd != -1);
vb@48
   118
    if (fd == -1)
vb@48
   119
        goto err_file;
vb@48
   120
vb@48
   121
    r = unlink(template);
vb@48
   122
    assert(r == 0);
vb@48
   123
    if (r == -1)
vb@48
   124
        goto err_file;
vb@48
   125
vb@48
   126
    free(template);
vb@48
   127
    template = NULL;
vb@48
   128
vb@48
   129
    do {
vb@48
   130
        file = fdopen(fd, "w+");
vb@48
   131
    } while (file == NULL && errno == EINTR);
vb@48
   132
vb@48
   133
    assert(file);
vb@48
   134
    if (file == NULL) {
vb@48
   135
        switch (errno) {
vb@48
   136
            case ENOMEM:
vb@48
   137
                goto enomem;
vb@48
   138
            default:
vb@48
   139
                goto err_file;
vb@48
   140
        }
vb@48
   141
    }
vb@48
   142
vb@48
   143
    fd = -1;
vb@48
   144
vb@48
   145
    col = 0;
vb@48
   146
    r = mailmime_write_file(file, &col, mime);
vb@48
   147
    assert(r == MAILIMF_NO_ERROR);
vb@48
   148
    if (r == MAILIMF_ERROR_MEMORY)
vb@48
   149
        goto enomem;
vb@48
   150
    else if (r != MAILIMF_NO_ERROR)
vb@48
   151
        goto err_file;
vb@48
   152
vb@48
   153
    off_t len = ftello(file);
vb@48
   154
    assert(len != -1);
vb@48
   155
    if (len == -1 && errno == EOVERFLOW)
vb@48
   156
        goto err_file;
vb@48
   157
vb@48
   158
    if (len + 1 > SIZE_T_MAX)
vb@48
   159
        goto err_buffer;
vb@48
   160
vb@48
   161
    size = (size_t) len;
vb@48
   162
vb@51
   163
    errno = 0;
vb@48
   164
    rewind(file);
vb@51
   165
    assert(errno == 0);
vb@51
   166
    clearerr(file);
vb@48
   167
vb@48
   168
    buf = calloc(1, size + 1);
vb@48
   169
    assert(buf);
vb@48
   170
    if (buf == NULL)
vb@48
   171
        goto enomem;
vb@48
   172
    
vb@48
   173
    char *_buf = buf;
vb@48
   174
    size_t rest = size;
vb@48
   175
    for (size_t bytes_read = 0; rest > 0; rest -= bytes_read, _buf += rest) {
vb@48
   176
        assert(feof(file) == 0);
vb@48
   177
        if (feof(file))
vb@48
   178
            goto err_file;
vb@51
   179
        bytes_read = rest * fread(_buf, rest, 1, file);
vb@48
   180
        if (ferror(file))
vb@48
   181
            goto err_file;
vb@48
   182
    }
vb@48
   183
vb@48
   184
    fclose(file);
vb@48
   185
    mailmime_free(msg_mime);
vb@48
   186
    *resulttext = buf;
vb@48
   187
    return PEP_STATUS_OK;
vb@48
   188
vb@48
   189
err_buffer:
vb@48
   190
    error = PEP_BUFFER_TOO_SMALL;
vb@52
   191
    goto release;
vb@48
   192
vb@48
   193
err_file:
vb@48
   194
    error = PEP_CANNOT_CREATE_TEMP_FILE;
vb@52
   195
    goto release;
vb@48
   196
vb@48
   197
enomem:
vb@52
   198
    error = PEP_OUT_OF_MEMORY;
vb@52
   199
vb@52
   200
release:
vb@48
   201
    free(buf);
vb@48
   202
    free(template);
vb@48
   203
vb@48
   204
    if (file)
vb@48
   205
        fclose(file);
vb@48
   206
    else if (fd != -1)
vb@48
   207
        close(fd);
vb@48
   208
vb@48
   209
    if (msg_mime)
vb@48
   210
        mailmime_free(msg_mime);
vb@48
   211
    if (fields)
vb@48
   212
        mailimf_fields_free(fields);
vb@48
   213
    if (submime)
vb@48
   214
        mailmime_free(submime);
vb@48
   215
vb@48
   216
    return error;
vb@48
   217
}