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