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