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