src/mime.c
author Edouard Tisserant
Wed, 22 Jun 2016 11:12:16 +0200
branchnull_size_attachment
changeset 754 2aab9c3e29ca
parent 747 d357dceebec6
child 871 f0c1582416e3
permissions -rw-r--r--
support for 0b attachment with PEP_enc_pieces (not tested)
     1 #include "pEp_internal.h"
     2 #include "mime.h"
     3 
     4 #include <string.h>
     5 #include <stdlib.h>
     6 #include <assert.h>
     7 #include <errno.h>
     8 
     9 #include "etpan_mime.h"
    10 #include "wrappers.h"
    11 
    12 static bool is_whitespace(char c)
    13 {
    14     switch (c) {
    15         case ' ':
    16         case '\t':
    17         case '\r':
    18         case '\n':
    19             return true;
    20 
    21         default:
    22             return false;
    23     }
    24 }
    25 
    26 DYNAMIC_API bool is_PGP_message_text(const char *text)
    27 {
    28     if (text == NULL)
    29         return false;
    30 
    31     for (; *text && is_whitespace(*text); text++);
    32 
    33     return strncmp(text, "-----BEGIN PGP MESSAGE-----", 27) == 0;
    34 }
    35 
    36 #define TMP_TEMPLATE "pEp.XXXXXXXXXXXXXXXXXXXX"
    37 #ifdef _WIN32
    38 #define PATH_SEP '\\'
    39 #else
    40 #define PATH_SEP '/'
    41 #endif
    42 
    43 static PEP_STATUS render_mime(struct mailmime *mime, char **mimetext)
    44 {
    45     PEP_STATUS status = PEP_STATUS_OK;
    46     int fd = -1;
    47     FILE *file = NULL;
    48     size_t size;
    49     char *buf = NULL;
    50     int col;
    51     int r;
    52 
    53     char *template = NULL;
    54     char *env_tmp = getenv("TEMP");
    55 
    56     if(env_tmp){
    57         unsigned long tmp_l = strlen(env_tmp);
    58         if(tmp_l == 0 ) {
    59             goto err_file;
    60         } else {
    61             int need_sep = (env_tmp[tmp_l-1] != PATH_SEP);
    62             template = calloc(1, tmp_l + 
    63                                  (need_sep ? 1 : 0) +
    64                                  sizeof(TMP_TEMPLATE));
    65             if (template == NULL)
    66                 goto enomem;
    67 
    68             memcpy(template, env_tmp, tmp_l);
    69             if(need_sep)
    70                 template[tmp_l] = PATH_SEP;
    71             memcpy(template + tmp_l + (need_sep ? 1 : 0), TMP_TEMPLATE, sizeof(TMP_TEMPLATE));
    72         }
    73     }else{
    74         template = strdup("/tmp/" TMP_TEMPLATE);
    75         if (template == NULL)
    76             goto enomem;
    77     }
    78     assert(template);
    79 
    80     *mimetext = NULL;
    81 
    82     fd = Mkstemp(template);
    83     assert(fd != -1);
    84     if (fd == -1)
    85         goto err_file;
    86 
    87     r = unlink(template);
    88     assert(r == 0);
    89     if (r)
    90         goto err_file;
    91 
    92     free(template);
    93     template = NULL;
    94 
    95     file = Fdopen(fd, "w+");
    96     assert(file);
    97     if (file == NULL) {
    98         switch (errno) {
    99             case ENOMEM:
   100                 goto enomem;
   101             default:
   102                 goto err_file;
   103         }
   104     }
   105 
   106     fd = -1;
   107 
   108     col = 0;
   109     r = mailmime_write_file(file, &col, mime);
   110     assert(r == MAILIMF_NO_ERROR);
   111     if (r == MAILIMF_ERROR_MEMORY)
   112         goto enomem;
   113     else if (r != MAILIMF_NO_ERROR)
   114         goto err_file;
   115 
   116     off_t len = ftello(file);
   117     assert(len != -1);
   118     if (len == -1 && errno == EOVERFLOW)
   119         goto err_file;
   120 
   121     if (len + 1 > SIZE_MAX)
   122         goto err_buffer;
   123 
   124     size = (size_t) len;
   125 
   126     errno = 0;
   127     rewind(file);
   128     assert(errno == 0);
   129     switch (errno) {
   130         case 0:
   131             break;
   132         case ENOMEM:
   133             goto enomem;
   134         default:
   135             goto err_file;
   136     }
   137 
   138     buf = calloc(1, size + 1);
   139     assert(buf);
   140     if (buf == NULL)
   141         goto enomem;
   142  
   143     size_t _read;
   144     _read = Fread(buf, size, 1, file);
   145     assert(_read == size);
   146 
   147     r = Fclose(file);
   148     assert(r == 0);
   149 
   150     *mimetext = buf;
   151     return PEP_STATUS_OK;
   152 
   153 err_buffer:
   154     status = PEP_BUFFER_TOO_SMALL;
   155     goto pep_error;
   156 
   157 err_file:
   158     status = PEP_CANNOT_CREATE_TEMP_FILE;
   159     goto pep_error;
   160 
   161 enomem:
   162     status = PEP_OUT_OF_MEMORY;
   163 
   164 pep_error:
   165     free(buf);
   166     free(template);
   167 
   168     if (file) {
   169         r = Fclose(file);
   170         assert(r == 0);
   171     }
   172     else if (fd != -1) {
   173         r = Close(fd);
   174         assert(r == 0);
   175     }
   176 
   177     return status;
   178 }
   179 
   180 static PEP_STATUS mime_html_text(
   181         const char *plaintext,
   182         const char *htmltext,
   183         struct mailmime **result
   184     )
   185 {
   186     PEP_STATUS status = PEP_STATUS_OK;
   187     struct mailmime * mime = NULL;
   188     struct mailmime * submime = NULL;
   189     int r;
   190 
   191     assert(plaintext);
   192     assert(htmltext);
   193     assert(result);
   194 
   195     *result = NULL;
   196 
   197     mime = part_multiple_new("multipart/alternative");
   198     assert(mime);
   199     if (mime == NULL)
   200         goto enomem;
   201 
   202     submime = get_text_part("msg.txt", "text/plain", plaintext, strlen(plaintext),
   203             MAILMIME_MECHANISM_QUOTED_PRINTABLE);
   204     assert(submime);
   205     if (submime == NULL)
   206         goto enomem;
   207 
   208     r = mailmime_smart_add_part(mime, submime);
   209     assert(r == MAILIMF_NO_ERROR);
   210     if (r == MAILIMF_ERROR_MEMORY) {
   211         goto enomem;
   212     }
   213     else {
   214         // mailmime_smart_add_part() takes ownership of submime
   215         submime = NULL;
   216     }
   217 
   218     submime = get_text_part("msg.html", "text/html", htmltext, strlen(htmltext),
   219             MAILMIME_MECHANISM_QUOTED_PRINTABLE);
   220     assert(submime);
   221     if (submime == NULL)
   222         goto enomem;
   223 
   224     r = mailmime_smart_add_part(mime, submime);
   225     assert(r == MAILIMF_NO_ERROR);
   226     if (r == MAILIMF_ERROR_MEMORY)
   227         goto enomem;
   228     else {
   229         // mailmime_smart_add_part() takes ownership of submime
   230         submime = NULL;
   231     }
   232 
   233     *result = mime;
   234     return PEP_STATUS_OK;
   235 
   236 enomem:
   237     status = PEP_OUT_OF_MEMORY;
   238 
   239     if (mime)
   240         mailmime_free(mime);
   241 
   242     if (submime)
   243         mailmime_free(submime);
   244 
   245     return status;
   246 }
   247 
   248 static PEP_STATUS mime_attachment(
   249         bloblist_t *blob,
   250         struct mailmime **result
   251     )
   252 {
   253     PEP_STATUS status = PEP_STATUS_OK;
   254     struct mailmime * mime = NULL;
   255     char * mime_type;
   256 
   257     assert(blob);
   258     assert(result);
   259 
   260     *result = NULL;
   261 
   262     if (blob->mime_type == NULL)
   263         mime_type = "application/octet-stream";
   264     else
   265         mime_type = blob->mime_type;
   266 
   267     mime = get_file_part(blob->filename, mime_type, blob->value, blob->size);
   268     assert(mime);
   269     if (mime == NULL)
   270         goto enomem;
   271 
   272     *result = mime;
   273     return PEP_STATUS_OK;
   274 
   275 enomem:
   276     status = PEP_OUT_OF_MEMORY;
   277 
   278     if (mime)
   279         mailmime_free(mime);
   280 
   281     return status;
   282 }
   283 
   284 static struct mailimf_mailbox * identity_to_mailbox(const pEp_identity *ident)
   285 {
   286     char *_username = NULL;
   287     struct mailimf_mailbox *mb;
   288 
   289     _username = mailmime_encode_subject_header("utf-8", ident->username, 0);
   290     if (_username == NULL)
   291         goto enomem;
   292 
   293     mb = mailbox_from_string(_username, ident->address);
   294     if (mb == NULL)
   295         goto enomem;
   296 
   297     free(_username);
   298     _username = NULL;
   299 
   300     return mb;
   301 
   302 enomem:
   303     free(_username);
   304     return NULL;
   305 }
   306 
   307 static struct mailimf_mailbox_list * identity_to_mbl(
   308         const pEp_identity *ident)
   309 {
   310     struct mailimf_mailbox_list *mbl = NULL;
   311     struct mailimf_mailbox *mb = NULL;
   312     clist *list = NULL;
   313     int r;
   314 
   315     assert(ident);
   316 
   317     list = clist_new();
   318     if (list == NULL)
   319         goto enomem;
   320 
   321     mb = identity_to_mailbox(ident);
   322     if (mb == NULL)
   323         goto enomem;
   324 
   325     r = clist_append(list, mb);
   326     if (r)
   327         goto enomem;
   328 
   329     mbl = mailimf_mailbox_list_new(list);
   330     if (mbl == NULL)
   331         goto enomem;
   332 
   333     return mbl;
   334 
   335 enomem:
   336     if (mb)
   337         mailimf_mailbox_free(mb);
   338 
   339     if (list)
   340         clist_free(list);
   341 
   342     return NULL;
   343 }
   344 
   345 static struct mailimf_address_list * identity_list_to_mal(identity_list *il)
   346 {
   347     struct mailimf_address_list *mal = NULL;
   348     struct mailimf_mailbox *mb = NULL;
   349     struct mailimf_address * addr = NULL;
   350     clist *list = NULL;
   351     int r;
   352 
   353     assert(il);
   354 
   355     list = clist_new();
   356     if (list == NULL)
   357         goto enomem;
   358 
   359     identity_list *_il;
   360     for (_il = il; _il; _il = _il->next) {
   361         mb = identity_to_mailbox(_il->ident);
   362         if (mb == NULL)
   363             goto enomem;
   364 
   365         addr = mailimf_address_new(MAILIMF_ADDRESS_MAILBOX, mb, NULL);
   366         if (addr == NULL)
   367             goto enomem;
   368         mb = NULL;
   369 
   370         r = clist_append(list, addr);
   371         if (r)
   372             goto enomem;
   373         addr = NULL;
   374     }
   375     mal = mailimf_address_list_new(list);
   376     if (mal == NULL)
   377         goto enomem;
   378 
   379     return mal;
   380 
   381 enomem:
   382     if (mb)
   383         mailimf_mailbox_free(mb);
   384 
   385     if (addr)
   386         mailimf_address_free(addr);
   387 
   388     if (list)
   389         clist_free(list);
   390 
   391     return NULL;
   392 }
   393 
   394 static clist * stringlist_to_clist(stringlist_t *sl)
   395 {
   396     clist * cl = clist_new();
   397     assert(cl);
   398     if (cl == NULL)
   399         return NULL;
   400 
   401     stringlist_t *_sl;
   402     for (_sl = sl; _sl; _sl = _sl->next) {
   403         int r;
   404         char * value = mailmime_encode_subject_header("utf-8", _sl->value, 0);
   405         assert(value);
   406         if (value == NULL) {
   407             clist_free(cl);
   408             return NULL;
   409         }
   410         r = clist_append(cl, value);
   411         assert(r == 0);
   412         if (r) {
   413             free(value);
   414             clist_free(cl);
   415             return NULL;
   416         }
   417     }
   418 
   419     return cl;
   420 }
   421 
   422 static PEP_STATUS build_fields(const message *msg, struct mailimf_fields **result)
   423 {
   424     PEP_STATUS status = PEP_STATUS_OK;
   425     struct mailimf_fields * fields = NULL;
   426     int r;
   427     clist * fields_list = NULL;
   428     char *subject = msg->shortmsg ? msg->shortmsg : "pEp";
   429 
   430     assert(msg);
   431     assert(msg->from);
   432     assert(msg->from->address);
   433     assert(result);
   434 
   435     *result = NULL;
   436 
   437     fields_list = clist_new();
   438     assert(fields_list);
   439     if (fields_list == NULL)
   440         goto enomem;
   441 
   442     if (msg->id) {
   443         char *_msgid = strdup(msg->id);
   444         if (_msgid == NULL)
   445             goto enomem;
   446 
   447         r = _append_field(fields_list, MAILIMF_FIELD_MESSAGE_ID,
   448                 (_new_func_t) mailimf_message_id_new, _msgid);
   449         if (r) {
   450             free(_msgid);
   451             goto enomem;
   452         }
   453     }
   454 
   455     if (msg->sent) {
   456         struct mailimf_date_time * dt = timestamp_to_etpantime(msg->sent);
   457         if (dt == NULL)
   458             goto enomem;
   459 
   460         r = _append_field(fields_list, MAILIMF_FIELD_ORIG_DATE,
   461                 (_new_func_t) mailimf_orig_date_new, dt);
   462         if (r) {
   463             mailimf_date_time_free(dt);
   464             goto enomem;
   465         }
   466         dt = NULL;
   467     }
   468 
   469     /* if (msg->from) */ {
   470         struct mailimf_mailbox_list *from = identity_to_mbl(msg->from);
   471         if (from == NULL)
   472             goto enomem;
   473 
   474         r = _append_field(fields_list, MAILIMF_FIELD_FROM,
   475                 (_new_func_t) mailimf_from_new, from);
   476         if (r) {
   477             mailimf_mailbox_list_free(from);
   478             goto enomem;
   479         }
   480     }
   481 
   482     if (msg->to) {
   483         struct mailimf_address_list *to = identity_list_to_mal(msg->to);
   484         if (to == NULL)
   485             goto enomem;
   486 
   487         r = _append_field(fields_list, MAILIMF_FIELD_TO,
   488                 (_new_func_t) mailimf_to_new, to);
   489         if (r) {
   490             mailimf_address_list_free(to);
   491             goto enomem;
   492         }
   493     }
   494 
   495     /* if (subject) */ {
   496         char *_subject = mailmime_encode_subject_header("utf-8", subject, 1);
   497         if (_subject == NULL)
   498             goto enomem;
   499 
   500         r = _append_field(fields_list, MAILIMF_FIELD_SUBJECT,
   501                 (_new_func_t) mailimf_subject_new, _subject);
   502         if (r) {
   503             free(_subject);
   504             goto enomem;
   505         }
   506     }
   507 
   508     if (msg->cc) {
   509         struct mailimf_address_list *cc = identity_list_to_mal(msg->cc);
   510         if (cc == NULL)
   511             goto enomem;
   512 
   513         r = _append_field(fields_list, MAILIMF_FIELD_CC,
   514                 (_new_func_t) mailimf_cc_new, cc);
   515         if (r) {
   516             mailimf_address_list_free(cc);
   517             goto enomem;
   518         }
   519     }
   520     
   521     if (msg->bcc) {
   522         struct mailimf_address_list *bcc = identity_list_to_mal(msg->bcc);
   523         if (bcc == NULL)
   524             goto enomem;
   525 
   526         r = _append_field(fields_list, MAILIMF_FIELD_BCC,
   527                 (_new_func_t) mailimf_bcc_new, bcc);
   528         if (r) {
   529             mailimf_address_list_free(bcc);
   530             goto enomem;
   531         }
   532     }
   533     
   534     if (msg->reply_to) {
   535         struct mailimf_address_list *reply_to = identity_list_to_mal(msg->reply_to);
   536         if (reply_to == NULL)
   537             goto enomem;
   538 
   539         r = _append_field(fields_list, MAILIMF_FIELD_REPLY_TO,
   540                 (_new_func_t) mailimf_reply_to_new, reply_to);
   541         if (r) {
   542             mailimf_address_list_free(reply_to);
   543             goto enomem;
   544         }
   545     }
   546 
   547     if (msg->in_reply_to) {
   548         clist *in_reply_to = stringlist_to_clist(msg->in_reply_to);
   549         if (in_reply_to == NULL)
   550             goto enomem;
   551 
   552         r = _append_field(fields_list, MAILIMF_FIELD_IN_REPLY_TO,
   553                 (_new_func_t) mailimf_in_reply_to_new, in_reply_to);
   554         if (r) {
   555             clist_free(in_reply_to);
   556             goto enomem;
   557         }
   558     }
   559 
   560     if (msg->references) {
   561         clist *references = stringlist_to_clist(msg->references);
   562         if (references == NULL)
   563             goto enomem;
   564 
   565         r = _append_field(fields_list, MAILIMF_FIELD_REFERENCES,
   566                 (_new_func_t) mailimf_references_new, references);
   567         if (r) {
   568             clist_free(references);
   569             goto enomem;
   570         }
   571     }
   572 
   573     if (msg->keywords) {
   574         clist *keywords = stringlist_to_clist(msg->keywords);
   575         if (keywords == NULL)
   576             goto enomem;
   577 
   578         r = _append_field(fields_list, MAILIMF_FIELD_KEYWORDS,
   579                 (_new_func_t) mailimf_keywords_new, keywords);
   580         if (r) {
   581             clist_free(keywords);
   582             goto enomem;
   583         }
   584     }
   585 
   586     if (msg->comments) {
   587         char *comments = mailmime_encode_subject_header("utf-8", msg->comments,
   588                 0);
   589         if (comments == NULL)
   590             goto enomem;
   591 
   592         r = _append_field(fields_list, MAILIMF_FIELD_COMMENTS,
   593                 (_new_func_t) mailimf_comments_new, comments);
   594         if (r) {
   595             free(comments);
   596             goto enomem;
   597         }
   598     }
   599 
   600     if (msg->opt_fields) {
   601         stringpair_list_t *_l;
   602         for (_l = msg->opt_fields; _l && _l->value; _l = _l->next) {
   603             char *key = _l->value->key;
   604             char *value = _l->value->value;
   605             if (key && value) {
   606                 char *_value = mailmime_encode_subject_header("utf-8", value, 0);
   607                 if (_value == NULL)
   608                     goto enomem;
   609 
   610                 r = _append_optional_field(fields_list, key, _value);
   611                 free(_value);
   612                 if (r)
   613                     goto enomem;
   614             }
   615         }
   616     }
   617 
   618     fields = mailimf_fields_new(fields_list);
   619     assert(fields);
   620     if (fields == NULL)
   621         goto enomem;
   622 
   623     *result = fields;
   624 
   625     return PEP_STATUS_OK;
   626 
   627 enomem:
   628     status = PEP_OUT_OF_MEMORY;
   629 
   630     if (fields_list)
   631         clist_free(fields_list);
   632 
   633     if (fields)
   634         mailimf_fields_free(fields);
   635 
   636     return status;
   637 }
   638 
   639 static PEP_STATUS mime_encode_message_plain(
   640         const message *msg,
   641         bool omit_fields,
   642         struct mailmime **result
   643     )
   644 {
   645     struct mailmime * mime = NULL;
   646     struct mailmime * submime = NULL;
   647     int r;
   648     PEP_STATUS status;
   649     //char *subject;
   650     char *plaintext;
   651     char *htmltext;
   652 
   653     assert(msg);
   654     assert(result);
   655 
   656     //subject = (msg->shortmsg) ? msg->shortmsg : "pEp";  // not used, yet.
   657     plaintext = (msg->longmsg) ? msg->longmsg : "";
   658     htmltext = msg->longmsg_formatted;
   659 
   660     if (htmltext) {
   661         status = mime_html_text(plaintext, htmltext, &mime);
   662         if (status != PEP_STATUS_OK)
   663             goto pep_error;
   664     }
   665     else {
   666         if (is_PGP_message_text(plaintext))
   667             mime = get_text_part("msg.asc", "application/octet-stream", plaintext,
   668                     strlen(plaintext), MAILMIME_MECHANISM_7BIT);
   669         else
   670             mime = get_text_part("msg.txt", "text/plain", plaintext, strlen(plaintext),
   671                     MAILMIME_MECHANISM_QUOTED_PRINTABLE);
   672         assert(mime);
   673         if (mime == NULL)
   674             goto enomem;
   675     }
   676 
   677     if (msg->attachments) {
   678         submime = mime;
   679         mime = part_multiple_new("multipart/mixed");
   680         assert(mime);
   681         if (mime == NULL)
   682             goto enomem;
   683 
   684         r = mailmime_smart_add_part(mime, submime);
   685         assert(r == MAILIMF_NO_ERROR);
   686         if (r == MAILIMF_ERROR_MEMORY) {
   687             goto enomem;
   688         }
   689         else {
   690             // mailmime_smart_add_part() takes ownership of submime
   691             submime = NULL;
   692         }
   693 
   694         bloblist_t *_a;
   695         for (_a = msg->attachments; _a != NULL; _a = _a->next) {
   696 
   697             status = mime_attachment(_a, &submime);
   698             if (status != PEP_STATUS_OK)
   699                 goto pep_error;
   700 
   701             r = mailmime_smart_add_part(mime, submime);
   702             assert(r == MAILIMF_NO_ERROR);
   703             if (r == MAILIMF_ERROR_MEMORY) {
   704                 goto enomem;
   705             }
   706             else {
   707                 // mailmime_smart_add_part() takes ownership of submime
   708                 submime = NULL;
   709             }
   710         }
   711     }
   712 
   713     *result = mime;
   714     return PEP_STATUS_OK;
   715 
   716 enomem:
   717     status = PEP_OUT_OF_MEMORY;
   718 
   719 pep_error:
   720     if (mime)
   721         mailmime_free(mime);
   722 
   723     if (submime)
   724         mailmime_free(submime);
   725 
   726     return status;
   727 }
   728 
   729 static PEP_STATUS mime_encode_message_PGP_MIME(
   730         const message * msg,
   731         bool omit_fields,
   732         struct mailmime **result
   733     )
   734 {
   735     struct mailmime * mime = NULL;
   736     struct mailmime * submime = NULL;
   737 	struct mailmime_parameter * param;
   738     int r;
   739     PEP_STATUS status;
   740     //char *subject;
   741     char *plaintext;
   742 
   743     assert(msg->attachments && msg->attachments->next &&
   744             msg->attachments->next->value);
   745 
   746     //subject = (msg->shortmsg) ? msg->shortmsg : "pEp"; // not used, yet.
   747     plaintext = msg->attachments->next->value;
   748 
   749     mime = part_multiple_new("multipart/encrypted");
   750     assert(mime);
   751     if (mime == NULL)
   752         goto enomem;
   753 
   754     param = mailmime_param_new_with_data("protocol", "application/pgp-encrypted");
   755     clist_append(mime->mm_content_type->ct_parameters, param);
   756 
   757     submime = get_pgp_encrypted_part();
   758     assert(submime);
   759     if (submime == NULL)
   760         goto enomem;
   761 
   762     r = mailmime_smart_add_part(mime, submime);
   763     assert(r == MAILIMF_NO_ERROR);
   764     if (r == MAILIMF_ERROR_MEMORY) {
   765         goto enomem;
   766     }
   767     else {
   768         // mailmime_smart_add_part() takes ownership of submime
   769         submime = NULL;
   770     }
   771 
   772     submime = get_text_part("msg.asc", "application/octet-stream", plaintext,
   773             strlen(plaintext), MAILMIME_MECHANISM_7BIT);
   774     assert(submime);
   775     if (submime == NULL)
   776         goto enomem;
   777 
   778     r = mailmime_smart_add_part(mime, submime);
   779     assert(r == MAILIMF_NO_ERROR);
   780     if (r == MAILIMF_ERROR_MEMORY) {
   781         goto enomem;
   782     }
   783     else {
   784         // mailmime_smart_add_part() takes ownership of submime
   785         submime = NULL;
   786     }
   787 
   788     *result = mime;
   789     return PEP_STATUS_OK;
   790 
   791 enomem:
   792     status = PEP_OUT_OF_MEMORY;
   793 
   794     if (mime)
   795         mailmime_free(mime);
   796 
   797     if (submime)
   798         mailmime_free(submime);
   799 
   800     return status;
   801 }
   802 
   803 DYNAMIC_API PEP_STATUS mime_encode_message(
   804         const message * msg,
   805         bool omit_fields,
   806         char **mimetext
   807     )
   808 {
   809     PEP_STATUS status = PEP_STATUS_OK;
   810     struct mailmime * msg_mime = NULL;
   811     struct mailmime * mime = NULL;
   812     struct mailimf_fields * fields = NULL;
   813     char *buf = NULL;
   814     int r;
   815 
   816     assert(msg);
   817     assert(mimetext);
   818 
   819     if (!(msg && mimetext))
   820         return PEP_ILLEGAL_VALUE;
   821 
   822     *mimetext = NULL;
   823 
   824     switch (msg->enc_format) {
   825         case PEP_enc_none:
   826             status = mime_encode_message_plain(msg, omit_fields, &mime);
   827             break;
   828 
   829         case PEP_enc_pieces:
   830             status = mime_encode_message_plain(msg, omit_fields, &mime);
   831             break;
   832 
   833         case PEP_enc_S_MIME:
   834             NOT_IMPLEMENTED
   835                 
   836         case PEP_enc_PGP_MIME:
   837             status = mime_encode_message_PGP_MIME(msg, omit_fields, &mime);
   838             break;
   839 
   840         case PEP_enc_PEP:
   841             NOT_IMPLEMENTED
   842     }
   843 
   844     if (status != PEP_STATUS_OK)
   845         goto pep_error;
   846 
   847     msg_mime = mailmime_new_message_data(NULL);
   848     assert(msg_mime);
   849     if (msg_mime == NULL)
   850         goto enomem;
   851 
   852     r = mailmime_add_part(msg_mime, mime);
   853     if (r) {
   854         mailmime_free(mime);
   855         goto enomem;
   856     }
   857     mime = NULL;
   858 
   859     if (!omit_fields) {
   860         status = build_fields(msg, &fields);
   861         if (status != PEP_STATUS_OK)
   862             goto pep_error;
   863 
   864         mailmime_set_imf_fields(msg_mime, fields);
   865     }
   866 
   867     status = render_mime(msg_mime, &buf);
   868     if (status != PEP_STATUS_OK)
   869         goto pep_error;
   870 
   871     mailmime_free(msg_mime);
   872     *mimetext = buf;
   873 
   874     return PEP_STATUS_OK;
   875 
   876 enomem:
   877     status = PEP_OUT_OF_MEMORY;
   878 
   879 pep_error:
   880     if (msg_mime)
   881         mailmime_free(msg_mime);
   882     else
   883         if (mime)
   884             mailmime_free(mime);
   885 
   886     return status;
   887 }
   888 
   889 static pEp_identity *mailbox_to_identity(const struct mailimf_mailbox * mb)
   890 {
   891     pEp_identity *ident;
   892     char *username = NULL;
   893     size_t index;
   894     int r;
   895 
   896     assert(mb);
   897     assert(mb->mb_addr_spec);
   898 
   899     if (mb->mb_addr_spec == NULL)
   900         return NULL;
   901 
   902     if (mb->mb_display_name) {
   903         index = 0;
   904         r = mailmime_encoded_phrase_parse("utf-8", mb->mb_display_name,
   905                 strlen(mb->mb_display_name), &index, "utf-8", &username);
   906         if (r)
   907             goto enomem;
   908     }
   909 
   910     ident = new_identity(mb->mb_addr_spec, NULL, NULL, username);
   911     if (ident == NULL)
   912         goto enomem;
   913     free(username);
   914 
   915     return ident;
   916 
   917 enomem:
   918     free(username);
   919 
   920     return NULL;
   921 }
   922 
   923 static pEp_identity * mbl_to_identity(const struct mailimf_mailbox_list * mbl)
   924 {
   925     struct mailimf_mailbox * mb = clist_content(clist_begin(mbl->mb_list));
   926     return mailbox_to_identity(mb);
   927 }
   928 
   929 static identity_list * mal_to_identity_list(
   930         const struct mailimf_address_list *mal
   931     )
   932 {
   933     identity_list *il = NULL;
   934     clist *list = mal->ad_list;
   935     struct mailimf_address * addr = NULL;
   936     clistiter *cur;
   937 
   938     assert(mal);
   939 
   940     il = new_identity_list(NULL);
   941     if (il == NULL)
   942         goto enomem;
   943 
   944     identity_list *_il = il;
   945     for (cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
   946         pEp_identity *ident;
   947 
   948         addr = clist_content(cur);
   949         switch(addr->ad_type) {
   950             case MAILIMF_ADDRESS_MAILBOX:
   951                 ident = mailbox_to_identity(addr->ad_data.ad_mailbox);
   952                 if (ident == NULL)
   953                     goto enomem;
   954                 _il = identity_list_add(_il, ident);
   955                 if (_il == NULL)
   956                     goto enomem;
   957                 break;
   958 
   959             case MAILIMF_ADDRESS_GROUP:
   960                 {
   961                     clistiter *cur2;
   962                     struct mailimf_mailbox_list * mbl =
   963                             addr->ad_data.ad_group->grp_mb_list;
   964                     for (cur2 = clist_begin(mbl->mb_list); cur2 != NULL;
   965                             cur2 = clist_next(cur2)) {
   966                         ident = mailbox_to_identity(clist_content(cur));
   967                         if (ident == NULL)
   968                             goto enomem;
   969                         _il = identity_list_add(_il, ident);
   970                         if (_il == NULL)
   971                             goto enomem;
   972                     }
   973                 }
   974                 break;
   975 
   976             default:
   977                 assert(0);
   978                 goto enomem;
   979         }
   980     }
   981 
   982     return il;
   983 
   984 enomem:
   985     free_identity_list(il);
   986 
   987     return NULL;
   988 }
   989 
   990 static stringlist_t * clist_to_stringlist(const clist *list)
   991 {
   992     char *text = NULL;;
   993     stringlist_t * sl = new_stringlist(NULL);
   994     if (sl == NULL)
   995         return NULL;
   996 
   997     clistiter *cur;
   998     stringlist_t *_sl = sl;
   999     for (cur = clist_begin(list); cur != NULL; cur = clist_next(cur)) {
  1000         char *phrase = clist_content(cur);
  1001         size_t index;
  1002         int r;
  1003 
  1004         index = 0;
  1005         r = mailmime_encoded_phrase_parse("utf-8", phrase, strlen(phrase),
  1006                 &index, "utf-8", &text);
  1007         if (r)
  1008             goto enomem;
  1009 
  1010         _sl = stringlist_add(_sl, text);
  1011         if (_sl == NULL)
  1012             goto enomem;
  1013 
  1014         free(text);
  1015         text = NULL;
  1016     }
  1017 
  1018     return _sl;
  1019 
  1020 enomem:
  1021     free_stringlist(sl);
  1022     free(text);
  1023 
  1024     return NULL;
  1025 }
  1026 
  1027 static PEP_STATUS read_fields(message *msg, clist *fieldlist)
  1028 {
  1029     PEP_STATUS status = PEP_STATUS_OK;
  1030     struct mailimf_field * _field;
  1031     clistiter *cur;
  1032     size_t index;
  1033     int r;
  1034     stringpair_list_t *opt = msg->opt_fields;
  1035 
  1036     for (cur = clist_begin(fieldlist); cur != NULL; cur = clist_next(cur)) {
  1037         _field = clist_content(cur);
  1038 
  1039         switch (_field->fld_type) {
  1040             case MAILIMF_FIELD_MESSAGE_ID:
  1041                 {
  1042                     char * text = _field->fld_data.fld_message_id->mid_value;
  1043 
  1044                     free(msg->id);
  1045                     index = 0;
  1046                     r = mailmime_encoded_phrase_parse("utf-8", text,
  1047                             strlen(text), &index, "utf-8", &msg->id);
  1048                     if (r)
  1049                         goto enomem;
  1050                 }
  1051                 break;
  1052 
  1053             case MAILIMF_FIELD_SUBJECT:
  1054                 {
  1055                     char * text = _field->fld_data.fld_subject->sbj_value;
  1056 
  1057                     free(msg->shortmsg);
  1058                     index = 0;
  1059                     r = mailmime_encoded_phrase_parse("utf-8", text,
  1060                             strlen(text), &index, "utf-8", &msg->shortmsg);
  1061                     if (r)
  1062                         goto enomem;
  1063                 }
  1064                 break;
  1065 
  1066             case MAILIMF_FIELD_ORIG_DATE:
  1067                 {
  1068                     struct mailimf_date_time *date =
  1069                         _field->fld_data.fld_orig_date->dt_date_time;
  1070 
  1071                     free_timestamp(msg->sent);
  1072                     msg->sent = etpantime_to_timestamp(date);
  1073                     if (msg->sent == NULL)
  1074                         goto enomem;
  1075                 }
  1076                 break;
  1077 
  1078             case MAILIMF_FIELD_FROM:
  1079                 {
  1080                     struct mailimf_mailbox_list *mbl =
  1081                             _field->fld_data.fld_from->frm_mb_list;
  1082                     pEp_identity *ident;
  1083 
  1084                     ident = mbl_to_identity(mbl);
  1085                     if (ident == NULL)
  1086                         goto pep_error;
  1087 
  1088                     free_identity(msg->from);
  1089                     msg->from = ident;
  1090                 }
  1091                 break;
  1092 
  1093             case MAILIMF_FIELD_TO:
  1094                 {
  1095                     struct mailimf_address_list *mal =
  1096                             _field->fld_data.fld_to->to_addr_list;
  1097                     identity_list *il = mal_to_identity_list(mal);
  1098                     if (il == NULL)
  1099                         goto enomem;
  1100 
  1101                     free_identity_list(msg->to);
  1102                     msg->to = il;
  1103                 }
  1104                 break;
  1105 
  1106             case MAILIMF_FIELD_CC:
  1107                 {
  1108                     struct mailimf_address_list *mal =
  1109                             _field->fld_data.fld_cc->cc_addr_list;
  1110                     identity_list *il = mal_to_identity_list(mal);
  1111                     if (il == NULL)
  1112                         goto enomem;
  1113 
  1114                     free_identity_list(msg->cc);
  1115                     msg->cc = il;
  1116                 }
  1117                 break;
  1118 
  1119             case MAILIMF_FIELD_BCC:
  1120                 {
  1121                     struct mailimf_address_list *mal =
  1122                             _field->fld_data.fld_bcc->bcc_addr_list;
  1123                     identity_list *il = mal_to_identity_list(mal);
  1124                     if (il == NULL)
  1125                         goto enomem;
  1126 
  1127                     free_identity_list(msg->bcc);
  1128                     msg->bcc = il;
  1129                 }
  1130                 break;
  1131 
  1132             case MAILIMF_FIELD_REPLY_TO:
  1133                 {
  1134                     struct mailimf_address_list *mal =
  1135                             _field->fld_data.fld_reply_to->rt_addr_list;
  1136                     identity_list *il = mal_to_identity_list(mal);
  1137                     if (il == NULL)
  1138                         goto enomem;
  1139 
  1140                     free_identity_list(msg->reply_to);
  1141                     msg->reply_to = il;
  1142                 }
  1143                 break;
  1144 
  1145             case MAILIMF_FIELD_IN_REPLY_TO:
  1146                 {
  1147                     clist *list = _field->fld_data.fld_in_reply_to->mid_list;
  1148                     stringlist_t *sl = clist_to_stringlist(list);
  1149                     if (sl == NULL)
  1150                         goto enomem;
  1151 
  1152                     free_stringlist(msg->in_reply_to);
  1153                     msg->in_reply_to = sl;
  1154                 }
  1155                 break;
  1156 
  1157             case MAILIMF_FIELD_REFERENCES:
  1158                 {
  1159                     clist *list = _field->fld_data.fld_references->mid_list;
  1160                     stringlist_t *sl = clist_to_stringlist(list);
  1161                     if (sl == NULL)
  1162                         goto enomem;
  1163 
  1164                     free_stringlist(msg->references);
  1165                     msg->references = sl;
  1166                 }
  1167                 break;
  1168 
  1169             case MAILIMF_FIELD_KEYWORDS:
  1170                 {
  1171                     clist *list = _field->fld_data.fld_keywords->kw_list;
  1172                     stringlist_t *sl = clist_to_stringlist(list);
  1173                     if (sl == NULL)
  1174                         goto enomem;
  1175 
  1176                     free_stringlist(msg->keywords);
  1177                     msg->keywords = sl;
  1178                 }
  1179                 break;
  1180 
  1181             case MAILIMF_FIELD_COMMENTS:
  1182                 {
  1183                     char * text = _field->fld_data.fld_comments->cm_value;
  1184 
  1185                     free(msg->comments);
  1186                     index = 0;
  1187                     r = mailmime_encoded_phrase_parse("utf-8", text,
  1188                             strlen(text), &index, "utf-8", &msg->comments);
  1189                     if (r)
  1190                         goto enomem;
  1191                 }
  1192                 break;
  1193 
  1194             case MAILIMF_FIELD_OPTIONAL_FIELD:
  1195                 {
  1196                     char * name =
  1197                             _field->fld_data.fld_optional_field->fld_name;
  1198                     char * value =
  1199                             _field->fld_data.fld_optional_field->fld_value;
  1200                     char *_value;
  1201 
  1202                     index = 0;
  1203                     r = mailmime_encoded_phrase_parse("utf-8", value,
  1204                             strlen(value), &index, "utf-8", &_value);
  1205                     if (r)
  1206                         goto enomem;
  1207 
  1208                     stringpair_t *pair = new_stringpair(name, _value);
  1209                     if (pair == NULL)
  1210                         goto enomem;
  1211 
  1212                     opt = stringpair_list_add(opt, pair);
  1213                     free(_value);
  1214                     if (opt == NULL)
  1215                         goto enomem;
  1216 
  1217                     if (msg->opt_fields == NULL)
  1218                         msg->opt_fields = opt;
  1219                 }
  1220                 break;
  1221         }
  1222     }
  1223 
  1224     return PEP_STATUS_OK;
  1225 
  1226 enomem:
  1227     status = PEP_OUT_OF_MEMORY;
  1228 
  1229 pep_error:
  1230     return status;
  1231 }
  1232 
  1233 static PEP_STATUS interpret_body(struct mailmime *part, char **longmsg, size_t *size)
  1234 {
  1235     const char *text;
  1236     char *_longmsg;
  1237     size_t length;
  1238     size_t _size;
  1239     int code;
  1240     int r;
  1241     size_t index;
  1242     char *type = NULL;
  1243     char *charset = NULL;
  1244 
  1245     assert(part);
  1246     assert(longmsg);
  1247 
  1248     *longmsg = NULL;
  1249     if (size)
  1250         *size = 0;
  1251 
  1252     if (part->mm_body == NULL)
  1253         return PEP_ILLEGAL_VALUE;
  1254 
  1255     text = part->mm_body-> dt_data.dt_text.dt_data;
  1256     if (text == NULL)
  1257         return PEP_ILLEGAL_VALUE;
  1258 
  1259     length = part->mm_body->dt_data.dt_text.dt_length;
  1260 
  1261     if (part->mm_body->dt_encoded) {
  1262         code = part->mm_body->dt_encoding;
  1263         index = 0;
  1264         r = mailmime_part_parse(text, length, &index, code, &_longmsg, &_size);
  1265         switch (r) {
  1266             case MAILIMF_NO_ERROR:
  1267                 break;
  1268             case MAILIMF_ERROR_MEMORY:
  1269                 return PEP_OUT_OF_MEMORY;
  1270             default:
  1271                 return PEP_ILLEGAL_VALUE;
  1272         }
  1273     }
  1274     else {
  1275         _size = length + 1;
  1276         _longmsg = strndup(text, length);
  1277         if (_longmsg == NULL)
  1278             return PEP_OUT_OF_MEMORY;
  1279     }
  1280 
  1281     if (part->mm_content_type) {
  1282         if (_get_content_type(part->mm_content_type, &type, &charset) == 0) {
  1283             if (charset && strncasecmp(charset, "utf-8", 5) != 0) {
  1284                 char * _text;
  1285                 int r = charconv("utf-8", charset, _longmsg, _size, &_text);
  1286                 switch (r) {
  1287                     case MAILIMF_NO_ERROR:
  1288                         break;
  1289                     case MAILIMF_ERROR_MEMORY:
  1290                         return PEP_OUT_OF_MEMORY;
  1291                     default:
  1292                         return PEP_ILLEGAL_VALUE;
  1293                 }
  1294                 free(_longmsg);
  1295                 _longmsg = _text;
  1296             }
  1297         }
  1298     }
  1299 
  1300     *longmsg = _longmsg;
  1301     if (size)
  1302         *size = _size;
  1303 
  1304     return PEP_STATUS_OK;
  1305 }
  1306 
  1307 static PEP_STATUS interpret_MIME(
  1308         struct mailmime *mime,
  1309         message *msg
  1310     )
  1311 {
  1312     PEP_STATUS status = PEP_STATUS_OK;
  1313 
  1314     assert(mime);
  1315     assert(msg);
  1316 
  1317     struct mailmime_content *content = mime->mm_content_type;
  1318     if (content) {
  1319         if (_is_multipart(content, "alternative")) {
  1320             clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
  1321             if (partlist == NULL)
  1322                 return PEP_ILLEGAL_VALUE;
  1323 
  1324             clistiter *cur;
  1325             for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
  1326                 struct mailmime *part = clist_content(cur);
  1327                 if (part == NULL)
  1328                     return PEP_ILLEGAL_VALUE;
  1329 
  1330                 content = part->mm_content_type;
  1331                 assert(content);
  1332                 if (content == NULL)
  1333                     return PEP_ILLEGAL_VALUE;
  1334 
  1335                 if (_is_text_part(content, "plain") && msg->longmsg == NULL) {
  1336                     status = interpret_body(part, &msg->longmsg, NULL);
  1337                     if (status)
  1338                         return status;
  1339                 }
  1340                 else if (_is_text_part(content, "html") &&
  1341                         msg->longmsg_formatted == NULL) {
  1342                     status = interpret_body(part, &msg->longmsg_formatted,
  1343                             NULL);
  1344                     if (status)
  1345                         return status;
  1346                 }
  1347                 else /* add as attachment */ {
  1348                     status = interpret_MIME(part, msg);
  1349                     if (status)
  1350                         return status;
  1351                 }
  1352             }
  1353         }
  1354         else if (_is_multipart(content, "encrypted")) {
  1355             if (msg->longmsg == NULL)
  1356                 msg->longmsg = strdup("");
  1357 
  1358             clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
  1359             if (partlist == NULL)
  1360                 return PEP_ILLEGAL_VALUE;
  1361 
  1362             clistiter *cur;
  1363             for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
  1364                 struct mailmime *part= clist_content(cur);
  1365                 if (part == NULL)
  1366                     return PEP_ILLEGAL_VALUE;
  1367 
  1368                 status = interpret_MIME(part, msg);
  1369                 if (status != PEP_STATUS_OK)
  1370                     return status;
  1371             }
  1372         }
  1373         else if (_is_multipart(content, NULL)) {
  1374             clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
  1375             if (partlist == NULL)
  1376                 return PEP_ILLEGAL_VALUE;
  1377 
  1378             clistiter *cur;
  1379             for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
  1380                 struct mailmime *part= clist_content(cur);
  1381                 if (part == NULL)
  1382                     return PEP_ILLEGAL_VALUE;
  1383 
  1384                 status = interpret_MIME(part, msg);
  1385                 if (status != PEP_STATUS_OK)
  1386                     return status;
  1387             }
  1388         }
  1389         else {
  1390             if (_is_text_part(content, NULL) && msg->longmsg == NULL) {
  1391                 status = interpret_body(mime, &msg->longmsg, NULL);
  1392                 if (status)
  1393                     return status;
  1394             }
  1395             else {
  1396                 char *data = NULL;
  1397                 size_t size = 0;
  1398                 char * mime_type;
  1399                 char * charset;
  1400                 char * filename;
  1401                 int r;
  1402 
  1403                 r = _get_content_type(content, &mime_type, &charset);
  1404                 switch (r) {
  1405                     case 0:
  1406                         break;
  1407                     case EINVAL:
  1408                         return PEP_ILLEGAL_VALUE;
  1409                     case ENOMEM:
  1410                         return PEP_OUT_OF_MEMORY;
  1411                     default:
  1412                         return PEP_UNKNOWN_ERROR;
  1413                 }
  1414 
  1415                 assert(mime_type);
  1416 
  1417                 status = interpret_body(mime, &data, &size);
  1418                 if (status)
  1419                     return status;
  1420 
  1421                 filename = _get_filename(mime);
  1422                 char *_filename = NULL;
  1423                 if (filename) {
  1424                     size_t index = 0;
  1425                     r = mailmime_encoded_phrase_parse("utf-8", filename,
  1426                             strlen(filename), &index, "utf-8", &_filename);
  1427                     if (r)
  1428                         goto enomem;
  1429                 }
  1430 
  1431                 bloblist_t *_a = bloblist_add(msg->attachments, data, size,
  1432                         mime_type, _filename);
  1433                 free(_filename);
  1434                 if (_a == NULL)
  1435                     return PEP_OUT_OF_MEMORY;
  1436                 if (msg->attachments == NULL)
  1437                     msg->attachments = _a;
  1438             }
  1439         }
  1440     }
  1441 
  1442     return PEP_STATUS_OK;
  1443 
  1444 enomem:
  1445     return PEP_OUT_OF_MEMORY;
  1446 }
  1447 
  1448 DYNAMIC_API PEP_STATUS mime_decode_message(
  1449         const char *mimetext,
  1450         size_t size,
  1451         message **msg
  1452     )
  1453 {
  1454     PEP_STATUS status = PEP_STATUS_OK;
  1455     struct mailmime * mime = NULL;
  1456     int r;
  1457     message *_msg = NULL;
  1458     size_t index;
  1459 
  1460     assert(mimetext);
  1461     assert(msg);
  1462 
  1463     if (!(mimetext && msg))
  1464         return PEP_ILLEGAL_VALUE;
  1465 
  1466     *msg = NULL;
  1467 
  1468     index = 0;
  1469     r = mailmime_parse(mimetext, size, &index, &mime);
  1470     assert(r == 0);
  1471     assert(mime);
  1472     if (r) {
  1473         if (r == MAILIMF_ERROR_MEMORY)
  1474             goto enomem;
  1475         else
  1476             goto err_mime;
  1477     }
  1478 
  1479     _msg = calloc(1, sizeof(message));
  1480     assert(_msg);
  1481     if (_msg == NULL)
  1482         goto enomem;
  1483 
  1484     clist * _fieldlist = _get_fields(mime);
  1485     if (_fieldlist) {
  1486         status = read_fields(_msg, _fieldlist);
  1487         if (status != PEP_STATUS_OK)
  1488             goto pep_error;
  1489     }
  1490 
  1491     struct mailmime_content *content = _get_content(mime);
  1492 
  1493     if (content) {
  1494         status = interpret_MIME(mime->mm_data.mm_message.mm_msg_mime,
  1495                 _msg);
  1496         if (status != PEP_STATUS_OK)
  1497             goto pep_error;
  1498     }
  1499 
  1500     mailmime_free(mime);
  1501     *msg = _msg;
  1502 
  1503     return status;
  1504 
  1505 err_mime:
  1506     status = PEP_ILLEGAL_VALUE;
  1507     goto pep_error;
  1508 
  1509 enomem:
  1510     status = PEP_OUT_OF_MEMORY;
  1511 
  1512 pep_error:
  1513     free_message(_msg);
  1514 
  1515     if (mime)
  1516         mailmime_free(mime);
  1517 
  1518     return status;
  1519 }
  1520