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