src/mime.c
author Edouard Tisserant
Thu, 21 Jan 2016 19:57:02 +0100
changeset 426 e13dc9689a4d
parent 425 8f08f2ffbdb8
child 427 556fb9c7d97c
permissions -rw-r--r--
reverted d3bb685f489b 'Converting remaining msg.asc -> PGPexch.htm.pgp'
     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";
   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             assert(_a->value);
   697             assert(_a->size);
   698 
   699             status = mime_attachment(_a, &submime);
   700             if (status != PEP_STATUS_OK)
   701                 goto pep_error;
   702 
   703             r = mailmime_smart_add_part(mime, submime);
   704             assert(r == MAILIMF_NO_ERROR);
   705             if (r == MAILIMF_ERROR_MEMORY) {
   706                 goto enomem;
   707             }
   708             else {
   709                 // mailmime_smart_add_part() takes ownership of submime
   710                 submime = NULL;
   711             }
   712         }
   713     }
   714 
   715     *result = mime;
   716     return PEP_STATUS_OK;
   717 
   718 enomem:
   719     status = PEP_OUT_OF_MEMORY;
   720 
   721 pep_error:
   722     if (mime)
   723         mailmime_free(mime);
   724 
   725     if (submime)
   726         mailmime_free(submime);
   727 
   728     return status;
   729 }
   730 
   731 static PEP_STATUS mime_encode_message_PGP_MIME(
   732         const message * msg,
   733         bool omit_fields,
   734         struct mailmime **result
   735     )
   736 {
   737     struct mailmime * mime = NULL;
   738     struct mailmime * submime = NULL;
   739 	struct mailmime_parameter * param;
   740     int r;
   741     PEP_STATUS status;
   742     char *subject;
   743     char *plaintext;
   744 
   745     assert(msg->attachments && msg->attachments->next &&
   746             msg->attachments->next->value);
   747 
   748     subject = (msg->shortmsg) ? msg->shortmsg : "pEp";
   749     plaintext = msg->attachments->next->value;
   750 
   751     mime = part_multiple_new("multipart/encrypted");
   752     assert(mime);
   753     if (mime == NULL)
   754         goto enomem;
   755 
   756     param = mailmime_param_new_with_data("protocol", "application/pgp-encrypted");
   757     clist_append(mime->mm_content_type->ct_parameters, param);
   758 
   759     submime = get_pgp_encrypted_part();
   760     assert(submime);
   761     if (submime == NULL)
   762         goto enomem;
   763 
   764     r = mailmime_smart_add_part(mime, submime);
   765     assert(r == MAILIMF_NO_ERROR);
   766     if (r == MAILIMF_ERROR_MEMORY) {
   767         goto enomem;
   768     }
   769     else {
   770         // mailmime_smart_add_part() takes ownership of submime
   771         submime = NULL;
   772     }
   773 
   774     submime = get_text_part("PGPexch.htm.pgp", "application/octet-stream", plaintext,
   775             strlen(plaintext), MAILMIME_MECHANISM_7BIT);
   776     assert(submime);
   777     if (submime == NULL)
   778         goto enomem;
   779 
   780     r = mailmime_smart_add_part(mime, submime);
   781     assert(r == MAILIMF_NO_ERROR);
   782     if (r == MAILIMF_ERROR_MEMORY) {
   783         goto enomem;
   784     }
   785     else {
   786         // mailmime_smart_add_part() takes ownership of submime
   787         submime = NULL;
   788     }
   789 
   790     *result = mime;
   791     return PEP_STATUS_OK;
   792 
   793 enomem:
   794     status = PEP_OUT_OF_MEMORY;
   795 
   796     if (mime)
   797         mailmime_free(mime);
   798 
   799     if (submime)
   800         mailmime_free(submime);
   801 
   802     return status;
   803 }
   804 
   805 DYNAMIC_API PEP_STATUS mime_encode_message(
   806         const message * msg,
   807         bool omit_fields,
   808         char **mimetext
   809     )
   810 {
   811     PEP_STATUS status = PEP_STATUS_OK;
   812     struct mailmime * msg_mime = NULL;
   813     struct mailmime * mime = NULL;
   814     struct mailimf_fields * fields = NULL;
   815     char *buf = NULL;
   816     int r;
   817 
   818     assert(msg);
   819     assert(mimetext);
   820 
   821     if (!(msg && mimetext))
   822         return PEP_ILLEGAL_VALUE;
   823 
   824     *mimetext = NULL;
   825 
   826     switch (msg->enc_format) {
   827         case PEP_enc_none:
   828             status = mime_encode_message_plain(msg, omit_fields, &mime);
   829             break;
   830 
   831         case PEP_enc_pieces:
   832             status = mime_encode_message_plain(msg, omit_fields, &mime);
   833             break;
   834 
   835         case PEP_enc_S_MIME:
   836             NOT_IMPLEMENTED
   837                 
   838         case PEP_enc_PGP_MIME:
   839             status = mime_encode_message_PGP_MIME(msg, omit_fields, &mime);
   840             break;
   841 
   842         case PEP_enc_PEP:
   843             NOT_IMPLEMENTED
   844     }
   845 
   846     if (status != PEP_STATUS_OK)
   847         goto pep_error;
   848 
   849     msg_mime = mailmime_new_message_data(NULL);
   850     assert(msg_mime);
   851     if (msg_mime == NULL)
   852         goto enomem;
   853 
   854     r = mailmime_add_part(msg_mime, mime);
   855     if (r) {
   856         mailmime_free(mime);
   857         goto enomem;
   858     }
   859     mime = NULL;
   860 
   861     if (!omit_fields) {
   862         status = build_fields(msg, &fields);
   863         if (status != PEP_STATUS_OK)
   864             goto pep_error;
   865 
   866         mailmime_set_imf_fields(msg_mime, fields);
   867     }
   868 
   869     status = render_mime(msg_mime, &buf);
   870     if (status != PEP_STATUS_OK)
   871         goto pep_error;
   872 
   873     mailmime_free(msg_mime);
   874     *mimetext = buf;
   875 
   876     return PEP_STATUS_OK;
   877 
   878 enomem:
   879     status = PEP_OUT_OF_MEMORY;
   880 
   881 pep_error:
   882     if (msg_mime)
   883         mailmime_free(msg_mime);
   884     else
   885         if (mime)
   886             mailmime_free(mime);
   887 
   888     return status;
   889 }
   890 
   891 static pEp_identity *mailbox_to_identity(const struct mailimf_mailbox * mb)
   892 {
   893     pEp_identity *ident;
   894     char *username = NULL;
   895     size_t index;
   896     int r;
   897 
   898     assert(mb);
   899     assert(mb->mb_addr_spec);
   900 
   901     if (mb->mb_addr_spec == NULL)
   902         return NULL;
   903 
   904     if (mb->mb_display_name) {
   905         index = 0;
   906         r = mailmime_encoded_phrase_parse("utf-8", mb->mb_display_name,
   907                 strlen(mb->mb_display_name), &index, "utf-8", &username);
   908         if (r)
   909             goto enomem;
   910     }
   911 
   912     ident = new_identity(mb->mb_addr_spec, NULL, NULL, username);
   913     if (ident == NULL)
   914         goto enomem;
   915     free(username);
   916 
   917     return ident;
   918 
   919 enomem:
   920     free(username);
   921 
   922     return NULL;
   923 }
   924 
   925 static pEp_identity * mbl_to_identity(const struct mailimf_mailbox_list * mbl)
   926 {
   927     struct mailimf_mailbox * mb = clist_content(clist_begin(mbl->mb_list));
   928     return mailbox_to_identity(mb);
   929 }
   930 
   931 static identity_list * mal_to_identity_list(
   932         const struct mailimf_address_list *mal
   933     )
   934 {
   935     identity_list *il = NULL;
   936     clist *list = mal->ad_list;
   937     struct mailimf_address * addr = NULL;
   938     clistiter *cur;
   939 
   940     assert(mal);
   941 
   942     il = new_identity_list(NULL);
   943     if (il == NULL)
   944         goto enomem;
   945 
   946     identity_list *_il = il;
   947     for (cur = clist_begin(list); cur != NULL ; cur = clist_next(cur)) {
   948         pEp_identity *ident;
   949 
   950         addr = clist_content(cur);
   951         switch(addr->ad_type) {
   952             case MAILIMF_ADDRESS_MAILBOX:
   953                 ident = mailbox_to_identity(addr->ad_data.ad_mailbox);
   954                 if (ident == NULL)
   955                     goto enomem;
   956                 _il = identity_list_add(_il, ident);
   957                 if (_il == NULL)
   958                     goto enomem;
   959                 break;
   960 
   961             case MAILIMF_ADDRESS_GROUP:
   962                 {
   963                     clistiter *cur2;
   964                     struct mailimf_mailbox_list * mbl =
   965                             addr->ad_data.ad_group->grp_mb_list;
   966                     for (cur2 = clist_begin(mbl->mb_list); cur2 != NULL;
   967                             cur2 = clist_next(cur2)) {
   968                         ident = mailbox_to_identity(clist_content(cur));
   969                         if (ident == NULL)
   970                             goto enomem;
   971                         _il = identity_list_add(_il, ident);
   972                         if (_il == NULL)
   973                             goto enomem;
   974                     }
   975                 }
   976                 break;
   977 
   978             default:
   979                 assert(0);
   980                 goto enomem;
   981         }
   982     }
   983 
   984     return il;
   985 
   986 enomem:
   987     free_identity_list(il);
   988 
   989     return NULL;
   990 }
   991 
   992 static stringlist_t * clist_to_stringlist(const clist *list)
   993 {
   994     char *text = NULL;;
   995     stringlist_t * sl = new_stringlist(NULL);
   996     if (sl == NULL)
   997         return NULL;
   998 
   999     clistiter *cur;
  1000     stringlist_t *_sl = sl;
  1001     for (cur = clist_begin(list); cur != NULL; cur = clist_next(cur)) {
  1002         char *phrase = clist_content(cur);
  1003         size_t index;
  1004         int r;
  1005 
  1006         index = 0;
  1007         r = mailmime_encoded_phrase_parse("utf-8", phrase, strlen(phrase),
  1008                 &index, "utf-8", &text);
  1009         if (r)
  1010             goto enomem;
  1011 
  1012         _sl = stringlist_add(_sl, text);
  1013         if (_sl == NULL)
  1014             goto enomem;
  1015 
  1016         free(text);
  1017         text = NULL;
  1018     }
  1019 
  1020     return _sl;
  1021 
  1022 enomem:
  1023     free_stringlist(sl);
  1024     free(text);
  1025 
  1026     return NULL;
  1027 }
  1028 
  1029 static PEP_STATUS read_fields(message *msg, clist *fieldlist)
  1030 {
  1031     PEP_STATUS status = PEP_STATUS_OK;
  1032     struct mailimf_field * _field;
  1033     clistiter *cur;
  1034     size_t index;
  1035     int r;
  1036     stringpair_list_t *opt = msg->opt_fields;
  1037 
  1038     for (cur = clist_begin(fieldlist); cur != NULL; cur = clist_next(cur)) {
  1039         _field = clist_content(cur);
  1040 
  1041         switch (_field->fld_type) {
  1042             case MAILIMF_FIELD_MESSAGE_ID:
  1043                 {
  1044                     char * text = _field->fld_data.fld_message_id->mid_value;
  1045 
  1046                     free(msg->id);
  1047                     index = 0;
  1048                     r = mailmime_encoded_phrase_parse("utf-8", text,
  1049                             strlen(text), &index, "utf-8", &msg->id);
  1050                     if (r)
  1051                         goto enomem;
  1052                 }
  1053                 break;
  1054 
  1055             case MAILIMF_FIELD_SUBJECT:
  1056                 {
  1057                     char * text = _field->fld_data.fld_subject->sbj_value;
  1058 
  1059                     free(msg->shortmsg);
  1060                     index = 0;
  1061                     r = mailmime_encoded_phrase_parse("utf-8", text,
  1062                             strlen(text), &index, "utf-8", &msg->shortmsg);
  1063                     if (r)
  1064                         goto enomem;
  1065                 }
  1066                 break;
  1067 
  1068             case MAILIMF_FIELD_ORIG_DATE:
  1069                 {
  1070                     struct mailimf_date_time *date =
  1071                         _field->fld_data.fld_orig_date->dt_date_time;
  1072 
  1073                     free_timestamp(msg->sent);
  1074                     msg->sent = etpantime_to_timestamp(date);
  1075                     if (msg->sent == NULL)
  1076                         goto enomem;
  1077                 }
  1078                 break;
  1079 
  1080             case MAILIMF_FIELD_FROM:
  1081                 {
  1082                     struct mailimf_mailbox_list *mbl =
  1083                             _field->fld_data.fld_from->frm_mb_list;
  1084                     pEp_identity *ident;
  1085 
  1086                     ident = mbl_to_identity(mbl);
  1087                     if (ident == NULL)
  1088                         goto pep_error;
  1089 
  1090                     free_identity(msg->from);
  1091                     msg->from = ident;
  1092                 }
  1093                 break;
  1094 
  1095             case MAILIMF_FIELD_TO:
  1096                 {
  1097                     struct mailimf_address_list *mal =
  1098                             _field->fld_data.fld_to->to_addr_list;
  1099                     identity_list *il = mal_to_identity_list(mal);
  1100                     if (il == NULL)
  1101                         goto enomem;
  1102 
  1103                     free_identity_list(msg->to);
  1104                     msg->to = il;
  1105                 }
  1106                 break;
  1107 
  1108             case MAILIMF_FIELD_CC:
  1109                 {
  1110                     struct mailimf_address_list *mal =
  1111                             _field->fld_data.fld_cc->cc_addr_list;
  1112                     identity_list *il = mal_to_identity_list(mal);
  1113                     if (il == NULL)
  1114                         goto enomem;
  1115 
  1116                     free_identity_list(msg->cc);
  1117                     msg->cc = il;
  1118                 }
  1119                 break;
  1120 
  1121             case MAILIMF_FIELD_BCC:
  1122                 {
  1123                     struct mailimf_address_list *mal =
  1124                             _field->fld_data.fld_bcc->bcc_addr_list;
  1125                     identity_list *il = mal_to_identity_list(mal);
  1126                     if (il == NULL)
  1127                         goto enomem;
  1128 
  1129                     free_identity_list(msg->bcc);
  1130                     msg->bcc = il;
  1131                 }
  1132                 break;
  1133 
  1134             case MAILIMF_FIELD_REPLY_TO:
  1135                 {
  1136                     struct mailimf_address_list *mal =
  1137                             _field->fld_data.fld_reply_to->rt_addr_list;
  1138                     identity_list *il = mal_to_identity_list(mal);
  1139                     if (il == NULL)
  1140                         goto enomem;
  1141 
  1142                     free_identity_list(msg->reply_to);
  1143                     msg->reply_to = il;
  1144                 }
  1145                 break;
  1146 
  1147             case MAILIMF_FIELD_IN_REPLY_TO:
  1148                 {
  1149                     clist *list = _field->fld_data.fld_in_reply_to->mid_list;
  1150                     stringlist_t *sl = clist_to_stringlist(list);
  1151                     if (sl == NULL)
  1152                         goto enomem;
  1153 
  1154                     free_stringlist(msg->in_reply_to);
  1155                     msg->in_reply_to = sl;
  1156                 }
  1157                 break;
  1158 
  1159             case MAILIMF_FIELD_REFERENCES:
  1160                 {
  1161                     clist *list = _field->fld_data.fld_references->mid_list;
  1162                     stringlist_t *sl = clist_to_stringlist(list);
  1163                     if (sl == NULL)
  1164                         goto enomem;
  1165 
  1166                     free_stringlist(msg->references);
  1167                     msg->references = sl;
  1168                 }
  1169                 break;
  1170 
  1171             case MAILIMF_FIELD_KEYWORDS:
  1172                 {
  1173                     clist *list = _field->fld_data.fld_keywords->kw_list;
  1174                     stringlist_t *sl = clist_to_stringlist(list);
  1175                     if (sl == NULL)
  1176                         goto enomem;
  1177 
  1178                     free_stringlist(msg->keywords);
  1179                     msg->keywords = sl;
  1180                 }
  1181                 break;
  1182 
  1183             case MAILIMF_FIELD_COMMENTS:
  1184                 {
  1185                     char * text = _field->fld_data.fld_comments->cm_value;
  1186 
  1187                     free(msg->comments);
  1188                     index = 0;
  1189                     r = mailmime_encoded_phrase_parse("utf-8", text,
  1190                             strlen(text), &index, "utf-8", &msg->comments);
  1191                     if (r)
  1192                         goto enomem;
  1193                 }
  1194                 break;
  1195 
  1196             case MAILIMF_FIELD_OPTIONAL_FIELD:
  1197                 {
  1198                     char * name =
  1199                             _field->fld_data.fld_optional_field->fld_name;
  1200                     char * value =
  1201                             _field->fld_data.fld_optional_field->fld_value;
  1202                     char *_value;
  1203 
  1204                     index = 0;
  1205                     r = mailmime_encoded_phrase_parse("utf-8", value,
  1206                             strlen(value), &index, "utf-8", &_value);
  1207                     if (r)
  1208                         goto enomem;
  1209 
  1210                     stringpair_t *pair = new_stringpair(name, _value);
  1211                     if (pair == NULL)
  1212                         goto enomem;
  1213 
  1214                     opt = stringpair_list_add(opt, pair);
  1215                     free(_value);
  1216                     if (opt == NULL)
  1217                         goto enomem;
  1218 
  1219                     if (msg->opt_fields == NULL)
  1220                         msg->opt_fields = opt;
  1221                 }
  1222                 break;
  1223         }
  1224     }
  1225 
  1226     return PEP_STATUS_OK;
  1227 
  1228 enomem:
  1229     status = PEP_OUT_OF_MEMORY;
  1230 
  1231 pep_error:
  1232     return status;
  1233 }
  1234 
  1235 static PEP_STATUS interpret_body(struct mailmime *part, char **longmsg, size_t *size)
  1236 {
  1237     const char *text;
  1238     char *_longmsg;
  1239     size_t length;
  1240     size_t _size;
  1241     int code;
  1242     int r;
  1243     size_t index;
  1244     char *type = NULL;
  1245     char *charset = NULL;
  1246 
  1247     assert(part);
  1248     assert(longmsg);
  1249 
  1250     *longmsg = NULL;
  1251     if (size)
  1252         *size = 0;
  1253 
  1254     if (part->mm_body == NULL)
  1255         return PEP_ILLEGAL_VALUE;
  1256 
  1257     text = part->mm_body-> dt_data.dt_text.dt_data;
  1258     if (text == NULL)
  1259         return PEP_ILLEGAL_VALUE;
  1260 
  1261     length = part->mm_body->dt_data.dt_text.dt_length;
  1262 
  1263     if (part->mm_body->dt_encoded) {
  1264         code = part->mm_body->dt_encoding;
  1265         index = 0;
  1266         r = mailmime_part_parse(text, length, &index, code, &_longmsg, &_size);
  1267         switch (r) {
  1268             case MAILIMF_NO_ERROR:
  1269                 break;
  1270             case MAILIMF_ERROR_MEMORY:
  1271                 return PEP_OUT_OF_MEMORY;
  1272             default:
  1273                 return PEP_ILLEGAL_VALUE;
  1274         }
  1275     }
  1276     else {
  1277         _size = length + 1;
  1278         _longmsg = strndup(text, length);
  1279         if (_longmsg == NULL)
  1280             return PEP_OUT_OF_MEMORY;
  1281     }
  1282 
  1283     if (part->mm_content_type) {
  1284         if (_get_content_type(part->mm_content_type, &type, &charset) == 0) {
  1285             if (charset && strncasecmp(charset, "utf-8", 5) != 0) {
  1286                 char * _text;
  1287                 int r = charconv("utf-8", charset, _longmsg, _size, &_text);
  1288                 switch (r) {
  1289                     case MAILIMF_NO_ERROR:
  1290                         break;
  1291                     case MAILIMF_ERROR_MEMORY:
  1292                         return PEP_OUT_OF_MEMORY;
  1293                     default:
  1294                         return PEP_ILLEGAL_VALUE;
  1295                 }
  1296                 free(_longmsg);
  1297                 _longmsg = _text;
  1298             }
  1299         }
  1300     }
  1301 
  1302     *longmsg = _longmsg;
  1303     if (size)
  1304         *size = _size;
  1305 
  1306     return PEP_STATUS_OK;
  1307 }
  1308 
  1309 static PEP_STATUS interpret_MIME(
  1310         struct mailmime *mime,
  1311         message *msg
  1312     )
  1313 {
  1314     PEP_STATUS status = PEP_STATUS_OK;
  1315 
  1316     assert(mime);
  1317     assert(msg);
  1318 
  1319     struct mailmime_content *content = mime->mm_content_type;
  1320     if (content) {
  1321         if (_is_multipart(content, "alternative")) {
  1322             clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
  1323             if (partlist == NULL)
  1324                 return PEP_ILLEGAL_VALUE;
  1325 
  1326             clistiter *cur;
  1327             for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
  1328                 struct mailmime *part = clist_content(cur);
  1329                 if (part == NULL)
  1330                     return PEP_ILLEGAL_VALUE;
  1331 
  1332                 content = part->mm_content_type;
  1333                 assert(content);
  1334                 if (content == NULL)
  1335                     return PEP_ILLEGAL_VALUE;
  1336 
  1337                 if (_is_text_part(content, "plain") && msg->longmsg == NULL) {
  1338                     status = interpret_body(part, &msg->longmsg, NULL);
  1339                     if (status)
  1340                         return status;
  1341                 }
  1342                 else if (_is_text_part(content, "html") &&
  1343                         msg->longmsg_formatted == NULL) {
  1344                     status = interpret_body(part, &msg->longmsg_formatted,
  1345                             NULL);
  1346                     if (status)
  1347                         return status;
  1348                 }
  1349                 else /* add as attachment */ {
  1350                     status = interpret_MIME(part, msg);
  1351                     if (status)
  1352                         return status;
  1353                 }
  1354             }
  1355         }
  1356         else if (_is_multipart(content, "encrypted")) {
  1357             if (msg->longmsg == NULL)
  1358                 msg->longmsg = strdup("");
  1359 
  1360             clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
  1361             if (partlist == NULL)
  1362                 return PEP_ILLEGAL_VALUE;
  1363 
  1364             clistiter *cur;
  1365             for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
  1366                 struct mailmime *part= clist_content(cur);
  1367                 if (part == NULL)
  1368                     return PEP_ILLEGAL_VALUE;
  1369 
  1370                 status = interpret_MIME(part, msg);
  1371                 if (status != PEP_STATUS_OK)
  1372                     return status;
  1373             }
  1374         }
  1375         else if (_is_multipart(content, NULL)) {
  1376             clist *partlist = mime->mm_data.mm_multipart.mm_mp_list;
  1377             if (partlist == NULL)
  1378                 return PEP_ILLEGAL_VALUE;
  1379 
  1380             clistiter *cur;
  1381             for (cur = clist_begin(partlist); cur; cur = clist_next(cur)) {
  1382                 struct mailmime *part= clist_content(cur);
  1383                 if (part == NULL)
  1384                     return PEP_ILLEGAL_VALUE;
  1385 
  1386                 status = interpret_MIME(part, msg);
  1387                 if (status != PEP_STATUS_OK)
  1388                     return status;
  1389             }
  1390         }
  1391         else {
  1392             if (_is_text_part(content, NULL) && msg->longmsg == NULL) {
  1393                 status = interpret_body(mime, &msg->longmsg, NULL);
  1394                 if (status)
  1395                     return status;
  1396             }
  1397             else {
  1398                 char *data = NULL;
  1399                 size_t size = 0;
  1400                 char * mime_type;
  1401                 char * charset;
  1402                 char * filename;
  1403                 int r;
  1404 
  1405                 r = _get_content_type(content, &mime_type, &charset);
  1406                 switch (r) {
  1407                     case 0:
  1408                         break;
  1409                     case EINVAL:
  1410                         return PEP_ILLEGAL_VALUE;
  1411                     case ENOMEM:
  1412                         return PEP_OUT_OF_MEMORY;
  1413                     default:
  1414                         return PEP_UNKNOWN_ERROR;
  1415                 }
  1416 
  1417                 assert(mime_type);
  1418 
  1419                 status = interpret_body(mime, &data, &size);
  1420                 if (status)
  1421                     return status;
  1422 
  1423                 filename = _get_filename(mime);
  1424 
  1425                 bloblist_t *_a = bloblist_add(msg->attachments, data, size,
  1426                         mime_type, filename);
  1427                 if (_a == NULL)
  1428                     return PEP_OUT_OF_MEMORY;
  1429                 if (msg->attachments == NULL)
  1430                     msg->attachments = _a;
  1431             }
  1432         }
  1433     }
  1434 
  1435     return PEP_STATUS_OK;
  1436 }
  1437 
  1438 DYNAMIC_API PEP_STATUS mime_decode_message(
  1439         const char *mimetext,
  1440         size_t size,
  1441         message **msg
  1442     )
  1443 {
  1444     PEP_STATUS status = PEP_STATUS_OK;
  1445     struct mailmime * mime = NULL;
  1446     int r;
  1447     message *_msg = NULL;
  1448     size_t index;
  1449 
  1450     assert(mimetext);
  1451     assert(msg);
  1452 
  1453     if (!(mimetext && msg))
  1454         return PEP_ILLEGAL_VALUE;
  1455 
  1456     *msg = NULL;
  1457 
  1458     index = 0;
  1459     r = mailmime_parse(mimetext, size, &index, &mime);
  1460     assert(r == 0);
  1461     assert(mime);
  1462     if (r) {
  1463         if (r == MAILIMF_ERROR_MEMORY)
  1464             goto enomem;
  1465         else
  1466             goto err_mime;
  1467     }
  1468 
  1469     _msg = calloc(1, sizeof(message));
  1470     assert(_msg);
  1471     if (_msg == NULL)
  1472         goto enomem;
  1473 
  1474     clist * _fieldlist = _get_fields(mime);
  1475     if (_fieldlist) {
  1476         status = read_fields(_msg, _fieldlist);
  1477         if (status != PEP_STATUS_OK)
  1478             goto pep_error;
  1479     }
  1480 
  1481     struct mailmime_content *content = _get_content(mime);
  1482 
  1483     if (content) {
  1484         status = interpret_MIME(mime->mm_data.mm_message.mm_msg_mime,
  1485                 _msg);
  1486         if (status != PEP_STATUS_OK)
  1487             goto pep_error;
  1488     }
  1489 
  1490     mailmime_free(mime);
  1491     *msg = _msg;
  1492 
  1493     return status;
  1494 
  1495 err_mime:
  1496     status = PEP_ILLEGAL_VALUE;
  1497     goto pep_error;
  1498 
  1499 enomem:
  1500     status = PEP_OUT_OF_MEMORY;
  1501 
  1502 pep_error:
  1503     free_message(_msg);
  1504 
  1505     if (mime)
  1506         mailmime_free(mime);
  1507 
  1508     return status;
  1509 }
  1510