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