src/message_api.c
author Edouard Tisserant
Wed, 15 Jun 2016 09:59:05 +0200
branchimport_own_key
changeset 737 b70708554378
parent 736 496905895282
child 738 51a8af1ef550
permissions -rw-r--r--
Private key import is now considered as soon as private key comes from green channel.
     1 #include "pEp_internal.h"
     2 #include "message_api.h"
     3 
     4 #include "platform.h"
     5 #include "mime.h"
     6 
     7 #include <assert.h>
     8 #include <string.h>
     9 #include <stdlib.h>
    10 
    11 #ifndef MIN
    12 #define MIN(A, B) ((B) > (A) ? (A) : (B))
    13 #endif
    14 #ifndef MAX
    15 #define MAX(A, B) ((B) > (A) ? (B) : (A))
    16 #endif
    17 
    18 
    19 static bool string_equality(const char *s1, const char *s2)
    20 {
    21     if (s1 == NULL || s2 == NULL)
    22         return false;
    23 
    24     assert(s1 && s2);
    25 
    26     return strcmp(s1, s2) == 0;
    27 }
    28 
    29 static bool is_mime_type(const bloblist_t *bl, const char *mt)
    30 {
    31     assert(mt);
    32 
    33     return bl && string_equality(bl->mime_type, mt);
    34 }
    35 
    36 static bool is_fileending(const bloblist_t *bl, const char *fe)
    37 {
    38     assert(fe);
    39 
    40     if (bl == NULL || bl->filename == NULL)
    41         return false;
    42 
    43     assert(bl && bl->filename);
    44 
    45     size_t fe_len = strlen(fe);
    46     size_t fn_len = strlen(bl->filename);
    47 
    48     if (fn_len <= fe_len)
    49         return false;
    50 
    51     assert(fn_len > fe_len);
    52 
    53     return strcmp(bl->filename + (fn_len - fe_len), fe) == 0;
    54 }
    55 
    56 static void add_opt_field(message *msg, const char *name, const char *value)
    57 {
    58     assert(msg);
    59 
    60     if (msg && name && value) {
    61         stringpair_t *pair = new_stringpair(name, value);
    62         if (pair == NULL)
    63             return;
    64 
    65         stringpair_list_t *field = stringpair_list_add(msg->opt_fields, pair);
    66         if (field == NULL)
    67             return;
    68 
    69         if (msg->opt_fields == NULL)
    70             msg->opt_fields = field;
    71     }
    72 }
    73 
    74 static char * combine_short_and_long(const char *shortmsg, const char *longmsg)
    75 {
    76     char * ptext;
    77 
    78     assert(shortmsg);
    79     assert(strcmp(shortmsg, "pEp") != 0);
    80 
    81     if (longmsg == NULL)
    82         longmsg = "";
    83 
    84     ptext = calloc(1, strlen(shortmsg) + strlen(longmsg) + 12);
    85     assert(ptext);
    86     if (ptext == NULL)
    87         return NULL;
    88 
    89     strcpy(ptext, "Subject: ");
    90     strcat(ptext, shortmsg);
    91     strcat(ptext, "\n\n");
    92     strcat(ptext, longmsg);
    93 
    94     return ptext;
    95 }
    96 
    97 static int seperate_short_and_long(const char *src, char **shortmsg, char **longmsg)
    98 {
    99     char *_shortmsg = NULL;
   100     char *_longmsg = NULL;
   101 
   102     assert(src);
   103     assert(shortmsg);
   104     assert(longmsg);
   105 
   106     *shortmsg = NULL;
   107     *longmsg = NULL;
   108 
   109     if (strncasecmp(src, "subject: ", 9) == 0) {
   110         char *line_end = strchr(src, '\n');
   111 
   112         if (line_end == NULL) {
   113             _shortmsg = strdup(src + 9);
   114             assert(_shortmsg);
   115             if (_shortmsg == NULL)
   116                 goto enomem;
   117             // _longmsg = NULL;
   118         }
   119         else {
   120             size_t n = line_end - src;
   121 
   122             if (*(line_end - 1) == '\r')
   123                 _shortmsg = strndup(src + 9, n - 10);
   124             else
   125                 _shortmsg = strndup(src + 9, n - 9);
   126             assert(_shortmsg);
   127             if (_shortmsg == NULL)
   128                 goto enomem;
   129 
   130             while (*(src + n) && (*(src + n) == '\n' || *(src + n) == '\r'))
   131                 ++n;
   132 
   133             if (*(src + n)) {
   134                 _longmsg = strdup(src + n);
   135                 assert(_longmsg);
   136                 if (_longmsg == NULL)
   137                     goto enomem;
   138             }
   139         }
   140     }
   141     else {
   142         _shortmsg = strdup("");
   143         assert(_shortmsg);
   144         if (_shortmsg == NULL)
   145             goto enomem;
   146         _longmsg = strdup(src);
   147         assert(_longmsg);
   148         if (_longmsg == NULL)
   149             goto enomem;
   150     }
   151 
   152     *shortmsg = _shortmsg;
   153     *longmsg = _longmsg;
   154 
   155     return 0;
   156 
   157 enomem:
   158     free(_shortmsg);
   159     free(_longmsg);
   160 
   161     return -1;
   162 }
   163 
   164 static PEP_STATUS copy_fields(message *dst, const message *src)
   165 {
   166     assert(dst);
   167     assert(src);
   168 
   169     free_timestamp(dst->sent);
   170     dst->sent = NULL;
   171     if (src->sent) {
   172         dst->sent = timestamp_dup(src->sent);
   173         if (dst->sent == NULL)
   174             return PEP_OUT_OF_MEMORY;
   175     }
   176 
   177     free_timestamp(dst->recv);
   178     dst->recv = NULL;
   179     if (src->recv) {
   180         dst->recv = timestamp_dup(src->recv);
   181         if (dst->recv == NULL)
   182             return PEP_OUT_OF_MEMORY;
   183     }
   184 
   185     free_identity(dst->from);
   186     dst->from = NULL;
   187     if (src->from) {
   188         dst->from = identity_dup(src->from);
   189         if (dst->from == NULL)
   190             return PEP_OUT_OF_MEMORY;
   191     }
   192 
   193     free_identity_list(dst->to);
   194     dst->to = NULL;
   195     if (src->to && src->to->ident) {
   196         dst->to = identity_list_dup(src->to);
   197         if (dst->to == NULL)
   198             return PEP_OUT_OF_MEMORY;
   199     }
   200 
   201     free_identity(dst->recv_by);
   202     dst->recv_by = NULL;
   203     if (src->recv_by) {
   204         dst->recv_by = identity_dup(src->recv_by);
   205         if (dst->recv_by == NULL)
   206             return PEP_OUT_OF_MEMORY;
   207     }
   208 
   209     free_identity_list(dst->cc);
   210     dst->cc = NULL;
   211     if (src->cc && src->cc->ident) {
   212         dst->cc = identity_list_dup(src->cc);
   213         if (dst->cc == NULL)
   214             return PEP_OUT_OF_MEMORY;
   215     }
   216 
   217     free_identity_list(dst->bcc);
   218     dst->bcc = NULL;
   219     if (src->bcc && src->bcc->ident) {
   220         dst->bcc = identity_list_dup(src->bcc);
   221         if (dst->bcc == NULL)
   222             return PEP_OUT_OF_MEMORY;
   223     }
   224 
   225     free_identity_list(dst->reply_to);
   226     dst->reply_to = NULL;
   227     if (src->reply_to && src->reply_to->ident) {
   228         dst->reply_to = identity_list_dup(src->reply_to);
   229         if (dst->reply_to == NULL)
   230             return PEP_OUT_OF_MEMORY;
   231     }
   232 
   233     free_stringlist(dst->in_reply_to);
   234     dst->in_reply_to = NULL;
   235     if (src->in_reply_to && src->in_reply_to->value) {
   236         dst->in_reply_to = stringlist_dup(src->in_reply_to);
   237         if (dst->in_reply_to == NULL)
   238             return PEP_OUT_OF_MEMORY;
   239     }
   240 
   241     free_stringlist(dst->references);
   242     dst->references = NULL;
   243     if (src->references) {
   244         dst->references = stringlist_dup(src->references);
   245         if (dst->references == NULL)
   246             return PEP_OUT_OF_MEMORY;
   247     }
   248 
   249     free_stringlist(dst->keywords);
   250     dst->keywords = NULL;
   251     if (src->keywords && src->keywords->value) {
   252         dst->keywords = stringlist_dup(src->keywords);
   253         if (dst->keywords == NULL)
   254             return PEP_OUT_OF_MEMORY;
   255     }
   256 
   257     free(dst->comments);
   258     dst->comments = NULL;
   259     if (src->comments) {
   260         dst->comments = strdup(src->comments);
   261         assert(dst->comments);
   262         if (dst->comments == NULL)
   263             return PEP_OUT_OF_MEMORY;
   264     }
   265 
   266     return PEP_STATUS_OK;
   267 }
   268 
   269 static message * clone_to_empty_message(const message * src)
   270 {
   271     PEP_STATUS status;
   272     message * msg = NULL;
   273 
   274     assert(src);
   275 
   276     msg = calloc(1, sizeof(message));
   277     assert(msg);
   278     if (msg == NULL)
   279         goto enomem;
   280 
   281     msg->dir = src->dir;
   282 
   283     status = copy_fields(msg, src);
   284     if (status != PEP_STATUS_OK)
   285         goto enomem;
   286 
   287     return msg;
   288 
   289 enomem:
   290     free_message(msg);
   291     return NULL;
   292 }
   293 
   294 static PEP_STATUS encrypt_PGP_MIME(
   295     PEP_SESSION session,
   296     const message *src,
   297     stringlist_t *keys,
   298     message *dst
   299     )
   300 {
   301     PEP_STATUS status = PEP_STATUS_OK;
   302     bool free_ptext = false;
   303     char *ptext = NULL;
   304     char *ctext;
   305     char *_ctext = NULL;
   306     char *mimetext = NULL;
   307     size_t csize;
   308     assert(dst->longmsg == NULL);
   309     dst->enc_format = PEP_enc_PGP_MIME;
   310 
   311     if (src->shortmsg && strcmp(src->shortmsg, "pEp") != 0) {
   312         if (session->unencrypted_subject) {
   313             dst->shortmsg = strdup(src->shortmsg);
   314             assert(dst->shortmsg);
   315             if (dst->shortmsg == NULL)
   316                 goto enomem;
   317             ptext = src->longmsg;
   318         }
   319         else {
   320             ptext = combine_short_and_long(src->shortmsg, src->longmsg);
   321             if (ptext == NULL)
   322                 goto enomem;
   323             free_ptext = true;
   324         }
   325     }
   326     else if (src->longmsg) {
   327         ptext = src->longmsg;
   328     }
   329     else {
   330         ptext = "pEp";
   331     }
   332 
   333     message *_src = calloc(1, sizeof(message));
   334     assert(_src);
   335     if (_src == NULL)
   336         goto enomem;
   337     _src->longmsg = ptext;
   338     _src->longmsg_formatted = src->longmsg_formatted;
   339     _src->attachments = src->attachments;
   340     _src->enc_format = PEP_enc_none;
   341     status = mime_encode_message(_src, true, &mimetext);
   342     assert(status == PEP_STATUS_OK);
   343     if (free_ptext){
   344         free(ptext);
   345         free_ptext=0;
   346     }
   347     free(_src);
   348     assert(mimetext);
   349     if (mimetext == NULL)
   350         goto pep_error;
   351 
   352     status = encrypt_and_sign(session, keys, mimetext, strlen(mimetext),
   353         &ctext, &csize);
   354     free(mimetext);
   355     if (ctext == NULL)
   356         goto pep_error;
   357 
   358     dst->longmsg = strdup("this message was encrypted with p≡p "
   359         "https://pEp-project.org");
   360     assert(dst->longmsg);
   361     if (dst->longmsg == NULL)
   362         goto enomem;
   363 
   364     char *v = strdup("Version: 1");
   365     assert(v);
   366     if (v == NULL)
   367         goto enomem;
   368 
   369     bloblist_t *_a = new_bloblist(v, 11, "application/pgp-encrypted", NULL);
   370     if (_a == NULL)
   371         goto enomem;
   372     dst->attachments = _a;
   373 
   374     _ctext = malloc(csize);
   375     assert(_ctext);
   376     if (_ctext == NULL)
   377         goto enomem;
   378     memcpy(_ctext, ctext, csize);
   379 
   380     _a = bloblist_add(_a, _ctext, csize, "application/octet-stream",
   381         "msg.asc");
   382     if (_a == NULL)
   383         goto enomem;
   384 
   385     return PEP_STATUS_OK;
   386 
   387 enomem:
   388     status = PEP_OUT_OF_MEMORY;
   389 
   390 pep_error:
   391     if (free_ptext)
   392         free(ptext);
   393     free(_ctext);
   394     return status;
   395 }
   396 
   397 static PEP_STATUS encrypt_PGP_in_pieces(
   398     PEP_SESSION session,
   399     const message *src,
   400     stringlist_t *keys,
   401     message *dst
   402     )
   403 {
   404     PEP_STATUS status = PEP_STATUS_OK;
   405     char *ctext;
   406     size_t csize;
   407     char *ptext = NULL;
   408     bool free_ptext = false;
   409 
   410     assert(dst->longmsg == NULL);
   411     assert(dst->attachments == NULL);
   412 
   413     dst->enc_format = PEP_enc_pieces;
   414 
   415     if (src->shortmsg && src->shortmsg[0] && strcmp(src->shortmsg, "pEp") != 0) {
   416         if (session->unencrypted_subject) {
   417             dst->shortmsg = strdup(src->shortmsg);
   418             assert(dst->shortmsg);
   419             if (dst->shortmsg == NULL)
   420                 goto enomem;
   421             ptext = src->longmsg;
   422         }
   423         else {
   424             ptext = combine_short_and_long(src->shortmsg, src->longmsg);
   425             if (ptext == NULL)
   426                 goto enomem;
   427             free_ptext = true;
   428         }
   429 
   430         status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
   431             &csize);
   432         if (free_ptext)
   433             free(ptext);
   434         free_ptext = false;
   435         if (ctext) {
   436             dst->longmsg = strndup(ctext, csize);
   437             assert(dst->longmsg);
   438             if (dst->longmsg == NULL)
   439                 goto enomem;
   440         }
   441         else {
   442             goto pep_error;
   443         }
   444     }
   445     else if (src->longmsg && src->longmsg[0]) {
   446         ptext = src->longmsg;
   447         status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
   448             &csize);
   449         if (ctext) {
   450             dst->longmsg = strndup(ctext, csize);
   451             assert(dst->longmsg);
   452             if (dst->longmsg == NULL)
   453                 goto enomem;
   454         }
   455         else {
   456             goto pep_error;
   457         }
   458     }
   459     else {
   460         dst->longmsg = strdup("");
   461         assert(dst->longmsg);
   462         if (dst->longmsg == NULL)
   463             goto enomem;
   464     }
   465 
   466     if (src->longmsg_formatted && src->longmsg_formatted[0]) {
   467         ptext = src->longmsg_formatted;
   468         status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
   469             &csize);
   470         if (ctext) {
   471             char *_ctext = malloc(csize);
   472             assert(_ctext);
   473             if (_ctext == NULL)
   474                 goto enomem;
   475             memcpy(_ctext, ctext, csize);
   476 
   477             bloblist_t *_a = bloblist_add(dst->attachments, _ctext, csize,
   478                 "application/octet-stream", "PGPexch.htm.pgp");
   479             if (_a == NULL)
   480                 goto enomem;
   481             if (dst->attachments == NULL)
   482                 dst->attachments = _a;
   483         }
   484         else {
   485             goto pep_error;
   486         }
   487     }
   488 
   489     if (src->attachments) {
   490         if (dst->attachments == NULL) {
   491             dst->attachments = new_bloblist(NULL, 0, NULL, NULL);
   492             if (dst->attachments == NULL)
   493                 goto enomem;
   494         }
   495 
   496         bloblist_t *_s = src->attachments;
   497         bloblist_t *_d = dst->attachments;
   498 
   499         for (int n = 0; _s && _s->value; _s = _s->next) {
   500             size_t psize = _s->size;
   501             ptext = _s->value;
   502             status = encrypt_and_sign(session, keys, ptext, psize, &ctext,
   503                 &csize);
   504             if (ctext) {
   505                 char *filename = NULL;
   506 
   507                 if (_s->filename) {
   508                     size_t len = strlen(_s->filename);
   509                     filename = calloc(1, len + 5);
   510                     if (filename == NULL)
   511                         goto enomem;
   512 
   513                     strcpy(filename, _s->filename);
   514                     strcpy(filename + len, ".pgp");
   515                 }
   516                 else {
   517                     filename = calloc(1, 20);
   518                     if (filename == NULL)
   519                         goto enomem;
   520 
   521                     ++n;
   522                     n &= 0xffff;
   523                     snprintf(filename, 20, "Attachment%d.pgp", n);
   524                 }
   525 
   526                 char *_ctext = malloc(csize);
   527                 assert(_ctext);
   528                 if (_ctext == NULL)
   529                     goto enomem;
   530                 memcpy(_ctext, ctext, csize);
   531 
   532                 _d = bloblist_add(_d, _ctext, csize, "application/octet-stream",
   533                     filename);
   534                 if (_d == NULL)
   535                     goto enomem;
   536             }
   537             else {
   538                 goto pep_error;
   539             }
   540         }
   541     }
   542 
   543     return PEP_STATUS_OK;
   544 
   545 enomem:
   546     status = PEP_OUT_OF_MEMORY;
   547 
   548 pep_error:
   549     if (free_ptext)
   550         free(ptext);
   551     return status;
   552 }
   553 
   554 static char * keylist_to_string(const stringlist_t *keylist)
   555 {
   556     if (keylist) {
   557         size_t size = stringlist_length(keylist);
   558 
   559         const stringlist_t *_kl;
   560         for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
   561             size += strlen(_kl->value);
   562         }
   563 
   564         char *result = calloc(1, size);
   565         if (result == NULL)
   566             return NULL;
   567 
   568         char *_r = result;
   569         for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
   570             _r = stpcpy(_r, _kl->value);
   571             if (_kl->next && _kl->next->value)
   572                 _r = stpcpy(_r, ",");
   573         }
   574 
   575         return result;
   576     }
   577     else {
   578         return NULL;
   579     }
   580 }
   581 
   582 static const char * color_to_string(PEP_color color)
   583 {
   584     switch (color) {
   585     case PEP_rating_cannot_decrypt:
   586         return "cannot_decrypt";
   587     case PEP_rating_have_no_key:
   588         return "have_no_key";
   589     case PEP_rating_unencrypted:
   590         return "unencrypted";
   591     case PEP_rating_unencrypted_for_some:
   592         return "unencrypted_for_some";
   593     case PEP_rating_unreliable:
   594         return "unreliable";
   595     case PEP_rating_reliable:
   596         return "reliable";
   597     case PEP_rating_trusted:
   598         return "trusted";
   599     case PEP_rating_trusted_and_anonymized:
   600         return "trusted_and_anonymized";
   601     case PEP_rating_fully_anonymous:
   602         return "fully_anonymous";
   603     case PEP_rating_mistrust:
   604         return "mistrust";
   605     case PEP_rating_b0rken:
   606         return "b0rken";
   607     case PEP_rating_under_attack:
   608         return "unter_attack";
   609     default:
   610         return "undefined";
   611     }
   612 }
   613 
   614 static void decorate_message(
   615     message *msg,
   616     PEP_color color,
   617     stringlist_t *keylist
   618     )
   619 {
   620     assert(msg);
   621 
   622     add_opt_field(msg, "X-pEp-Version", "1.0");
   623     
   624     if (color != PEP_rating_undefined)
   625         add_opt_field(msg, "X-EncStatus", color_to_string(color));
   626 
   627     if (keylist) {
   628         char *_keylist = keylist_to_string(keylist);
   629         add_opt_field(msg, "X-KeyList", _keylist);
   630         free(_keylist);
   631     }
   632 }
   633 
   634 static PEP_color _rating(PEP_comm_type ct, PEP_color color)
   635 {
   636     if (ct == PEP_ct_unknown)
   637         return PEP_rating_undefined;
   638 
   639     else if (ct == PEP_ct_compromized)
   640         return PEP_rating_under_attack;
   641 
   642     else if (ct == PEP_ct_mistrusted)
   643         return PEP_rating_mistrust;
   644     
   645     if (color == PEP_rating_unencrypted_for_some)
   646         return PEP_rating_unencrypted_for_some;
   647 
   648     if (ct == PEP_ct_no_encryption || ct == PEP_ct_no_encrypted_channel ||
   649             ct == PEP_ct_my_key_not_included) {
   650         if (color > PEP_rating_unencrypted_for_some)
   651             return PEP_rating_unencrypted_for_some;
   652         else
   653             return PEP_rating_unencrypted;
   654     }
   655 
   656     if (color == PEP_rating_unencrypted)
   657         return PEP_rating_unencrypted_for_some;
   658 
   659     if (ct >= PEP_ct_confirmed_enc_anon)
   660         return PEP_rating_trusted_and_anonymized;
   661 
   662     else if (ct >= PEP_ct_strong_encryption)
   663         return PEP_rating_trusted;
   664 
   665     else if (ct >= PEP_ct_strong_but_unconfirmed && ct < PEP_ct_confirmed)
   666         return PEP_rating_reliable;
   667 
   668     else
   669         return PEP_rating_unreliable;
   670 }
   671 
   672 static bool is_encrypted_attachment(const bloblist_t *blob)
   673 {
   674     char *ext;
   675 
   676     assert(blob);
   677 
   678     if (blob->filename == NULL)
   679         return false;
   680 
   681     ext = strrchr(blob->filename, '.');
   682     if (ext == NULL)
   683         return false;
   684 
   685     if (strcmp(blob->mime_type, "application/octet-stream") == 0) {
   686         if (strcmp(ext, ".pgp") == 0 || strcmp(ext, ".gpg") == 0 ||
   687             strcmp(ext, ".asc") == 0)
   688             return true;
   689     }
   690     else if (strcmp(blob->mime_type, "text/plain") == 0) {
   691         if (strcmp(ext, ".asc") == 0)
   692             return true;
   693     }
   694 
   695     return false;
   696 }
   697 
   698 static bool is_encrypted_html_attachment(const bloblist_t *blob)
   699 {
   700     assert(blob);
   701     assert(blob->filename);
   702 
   703     if (strncmp(blob->filename, "PGPexch.htm.", 12) == 0) {
   704         if (strcmp(blob->filename + 11, ".pgp") == 0 ||
   705             strcmp(blob->filename + 11, ".asc") == 0)
   706             return true;
   707     }
   708 
   709     return false;
   710 }
   711 
   712 static char * without_double_ending(const char *filename)
   713 {
   714     char *ext;
   715 
   716     assert(filename);
   717 
   718     ext = strrchr(filename, '.');
   719     if (ext == NULL)
   720         return NULL;
   721 
   722     char *result = strndup(filename, ext - filename);
   723     assert(result);
   724     return result;
   725 }
   726 
   727 static PEP_color decrypt_color(PEP_STATUS status)
   728 {
   729     switch (status) {
   730     case PEP_UNENCRYPTED:
   731     case PEP_VERIFIED:
   732     case PEP_VERIFY_NO_KEY:
   733     case PEP_VERIFIED_AND_TRUSTED:
   734         return PEP_rating_unencrypted;
   735 
   736     case PEP_DECRYPTED:
   737         return PEP_rating_unreliable;
   738 
   739     case PEP_DECRYPTED_AND_VERIFIED:
   740         return PEP_rating_reliable;
   741 
   742     case PEP_DECRYPT_NO_KEY:
   743         return PEP_rating_have_no_key;
   744 
   745     case PEP_DECRYPT_WRONG_FORMAT:
   746     case PEP_CANNOT_DECRYPT_UNKNOWN:
   747         return PEP_rating_cannot_decrypt;
   748 
   749     default:
   750         return PEP_rating_undefined;
   751     }
   752 }
   753 
   754 static PEP_color key_color(PEP_SESSION session, const char *fpr)
   755 {
   756     PEP_comm_type comm_type = PEP_ct_unknown;
   757 
   758     assert(session);
   759     assert(fpr);
   760 
   761     PEP_STATUS status = get_key_rating(session, fpr, &comm_type);
   762     if (status != PEP_STATUS_OK)
   763         return PEP_rating_undefined;
   764 
   765     return _rating(comm_type, PEP_rating_undefined);
   766 }
   767 
   768 static PEP_color keylist_color(PEP_SESSION session, stringlist_t *keylist)
   769 {
   770     PEP_color color = PEP_rating_reliable;
   771 
   772     assert(keylist && keylist->value);
   773     if (keylist == NULL || keylist->value == NULL)
   774         return PEP_rating_undefined;
   775 
   776     stringlist_t *_kl;
   777     for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
   778         PEP_comm_type ct;
   779         PEP_STATUS status;
   780 
   781         PEP_color _color = key_color(session, _kl->value);
   782         if (_color <= PEP_rating_mistrust)
   783             return _color;
   784 
   785         if (color == PEP_rating_undefined)
   786             color = _color;
   787 
   788         if (_color >= PEP_rating_reliable) {
   789             status = least_trust(session, _kl->value, &ct);
   790             if (status != PEP_STATUS_OK)
   791                 return PEP_rating_undefined;
   792             if (ct == PEP_ct_unknown)
   793                 color = PEP_rating_unencrypted_for_some;
   794             else
   795                 color = _rating(ct, color);
   796         }
   797         else if (_color == PEP_rating_unencrypted) {
   798             if (color > PEP_rating_unencrypted_for_some)
   799                 color = PEP_rating_unencrypted_for_some;
   800         }
   801     }
   802 
   803     return color;
   804 }
   805 
   806 static PEP_comm_type _get_comm_type(
   807     PEP_SESSION session,
   808     PEP_comm_type max_comm_type,
   809     pEp_identity *ident
   810     )
   811 {
   812     PEP_STATUS status = update_identity(session, ident);
   813 
   814     if (max_comm_type == PEP_ct_compromized)
   815         return PEP_ct_compromized;
   816     
   817     if (max_comm_type == PEP_ct_mistrusted)
   818         return PEP_ct_mistrusted;
   819 
   820     if (status == PEP_STATUS_OK) {
   821         if (ident->comm_type == PEP_ct_compromized)
   822             return PEP_ct_compromized;
   823         else if (ident->comm_type == PEP_ct_mistrusted)
   824             return PEP_ct_mistrusted;
   825         else
   826             return MIN(max_comm_type, ident->comm_type);
   827     }
   828     else {
   829         return PEP_ct_unknown;
   830     }
   831 }
   832 
   833 static void free_bl_entry(bloblist_t *bl)
   834 {
   835     if (bl) {
   836         free(bl->value);
   837         free(bl->mime_type);
   838         free(bl->filename);
   839         free(bl);
   840     }
   841 }
   842 
   843 static bool is_key(const bloblist_t *bl)
   844 {
   845     return (// workaround for Apple Mail bugs
   846             (is_mime_type(bl, "application/x-apple-msg-attachment") &&
   847              is_fileending(bl, ".asc")) ||
   848             // as binary, by file name
   849             ((bl->mime_type == NULL ||
   850               is_mime_type(bl, "application/octet-stream")) &&
   851              (is_fileending(bl, ".pgp") || is_fileending(bl, ".gpg") ||
   852                     is_fileending(bl, ".key") || is_fileending(bl, ".asc"))) ||
   853             // explicit mime type 
   854             is_mime_type(bl, "application/pgp-keys") ||
   855             // as text, by file name
   856             (is_mime_type(bl, "text/plain") &&
   857              (is_fileending(bl, ".pgp") || is_fileending(bl, ".gpg") ||
   858                     is_fileending(bl, ".key") || is_fileending(bl, ".asc")))
   859            );
   860 }
   861 
   862 static void remove_attached_keys(message *msg)
   863 {
   864     if (msg) {
   865         bloblist_t *last = NULL;
   866         for (bloblist_t *bl = msg->attachments; bl && bl->value; ) {
   867             bloblist_t *next = bl->next;
   868 
   869             if (is_key(bl)) {
   870                 if (last) {
   871                     last->next = next;
   872                 }
   873                 else {
   874                     msg->attachments = next;
   875                 }
   876                 free_bl_entry(bl);
   877             }
   878             else {
   879                 last = bl;
   880             }
   881             bl = next;
   882         }
   883     }
   884 }
   885 
   886 bool import_attached_keys(
   887         PEP_SESSION session, 
   888         const message *msg,
   889         identity_list **private_idents
   890     )
   891 {
   892     assert(session);
   893     assert(msg);
   894 
   895     bool remove = false;
   896 
   897     bloblist_t *bl;
   898     for (bl = msg->attachments; bl && bl->value; bl = bl->next) {
   899         assert(bl && bl->value && bl->size);
   900 
   901         if (is_key(bl)) 
   902         {
   903             import_key(session, bl->value, bl->size, private_idents);
   904             remove = true;
   905         }
   906     }
   907     return remove;
   908 }
   909 
   910 
   911 PEP_STATUS _attach_key(PEP_SESSION session, const char* fpr, message *msg)
   912 {
   913     char *keydata;
   914     size_t size;
   915     bloblist_t *bl;
   916 
   917     PEP_STATUS status = export_key(session, fpr, &keydata, &size);
   918     assert(status == PEP_STATUS_OK);
   919     if (status != PEP_STATUS_OK)
   920         return status;
   921     assert(size);
   922     
   923     bl = bloblist_add(msg->attachments, keydata, size, "application/pgp-keys",
   924                       "pEpkey.asc");
   925     
   926     if (msg->attachments == NULL && bl)
   927         msg->attachments = bl;
   928 
   929     return PEP_STATUS_OK;
   930 }
   931 
   932 #define ONE_WEEK (7*24*3600)
   933 
   934 void attach_own_key(PEP_SESSION session, message *msg)
   935 {
   936     assert(session);
   937     assert(msg);
   938 
   939     if (msg->dir == PEP_dir_incoming)
   940         return;
   941 
   942     assert(msg->from && msg->from->fpr);
   943     if (msg->from == NULL || msg->from->fpr == NULL)
   944         return;
   945 
   946     if(_attach_key(session, msg->from->fpr, msg) != PEP_STATUS_OK)
   947         return;
   948     
   949     char *revoked_fpr = NULL;
   950     uint64_t revocation_date = 0;
   951     
   952     if(get_revoked(session, msg->from->fpr,
   953                    &revoked_fpr, &revocation_date) == PEP_STATUS_OK &&
   954        revoked_fpr != NULL)
   955     {
   956         time_t now = time(NULL);
   957         
   958         if (now < (time_t)revocation_date + ONE_WEEK)
   959         {
   960             _attach_key(session, revoked_fpr, msg);
   961         }
   962     }
   963     free(revoked_fpr);
   964 }
   965 
   966 PEP_cryptotech determine_encryption_format(message *msg)
   967 {
   968     assert(msg);
   969 
   970     if (is_PGP_message_text(msg->longmsg)) {
   971         msg->enc_format = PEP_enc_pieces;
   972         return PEP_crypt_OpenPGP;
   973     }
   974     else if (msg->attachments && msg->attachments->next &&
   975             is_mime_type(msg->attachments, "application/pgp-encrypted") &&
   976             is_PGP_message_text(msg->attachments->next->value)
   977         ) {
   978         msg->enc_format = PEP_enc_PGP_MIME;
   979         return PEP_crypt_OpenPGP;
   980     }
   981     else {
   982         msg->enc_format = PEP_enc_none;
   983         return PEP_crypt_none;
   984     }
   985 }
   986 
   987 DYNAMIC_API PEP_STATUS encrypt_message(
   988         PEP_SESSION session,
   989         message *src,
   990         stringlist_t * extra,
   991         message **dst,
   992         PEP_enc_format enc_format
   993     )
   994 {
   995     PEP_STATUS status = PEP_STATUS_OK;
   996     message * msg = NULL;
   997     stringlist_t * keys = NULL;
   998 
   999     assert(session);
  1000     assert(src);
  1001     assert(dst);
  1002     assert(enc_format != PEP_enc_none);
  1003 
  1004     if (!(session && src && dst && enc_format != PEP_enc_none))
  1005         return PEP_ILLEGAL_VALUE;
  1006 
  1007     if (src->dir == PEP_dir_incoming)
  1008         return PEP_ILLEGAL_VALUE;
  1009     
  1010     determine_encryption_format(src);
  1011     if (src->enc_format != PEP_enc_none)
  1012         return PEP_ILLEGAL_VALUE;
  1013 
  1014     *dst = NULL;
  1015 
  1016     status = myself(session, src->from);
  1017     if (status != PEP_STATUS_OK)
  1018         goto pep_error;
  1019 
  1020     keys = new_stringlist(src->from->fpr);
  1021     if (keys == NULL)
  1022         goto enomem;
  1023 
  1024     stringlist_t *_k = keys;
  1025 
  1026     if (extra) {
  1027         _k = stringlist_append(_k, extra);
  1028         if (_k == NULL)
  1029             goto enomem;
  1030     }
  1031 
  1032     bool dest_keys_found = true;
  1033     PEP_comm_type max_comm_type = PEP_ct_pEp;
  1034 
  1035     identity_list * _il;
  1036     
  1037     if ((_il = src->bcc) && _il->ident)
  1038     {
  1039         // BCC limited support:
  1040         //     - App splits mails with BCC in multiple mails.
  1041         //     - Each email is encrypted separately
  1042         
  1043         if(_il->next || src->to || src->cc)
  1044         {
  1045             // Only one Bcc with no other recipient allowed for now
  1046             return PEP_ILLEGAL_VALUE;
  1047         }
  1048         
  1049         PEP_STATUS _status = update_identity(session, _il->ident);
  1050         if (_status != PEP_STATUS_OK) {
  1051             status = _status;
  1052             goto pep_error;
  1053         }
  1054         
  1055         if (_il->ident->fpr && _il->ident->fpr[0]) {
  1056             _k = stringlist_add(_k, _il->ident->fpr);
  1057             if (_k == NULL)
  1058                 goto enomem;
  1059             max_comm_type = _get_comm_type(session, max_comm_type,
  1060                                            _il->ident);
  1061         }
  1062         else {
  1063             dest_keys_found = false;
  1064             status = PEP_KEY_NOT_FOUND;
  1065         }        
  1066     }
  1067     else
  1068     {
  1069         for (_il = src->to; _il && _il->ident; _il = _il->next) {
  1070             PEP_STATUS _status = update_identity(session, _il->ident);
  1071             if (_status != PEP_STATUS_OK) {
  1072                 status = _status;
  1073                 goto pep_error;
  1074             }
  1075 
  1076             if (_il->ident->fpr && _il->ident->fpr[0]) {
  1077                 _k = stringlist_add(_k, _il->ident->fpr);
  1078                 if (_k == NULL)
  1079                     goto enomem;
  1080                 max_comm_type = _get_comm_type(session, max_comm_type,
  1081                                                _il->ident);
  1082             }
  1083             else {
  1084                 dest_keys_found = false;
  1085                 status = PEP_KEY_NOT_FOUND;
  1086             }
  1087         }
  1088 
  1089         for (_il = src->cc; _il && _il->ident; _il = _il->next) {
  1090             PEP_STATUS _status = update_identity(session, _il->ident);
  1091             if (_status != PEP_STATUS_OK)
  1092             {
  1093                 status = _status;
  1094                 goto pep_error;
  1095             }
  1096 
  1097             if (_il->ident->fpr && _il->ident->fpr[0]) {
  1098                 _k = stringlist_add(_k, _il->ident->fpr);
  1099                 if (_k == NULL)
  1100                     goto enomem;
  1101                 max_comm_type = _get_comm_type(session, max_comm_type,
  1102                                                _il->ident);
  1103             }
  1104             else {
  1105                 dest_keys_found = false;
  1106                 status = PEP_KEY_NOT_FOUND;
  1107             }
  1108         }
  1109     }
  1110     
  1111     if (!dest_keys_found ||
  1112         stringlist_length(keys) == 0 ||
  1113         _rating(max_comm_type,
  1114                 PEP_rating_undefined) < PEP_rating_reliable)
  1115     {
  1116         free_stringlist(keys);
  1117         if (!session->passive_mode)
  1118             attach_own_key(session, src);
  1119         return PEP_UNENCRYPTED;
  1120     }
  1121     else {
  1122         msg = clone_to_empty_message(src);
  1123         if (msg == NULL)
  1124             goto enomem;
  1125 
  1126         attach_own_key(session, src);
  1127 
  1128         switch (enc_format) {
  1129         case PEP_enc_PGP_MIME:
  1130         case PEP_enc_PEP: // BUG: should be implemented extra
  1131             status = encrypt_PGP_MIME(session, src, keys, msg);
  1132             break;
  1133 
  1134         case PEP_enc_pieces:
  1135             status = encrypt_PGP_in_pieces(session, src, keys, msg);
  1136             break;
  1137 
  1138         /* case PEP_enc_PEP:
  1139             // TODO: implement
  1140             NOT_IMPLEMENTED */
  1141 
  1142         default:
  1143             assert(0);
  1144             status = PEP_ILLEGAL_VALUE;
  1145             goto pep_error;
  1146         }
  1147         
  1148         if (status == PEP_OUT_OF_MEMORY)
  1149             goto enomem;
  1150         
  1151         if (status != PEP_STATUS_OK)
  1152             goto pep_error;
  1153     }
  1154 
  1155     free_stringlist(keys);
  1156 
  1157     if (msg && msg->shortmsg == NULL) {
  1158         msg->shortmsg = strdup("pEp");
  1159         assert(msg->shortmsg);
  1160     }
  1161 
  1162     if (msg)
  1163         decorate_message(msg, PEP_rating_undefined, NULL);
  1164 
  1165     *dst = msg;
  1166     return status;
  1167 
  1168 enomem:
  1169     status = PEP_OUT_OF_MEMORY;
  1170 
  1171 pep_error:
  1172     free_stringlist(keys);
  1173     free_message(msg);
  1174 
  1175     return status;
  1176 }
  1177 
  1178 DYNAMIC_API PEP_STATUS decrypt_message(
  1179         PEP_SESSION session,
  1180         message *src,
  1181         message **dst,
  1182         stringlist_t **keylist,
  1183         PEP_color *color,
  1184         PEP_decrypt_flags_t *flags 
  1185     )
  1186 {
  1187     PEP_STATUS status = PEP_STATUS_OK;
  1188     PEP_STATUS decrypt_status = PEP_CANNOT_DECRYPT_UNKNOWN;
  1189     message *msg = NULL;
  1190     char *ctext;
  1191     size_t csize;
  1192     char *ptext = NULL;
  1193     size_t psize;
  1194     stringlist_t *_keylist = NULL;
  1195 
  1196     assert(session);
  1197     assert(src);
  1198     assert(dst);
  1199     assert(keylist);
  1200     assert(color);
  1201 
  1202     if (!(session && src && dst && keylist && color))
  1203         return PEP_ILLEGAL_VALUE;
  1204 
  1205     // Private key in unencrypted mail are ignored -> NULL
  1206     bool imported_keys = import_attached_keys(session, src, NULL);
  1207 
  1208     // Update src->from in case we just imported a key
  1209     // we would need to check signature
  1210     if(src->from && src->from->user_id && src->from->address)
  1211         update_identity(session, src->from);
  1212 
  1213     PEP_cryptotech crypto = determine_encryption_format(src);
  1214 
  1215     *dst = NULL;
  1216     *keylist = NULL;
  1217     *color = PEP_rating_undefined;
  1218  
  1219     switch (src->enc_format) {
  1220         case PEP_enc_none:
  1221             *color = PEP_rating_unencrypted;
  1222             if (imported_keys)
  1223                 remove_attached_keys(src);
  1224             return PEP_UNENCRYPTED;
  1225 
  1226         case PEP_enc_PGP_MIME:
  1227             ctext = src->attachments->next->value;
  1228             csize = src->attachments->next->size;
  1229             break;
  1230 
  1231         case PEP_enc_pieces:
  1232             ctext = src->longmsg;
  1233             csize = strlen(ctext);
  1234             break;
  1235 
  1236         default:
  1237             NOT_IMPLEMENTED
  1238     }
  1239     status = cryptotech[crypto].decrypt_and_verify(session, ctext,
  1240                                                    csize, &ptext, &psize, &_keylist);
  1241     if (status > PEP_CANNOT_DECRYPT_UNKNOWN)
  1242         goto pep_error;
  1243 
  1244     decrypt_status = status;
  1245 
  1246     char *imported_private_key_address = NULL; 
  1247 
  1248     if (ptext) {
  1249         switch (src->enc_format) {
  1250             case PEP_enc_PGP_MIME:
  1251                 status = mime_decode_message(ptext, psize, &msg);
  1252                 if (status != PEP_STATUS_OK)
  1253                     goto pep_error;
  1254                 break;
  1255 
  1256             case PEP_enc_pieces:
  1257                 msg = clone_to_empty_message(src);
  1258                 if (msg == NULL)
  1259                     goto enomem;
  1260 
  1261                 msg->longmsg = strdup(ptext);
  1262                 assert(msg->longmsg);
  1263                 if (msg->longmsg == NULL)
  1264                     goto enomem;
  1265 
  1266                 bloblist_t *_m = msg->attachments;
  1267                 if (_m == NULL && src->attachments && src->attachments->value) {
  1268                     msg->attachments = new_bloblist(NULL, 0, NULL, NULL);
  1269                     _m = msg->attachments;
  1270                 }
  1271 
  1272                 bloblist_t *_s;
  1273                 for (_s = src->attachments; _s && _s->value; _s = _s->next) {
  1274                     if (is_encrypted_attachment(_s)) {
  1275                         stringlist_t *_keylist = NULL;
  1276                         char *attctext;
  1277                         size_t attcsize;
  1278 
  1279                         attctext = _s->value;
  1280                         attcsize = _s->size;
  1281 
  1282                         status = decrypt_and_verify(session, attctext, attcsize,
  1283                                 &ptext, &psize, &_keylist);
  1284                         free_stringlist(_keylist);
  1285 
  1286                         if (ptext) {
  1287                             if (is_encrypted_html_attachment(_s)) {
  1288                                 msg->longmsg_formatted = strdup(ptext);
  1289                                 assert(msg->longmsg_formatted);
  1290                                 if (msg->longmsg_formatted == NULL)
  1291                                     goto pep_error;
  1292                             }
  1293                             else {
  1294                                 char * mime_type = "application/octet-stream";
  1295                                 char * filename =
  1296                                     without_double_ending(_s->filename);
  1297                                 if (filename == NULL)
  1298                                     goto enomem;
  1299 
  1300                                 char *_ptext = malloc(psize);
  1301                                 assert(_ptext);
  1302                                 if (_ptext == NULL)
  1303                                     goto enomem;
  1304                                 memcpy(_ptext, ptext, psize);
  1305 
  1306                                 _m = bloblist_add(_m, _ptext, psize, mime_type,
  1307                                     filename);
  1308                                 if (_m == NULL)
  1309                                     goto enomem;
  1310 
  1311                                 if (msg->attachments == NULL)
  1312                                     msg->attachments = _m;
  1313                             }
  1314                         }
  1315                         else {
  1316                             char *copy = malloc(_s->size);
  1317                             assert(copy);
  1318                             if (copy == NULL)
  1319                                 goto enomem;
  1320                             memcpy(copy, _s->value, _s->size);
  1321                             _m = bloblist_add(_m, copy, _s->size, _s->mime_type, _s->filename);
  1322                             if (_m == NULL)
  1323                                 goto enomem;
  1324                         }
  1325                     }
  1326                     else {
  1327                         char *copy = malloc(_s->size);
  1328                         assert(copy);
  1329                         if (copy == NULL)
  1330                             goto enomem;
  1331                         memcpy(copy, _s->value, _s->size);
  1332                         _m = bloblist_add(_m, copy, _s->size, _s->mime_type, _s->filename);
  1333                         if (_m == NULL)
  1334                             goto enomem;
  1335                     }
  1336                 }
  1337 
  1338                 break;
  1339 
  1340             default:
  1341                 // BUG: must implement more
  1342                 NOT_IMPLEMENTED
  1343         }
  1344         
  1345         switch (src->enc_format) {
  1346             case PEP_enc_PGP_MIME:
  1347             case PEP_enc_pieces:
  1348                 status = copy_fields(msg, src);
  1349                 if (status != PEP_STATUS_OK)
  1350                     goto pep_error;
  1351 
  1352                 if (src->shortmsg == NULL || strcmp(src->shortmsg, "pEp") == 0)
  1353                 {
  1354                     char * shortmsg;
  1355                     char * longmsg;
  1356 
  1357                     int r = seperate_short_and_long(msg->longmsg, &shortmsg,
  1358                             &longmsg);
  1359                     if (r == -1)
  1360                         goto enomem;
  1361 
  1362                     free(msg->shortmsg);
  1363                     free(msg->longmsg);
  1364 
  1365                     msg->shortmsg = shortmsg;
  1366                     msg->longmsg = longmsg;
  1367                 }
  1368                 else {
  1369                     msg->shortmsg = strdup(src->shortmsg);
  1370                     assert(msg->shortmsg);
  1371                     if (msg->shortmsg == NULL)
  1372                         goto enomem;
  1373                 }
  1374                 break;
  1375 
  1376             default:
  1377                 // BUG: must implement more
  1378                 NOT_IMPLEMENTED
  1379         }
  1380        
  1381         // check for private key in decrypted message attachement while inporting
  1382         identity_list *private_il = NULL;
  1383         imported_keys = import_attached_keys(session, msg, &private_il);
  1384         if (private_il && 
  1385             identity_list_length(private_il) == 1 &&
  1386             private_il->ident->address)
  1387         {
  1388             imported_private_key_address = 
  1389                 strdup(private_il->ident->address);
  1390         }
  1391         free_identity_list(private_il);
  1392          
  1393         if(decrypt_status == PEP_DECRYPTED){
  1394 
  1395             // TODO optimize if import_attached_keys didn't import any key
  1396             
  1397             // In case message did decrypt, but no valid signature could be found
  1398             // then retry decrypt+verify after importing key.
  1399 
  1400             // Update msg->from in case we just imported a key
  1401             // we would need to check signature
  1402             if(msg->from && msg->from->user_id && msg->from->address)
  1403                  update_identity(session, msg->from);
  1404             
  1405             char *re_ptext = NULL;
  1406             size_t re_psize;
  1407             
  1408             free_stringlist(_keylist);
  1409             _keylist = NULL;
  1410 
  1411             status = cryptotech[crypto].decrypt_and_verify(session, ctext,
  1412                 csize, &re_ptext, &re_psize, &_keylist);
  1413             
  1414             if (re_ptext)
  1415                 free(re_ptext);
  1416             
  1417             if (status > PEP_CANNOT_DECRYPT_UNKNOWN)
  1418                 goto pep_error;
  1419             
  1420             decrypt_status = status;
  1421         }
  1422         
  1423         *color = decrypt_color(decrypt_status);
  1424         
  1425         if (*color > PEP_rating_mistrust) {
  1426             PEP_color kl_color = PEP_rating_undefined;
  1427             
  1428             if (_keylist)
  1429                 kl_color = keylist_color(session, _keylist);
  1430             
  1431             if (kl_color <= PEP_rating_mistrust) {
  1432                 *color = kl_color;
  1433             }
  1434             else if (*color >= PEP_rating_reliable &&
  1435                      kl_color < PEP_rating_reliable) {
  1436                 *color = PEP_rating_unreliable;
  1437             }
  1438             else if (*color >= PEP_rating_reliable &&
  1439                      kl_color >= PEP_rating_reliable) {
  1440                 if (!(src->from && src->from->user_id && src->from->user_id[0])) {
  1441                     *color = PEP_rating_unreliable;
  1442                 }
  1443                 else {
  1444                     char *fpr = _keylist->value;
  1445                     pEp_identity *_from = new_identity(src->from->address, fpr,
  1446                                                        src->from->user_id, src->from->username);
  1447                     if (_from == NULL)
  1448                         goto enomem;
  1449                     status = update_identity(session, _from);
  1450                     if (_from->comm_type != PEP_ct_unknown)
  1451                         *color = _rating(_from->comm_type, PEP_rating_undefined);
  1452                     free_identity(_from);
  1453                     if (status != PEP_STATUS_OK)
  1454                         goto pep_error;
  1455                 }
  1456             }
  1457         }
  1458     }
  1459         
  1460     // Case of own key imported from own trusted message
  1461     if (// Message have been reliably decrypted 
  1462         msg &&
  1463         *color >= PEP_rating_green &&
  1464         imported_private_key_address &&
  1465         // to is [own]
  1466         msg->to->ident->user_id &&
  1467         strcmp(msg->to->ident->user_id, PEP_OWN_USERID) == 0 
  1468         )
  1469     {
  1470         *flags &= PEP_decrypt_flag_own_private_key;
  1471     }
  1472 
  1473     free(imported_private_key_address);
  1474 
  1475     if (msg){
  1476         decorate_message(msg, *color, _keylist);
  1477         if (imported_keys)
  1478             remove_attached_keys(msg);
  1479     }
  1480 
  1481     *dst = msg;
  1482     *keylist = _keylist;
  1483 
  1484     return PEP_STATUS_OK;
  1485 
  1486 enomem:
  1487     status = PEP_OUT_OF_MEMORY;
  1488 
  1489 pep_error:
  1490     free(imported_private_key_address);
  1491     free_message(msg);
  1492     free_stringlist(_keylist);
  1493 
  1494     return status;
  1495 }
  1496 
  1497 DYNAMIC_API PEP_STATUS own_message_private_key_details(
  1498         PEP_SESSION session,
  1499         message *msg,
  1500         pEp_identity **ident 
  1501     )
  1502 {
  1503     PEP_STATUS status = PEP_STATUS_OK;
  1504     assert(session);
  1505     assert(msg);
  1506     assert(ident);
  1507 
  1508     if (!(session && msg && ident))
  1509         return PEP_ILLEGAL_VALUE;
  1510 
  1511     message *dst; 
  1512     stringlist_t *keylist;
  1513     PEP_color color;
  1514     PEP_decrypt_flags_t flags; 
  1515 
  1516     *ident = NULL;
  1517 
  1518     status = decrypt_message(session, msg,  &dst, &keylist, &color, &flags);
  1519 
  1520     if (status == PEP_STATUS_OK &&
  1521         flags & PEP_decrypt_flag_own_private_key)
  1522     {
  1523         identity_list *private_il = NULL;
  1524         import_attached_keys(session, msg, &private_il);
  1525 
  1526         if (private_il && 
  1527             identity_list_length(private_il) == 1 &&
  1528             private_il->ident->address)
  1529         {
  1530             *ident = identity_dup(private_il->ident);
  1531         }
  1532         free_identity_list(private_il);
  1533     }
  1534 
  1535     return status;
  1536 }
  1537 
  1538 DYNAMIC_API PEP_STATUS outgoing_message_color(
  1539         PEP_SESSION session,
  1540         message *msg,
  1541         PEP_color *color
  1542     )
  1543 {
  1544     PEP_STATUS status = PEP_STATUS_OK;
  1545     PEP_comm_type max_comm_type = PEP_ct_pEp;
  1546     bool comm_type_determined = false;
  1547     identity_list * il;
  1548 
  1549     assert(session);
  1550     assert(msg);
  1551     assert(msg->from);
  1552     assert(msg->dir == PEP_dir_outgoing);
  1553     assert(color);
  1554 
  1555     if (!(session && msg && color))
  1556         return PEP_ILLEGAL_VALUE;
  1557 
  1558     if (msg->from == NULL || msg->dir != PEP_dir_outgoing)
  1559         return PEP_ILLEGAL_VALUE;
  1560 
  1561     *color = PEP_rating_undefined;
  1562 
  1563     status = myself(session, msg->from);
  1564     if (status != PEP_STATUS_OK)
  1565         return status;
  1566 
  1567     for (il = msg->to; il != NULL; il = il->next)
  1568     {
  1569         if (il->ident)
  1570         {
  1571             update_identity(session, il->ident);
  1572             max_comm_type = _get_comm_type(session, max_comm_type,
  1573                     il->ident);
  1574             comm_type_determined = true;
  1575         }
  1576     }
  1577 
  1578     for (il = msg->cc; il != NULL; il = il->next)
  1579     {
  1580         if (il->ident)
  1581         {
  1582             update_identity(session, il->ident);
  1583             max_comm_type = _get_comm_type(session, max_comm_type,
  1584                     il->ident);
  1585             comm_type_determined = true;
  1586         }
  1587     }
  1588         
  1589     for (il = msg->bcc; il != NULL; il = il->next)
  1590     {
  1591         if (il->ident)
  1592         {
  1593             update_identity(session, il->ident);
  1594             max_comm_type = _get_comm_type(session, max_comm_type,
  1595                                            il->ident);
  1596             comm_type_determined = true;
  1597         }
  1598     }
  1599 
  1600     if (comm_type_determined == false)
  1601         *color = PEP_rating_undefined;
  1602     else
  1603         *color = MAX(_rating(max_comm_type, PEP_rating_undefined),
  1604                 PEP_rating_unencrypted);
  1605 
  1606     return PEP_STATUS_OK;
  1607 }
  1608 
  1609 DYNAMIC_API PEP_STATUS identity_color(
  1610         PEP_SESSION session,
  1611         pEp_identity *ident,
  1612         PEP_color *color
  1613     )
  1614 {
  1615     PEP_STATUS status = PEP_STATUS_OK;
  1616 
  1617     assert(session);
  1618     assert(ident);
  1619     assert(color);
  1620 
  1621     if (!(session && ident && color))
  1622         return PEP_ILLEGAL_VALUE;
  1623 
  1624     if (ident->me)
  1625         status = myself(session, ident);
  1626     else
  1627         status = update_identity(session, ident);
  1628 
  1629     if (status == PEP_STATUS_OK)
  1630         *color = _rating(ident->comm_type, PEP_rating_undefined);
  1631 
  1632     return status;
  1633 }
  1634 
  1635 DYNAMIC_API PEP_STATUS get_binary_path(PEP_cryptotech tech, const char **path)
  1636 {
  1637     PEP_STATUS status = PEP_STATUS_OK;
  1638 
  1639     assert(path);
  1640     if (path == NULL)
  1641         return PEP_ILLEGAL_VALUE;
  1642 
  1643     if (cryptotech[tech].binary_path == NULL)
  1644         *path = NULL;
  1645     else
  1646         status = cryptotech[tech].binary_path(path);
  1647 
  1648     return status;
  1649 }
  1650