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