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