src/message_api.c
author Edouard Tisserant <edouard@pep-project.org>
Thu, 15 Jun 2017 13:26:34 +0200
changeset 1862 881f5a1d8a40
parent 1859 acf5c59a49e3
parent 1745 373a181d7185
child 1863 c9c47bbd0dcd
permissions -rw-r--r--
ENGINE-204 merged into default
     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             identity_list *local_private_idents = NULL;
   999             import_key(session, bl->value, bl->size, &local_private_idents);
  1000             remove = true;
  1001             if (*private_idents == NULL && local_private_idents != NULL)
  1002                 *private_idents = local_private_idents;
  1003             else
  1004                 free_identity_list(local_private_idents);
  1005         }
  1006     }
  1007     return remove;
  1008 }
  1009 
  1010 
  1011 PEP_STATUS _attach_key(PEP_SESSION session, const char* fpr, message *msg)
  1012 {
  1013     char *keydata = NULL;
  1014     size_t size;
  1015 
  1016     PEP_STATUS status = export_key(session, fpr, &keydata, &size);
  1017     assert(status == PEP_STATUS_OK);
  1018     if (status != PEP_STATUS_OK)
  1019         return status;
  1020     assert(size);
  1021 
  1022      bloblist_t *bl = bloblist_add(msg->attachments, keydata, size, "application/pgp-keys",
  1023                       "pEpkey.asc");
  1024 
  1025     if (msg->attachments == NULL && bl)
  1026         msg->attachments = bl;
  1027 
  1028     return PEP_STATUS_OK;
  1029 }
  1030 
  1031 #define ONE_WEEK (7*24*3600)
  1032 
  1033 void attach_own_key(PEP_SESSION session, message *msg)
  1034 {
  1035     assert(session);
  1036     assert(msg);
  1037 
  1038     if (msg->dir == PEP_dir_incoming)
  1039         return;
  1040 
  1041     assert(msg->from && msg->from->fpr);
  1042     if (msg->from == NULL || msg->from->fpr == NULL)
  1043         return;
  1044 
  1045     if(_attach_key(session, msg->from->fpr, msg) != PEP_STATUS_OK)
  1046         return;
  1047 
  1048     char *revoked_fpr = NULL;
  1049     uint64_t revocation_date = 0;
  1050 
  1051     if(get_revoked(session, msg->from->fpr,
  1052                    &revoked_fpr, &revocation_date) == PEP_STATUS_OK &&
  1053        revoked_fpr != NULL)
  1054     {
  1055         time_t now = time(NULL);
  1056 
  1057         if (now < (time_t)revocation_date + ONE_WEEK)
  1058         {
  1059             _attach_key(session, revoked_fpr, msg);
  1060         }
  1061     }
  1062     free(revoked_fpr);
  1063 }
  1064 
  1065 PEP_cryptotech determine_encryption_format(message *msg)
  1066 {
  1067     assert(msg);
  1068 
  1069     if (is_PGP_message_text(msg->longmsg)) {
  1070         msg->enc_format = PEP_enc_pieces;
  1071         return PEP_crypt_OpenPGP;
  1072     }
  1073     else if (msg->attachments && msg->attachments->next &&
  1074             is_mime_type(msg->attachments, "application/pgp-encrypted") &&
  1075             is_PGP_message_text(msg->attachments->next->value)
  1076         ) {
  1077         msg->enc_format = PEP_enc_PGP_MIME;
  1078         return PEP_crypt_OpenPGP;
  1079     }
  1080     else if (msg->attachments && msg->attachments->next &&
  1081             is_mime_type(msg->attachments->next, "application/pgp-encrypted") &&
  1082             is_PGP_message_text(msg->attachments->value)
  1083         ) {
  1084         msg->enc_format = PEP_enc_PGP_MIME_Outlook1;
  1085         return PEP_crypt_OpenPGP;
  1086     }
  1087     else {
  1088         msg->enc_format = PEP_enc_none;
  1089         return PEP_crypt_none;
  1090     }
  1091 }
  1092 
  1093 DYNAMIC_API PEP_STATUS encrypt_message(
  1094         PEP_SESSION session,
  1095         message *src,
  1096         stringlist_t * extra,
  1097         message **dst,
  1098         PEP_enc_format enc_format,
  1099         PEP_encrypt_flags_t flags
  1100     )
  1101 {
  1102     PEP_STATUS status = PEP_STATUS_OK;
  1103     message * msg = NULL;
  1104     stringlist_t * keys = NULL;
  1105 
  1106     assert(session);
  1107     assert(src);
  1108     assert(dst);
  1109     assert(enc_format != PEP_enc_none);
  1110 
  1111     if (!(session && src && dst && enc_format != PEP_enc_none))
  1112         return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
  1113 
  1114     if (src->dir == PEP_dir_incoming)
  1115         return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
  1116 
  1117     determine_encryption_format(src);
  1118     if (src->enc_format != PEP_enc_none)
  1119         return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
  1120 
  1121     *dst = NULL;
  1122 
  1123     status = myself(session, src->from);
  1124     if (status != PEP_STATUS_OK)
  1125         GOTO(pep_error);
  1126 
  1127     keys = new_stringlist(src->from->fpr);
  1128     if (keys == NULL)
  1129         goto enomem;
  1130 
  1131     stringlist_t *_k = keys;
  1132 
  1133     if (extra) {
  1134         _k = stringlist_append(_k, extra);
  1135         if (_k == NULL)
  1136             goto enomem;
  1137     }
  1138 
  1139     bool dest_keys_found = true;
  1140     PEP_comm_type max_comm_type = PEP_ct_pEp;
  1141 
  1142     identity_list * _il;
  1143 
  1144     if ((_il = src->bcc) && _il->ident)
  1145     {
  1146         // BCC limited support:
  1147         //     - App splits mails with BCC in multiple mails.
  1148         //     - Each email is encrypted separately
  1149 
  1150         if(_il->next || (src->to && src->to->ident) || (src->cc && src->cc->ident))
  1151         {
  1152             // Only one Bcc with no other recipient allowed for now
  1153             return PEP_ILLEGAL_VALUE;
  1154         }
  1155 
  1156         PEP_STATUS _status = update_identity(session, _il->ident);
  1157         if (_status != PEP_STATUS_OK) {
  1158             status = _status;
  1159             GOTO(pep_error);
  1160         }
  1161 
  1162         if (_il->ident->fpr && _il->ident->fpr[0]) {
  1163             _k = stringlist_add(_k, _il->ident->fpr);
  1164             if (_k == NULL)
  1165                 goto enomem;
  1166             max_comm_type = _get_comm_type(session, max_comm_type,
  1167                                            _il->ident);
  1168         }
  1169         else {
  1170             dest_keys_found = false;
  1171             status = PEP_KEY_NOT_FOUND;
  1172         }
  1173     }
  1174     else
  1175     {
  1176         for (_il = src->to; _il && _il->ident; _il = _il->next) {
  1177             PEP_STATUS _status = update_identity(session, _il->ident);
  1178             if (_status != PEP_STATUS_OK) {
  1179                 status = _status;
  1180                 GOTO(pep_error);
  1181             }
  1182 
  1183             if (_il->ident->fpr && _il->ident->fpr[0]) {
  1184                 _k = stringlist_add(_k, _il->ident->fpr);
  1185                 if (_k == NULL)
  1186                     goto enomem;
  1187                 max_comm_type = _get_comm_type(session, max_comm_type,
  1188                                                _il->ident);
  1189             }
  1190             else {
  1191                 dest_keys_found = false;
  1192                 status = PEP_KEY_NOT_FOUND;
  1193             }
  1194         }
  1195 
  1196         for (_il = src->cc; _il && _il->ident; _il = _il->next) {
  1197             PEP_STATUS _status = update_identity(session, _il->ident);
  1198             if (_status != PEP_STATUS_OK)
  1199             {
  1200                 status = _status;
  1201                 GOTO(pep_error);
  1202             }
  1203 
  1204             if (_il->ident->fpr && _il->ident->fpr[0]) {
  1205                 _k = stringlist_add(_k, _il->ident->fpr);
  1206                 if (_k == NULL)
  1207                     goto enomem;
  1208                 max_comm_type = _get_comm_type(session, max_comm_type,
  1209                                                _il->ident);
  1210             }
  1211             else {
  1212                 dest_keys_found = false;
  1213                 status = PEP_KEY_NOT_FOUND;
  1214             }
  1215         }
  1216     }
  1217 
  1218     if (!dest_keys_found ||
  1219         stringlist_length(keys)  == 0 ||
  1220         _rating(max_comm_type,
  1221                 PEP_rating_undefined) < PEP_rating_reliable)
  1222     {
  1223         free_stringlist(keys);
  1224         if (!session->passive_mode && !(flags & PEP_encrypt_flag_force_no_attached_key))
  1225             attach_own_key(session, src);
  1226         return ADD_TO_LOG(PEP_UNENCRYPTED);
  1227     }
  1228     else {
  1229         msg = clone_to_empty_message(src);
  1230         if (msg == NULL)
  1231             goto enomem;
  1232 
  1233         if (!(flags & PEP_encrypt_flag_force_no_attached_key))
  1234             attach_own_key(session, src);
  1235 
  1236         switch (enc_format) {
  1237         case PEP_enc_PGP_MIME:
  1238         case PEP_enc_PEP: // BUG: should be implemented extra
  1239             status = encrypt_PGP_MIME(session, src, keys, msg, flags);
  1240             break;
  1241 
  1242         case PEP_enc_pieces:
  1243             status = encrypt_PGP_in_pieces(session, src, keys, msg, flags);
  1244             break;
  1245 
  1246         /* case PEP_enc_PEP:
  1247             // TODO: implement
  1248             NOT_IMPLEMENTED */
  1249 
  1250         default:
  1251             assert(0);
  1252             status = PEP_ILLEGAL_VALUE;
  1253             GOTO(pep_error);
  1254         }
  1255 
  1256         if (status == PEP_OUT_OF_MEMORY)
  1257             goto enomem;
  1258 
  1259         if (status != PEP_STATUS_OK)
  1260             GOTO(pep_error);
  1261     }
  1262 
  1263     free_stringlist(keys);
  1264 
  1265     if (msg && msg->shortmsg == NULL) {
  1266         msg->shortmsg = strdup("pEp");
  1267         assert(msg->shortmsg);
  1268         if (msg->shortmsg == NULL)
  1269             goto enomem;
  1270     }
  1271 
  1272     if (msg) {
  1273         decorate_message(msg, PEP_rating_undefined, NULL);
  1274         if (src->id) {
  1275             msg->id = strdup(src->id);
  1276             assert(msg->id);
  1277             if (msg->id == NULL)
  1278                 goto enomem;
  1279         }
  1280     }
  1281 
  1282     *dst = msg;
  1283     return ADD_TO_LOG(status);
  1284 
  1285 enomem:
  1286     status = PEP_OUT_OF_MEMORY;
  1287 
  1288 pep_error:
  1289     free_stringlist(keys);
  1290     free_message(msg);
  1291 
  1292     return ADD_TO_LOG(status);
  1293 }
  1294 
  1295 DYNAMIC_API PEP_STATUS encrypt_message_for_self(
  1296         PEP_SESSION session,
  1297         pEp_identity* target_id,
  1298         message *src,
  1299         message **dst,
  1300         PEP_enc_format enc_format,
  1301         PEP_encrypt_flags_t flags
  1302     )
  1303 {
  1304     PEP_STATUS status = PEP_STATUS_OK;
  1305     message * msg = NULL;
  1306     stringlist_t * keys = NULL;
  1307 
  1308     assert(session);
  1309     assert(src);
  1310     assert(dst);
  1311     assert(enc_format != PEP_enc_none);
  1312 
  1313     if (!(session && src && dst && enc_format != PEP_enc_none))
  1314         return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
  1315 
  1316     if (src->dir == PEP_dir_incoming)
  1317         return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
  1318 
  1319     determine_encryption_format(src);
  1320     if (src->enc_format != PEP_enc_none)
  1321         return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
  1322 
  1323     status = myself(session, target_id);
  1324     if (status != PEP_STATUS_OK)
  1325         GOTO(pep_error);
  1326 
  1327     *dst = NULL;
  1328 
  1329 
  1330     PEP_STATUS _status = update_identity(session, target_id);
  1331     if (_status != PEP_STATUS_OK) {
  1332         status = _status;
  1333         goto pep_error;
  1334     }
  1335 
  1336     char* target_fpr = target_id->fpr;
  1337     if (!target_fpr)
  1338         return PEP_KEY_NOT_FOUND; // FIXME: Error condition
  1339  
  1340     keys = new_stringlist(target_fpr);
  1341     
  1342     /* KG: did we ever do this??? */
  1343     if (!(flags & PEP_encrypt_flag_force_no_attached_key))
  1344         _attach_key(session, target_fpr, src);
  1345 
  1346     msg = clone_to_empty_message(src);
  1347     if (msg == NULL)
  1348         goto enomem;
  1349 
  1350     switch (enc_format) {
  1351         case PEP_enc_PGP_MIME:
  1352         case PEP_enc_PEP: // BUG: should be implemented extra
  1353             status = encrypt_PGP_MIME(session, src, keys, msg, flags);
  1354             break;
  1355 
  1356         case PEP_enc_pieces:
  1357             status = encrypt_PGP_in_pieces(session, src, keys, msg, flags);
  1358             break;
  1359 
  1360         /* case PEP_enc_PEP:
  1361             NOT_IMPLEMENTED */
  1362             // TODO: implement
  1363 
  1364         default:
  1365             assert(0);
  1366             status = PEP_ILLEGAL_VALUE;
  1367             goto pep_error;
  1368     }
  1369 
  1370     if (status == PEP_OUT_OF_MEMORY)
  1371         goto enomem;
  1372 
  1373     if (status != PEP_STATUS_OK)
  1374         goto pep_error;
  1375 
  1376      if (msg && msg->shortmsg == NULL) {
  1377          msg->shortmsg = strdup("pEp");
  1378          assert(msg->shortmsg);
  1379          if (msg->shortmsg == NULL)
  1380              goto enomem;
  1381      }
  1382 
  1383      if (msg) {
  1384          if (src->id) {
  1385              msg->id = strdup(src->id);
  1386              assert(msg->id);
  1387              if (msg->id == NULL)
  1388                  goto enomem;
  1389          }
  1390      }
  1391 
  1392     *dst = msg;
  1393     return status;
  1394 
  1395 enomem:
  1396     status = PEP_OUT_OF_MEMORY;
  1397 
  1398 pep_error:
  1399     free_stringlist(keys);
  1400     free_message(msg);
  1401 
  1402     return ADD_TO_LOG(status);
  1403 }
  1404 
  1405 static bool is_a_pEpmessage(const message *msg)
  1406 {
  1407     for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
  1408         if (strcasecmp(i->value->key, "X-pEp-Version") == 0)
  1409             return true;
  1410     }
  1411     return false;
  1412 }
  1413 
  1414 // update comm_type to pEp_ct_pEp if needed
  1415 
  1416 static PEP_STATUS _update_identity_for_incoming_message(
  1417         PEP_SESSION session,
  1418         const message *src
  1419     )
  1420 {
  1421     PEP_STATUS status;
  1422     if (src->from && src->from->address) {
  1423         status = update_identity(session, src->from);
  1424         if (status == PEP_STATUS_OK
  1425                 && is_a_pEpmessage(src)
  1426                 && src->from->comm_type >= PEP_ct_OpenPGP_unconfirmed
  1427                 && src->from->comm_type != PEP_ct_pEp_unconfirmed
  1428                 && src->from->comm_type != PEP_ct_pEp)
  1429         {
  1430             src->from->comm_type |= PEP_ct_pEp_unconfirmed;
  1431             status = set_identity(session, src->from);
  1432         }
  1433         return status;
  1434     }
  1435     return PEP_ILLEGAL_VALUE;
  1436 }
  1437 
  1438 
  1439 PEP_STATUS _get_detached_signature(message* msg, bloblist_t** signature_blob) {
  1440     bloblist_t* attach_curr = msg->attachments;
  1441 
  1442     *signature_blob = NULL;
  1443 
  1444     while (attach_curr) {
  1445         if (strcasecmp(attach_curr->mime_type, "application/pgp-signature") == 0) {
  1446             *signature_blob = attach_curr;
  1447             break;
  1448         }
  1449         attach_curr = attach_curr->next;
  1450     }
  1451 
  1452     return PEP_STATUS_OK;
  1453 }
  1454 
  1455 PEP_STATUS _get_signed_text(const char* ptext, const size_t psize,
  1456                             char** stext, size_t* ssize) {
  1457 
  1458     char* signed_boundary = NULL;
  1459     char* signpost = strstr(ptext, "Content-Type: multipart/signed");
  1460 
  1461     *ssize = 0;
  1462     *stext = NULL;
  1463 
  1464     if (!signpost)
  1465         return PEP_UNKNOWN_ERROR;
  1466 
  1467     char* curr_line = signpost;
  1468 //    const char* end_text = ptext + psize;
  1469     const char* boundary_key = "boundary=";
  1470     const size_t BOUNDARY_KEY_SIZE = 9;
  1471 
  1472     char* start_boundary = strstr(curr_line, boundary_key);
  1473     if (!start_boundary)
  1474         return PEP_UNKNOWN_ERROR;
  1475 
  1476     start_boundary += BOUNDARY_KEY_SIZE;
  1477 
  1478     bool quoted = (*start_boundary == '"');
  1479 
  1480     if (quoted)
  1481         start_boundary++;
  1482         
  1483     char* end_boundary = (quoted ? strstr(start_boundary, "\"") : strstr(start_boundary, ";")); // FIXME: third possiblity is CRLF, or?
  1484 
  1485     if (!end_boundary)
  1486         return PEP_UNKNOWN_ERROR;
  1487 
  1488     // Add space for the "--"
  1489     size_t boundary_strlen = (end_boundary - start_boundary) + 2;
  1490 
  1491     signed_boundary = calloc(1, boundary_strlen + 1);
  1492     strlcpy(signed_boundary, "--", boundary_strlen + 1);
  1493     strlcat(signed_boundary, start_boundary, boundary_strlen + 1);
  1494 
  1495     start_boundary = strstr(end_boundary, signed_boundary);
  1496 
  1497     if (!start_boundary)
  1498         return PEP_UNKNOWN_ERROR;
  1499 
  1500     start_boundary += boundary_strlen;
  1501 
  1502     if (*start_boundary == '\r') {
  1503         if (*(start_boundary + 1) == '\n')
  1504             start_boundary += 2;
  1505     }
  1506     else if (*start_boundary == '\n')
  1507         start_boundary++;
  1508 
  1509     end_boundary = strstr(start_boundary + boundary_strlen, signed_boundary);
  1510 
  1511     if (!end_boundary)
  1512         return PEP_UNKNOWN_ERROR;
  1513 
  1514     // See RFC3156 section 5...
  1515     end_boundary--; 
  1516     if (*(end_boundary - 1) == '\r')
  1517         end_boundary--; 
  1518 
  1519     *ssize = end_boundary - start_boundary;
  1520     *stext = start_boundary;
  1521     free(signed_boundary);
  1522 
  1523     return PEP_STATUS_OK;
  1524 }
  1525 
  1526 PEP_STATUS combine_keylists(PEP_SESSION session, stringlist_t** verify_in, 
  1527                             stringlist_t** keylist_in_out, 
  1528                             pEp_identity* from) {
  1529     
  1530     if (!verify_in || !(*verify_in)) // this isn't really a problem.
  1531         return PEP_STATUS_OK;
  1532     
  1533     stringlist_t* orig_verify = *verify_in;
  1534     
  1535     stringlist_t* verify_curr = NULL;
  1536     stringlist_t* from_keys = NULL;
  1537     
  1538     /* FIXME: what to do if head needs to be null */
  1539     PEP_STATUS status = find_keys(session, from->address, &from_keys);
  1540     
  1541     stringlist_t* from_fpr_node = NULL;
  1542     stringlist_t* from_curr;
  1543     
  1544     for (from_curr = from_keys; from_curr; from_curr = from_curr->next) {
  1545         for (verify_curr = orig_verify; verify_curr; verify_curr = verify_curr->next) {
  1546             if (from_curr->value && verify_curr->value &&
  1547                 _same_fpr(from_curr->value, strlen(from_curr->value),
  1548                           verify_curr->value, strlen(verify_curr->value))) {
  1549                 from_fpr_node = from_curr;
  1550                 break;
  1551             }
  1552         }
  1553     }
  1554     
  1555     if (!from_fpr_node) {
  1556         status = PEP_KEY_NOT_FOUND;
  1557         goto free;
  1558     }
  1559 
  1560     verify_curr = orig_verify;
  1561     
  1562     /* put "from" signer at the beginning of the list */
  1563     if (!_same_fpr(orig_verify->value, strlen(orig_verify->value),
  1564                    from_fpr_node->value, strlen(from_fpr_node->value))) {
  1565         orig_verify = stringlist_delete(orig_verify, from_fpr_node->value);
  1566         verify_curr = new_stringlist(from_fpr_node->value);
  1567         verify_curr->next = orig_verify;
  1568     }
  1569 
  1570     /* append keylist to signers */
  1571     if (keylist_in_out && *keylist_in_out && (*keylist_in_out)->value) {
  1572         stringlist_t** tail_pp = &verify_curr->next;
  1573         
  1574         while (*tail_pp) {
  1575             tail_pp = &((*tail_pp)->next);
  1576         }
  1577         stringlist_t* second_list = *keylist_in_out;
  1578         if (second_list) {
  1579             char* listhead_val = second_list->value;
  1580             if (!listhead_val || listhead_val[0] == '\0') {
  1581                 /* remove head, basically. This can happen when,
  1582                    for example, the signature is detached and
  1583                    verification is not seen directly after
  1584                    decryption, so no signer is presumed in
  1585                    the first construction of the keylist */
  1586                 *keylist_in_out = (*keylist_in_out)->next;
  1587                 second_list->next = NULL;
  1588                 free_stringlist(second_list);
  1589             }
  1590         }
  1591         *tail_pp = *keylist_in_out;
  1592     }
  1593     
  1594     *keylist_in_out = verify_curr;
  1595     
  1596     status = PEP_STATUS_OK;
  1597     
  1598 free:
  1599     free_stringlist(from_keys);
  1600     return status;
  1601 }
  1602 
  1603 PEP_STATUS amend_rating_according_to_sender_and_recipients(
  1604     PEP_SESSION session,
  1605     PEP_rating *rating,
  1606     pEp_identity *sender,
  1607     stringlist_t *recipients) {
  1608     
  1609     PEP_STATUS status = PEP_STATUS_OK;
  1610 
  1611     if (*rating > PEP_rating_mistrust) {
  1612         PEP_rating kl_rating = PEP_rating_undefined;
  1613 
  1614         if (recipients)
  1615             kl_rating = keylist_rating(session, recipients);
  1616 
  1617         if (kl_rating <= PEP_rating_mistrust) {
  1618             *rating = kl_rating;
  1619         }
  1620         else if (*rating >= PEP_rating_reliable &&
  1621                  kl_rating < PEP_rating_reliable) {
  1622             *rating = PEP_rating_unreliable;
  1623         }
  1624         else if (*rating >= PEP_rating_reliable &&
  1625                  kl_rating >= PEP_rating_reliable) {
  1626             if (!(sender && sender->user_id && sender->user_id[0])) {
  1627                 *rating = PEP_rating_unreliable;
  1628             }
  1629             else {
  1630                 char *fpr = recipients->value;
  1631                 pEp_identity *_sender = new_identity(sender->address, fpr,
  1632                                                    sender->user_id, sender->username);
  1633                 if (_sender == NULL)
  1634                     return PEP_OUT_OF_MEMORY;
  1635                 status = get_trust(session, _sender);
  1636                 if (_sender->comm_type != PEP_ct_unknown) {
  1637                     *rating = worst_rating(_rating(_sender->comm_type, PEP_rating_undefined),
  1638                               kl_rating);
  1639                 }
  1640                 free_identity(_sender);
  1641                 if (status == PEP_CANNOT_FIND_IDENTITY)
  1642                    status = PEP_STATUS_OK;
  1643             }
  1644         }
  1645     }
  1646     return status;
  1647 }
  1648 
  1649 
  1650 DYNAMIC_API PEP_STATUS _decrypt_message(
  1651         PEP_SESSION session,
  1652         message *src,
  1653         message **dst,
  1654         stringlist_t **keylist,
  1655         PEP_rating *rating,
  1656         PEP_decrypt_flags_t *flags,
  1657         identity_list **private_il
  1658     )
  1659 {
  1660     PEP_STATUS status = PEP_STATUS_OK;
  1661     PEP_STATUS decrypt_status = PEP_CANNOT_DECRYPT_UNKNOWN;
  1662     message *msg = NULL;
  1663     char *ctext;
  1664     size_t csize;
  1665     char *ptext = NULL;
  1666     size_t psize;
  1667     stringlist_t *_keylist = NULL;
  1668 
  1669     assert(session);
  1670     assert(src);
  1671     assert(dst);
  1672     assert(keylist);
  1673     assert(rating);
  1674     assert(flags);
  1675 
  1676     if (!(session && src && dst && keylist && rating && flags))
  1677         return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
  1678 
  1679     *flags = 0;
  1680 
  1681     // Private key in unencrypted mail are ignored -> NULL
  1682     bool imported_keys = import_attached_keys(session, src, NULL);
  1683 
  1684     // Update src->from in case we just imported a key
  1685     // we would need to check signature
  1686     status = _update_identity_for_incoming_message(session, src);
  1687     if(status != PEP_STATUS_OK)
  1688         return ADD_TO_LOG(status);
  1689 
  1690     // Get detached signature, if any
  1691     bloblist_t* detached_sig = NULL;
  1692     char* dsig_text = NULL;
  1693     size_t dsig_size = 0;
  1694     status = _get_detached_signature(src, &detached_sig);
  1695     if (detached_sig) {
  1696         dsig_text = detached_sig->value;
  1697         dsig_size = detached_sig->size;
  1698     }
  1699 
  1700     PEP_cryptotech crypto = determine_encryption_format(src);
  1701 
  1702     *dst = NULL;
  1703     *keylist = NULL;
  1704     *rating = PEP_rating_undefined;
  1705 
  1706     switch (src->enc_format) {
  1707         case PEP_enc_none:
  1708             *rating = PEP_rating_unencrypted;
  1709             if (imported_keys)
  1710                 remove_attached_keys(src);
  1711             if(session->sync_session->inject_sync_msg){
  1712                 status = receive_DeviceState_msg(session, src, *rating, *keylist);
  1713                 if (status == PEP_MESSAGE_CONSUME ||
  1714                     status == PEP_MESSAGE_IGNORE) {
  1715                     free_message(msg);
  1716                     msg = NULL;
  1717                     *flags |= (status == PEP_MESSAGE_IGNORE) ?
  1718                                 PEP_decrypt_flag_ignore :
  1719                                 PEP_decrypt_flag_consume;
  1720                 }
  1721                 else if (status != PEP_STATUS_OK) {
  1722                     return ADD_TO_LOG(status);
  1723                 }
  1724             }
  1725             
  1726             char* slong = src->longmsg;
  1727             char* sform = src->longmsg_formatted;
  1728             bloblist_t* satt = src->attachments;
  1729             
  1730             if ((!slong || slong[0] == '\0')
  1731                  && (!sform || sform[0] == '\0')) {
  1732                 if (satt) {
  1733                     const char* inner_mime_type = satt->mime_type;
  1734                     if (strcasecmp(inner_mime_type, "text/plain") == 0) {
  1735                         free(slong); /* in case of "" */
  1736                         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!
  1737                         
  1738                         bloblist_t* next_node = satt->next;
  1739                         if (next_node) {
  1740                             inner_mime_type = next_node->mime_type;
  1741                             if (strcasecmp(inner_mime_type, "text/html") == 0) {
  1742                                 free(sform);
  1743                                 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!
  1744                             }
  1745                         }
  1746                     }
  1747                     else if (strcasecmp(inner_mime_type, "text/html") == 0) {
  1748                         free(sform);
  1749                         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!
  1750                     }
  1751                 }
  1752             }
  1753             
  1754             return ADD_TO_LOG(PEP_UNENCRYPTED);
  1755 
  1756         case PEP_enc_PGP_MIME:
  1757             ctext = src->attachments->next->value;
  1758             csize = src->attachments->next->size;
  1759             break;
  1760 
  1761         case PEP_enc_PGP_MIME_Outlook1:
  1762             ctext = src->attachments->value;
  1763             csize = src->attachments->size;
  1764             break;
  1765 
  1766         case PEP_enc_pieces:
  1767             ctext = src->longmsg;
  1768             csize = strlen(ctext);
  1769             break;
  1770 
  1771         default:
  1772             NOT_IMPLEMENTED
  1773     }
  1774     status = cryptotech[crypto].decrypt_and_verify(session, ctext,
  1775                                                    csize, dsig_text, dsig_size,
  1776                                                    &ptext, &psize, &_keylist);
  1777     if (status > PEP_CANNOT_DECRYPT_UNKNOWN){
  1778         GOTO(pep_error);
  1779     }
  1780 
  1781     decrypt_status = status;
  1782 
  1783     if (status == PEP_DECRYPT_NO_KEY){
  1784         PEP_STATUS sync_status = inject_DeviceState_event(session, CannotDecrypt, NULL, NULL);
  1785         if (sync_status == PEP_OUT_OF_MEMORY){
  1786             status = PEP_OUT_OF_MEMORY;
  1787             goto pep_error;
  1788         }
  1789     }
  1790 
  1791     bool imported_private_key_address = false;
  1792 
  1793     if (ptext) {
  1794         switch (src->enc_format) {
  1795             case PEP_enc_PGP_MIME:
  1796             case PEP_enc_PGP_MIME_Outlook1:
  1797                 status = mime_decode_message(ptext, psize, &msg);
  1798                 if (status != PEP_STATUS_OK)
  1799                     goto pep_error;
  1800                 
  1801                 char* mlong = msg->longmsg;
  1802                 char* mform = msg->longmsg_formatted;
  1803                 bloblist_t* matt = msg->attachments;
  1804                 
  1805                 if ((!mlong || mlong[0] == '\0')
  1806                      && (!mform || mform[0] == '\0')) {
  1807                     if (matt) {
  1808                         const char* inner_mime_type = matt->mime_type;
  1809                         if (strcasecmp(inner_mime_type, "text/plain") == 0) {
  1810                             free(mlong); /* in case of "" */
  1811                             msg->longmsg = strndup(matt->value, matt->size);
  1812                             
  1813                             bloblist_t* next_node = matt->next;
  1814                             if (next_node) {
  1815                                 inner_mime_type = next_node->mime_type;
  1816                                 if (strcasecmp(inner_mime_type, "text/html") == 0) {
  1817                                     free(mform);
  1818                                     msg->longmsg_formatted = strndup(next_node->value, next_node->size);
  1819                                 }
  1820                             }
  1821                         }
  1822                         else if (strcasecmp(inner_mime_type, "text/html") == 0) {
  1823                             free(mform);
  1824                             msg->longmsg_formatted = strndup(matt->value, matt->size);
  1825                         }
  1826                     }
  1827                     if (msg->shortmsg) {
  1828                         free(src->shortmsg);
  1829                         src->shortmsg = strdup(msg->shortmsg);
  1830                     }
  1831                 }
  1832 
  1833                 if (decrypt_status != PEP_DECRYPTED_AND_VERIFIED) {
  1834                     status = _get_detached_signature(msg, &detached_sig);
  1835                     if (decrypt_status == PEP_DECRYPTED && detached_sig) {
  1836                         dsig_text = detached_sig->value;
  1837                         dsig_size = detached_sig->size;
  1838                         size_t ssize = 0;
  1839                         char* stext = NULL;
  1840 
  1841                         status = _get_signed_text(ptext, psize, &stext, &ssize);
  1842                         stringlist_t *_verify_keylist = NULL;
  1843 
  1844                         if (ssize > 0 && stext) {
  1845                             status = cryptotech[crypto].verify_text(session, stext,
  1846                                                                     ssize, dsig_text, dsig_size,
  1847                                                                     &_verify_keylist);
  1848 
  1849                             if (status == PEP_VERIFIED || status == PEP_VERIFIED_AND_TRUSTED)
  1850                                 decrypt_status = PEP_DECRYPTED_AND_VERIFIED;
  1851                             
  1852                                 status = combine_keylists(session, &_verify_keylist, &_keylist, src->from);
  1853                         }
  1854                     }
  1855                 }
  1856                 break;
  1857 
  1858             case PEP_enc_pieces:
  1859                 msg = clone_to_empty_message(src);
  1860                 if (msg == NULL)
  1861                     goto enomem;
  1862 
  1863                 msg->longmsg = ptext;
  1864                 ptext = NULL;
  1865 
  1866                 bloblist_t *_m = msg->attachments;
  1867                 if (_m == NULL && src->attachments && src->attachments->value) {
  1868                     msg->attachments = new_bloblist(NULL, 0, NULL, NULL);
  1869                     _m = msg->attachments;
  1870                 }
  1871 
  1872                 bloblist_t *_s;
  1873                 for (_s = src->attachments; _s; _s = _s->next) {
  1874                     if (_s->value == NULL && _s->size == 0){
  1875                         _m = bloblist_add(_m, NULL, 0, _s->mime_type, _s->filename);
  1876                         if (_m == NULL)
  1877                             goto enomem;
  1878 
  1879                     }
  1880                     else if (is_encrypted_attachment(_s)) {
  1881                         stringlist_t *_keylist = NULL;
  1882                         char *attctext  = _s->value;
  1883                         size_t attcsize = _s->size;
  1884 
  1885                         free(ptext);
  1886                         ptext = NULL;
  1887 
  1888                         // FIXME: What about attachments with separate sigs???
  1889                         status = decrypt_and_verify(session, attctext, attcsize,
  1890                                                     NULL, 0,
  1891                                                     &ptext, &psize, &_keylist);
  1892                         free_stringlist(_keylist); // FIXME: Why do we do this?
  1893 
  1894                         if (ptext) {
  1895                             if (is_encrypted_html_attachment(_s)) {
  1896                                 msg->longmsg_formatted = ptext;
  1897                                 ptext = NULL;
  1898                             }
  1899                             else {
  1900                                 static const char * const mime_type = "application/octet-stream";
  1901                                 char * const filename =
  1902                                     without_double_ending(_s->filename);
  1903                                 if (filename == NULL)
  1904                                     goto enomem;
  1905 
  1906                                 _m = bloblist_add(_m, ptext, psize, mime_type,
  1907                                     filename);
  1908                                 free(filename);
  1909                                 if (_m == NULL)
  1910                                     goto enomem;
  1911 
  1912                                 ptext = NULL;
  1913 
  1914                                 if (msg->attachments == NULL)
  1915                                     msg->attachments = _m;
  1916                             }
  1917                         }
  1918                         else {
  1919                             char *copy = malloc(_s->size);
  1920                             assert(copy);
  1921                             if (copy == NULL)
  1922                                 goto enomem;
  1923                             memcpy(copy, _s->value, _s->size);
  1924                             _m = bloblist_add(_m, copy, _s->size, _s->mime_type, _s->filename);
  1925                             if (_m == NULL)
  1926                                 goto enomem;
  1927                         }
  1928                     }
  1929                     else {
  1930                         char *copy = malloc(_s->size);
  1931                         assert(copy);
  1932                         if (copy == NULL)
  1933                             goto enomem;
  1934                         memcpy(copy, _s->value, _s->size);
  1935                         _m = bloblist_add(_m, copy, _s->size, _s->mime_type, _s->filename);
  1936                         if (_m == NULL)
  1937                             goto enomem;
  1938                     }
  1939                 }
  1940 
  1941                 break;
  1942 
  1943             default:
  1944                 // BUG: must implement more
  1945                 NOT_IMPLEMENTED
  1946         }
  1947 
  1948         switch (src->enc_format) {
  1949             case PEP_enc_PGP_MIME:
  1950             case PEP_enc_pieces:
  1951             case PEP_enc_PGP_MIME_Outlook1:
  1952                 status = copy_fields(msg, src);
  1953                 if (status != PEP_STATUS_OK)
  1954                 {
  1955                     GOTO(pep_error);
  1956                 }
  1957 
  1958                 if (src->shortmsg == NULL || strcmp(src->shortmsg, "pEp") == 0)
  1959                 {
  1960                     char * shortmsg;
  1961                     char * longmsg;
  1962 
  1963                     int r = separate_short_and_long(msg->longmsg, &shortmsg,
  1964                             &longmsg);
  1965                     
  1966                     if (r == -1)
  1967                         goto enomem;
  1968 
  1969                     if (shortmsg == NULL) {
  1970                         if (src->shortmsg == NULL)
  1971                             shortmsg = strdup("");
  1972                         else {
  1973                             // FIXME: is msg->shortmsg always a copy of
  1974                             // src->shortmsg already?
  1975                             // if so, we need to change the logic so
  1976                             // that in this case, we don't free msg->shortmsg
  1977                             // and do this strdup, etc.
  1978                             shortmsg = strdup(src->shortmsg);
  1979                         }
  1980                     }
  1981 
  1982 
  1983                     free(msg->shortmsg);
  1984                     free(msg->longmsg);
  1985 
  1986                     msg->shortmsg = shortmsg;
  1987                     msg->longmsg = longmsg;
  1988                 }
  1989                 else {
  1990                     msg->shortmsg = strdup(src->shortmsg);
  1991                     assert(msg->shortmsg);
  1992                     if (msg->shortmsg == NULL)
  1993                         goto enomem;
  1994                 }
  1995                 break;
  1996             default:
  1997                     // BUG: must implement more
  1998                     NOT_IMPLEMENTED
  1999         }
  2000 
  2001         // check for private key in decrypted message attachement while inporting
  2002         identity_list *_private_il = NULL;
  2003         imported_keys = import_attached_keys(session, msg, &_private_il);
  2004         if (_private_il &&
  2005             identity_list_length(_private_il) == 1 &&
  2006             _private_il->ident->address)
  2007         {
  2008             imported_private_key_address = true;
  2009         }
  2010 
  2011         if(private_il && imported_private_key_address){
  2012             *private_il = _private_il;
  2013         }else{
  2014             free_identity_list(_private_il);
  2015         }
  2016 
  2017         if(decrypt_status == PEP_DECRYPTED){
  2018 
  2019             // TODO optimize if import_attached_keys didn't import any key
  2020 
  2021             // In case message did decrypt, but no valid signature could be found
  2022             // then retry decrypt+verify after importing key.
  2023 
  2024             // Update msg->from in case we just imported a key
  2025             // we would need to check signature
  2026 
  2027             status = _update_identity_for_incoming_message(session, src);
  2028             if(status != PEP_STATUS_OK)
  2029             {
  2030                 GOTO(pep_error);
  2031             }
  2032 
  2033             char *re_ptext = NULL;
  2034             size_t re_psize;
  2035 
  2036             free_stringlist(_keylist);
  2037             _keylist = NULL;
  2038 
  2039             status = cryptotech[crypto].decrypt_and_verify(session, ctext,
  2040                 csize, dsig_text, dsig_size, &re_ptext, &re_psize, &_keylist);
  2041 
  2042             free(re_ptext);
  2043 
  2044             if (status > PEP_CANNOT_DECRYPT_UNKNOWN)
  2045             {
  2046                 GOTO(pep_error);
  2047             }
  2048 
  2049             decrypt_status = status;
  2050         }
  2051 
  2052         *rating = decrypt_rating(decrypt_status);
  2053 
  2054         status = amend_rating_according_to_sender_and_recipients(session,
  2055                                                                  rating,
  2056                                                                  src->from,
  2057                                                                  _keylist);
  2058 
  2059         if (status != PEP_STATUS_OK)
  2060             GOTO(pep_error);
  2061     }
  2062     else
  2063     {
  2064         *rating = decrypt_rating(decrypt_status);
  2065         goto pep_error;
  2066     }
  2067 
  2068     // Case of own key imported from own trusted message
  2069     if (// Message have been reliably decrypted
  2070         msg &&
  2071         *rating >= PEP_rating_trusted &&
  2072         imported_private_key_address &&
  2073         // to is [own]
  2074         msg->to->ident->user_id &&
  2075         strcmp(msg->to->ident->user_id, PEP_OWN_USERID) == 0
  2076         )
  2077     {
  2078         *flags |= PEP_decrypt_flag_own_private_key;
  2079     }
  2080 
  2081     if (msg) {
  2082         decorate_message(msg, *rating, _keylist);
  2083         if (imported_keys)
  2084             remove_attached_keys(msg);
  2085         if (*rating >= PEP_rating_reliable &&
  2086             session->sync_session->inject_sync_msg) {
  2087             status = receive_DeviceState_msg(session, msg, *rating, _keylist);
  2088             if (status == PEP_MESSAGE_CONSUME ||
  2089                 status == PEP_MESSAGE_IGNORE) {
  2090                 free_message(msg);
  2091                 msg = NULL;
  2092                 *flags |= (status == PEP_MESSAGE_IGNORE) ?
  2093                             PEP_decrypt_flag_ignore :
  2094                             PEP_decrypt_flag_consume;
  2095 
  2096             }
  2097             else if (status != PEP_STATUS_OK){
  2098                 goto pep_error;
  2099             }
  2100         }
  2101     }
  2102     if (msg) {
  2103         if (src->id) {
  2104             msg->id = strdup(src->id);
  2105             assert(msg->id);
  2106             if (msg->id == NULL)
  2107                 goto enomem;
  2108         }
  2109     }
  2110 
  2111     *dst = msg;
  2112     *keylist = _keylist;
  2113 
  2114     if(decrypt_status == PEP_DECRYPTED_AND_VERIFIED)
  2115         return ADD_TO_LOG(PEP_STATUS_OK);
  2116     else
  2117         return ADD_TO_LOG(decrypt_status);
  2118 
  2119 enomem:
  2120     status = PEP_OUT_OF_MEMORY;
  2121 
  2122 pep_error:
  2123     free(ptext);
  2124     free_message(msg);
  2125     free_stringlist(_keylist);
  2126 
  2127     return ADD_TO_LOG(status);
  2128 }
  2129 
  2130 DYNAMIC_API PEP_STATUS decrypt_message(
  2131         PEP_SESSION session,
  2132         message *src,
  2133         message **dst,
  2134         stringlist_t **keylist,
  2135         PEP_rating *rating,
  2136         PEP_decrypt_flags_t *flags
  2137     )
  2138 {
  2139     return _decrypt_message( session, src, dst, keylist, rating, flags, NULL );
  2140 }
  2141 
  2142 DYNAMIC_API PEP_STATUS own_message_private_key_details(
  2143         PEP_SESSION session,
  2144         message *msg,
  2145         pEp_identity **ident
  2146     )
  2147 {
  2148     assert(session);
  2149     assert(msg);
  2150     assert(ident);
  2151 
  2152     if (!(session && msg && ident))
  2153         return PEP_ILLEGAL_VALUE;
  2154 
  2155     message *dst = NULL;
  2156     stringlist_t *keylist = NULL;
  2157     PEP_rating rating;
  2158     PEP_decrypt_flags_t flags;
  2159 
  2160     *ident = NULL;
  2161 
  2162     identity_list *private_il = NULL;
  2163     PEP_STATUS status = _decrypt_message(session, msg,  &dst, &keylist, &rating, &flags, &private_il);
  2164     free_message(dst);
  2165     free_stringlist(keylist);
  2166 
  2167     if (status == PEP_STATUS_OK &&
  2168         flags & PEP_decrypt_flag_own_private_key &&
  2169         private_il)
  2170     {
  2171         *ident = identity_dup(private_il->ident);
  2172     }
  2173 
  2174     free_identity_list(private_il);
  2175 
  2176     return ADD_TO_LOG(status);
  2177 }
  2178 
  2179 static void _max_comm_type_from_identity_list(
  2180         identity_list *identities,
  2181         PEP_SESSION session,
  2182         PEP_comm_type *max_comm_type,
  2183         bool *comm_type_determined
  2184     )
  2185 {
  2186     identity_list * il;
  2187     for (il = identities; il != NULL; il = il->next)
  2188     {
  2189         if (il->ident)
  2190         {
  2191             PEP_STATUS status = update_identity(session, il->ident);
  2192             if (status == PEP_STATUS_OK)
  2193             {
  2194                 *max_comm_type = _get_comm_type(session, *max_comm_type,
  2195                         il->ident);
  2196                 *comm_type_determined = true;
  2197             }
  2198         }
  2199     }
  2200 }
  2201 
  2202 DYNAMIC_API PEP_STATUS outgoing_message_rating(
  2203         PEP_SESSION session,
  2204         message *msg,
  2205         PEP_rating *rating
  2206     )
  2207 {
  2208     PEP_comm_type max_comm_type = PEP_ct_pEp;
  2209     bool comm_type_determined = false;
  2210 
  2211     assert(session);
  2212     assert(msg);
  2213     assert(msg->dir == PEP_dir_outgoing);
  2214     assert(rating);
  2215 
  2216     if (!(session && msg && rating))
  2217         return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
  2218 
  2219     if (msg->dir != PEP_dir_outgoing)
  2220         return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
  2221 
  2222     *rating = PEP_rating_undefined;
  2223 
  2224     _max_comm_type_from_identity_list(msg->to, session,
  2225                                       &max_comm_type, &comm_type_determined);
  2226 
  2227     _max_comm_type_from_identity_list(msg->cc, session,
  2228                                       &max_comm_type, &comm_type_determined);
  2229 
  2230     _max_comm_type_from_identity_list(msg->bcc, session,
  2231                                       &max_comm_type, &comm_type_determined);
  2232 
  2233     if (comm_type_determined == false)
  2234         *rating = PEP_rating_undefined;
  2235     else
  2236         *rating = _MAX(_rating(max_comm_type, PEP_rating_undefined),
  2237                 PEP_rating_unencrypted);
  2238 
  2239     return PEP_STATUS_OK;
  2240 }
  2241 
  2242 DYNAMIC_API PEP_STATUS identity_rating(
  2243         PEP_SESSION session,
  2244         pEp_identity *ident,
  2245         PEP_rating *rating
  2246     )
  2247 {
  2248     PEP_STATUS status = PEP_STATUS_OK;
  2249 
  2250     assert(session);
  2251     assert(ident);
  2252     assert(rating);
  2253 
  2254     if (!(session && ident && rating))
  2255         return PEP_ILLEGAL_VALUE;
  2256 
  2257     if (ident->me)
  2258         status = _myself(session, ident, false, true);
  2259     else
  2260         status = update_identity(session, ident);
  2261 
  2262     if (status == PEP_STATUS_OK)
  2263         *rating = _rating(ident->comm_type, PEP_rating_undefined);
  2264 
  2265     return status;
  2266 }
  2267 
  2268 DYNAMIC_API PEP_STATUS get_binary_path(PEP_cryptotech tech, const char **path)
  2269 {
  2270     PEP_STATUS status = PEP_STATUS_OK;
  2271 
  2272     assert(path);
  2273     if (path == NULL)
  2274         return PEP_ILLEGAL_VALUE;
  2275 
  2276     if (cryptotech[tech].binary_path == NULL)
  2277         *path = NULL;
  2278     else
  2279         status = cryptotech[tech].binary_path(path);
  2280 
  2281     return status;
  2282 }
  2283 
  2284 
  2285 DYNAMIC_API PEP_color color_from_rating(PEP_rating rating)
  2286 {
  2287     if (rating == PEP_rating_b0rken || rating == PEP_rating_have_no_key)
  2288         return PEP_color_no_color;
  2289 
  2290     if (rating < PEP_rating_undefined)
  2291         return PEP_color_red;
  2292 
  2293     if (rating < PEP_rating_reliable)
  2294         return PEP_color_no_color;
  2295 
  2296     if (rating < PEP_rating_trusted)
  2297         return PEP_color_yellow;
  2298 
  2299     if (rating >= PEP_rating_trusted)
  2300         return PEP_color_green;
  2301 
  2302     // this should never happen
  2303     assert(false);
  2304     return PEP_color_no_color;
  2305 }
  2306 
  2307 DYNAMIC_API PEP_STATUS get_trustwords(
  2308     PEP_SESSION session, const pEp_identity* id1, const pEp_identity* id2,
  2309     const char* lang, char **words, size_t *wsize, bool full
  2310 )
  2311 {
  2312     assert(session);
  2313     assert(id1);
  2314     assert(id2);
  2315     assert(id1->fpr);
  2316     assert(id2->fpr);
  2317     assert(words);
  2318     assert(wsize);
  2319 
  2320     if (!(session && id1 && id2 && words && wsize) ||
  2321         !(id1->fpr) || (!id2->fpr))
  2322         return PEP_ILLEGAL_VALUE;
  2323 
  2324     const char *source1 = id1->fpr;
  2325     const char *source2 = id2->fpr;
  2326 
  2327     *words = NULL;
  2328     *wsize = 0;
  2329 
  2330     const size_t SHORT_NUM_TWORDS = 5;
  2331 
  2332     // N.B. THIS will have to be changed once we start checking trustword entropy.
  2333     // For now, full is ALL, and otherwise it's 5-per-id.
  2334     size_t max_words_per_id = (full ? 0 : SHORT_NUM_TWORDS);
  2335 
  2336     char* first_set = NULL;
  2337     char* second_set = NULL;
  2338     size_t first_wsize = 0;
  2339     size_t second_wsize = 0;
  2340 
  2341     int fpr_comparison = -255;
  2342     PEP_STATUS status = _compare_fprs(source1, strlen(source1), source2, strlen(source2), &fpr_comparison);
  2343     if (status != PEP_STATUS_OK)
  2344         return status;
  2345 
  2346     char* _retstr = NULL;
  2347 
  2348     switch (fpr_comparison) {
  2349         case 1: // source1 > source2
  2350             status = trustwords(session, source2, lang, &first_set, &first_wsize, max_words_per_id);
  2351             if (status != PEP_STATUS_OK)
  2352                 goto error_release;
  2353             status = trustwords(session, source1, lang, &second_set, &second_wsize, max_words_per_id);
  2354             if (status != PEP_STATUS_OK)
  2355                 goto error_release;
  2356             break;
  2357         case 0:
  2358         case -1: // source1 <= source2
  2359             status = trustwords(session, source1, lang, &first_set, &first_wsize, max_words_per_id);
  2360             if (status != PEP_STATUS_OK)
  2361                 goto error_release;
  2362             status = trustwords(session, source2, lang, &second_set, &second_wsize, max_words_per_id);
  2363             if (status != PEP_STATUS_OK)
  2364                 goto error_release;
  2365             break;
  2366         default:
  2367             return ADD_TO_LOG(PEP_UNKNOWN_ERROR); // shouldn't be possible
  2368     }
  2369 
  2370     size_t _wsize = first_wsize + second_wsize;
  2371 
  2372     bool needs_space = (first_set[first_wsize - 1] != ' ');
  2373 
  2374     if (needs_space)
  2375         _wsize++;
  2376 
  2377     _retstr = calloc(1, _wsize + 1);
  2378 
  2379     size_t len = strlcpy(_retstr, first_set, _wsize);
  2380     if (len >= _wsize) {
  2381         status = PEP_UNKNOWN_ERROR;
  2382         goto error_release;
  2383     }
  2384     if (needs_space) {
  2385         strlcat(_retstr, " ", _wsize);
  2386         if (len >= _wsize) {
  2387             status = PEP_UNKNOWN_ERROR;
  2388             goto error_release;
  2389         }
  2390     }
  2391     strlcat(_retstr, second_set, _wsize);
  2392     if (len >= _wsize){
  2393         status = PEP_UNKNOWN_ERROR;
  2394         goto error_release;
  2395     }
  2396 
  2397     *words = _retstr;
  2398     *wsize = _wsize;
  2399     status = PEP_STATUS_OK;
  2400 
  2401     goto the_end;
  2402 
  2403     error_release:
  2404     free(_retstr);
  2405 
  2406     the_end:
  2407     free(first_set);
  2408     free(second_set);
  2409     return ADD_TO_LOG(status);
  2410 }
  2411 
  2412 DYNAMIC_API PEP_STATUS get_message_trustwords(
  2413     PEP_SESSION session, 
  2414     message *msg,
  2415     stringlist_t *keylist,
  2416     pEp_identity* received_by,
  2417     const char* lang, char **words, bool full
  2418 )
  2419 {
  2420     assert(session);
  2421     assert(msg);
  2422     assert(received_by);
  2423     assert(received_by->address);
  2424     assert(lang);
  2425     assert(words);
  2426 
  2427     if (!(session && 
  2428           msg &&
  2429           received_by && 
  2430           received_by->address && 
  2431           lang && 
  2432           words))
  2433         return PEP_ILLEGAL_VALUE;
  2434     
  2435     pEp_identity* partner = NULL;
  2436      
  2437     PEP_STATUS status = PEP_STATUS_OK;
  2438     
  2439     *words = NULL;
  2440 
  2441     // We want fingerprint of key that did sign the message
  2442 
  2443     if (keylist == NULL) {
  2444 
  2445         // Message is to be decrypted
  2446         message *dst = NULL;
  2447         stringlist_t *_keylist = keylist;
  2448         PEP_rating rating;
  2449         PEP_decrypt_flags_t flags;
  2450         status = decrypt_message( session, msg, &dst, &_keylist, &rating, &flags);
  2451 
  2452         if (status != PEP_STATUS_OK) {
  2453             free_message(dst);
  2454             free_stringlist(_keylist);
  2455             return status;
  2456         }
  2457 
  2458         if (dst && dst->from && _keylist) {
  2459             partner = identity_dup(dst->from); 
  2460             if(partner){
  2461                 free(partner->fpr);
  2462                 partner->fpr = strdup(_keylist->value);
  2463                 if (partner->fpr == NULL)
  2464                     status = PEP_OUT_OF_MEMORY;
  2465             } else {
  2466                 status = PEP_OUT_OF_MEMORY;
  2467             }
  2468         } else {
  2469             status = PEP_UNKNOWN_ERROR;
  2470         }
  2471 
  2472         free_message(dst);
  2473         free_stringlist(_keylist);
  2474 
  2475     } else {
  2476 
  2477         // Message already decrypted
  2478         if (keylist->value) {
  2479             partner = identity_dup(msg->from); 
  2480             if(partner){
  2481                 free(partner->fpr);
  2482                 partner->fpr = strdup(keylist->value);
  2483                 if (partner->fpr == NULL)
  2484                     status = PEP_OUT_OF_MEMORY;
  2485             } else {
  2486                 status = PEP_OUT_OF_MEMORY;
  2487             }
  2488         } else {
  2489             status = PEP_ILLEGAL_VALUE;
  2490         }
  2491     }
  2492 
  2493     if (status != PEP_STATUS_OK) {
  2494         free_identity(partner);
  2495         return ADD_TO_LOG(status);
  2496     }
  2497    
  2498     // Find own identity corresponding to given account address.
  2499     // In that case we want default key attached to own identity
  2500     pEp_identity *stored_identity = NULL;
  2501     status = get_identity(session,
  2502                           received_by->address,
  2503                           PEP_OWN_USERID,
  2504                           &stored_identity);
  2505 
  2506     if (status != PEP_STATUS_OK) {
  2507         free_identity(stored_identity);
  2508         return ADD_TO_LOG(status);
  2509     }
  2510 
  2511     // get the trustwords
  2512     size_t wsize;
  2513     status = get_trustwords(session, 
  2514                             partner, received_by, 
  2515                             lang, words, &wsize, full);
  2516 
  2517     return ADD_TO_LOG(status);
  2518 }
  2519 
  2520 DYNAMIC_API PEP_STATUS MIME_decrypt_message(
  2521     PEP_SESSION session,
  2522     const char *mimetext,
  2523     size_t size,
  2524     char** mime_plaintext,
  2525     stringlist_t **keylist,
  2526     PEP_rating *rating,
  2527     PEP_decrypt_flags_t *flags
  2528 )
  2529 {
  2530     assert(mimetext);
  2531     assert(mime_plaintext);
  2532     assert(keylist);
  2533     assert(rating);
  2534     assert(flags);
  2535 
  2536     PEP_STATUS status = PEP_STATUS_OK;
  2537     message* tmp_msg = NULL;
  2538     message* dec_msg = NULL;
  2539     *mime_plaintext = NULL;
  2540 
  2541     status = mime_decode_message(mimetext, size, &tmp_msg);
  2542     if (status != PEP_STATUS_OK)
  2543         GOTO(pep_error);
  2544 
  2545     PEP_STATUS decrypt_status = decrypt_message(session,
  2546                                                 tmp_msg,
  2547                                                 &dec_msg,
  2548                                                 keylist,
  2549                                                 rating,
  2550                                                 flags);
  2551                                                 
  2552     if (!dec_msg && (decrypt_status == PEP_UNENCRYPTED || decrypt_status == PEP_VERIFIED)) {
  2553         dec_msg = message_dup(tmp_msg);
  2554     }
  2555         
  2556     if (decrypt_status > PEP_CANNOT_DECRYPT_UNKNOWN || !dec_msg)
  2557     {
  2558         status = decrypt_status;
  2559         GOTO(pep_error);
  2560     }
  2561 
  2562     status = mime_encode_message(dec_msg, false, mime_plaintext);
  2563 
  2564     if (status == PEP_STATUS_OK)
  2565     {
  2566         free(tmp_msg);
  2567         free(dec_msg);
  2568         return ADD_TO_LOG(decrypt_status);
  2569     }
  2570     
  2571 pep_error:
  2572     free_message(tmp_msg);
  2573     free_message(dec_msg);
  2574 
  2575     return ADD_TO_LOG(status);
  2576 }
  2577 
  2578 
  2579 DYNAMIC_API PEP_STATUS MIME_encrypt_message(
  2580     PEP_SESSION session,
  2581     const char *mimetext,
  2582     size_t size,
  2583     stringlist_t* extra,
  2584     char** mime_ciphertext,
  2585     PEP_enc_format enc_format,
  2586     PEP_encrypt_flags_t flags
  2587 )
  2588 {
  2589     PEP_STATUS status = PEP_STATUS_OK;
  2590     message* tmp_msg = NULL;
  2591     message* enc_msg = NULL;
  2592 
  2593     status = mime_decode_message(mimetext, size, &tmp_msg);
  2594     if (status != PEP_STATUS_OK)
  2595         GOTO(pep_error);
  2596 
  2597     // This isn't incoming, though... so we need to reverse the direction
  2598     tmp_msg->dir = PEP_dir_outgoing;
  2599     status = encrypt_message(session,
  2600                              tmp_msg,
  2601                              extra,
  2602                              &enc_msg,
  2603                              enc_format,
  2604                              flags);
  2605     if (status != PEP_STATUS_OK)
  2606         GOTO(pep_error);
  2607 
  2608 
  2609     if (!enc_msg) {
  2610         status = PEP_UNKNOWN_ERROR;
  2611         GOTO(pep_error);
  2612     }
  2613 
  2614     status = mime_encode_message(enc_msg, false, mime_ciphertext);
  2615 
  2616 pep_error:
  2617     free_message(tmp_msg);
  2618     free_message(enc_msg);
  2619 
  2620     return ADD_TO_LOG(status);
  2621 
  2622 }
  2623 
  2624 DYNAMIC_API PEP_STATUS MIME_encrypt_message_for_self(
  2625     PEP_SESSION session,
  2626     pEp_identity* target_id,
  2627     const char *mimetext,
  2628     size_t size,
  2629     char** mime_ciphertext,
  2630     PEP_enc_format enc_format,
  2631     PEP_encrypt_flags_t flags
  2632 )
  2633 {
  2634     PEP_STATUS status = PEP_STATUS_OK;
  2635     message* tmp_msg = NULL;
  2636     message* enc_msg = NULL;
  2637 
  2638     status = mime_decode_message(mimetext, size, &tmp_msg);
  2639     if (status != PEP_STATUS_OK)
  2640         goto pep_error;
  2641 
  2642     // This isn't incoming, though... so we need to reverse the direction
  2643     tmp_msg->dir = PEP_dir_outgoing;
  2644     status = encrypt_message_for_self(session,
  2645                                       target_id,
  2646                                       tmp_msg,
  2647                                       &enc_msg,
  2648                                       enc_format,
  2649                                       flags);
  2650     if (status != PEP_STATUS_OK)
  2651         goto pep_error;
  2652  
  2653     if (!enc_msg) {
  2654         status = PEP_UNKNOWN_ERROR;
  2655         goto pep_error;
  2656     }
  2657 
  2658     status = mime_encode_message(enc_msg, false, mime_ciphertext);
  2659 
  2660 pep_error:
  2661     free_message(tmp_msg);
  2662     free_message(enc_msg);
  2663 
  2664     return ADD_TO_LOG(status);
  2665 }
  2666 
  2667 static PEP_rating string_to_rating(const char * rating)
  2668 {
  2669     if (rating == NULL)
  2670         return PEP_rating_undefined;
  2671     if (strcmp(rating, "cannot_decrypt") == 0)
  2672         return PEP_rating_cannot_decrypt;
  2673     if (strcmp(rating, "have_no_key") == 0)
  2674         return PEP_rating_have_no_key;
  2675     if (strcmp(rating, "unencrypted") == 0)
  2676         return PEP_rating_unencrypted;
  2677     if (strcmp(rating, "unencrypted_for_some") == 0)
  2678         return PEP_rating_unencrypted_for_some;
  2679     if (strcmp(rating, "unreliable") == 0)
  2680         return PEP_rating_unreliable;
  2681     if (strcmp(rating, "reliable") == 0)
  2682         return PEP_rating_reliable;
  2683     if (strcmp(rating, "trusted") == 0)
  2684         return PEP_rating_trusted;
  2685     if (strcmp(rating, "trusted_and_anonymized") == 0)
  2686         return PEP_rating_trusted_and_anonymized;
  2687     if (strcmp(rating, "fully_anonymous") == 0)
  2688         return PEP_rating_fully_anonymous;
  2689     if (strcmp(rating, "mistrust") == 0)
  2690         return PEP_rating_mistrust;
  2691     if (strcmp(rating, "b0rken") == 0)
  2692         return PEP_rating_b0rken;
  2693     if (strcmp(rating, "under_attack") == 0)
  2694         return PEP_rating_under_attack;
  2695     return PEP_rating_undefined;
  2696 }
  2697 
  2698 static PEP_STATUS string_to_keylist(const char * skeylist, stringlist_t **keylist)
  2699 {
  2700     if (skeylist == NULL || keylist == NULL)
  2701         return PEP_ILLEGAL_VALUE;
  2702 
  2703     stringlist_t *rkeylist = NULL;
  2704     stringlist_t *_kcurr = NULL;
  2705     const char * fpr_begin = skeylist;
  2706     const char * fpr_end = NULL;
  2707 
  2708     do {
  2709         fpr_end = strstr(fpr_begin, ",");
  2710         
  2711         char * fpr = strndup(
  2712             fpr_begin,
  2713             (fpr_end == NULL) ? strlen(fpr_begin) : fpr_end - fpr_begin);
  2714         
  2715         if (fpr == NULL)
  2716             goto enomem;
  2717         
  2718         _kcurr = stringlist_add(_kcurr, fpr);
  2719         if (_kcurr == NULL) {
  2720             free(fpr);
  2721             goto enomem;
  2722         }
  2723         
  2724         if (rkeylist == NULL)
  2725             rkeylist = _kcurr;
  2726         
  2727         fpr_begin = fpr_end ? fpr_end + 1 : NULL;
  2728         
  2729     } while (fpr_begin);
  2730     
  2731     *keylist = rkeylist;
  2732     return PEP_STATUS_OK;
  2733     
  2734 enomem:
  2735     free_stringlist(rkeylist);
  2736     return PEP_OUT_OF_MEMORY;
  2737 }
  2738 
  2739 DYNAMIC_API PEP_STATUS re_evaluate_message_rating(
  2740     PEP_SESSION session,
  2741     message *msg,
  2742     stringlist_t *x_keylist,
  2743     PEP_rating x_enc_status,
  2744     PEP_rating *rating
  2745 )
  2746 {
  2747     PEP_STATUS status = PEP_STATUS_OK;
  2748     stringlist_t *_keylist = x_keylist;
  2749     bool must_free_keylist = false;
  2750     PEP_rating _rating;
  2751 
  2752     assert(session);
  2753     assert(msg);
  2754     assert(rating);
  2755 
  2756     if (!(session && msg && rating))
  2757         return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
  2758 
  2759     *rating = PEP_rating_undefined;
  2760 
  2761     if (x_enc_status == PEP_rating_undefined){
  2762         for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
  2763             if (strcasecmp(i->value->key, "X-EncStatus") == 0){
  2764                 x_enc_status = string_to_rating(i->value->value);
  2765                 goto got_rating;
  2766             }
  2767         }
  2768         return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
  2769     }
  2770 
  2771 got_rating:
  2772 
  2773     _rating = x_enc_status;
  2774 
  2775     if (_keylist == NULL){
  2776         for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
  2777             if (strcasecmp(i->value->key, "X-KeyList") == 0){
  2778                 status = string_to_keylist(i->value->value, &_keylist);
  2779                 if (status != PEP_STATUS_OK)
  2780                     GOTO(pep_error);
  2781                 must_free_keylist = true;
  2782                 goto got_keylist;
  2783             }
  2784         }
  2785         return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
  2786     }
  2787 got_keylist:
  2788 
  2789     status = update_identity(session, msg->from);
  2790     if (status != PEP_STATUS_OK)
  2791         GOTO(pep_error);
  2792 
  2793     status = amend_rating_according_to_sender_and_recipients(session,
  2794                                                              &_rating,
  2795                                                              msg->from,
  2796                                                              _keylist);
  2797     if (status == PEP_STATUS_OK)
  2798         *rating = _rating;
  2799     
  2800 pep_error:
  2801     if (must_free_keylist)
  2802         free_stringlist(_keylist);
  2803 
  2804     return ADD_TO_LOG(status);
  2805 }