src/message_api.c
author Volker Birk <vb@pep-project.org>
Sun, 03 May 2015 16:40:28 +0200
changeset 235 8b7468ca8034
parent 232 3d44d9bb18e5
child 236 154a7077dbb7
permissions -rw-r--r--
import attached keys automatically in Message API
     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 
    15 
    16 static bool string_equality(const char *s1, const char *s2)
    17 {
    18     if (s1 == NULL || s2 == NULL)
    19         return false;
    20 
    21     assert(s1 && s2);
    22 
    23     return strcmp(s1, s2) == 0;
    24 }
    25 
    26 static bool is_mime_type(const bloblist_t *bl, const char *mt)
    27 {
    28     assert(mt);
    29 
    30     return bl && string_equality(bl->mime_type, mt);
    31 }
    32 
    33 static bool is_fileending(const bloblist_t *bl, const char *fe)
    34 {
    35     assert(fe);
    36 
    37     if (bl == NULL || bl->filename == NULL)
    38         return false;
    39 
    40     assert(bl && bl->filename);
    41 
    42     size_t fe_len = strlen(fe);
    43     size_t fn_len = strlen(bl->filename);
    44 
    45     if (fn_len <= fe_len)
    46         return false;
    47 
    48     assert(fn_len > fe_len);
    49 
    50     return strcmp(bl->filename + (fn_len - fe_len), fe) == 0;
    51 }
    52 
    53 void import_attached_keys(PEP_SESSION session, const message *msg)
    54 {
    55     assert(msg);
    56 
    57     bloblist_t *bl;
    58     for (bl = msg->attachments; bl && bl->data; bl = bl->next) {
    59         assert(bl && bl->data && bl->size);
    60 
    61         if (bl->mime_type == NULL ||
    62                     is_mime_type(bl, "application/octet-stream")) {
    63             if (is_fileending(bl, ".pgp") || is_fileending(bl, ".gpg") ||
    64                     is_fileending(bl, ".key") ||
    65                     string_equality(bl->filename, "key.asc"))
    66                 import_key(session, bl->data, bl->size);
    67         }
    68         else if (is_mime_type(bl, "application/pgp-keys")) {
    69             import_key(session, bl->data, bl->size);
    70         }
    71         else if (is_mime_type(bl, "text/plain")) {
    72             if (is_fileending(bl, ".pgp") || is_fileending(bl, ".gpg") ||
    73                     is_fileending(bl, ".key") || is_fileending(bl, ".asc"))
    74                 import_key(session, bl->data, bl->size);
    75         }
    76     }
    77 }
    78 
    79 static char * combine_short_and_long(const char *shortmsg, const char *longmsg)
    80 {
    81     char * ptext;
    82 
    83     assert(shortmsg);
    84     assert(strcmp(shortmsg, "pEp") != 0);
    85 
    86     if (longmsg == NULL)
    87         longmsg = "";
    88 
    89     ptext = calloc(1, strlen(shortmsg) + strlen(longmsg) + 12);
    90     assert(ptext);
    91     if (ptext == NULL)
    92         return NULL;
    93 
    94     strcpy(ptext, "Subject: ");
    95     strcat(ptext, shortmsg);
    96     strcat(ptext, "\n\n");
    97     strcat(ptext, longmsg);
    98 
    99     return ptext;
   100 }
   101 
   102 static int seperate_short_and_long(const char *src, char **shortmsg, char **longmsg)
   103 {
   104     char *_shortmsg = NULL;
   105     char *_longmsg = NULL;
   106 
   107     assert(src);
   108     assert(shortmsg);
   109     assert(longmsg);
   110 
   111     *shortmsg = NULL;
   112     *longmsg = NULL;
   113 
   114     if (strncasecmp(src, "subject: ", 9) == 0) {
   115         char *line_end = strchr(src, '\n');
   116         
   117         if (line_end == NULL) {
   118             _shortmsg = strdup(src + 9);
   119             if (_shortmsg == NULL)
   120                 goto enomem;
   121             // _longmsg = NULL;
   122         }
   123         else {
   124             size_t n = line_end - src;
   125 
   126             if (*(line_end - 1) == '\r')
   127                 _shortmsg = strndup(src + 9, n - 10);
   128             else
   129                 _shortmsg = strndup(src + 9, n - 9);
   130 
   131             if (_shortmsg == NULL)
   132                 goto enomem;
   133 
   134             while (*(src + n) && (*(src + n) == '\n' || *(src + n) == '\r'))
   135                 ++n;
   136 
   137             if (*(src + n)) {
   138                 _longmsg = strdup(src + n);
   139                 if (_longmsg == NULL)
   140                     goto enomem;
   141             }
   142         }
   143     }
   144     else {
   145         _shortmsg = strdup("");
   146         if (_shortmsg == NULL)
   147             goto enomem;
   148         _longmsg = strdup(src);
   149         if (_longmsg == NULL)
   150             goto enomem;
   151     }
   152     
   153     *shortmsg = _shortmsg;
   154     *longmsg = _longmsg;
   155 
   156     return 0;
   157 
   158 enomem:
   159     free(_shortmsg);
   160     free(_longmsg);
   161 
   162     return -1;
   163 }
   164 
   165 static PEP_STATUS copy_fields(message *dst, const message *src)
   166 {
   167     assert(dst);
   168     assert(src);
   169 
   170     free_timestamp(dst->sent);
   171     dst->sent = NULL;
   172     if (src->sent) {
   173         dst->sent = timestamp_dup(src->sent);
   174         if (dst->sent == NULL)
   175             return PEP_OUT_OF_MEMORY;
   176     }
   177 
   178     free_timestamp(dst->recv);
   179     dst->recv = NULL;
   180     if (src->recv) {
   181         dst->recv = timestamp_dup(src->recv);
   182         if (dst->recv == NULL)
   183             return PEP_OUT_OF_MEMORY;
   184     }
   185 
   186     free_identity(dst->from);
   187     dst->from = NULL;
   188     if (src->from) {
   189         dst->from = identity_dup(src->from);
   190         if (dst->from == NULL)
   191             return PEP_OUT_OF_MEMORY;
   192     }
   193 
   194     free_identity_list(dst->to);
   195     dst->to = NULL;
   196     if (src->to) {
   197         dst->to = identity_list_dup(src->to);
   198         if (dst->to == NULL)
   199             return PEP_OUT_OF_MEMORY;
   200     }
   201 
   202     free_identity(dst->recv_by);
   203     dst->recv_by = NULL;
   204     if (src->recv_by) {
   205         dst->recv_by = identity_dup(src->recv_by);
   206         if (dst->recv_by == NULL)
   207             return PEP_OUT_OF_MEMORY;
   208     }
   209 
   210     free_identity_list(dst->cc);
   211     dst->cc = NULL;
   212     if (src->cc) {
   213         dst->cc = identity_list_dup(src->cc);
   214         if (dst->cc == NULL)
   215             return PEP_OUT_OF_MEMORY;
   216     }
   217 
   218     free_identity_list(dst->bcc);
   219     dst->bcc = NULL;
   220     if (src->bcc) {
   221         dst->bcc = identity_list_dup(src->bcc);
   222         if (dst->bcc == NULL)
   223             return PEP_OUT_OF_MEMORY;
   224     }
   225 
   226     free_identity_list(dst->reply_to);
   227     dst->reply_to = NULL;
   228     if (src->reply_to) {
   229         dst->reply_to = identity_list_dup(src->reply_to);
   230         if (dst->reply_to == NULL)
   231             return PEP_OUT_OF_MEMORY;
   232     }
   233 
   234     free_stringlist(dst->in_reply_to);
   235     dst->in_reply_to = NULL;
   236     if (src->in_reply_to) {
   237         dst->in_reply_to = stringlist_dup(src->in_reply_to);
   238         if (dst->in_reply_to == NULL)
   239             return PEP_OUT_OF_MEMORY;
   240     }
   241 
   242     free_stringlist(dst->references);
   243     dst->references = NULL;
   244     if (src->references) {
   245         dst->references = stringlist_dup(src->references);
   246         if (dst->references == NULL)
   247             return PEP_OUT_OF_MEMORY;
   248     }
   249 
   250     free_stringlist(dst->keywords);
   251     dst->keywords = NULL;
   252     if (src->keywords) {
   253         dst->keywords = stringlist_dup(src->keywords);
   254         if (dst->keywords == NULL)
   255             return PEP_OUT_OF_MEMORY;
   256     }
   257 
   258     free(dst->comments);
   259     dst->comments = NULL;
   260     if (src->comments) {
   261         dst->comments = strdup(src->comments);
   262         assert(dst->comments);
   263         if (dst->comments == NULL)
   264             return PEP_OUT_OF_MEMORY;
   265     }
   266 
   267     return PEP_STATUS_OK;
   268 }
   269 
   270 static message * clone_to_empty_message(const message * src)
   271 {
   272     PEP_STATUS status;
   273     message * msg = NULL;
   274 
   275     assert(src);
   276 
   277     msg = calloc(1, sizeof(message));
   278     assert(msg);
   279     if (msg == NULL)
   280         goto enomem;
   281 
   282     msg->dir = src->dir;
   283 
   284     status = copy_fields(msg, src);
   285     if (status != PEP_STATUS_OK)
   286         goto enomem;
   287 
   288     return msg;
   289 
   290 enomem:
   291     free_message(msg);
   292     return NULL;
   293 }
   294 
   295 DYNAMIC_API PEP_STATUS encrypt_message(
   296         PEP_SESSION session,
   297         message *src,
   298         stringlist_t * extra,
   299         message **dst,
   300         PEP_enc_format enc_format
   301     )
   302 {
   303     PEP_STATUS status = PEP_STATUS_OK;
   304     message * msg = NULL;
   305     stringlist_t * keys = NULL;
   306     bool free_src = false;
   307 
   308     assert(session);
   309     assert(src);
   310     assert(dst);
   311     assert(enc_format >= PEP_enc_pieces);
   312 
   313     if (!(session && src && dst && (enc_format >= PEP_enc_pieces)))
   314         return PEP_ILLEGAL_VALUE;
   315 
   316     *dst = NULL;
   317 
   318     import_attached_keys(session, src);
   319 
   320     if (src->enc_format >= PEP_enc_pieces) {
   321         if (src->enc_format == enc_format) {
   322             assert(0); // the message is encrypted this way already
   323             msg = message_dup(src);
   324             if (msg == NULL)
   325                 goto enomem;
   326             *dst = msg;
   327             return PEP_STATUS_OK;
   328         }
   329         else {
   330             // decrypt and re-encrypt again
   331             message * _dst = NULL;
   332             PEP_MIME_format mime = (enc_format == PEP_enc_PEP) ? PEP_MIME :
   333                     PEP_MIME_fields_omitted;
   334 
   335             status = decrypt_message(session, src, mime, &_dst);
   336             if (status != PEP_STATUS_OK)
   337                 goto pep_error;
   338 
   339             src = _dst;
   340             free_src = true;
   341         }
   342     }
   343 
   344     msg = clone_to_empty_message(src);
   345     if (msg == NULL)
   346         goto enomem;
   347 
   348     status = myself(session, src->from);
   349     if (status != PEP_STATUS_OK)
   350         goto pep_error;
   351 
   352     keys = new_stringlist(src->from->fpr);
   353     if (keys == NULL)
   354         goto enomem;
   355 
   356     stringlist_t *_k = keys;
   357 
   358     if (extra) {
   359         _k = stringlist_append(_k, extra);
   360         if (_k == NULL)
   361             goto enomem;
   362     }
   363 
   364     bool dest_keys_found = false;
   365     identity_list * _il;
   366     for (_il = msg->to; _il && _il->ident; _il = _il->next) {
   367         PEP_STATUS status = update_identity(session, _il->ident);
   368         if (status != PEP_STATUS_OK)
   369             goto pep_error;
   370 
   371         if (_il->ident->fpr) {
   372             dest_keys_found = true;
   373             _k = stringlist_add(_k, _il->ident->fpr);
   374             if (_k == NULL)
   375                 goto enomem;
   376         }
   377         else
   378             status = PEP_KEY_NOT_FOUND;
   379     }
   380 
   381     if (dest_keys_found) {
   382         char *ptext;
   383         char *ctext = NULL;
   384         size_t csize = 0;
   385 
   386         switch (enc_format) {
   387         case PEP_enc_PGP_MIME: {
   388             bool free_ptext = false;
   389 
   390             msg->enc_format = PEP_enc_PGP_MIME;
   391 
   392             if (src->mime == PEP_MIME) {
   393                 message *_src = NULL;
   394                 assert(src->longmsg);
   395                 status = mime_decode_message(src->longmsg, &_src);
   396                 if (status != PEP_STATUS_OK)
   397                     goto pep_error;
   398                 if (free_src)
   399                     free_message(src);
   400                 src = _src;
   401                 free_src = true;
   402             }
   403 
   404             if (src->mime == PEP_MIME_none) {
   405                 if (src->shortmsg && strcmp(src->shortmsg, "pEp") != 0) {
   406                     ptext = combine_short_and_long(src->shortmsg, src->longmsg);
   407                     if (ptext == NULL)
   408                         goto enomem;
   409                     free_ptext = true;
   410                 }
   411                 else if (src->longmsg) {
   412                     ptext = src->longmsg;
   413                 }
   414                 else {
   415                     ptext = "pEp";
   416                 }
   417 
   418                 message *_src = calloc(1, sizeof(message));
   419                 assert(_src);
   420                 if (_src == NULL)
   421                     goto enomem;
   422                 _src->longmsg = ptext;
   423                 _src->longmsg_formatted = src->longmsg_formatted;
   424                 _src->attachments = src->attachments;
   425                 _src->enc_format = PEP_enc_PGP_MIME;
   426                 status = mime_encode_message(_src, true, &ptext);
   427                 assert(status == PEP_STATUS_OK);
   428                 if (free_ptext)
   429                     free(_src->longmsg);
   430                 free(_src);
   431                 assert(ptext);
   432                 if (ptext == NULL)
   433                     goto pep_error;
   434                 free_ptext = true;
   435             }
   436             else /* if (src->mime == PEP_MIME_fields_omitted) */ {
   437                 ptext = src->longmsg;
   438             }
   439 
   440             status = encrypt_and_sign(session, keys, ptext, strlen(ptext),
   441                     &ctext, &csize);
   442             if (free_ptext)
   443                 free(ptext);
   444             if (ctext == NULL)
   445                 goto pep_error;
   446 
   447             msg->longmsg = strdup(ctext);
   448             if (msg->longmsg == NULL)
   449                 goto enomem;
   450         }
   451         break;
   452 
   453         case PEP_enc_pieces:
   454             msg->enc_format = PEP_enc_pieces;
   455 
   456             if (src->shortmsg && strcmp(src->shortmsg, "pEp") != 0) {
   457                 ptext = combine_short_and_long(src->shortmsg, src->longmsg);
   458                 if (ptext == NULL)
   459                     goto enomem;
   460 
   461                 status = encrypt_and_sign(session, keys, ptext, strlen(ptext),
   462                         &ctext, &csize);
   463                 free(ptext);
   464                 if (ctext) {
   465                     msg->longmsg = strdup(ctext);
   466                     if (msg->longmsg == NULL)
   467                         goto enomem;
   468                 }
   469                 else {
   470                     goto pep_error;
   471                 }
   472             }
   473             else if (src->longmsg) {
   474                 ptext = src->longmsg;
   475                 status = encrypt_and_sign(session, keys, ptext, strlen(ptext),
   476                         &ctext, &csize);
   477                 if (ctext) {
   478                     msg->longmsg = strdup(ctext);
   479                     if (msg->longmsg == NULL)
   480                         goto enomem;
   481                 }
   482                 else {
   483                     goto pep_error;
   484                 }
   485             }
   486 
   487             if (msg->longmsg_formatted) {
   488                 ptext = src->longmsg_formatted;
   489                 status = encrypt_and_sign(session, keys, ptext, strlen(ptext),
   490                         &ctext, &csize);
   491                 if (ctext) {
   492                     msg->longmsg_formatted = strdup(ctext);
   493                     if (msg->longmsg_formatted == NULL)
   494                         goto enomem;
   495                 }
   496                 else {
   497                     goto pep_error;
   498                 }
   499             }
   500 
   501             if (src->attachments) {
   502                 bloblist_t *_s;
   503                 bloblist_t *_d = new_bloblist(NULL, 0, NULL, NULL);
   504                 if (_d == NULL)
   505                     goto enomem;
   506 
   507                 msg->attachments = _d;
   508                 for (_s = src->attachments; _s && _s->data; _s = _s->next) {
   509                     int psize = _s->size;
   510                     ptext = _s->data;
   511                     status = encrypt_and_sign(session, keys, ptext, psize,
   512                             &ctext, &csize);
   513                     if (ctext) {
   514                         char * _c = strdup(ctext);
   515                         if (_c == NULL)
   516                             goto enomem;
   517 
   518                         _d = bloblist_add(_d, _c, csize, _s->mime_type,
   519                                 _s->filename);
   520                         if (_d == NULL)
   521                             goto enomem;
   522                     }
   523                     else {
   524                         goto pep_error;
   525                     }
   526                 }
   527             }
   528             break;
   529 
   530         case PEP_enc_PEP:
   531             // TODO: implement
   532             NOT_IMPLEMENTED
   533 
   534         default:
   535             assert(0);
   536             status = PEP_ILLEGAL_VALUE;
   537             goto pep_error;
   538         }
   539     }
   540 
   541     free_stringlist(keys);
   542     if (free_src)
   543         free_message(src);
   544 
   545     if (msg->shortmsg == NULL)
   546         msg->shortmsg = strdup("pEp");
   547 
   548     import_attached_keys(session, msg);
   549 
   550     *dst = msg;
   551     return PEP_STATUS_OK;
   552 
   553 enomem:
   554     status = PEP_OUT_OF_MEMORY;
   555 
   556 pep_error:
   557     free_stringlist(keys);
   558     free_message(msg);
   559     if (free_src)
   560         free_message(src);
   561 
   562     return status;
   563 }
   564 
   565 static bool is_encrypted_attachment(const bloblist_t *blob)
   566 {
   567     char *ext;
   568  
   569     assert(blob);
   570 
   571     if (blob->filename == NULL)
   572         return false;
   573 
   574     ext = strrchr(blob->filename, '.');
   575     if (ext == NULL)
   576         return false;
   577 
   578     if (strcmp(blob->mime_type, "application/octet-stream")) {
   579         if (strcmp(ext, ".pgp") == 0 || strcmp(ext, ".gpg") == 0 ||
   580                 strcmp(ext, ".asc") == 0)
   581             return true;
   582     }
   583     else if (strcmp(blob->mime_type, "text/plain")) {
   584         if (strcmp(ext, ".asc") == 0)
   585             return true;
   586     }
   587 
   588     return false;
   589 }
   590 
   591 static bool is_encrypted_html_attachment(const bloblist_t *blob)
   592 {
   593     assert(blob);
   594     assert(blob->filename);
   595 
   596     if (strncmp(blob->filename, "PGPexch.htm.", 12) == 0) {
   597         if (strcmp(blob->filename + 11, ".pgp") == 0 ||
   598                 strcmp(blob->filename + 11, ".asc") == 0)
   599             return true;
   600     }
   601 
   602     return false;
   603 }
   604 
   605 static char * without_double_ending(const char *filename)
   606 {
   607     char *ext;
   608 
   609     assert(filename);
   610 
   611     ext = strrchr(filename, '.');
   612     if (ext == NULL)
   613         return NULL;
   614 
   615     return strndup(filename, ext - filename);
   616 }
   617 
   618 DYNAMIC_API PEP_STATUS decrypt_message(
   619         PEP_SESSION session,
   620         message *src,
   621         PEP_MIME_format mime,
   622         message **dst
   623     )
   624 {
   625     PEP_STATUS status = PEP_STATUS_OK;
   626     message *msg = NULL;
   627     char *ctext;
   628     size_t csize;
   629     char *ptext;
   630     size_t psize;
   631     stringlist_t *keylist;
   632     bool free_src = false;
   633 
   634     assert(session);
   635     assert(src);
   636     assert(dst);
   637 
   638     if (!(session && src && dst))
   639         return PEP_ILLEGAL_VALUE;
   640 
   641     *dst = NULL;
   642  
   643     import_attached_keys(session, src);
   644 
   645     if (src->mime == PEP_MIME_fields_omitted || src->mime == PEP_MIME) {
   646         message *_src = NULL;
   647         status = mime_decode_message(src->longmsg, &_src);
   648         if (status != PEP_STATUS_OK)
   649             goto pep_error;
   650 
   651         if ( src->mime == PEP_MIME_fields_omitted) {
   652             status = copy_fields(_src, src);
   653             if (status != PEP_STATUS_OK) {
   654                 free_message(_src);
   655                 goto pep_error;
   656             }
   657         }
   658 
   659         src = _src;
   660         free_src = true;
   661     }
   662 
   663     // src message is not MIME encoded (any more)
   664     assert(src->mime == PEP_MIME_none);
   665 
   666     if (!is_PGP_message_text(src->longmsg)) {
   667         status = PEP_UNENCRYPTED;
   668         goto pep_error;
   669     }
   670 
   671     ctext = src->longmsg;
   672     csize = strlen(src->longmsg);
   673 
   674     status = decrypt_and_verify(session, ctext, csize, &ptext, &psize,
   675             &keylist);
   676     if (ptext == NULL)
   677         goto pep_error;
   678 
   679     switch (src->enc_format) {
   680         case PEP_enc_PGP_MIME:
   681             status = mime_decode_message(ptext, &msg);
   682             if (status != PEP_STATUS_OK)
   683                 goto pep_error;
   684 
   685             break;
   686 
   687         case PEP_enc_pieces:
   688             msg = clone_to_empty_message(src);
   689             if (msg == NULL)
   690                 goto enomem;
   691 
   692             msg->longmsg = strdup(ptext);
   693             if (msg->longmsg == NULL)
   694                 goto enomem;
   695 
   696             bloblist_t *_m = msg->attachments;
   697             bloblist_t *_s;
   698             for (_s = src->attachments; _s; _s = _s->next) {
   699                 if (is_encrypted_attachment(_s)) {
   700                     ctext = _s->data;
   701                     csize = _s->size;
   702 
   703                     status = decrypt_and_verify(session, ctext, csize, &ptext,
   704                             &psize, &keylist);
   705                     if (ptext == NULL)
   706                         goto pep_error;
   707                     
   708                     if (is_encrypted_html_attachment(_s)) {
   709                         msg->longmsg_formatted = strdup(ptext);
   710                         if (msg->longmsg_formatted == NULL)
   711                             goto pep_error;
   712                     }
   713                     else {
   714                         char * mime_type = "application/octet-stream";
   715                         char * filename = without_double_ending(_s->filename);
   716                         if (filename == NULL)
   717                             goto enomem;
   718 
   719                         _m = bloblist_add(_m, ptext, psize, mime_type, filename);
   720                         if (_m == NULL)
   721                             goto enomem;
   722 
   723                        if (msg->attachments == NULL)
   724                             msg->attachments = _m;
   725                     }
   726                 }
   727             }
   728 
   729             break;
   730 
   731         default:
   732             // BUG: must implement more
   733             NOT_IMPLEMENTED
   734     }
   735 
   736     switch (src->enc_format) {
   737         case PEP_enc_PGP_MIME:
   738         case PEP_enc_pieces:
   739             status = copy_fields(msg, src);
   740             if (status != PEP_STATUS_OK)
   741                 goto pep_error;
   742 
   743             if (src->shortmsg && strcmp(src->shortmsg, "pEp") != 0) {
   744                 free(msg->shortmsg);
   745                 msg->shortmsg = strdup(src->shortmsg);
   746                 if (msg->shortmsg == NULL)
   747                     goto enomem;
   748             }
   749 
   750             if (msg->shortmsg == NULL || strcmp(msg->shortmsg, "pEp") == 0)
   751             {
   752                 char * shortmsg;
   753                 char * longmsg;
   754 
   755                 int r = seperate_short_and_long(msg->longmsg, &shortmsg,
   756                         &longmsg);
   757                 if (r == -1)
   758                     goto enomem;
   759 
   760                 free(msg->shortmsg);
   761                 free(msg->longmsg);
   762 
   763                 msg->shortmsg = shortmsg;
   764                 msg->longmsg = longmsg;
   765             }
   766             else {
   767                 msg->shortmsg = strdup(src->shortmsg);
   768                 if (msg->shortmsg == NULL)
   769                     goto enomem;
   770                 msg->longmsg = ptext;
   771             }
   772             break;
   773 
   774         default:
   775             // BUG: must implement more
   776             NOT_IMPLEMENTED
   777     }
   778 
   779     switch (mime) {
   780         case PEP_MIME_none:
   781             break;
   782 
   783         case PEP_MIME:
   784         case PEP_MIME_fields_omitted:
   785             {
   786                 char *text = NULL;
   787                 status = mime_encode_message(msg,
   788                         mime == PEP_MIME_fields_omitted, &text);
   789                 if (status != PEP_STATUS_OK)
   790                     goto pep_error;
   791 
   792                 message *_msg = clone_to_empty_message(msg);
   793                 if (_msg == NULL) {
   794                     free(text);
   795                     goto enomem;
   796                 }
   797                 _msg->longmsg = text;
   798                 _msg->shortmsg = strdup(msg->shortmsg);
   799                 if (msg->shortmsg == NULL)
   800                     goto enomem;
   801 
   802                 free_message(msg);
   803                 msg = _msg;
   804             }
   805             break;
   806     }
   807 
   808     if (free_src)
   809         free_message(src);
   810 
   811     import_attached_keys(session, msg);
   812 
   813     *dst = msg;
   814     return PEP_STATUS_OK;
   815 
   816 enomem:
   817     status = PEP_OUT_OF_MEMORY;
   818 
   819 pep_error:
   820     free_message(msg);
   821     if (free_src)
   822         free_message(src);
   823 
   824     return status;
   825 }
   826 
   827 static PEP_comm_type _get_comm_type(
   828         PEP_SESSION session,
   829         PEP_comm_type max_comm_type,
   830         pEp_identity *ident
   831     )
   832 {
   833     PEP_STATUS status = update_identity(session, ident);
   834 
   835     if (max_comm_type == PEP_ct_compromized)
   836         return PEP_ct_compromized;
   837 
   838     if (status == PEP_STATUS_OK) {
   839         if (ident->comm_type == PEP_ct_compromized)
   840             return PEP_ct_compromized;
   841         else
   842             return MIN(max_comm_type, ident->comm_type);
   843     }
   844     else {
   845         return PEP_ct_unknown;
   846     }
   847 }
   848 
   849 DYNAMIC_API PEP_STATUS get_message_color(
   850         PEP_SESSION session,
   851         message *msg,
   852         PEP_color *color
   853     )
   854 {
   855     PEP_STATUS status = PEP_STATUS_OK;
   856     PEP_comm_type max_comm_type = PEP_ct_pEp;
   857     bool comm_type_determined = false;
   858     identity_list * il;
   859 
   860     assert(session);
   861     assert(msg);
   862     assert(color);
   863 
   864     if (!(session && msg && color))
   865         return PEP_ILLEGAL_VALUE;
   866 
   867     *color = PEP_undefined;
   868 
   869     assert(msg->from);
   870     if (msg->from == NULL)
   871         return PEP_ILLEGAL_VALUE;
   872 
   873     switch (msg->dir) {
   874         case PEP_dir_incoming:
   875             status = update_identity(session, msg->from);
   876             if (status != PEP_STATUS_OK)
   877                 return status;
   878             max_comm_type = msg->from->comm_type;
   879             comm_type_determined = true;
   880             break;
   881         
   882         case PEP_dir_outgoing:
   883             status = myself(session, msg->from);
   884             if (status != PEP_STATUS_OK)
   885                 return status;
   886 
   887             for (il = msg->to; il != NULL; il = il->next) {
   888                 if (il->ident) {
   889                     max_comm_type = _get_comm_type(session, max_comm_type,
   890                             il->ident);
   891                     comm_type_determined = true;
   892                 }
   893             }
   894 
   895             for (il = msg->cc; il != NULL; il = il->next) {
   896                 if (il->ident) {
   897                     max_comm_type = _get_comm_type(session, max_comm_type,
   898                             il->ident);
   899                     comm_type_determined = true;
   900                 }
   901             }
   902 
   903             for (il = msg->bcc; il != NULL; il = il->next) {
   904                 if (il->ident) {
   905                     max_comm_type = _get_comm_type(session, max_comm_type,
   906                             il->ident);
   907                     comm_type_determined = true;
   908                 }
   909             }
   910             break;
   911 
   912         default:
   913             return PEP_ILLEGAL_VALUE;
   914     }
   915 
   916     if (comm_type_determined == false)
   917         *color = PEP_undefined;
   918 
   919     else if (max_comm_type == PEP_ct_compromized)
   920         *color = PEP_under_attack;
   921 
   922     else if (max_comm_type >= PEP_ct_confirmed_enc_anon)
   923         *color = PEP_trusted_and_anonymized;
   924 
   925     else if (max_comm_type >= PEP_ct_strong_encryption)
   926         *color = PEP_trusted;
   927 
   928     else if (max_comm_type >= PEP_ct_strong_but_unconfirmed &&
   929             max_comm_type < PEP_ct_confirmed)
   930         *color = PEP_reliable;
   931     
   932     else if (max_comm_type == PEP_ct_no_encryption ||
   933             max_comm_type == PEP_ct_no_encrypted_channel)
   934         *color = PEP_unencrypted;
   935 
   936     else if (max_comm_type == PEP_ct_unknown)
   937         *color = PEP_undefined;
   938 
   939     else
   940         *color = PEP_unreliable;
   941 
   942     return PEP_STATUS_OK;
   943 }
   944