src/message_api.c
author Krista Bennett <krista@pep-project.org>
Thu, 04 May 2017 14:46:36 +0200
changeset 1748 58ae886d5079
parent 1746 498b0671ff4e
child 1753 01faac16cec6
child 1755 1de149b237ab
permissions -rw-r--r--
ENGINE-205: Corrected rating for PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH
     1 // This file is under GNU General Public License 3.0
     2 // see LICENSE.txt
     3 
     4 #include "pEp_internal.h"
     5 #include "message_api.h"
     6 
     7 #include "platform.h"
     8 #include "mime.h"
     9 #include "sync_fsm.h"
    10 
    11 #include <assert.h>
    12 #include <string.h>
    13 #include <stdlib.h>
    14 
    15 
    16 #ifndef _MIN
    17 #define _MIN(A, B) ((B) > (A) ? (A) : (B))
    18 #endif
    19 #ifndef _MAX
    20 #define _MAX(A, B) ((B) > (A) ? (B) : (A))
    21 #endif
    22 
    23 
    24 static bool string_equality(const char *s1, const char *s2)
    25 {
    26     if (s1 == NULL || s2 == NULL)
    27         return false;
    28 
    29     assert(s1 && s2);
    30 
    31     return strcmp(s1, s2) == 0;
    32 }
    33 
    34 static bool is_mime_type(const bloblist_t *bl, const char *mt)
    35 {
    36     assert(mt);
    37 
    38     return bl && string_equality(bl->mime_type, mt);
    39 }
    40 
    41 //
    42 // This function presumes the file ending is a proper substring of the
    43 // filename (i.e. if bl->filename is "a.pgp" and fe is ".pgp", it will
    44 // return true, but if bl->filename is ".pgp" and fe is ".pgp", it will
    45 // return false. This is desired behaviour.
    46 //
    47 static bool is_fileending(const bloblist_t *bl, const char *fe)
    48 {
    49     assert(fe);
    50 
    51     if (bl == NULL || bl->filename == NULL || fe == NULL)
    52         return false;
    53 
    54     assert(bl && bl->filename);
    55 
    56     size_t fe_len = strlen(fe);
    57     size_t fn_len = strlen(bl->filename);
    58 
    59     if (fn_len <= fe_len)
    60         return false;
    61 
    62     assert(fn_len > fe_len);
    63 
    64     return strcmp(bl->filename + (fn_len - fe_len), fe) == 0;
    65 }
    66 
    67 void add_opt_field(message *msg, const char *name, const char *value)
    68 {
    69     assert(msg && name && value);
    70 
    71     if (msg && name && value) {
    72         stringpair_t *pair = new_stringpair(name, value);
    73         if (pair == NULL)
    74             return;
    75 
    76         stringpair_list_t *field = stringpair_list_add(msg->opt_fields, pair);
    77         if (field == NULL)
    78         {
    79             free_stringpair(pair);
    80             return;
    81         }
    82 
    83         if (msg->opt_fields == NULL)
    84             msg->opt_fields = field;
    85     }
    86 }
    87 
    88 static char * combine_short_and_long(const char *shortmsg, const char *longmsg)
    89 {
    90     assert(shortmsg);
    91     assert(strcmp(shortmsg, "pEp") != 0);
    92 
    93     if (!shortmsg || strcmp(shortmsg, "pEp") == 0) {
    94         if (!longmsg) {
    95             return NULL;
    96         }
    97         else {
    98             char *result = strdup(longmsg);
    99             assert(result);
   100             return result;
   101         }
   102     }
   103 
   104     if (longmsg == NULL)
   105         longmsg = "";
   106 
   107     const char * const subject = "Subject: ";
   108     const size_t SUBJ_LEN = 9;
   109     const char * const newlines = "\n\n";
   110     const size_t NL_LEN = 2;
   111 
   112     const size_t bufsize = SUBJ_LEN + strlen(shortmsg) + NL_LEN + strlen(longmsg) + 1;
   113     char * ptext = calloc(1, bufsize);
   114     assert(ptext);
   115     if (ptext == NULL)
   116         return NULL;
   117 
   118     strlcpy(ptext, subject, bufsize);
   119     strlcat(ptext, shortmsg, bufsize);
   120     strlcat(ptext, newlines, bufsize);
   121     strlcat(ptext, longmsg, bufsize);
   122 
   123     return ptext;
   124 }
   125 
   126 static int separate_short_and_long(const char *src, char **shortmsg, char **longmsg)
   127 {
   128     char *_shortmsg = NULL;
   129     char *_longmsg = NULL;
   130 
   131     assert(src);
   132     assert(shortmsg);
   133     assert(longmsg);
   134 
   135     if (src == NULL || shortmsg == NULL || longmsg == NULL)
   136         return -1;
   137 
   138     *shortmsg = NULL;
   139     *longmsg = NULL;
   140 
   141     if (strncasecmp(src, "subject: ", 9) == 0) {
   142         char *line_end = strchr(src, '\n');
   143 
   144         if (line_end == NULL) {
   145             _shortmsg = strdup(src + 9);
   146             assert(_shortmsg);
   147             if (_shortmsg == NULL)
   148                 goto enomem;
   149             // _longmsg = NULL;
   150         }
   151         else {
   152             size_t n = line_end - src;
   153 
   154             if (*(line_end - 1) == '\r')
   155                 _shortmsg = strndup(src + 9, n - 10);
   156             else
   157                 _shortmsg = strndup(src + 9, n - 9);
   158             assert(_shortmsg);
   159             if (_shortmsg == NULL)
   160                 goto enomem;
   161 
   162             while (*(src + n) && (*(src + n) == '\n' || *(src + n) == '\r'))
   163                 ++n;
   164 
   165             if (*(src + n)) {
   166                 _longmsg = strdup(src + n);
   167                 assert(_longmsg);
   168                 if (_longmsg == NULL)
   169                     goto enomem;
   170             }
   171         }
   172     }
   173     else {
   174         _shortmsg = strdup("");
   175         assert(_shortmsg);
   176         if (_shortmsg == NULL)
   177             goto enomem;
   178         _longmsg = strdup(src);
   179         assert(_longmsg);
   180         if (_longmsg == NULL)
   181             goto enomem;
   182     }
   183 
   184     *shortmsg = _shortmsg;
   185     *longmsg = _longmsg;
   186 
   187     return 0;
   188 
   189 enomem:
   190     free(_shortmsg);
   191     free(_longmsg);
   192 
   193     return -1;
   194 }
   195 
   196 static PEP_STATUS copy_fields(message *dst, const message *src)
   197 {
   198     assert(dst);
   199     assert(src);
   200 
   201     if(!(dst && src))
   202         return PEP_ILLEGAL_VALUE;
   203 
   204     free_timestamp(dst->sent);
   205     dst->sent = NULL;
   206     if (src->sent) {
   207         dst->sent = timestamp_dup(src->sent);
   208         if (dst->sent == NULL)
   209             return PEP_OUT_OF_MEMORY;
   210     }
   211 
   212     free_timestamp(dst->recv);
   213     dst->recv = NULL;
   214     if (src->recv) {
   215         dst->recv = timestamp_dup(src->recv);
   216         if (dst->recv == NULL)
   217             return PEP_OUT_OF_MEMORY;
   218     }
   219 
   220     free_identity(dst->from);
   221     dst->from = NULL;
   222     if (src->from) {
   223         dst->from = identity_dup(src->from);
   224         if (dst->from == NULL)
   225             return PEP_OUT_OF_MEMORY;
   226     }
   227 
   228     free_identity_list(dst->to);
   229     dst->to = NULL;
   230     if (src->to && src->to->ident) {
   231         dst->to = identity_list_dup(src->to);
   232         if (dst->to == NULL)
   233             return PEP_OUT_OF_MEMORY;
   234     }
   235 
   236     free_identity(dst->recv_by);
   237     dst->recv_by = NULL;
   238     if (src->recv_by) {
   239         dst->recv_by = identity_dup(src->recv_by);
   240         if (dst->recv_by == NULL)
   241             return PEP_OUT_OF_MEMORY;
   242     }
   243 
   244     free_identity_list(dst->cc);
   245     dst->cc = NULL;
   246     if (src->cc && src->cc->ident) {
   247         dst->cc = identity_list_dup(src->cc);
   248         if (dst->cc == NULL)
   249             return PEP_OUT_OF_MEMORY;
   250     }
   251 
   252     free_identity_list(dst->bcc);
   253     dst->bcc = NULL;
   254     if (src->bcc && src->bcc->ident) {
   255         dst->bcc = identity_list_dup(src->bcc);
   256         if (dst->bcc == NULL)
   257             return PEP_OUT_OF_MEMORY;
   258     }
   259 
   260     free_identity_list(dst->reply_to);
   261     dst->reply_to = NULL;
   262     if (src->reply_to && src->reply_to->ident) {
   263         dst->reply_to = identity_list_dup(src->reply_to);
   264         if (dst->reply_to == NULL)
   265             return PEP_OUT_OF_MEMORY;
   266     }
   267 
   268     free_stringlist(dst->in_reply_to);
   269     dst->in_reply_to = NULL;
   270     if (src->in_reply_to && src->in_reply_to->value) {
   271         dst->in_reply_to = stringlist_dup(src->in_reply_to);
   272         if (dst->in_reply_to == NULL)
   273             return PEP_OUT_OF_MEMORY;
   274     }
   275 
   276     free_stringlist(dst->references);
   277     dst->references = NULL;
   278     if (src->references) {
   279         dst->references = stringlist_dup(src->references);
   280         if (dst->references == NULL)
   281             return PEP_OUT_OF_MEMORY;
   282     }
   283 
   284     free_stringlist(dst->keywords);
   285     dst->keywords = NULL;
   286     if (src->keywords && src->keywords->value) {
   287         dst->keywords = stringlist_dup(src->keywords);
   288         if (dst->keywords == NULL)
   289             return PEP_OUT_OF_MEMORY;
   290     }
   291 
   292     free(dst->comments);
   293     dst->comments = NULL;
   294     if (src->comments) {
   295         dst->comments = strdup(src->comments);
   296         assert(dst->comments);
   297         if (dst->comments == NULL)
   298             return PEP_OUT_OF_MEMORY;
   299     }
   300 
   301     free_stringpair_list(dst->opt_fields);
   302     dst->opt_fields = NULL;
   303     if (src->opt_fields) {
   304         dst->opt_fields = stringpair_list_dup(src->opt_fields);
   305         if (dst->opt_fields == NULL)
   306             return PEP_OUT_OF_MEMORY;
   307     }
   308 
   309     return PEP_STATUS_OK;
   310 }
   311 
   312 static message * clone_to_empty_message(const message * src)
   313 {
   314     PEP_STATUS status;
   315     message * msg = NULL;
   316 
   317     assert(src);
   318     if (src == NULL)
   319         return NULL;
   320 
   321     msg = calloc(1, sizeof(message));
   322     assert(msg);
   323     if (msg == NULL)
   324         goto enomem;
   325 
   326     msg->dir = src->dir;
   327 
   328     status = copy_fields(msg, src);
   329     if (status != PEP_STATUS_OK)
   330         goto enomem;
   331 
   332     return msg;
   333 
   334 enomem:
   335     free_message(msg);
   336     return NULL;
   337 }
   338 
   339 static PEP_STATUS encrypt_PGP_MIME(
   340     PEP_SESSION session,
   341     const message *src,
   342     stringlist_t *keys,
   343     message *dst,
   344     PEP_encrypt_flags_t flags
   345     )
   346 {
   347     PEP_STATUS status = PEP_STATUS_OK;
   348     bool free_ptext = false;
   349     char *ptext = NULL;
   350     char *ctext = NULL;
   351     char *mimetext = NULL;
   352     size_t csize;
   353     assert(dst->longmsg == NULL);
   354     dst->enc_format = PEP_enc_PGP_MIME;
   355 
   356     if (src->shortmsg && strcmp(src->shortmsg, "pEp") != 0) {
   357         if (session->unencrypted_subject) {
   358             dst->shortmsg = strdup(src->shortmsg);
   359             assert(dst->shortmsg);
   360             if (dst->shortmsg == NULL)
   361                 goto enomem;
   362             ptext = src->longmsg;
   363         }
   364         else {
   365             ptext = combine_short_and_long(src->shortmsg, src->longmsg);
   366             if (ptext == NULL)
   367                 goto enomem;
   368             free_ptext = true;
   369         }
   370     }
   371     else if (src->longmsg) {
   372         ptext = src->longmsg;
   373     }
   374     else {
   375         ptext = "pEp";
   376     }
   377 
   378     message *_src = calloc(1, sizeof(message));
   379     assert(_src);
   380     if (_src == NULL)
   381         goto enomem;
   382     _src->longmsg = ptext;
   383     _src->longmsg_formatted = src->longmsg_formatted;
   384     _src->attachments = src->attachments;
   385     _src->enc_format = PEP_enc_none;
   386     status = mime_encode_message(_src, true, &mimetext);
   387     assert(status == PEP_STATUS_OK);
   388     if (status != PEP_STATUS_OK)
   389         goto pep_error;
   390 
   391     if (free_ptext){
   392         free(ptext);
   393         free_ptext=0;
   394     }
   395     free(_src);
   396     assert(mimetext);
   397     if (mimetext == NULL)
   398         goto pep_error;
   399 
   400     if (flags & PEP_encrypt_flag_force_unsigned)
   401         status = encrypt_only(session, keys, mimetext, strlen(mimetext),
   402             &ctext, &csize);
   403     else
   404         status = encrypt_and_sign(session, keys, mimetext, strlen(mimetext),
   405             &ctext, &csize);
   406     free(mimetext);
   407     if (ctext == NULL)
   408         goto pep_error;
   409 
   410     dst->longmsg = strdup("this message was encrypted with p≡p "
   411         "https://pEp-project.org");
   412     assert(dst->longmsg);
   413     if (dst->longmsg == NULL)
   414         goto enomem;
   415 
   416     char *v = strdup("Version: 1");
   417     assert(v);
   418     if (v == NULL)
   419         goto enomem;
   420 
   421     bloblist_t *_a = new_bloblist(v, strlen(v), "application/pgp-encrypted", NULL);
   422     if (_a == NULL)
   423         goto enomem;
   424     dst->attachments = _a;
   425 
   426     _a = bloblist_add(_a, ctext, csize, "application/octet-stream",
   427         "msg.asc");
   428     if (_a == NULL)
   429         goto enomem;
   430 
   431     return PEP_STATUS_OK;
   432 
   433 enomem:
   434     status = PEP_OUT_OF_MEMORY;
   435 
   436 pep_error:
   437     if (free_ptext)
   438         free(ptext);
   439     free(ctext);
   440     return status;
   441 }
   442 
   443 static PEP_STATUS encrypt_PGP_in_pieces(
   444     PEP_SESSION session,
   445     const message *src,
   446     stringlist_t *keys,
   447     message *dst,
   448     PEP_encrypt_flags_t flags
   449     )
   450 {
   451     PEP_STATUS status = PEP_STATUS_OK;
   452     char *ctext = NULL;
   453     size_t csize;
   454     char *ptext = NULL;
   455     bool free_ptext = false;
   456 
   457     assert(dst->longmsg == NULL);
   458     assert(dst->attachments == NULL);
   459 
   460     dst->enc_format = PEP_enc_pieces;
   461 
   462     bool nosign = (flags & PEP_encrypt_flag_force_unsigned);
   463 
   464     if (src->shortmsg && src->shortmsg[0] && strcmp(src->shortmsg, "pEp") != 0) {
   465         if (session->unencrypted_subject) {
   466             dst->shortmsg = strdup(src->shortmsg);
   467             assert(dst->shortmsg);
   468             if (dst->shortmsg == NULL)
   469                 goto enomem;
   470             ptext = src->longmsg;
   471         }
   472         else {
   473             ptext = combine_short_and_long(src->shortmsg, src->longmsg);
   474             if (ptext == NULL)
   475                 goto enomem;
   476             free_ptext = true;
   477         }
   478 
   479         if (nosign)
   480             status = encrypt_only(session, keys, ptext, strlen(ptext), &ctext,
   481                 &csize);
   482         else 
   483             status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
   484                 &csize);
   485         if (free_ptext)
   486             free(ptext);
   487         free_ptext = false;
   488         if (ctext) {
   489             dst->longmsg = ctext;
   490         }
   491         else {
   492             goto pep_error;
   493         }
   494     }
   495     else if (src->longmsg && src->longmsg[0]) {
   496         ptext = src->longmsg;
   497         if (nosign)
   498             status = encrypt_only(session, keys, ptext, strlen(ptext), &ctext,
   499                 &csize);
   500         else 
   501             status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
   502                 &csize);
   503         if (ctext) {
   504             dst->longmsg = ctext;
   505         }
   506         else {
   507             goto pep_error;
   508         }
   509     }
   510     else {
   511         dst->longmsg = strdup("");
   512         assert(dst->longmsg);
   513         if (dst->longmsg == NULL)
   514             goto enomem;
   515     }
   516 
   517     if (src->longmsg_formatted && src->longmsg_formatted[0]) {
   518         ptext = src->longmsg_formatted;
   519         if (nosign)
   520             status = encrypt_only(session, keys, ptext, strlen(ptext), &ctext,
   521                 &csize);
   522         else 
   523             status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
   524                 &csize);
   525         if (ctext) {
   526 
   527             bloblist_t *_a = bloblist_add(dst->attachments, ctext, csize,
   528                 "application/octet-stream", "PGPexch.htm.pgp");
   529             if (_a == NULL)
   530                 goto enomem;
   531             if (dst->attachments == NULL)
   532                 dst->attachments = _a;
   533         }
   534         else {
   535             goto pep_error;
   536         }
   537     }
   538 
   539     if (src->attachments) {
   540         if (dst->attachments == NULL) {
   541             dst->attachments = new_bloblist(NULL, 0, NULL, NULL);
   542             if (dst->attachments == NULL)
   543                 goto enomem;
   544         }
   545 
   546         bloblist_t *_s = src->attachments;
   547         bloblist_t *_d = dst->attachments;
   548 
   549         for (int n = 0; _s; _s = _s->next) {
   550             if (_s->value == NULL && _s->size == 0) {
   551                 _d = bloblist_add(_d, NULL, 0, _s->mime_type, _s->filename);
   552                 if (_d == NULL)
   553                     goto enomem;
   554             }
   555             else {
   556                 size_t psize = _s->size;
   557                 ptext = _s->value;
   558                 if (nosign)
   559                     status = encrypt_only(session, keys, ptext, psize, &ctext,
   560                         &csize);
   561                 else 
   562                     status = encrypt_and_sign(session, keys, ptext, psize, &ctext,
   563                         &csize);
   564                 if (ctext) {
   565                     char *filename = NULL;
   566 
   567                     if (_s->filename) {
   568                         size_t len = strlen(_s->filename);
   569                         size_t bufsize = len + 5; // length of .pgp extension + NUL
   570                         filename = calloc(1, bufsize);
   571                         if (filename == NULL)
   572                             goto enomem;
   573 
   574                         strlcpy(filename, _s->filename, bufsize);
   575                         strlcat(filename, ".pgp", bufsize);
   576                     }
   577                     else {
   578                         filename = calloc(1, 20);
   579                         if (filename == NULL)
   580                             goto enomem;
   581 
   582                         ++n;
   583                         n &= 0xffff;
   584                         snprintf(filename, 20, "Attachment%d.pgp", n);
   585                     }
   586 
   587                     _d = bloblist_add(_d, ctext, csize, "application/octet-stream",
   588                         filename);
   589                     free(filename);
   590                     if (_d == NULL)
   591                         goto enomem;
   592                 }
   593                 else {
   594                     goto pep_error;
   595                 }
   596             }
   597         }
   598     }
   599 
   600     return PEP_STATUS_OK;
   601 
   602 enomem:
   603     status = PEP_OUT_OF_MEMORY;
   604 
   605 pep_error:
   606     if (free_ptext)
   607         free(ptext);
   608     return status;
   609 }
   610 
   611 static char * keylist_to_string(const stringlist_t *keylist)
   612 {
   613     if (keylist) {
   614         size_t size = stringlist_length(keylist);
   615 
   616         const stringlist_t *_kl;
   617         for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
   618             size += strlen(_kl->value);
   619         }
   620 
   621         char *result = calloc(1, size);
   622         if (result == NULL)
   623             return NULL;
   624 
   625         char *_r = result;
   626         for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
   627             _r = stpcpy(_r, _kl->value);
   628             if (_kl->next && _kl->next->value)
   629                 _r = stpcpy(_r, ",");
   630         }
   631 
   632         return result;
   633     }
   634     else {
   635         return NULL;
   636     }
   637 }
   638 
   639 static const char * rating_to_string(PEP_rating rating)
   640 {
   641     switch (rating) {
   642     case PEP_rating_cannot_decrypt:
   643         return "cannot_decrypt";
   644     case PEP_rating_have_no_key:
   645         return "have_no_key";
   646     case PEP_rating_unencrypted:
   647         return "unencrypted";
   648     case PEP_rating_unencrypted_for_some:
   649         return "unencrypted_for_some";
   650     case PEP_rating_unreliable:
   651         return "unreliable";
   652     case PEP_rating_reliable:
   653         return "reliable";
   654     case PEP_rating_trusted:
   655         return "trusted";
   656     case PEP_rating_trusted_and_anonymized:
   657         return "trusted_and_anonymized";
   658     case PEP_rating_fully_anonymous:
   659         return "fully_anonymous";
   660     case PEP_rating_mistrust:
   661         return "mistrust";
   662     case PEP_rating_b0rken:
   663         return "b0rken";
   664     case PEP_rating_under_attack:
   665         return "under_attack";
   666     default:
   667         return "undefined";
   668     }
   669 }
   670 
   671 static void decorate_message(
   672     message *msg,
   673     PEP_rating rating,
   674     stringlist_t *keylist
   675     )
   676 {
   677     assert(msg);
   678 
   679     add_opt_field(msg, "X-pEp-Version", PEP_VERSION);
   680 
   681     if (rating != PEP_rating_undefined)
   682         add_opt_field(msg, "X-EncStatus", rating_to_string(rating));
   683 
   684     if (keylist) {
   685         char *_keylist = keylist_to_string(keylist);
   686         add_opt_field(msg, "X-KeyList", _keylist);
   687         free(_keylist);
   688     }
   689 }
   690 
   691 static PEP_rating _rating(PEP_comm_type ct, PEP_rating rating)
   692 {
   693     if (ct == PEP_ct_unknown)
   694         return PEP_rating_undefined;
   695 
   696     else if (ct == PEP_ct_key_not_found)
   697         return PEP_rating_have_no_key;
   698 
   699     else if (ct == PEP_ct_compromized)
   700         return PEP_rating_under_attack;
   701 
   702     else if (ct == PEP_ct_mistrusted)
   703         return PEP_rating_mistrust;
   704 
   705     if (rating == PEP_rating_unencrypted_for_some)
   706         return PEP_rating_unencrypted_for_some;
   707 
   708     if (ct == PEP_ct_no_encryption || ct == PEP_ct_no_encrypted_channel ||
   709             ct == PEP_ct_my_key_not_included) {
   710         if (rating > PEP_rating_unencrypted_for_some)
   711             return PEP_rating_unencrypted_for_some;
   712         else
   713             return PEP_rating_unencrypted;
   714     }
   715 
   716     if (rating == PEP_rating_unencrypted)
   717         return PEP_rating_unencrypted_for_some;
   718 
   719     if (ct >= PEP_ct_confirmed_enc_anon)
   720         return PEP_rating_trusted_and_anonymized;
   721 
   722     else if (ct >= PEP_ct_strong_encryption)
   723         return PEP_rating_trusted;
   724 
   725     else if (ct >= PEP_ct_strong_but_unconfirmed && ct < PEP_ct_confirmed)
   726         return PEP_rating_reliable;
   727 
   728     else
   729         return PEP_rating_unreliable;
   730 }
   731 
   732 static bool is_encrypted_attachment(const bloblist_t *blob)
   733 {
   734     assert(blob);
   735 
   736     if (blob == NULL || blob->filename == NULL)
   737         return false;
   738 
   739     char *ext = strrchr(blob->filename, '.');
   740     if (ext == NULL)
   741         return false;
   742 
   743     if (strcmp(blob->mime_type, "application/octet-stream") == 0) {
   744         if (strcmp(ext, ".pgp") == 0 || strcmp(ext, ".gpg") == 0 ||
   745             strcmp(ext, ".asc") == 0)
   746             return true;
   747     }
   748     else if (strcmp(blob->mime_type, "text/plain") == 0) {
   749         if (strcmp(ext, ".asc") == 0)
   750             return true;
   751     }
   752 
   753     return false;
   754 }
   755 
   756 static bool is_encrypted_html_attachment(const bloblist_t *blob)
   757 {
   758     assert(blob);
   759     assert(blob->filename);
   760     if (blob == NULL || blob->filename == NULL)
   761         return false;
   762 
   763     if (strncmp(blob->filename, "PGPexch.htm.", 12) == 0) {
   764         if (strcmp(blob->filename + 11, ".pgp") == 0 ||
   765             strcmp(blob->filename + 11, ".asc") == 0)
   766             return true;
   767     }
   768 
   769     return false;
   770 }
   771 
   772 static char * without_double_ending(const char *filename)
   773 {
   774     assert(filename);
   775     if (filename == NULL)
   776         return NULL;
   777 
   778     char *ext = strrchr(filename, '.');
   779     if (ext == NULL)
   780         return NULL;
   781 
   782     char *result = strndup(filename, ext - filename);
   783     assert(result);
   784     return result;
   785 }
   786 
   787 static PEP_rating decrypt_rating(PEP_STATUS status)
   788 {
   789     switch (status) {
   790     case PEP_UNENCRYPTED:
   791     case PEP_VERIFIED:
   792     case PEP_VERIFY_NO_KEY:
   793     case PEP_VERIFIED_AND_TRUSTED:
   794         return PEP_rating_unencrypted;
   795 
   796     case PEP_DECRYPTED:
   797     case PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH:
   798         return PEP_rating_unreliable;
   799 
   800     case PEP_DECRYPTED_AND_VERIFIED:
   801         return PEP_rating_reliable;
   802 
   803     case PEP_DECRYPT_NO_KEY:
   804         return PEP_rating_have_no_key;
   805 
   806     case PEP_DECRYPT_WRONG_FORMAT:
   807     case PEP_CANNOT_DECRYPT_UNKNOWN:
   808         return PEP_rating_cannot_decrypt;
   809 
   810     default:
   811         return PEP_rating_undefined;
   812     }
   813 }
   814 
   815 static PEP_rating key_rating(PEP_SESSION session, const char *fpr)
   816 {
   817 
   818     assert(session);
   819     assert(fpr);
   820 
   821     if (session == NULL || fpr == NULL)
   822         return PEP_rating_undefined;
   823 
   824 
   825     PEP_comm_type bare_comm_type = PEP_ct_unknown;
   826     PEP_STATUS status = get_key_rating(session, fpr, &bare_comm_type);
   827     if (status != PEP_STATUS_OK)
   828         return PEP_rating_undefined;
   829 
   830     PEP_comm_type least_trust_type = PEP_ct_unknown;
   831     least_trust(session, fpr, &least_trust_type);
   832 
   833     if (least_trust_type == PEP_ct_unknown) {
   834         return _rating(bare_comm_type, PEP_rating_undefined);
   835     } else {
   836         return _rating(least_trust_type, PEP_rating_undefined);
   837     }
   838 }
   839 
   840 static PEP_rating worst_rating(PEP_rating rating1, PEP_rating rating2) {
   841     return ((rating1 < rating2) ? rating1 : rating2);
   842 }
   843 
   844 static PEP_rating keylist_rating(PEP_SESSION session, stringlist_t *keylist)
   845 {
   846     PEP_rating rating = PEP_rating_undefined;
   847 
   848     assert(keylist && keylist->value);
   849     if (keylist == NULL || keylist->value == NULL)
   850         return PEP_rating_undefined;
   851 
   852     stringlist_t *_kl;
   853     bool first = true;
   854     for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
   855         PEP_comm_type ct;
   856         PEP_STATUS status;
   857 
   858         PEP_rating _rating_ = key_rating(session, _kl->value);
   859          
   860         if (_rating_ <= PEP_rating_mistrust)
   861             return _rating_;
   862             
   863         if (first) {
   864             rating = _rating_;
   865             first = false;
   866         }
   867         else if (rating == PEP_rating_undefined)
   868             rating = worst_rating(rating, _rating_);
   869 
   870         if (_rating_ >= PEP_rating_reliable) {
   871             status = least_trust(session, _kl->value, &ct);
   872             if (status != PEP_STATUS_OK)
   873                 return PEP_rating_undefined;
   874             if (ct == PEP_ct_unknown){
   875                 /* per edouard, we reduce reliable+ ratings to reliable because
   876                    ct unknown */
   877                 if (rating >= PEP_rating_reliable){
   878                     rating = PEP_rating_reliable; 
   879                 }
   880             }
   881             else{
   882                 rating = worst_rating(rating, _rating(ct, rating));
   883             }
   884         }
   885         else if (_rating_ == PEP_rating_unencrypted) {
   886             if (rating > PEP_rating_unencrypted_for_some)
   887                 rating = worst_rating(rating, PEP_rating_unencrypted_for_some);
   888         }
   889     }
   890 
   891     return rating;
   892 }
   893 
   894 static PEP_comm_type _get_comm_type(
   895     PEP_SESSION session,
   896     PEP_comm_type max_comm_type,
   897     pEp_identity *ident
   898     )
   899 {
   900     PEP_STATUS status = update_identity(session, ident);
   901 
   902     if (max_comm_type == PEP_ct_compromized)
   903         return PEP_ct_compromized;
   904 
   905     if (max_comm_type == PEP_ct_mistrusted)
   906         return PEP_ct_mistrusted;
   907 
   908     if (status == PEP_STATUS_OK) {
   909         if (ident->comm_type == PEP_ct_compromized)
   910             return PEP_ct_compromized;
   911         else if (ident->comm_type == PEP_ct_mistrusted)
   912             return PEP_ct_mistrusted;
   913         else
   914             return _MIN(max_comm_type, ident->comm_type);
   915     }
   916     else {
   917         return PEP_ct_unknown;
   918     }
   919 }
   920 
   921 static void free_bl_entry(bloblist_t *bl)
   922 {
   923     if (bl) {
   924         free(bl->value);
   925         free(bl->mime_type);
   926         free(bl->filename);
   927         free(bl);
   928     }
   929 }
   930 
   931 static bool is_key(const bloblist_t *bl)
   932 {
   933     return (// workaround for Apple Mail bugs
   934             (is_mime_type(bl, "application/x-apple-msg-attachment") &&
   935              is_fileending(bl, ".asc")) ||
   936             // as binary, by file name
   937             ((bl->mime_type == NULL ||
   938               is_mime_type(bl, "application/octet-stream")) &&
   939              (is_fileending(bl, ".pgp") || is_fileending(bl, ".gpg") ||
   940                     is_fileending(bl, ".key") || is_fileending(bl, ".asc"))) ||
   941             // explicit mime type
   942             is_mime_type(bl, "application/pgp-keys") ||
   943             // as text, by file name
   944             (is_mime_type(bl, "text/plain") &&
   945              (is_fileending(bl, ".pgp") || is_fileending(bl, ".gpg") ||
   946                     is_fileending(bl, ".key") || is_fileending(bl, ".asc")))
   947            );
   948 }
   949 
   950 static void remove_attached_keys(message *msg)
   951 {
   952     if (msg) {
   953         bloblist_t *last = NULL;
   954         for (bloblist_t *bl = msg->attachments; bl && bl->value; ) {
   955             bloblist_t *next = bl->next;
   956 
   957             if (is_key(bl)) {
   958                 if (last) {
   959                     last->next = next;
   960                 }
   961                 else {
   962                     msg->attachments = next;
   963                 }
   964                 free_bl_entry(bl);
   965             }
   966             else {
   967                 last = bl;
   968             }
   969             bl = next;
   970         }
   971     }
   972 }
   973 
   974 bool import_attached_keys(
   975         PEP_SESSION session,
   976         const message *msg,
   977         identity_list **private_idents
   978     )
   979 {
   980     assert(session);
   981     assert(msg);
   982 
   983     if (session == NULL || msg == NULL)
   984         return false;
   985 
   986     bool remove = false;
   987 
   988     int i = 0;
   989     for (bloblist_t *bl = msg->attachments; i < MAX_KEYS_TO_IMPORT && bl && bl->value;
   990             bl = bl->next, i++)
   991     {
   992         if (bl && bl->value && bl->size && bl->size < MAX_KEY_SIZE
   993                 && is_key(bl))
   994         {
   995             import_key(session, bl->value, bl->size, private_idents);
   996             remove = true;
   997         }
   998     }
   999     return remove;
  1000 }
  1001 
  1002 
  1003 PEP_STATUS _attach_key(PEP_SESSION session, const char* fpr, message *msg)
  1004 {
  1005     char *keydata = NULL;
  1006     size_t size;
  1007 
  1008     PEP_STATUS status = export_key(session, fpr, &keydata, &size);
  1009     assert(status == PEP_STATUS_OK);
  1010     if (status != PEP_STATUS_OK)
  1011         return status;
  1012     assert(size);
  1013 
  1014      bloblist_t *bl = bloblist_add(msg->attachments, keydata, size, "application/pgp-keys",
  1015                       "pEpkey.asc");
  1016 
  1017     if (msg->attachments == NULL && bl)
  1018         msg->attachments = bl;
  1019 
  1020     return PEP_STATUS_OK;
  1021 }
  1022 
  1023 #define ONE_WEEK (7*24*3600)
  1024 
  1025 void attach_own_key(PEP_SESSION session, message *msg)
  1026 {
  1027     assert(session);
  1028     assert(msg);
  1029 
  1030     if (msg->dir == PEP_dir_incoming)
  1031         return;
  1032 
  1033     assert(msg->from && msg->from->fpr);
  1034     if (msg->from == NULL || msg->from->fpr == NULL)
  1035         return;
  1036 
  1037     if(_attach_key(session, msg->from->fpr, msg) != PEP_STATUS_OK)
  1038         return;
  1039 
  1040     char *revoked_fpr = NULL;
  1041     uint64_t revocation_date = 0;
  1042 
  1043     if(get_revoked(session, msg->from->fpr,
  1044                    &revoked_fpr, &revocation_date) == PEP_STATUS_OK &&
  1045        revoked_fpr != NULL)
  1046     {
  1047         time_t now = time(NULL);
  1048 
  1049         if (now < (time_t)revocation_date + ONE_WEEK)
  1050         {
  1051             _attach_key(session, revoked_fpr, msg);
  1052         }
  1053     }
  1054     free(revoked_fpr);
  1055 }
  1056 
  1057 PEP_cryptotech determine_encryption_format(message *msg)
  1058 {
  1059     assert(msg);
  1060 
  1061     if (is_PGP_message_text(msg->longmsg)) {
  1062         msg->enc_format = PEP_enc_pieces;
  1063         return PEP_crypt_OpenPGP;
  1064     }
  1065     else if (msg->attachments && msg->attachments->next &&
  1066             is_mime_type(msg->attachments, "application/pgp-encrypted") &&
  1067             is_PGP_message_text(msg->attachments->next->value)
  1068         ) {
  1069         msg->enc_format = PEP_enc_PGP_MIME;
  1070         return PEP_crypt_OpenPGP;
  1071     }
  1072     else if (msg->attachments && msg->attachments->next &&
  1073             is_mime_type(msg->attachments->next, "application/pgp-encrypted") &&
  1074             is_PGP_message_text(msg->attachments->value)
  1075         ) {
  1076         msg->enc_format = PEP_enc_PGP_MIME_Outlook1;
  1077         return PEP_crypt_OpenPGP;
  1078     }
  1079     else {
  1080         msg->enc_format = PEP_enc_none;
  1081         return PEP_crypt_none;
  1082     }
  1083 }
  1084 
  1085 DYNAMIC_API PEP_STATUS encrypt_message(
  1086         PEP_SESSION session,
  1087         message *src,
  1088         stringlist_t * extra,
  1089         message **dst,
  1090         PEP_enc_format enc_format,
  1091         PEP_encrypt_flags_t flags
  1092     )
  1093 {
  1094     PEP_STATUS status = PEP_STATUS_OK;
  1095     message * msg = NULL;
  1096     stringlist_t * keys = NULL;
  1097 
  1098     assert(session);
  1099     assert(src);
  1100     assert(dst);
  1101     assert(enc_format != PEP_enc_none);
  1102 
  1103     if (!(session && src && dst && enc_format != PEP_enc_none))
  1104         return PEP_ILLEGAL_VALUE;
  1105 
  1106     if (src->dir == PEP_dir_incoming)
  1107         return PEP_ILLEGAL_VALUE;
  1108 
  1109     determine_encryption_format(src);
  1110     if (src->enc_format != PEP_enc_none)
  1111         return PEP_ILLEGAL_VALUE;
  1112 
  1113     *dst = NULL;
  1114 
  1115     status = myself(session, src->from);
  1116     if (status != PEP_STATUS_OK)
  1117         goto pep_error;
  1118 
  1119     keys = new_stringlist(src->from->fpr);
  1120     if (keys == NULL)
  1121         goto enomem;
  1122 
  1123     stringlist_t *_k = keys;
  1124 
  1125     if (extra) {
  1126         _k = stringlist_append(_k, extra);
  1127         if (_k == NULL)
  1128             goto enomem;
  1129     }
  1130 
  1131     bool dest_keys_found = true;
  1132     PEP_comm_type max_comm_type = PEP_ct_pEp;
  1133 
  1134     identity_list * _il;
  1135 
  1136     if ((_il = src->bcc) && _il->ident)
  1137     {
  1138         // BCC limited support:
  1139         //     - App splits mails with BCC in multiple mails.
  1140         //     - Each email is encrypted separately
  1141 
  1142         if(_il->next || (src->to && src->to->ident) || (src->cc && src->cc->ident))
  1143         {
  1144             // Only one Bcc with no other recipient allowed for now
  1145             return PEP_ILLEGAL_VALUE;
  1146         }
  1147 
  1148         PEP_STATUS _status = update_identity(session, _il->ident);
  1149         if (_status != PEP_STATUS_OK) {
  1150             status = _status;
  1151             goto pep_error;
  1152         }
  1153 
  1154         if (_il->ident->fpr && _il->ident->fpr[0]) {
  1155             _k = stringlist_add(_k, _il->ident->fpr);
  1156             if (_k == NULL)
  1157                 goto enomem;
  1158             max_comm_type = _get_comm_type(session, max_comm_type,
  1159                                            _il->ident);
  1160         }
  1161         else {
  1162             dest_keys_found = false;
  1163             status = PEP_KEY_NOT_FOUND;
  1164         }
  1165     }
  1166     else
  1167     {
  1168         for (_il = src->to; _il && _il->ident; _il = _il->next) {
  1169             PEP_STATUS _status = update_identity(session, _il->ident);
  1170             if (_status != PEP_STATUS_OK) {
  1171                 status = _status;
  1172                 goto pep_error;
  1173             }
  1174 
  1175             if (_il->ident->fpr && _il->ident->fpr[0]) {
  1176                 _k = stringlist_add(_k, _il->ident->fpr);
  1177                 if (_k == NULL)
  1178                     goto enomem;
  1179                 max_comm_type = _get_comm_type(session, max_comm_type,
  1180                                                _il->ident);
  1181             }
  1182             else {
  1183                 dest_keys_found = false;
  1184                 status = PEP_KEY_NOT_FOUND;
  1185             }
  1186         }
  1187 
  1188         for (_il = src->cc; _il && _il->ident; _il = _il->next) {
  1189             PEP_STATUS _status = update_identity(session, _il->ident);
  1190             if (_status != PEP_STATUS_OK)
  1191             {
  1192                 status = _status;
  1193                 goto pep_error;
  1194             }
  1195 
  1196             if (_il->ident->fpr && _il->ident->fpr[0]) {
  1197                 _k = stringlist_add(_k, _il->ident->fpr);
  1198                 if (_k == NULL)
  1199                     goto enomem;
  1200                 max_comm_type = _get_comm_type(session, max_comm_type,
  1201                                                _il->ident);
  1202             }
  1203             else {
  1204                 dest_keys_found = false;
  1205                 status = PEP_KEY_NOT_FOUND;
  1206             }
  1207         }
  1208     }
  1209 
  1210     if (!dest_keys_found ||
  1211         stringlist_length(keys)  == 0 ||
  1212         _rating(max_comm_type,
  1213                 PEP_rating_undefined) < PEP_rating_reliable)
  1214     {
  1215         free_stringlist(keys);
  1216         if (!session->passive_mode && !(flags & PEP_encrypt_flag_force_no_attached_key))
  1217             attach_own_key(session, src);
  1218         return PEP_UNENCRYPTED;
  1219     }
  1220     else {
  1221         msg = clone_to_empty_message(src);
  1222         if (msg == NULL)
  1223             goto enomem;
  1224 
  1225         if (!(flags & PEP_encrypt_flag_force_no_attached_key))
  1226             attach_own_key(session, src);
  1227 
  1228         switch (enc_format) {
  1229         case PEP_enc_PGP_MIME:
  1230         case PEP_enc_PEP: // BUG: should be implemented extra
  1231             status = encrypt_PGP_MIME(session, src, keys, msg, flags);
  1232             break;
  1233 
  1234         case PEP_enc_pieces:
  1235             status = encrypt_PGP_in_pieces(session, src, keys, msg, flags);
  1236             break;
  1237 
  1238         /* case PEP_enc_PEP:
  1239             // TODO: implement
  1240             NOT_IMPLEMENTED */
  1241 
  1242         default:
  1243             assert(0);
  1244             status = PEP_ILLEGAL_VALUE;
  1245             goto pep_error;
  1246         }
  1247 
  1248         if (status == PEP_OUT_OF_MEMORY)
  1249             goto enomem;
  1250 
  1251         if (status != PEP_STATUS_OK)
  1252             goto pep_error;
  1253     }
  1254 
  1255     free_stringlist(keys);
  1256 
  1257     if (msg && msg->shortmsg == NULL) {
  1258         msg->shortmsg = strdup("pEp");
  1259         assert(msg->shortmsg);
  1260         if (msg->shortmsg == NULL)
  1261             goto enomem;
  1262     }
  1263 
  1264     if (msg) {
  1265         decorate_message(msg, PEP_rating_undefined, NULL);
  1266         if (src->id) {
  1267             msg->id = strdup(src->id);
  1268             assert(msg->id);
  1269             if (msg->id == NULL)
  1270                 goto enomem;
  1271         }
  1272     }
  1273 
  1274     *dst = msg;
  1275     return status;
  1276 
  1277 enomem:
  1278     status = PEP_OUT_OF_MEMORY;
  1279 
  1280 pep_error:
  1281     free_stringlist(keys);
  1282     free_message(msg);
  1283 
  1284     return status;
  1285 }
  1286 
  1287 DYNAMIC_API PEP_STATUS encrypt_message_for_self(
  1288         PEP_SESSION session,
  1289         pEp_identity* target_id,
  1290         message *src,
  1291         message **dst,
  1292         PEP_enc_format enc_format,
  1293         PEP_encrypt_flags_t flags
  1294     )
  1295 {
  1296     PEP_STATUS status = PEP_STATUS_OK;
  1297     message * msg = NULL;
  1298     stringlist_t * keys = NULL;
  1299 
  1300     assert(session);
  1301     assert(src);
  1302     assert(dst);
  1303     assert(enc_format != PEP_enc_none);
  1304 
  1305     if (!(session && src && dst && enc_format != PEP_enc_none))
  1306         return PEP_ILLEGAL_VALUE;
  1307 
  1308     if (src->dir == PEP_dir_incoming)
  1309         return PEP_ILLEGAL_VALUE;
  1310 
  1311     determine_encryption_format(src);
  1312     if (src->enc_format != PEP_enc_none)
  1313         return PEP_ILLEGAL_VALUE;
  1314 
  1315     status = myself(session, target_id);
  1316     if (status != PEP_STATUS_OK)
  1317         goto pep_error;
  1318 
  1319     *dst = NULL;
  1320 
  1321 
  1322     PEP_STATUS _status = update_identity(session, target_id);
  1323     if (_status != PEP_STATUS_OK) {
  1324         status = _status;
  1325         goto pep_error;
  1326     }
  1327 
  1328     char* target_fpr = target_id->fpr;
  1329     if (!target_fpr)
  1330         return PEP_KEY_NOT_FOUND; // FIXME: Error condition
  1331  
  1332     keys = new_stringlist(target_fpr);
  1333     
  1334     /* KG: did we ever do this??? */
  1335     if (!(flags & PEP_encrypt_flag_force_no_attached_key))
  1336         _attach_key(session, target_fpr, src);
  1337 
  1338     msg = clone_to_empty_message(src);
  1339     if (msg == NULL)
  1340         goto enomem;
  1341 
  1342     switch (enc_format) {
  1343         case PEP_enc_PGP_MIME:
  1344         case PEP_enc_PEP: // BUG: should be implemented extra
  1345             status = encrypt_PGP_MIME(session, src, keys, msg, flags);
  1346             break;
  1347 
  1348         case PEP_enc_pieces:
  1349             status = encrypt_PGP_in_pieces(session, src, keys, msg, flags);
  1350             break;
  1351 
  1352         /* case PEP_enc_PEP:
  1353             NOT_IMPLEMENTED */
  1354             // TODO: implement
  1355 
  1356         default:
  1357             assert(0);
  1358             status = PEP_ILLEGAL_VALUE;
  1359             goto pep_error;
  1360     }
  1361 
  1362     if (status == PEP_OUT_OF_MEMORY)
  1363         goto enomem;
  1364 
  1365     if (status != PEP_STATUS_OK)
  1366         goto pep_error;
  1367 
  1368      if (msg && msg->shortmsg == NULL) {
  1369          msg->shortmsg = strdup("pEp");
  1370          assert(msg->shortmsg);
  1371          if (msg->shortmsg == NULL)
  1372              goto enomem;
  1373      }
  1374 
  1375      if (msg) {
  1376          if (src->id) {
  1377              msg->id = strdup(src->id);
  1378              assert(msg->id);
  1379              if (msg->id == NULL)
  1380                  goto enomem;
  1381          }
  1382      }
  1383 
  1384     *dst = msg;
  1385     return status;
  1386 
  1387 enomem:
  1388     status = PEP_OUT_OF_MEMORY;
  1389 
  1390 pep_error:
  1391     free_stringlist(keys);
  1392     free_message(msg);
  1393 
  1394     return status;
  1395 }
  1396 
  1397 static bool is_a_pEpmessage(const message *msg)
  1398 {
  1399     for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
  1400         if (strcasecmp(i->value->key, "X-pEp-Version") == 0)
  1401             return true;
  1402     }
  1403     return false;
  1404 }
  1405 
  1406 // update comm_type to pEp_ct_pEp if needed
  1407 
  1408 static PEP_STATUS _update_identity_for_incoming_message(
  1409         PEP_SESSION session,
  1410         const message *src
  1411     )
  1412 {
  1413     PEP_STATUS status;
  1414     if (src->from && src->from->address) {
  1415         status = update_identity(session, src->from);
  1416         if (status == PEP_STATUS_OK
  1417                 && is_a_pEpmessage(src)
  1418                 && src->from->comm_type >= PEP_ct_OpenPGP_unconfirmed
  1419                 && src->from->comm_type != PEP_ct_pEp_unconfirmed
  1420                 && src->from->comm_type != PEP_ct_pEp)
  1421         {
  1422             src->from->comm_type |= PEP_ct_pEp_unconfirmed;
  1423             status = update_identity(session, src->from);
  1424         }
  1425         return status;
  1426     }
  1427     return PEP_ILLEGAL_VALUE;
  1428 }
  1429 
  1430 
  1431 PEP_STATUS _get_detached_signature(message* msg, bloblist_t** signature_blob) {
  1432     bloblist_t* attach_curr = msg->attachments;
  1433 
  1434     *signature_blob = NULL;
  1435 
  1436     while (attach_curr) {
  1437         if (strcasecmp(attach_curr->mime_type, "application/pgp-signature") == 0) {
  1438             *signature_blob = attach_curr;
  1439             break;
  1440         }
  1441         attach_curr = attach_curr->next;
  1442     }
  1443 
  1444     return PEP_STATUS_OK;
  1445 }
  1446 
  1447 PEP_STATUS _get_signed_text(const char* ptext, const size_t psize,
  1448                             char** stext, size_t* ssize) {
  1449 
  1450     char* signed_boundary = NULL;
  1451     char* signpost = strstr(ptext, "Content-Type: multipart/signed");
  1452 
  1453     *ssize = 0;
  1454     *stext = NULL;
  1455 
  1456     if (!signpost)
  1457         return PEP_UNKNOWN_ERROR;
  1458 
  1459     char* curr_line = signpost;
  1460 //    const char* end_text = ptext + psize;
  1461     const char* boundary_key = "boundary=\"";
  1462     const size_t BOUNDARY_KEY_SIZE = 10;
  1463 
  1464     char* start_boundary = strstr(curr_line, boundary_key);
  1465     if (!start_boundary)
  1466         return PEP_UNKNOWN_ERROR;
  1467 
  1468     start_boundary += BOUNDARY_KEY_SIZE;
  1469 
  1470     char* end_boundary = strstr(start_boundary, "\"");
  1471 
  1472     if (!end_boundary)
  1473         return PEP_UNKNOWN_ERROR;
  1474 
  1475     size_t boundary_strlen = (end_boundary - start_boundary) + 2;
  1476 
  1477     signed_boundary = calloc(1, boundary_strlen + 1);
  1478     strlcpy(signed_boundary, "--", boundary_strlen + 1);
  1479     strlcat(signed_boundary, start_boundary, boundary_strlen + 1);
  1480 
  1481     start_boundary = strstr(end_boundary, signed_boundary);
  1482 
  1483     if (!start_boundary)
  1484         return PEP_UNKNOWN_ERROR;
  1485 
  1486     start_boundary += boundary_strlen;
  1487 
  1488     while (*start_boundary == '\n')
  1489         start_boundary++;
  1490 
  1491     end_boundary = strstr(start_boundary + boundary_strlen, signed_boundary);
  1492 
  1493     if (!end_boundary)
  1494         return PEP_UNKNOWN_ERROR;
  1495 
  1496     end_boundary--; // See RFC3156 section 5...
  1497 
  1498     *ssize = end_boundary - start_boundary;
  1499     *stext = start_boundary;
  1500     free(signed_boundary);
  1501 
  1502     return PEP_STATUS_OK;
  1503 }
  1504 
  1505 PEP_STATUS combine_keylists(PEP_SESSION session, stringlist_t** verify_in, 
  1506                             stringlist_t** keylist_in_out, 
  1507                             pEp_identity* from) {
  1508     
  1509     if (!verify_in || !(*verify_in)) // this isn't really a problem.
  1510         return PEP_STATUS_OK;
  1511     
  1512     stringlist_t* orig_verify = *verify_in;
  1513     
  1514     stringlist_t* verify_curr = NULL;
  1515     stringlist_t* from_keys = NULL;
  1516     
  1517     /* FIXME: what to do if head needs to be null */
  1518     PEP_STATUS status = find_keys(session, from->address, &from_keys);
  1519     
  1520     stringlist_t* from_fpr_node = NULL;
  1521     stringlist_t* from_curr;
  1522     
  1523     for (from_curr = from_keys; from_curr; from_curr = from_curr->next) {
  1524         for (verify_curr = orig_verify; verify_curr; verify_curr = verify_curr->next) {
  1525             if (from_curr->value && verify_curr->value &&
  1526                 _same_fpr(from_curr->value, strlen(from_curr->value),
  1527                           verify_curr->value, strlen(verify_curr->value))) {
  1528                 from_fpr_node = from_curr;
  1529                 break;
  1530             }
  1531         }
  1532     }
  1533     
  1534     if (!from_fpr_node) {
  1535         status = PEP_KEY_NOT_FOUND;
  1536         goto free;
  1537     }
  1538 
  1539     verify_curr = orig_verify;
  1540     
  1541     /* put "from" signer at the beginning of the list */
  1542     if (!_same_fpr(orig_verify->value, strlen(orig_verify->value),
  1543                    from_fpr_node->value, strlen(from_fpr_node->value))) {
  1544         orig_verify = stringlist_delete(orig_verify, from_fpr_node->value);
  1545         verify_curr = new_stringlist(from_fpr_node->value);
  1546         verify_curr->next = orig_verify;
  1547     }
  1548 
  1549     /* append keylist to signers */
  1550     if (keylist_in_out && *keylist_in_out && (*keylist_in_out)->value) {
  1551         stringlist_t** tail_pp = &verify_curr->next;
  1552         
  1553         while (*tail_pp) {
  1554             tail_pp = &((*tail_pp)->next);
  1555         }
  1556         stringlist_t* second_list = *keylist_in_out;
  1557         if (second_list) {
  1558             char* listhead_val = second_list->value;
  1559             if (!listhead_val || listhead_val[0] == '\0') {
  1560                 /* remove head, basically. This can happen when,
  1561                    for example, the signature is detached and
  1562                    verification is not seen directly after
  1563                    decryption, so no signer is presumed in
  1564                    the first construction of the keylist */
  1565                 *keylist_in_out = (*keylist_in_out)->next;
  1566                 second_list->next = NULL;
  1567                 free_stringlist(second_list);
  1568             }
  1569         }
  1570         *tail_pp = *keylist_in_out;
  1571     }
  1572     
  1573     *keylist_in_out = verify_curr;
  1574     
  1575     status = PEP_STATUS_OK;
  1576     
  1577 free:
  1578     free_stringlist(from_keys);
  1579     return status;
  1580 }
  1581 
  1582 
  1583 DYNAMIC_API PEP_STATUS _decrypt_message(
  1584         PEP_SESSION session,
  1585         message *src,
  1586         message **dst,
  1587         stringlist_t **keylist,
  1588         PEP_rating *rating,
  1589         PEP_decrypt_flags_t *flags,
  1590         identity_list **private_il
  1591     )
  1592 {
  1593     PEP_STATUS status = PEP_STATUS_OK;
  1594     PEP_STATUS decrypt_status = PEP_CANNOT_DECRYPT_UNKNOWN;
  1595     message *msg = NULL;
  1596     char *ctext;
  1597     size_t csize;
  1598     char *ptext = NULL;
  1599     size_t psize;
  1600     stringlist_t *_keylist = NULL;
  1601 
  1602     assert(session);
  1603     assert(src);
  1604     assert(dst);
  1605     assert(keylist);
  1606     assert(rating);
  1607     assert(flags);
  1608 
  1609     if (!(session && src && dst && keylist && rating && flags))
  1610         return PEP_ILLEGAL_VALUE;
  1611 
  1612     *flags = 0;
  1613 
  1614     // Private key in unencrypted mail are ignored -> NULL
  1615     bool imported_keys = import_attached_keys(session, src, NULL);
  1616 
  1617     // Update src->from in case we just imported a key
  1618     // we would need to check signature
  1619     status = _update_identity_for_incoming_message(session, src);
  1620     if(status != PEP_STATUS_OK)
  1621         return status;
  1622 
  1623     // Get detached signature, if any
  1624     bloblist_t* detached_sig = NULL;
  1625     char* dsig_text = NULL;
  1626     size_t dsig_size = 0;
  1627     status = _get_detached_signature(src, &detached_sig);
  1628     if (detached_sig) {
  1629         dsig_text = detached_sig->value;
  1630         dsig_size = detached_sig->size;
  1631     }
  1632 
  1633     PEP_cryptotech crypto = determine_encryption_format(src);
  1634 
  1635     *dst = NULL;
  1636     *keylist = NULL;
  1637     *rating = PEP_rating_undefined;
  1638 
  1639     switch (src->enc_format) {
  1640         case PEP_enc_none:
  1641             *rating = PEP_rating_unencrypted;
  1642             if (imported_keys)
  1643                 remove_attached_keys(src);
  1644             if(session->sync_session->inject_sync_msg){
  1645                 status = receive_DeviceState_msg(session, src, *rating, *keylist);
  1646                 if (status == PEP_MESSAGE_CONSUME ||
  1647                     status == PEP_MESSAGE_IGNORE) {
  1648                     free_message(msg);
  1649                     msg = NULL;
  1650                     *flags |= (status == PEP_MESSAGE_IGNORE) ?
  1651                                 PEP_decrypt_flag_ignore :
  1652                                 PEP_decrypt_flag_consume;
  1653                 }
  1654                 else if (status != PEP_STATUS_OK) {
  1655                     return status;
  1656                 }
  1657             }
  1658             
  1659             char* slong = src->longmsg;
  1660             char* sform = src->longmsg_formatted;
  1661             bloblist_t* satt = src->attachments;
  1662             
  1663             if ((!slong || slong[0] == '\0')
  1664                  && (!sform || sform[0] == '\0')) {
  1665                 if (satt) {
  1666                     const char* inner_mime_type = satt->mime_type;
  1667                     if (strcasecmp(inner_mime_type, "text/plain") == 0) {
  1668                         free(slong); /* in case of "" */
  1669                         src->longmsg = strndup(satt->value, satt->size); // N.B.: longmsg might be shorter, if attachment contains NUL bytes which are not allowed in text/plain!
  1670                         
  1671                         bloblist_t* next_node = satt->next;
  1672                         if (next_node) {
  1673                             inner_mime_type = next_node->mime_type;
  1674                             if (strcasecmp(inner_mime_type, "text/html") == 0) {
  1675                                 free(sform);
  1676                                 src->longmsg_formatted = strndup(next_node->value, next_node->size);  // N.B.: longmsg might be shorter, if attachment contains NUL bytes which are not allowed in text/plain!
  1677                             }
  1678                         }
  1679                     }
  1680                     else if (strcasecmp(inner_mime_type, "text/html") == 0) {
  1681                         free(sform);
  1682                         src->longmsg_formatted = strndup(satt->value, satt->size);  // N.B.: longmsg might be shorter, if attachment contains NUL bytes which are not allowed in text/plain!
  1683                     }
  1684                 }
  1685             }
  1686             
  1687             return PEP_UNENCRYPTED;
  1688 
  1689         case PEP_enc_PGP_MIME:
  1690             ctext = src->attachments->next->value;
  1691             csize = src->attachments->next->size;
  1692             break;
  1693 
  1694         case PEP_enc_PGP_MIME_Outlook1:
  1695             ctext = src->attachments->value;
  1696             csize = src->attachments->size;
  1697             break;
  1698 
  1699         case PEP_enc_pieces:
  1700             ctext = src->longmsg;
  1701             csize = strlen(ctext);
  1702             break;
  1703 
  1704         default:
  1705             NOT_IMPLEMENTED
  1706     }
  1707     status = cryptotech[crypto].decrypt_and_verify(session, ctext,
  1708                                                    csize, dsig_text, dsig_size,
  1709                                                    &ptext, &psize, &_keylist);
  1710     if (status > PEP_CANNOT_DECRYPT_UNKNOWN){
  1711         goto pep_error;
  1712     }
  1713 
  1714     decrypt_status = status;
  1715 
  1716     if (status == PEP_DECRYPT_NO_KEY){
  1717         PEP_STATUS sync_status = inject_DeviceState_event(session, CannotDecrypt, NULL, NULL);
  1718         if (sync_status == PEP_OUT_OF_MEMORY){
  1719             status = PEP_OUT_OF_MEMORY;
  1720             goto pep_error;
  1721         }
  1722     }
  1723 
  1724     bool imported_private_key_address = false;
  1725 
  1726     if (ptext) {
  1727         switch (src->enc_format) {
  1728             case PEP_enc_PGP_MIME:
  1729             case PEP_enc_PGP_MIME_Outlook1:
  1730                 status = mime_decode_message(ptext, psize, &msg);
  1731                 if (status != PEP_STATUS_OK)
  1732                     goto pep_error;
  1733                 
  1734                 char* mlong = msg->longmsg;
  1735                 char* mform = msg->longmsg_formatted;
  1736                 bloblist_t* matt = msg->attachments;
  1737                 
  1738                 if ((!mlong || mlong[0] == '\0')
  1739                      && (!mform || mform[0] == '\0')) {
  1740                     if (matt) {
  1741                         const char* inner_mime_type = matt->mime_type;
  1742                         if (strcasecmp(inner_mime_type, "text/plain") == 0) {
  1743                             free(mlong); /* in case of "" */
  1744                             msg->longmsg = strndup(matt->value, matt->size);
  1745                             
  1746                             bloblist_t* next_node = matt->next;
  1747                             if (next_node) {
  1748                                 inner_mime_type = next_node->mime_type;
  1749                                 if (strcasecmp(inner_mime_type, "text/html") == 0) {
  1750                                     free(mform);
  1751                                     msg->longmsg_formatted = strndup(next_node->value, next_node->size);
  1752                                 }
  1753                             }
  1754                         }
  1755                         else if (strcasecmp(inner_mime_type, "text/html") == 0) {
  1756                             free(mform);
  1757                             msg->longmsg_formatted = strndup(matt->value, matt->size);
  1758                         }
  1759                     }
  1760                     if (msg->shortmsg) {
  1761                         free(src->shortmsg);
  1762                         src->shortmsg = strdup(msg->shortmsg);
  1763                     }
  1764                 }
  1765 
  1766                 if (decrypt_status != PEP_DECRYPTED_AND_VERIFIED) {
  1767                     status = _get_detached_signature(msg, &detached_sig);
  1768                     if (decrypt_status == PEP_DECRYPTED && detached_sig) {
  1769                         dsig_text = detached_sig->value;
  1770                         dsig_size = detached_sig->size;
  1771                         size_t ssize = 0;
  1772                         char* stext = NULL;
  1773 
  1774                         status = _get_signed_text(ptext, psize, &stext, &ssize);
  1775                         stringlist_t *_verify_keylist = NULL;
  1776 
  1777                         if (ssize > 0 && stext) {
  1778                             status = cryptotech[crypto].verify_text(session, stext,
  1779                                                                     ssize, dsig_text, dsig_size,
  1780                                                                     &_verify_keylist);
  1781 
  1782                             if (status == PEP_VERIFIED || status == PEP_VERIFIED_AND_TRUSTED)
  1783                                 decrypt_status = PEP_DECRYPTED_AND_VERIFIED;
  1784                             
  1785                                 status = combine_keylists(session, &_verify_keylist, &_keylist, src->from);
  1786                         }
  1787                     }
  1788                 }
  1789                 break;
  1790 
  1791             case PEP_enc_pieces:
  1792                 msg = clone_to_empty_message(src);
  1793                 if (msg == NULL)
  1794                     goto enomem;
  1795 
  1796                 msg->longmsg = ptext;
  1797                 ptext = NULL;
  1798 
  1799                 bloblist_t *_m = msg->attachments;
  1800                 if (_m == NULL && src->attachments && src->attachments->value) {
  1801                     msg->attachments = new_bloblist(NULL, 0, NULL, NULL);
  1802                     _m = msg->attachments;
  1803                 }
  1804 
  1805                 bloblist_t *_s;
  1806                 for (_s = src->attachments; _s; _s = _s->next) {
  1807                     if (_s->value == NULL && _s->size == 0){
  1808                         _m = bloblist_add(_m, NULL, 0, _s->mime_type, _s->filename);
  1809                         if (_m == NULL)
  1810                             goto enomem;
  1811 
  1812                     }
  1813                     else if (is_encrypted_attachment(_s)) {
  1814                         stringlist_t *_keylist = NULL;
  1815                         char *attctext  = _s->value;
  1816                         size_t attcsize = _s->size;
  1817 
  1818                         free(ptext);
  1819                         ptext = NULL;
  1820 
  1821                         // FIXME: What about attachments with separate sigs???
  1822                         status = decrypt_and_verify(session, attctext, attcsize,
  1823                                                     NULL, 0,
  1824                                                     &ptext, &psize, &_keylist);
  1825                         free_stringlist(_keylist); // FIXME: Why do we do this?
  1826 
  1827                         if (ptext) {
  1828                             if (is_encrypted_html_attachment(_s)) {
  1829                                 msg->longmsg_formatted = ptext;
  1830                                 ptext = NULL;
  1831                             }
  1832                             else {
  1833                                 static const char * const mime_type = "application/octet-stream";
  1834                                 char * const filename =
  1835                                     without_double_ending(_s->filename);
  1836                                 if (filename == NULL)
  1837                                     goto enomem;
  1838 
  1839                                 _m = bloblist_add(_m, ptext, psize, mime_type,
  1840                                     filename);
  1841                                 free(filename);
  1842                                 if (_m == NULL)
  1843                                     goto enomem;
  1844 
  1845                                 ptext = NULL;
  1846 
  1847                                 if (msg->attachments == NULL)
  1848                                     msg->attachments = _m;
  1849                             }
  1850                         }
  1851                         else {
  1852                             char *copy = malloc(_s->size);
  1853                             assert(copy);
  1854                             if (copy == NULL)
  1855                                 goto enomem;
  1856                             memcpy(copy, _s->value, _s->size);
  1857                             _m = bloblist_add(_m, copy, _s->size, _s->mime_type, _s->filename);
  1858                             if (_m == NULL)
  1859                                 goto enomem;
  1860                         }
  1861                     }
  1862                     else {
  1863                         char *copy = malloc(_s->size);
  1864                         assert(copy);
  1865                         if (copy == NULL)
  1866                             goto enomem;
  1867                         memcpy(copy, _s->value, _s->size);
  1868                         _m = bloblist_add(_m, copy, _s->size, _s->mime_type, _s->filename);
  1869                         if (_m == NULL)
  1870                             goto enomem;
  1871                     }
  1872                 }
  1873 
  1874                 break;
  1875 
  1876             default:
  1877                 // BUG: must implement more
  1878                 NOT_IMPLEMENTED
  1879         }
  1880 
  1881         switch (src->enc_format) {
  1882             case PEP_enc_PGP_MIME:
  1883             case PEP_enc_pieces:
  1884             case PEP_enc_PGP_MIME_Outlook1:
  1885                 status = copy_fields(msg, src);
  1886                 if (status != PEP_STATUS_OK)
  1887                     goto pep_error;
  1888 
  1889                 if (src->shortmsg == NULL || strcmp(src->shortmsg, "pEp") == 0)
  1890                 {
  1891                     char * shortmsg;
  1892                     char * longmsg;
  1893 
  1894                     int r = separate_short_and_long(msg->longmsg, &shortmsg,
  1895                             &longmsg);
  1896                     if (r == -1)
  1897                         goto enomem;
  1898 
  1899                     free(msg->shortmsg);
  1900                     free(msg->longmsg);
  1901 
  1902                     msg->shortmsg = shortmsg;
  1903                     msg->longmsg = longmsg;
  1904                 }
  1905                 else {
  1906                     msg->shortmsg = strdup(src->shortmsg);
  1907                     assert(msg->shortmsg);
  1908                     if (msg->shortmsg == NULL)
  1909                         goto enomem;
  1910                 }
  1911                 break;
  1912             default:
  1913                     // BUG: must implement more
  1914                     NOT_IMPLEMENTED
  1915         }
  1916 
  1917         // check for private key in decrypted message attachement while inporting
  1918         identity_list *_private_il = NULL;
  1919         imported_keys = import_attached_keys(session, msg, &_private_il);
  1920         if (_private_il &&
  1921             identity_list_length(_private_il) == 1 &&
  1922             _private_il->ident->address)
  1923         {
  1924             imported_private_key_address = true;
  1925         }
  1926 
  1927         if(private_il && imported_private_key_address){
  1928             *private_il = _private_il;
  1929         }else{
  1930             free_identity_list(_private_il);
  1931         }
  1932 
  1933         if(decrypt_status == PEP_DECRYPTED){
  1934 
  1935             // TODO optimize if import_attached_keys didn't import any key
  1936 
  1937             // In case message did decrypt, but no valid signature could be found
  1938             // then retry decrypt+verify after importing key.
  1939 
  1940             // Update msg->from in case we just imported a key
  1941             // we would need to check signature
  1942 
  1943             status = _update_identity_for_incoming_message(session, src);
  1944             if(status != PEP_STATUS_OK)
  1945                 goto pep_error;
  1946 
  1947             char *re_ptext = NULL;
  1948             size_t re_psize;
  1949 
  1950             free_stringlist(_keylist);
  1951             _keylist = NULL;
  1952 
  1953             status = cryptotech[crypto].decrypt_and_verify(session, ctext,
  1954                 csize, dsig_text, dsig_size, &re_ptext, &re_psize, &_keylist);
  1955 
  1956             free(re_ptext);
  1957 
  1958             if (status > PEP_CANNOT_DECRYPT_UNKNOWN)
  1959                 goto pep_error;
  1960 
  1961             decrypt_status = status;
  1962         }
  1963 
  1964         *rating = decrypt_rating(decrypt_status);
  1965 
  1966         if (*rating > PEP_rating_mistrust) {
  1967             PEP_rating kl_rating = PEP_rating_undefined;
  1968 
  1969             if (_keylist)
  1970                 kl_rating = keylist_rating(session, _keylist);
  1971 
  1972             if (kl_rating <= PEP_rating_mistrust) {
  1973                 *rating = kl_rating;
  1974             }
  1975             else if (*rating >= PEP_rating_reliable &&
  1976                      kl_rating < PEP_rating_reliable) {
  1977                 *rating = PEP_rating_unreliable;
  1978             }
  1979             else if (*rating >= PEP_rating_reliable &&
  1980                      kl_rating >= PEP_rating_reliable) {
  1981                 if (!(src->from && src->from->user_id && src->from->user_id[0])) {
  1982                     *rating = PEP_rating_unreliable;
  1983                 }
  1984                 else {
  1985                     char *fpr = _keylist->value;
  1986                     pEp_identity *_from = new_identity(src->from->address, fpr,
  1987                                                        src->from->user_id, src->from->username);
  1988                     if (_from == NULL)
  1989                         goto enomem;
  1990                     status = get_trust(session, _from);
  1991                     if (_from->comm_type != PEP_ct_unknown) {
  1992                         *rating = worst_rating(_rating(_from->comm_type, PEP_rating_undefined),
  1993                                   kl_rating);
  1994                     }
  1995                     free_identity(_from);
  1996                     if (status == PEP_CANNOT_FIND_IDENTITY)
  1997                        status = PEP_STATUS_OK;
  1998                     if (status != PEP_STATUS_OK)
  1999                         goto pep_error;
  2000                 }
  2001             }
  2002         }
  2003     }
  2004     else
  2005     {
  2006         *rating = decrypt_rating(decrypt_status);
  2007         goto pep_error;
  2008     }
  2009 
  2010     // Case of own key imported from own trusted message
  2011     if (// Message have been reliably decrypted
  2012         msg &&
  2013         *rating >= PEP_rating_trusted &&
  2014         imported_private_key_address &&
  2015         // to is [own]
  2016         msg->to->ident->user_id &&
  2017         strcmp(msg->to->ident->user_id, PEP_OWN_USERID) == 0
  2018         )
  2019     {
  2020         *flags |= PEP_decrypt_flag_own_private_key;
  2021     }
  2022 
  2023     if (msg) {
  2024         decorate_message(msg, *rating, _keylist);
  2025         if (imported_keys)
  2026             remove_attached_keys(msg);
  2027         if (*rating >= PEP_rating_reliable &&
  2028             session->sync_session->inject_sync_msg) {
  2029             status = receive_DeviceState_msg(session, msg, *rating, _keylist);
  2030             if (status == PEP_MESSAGE_CONSUME ||
  2031                 status == PEP_MESSAGE_IGNORE) {
  2032                 free_message(msg);
  2033                 msg = NULL;
  2034                 *flags |= (status == PEP_MESSAGE_IGNORE) ?
  2035                             PEP_decrypt_flag_ignore :
  2036                             PEP_decrypt_flag_consume;
  2037 
  2038                 status = decrypt_status;
  2039             }
  2040             else if (status != PEP_STATUS_OK){
  2041                 goto pep_error;
  2042             }
  2043         }
  2044     }
  2045     if (msg) {
  2046         if (src->id) {
  2047             msg->id = strdup(src->id);
  2048             assert(msg->id);
  2049             if (msg->id == NULL)
  2050                 goto enomem;
  2051         }
  2052     }
  2053 
  2054     *dst = msg;
  2055     *keylist = _keylist;
  2056 
  2057     return status;
  2058 
  2059 enomem:
  2060     status = PEP_OUT_OF_MEMORY;
  2061 
  2062 pep_error:
  2063     free(ptext);
  2064     free_message(msg);
  2065     free_stringlist(_keylist);
  2066 
  2067     return status;
  2068 }
  2069 
  2070 DYNAMIC_API PEP_STATUS decrypt_message(
  2071         PEP_SESSION session,
  2072         message *src,
  2073         message **dst,
  2074         stringlist_t **keylist,
  2075         PEP_rating *rating,
  2076         PEP_decrypt_flags_t *flags
  2077     )
  2078 {
  2079     return _decrypt_message( session, src, dst, keylist, rating, flags, NULL );
  2080 }
  2081 
  2082 DYNAMIC_API PEP_STATUS own_message_private_key_details(
  2083         PEP_SESSION session,
  2084         message *msg,
  2085         pEp_identity **ident
  2086     )
  2087 {
  2088     assert(session);
  2089     assert(msg);
  2090     assert(ident);
  2091 
  2092     if (!(session && msg && ident))
  2093         return PEP_ILLEGAL_VALUE;
  2094 
  2095     message *dst = NULL;
  2096     stringlist_t *keylist = NULL;
  2097     PEP_rating rating;
  2098     PEP_decrypt_flags_t flags;
  2099 
  2100     *ident = NULL;
  2101 
  2102     identity_list *private_il = NULL;
  2103     PEP_STATUS status = _decrypt_message(session, msg,  &dst, &keylist, &rating, &flags, &private_il);
  2104     free_message(dst);
  2105     free_stringlist(keylist);
  2106 
  2107     if (status == PEP_STATUS_OK &&
  2108         flags & PEP_decrypt_flag_own_private_key &&
  2109         private_il)
  2110     {
  2111         *ident = identity_dup(private_il->ident);
  2112     }
  2113 
  2114     free_identity_list(private_il);
  2115 
  2116     return status;
  2117 
  2118 }
  2119 
  2120 static void _max_comm_type_from_identity_list(
  2121         identity_list *identities,
  2122         PEP_SESSION session,
  2123         PEP_comm_type *max_comm_type,
  2124         bool *comm_type_determined
  2125     )
  2126 {
  2127     identity_list * il;
  2128     for (il = identities; il != NULL; il = il->next)
  2129     {
  2130         if (il->ident)
  2131         {
  2132             PEP_STATUS status = update_identity(session, il->ident);
  2133             if (status == PEP_STATUS_OK)
  2134             {
  2135                 *max_comm_type = _get_comm_type(session, *max_comm_type,
  2136                         il->ident);
  2137                 *comm_type_determined = true;
  2138             }
  2139         }
  2140     }
  2141 }
  2142 
  2143 DYNAMIC_API PEP_STATUS outgoing_message_rating(
  2144         PEP_SESSION session,
  2145         message *msg,
  2146         PEP_rating *rating
  2147     )
  2148 {
  2149     PEP_comm_type max_comm_type = PEP_ct_pEp;
  2150     bool comm_type_determined = false;
  2151 
  2152     assert(session);
  2153     assert(msg);
  2154     assert(msg->dir == PEP_dir_outgoing);
  2155     assert(rating);
  2156 
  2157     if (!(session && msg && rating))
  2158         return PEP_ILLEGAL_VALUE;
  2159 
  2160     if (msg->dir != PEP_dir_outgoing)
  2161         return PEP_ILLEGAL_VALUE;
  2162 
  2163     *rating = PEP_rating_undefined;
  2164 
  2165     _max_comm_type_from_identity_list(msg->to, session,
  2166                                       &max_comm_type, &comm_type_determined);
  2167 
  2168     _max_comm_type_from_identity_list(msg->cc, session,
  2169                                       &max_comm_type, &comm_type_determined);
  2170 
  2171     _max_comm_type_from_identity_list(msg->bcc, session,
  2172                                       &max_comm_type, &comm_type_determined);
  2173 
  2174     if (comm_type_determined == false)
  2175         *rating = PEP_rating_undefined;
  2176     else
  2177         *rating = _MAX(_rating(max_comm_type, PEP_rating_undefined),
  2178                 PEP_rating_unencrypted);
  2179 
  2180     return PEP_STATUS_OK;
  2181 }
  2182 
  2183 DYNAMIC_API PEP_STATUS identity_rating(
  2184         PEP_SESSION session,
  2185         pEp_identity *ident,
  2186         PEP_rating *rating
  2187     )
  2188 {
  2189     PEP_STATUS status = PEP_STATUS_OK;
  2190 
  2191     assert(session);
  2192     assert(ident);
  2193     assert(rating);
  2194 
  2195     if (!(session && ident && rating))
  2196         return PEP_ILLEGAL_VALUE;
  2197 
  2198     if (ident->me)
  2199         status = _myself(session, ident, false, true);
  2200     else
  2201         status = update_identity(session, ident);
  2202 
  2203     if (status == PEP_STATUS_OK)
  2204         *rating = _rating(ident->comm_type, PEP_rating_undefined);
  2205 
  2206     return status;
  2207 }
  2208 
  2209 DYNAMIC_API PEP_STATUS get_binary_path(PEP_cryptotech tech, const char **path)
  2210 {
  2211     PEP_STATUS status = PEP_STATUS_OK;
  2212 
  2213     assert(path);
  2214     if (path == NULL)
  2215         return PEP_ILLEGAL_VALUE;
  2216 
  2217     if (cryptotech[tech].binary_path == NULL)
  2218         *path = NULL;
  2219     else
  2220         status = cryptotech[tech].binary_path(path);
  2221 
  2222     return status;
  2223 }
  2224 
  2225 
  2226 DYNAMIC_API PEP_color color_from_rating(PEP_rating rating)
  2227 {
  2228     if (rating == PEP_rating_b0rken || rating == PEP_rating_have_no_key)
  2229         return PEP_color_no_color;
  2230 
  2231     if (rating < PEP_rating_undefined)
  2232         return PEP_color_red;
  2233 
  2234     if (rating < PEP_rating_reliable)
  2235         return PEP_color_no_color;
  2236 
  2237     if (rating < PEP_rating_trusted)
  2238         return PEP_color_yellow;
  2239 
  2240     if (rating >= PEP_rating_trusted)
  2241         return PEP_color_green;
  2242 
  2243     // this should never happen
  2244     assert(false);
  2245 	return PEP_color_no_color;
  2246 }
  2247 
  2248 DYNAMIC_API PEP_STATUS get_trustwords(
  2249     PEP_SESSION session, const pEp_identity* id1, const pEp_identity* id2,
  2250     const char* lang, char **words, size_t *wsize, bool full
  2251 )
  2252 {
  2253     assert(session);
  2254     assert(id1);
  2255     assert(id2);
  2256     assert(id1->fpr);
  2257     assert(id2->fpr);
  2258     assert(words);
  2259     assert(wsize);
  2260 
  2261     if (!(session && id1 && id2 && words && wsize) ||
  2262         !(id1->fpr) || (!id2->fpr))
  2263         return PEP_ILLEGAL_VALUE;
  2264 
  2265     const char *source1 = id1->fpr;
  2266     const char *source2 = id2->fpr;
  2267 
  2268     *words = NULL;
  2269     *wsize = 0;
  2270 
  2271     const size_t SHORT_NUM_TWORDS = 5;
  2272 
  2273     // N.B. THIS will have to be changed once we start checking trustword entropy.
  2274     // For now, full is ALL, and otherwise it's 5-per-id.
  2275     size_t max_words_per_id = (full ? 0 : SHORT_NUM_TWORDS);
  2276 
  2277     char* first_set = NULL;
  2278     char* second_set = NULL;
  2279     size_t first_wsize = 0;
  2280     size_t second_wsize = 0;
  2281 
  2282     int fpr_comparison = -255;
  2283     PEP_STATUS status = _compare_fprs(source1, strlen(source1), source2, strlen(source2), &fpr_comparison);
  2284     if (status != PEP_STATUS_OK)
  2285         return status;
  2286 
  2287     char* _retstr = NULL;
  2288 
  2289     switch (fpr_comparison) {
  2290         case 1: // source1 > source2
  2291             status = trustwords(session, source2, lang, &first_set, &first_wsize, max_words_per_id);
  2292             if (status != PEP_STATUS_OK)
  2293                 goto error_release;
  2294             status = trustwords(session, source1, lang, &second_set, &second_wsize, max_words_per_id);
  2295             if (status != PEP_STATUS_OK)
  2296                 goto error_release;
  2297             break;
  2298         case 0:
  2299         case -1: // source1 <= source2
  2300             status = trustwords(session, source1, lang, &first_set, &first_wsize, max_words_per_id);
  2301             if (status != PEP_STATUS_OK)
  2302                 goto error_release;
  2303             status = trustwords(session, source2, lang, &second_set, &second_wsize, max_words_per_id);
  2304             if (status != PEP_STATUS_OK)
  2305                 goto error_release;
  2306             break;
  2307         default:
  2308             return PEP_UNKNOWN_ERROR; // shouldn't be possible
  2309     }
  2310 
  2311     size_t _wsize = first_wsize + second_wsize;
  2312 
  2313     bool needs_space = (first_set[first_wsize - 1] != ' ');
  2314 
  2315     if (needs_space)
  2316         _wsize++;
  2317 
  2318     _retstr = calloc(1, _wsize + 1);
  2319 
  2320     size_t len = strlcpy(_retstr, first_set, _wsize);
  2321     if (len >= _wsize) {
  2322         status = PEP_UNKNOWN_ERROR;
  2323         goto error_release;
  2324     }
  2325     if (needs_space) {
  2326         strlcat(_retstr, " ", _wsize);
  2327         if (len >= _wsize) {
  2328             status = PEP_UNKNOWN_ERROR;
  2329             goto error_release;
  2330         }
  2331     }
  2332     strlcat(_retstr, second_set, _wsize);
  2333     if (len >= _wsize){
  2334         status = PEP_UNKNOWN_ERROR;
  2335         goto error_release;
  2336     }
  2337 
  2338     *words = _retstr;
  2339     *wsize = _wsize;
  2340     status = PEP_STATUS_OK;
  2341 
  2342     goto the_end;
  2343 
  2344     error_release:
  2345     free(_retstr);
  2346 
  2347     the_end:
  2348     free(first_set);
  2349     free(second_set);
  2350     return status;
  2351 }
  2352 
  2353 DYNAMIC_API PEP_STATUS get_message_trustwords(
  2354     PEP_SESSION session, 
  2355     message *msg,
  2356     stringlist_t *keylist,
  2357     pEp_identity* received_by,
  2358     const char* lang, char **words, bool full
  2359 )
  2360 {
  2361     assert(session);
  2362     assert(msg);
  2363     assert(received_by);
  2364     assert(received_by->address);
  2365     assert(lang);
  2366     assert(words);
  2367 
  2368     if (!(session && 
  2369           msg &&
  2370           received_by && 
  2371           received_by->address && 
  2372           lang && 
  2373           words))
  2374         return PEP_ILLEGAL_VALUE;
  2375     
  2376     pEp_identity* partner = NULL;
  2377      
  2378     PEP_STATUS status = PEP_STATUS_OK;
  2379     
  2380     *words = NULL;
  2381 
  2382     // We want fingerprint of key that did sign the message
  2383 
  2384     if (keylist == NULL) {
  2385 
  2386         // Message is to be decrypted
  2387         message *dst = NULL;
  2388         stringlist_t *_keylist = keylist;
  2389         PEP_rating rating;
  2390         PEP_decrypt_flags_t flags;
  2391         status = decrypt_message( session, msg, &dst, &_keylist, &rating, &flags);
  2392 
  2393         if (status != PEP_STATUS_OK) {
  2394             free_message(dst);
  2395             free_stringlist(_keylist);
  2396             return status;
  2397         }
  2398 
  2399         if (dst && dst->from && _keylist) {
  2400             partner = identity_dup(dst->from); 
  2401             if(partner){
  2402                 free(partner->fpr);
  2403                 partner->fpr = strdup(_keylist->value);
  2404                 if (partner->fpr == NULL)
  2405                     status = PEP_OUT_OF_MEMORY;
  2406             } else {
  2407                 status = PEP_OUT_OF_MEMORY;
  2408             }
  2409         } else {
  2410             status = PEP_UNKNOWN_ERROR;
  2411         }
  2412 
  2413         free_message(dst);
  2414         free_stringlist(_keylist);
  2415 
  2416     } else {
  2417 
  2418         // Message already decrypted
  2419         if (keylist->value) {
  2420             partner = identity_dup(msg->from); 
  2421             if(partner){
  2422                 free(partner->fpr);
  2423                 partner->fpr = strdup(keylist->value);
  2424                 if (partner->fpr == NULL)
  2425                     status = PEP_OUT_OF_MEMORY;
  2426             } else {
  2427                 status = PEP_OUT_OF_MEMORY;
  2428             }
  2429         } else {
  2430             status = PEP_ILLEGAL_VALUE;
  2431         }
  2432     }
  2433 
  2434     if (status != PEP_STATUS_OK) {
  2435         free_identity(partner);
  2436         return status;
  2437     }
  2438    
  2439     // Find own identity corresponding to given account address.
  2440     // In that case we want default key attached to own identity
  2441     pEp_identity *stored_identity = NULL;
  2442     status = get_identity(session,
  2443                           received_by->address,
  2444                           PEP_OWN_USERID,
  2445                           &stored_identity);
  2446 
  2447     if (status != PEP_STATUS_OK) {
  2448         free_identity(stored_identity);
  2449         return status;
  2450     }
  2451 
  2452     // get the trustwords
  2453     size_t wsize;
  2454     status = get_trustwords(session, 
  2455                             partner, received_by, 
  2456                             lang, words, &wsize, full);
  2457 
  2458     return status;
  2459 }
  2460 
  2461 DYNAMIC_API PEP_STATUS MIME_decrypt_message(
  2462     PEP_SESSION session,
  2463     const char *mimetext,
  2464     size_t size,
  2465     char** mime_plaintext,
  2466     stringlist_t **keylist,
  2467     PEP_rating *rating,
  2468     PEP_decrypt_flags_t *flags
  2469 )
  2470 {
  2471     assert(mimetext);
  2472     assert(mime_plaintext);
  2473     assert(keylist);
  2474     assert(rating);
  2475     assert(flags);
  2476 
  2477     PEP_STATUS status = PEP_STATUS_OK;
  2478     message* tmp_msg = NULL;
  2479     message* dec_msg = NULL;
  2480 
  2481     status = mime_decode_message(mimetext, size, &tmp_msg);
  2482     if (status != PEP_STATUS_OK)
  2483         goto pep_error;
  2484 
  2485     PEP_STATUS decrypt_status = decrypt_message(session,
  2486                                                 tmp_msg,
  2487                                                 &dec_msg,
  2488                                                 keylist,
  2489                                                 rating,
  2490                                                 flags);
  2491                                                 
  2492     if (!dec_msg && (decrypt_status == PEP_UNENCRYPTED || decrypt_status == PEP_VERIFIED)) {
  2493         dec_msg = message_dup(tmp_msg);
  2494     }
  2495         
  2496     if (decrypt_status > PEP_CANNOT_DECRYPT_UNKNOWN)
  2497     {
  2498         status = decrypt_status;
  2499         goto pep_error;
  2500     }
  2501 
  2502     assert(dec_msg);
  2503     
  2504     if (!dec_msg) {
  2505         status = PEP_UNKNOWN_ERROR;
  2506         goto pep_error;
  2507     }
  2508 
  2509     status = mime_encode_message(dec_msg, false, mime_plaintext);
  2510 
  2511     if (status == PEP_STATUS_OK)
  2512     {
  2513         free(tmp_msg);
  2514         free(dec_msg);
  2515         return decrypt_status;
  2516     }
  2517     
  2518 pep_error:
  2519     free_message(tmp_msg);
  2520     free_message(dec_msg);
  2521 
  2522     return status;
  2523 }
  2524 
  2525 
  2526 DYNAMIC_API PEP_STATUS MIME_encrypt_message(
  2527     PEP_SESSION session,
  2528     const char *mimetext,
  2529     size_t size,
  2530     stringlist_t* extra,
  2531     char** mime_ciphertext,
  2532     PEP_enc_format enc_format,
  2533     PEP_encrypt_flags_t flags
  2534 )
  2535 {
  2536     PEP_STATUS status = PEP_STATUS_OK;
  2537     message* tmp_msg = NULL;
  2538     message* enc_msg = NULL;
  2539 
  2540     status = mime_decode_message(mimetext, size, &tmp_msg);
  2541     if (status != PEP_STATUS_OK)
  2542         goto pep_error;
  2543 
  2544     // This isn't incoming, though... so we need to reverse the direction
  2545     tmp_msg->dir = PEP_dir_outgoing;
  2546     status = encrypt_message(session,
  2547                              tmp_msg,
  2548                              extra,
  2549                              &enc_msg,
  2550                              enc_format,
  2551                              flags);
  2552     if (status != PEP_STATUS_OK)
  2553         goto pep_error;
  2554 
  2555 
  2556     if (!enc_msg) {
  2557         status = PEP_UNKNOWN_ERROR;
  2558         goto pep_error;
  2559     }
  2560 
  2561     status = mime_encode_message(enc_msg, false, mime_ciphertext);
  2562 
  2563 pep_error:
  2564     free_message(tmp_msg);
  2565     free_message(enc_msg);
  2566 
  2567     return status;
  2568 
  2569 }
  2570 
  2571 DYNAMIC_API PEP_STATUS MIME_encrypt_message_for_self(
  2572     PEP_SESSION session,
  2573     pEp_identity* target_id,
  2574     const char *mimetext,
  2575     size_t size,
  2576     char** mime_ciphertext,
  2577     PEP_enc_format enc_format,
  2578     PEP_encrypt_flags_t flags
  2579 )
  2580 {
  2581     PEP_STATUS status = PEP_STATUS_OK;
  2582     message* tmp_msg = NULL;
  2583     message* enc_msg = NULL;
  2584 
  2585     status = mime_decode_message(mimetext, size, &tmp_msg);
  2586     if (status != PEP_STATUS_OK)
  2587         goto pep_error;
  2588 
  2589     // This isn't incoming, though... so we need to reverse the direction
  2590     tmp_msg->dir = PEP_dir_outgoing;
  2591     status = encrypt_message_for_self(session,
  2592                                       target_id,
  2593                                       tmp_msg,
  2594                                       &enc_msg,
  2595                                       enc_format,
  2596                                       flags);
  2597     if (status != PEP_STATUS_OK)
  2598         goto pep_error;
  2599  
  2600     if (!enc_msg) {
  2601         status = PEP_UNKNOWN_ERROR;
  2602         goto pep_error;
  2603     }
  2604 
  2605     status = mime_encode_message(enc_msg, false, mime_ciphertext);
  2606 
  2607 pep_error:
  2608     free_message(tmp_msg);
  2609     free_message(enc_msg);
  2610 
  2611     return status;
  2612 }