src/mime.c
author Volker Birk <vb@pep.foundation>
Tue, 16 Aug 2016 19:19:53 +0200
branchkeysync
changeset 1025 484c6671be0f
parent 1016 3c97711fc15a
child 1169 7d666711da67
permissions -rw-r--r--
deal with empty string for mime_type
     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     assert(blob);
   257     assert(result);
   258 
   259     *result = NULL;
   260 
   261     if (blob->mime_type == NULL || blob->mime_type[0] == 0)
   262         mime_type = "application/octet-stream";
   263     else
   264         mime_type = blob->mime_type;
   265 
   266     mime = get_file_part(blob->filename, mime_type, blob->value, blob->size);
   267     assert(mime);
   268     if (mime == NULL)
   269         goto enomem;
   270 
   271     *result = mime;
   272     return PEP_STATUS_OK;
   273 
   274 enomem:
   275     status = PEP_OUT_OF_MEMORY;
   276 
   277     if (mime)
   278         mailmime_free(mime);
   279 
   280     return status;
   281 }
   282 
   283 static struct mailimf_mailbox * identity_to_mailbox(const pEp_identity *ident)
   284 {
   285     char *_username = NULL;
   286     struct mailimf_mailbox *mb;
   287 
   288     _username = ident->username ? mailmime_encode_subject_header("utf-8",
   289             ident->username, 0) : strdup("");
   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->ident; _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     char *username = NULL;
   892 
   893     assert(mb);
   894     assert(mb->mb_addr_spec);
   895 
   896     if (mb->mb_addr_spec == NULL)
   897         return NULL;
   898 
   899     if (mb->mb_display_name) {
   900         size_t index = 0;
   901         const int r = mailmime_encoded_phrase_parse("utf-8", mb->mb_display_name,
   902                 strlen(mb->mb_display_name), &index, "utf-8", &username);
   903         if (r)
   904             goto enomem;
   905     }
   906 
   907     pEp_identity *ident = new_identity(mb->mb_addr_spec, NULL, NULL, username);
   908     if (ident == NULL)
   909         goto enomem;
   910     free(username);
   911 
   912     return ident;
   913 
   914 enomem:
   915     free(username);
   916     return NULL;
   917 }
   918 
   919 static pEp_identity * mbl_to_identity(const struct mailimf_mailbox_list * mbl)
   920 {
   921     struct mailimf_mailbox * mb = clist_content(clist_begin(mbl->mb_list));
   922     return mailbox_to_identity(mb);
   923 }
   924 
   925 static identity_list * mal_to_identity_list(
   926         const struct mailimf_address_list *mal
   927     )
   928 {
   929     assert(mal);
   930     clist *list = mal->ad_list;
   931 
   932     identity_list *il = new_identity_list(NULL);
   933     if (il == NULL)
   934         goto enomem;
   935 
   936     identity_list *_il = il;
   937     for (clistiter *cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
   938         pEp_identity *ident;
   939 
   940         struct mailimf_address *addr = clist_content(cur);
   941         switch(addr->ad_type) {
   942             case MAILIMF_ADDRESS_MAILBOX:
   943                 ident = mailbox_to_identity(addr->ad_data.ad_mailbox);
   944                 if (ident == NULL)
   945                     goto enomem;
   946                 _il = identity_list_add(_il, ident);
   947                 if (_il == NULL)
   948                     goto enomem;
   949                 break;
   950 
   951             case MAILIMF_ADDRESS_GROUP:
   952                 {
   953                     struct mailimf_mailbox_list * mbl =
   954                             addr->ad_data.ad_group->grp_mb_list;
   955                     for (clistiter *cur2 = clist_begin(mbl->mb_list); cur2 != NULL;
   956                             cur2 = clist_next(cur2)) {
   957                         ident = mailbox_to_identity(clist_content(cur));
   958                         if (ident == NULL)
   959                             goto enomem;
   960                         _il = identity_list_add(_il, ident);
   961                         if (_il == NULL)
   962                             goto enomem;
   963                     }
   964                 }
   965                 break;
   966 
   967             default:
   968                 assert(0);
   969                 goto enomem;
   970         }
   971     }
   972 
   973     return il;
   974 
   975 enomem:
   976     free_identity_list(il);
   977     return NULL;
   978 }
   979 
   980 static stringlist_t * clist_to_stringlist(const clist *list)
   981 {
   982     char *text = NULL;;
   983     stringlist_t * sl = new_stringlist(NULL);
   984     if (sl == NULL)
   985         return NULL;
   986 
   987     stringlist_t *_sl = sl;
   988     for (clistiter *cur = clist_begin(list); cur != NULL; cur = clist_next(cur)) {
   989         char *phrase = clist_content(cur);
   990         size_t index = 0;
   991         
   992         const int r = mailmime_encoded_phrase_parse("utf-8", phrase, strlen(phrase),
   993                 &index, "utf-8", &text);
   994         if (r)
   995             goto enomem;
   996 
   997         _sl = stringlist_add(_sl, text);
   998         if (_sl == NULL)
   999             goto enomem;
  1000 
  1001         free(text);
  1002         text = NULL;
  1003     }
  1004 
  1005     return _sl;
  1006 
  1007 enomem:
  1008     free_stringlist(sl);
  1009     free(text);
  1010 
  1011     return NULL;
  1012 }
  1013 
  1014 static PEP_STATUS read_fields(message *msg, clist *fieldlist)
  1015 {
  1016     PEP_STATUS status = PEP_STATUS_OK;
  1017     struct mailimf_field * _field;
  1018     clistiter *cur;
  1019     size_t index;
  1020     int r;
  1021     stringpair_list_t *opt = msg->opt_fields;
  1022 
  1023     for (cur = clist_begin(fieldlist); cur != NULL; cur = clist_next(cur)) {
  1024         _field = clist_content(cur);
  1025 
  1026         switch (_field->fld_type) {
  1027             case MAILIMF_FIELD_MESSAGE_ID:
  1028                 {
  1029                     char * text = _field->fld_data.fld_message_id->mid_value;
  1030 
  1031                     free(msg->id);
  1032                     index = 0;
  1033                     r = mailmime_encoded_phrase_parse("utf-8", text,
  1034                             strlen(text), &index, "utf-8", &msg->id);
  1035                     if (r)
  1036                         goto enomem;
  1037                 }
  1038                 break;
  1039 
  1040             case MAILIMF_FIELD_SUBJECT:
  1041                 {
  1042                     char * text = _field->fld_data.fld_subject->sbj_value;
  1043 
  1044                     free(msg->shortmsg);
  1045                     index = 0;
  1046                     r = mailmime_encoded_phrase_parse("utf-8", text,
  1047                             strlen(text), &index, "utf-8", &msg->shortmsg);
  1048                     if (r)
  1049                         goto enomem;
  1050                 }
  1051                 break;
  1052 
  1053             case MAILIMF_FIELD_ORIG_DATE:
  1054                 {
  1055                     struct mailimf_date_time *date =
  1056                         _field->fld_data.fld_orig_date->dt_date_time;
  1057 
  1058                     free_timestamp(msg->sent);
  1059                     msg->sent = etpantime_to_timestamp(date);
  1060                     if (msg->sent == NULL)
  1061                         goto enomem;
  1062                 }
  1063                 break;
  1064 
  1065             case MAILIMF_FIELD_FROM:
  1066                 {
  1067                     struct mailimf_mailbox_list *mbl =
  1068                             _field->fld_data.fld_from->frm_mb_list;
  1069                     pEp_identity *ident;
  1070 
  1071                     ident = mbl_to_identity(mbl);
  1072                     if (ident == NULL)
  1073                         goto pep_error;
  1074 
  1075                     free_identity(msg->from);
  1076                     msg->from = ident;
  1077                 }
  1078                 break;
  1079 
  1080             case MAILIMF_FIELD_TO:
  1081                 {
  1082                     struct mailimf_address_list *mal =
  1083                             _field->fld_data.fld_to->to_addr_list;
  1084                     identity_list *il = mal_to_identity_list(mal);
  1085                     if (il == NULL)
  1086                         goto enomem;
  1087 
  1088                     free_identity_list(msg->to);
  1089                     msg->to = il;
  1090                 }
  1091                 break;
  1092 
  1093             case MAILIMF_FIELD_CC:
  1094                 {
  1095                     struct mailimf_address_list *mal =
  1096                             _field->fld_data.fld_cc->cc_addr_list;
  1097                     identity_list *il = mal_to_identity_list(mal);
  1098                     if (il == NULL)
  1099                         goto enomem;
  1100 
  1101                     free_identity_list(msg->cc);
  1102                     msg->cc = il;
  1103                 }
  1104                 break;
  1105 
  1106             case MAILIMF_FIELD_BCC:
  1107                 {
  1108                     struct mailimf_address_list *mal =
  1109                             _field->fld_data.fld_bcc->bcc_addr_list;
  1110                     identity_list *il = mal_to_identity_list(mal);
  1111                     if (il == NULL)
  1112                         goto enomem;
  1113 
  1114                     free_identity_list(msg->bcc);
  1115                     msg->bcc = il;
  1116                 }
  1117                 break;
  1118 
  1119             case MAILIMF_FIELD_REPLY_TO:
  1120                 {
  1121                     struct mailimf_address_list *mal =
  1122                             _field->fld_data.fld_reply_to->rt_addr_list;
  1123                     identity_list *il = mal_to_identity_list(mal);
  1124                     if (il == NULL)
  1125                         goto enomem;
  1126 
  1127                     free_identity_list(msg->reply_to);
  1128                     msg->reply_to = il;
  1129                 }
  1130                 break;
  1131 
  1132             case MAILIMF_FIELD_IN_REPLY_TO:
  1133                 {
  1134                     clist *list = _field->fld_data.fld_in_reply_to->mid_list;
  1135                     stringlist_t *sl = clist_to_stringlist(list);
  1136                     if (sl == NULL)
  1137                         goto enomem;
  1138 
  1139                     free_stringlist(msg->in_reply_to);
  1140                     msg->in_reply_to = sl;
  1141                 }
  1142                 break;
  1143 
  1144             case MAILIMF_FIELD_REFERENCES:
  1145                 {
  1146                     clist *list = _field->fld_data.fld_references->mid_list;
  1147                     stringlist_t *sl = clist_to_stringlist(list);
  1148                     if (sl == NULL)
  1149                         goto enomem;
  1150 
  1151                     free_stringlist(msg->references);
  1152                     msg->references = sl;
  1153                 }
  1154                 break;
  1155 
  1156             case MAILIMF_FIELD_KEYWORDS:
  1157                 {
  1158                     clist *list = _field->fld_data.fld_keywords->kw_list;
  1159                     stringlist_t *sl = clist_to_stringlist(list);
  1160                     if (sl == NULL)
  1161                         goto enomem;
  1162 
  1163                     free_stringlist(msg->keywords);
  1164                     msg->keywords = sl;
  1165                 }
  1166                 break;
  1167 
  1168             case MAILIMF_FIELD_COMMENTS:
  1169                 {
  1170                     char * text = _field->fld_data.fld_comments->cm_value;
  1171 
  1172                     free(msg->comments);
  1173                     index = 0;
  1174                     r = mailmime_encoded_phrase_parse("utf-8", text,
  1175                             strlen(text), &index, "utf-8", &msg->comments);
  1176                     if (r)
  1177                         goto enomem;
  1178                 }
  1179                 break;
  1180 
  1181             case MAILIMF_FIELD_OPTIONAL_FIELD:
  1182                 {
  1183                     char * name =
  1184                             _field->fld_data.fld_optional_field->fld_name;
  1185                     char * value =
  1186                             _field->fld_data.fld_optional_field->fld_value;
  1187                     char *_value;
  1188 
  1189                     index = 0;
  1190                     r = mailmime_encoded_phrase_parse("utf-8", value,
  1191                             strlen(value), &index, "utf-8", &_value);
  1192                     if (r)
  1193                         goto enomem;
  1194 
  1195                     stringpair_t *pair = new_stringpair(name, _value);
  1196                     if (pair == NULL)
  1197                         goto enomem;
  1198 
  1199                     opt = stringpair_list_add(opt, pair);
  1200                     free(_value);
  1201                     if (opt == NULL)
  1202                         goto enomem;
  1203 
  1204                     if (msg->opt_fields == NULL)
  1205                         msg->opt_fields = opt;
  1206                 }
  1207                 break;
  1208         }
  1209     }
  1210 
  1211     return PEP_STATUS_OK;
  1212 
  1213 enomem:
  1214     status = PEP_OUT_OF_MEMORY;
  1215 
  1216 pep_error:
  1217     return status;
  1218 }
  1219 
  1220 static PEP_STATUS interpret_body(struct mailmime *part, char **longmsg, size_t *size)
  1221 {
  1222     const char *text;
  1223     char *_longmsg;
  1224     size_t length;
  1225     size_t _size;
  1226     int code;
  1227     int r;
  1228     size_t index;
  1229     char *type = NULL;
  1230     char *charset = NULL;
  1231 
  1232     assert(part);
  1233     assert(longmsg);
  1234 
  1235     *longmsg = NULL;
  1236     if (size)
  1237         *size = 0;
  1238 
  1239     if (part->mm_body == NULL)
  1240         return PEP_ILLEGAL_VALUE;
  1241 
  1242     text = part->mm_body-> dt_data.dt_text.dt_data;
  1243     if (text == NULL)
  1244         return PEP_ILLEGAL_VALUE;
  1245 
  1246     length = part->mm_body->dt_data.dt_text.dt_length;
  1247 
  1248     if (part->mm_body->dt_encoded) {
  1249         code = part->mm_body->dt_encoding;
  1250         index = 0;
  1251         r = mailmime_part_parse(text, length, &index, code, &_longmsg, &_size);
  1252         switch (r) {
  1253             case MAILIMF_NO_ERROR:
  1254                 break;
  1255             case MAILIMF_ERROR_MEMORY:
  1256                 return PEP_OUT_OF_MEMORY;
  1257             default:
  1258                 return PEP_ILLEGAL_VALUE;
  1259         }
  1260     }
  1261     else {
  1262         _size = length + 1;
  1263         _longmsg = strndup(text, length);
  1264         if (_longmsg == NULL)
  1265             return PEP_OUT_OF_MEMORY;
  1266     }
  1267 
  1268     if (part->mm_content_type) {
  1269         if (_get_content_type(part->mm_content_type, &type, &charset) == 0) {
  1270             if (charset && strncasecmp(charset, "utf-8", 5) != 0) {
  1271                 char * _text;
  1272                 int r = charconv("utf-8", charset, _longmsg, _size, &_text);
  1273                 switch (r) {
  1274                     case MAILIMF_NO_ERROR:
  1275                         break;
  1276                     case MAILIMF_ERROR_MEMORY:
  1277                         return PEP_OUT_OF_MEMORY;
  1278                     default:
  1279                         return PEP_ILLEGAL_VALUE;
  1280                 }
  1281                 free(_longmsg);
  1282                 _longmsg = _text;
  1283                 // FIXME: KG - This is where we have the text we want to deal with.
  1284                 // Now we need to strip sigs and process them.
  1285             }
  1286         }
  1287     }
  1288 
  1289     *longmsg = _longmsg;
  1290     if (size)
  1291         *size = _size;
  1292 
  1293     return PEP_STATUS_OK;
  1294 }
  1295 
  1296 static PEP_STATUS interpret_MIME(
  1297         struct mailmime *mime,
  1298         message *msg
  1299     )
  1300 {
  1301     PEP_STATUS status = PEP_STATUS_OK;
  1302 
  1303     assert(mime);
  1304     assert(msg);
  1305 
  1306     struct mailmime_content *content = mime->mm_content_type;
  1307     if (content) {
  1308         if (_is_multipart(content, "alternative")) {
  1309             clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
  1310             if (partlist == NULL)
  1311                 return PEP_ILLEGAL_VALUE;
  1312 
  1313             clistiter *cur;
  1314             for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
  1315                 struct mailmime *part = clist_content(cur);
  1316                 if (part == NULL)
  1317                     return PEP_ILLEGAL_VALUE;
  1318 
  1319                 content = part->mm_content_type;
  1320                 assert(content);
  1321                 if (content == NULL)
  1322                     return PEP_ILLEGAL_VALUE;
  1323 
  1324                 if (_is_text_part(content, "plain") && msg->longmsg == NULL) {
  1325                     status = interpret_body(part, &msg->longmsg, NULL);
  1326                     if (status)
  1327                         return status;
  1328                 }
  1329                 else if (_is_text_part(content, "html") &&
  1330                         msg->longmsg_formatted == NULL) {
  1331                     status = interpret_body(part, &msg->longmsg_formatted,
  1332                             NULL);
  1333                     if (status)
  1334                         return status;
  1335                 }
  1336                 else /* add as attachment */ {
  1337                     status = interpret_MIME(part, msg);
  1338                     if (status)
  1339                         return status;
  1340                 }
  1341             }
  1342         }
  1343         else if (_is_multipart(content, "encrypted")) {
  1344             if (msg->longmsg == NULL)
  1345                 msg->longmsg = strdup("");
  1346 
  1347             clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
  1348             if (partlist == NULL)
  1349                 return PEP_ILLEGAL_VALUE;
  1350 
  1351             clistiter *cur;
  1352             for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
  1353                 struct mailmime *part= clist_content(cur);
  1354                 if (part == NULL)
  1355                     return PEP_ILLEGAL_VALUE;
  1356 
  1357                 status = interpret_MIME(part, msg);
  1358                 if (status != PEP_STATUS_OK)
  1359                     return status;
  1360             }
  1361         }
  1362         else if (_is_multipart(content, NULL)) {
  1363             clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
  1364             if (partlist == NULL)
  1365                 return PEP_ILLEGAL_VALUE;
  1366 
  1367             clistiter *cur;
  1368             for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
  1369                 struct mailmime *part= clist_content(cur);
  1370                 if (part == NULL)
  1371                     return PEP_ILLEGAL_VALUE;
  1372 
  1373                 status = interpret_MIME(part, msg);
  1374                 if (status != PEP_STATUS_OK)
  1375                     return status;
  1376             }
  1377         }
  1378         else {
  1379             if (_is_text_part(content, NULL) && msg->longmsg == NULL) {
  1380                 status = interpret_body(mime, &msg->longmsg, NULL);
  1381                 if (status)
  1382                     return status;
  1383             }
  1384             else {
  1385                 char *data = NULL;
  1386                 size_t size = 0;
  1387                 char * mime_type;
  1388                 char * charset;
  1389                 char * filename;
  1390                 int r;
  1391 
  1392                 r = _get_content_type(content, &mime_type, &charset);
  1393                 switch (r) {
  1394                     case 0:
  1395                         break;
  1396                     case EINVAL:
  1397                         return PEP_ILLEGAL_VALUE;
  1398                     case ENOMEM:
  1399                         return PEP_OUT_OF_MEMORY;
  1400                     default:
  1401                         return PEP_UNKNOWN_ERROR;
  1402                 }
  1403 
  1404                 assert(mime_type);
  1405 
  1406                 status = interpret_body(mime, &data, &size);
  1407                 if (status)
  1408                     return status;
  1409 
  1410                 filename = _get_filename(mime);
  1411                 char *_filename = NULL;
  1412                 if (filename) {
  1413                     size_t index = 0;
  1414                     r = mailmime_encoded_phrase_parse("utf-8", filename,
  1415                             strlen(filename), &index, "utf-8", &_filename);
  1416                     if (r)
  1417                         goto enomem;
  1418                 }
  1419 
  1420                 bloblist_t *_a = bloblist_add(msg->attachments, data, size,
  1421                         mime_type, _filename);
  1422                 free(_filename);
  1423                 if (_a == NULL)
  1424                     return PEP_OUT_OF_MEMORY;
  1425                 if (msg->attachments == NULL)
  1426                     msg->attachments = _a;
  1427             }
  1428         }
  1429     }
  1430 
  1431     return PEP_STATUS_OK;
  1432 
  1433 enomem:
  1434     return PEP_OUT_OF_MEMORY;
  1435 }
  1436 
  1437 DYNAMIC_API PEP_STATUS mime_decode_message(
  1438         const char *mimetext,
  1439         size_t size,
  1440         message **msg
  1441     )
  1442 {
  1443     PEP_STATUS status = PEP_STATUS_OK;
  1444     struct mailmime * mime = NULL;
  1445     int r;
  1446     message *_msg = NULL;
  1447     size_t index;
  1448 
  1449     assert(mimetext);
  1450     assert(msg);
  1451 
  1452     if (!(mimetext && msg))
  1453         return PEP_ILLEGAL_VALUE;
  1454 
  1455     *msg = NULL;
  1456 
  1457     index = 0;
  1458     r = mailmime_parse(mimetext, size, &index, &mime);
  1459     assert(r == 0);
  1460     assert(mime);
  1461     if (r) {
  1462         if (r == MAILIMF_ERROR_MEMORY)
  1463             goto enomem;
  1464         else
  1465             goto err_mime;
  1466     }
  1467 
  1468     _msg = calloc(1, sizeof(message));
  1469     assert(_msg);
  1470     if (_msg == NULL)
  1471         goto enomem;
  1472 
  1473     clist * _fieldlist = _get_fields(mime);
  1474     if (_fieldlist) {
  1475         status = read_fields(_msg, _fieldlist);
  1476         if (status != PEP_STATUS_OK)
  1477             goto pep_error;
  1478     }
  1479 
  1480     struct mailmime_content *content = _get_content(mime);
  1481 
  1482     if (content) {
  1483         status = interpret_MIME(mime->mm_data.mm_message.mm_msg_mime,
  1484                 _msg);
  1485         if (status != PEP_STATUS_OK)
  1486             goto pep_error;
  1487     }
  1488 
  1489     mailmime_free(mime);
  1490     *msg = _msg;
  1491 
  1492     return status;
  1493 
  1494 err_mime:
  1495     status = PEP_ILLEGAL_VALUE;
  1496     goto pep_error;
  1497 
  1498 enomem:
  1499     status = PEP_OUT_OF_MEMORY;
  1500 
  1501 pep_error:
  1502     free_message(_msg);
  1503 
  1504     if (mime)
  1505         mailmime_free(mime);
  1506 
  1507     return status;
  1508 }
  1509