...
authorvb
Sun, 15 Mar 2015 10:14:43 +0100
changeset 1134bee48270834
parent 112 d001ca329a48
child 114 7a006f74365d
...
src/bloblist.c
src/bloblist.h
src/message.c
src/message.h
src/message_api.c
src/message_api.h
src/mime.c
src/mime.h
src/pEpEngine.c
src/platform_windows.h
src/stringlist.c
src/stringlist.h
test/message_api_test.cc
test/mime_test.cc
     1.1 --- a/src/bloblist.c	Sat Mar 14 11:28:14 2015 +0100
     1.2 +++ b/src/bloblist.c	Sun Mar 15 10:14:43 2015 +0100
     1.3 @@ -5,7 +5,7 @@
     1.4  #include "bloblist.h"
     1.5  
     1.6  DYNAMIC_API bloblist_t *new_bloblist(char *blob, size_t size, const char *mime_type,
     1.7 -        const char *file_name)
     1.8 +        const char *filename)
     1.9  {
    1.10      bloblist_t * bloblist = calloc(1, sizeof(bloblist_t));
    1.11      assert(bloblist);
    1.12 @@ -20,9 +20,9 @@
    1.13          }
    1.14      }
    1.15  
    1.16 -    if (file_name) {
    1.17 -        bloblist->file_name = strdup(file_name);
    1.18 -        if (bloblist->file_name == NULL) {
    1.19 +    if (filename) {
    1.20 +        bloblist->filename = strdup(filename);
    1.21 +        if (bloblist->filename == NULL) {
    1.22              free(bloblist->mime_type);
    1.23              free(bloblist);
    1.24              return NULL;
    1.25 @@ -42,7 +42,7 @@
    1.26              free_bloblist(bloblist->next);
    1.27          free(bloblist->data);
    1.28          free(bloblist->mime_type);
    1.29 -        free(bloblist->file_name);
    1.30 +        free(bloblist->filename);
    1.31          free(bloblist);
    1.32      }
    1.33  }
    1.34 @@ -53,7 +53,7 @@
    1.35  
    1.36      assert(src);
    1.37  
    1.38 -    bloblist = new_bloblist(src->data, src->size, src->mime_type, src->file_name);
    1.39 +    bloblist = new_bloblist(src->data, src->size, src->mime_type, src->filename);
    1.40      if (bloblist == NULL)
    1.41          goto enomem;
    1.42  
    1.43 @@ -71,12 +71,12 @@
    1.44  }
    1.45  
    1.46  DYNAMIC_API bloblist_t *bloblist_add(bloblist_t *bloblist, char *blob, size_t size,
    1.47 -        const char *mime_type, const char *file_name)
    1.48 +        const char *mime_type, const char *filename)
    1.49  {
    1.50      assert(blob);
    1.51  
    1.52      if (bloblist == NULL)
    1.53 -        return new_bloblist(blob, size, mime_type, file_name);
    1.54 +        return new_bloblist(blob, size, mime_type, filename);
    1.55  
    1.56      if (bloblist->data == NULL) {
    1.57          if (mime_type) {
    1.58 @@ -86,9 +86,9 @@
    1.59                  return NULL;
    1.60              }
    1.61          }
    1.62 -        if (file_name) {
    1.63 -            bloblist->file_name = strdup(file_name);
    1.64 -            if (bloblist->file_name == NULL) {
    1.65 +        if (filename) {
    1.66 +            bloblist->filename = strdup(filename);
    1.67 +            if (bloblist->filename == NULL) {
    1.68                  free(bloblist->mime_type);
    1.69                  free(bloblist);
    1.70                  return NULL;
    1.71 @@ -100,10 +100,10 @@
    1.72      }
    1.73  
    1.74      if (bloblist->next == NULL) {
    1.75 -        bloblist->next = new_bloblist(blob, size, mime_type, file_name);
    1.76 +        bloblist->next = new_bloblist(blob, size, mime_type, filename);
    1.77          return bloblist->next;
    1.78      }
    1.79  
    1.80 -    return bloblist_add(bloblist->next, blob, size, mime_type, file_name);
    1.81 +    return bloblist_add(bloblist->next, blob, size, mime_type, filename);
    1.82  }
    1.83  
     2.1 --- a/src/bloblist.h	Sat Mar 14 11:28:14 2015 +0100
     2.2 +++ b/src/bloblist.h	Sun Mar 15 10:14:43 2015 +0100
     2.3 @@ -12,7 +12,7 @@
     2.4      size_t size;                    // size of blob
     2.5      char *mime_type;                // UTF-8 string of MIME type of blob or
     2.6                                      // NULL if unknown
     2.7 -    char *file_name;                // UTF-8 string of file name of blob or
     2.8 +    char *filename;                // UTF-8 string of file name of blob or
     2.9                                      // NULL if unknown
    2.10      struct _bloblist_t *next;
    2.11  } bloblist_t;
    2.12 @@ -24,17 +24,17 @@
    2.13  //      blob (in)       blob to add to the list
    2.14  //      size (in)       size of the blob
    2.15  //      mime_type (in)  MIME type of the blob data or NULL if unknown
    2.16 -//      file_name (in)  file name of origin of blob data or NULL if unknown
    2.17 +//      filename (in)  file name of origin of blob data or NULL if unknown
    2.18  //
    2.19  //  return value:
    2.20  //      pointer to new bloblist_t or NULL if out of memory
    2.21  //
    2.22  //  caveat:
    2.23 -//      the ownership of the blob goes to the bloblist; mime_type and file_name
    2.24 +//      the ownership of the blob goes to the bloblist; mime_type and filename
    2.25  //      are being copied, the originals remain in the ownership of the caller
    2.26  
    2.27  DYNAMIC_API bloblist_t *new_bloblist(char *blob, size_t size, const char *mime_type,
    2.28 -        const char *file_name);
    2.29 +        const char *filename);
    2.30  
    2.31  
    2.32  // free_bloblist() - free bloblist
    2.33 @@ -65,17 +65,17 @@
    2.34  //      blob (in)       blob
    2.35  //      size (in)       size of the blob
    2.36  //      mime_type (in)  MIME type of the blob or NULL if unknown
    2.37 -//      file_name (in)  file name of the blob or NULL if unknown
    2.38 +//      filename (in)  file name of the blob or NULL if unknown
    2.39  //
    2.40  //  return value:
    2.41  //      pointer to the last element of bloblist or NULL if out of memory
    2.42  //
    2.43  //  caveat:
    2.44 -//      the ownership of the blob goes to the bloblist; mime_type and file_name
    2.45 +//      the ownership of the blob goes to the bloblist; mime_type and filename
    2.46  //      are being copied, the originals remain in the ownership of the caller
    2.47  
    2.48  DYNAMIC_API bloblist_t *bloblist_add(bloblist_t *bloblist, char *blob, size_t size,
    2.49 -        const char *mime_type, const char *file_name);
    2.50 +        const char *mime_type, const char *filename);
    2.51  
    2.52  
    2.53  #ifdef __cplusplus
     3.1 --- a/src/message.c	Sat Mar 14 11:28:14 2015 +0100
     3.2 +++ b/src/message.c	Sun Mar 15 10:14:43 2015 +0100
     3.3 @@ -50,8 +50,8 @@
     3.4          free(msg->longmsg);
     3.5          free(msg->longmsg_formatted);
     3.6          free_bloblist(msg->attachments);
     3.7 -        free(msg->sent);
     3.8 -        free(msg->recv);
     3.9 +        free_timestamp(msg->sent);
    3.10 +        free_timestamp(msg->recv);
    3.11          free_identity(msg->from);
    3.12          free_identity_list(msg->to);
    3.13          free_identity(msg->recv_by);
    3.14 @@ -118,19 +118,15 @@
    3.15      msg->rawmsg_size = src->rawmsg_size;
    3.16  
    3.17      if (src->sent) {
    3.18 -        msg->sent = malloc(sizeof(timestamp));
    3.19 -        assert(msg->sent);
    3.20 +        msg->sent = timestamp_dup(src->sent);
    3.21          if (msg->sent == NULL)
    3.22              goto enomem;
    3.23 -        memcpy(msg->sent, src->sent, sizeof(timestamp));
    3.24      }
    3.25  
    3.26      if (src->recv) {
    3.27 -        msg->recv = malloc(sizeof(timestamp));
    3.28 -        assert(msg->recv);
    3.29 +        msg->recv = timestamp_dup(src->recv);
    3.30          if (msg->recv == NULL)
    3.31              goto enomem;
    3.32 -        memcpy(msg->recv, src->recv, sizeof(timestamp));
    3.33      }
    3.34  
    3.35      if (src->recv_by) {
     4.1 --- a/src/message.h	Sat Mar 14 11:28:14 2015 +0100
     4.2 +++ b/src/message.h	Sun Mar 15 10:14:43 2015 +0100
     4.3 @@ -7,14 +7,12 @@
     4.4  #include "bloblist.h"
     4.5  #include "stringlist.h"
     4.6  #include "stringpair.h"
     4.7 +#include "timestamp.h"
     4.8  
     4.9  #ifdef __cplusplus
    4.10  extern "C" {
    4.11  #endif
    4.12  
    4.13 -// for time values all functions are using POSIX struct tm
    4.14 -
    4.15 -typedef struct tm timestamp;
    4.16  
    4.17  typedef enum _PEP_text_format {
    4.18      PEP_text_format_plain = 0,
    4.19 @@ -27,13 +25,16 @@
    4.20      PEP_dir_outgoing
    4.21  } PEP_msg_direction;
    4.22  
    4.23 +typedef enum _PEP_MIME_format {
    4.24 +    PEP_MIME_none = 0,                      // message is not MIME encoded
    4.25 +    PEP_MIME_fields_omitted,                // message content but no fields
    4.26 +    PEP_MIME                                // message is fully MIME encoded
    4.27 +} PEP_MIME_format;
    4.28 +
    4.29  typedef enum _PEP_enc_format {
    4.30 -    PEP_enc_none = 0,                       // message is in pieces and nor
    4.31 -                                            // encoded nor encrypted
    4.32 -    PEP_enc_none_MIME,                      // message is MIME encoded but not
    4.33 -                                            // encrypted; all code is in longmsg
    4.34 +    PEP_enc_none = 0,                       // message is not encrypted
    4.35      PEP_enc_pieces,                         // inline PGP + PGP extensions
    4.36 -    PEP_ecn_S_MIME,                         // RFC5751
    4.37 +    PEP_enc_S_MIME,                         // RFC5751
    4.38      PEP_enc_PGP_MIME,                       // RFC3156
    4.39      PEP_enc_PEP                             // pEp encryption format
    4.40  } PEP_enc_format;
    4.41 @@ -70,6 +71,8 @@
    4.42      char *comments;                         // UTF-8 string with comments
    4.43      stringpair_list_t *opt_fields;          // optional fields
    4.44      PEP_enc_format enc_format;              // format of encrypted data
    4.45 +    PEP_MIME_format mime;                   // if this is not PEP_MIME_none the
    4.46 +                                            // message content is in longmsg
    4.47  } message;
    4.48  
    4.49  typedef struct _message_ref_list {
     5.1 --- a/src/message_api.c	Sat Mar 14 11:28:14 2015 +0100
     5.2 +++ b/src/message_api.c	Sun Mar 15 10:14:43 2015 +0100
     5.3 @@ -71,7 +71,7 @@
     5.4          }
     5.5      }
     5.6      else {
     5.7 -        _shortmsg = strdup("pEp");
     5.8 +        _shortmsg = strdup("");
     5.9          if (_shortmsg == NULL)
    5.10              goto enomem;
    5.11          _longmsg = strdup(src);
    5.12 @@ -91,71 +91,136 @@
    5.13      return -1;
    5.14  }
    5.15  
    5.16 +static PEP_STATUS copy_fields(message *dst, const message *src)
    5.17 +{
    5.18 +    free_timestamp(dst->sent);
    5.19 +    dst->sent = NULL;
    5.20 +    if (src->sent) {
    5.21 +        dst->sent = timestamp_dup(src->sent);
    5.22 +        if (dst->sent == NULL)
    5.23 +            return PEP_OUT_OF_MEMORY;
    5.24 +    }
    5.25 +
    5.26 +    free_timestamp(dst->recv);
    5.27 +    dst->recv = NULL;
    5.28 +    if (src->recv) {
    5.29 +        dst->recv = timestamp_dup(src->recv);
    5.30 +        if (dst->recv == NULL)
    5.31 +            return PEP_OUT_OF_MEMORY;
    5.32 +    }
    5.33 +
    5.34 +    free_identity(dst->from);
    5.35 +    dst->from = NULL;
    5.36 +    if (src->from) {
    5.37 +        dst->from = identity_dup(src->from);
    5.38 +        if (dst->from == NULL)
    5.39 +            return PEP_OUT_OF_MEMORY;
    5.40 +    }
    5.41 +
    5.42 +    free_identity_list(dst->to);
    5.43 +    dst->to = NULL;
    5.44 +    if (src->to) {
    5.45 +        dst->to = identity_list_dup(src->to);
    5.46 +        if (dst->to == NULL)
    5.47 +            return PEP_OUT_OF_MEMORY;
    5.48 +    }
    5.49 +
    5.50 +    free_identity(dst->recv_by);
    5.51 +    dst->recv_by = NULL;
    5.52 +    if (src->recv_by) {
    5.53 +        dst->recv_by = identity_dup(src->recv_by);
    5.54 +        if (dst->recv_by == NULL)
    5.55 +            return PEP_OUT_OF_MEMORY;
    5.56 +    }
    5.57 +
    5.58 +    free_identity_list(dst->cc);
    5.59 +    dst->cc = NULL;
    5.60 +    if (src->cc) {
    5.61 +        dst->cc = identity_list_dup(src->cc);
    5.62 +        if (dst->cc == NULL)
    5.63 +            return PEP_OUT_OF_MEMORY;
    5.64 +    }
    5.65 +
    5.66 +    free_identity_list(dst->bcc);
    5.67 +    dst->bcc = NULL;
    5.68 +    if (src->bcc) {
    5.69 +        dst->bcc = identity_list_dup(src->bcc);
    5.70 +        if (dst->bcc == NULL)
    5.71 +            return PEP_OUT_OF_MEMORY;
    5.72 +    }
    5.73 +
    5.74 +    free_identity_list(dst->reply_to);
    5.75 +    dst->reply_to = NULL;
    5.76 +    if (src->reply_to) {
    5.77 +        dst->reply_to = identity_list_dup(src->reply_to);
    5.78 +        if (dst->reply_to == NULL)
    5.79 +            return PEP_OUT_OF_MEMORY;
    5.80 +    }
    5.81 +
    5.82 +    free_stringlist(dst->in_reply_to);
    5.83 +    dst->in_reply_to = NULL;
    5.84 +    if (src->in_reply_to) {
    5.85 +        dst->in_reply_to = stringlist_dup(src->in_reply_to);
    5.86 +        if (dst->in_reply_to == NULL)
    5.87 +            return PEP_OUT_OF_MEMORY;
    5.88 +    }
    5.89 +
    5.90 +    free_stringlist(dst->references);
    5.91 +    dst->references = NULL;
    5.92 +    if (src->references) {
    5.93 +        dst->references = stringlist_dup(src->references);
    5.94 +        if (dst->references == NULL)
    5.95 +            return PEP_OUT_OF_MEMORY;
    5.96 +    }
    5.97 +
    5.98 +    free_stringlist(dst->keywords);
    5.99 +    dst->keywords = NULL;
   5.100 +    if (src->keywords) {
   5.101 +        dst->keywords = stringlist_dup(src->keywords);
   5.102 +        if (dst->keywords == NULL)
   5.103 +            return PEP_OUT_OF_MEMORY;
   5.104 +    }
   5.105 +
   5.106 +    free(dst->comments);
   5.107 +    dst->comments = NULL;
   5.108 +    if (src->comments) {
   5.109 +        dst->comments = strdup(src->comments);
   5.110 +        assert(dst->comments);
   5.111 +        if (dst->comments == NULL)
   5.112 +            return PEP_OUT_OF_MEMORY;
   5.113 +    }
   5.114 +
   5.115 +    return PEP_STATUS_OK;
   5.116 +}
   5.117 +
   5.118  static message * clone_to_empty_message(const message * src)
   5.119  {
   5.120 -    pEp_identity *from = NULL;
   5.121 -    identity_list *to = NULL;
   5.122 -
   5.123 +    PEP_STATUS status;
   5.124      message * msg = NULL;
   5.125  
   5.126      assert(src);
   5.127 -    assert(src->from);
   5.128 -    assert(src->to);
   5.129  
   5.130 -    from = identity_dup(src->from);
   5.131 -    if (from == NULL)
   5.132 -        goto enomem;
   5.133 -
   5.134 -    from->me = true;
   5.135 -
   5.136 -    to = identity_list_dup(src->to);
   5.137 -    if (to == NULL)
   5.138 -        goto enomem;
   5.139 -
   5.140 -    msg = new_message(src->dir, from, to, NULL);
   5.141 +    msg = calloc(1, sizeof(message));
   5.142 +    assert(msg);
   5.143      if (msg == NULL)
   5.144          goto enomem;
   5.145  
   5.146      msg->dir = src->dir;
   5.147  
   5.148 -    if (src->cc) {
   5.149 -        msg->cc = identity_list_dup(src->cc);
   5.150 -        if (msg->cc == NULL)
   5.151 -            goto enomem;
   5.152 -    }
   5.153 -
   5.154 -    if (src->bcc) {
   5.155 -        msg->bcc = identity_list_dup(src->bcc);
   5.156 -        if (msg->bcc == NULL)
   5.157 -            goto enomem;
   5.158 -    }
   5.159 -
   5.160 -    if (src->reply_to) {
   5.161 -        msg->reply_to = identity_list_dup(src->reply_to);
   5.162 -        if (msg->reply_to == NULL)
   5.163 -            goto enomem;
   5.164 -    }
   5.165 -
   5.166 -    msg->sent = src->sent;
   5.167 -    msg->recv = src->recv;
   5.168 +    status = copy_fields(msg, src);
   5.169 +    if (status != PEP_STATUS_OK)
   5.170 +        goto enomem;
   5.171  
   5.172      return msg;
   5.173  
   5.174  enomem:
   5.175 -    if (msg) {
   5.176 -        free_message(msg);
   5.177 -    }
   5.178 -    else {
   5.179 -        free_identity(from);
   5.180 -        free_identity_list(to);
   5.181 -    }
   5.182 -
   5.183 +    free_message(msg);
   5.184      return NULL;
   5.185  }
   5.186  
   5.187  DYNAMIC_API PEP_STATUS encrypt_message(
   5.188          PEP_SESSION session,
   5.189 -        const message *src,
   5.190 +        message *src,
   5.191          stringlist_t * extra,
   5.192          message **dst,
   5.193          PEP_enc_format enc_format
   5.194 @@ -163,7 +228,9 @@
   5.195  {
   5.196      PEP_STATUS status = PEP_STATUS_OK;
   5.197      message * msg = NULL;
   5.198 +    message * _src;
   5.199      stringlist_t * keys = NULL;
   5.200 +    bool free_src = false;
   5.201  
   5.202      assert(session);
   5.203      assert(src);
   5.204 @@ -174,6 +241,7 @@
   5.205  
   5.206      if (src->enc_format >= PEP_enc_pieces) {
   5.207          if (src->enc_format == enc_format) {
   5.208 +            assert(0); // the message is encrypted this way already
   5.209              msg = message_dup(src);
   5.210              if (msg == NULL)
   5.211                  goto enomem;
   5.212 @@ -181,8 +249,17 @@
   5.213              return PEP_STATUS_OK;
   5.214          }
   5.215          else {
   5.216 -            // TODO: we don't re-encrypt yet
   5.217 -            NOT_IMPLEMENTED
   5.218 +            // decrypt and re-encrypt again
   5.219 +            message * _dst = NULL;
   5.220 +            PEP_MIME_format mime = (enc_format == PEP_enc_PEP) ? PEP_MIME :
   5.221 +                    PEP_MIME_fields_omitted;
   5.222 +
   5.223 +            status = decrypt_message(session, src, mime, &_dst);
   5.224 +            if (status != PEP_STATUS_OK)
   5.225 +                goto pep_error;
   5.226 +
   5.227 +            src = _dst;
   5.228 +            free_src = true;
   5.229          }
   5.230      }
   5.231  
   5.232 @@ -190,8 +267,6 @@
   5.233      if (msg == NULL)
   5.234          goto enomem;
   5.235  
   5.236 -    msg->enc_format = PEP_enc_pieces;
   5.237 -
   5.238      status = myself(session, src->from);
   5.239      if (status != PEP_STATUS_OK)
   5.240          goto pep_error;
   5.241 @@ -236,25 +311,38 @@
   5.242  
   5.243              msg->enc_format = PEP_enc_PGP_MIME;
   5.244  
   5.245 -            if (src->shortmsg && strcmp(src->shortmsg, "pEp") != 0) {
   5.246 -                ptext = combine_short_and_long(src->shortmsg, src->longmsg);
   5.247 -                if (ptext == NULL)
   5.248 -                    goto enomem;
   5.249 -                free_ptext = true;
   5.250 -            }
   5.251 -            else if (src->longmsg) {
   5.252 -                ptext = src->longmsg;
   5.253 +            if (src->mime == PEP_MIME) {
   5.254 +                message *_src = NULL;
   5.255 +                assert(src->longmsg);
   5.256 +                status = mime_decode_message(src->longmsg, &_src);
   5.257 +                if (status != PEP_STATUS_OK)
   5.258 +                    goto pep_error;
   5.259 +                if (free_src)
   5.260 +                    free_message(src);
   5.261 +                src = _src;
   5.262 +                free_src = true;
   5.263              }
   5.264  
   5.265 -            if (src->enc_format == PEP_enc_none) {
   5.266 -                message *_src = malloc(sizeof(message));
   5.267 +            if (src->mime == PEP_MIME_none) {
   5.268 +                if (src->shortmsg && strcmp(src->shortmsg, "pEp") != 0) {
   5.269 +                    ptext = combine_short_and_long(src->shortmsg, src->longmsg);
   5.270 +                    if (ptext == NULL)
   5.271 +                        goto enomem;
   5.272 +                    free_ptext = true;
   5.273 +                }
   5.274 +                else if (src->longmsg) {
   5.275 +                    ptext = src->longmsg;
   5.276 +                }
   5.277 +
   5.278 +                message *_src = calloc(1, sizeof(message));
   5.279                  assert(_src);
   5.280                  if (_src == NULL)
   5.281                      goto enomem;
   5.282 -                memcpy(_src, src, sizeof(message));
   5.283 -                _src->shortmsg = "pEp";
   5.284                  _src->longmsg = ptext;
   5.285 -                status = mime_encode_message(_src, &ptext);
   5.286 +                _src->longmsg_formatted = src->longmsg_formatted;
   5.287 +                _src->attachments = src->attachments;
   5.288 +                _src->enc_format = PEP_enc_PGP_MIME;
   5.289 +                status = mime_encode_message(_src, true, &ptext);
   5.290                  assert(status == PEP_STATUS_OK);
   5.291                  if (free_ptext)
   5.292                      free(_src->longmsg);
   5.293 @@ -264,12 +352,7 @@
   5.294                      goto pep_error;
   5.295                  free_ptext = true;
   5.296              }
   5.297 -            else if (src->enc_format == PEP_enc_none_MIME) {
   5.298 -                assert(src->longmsg);
   5.299 -                if (src->longmsg == NULL) {
   5.300 -                    status = PEP_ILLEGAL_VALUE;
   5.301 -                    goto pep_error;
   5.302 -                }
   5.303 +            else /* if (src->mime == PEP_MIME_fields_omitted) */ {
   5.304                  ptext = src->longmsg;
   5.305              }
   5.306  
   5.307 @@ -277,25 +360,18 @@
   5.308                      &ctext, &csize);
   5.309              if (free_ptext)
   5.310                  free(ptext);
   5.311 -            if (ctext) {
   5.312 -                msg->longmsg = strdup(ctext);
   5.313 -                if (msg->longmsg == NULL)
   5.314 -                    goto enomem;
   5.315 -            }
   5.316 -            else {
   5.317 +            if (ctext == NULL)
   5.318                  goto pep_error;
   5.319 -            }
   5.320 +
   5.321 +            msg->longmsg = strdup(ctext);
   5.322 +            if (msg->longmsg == NULL)
   5.323 +                goto enomem;
   5.324          }
   5.325          break;
   5.326  
   5.327          case PEP_enc_pieces:
   5.328              msg->enc_format = PEP_enc_pieces;
   5.329  
   5.330 -            // TODO: decoding MIME
   5.331 -            if (src->enc_format == PEP_enc_none_MIME) {
   5.332 -                NOT_IMPLEMENTED
   5.333 -            }
   5.334 -
   5.335              if (src->shortmsg && strcmp(src->shortmsg, "pEp") != 0) {
   5.336                  ptext = combine_short_and_long(src->shortmsg, src->longmsg);
   5.337                  if (ptext == NULL)
   5.338 @@ -359,7 +435,7 @@
   5.339                              goto enomem;
   5.340  
   5.341                          _d = bloblist_add(_d, _c, csize, _s->mime_type,
   5.342 -                                _s->file_name);
   5.343 +                                _s->filename);
   5.344                          if (_d == NULL)
   5.345                              goto enomem;
   5.346                      }
   5.347 @@ -382,6 +458,8 @@
   5.348      }
   5.349  
   5.350      free_stringlist(keys);
   5.351 +    if (free_src)
   5.352 +        free_message(src);
   5.353  
   5.354      if (msg->shortmsg == NULL)
   5.355          msg->shortmsg = strdup("pEp");
   5.356 @@ -395,15 +473,70 @@
   5.357  pep_error:
   5.358      free_stringlist(keys);
   5.359      free_message(msg);
   5.360 +    if (free_src)
   5.361 +        free_message(src);
   5.362  
   5.363      return status;
   5.364  }
   5.365  
   5.366 +static bool is_encrypted_attachment(const bloblist_t *blob)
   5.367 +{
   5.368 +    char *ext;
   5.369 + 
   5.370 +    assert(blob);
   5.371 +
   5.372 +    if (blob->filename == NULL)
   5.373 +        return false;
   5.374 +
   5.375 +    ext = strrchr(blob->filename, '.');
   5.376 +    if (ext == NULL)
   5.377 +        return false;
   5.378 +
   5.379 +    if (strcmp(blob->mime_type, "application/octet-stream")) {
   5.380 +        if (strcmp(ext, ".pgp") == 0 || strcmp(ext, ".gpg") == 0 ||
   5.381 +                strcmp(ext, ".asc") == 0)
   5.382 +            return true;
   5.383 +    }
   5.384 +    else if (strcmp(blob->mime_type, "application/octet-stream")) {
   5.385 +        if (strcmp(ext, ".asc") == 0)
   5.386 +            return true;
   5.387 +    }
   5.388 +
   5.389 +    return false;
   5.390 +}
   5.391 +
   5.392 +static bool is_encrypted_html_attachment(const bloblist_t *blob)
   5.393 +{
   5.394 +    assert(blob);
   5.395 +    assert(blob->filename);
   5.396 +
   5.397 +    if (strncmp(blob->filename, "PGPexch.htm.", 12) == 0) {
   5.398 +        if (strcmp(blob->filename + 11, ".pgp") == 0 ||
   5.399 +                strcmp(blob->filename + 11, ".asc") == 0)
   5.400 +            return true;
   5.401 +    }
   5.402 +
   5.403 +    return false;
   5.404 +}
   5.405 +
   5.406 +char * without_double_ending(const char *filename)
   5.407 +{
   5.408 +    char *ext;
   5.409 +
   5.410 +    assert(filename);
   5.411 +
   5.412 +    ext = strrchr(filename, '.');
   5.413 +    if (ext == NULL)
   5.414 +        return NULL;
   5.415 +
   5.416 +    return strndup(filename, ext - filename);
   5.417 +}
   5.418 +
   5.419  DYNAMIC_API PEP_STATUS decrypt_message(
   5.420          PEP_SESSION session,
   5.421 -        const message *src,
   5.422 -        message **dst,
   5.423 -        PEP_enc_format enc_format
   5.424 +        message *src,
   5.425 +        PEP_MIME_format mime,
   5.426 +        message **dst
   5.427      )
   5.428  {
   5.429      PEP_STATUS status = PEP_STATUS_OK;
   5.430 @@ -413,16 +546,17 @@
   5.431      char *ptext;
   5.432      size_t psize;
   5.433      stringlist_t *keylist;
   5.434 +    bool free_src = false;
   5.435  
   5.436      assert(session);
   5.437      assert(src);
   5.438      assert(dst);
   5.439 -    assert(enc_format < PEP_enc_pieces);
   5.440  
   5.441      *dst = NULL;
   5.442   
   5.443      if (src->enc_format < PEP_enc_pieces) {
   5.444 -        if (enc_format == src->enc_format) {
   5.445 +        assert(0); // message is not encrypted
   5.446 +        if (mime == src->mime) {
   5.447              msg = message_dup(src);
   5.448              if (msg == NULL)
   5.449                  goto enomem;
   5.450 @@ -435,62 +569,167 @@
   5.451          }
   5.452      }
   5.453  
   5.454 -    msg = clone_to_empty_message(src);
   5.455 -    if (msg == NULL)
   5.456 -        goto enomem;
   5.457 +    // src message is encrypted
   5.458 +    assert(src->enc_format >= PEP_enc_pieces);
   5.459  
   5.460 -    switch (enc_format) {
   5.461 -        case PEP_enc_none:
   5.462 -            // TODO: implement
   5.463 -            NOT_IMPLEMENTED
   5.464 +    if (src->mime == PEP_MIME_fields_omitted || src->mime == PEP_MIME) {
   5.465 +        message *_src = NULL;
   5.466 +        status = mime_decode_message(src->longmsg, &_src);
   5.467 +        if (status != PEP_STATUS_OK)
   5.468 +            goto pep_error;
   5.469  
   5.470 -        case PEP_enc_none_MIME:
   5.471 -            if (src->enc_format == PEP_enc_PEP) {
   5.472 -                // TODO: implement
   5.473 -                NOT_IMPLEMENTED
   5.474 +        if ( src->mime == PEP_MIME_fields_omitted) {
   5.475 +            status = copy_fields(_src, src);
   5.476 +            if (status != PEP_STATUS_OK) {
   5.477 +                free_message(_src);
   5.478 +                goto pep_error;
   5.479 +            }
   5.480 +        }
   5.481 +
   5.482 +        src = _src;
   5.483 +        free_src = true;
   5.484 +    }
   5.485 +
   5.486 +    // src message is not MIME encoded but still encrypted
   5.487 +    assert(src->mime == PEP_MIME_none);
   5.488 +
   5.489 +    ctext = src->longmsg;
   5.490 +    csize = strlen(src->longmsg);
   5.491 +
   5.492 +    status = decrypt_and_verify(session, ctext, csize, &ptext, &psize,
   5.493 +            &keylist);
   5.494 +    if (ptext == NULL)
   5.495 +        goto pep_error;
   5.496 +
   5.497 +    switch (src->enc_format) {
   5.498 +        case PEP_enc_PGP_MIME:
   5.499 +            status = mime_decode_message(ptext, &msg);
   5.500 +            if (status != PEP_STATUS_OK)
   5.501 +                goto pep_error;
   5.502 +
   5.503 +            break;
   5.504 +
   5.505 +        case PEP_enc_pieces:
   5.506 +            msg = clone_to_empty_message(src);
   5.507 +            if (msg == NULL)
   5.508 +                goto enomem;
   5.509 +
   5.510 +            msg->longmsg = strdup(ptext);
   5.511 +            if (msg->longmsg == NULL)
   5.512 +                goto enomem;
   5.513 +
   5.514 +            bloblist_t *_m = msg->attachments;
   5.515 +            bloblist_t *_s;
   5.516 +            for (_s = src->attachments; _s; _s = _s->next) {
   5.517 +                if (is_encrypted_attachment(_s)) {
   5.518 +                    ctext = _s->data;
   5.519 +                    csize = _s->size;
   5.520 +
   5.521 +                    status = decrypt_and_verify(session, ctext, csize, &ptext,
   5.522 +                            &psize, &keylist);
   5.523 +                    if (ptext == NULL)
   5.524 +                        goto pep_error;
   5.525 +                    
   5.526 +                    if (is_encrypted_html_attachment(_s)) {
   5.527 +                        msg->longmsg_formatted = strdup(ptext);
   5.528 +                        if (msg->longmsg_formatted == NULL)
   5.529 +                            goto pep_error;
   5.530 +                    }
   5.531 +                    else {
   5.532 +                        char * mime_type = "application/octet-stream";
   5.533 +                        char * filename = without_double_ending(_s->filename);
   5.534 +                        if (filename == NULL)
   5.535 +                            goto enomem;
   5.536 +
   5.537 +                        _m = bloblist_add(_m, ptext, psize, mime_type, filename);
   5.538 +                        if (_m == NULL)
   5.539 +                            goto enomem;
   5.540 +
   5.541 +                       if (msg->attachments == NULL)
   5.542 +                            msg->attachments = _m;
   5.543 +                    }
   5.544 +                }
   5.545              }
   5.546  
   5.547 -            ctext = src->longmsg;
   5.548 -            csize = strlen(src->longmsg);
   5.549 -
   5.550 -            status = decrypt_and_verify(session, ctext, csize, &ptext, &psize,
   5.551 -                    &keylist);
   5.552 -            if (ptext == NULL)
   5.553 -                goto pep_error;
   5.554 -
   5.555 -            if (src->enc_format == PEP_enc_PGP_MIME) {
   5.556 -                if (src->shortmsg == NULL || strcmp(src->shortmsg, "pEp") == 0)
   5.557 -                {
   5.558 -                    char * shortmsg;
   5.559 -                    char * longmsg;
   5.560 -
   5.561 -                    int r = seperate_short_and_long(ptext, &shortmsg,
   5.562 -                            &longmsg);
   5.563 -                    free(ptext);
   5.564 -                    if (r == -1)
   5.565 -                        goto enomem;
   5.566 -
   5.567 -                    msg->shortmsg = shortmsg;
   5.568 -                    msg->longmsg = longmsg;
   5.569 -                }
   5.570 -                else {
   5.571 -                    msg->shortmsg = strdup(src->shortmsg);
   5.572 -                    if (msg->shortmsg == NULL)
   5.573 -                        goto enomem;
   5.574 -                    msg->longmsg = ptext;
   5.575 -                }
   5.576 -            }
   5.577 -            else {
   5.578 -                
   5.579 -            }
   5.580              break;
   5.581  
   5.582          default:
   5.583 -            assert(0);
   5.584 -            status = PEP_ILLEGAL_VALUE;
   5.585 -            goto pep_error;
   5.586 +            // BUG: must implement more
   5.587 +            NOT_IMPLEMENTED
   5.588      }
   5.589  
   5.590 +    switch (src->enc_format) {
   5.591 +        case PEP_enc_PGP_MIME:
   5.592 +        case PEP_enc_pieces:
   5.593 +            status = copy_fields(msg, src);
   5.594 +            if (status != PEP_STATUS_OK)
   5.595 +                goto pep_error;
   5.596 +
   5.597 +            if (src->shortmsg) {
   5.598 +                free(msg->shortmsg);
   5.599 +                msg->shortmsg = strdup(src->shortmsg);
   5.600 +                if (msg->shortmsg == NULL)
   5.601 +                    goto enomem;
   5.602 +            }
   5.603 +
   5.604 +            if (msg->shortmsg == NULL || strcmp(msg->shortmsg, "pEp") == 0)
   5.605 +            {
   5.606 +                char * shortmsg;
   5.607 +                char * longmsg;
   5.608 +
   5.609 +                int r = seperate_short_and_long(msg->longmsg, &shortmsg,
   5.610 +                        &longmsg);
   5.611 +                if (r == -1)
   5.612 +                    goto enomem;
   5.613 +
   5.614 +                free(msg->shortmsg);
   5.615 +                free(msg->longmsg);
   5.616 +
   5.617 +                msg->shortmsg = shortmsg;
   5.618 +                msg->longmsg = longmsg;
   5.619 +            }
   5.620 +            else {
   5.621 +                msg->shortmsg = strdup(src->shortmsg);
   5.622 +                if (msg->shortmsg == NULL)
   5.623 +                    goto enomem;
   5.624 +                msg->longmsg = ptext;
   5.625 +            }
   5.626 +
   5.627 +        default:
   5.628 +            // BUG: must implement more
   5.629 +            NOT_IMPLEMENTED
   5.630 +    }
   5.631 +
   5.632 +    switch (mime) {
   5.633 +        case PEP_MIME_none:
   5.634 +            break;
   5.635 +
   5.636 +        case PEP_MIME:
   5.637 +        case PEP_MIME_fields_omitted:
   5.638 +            {
   5.639 +                char *text = NULL;
   5.640 +                status = mime_encode_message(msg,
   5.641 +                        mime == PEP_MIME_fields_omitted, &text);
   5.642 +                if (status != PEP_STATUS_OK)
   5.643 +                    goto pep_error;
   5.644 +
   5.645 +                message *_msg = clone_to_empty_message(msg);
   5.646 +                if (_msg == NULL) {
   5.647 +                    free(text);
   5.648 +                    goto enomem;
   5.649 +                }
   5.650 +                _msg->longmsg = text;
   5.651 +                _msg->shortmsg = strdup(msg->shortmsg);
   5.652 +                if (msg->shortmsg == NULL)
   5.653 +                    goto enomem;
   5.654 +
   5.655 +                free_message(msg);
   5.656 +                msg = _msg;
   5.657 +            }
   5.658 +    }
   5.659 +
   5.660 +    if (free_src)
   5.661 +        free_message(src);
   5.662      *dst = msg;
   5.663      return PEP_STATUS_OK;
   5.664  
   5.665 @@ -499,6 +738,8 @@
   5.666  
   5.667  pep_error:
   5.668      free_message(msg);
   5.669 +    if (free_src)
   5.670 +        free_message(src);
   5.671  
   5.672      return status;
   5.673  }
     6.1 --- a/src/message_api.h	Sat Mar 14 11:28:14 2015 +0100
     6.2 +++ b/src/message_api.h	Sun Mar 15 10:14:43 2015 +0100
     6.3 @@ -32,7 +32,7 @@
     6.4  
     6.5  DYNAMIC_API PEP_STATUS encrypt_message(
     6.6          PEP_SESSION session,
     6.7 -        const message *src,
     6.8 +        message *src,
     6.9          stringlist_t *extra,
    6.10          message **dst,
    6.11          PEP_enc_format enc_format
    6.12 @@ -44,8 +44,8 @@
    6.13  //  parameters:
    6.14  //      session (in)        session handle
    6.15  //      src (in)            message to decrypt
    6.16 +//      mime (in)           MIME encoding wanted
    6.17  //      dst (out)           pointer to new decrypted message or NULL on failure
    6.18 -//      enc_format (in)     unencrypted format
    6.19  //
    6.20  //  return value:
    6.21  //      error status or PEP_STATUS_OK on success
    6.22 @@ -55,9 +55,9 @@
    6.23  
    6.24  DYNAMIC_API PEP_STATUS decrypt_message(
    6.25          PEP_SESSION session,
    6.26 -        const message *src,
    6.27 -        message **dst,
    6.28 -        PEP_enc_format enc_format
    6.29 +        message *src,
    6.30 +        PEP_MIME_format mime,
    6.31 +        message **dst
    6.32      );
    6.33  
    6.34  #ifdef __cplusplus
     7.1 --- a/src/mime.c	Sat Mar 14 11:28:14 2015 +0100
     7.2 +++ b/src/mime.c	Sun Mar 15 10:14:43 2015 +0100
     7.3 @@ -213,7 +213,7 @@
     7.4      else
     7.5          mime_type = blob->mime_type;
     7.6  
     7.7 -    mime = get_file_part(blob->file_name, mime_type, blob->data, blob->size);
     7.8 +    mime = get_file_part(blob->filename, mime_type, blob->data, blob->size);
     7.9      assert(mime);
    7.10      if (mime == NULL)
    7.11          goto enomem;
    7.12 @@ -587,6 +587,7 @@
    7.13  
    7.14  DYNAMIC_API PEP_STATUS mime_encode_message(
    7.15          const message *msg,
    7.16 +        bool omit_fields,
    7.17          char **mimetext
    7.18      )
    7.19  {
    7.20 @@ -606,7 +607,7 @@
    7.21  
    7.22      *mimetext = NULL;
    7.23  
    7.24 -    if (msg->enc_format == PEP_enc_none_MIME) {
    7.25 +    if (msg->mime == PEP_MIME) {
    7.26          assert(0); // why encoding again what is already encoded?
    7.27          buf = strdup(msg->longmsg);
    7.28          if (buf == NULL)
    7.29 @@ -683,11 +684,13 @@
    7.30          goto enomem;
    7.31      }
    7.32  
    7.33 -    status = build_fields(msg, &fields);
    7.34 -    if (status != PEP_STATUS_OK)
    7.35 -        goto pep_error;
    7.36 +    if (!omit_fields) {
    7.37 +        status = build_fields(msg, &fields);
    7.38 +        if (status != PEP_STATUS_OK)
    7.39 +            goto pep_error;
    7.40  
    7.41 -    mailmime_set_imf_fields(msg_mime, fields);
    7.42 +        mailmime_set_imf_fields(msg_mime, fields);
    7.43 +    }
    7.44  
    7.45      status = render_mime(msg_mime, &buf);
    7.46      if (status != PEP_STATUS_OK)
    7.47 @@ -1045,7 +1048,7 @@
    7.48      assert(msg);
    7.49  
    7.50      *msg = NULL;
    7.51 -    
    7.52 +
    7.53      index = 0;
    7.54      r = mailmime_parse(mimetext, strlen(mimetext), &index, &mime);
    7.55      assert(r == 0);
     8.1 --- a/src/mime.h	Sat Mar 14 11:28:14 2015 +0100
     8.2 +++ b/src/mime.h	Sun Mar 15 10:14:43 2015 +0100
     8.3 @@ -11,6 +11,7 @@
     8.4  //
     8.5  //  parameters:
     8.6  //      msg (in)                message to encode
     8.7 +//      omit_fields (in)        only encode message body and attachments
     8.8  //      mimetext (out)          the resulting encoded text or NULL on any error
     8.9  //
    8.10  //  return value:
    8.11 @@ -25,9 +26,11 @@
    8.12  //  caveat:
    8.13  //      the resulttext will go to the ownership of the caller
    8.14  //      the message will remain in the ownership of the caller
    8.15 +//      omit_fields is true for payload of PGP/MIME messages
    8.16  
    8.17  DYNAMIC_API PEP_STATUS mime_encode_message(
    8.18          const message * msg,
    8.19 +        bool omit_fields,
    8.20          char **mimetext
    8.21      );
    8.22  
     9.1 --- a/src/pEpEngine.c	Sat Mar 14 11:28:14 2015 +0100
     9.2 +++ b/src/pEpEngine.c	Sun Mar 15 10:14:43 2015 +0100
     9.3 @@ -24,7 +24,7 @@
     9.4          return PEP_INIT_SQLITE3_WITHOUT_MUTEX;
     9.5  
     9.6      // a little race condition - but still a race condition
     9.7 -    // removed by calling caveat (see documentation)
     9.8 +    // mitigated by calling caveat (see documentation)
     9.9  
    9.10      ++init_count;
    9.11      if (init_count == 0)
    9.12 @@ -255,7 +255,7 @@
    9.13  	assert(session);
    9.14  
    9.15      // a small race condition but still a race condition
    9.16 -    // removed by calling caveat (see documentation)
    9.17 +    // mitigated by calling caveat (see documentation)
    9.18  
    9.19      if (init_count == 0)
    9.20          out_last = true;
    10.1 --- a/src/platform_windows.h	Sat Mar 14 11:28:14 2015 +0100
    10.2 +++ b/src/platform_windows.h	Sun Mar 15 10:14:43 2015 +0100
    10.3 @@ -15,7 +15,7 @@
    10.4  void *dlsym(void *handle, const char *symbol);
    10.5  
    10.6  #ifndef strdup
    10.7 -#define strdup(A) _strdup(A)
    10.8 +#define strdup(A) _strdup((A))
    10.9  #endif
   10.10  #ifndef snprintf
   10.11  #define snprintf(...) _snprintf(__VA_ARGS__)
   10.12 @@ -26,6 +26,10 @@
   10.13  #ifndef strncasecmp
   10.14  #define strncasecmp(A, B, C) _strnicmp((A), (B), (C))
   10.15  #endif
   10.16 +#ifndef gmtime_r
   10.17 +#define gmtime_r(A, B) gmtime_s((B), (A))
   10.18 +#endif
   10.19 +
   10.20  char *strndup(const char *s1, size_t n);
   10.21  
   10.22  const char *windoze_local_db(void);
    11.1 --- a/src/stringlist.c	Sat Mar 14 11:28:14 2015 +0100
    11.2 +++ b/src/stringlist.c	Sun Mar 15 10:14:43 2015 +0100
    11.3 @@ -43,7 +43,10 @@
    11.4      return dst;
    11.5  }
    11.6  
    11.7 -DYNAMIC_API stringlist_t *stringlist_add(stringlist_t *stringlist, const char *value)
    11.8 +DYNAMIC_API stringlist_t *stringlist_add(
    11.9 +        stringlist_t *stringlist,
   11.10 +        const char *value
   11.11 +    )
   11.12  {
   11.13      assert(value);
   11.14  
   11.15 @@ -68,8 +71,10 @@
   11.16      return stringlist->next;
   11.17  }
   11.18  
   11.19 -DYNAMIC_API stringlist_t *stringlist_append(stringlist_t *stringlist,
   11.20 -        stringlist_t *second)
   11.21 +DYNAMIC_API stringlist_t *stringlist_append(
   11.22 +        stringlist_t *stringlist,
   11.23 +        stringlist_t *second
   11.24 +    )
   11.25  {
   11.26      assert(stringlist);
   11.27  
   11.28 @@ -96,7 +101,8 @@
   11.29      if (stringlist->value == NULL)
   11.30          return 0;
   11.31  
   11.32 -    for (_stringlist=stringlist->next; _stringlist!=NULL; _stringlist=_stringlist->next)
   11.33 +    for (_stringlist=stringlist->next; _stringlist!=NULL;
   11.34 +            _stringlist=_stringlist->next)
   11.35          len += 1;
   11.36  
   11.37      return len;
    12.1 --- a/src/stringlist.h	Sat Mar 14 11:28:14 2015 +0100
    12.2 +++ b/src/stringlist.h	Sun Mar 15 10:14:43 2015 +0100
    12.3 @@ -52,7 +52,10 @@
    12.4  //      the value is being copied before being added to the list
    12.5  //      the original string is still being owned by the caller
    12.6  
    12.7 -DYNAMIC_API stringlist_t *stringlist_add(stringlist_t *stringlist, const char *value);
    12.8 +DYNAMIC_API stringlist_t *stringlist_add(
    12.9 +        stringlist_t *stringlist,
   12.10 +        const char *value
   12.11 +    );
   12.12  
   12.13  
   12.14  // stringlist_append() - append stringlist to stringlist
   12.15 @@ -68,8 +71,10 @@
   12.16  //      all values are being copied before being added to the list
   12.17  //      the original values are still being owned by the caller
   12.18  
   12.19 -DYNAMIC_API stringlist_t *stringlist_append(stringlist_t *stringlist,
   12.20 -        stringlist_t *second);
   12.21 +DYNAMIC_API stringlist_t *stringlist_append(
   12.22 +        stringlist_t *stringlist,
   12.23 +        stringlist_t *second
   12.24 +    );
   12.25  
   12.26  
   12.27  // stringlist_length() - get length of stringlist
    13.1 --- a/test/message_api_test.cc	Sat Mar 14 11:28:14 2015 +0100
    13.2 +++ b/test/message_api_test.cc	Sun Mar 15 10:14:43 2015 +0100
    13.3 @@ -26,7 +26,7 @@
    13.4      cout << "message created.\n";
    13.5  
    13.6      char *text2;
    13.7 -    PEP_STATUS status2 = mime_encode_message(msg2, &text2);
    13.8 +    PEP_STATUS status2 = mime_encode_message(msg2, false, &text2);
    13.9      assert(status2 == PEP_STATUS_OK);
   13.10      assert(text2);
   13.11  
   13.12 @@ -38,12 +38,12 @@
   13.13      cout << "encrypting message as MIME multipart…\n";
   13.14      message *enc_msg2;
   13.15      cout << "calling encrypt_message()\n";
   13.16 -    status2 = encrypt_message(session, msg2, NULL, &enc_msg2, PEP_enc_MIME_multipart);
   13.17 +    status2 = encrypt_message(session, msg2, NULL, &enc_msg2, PEP_enc_PGP_MIME);
   13.18      assert(status2 == PEP_STATUS_OK);
   13.19      assert(enc_msg2);
   13.20      cout << "message encrypted.\n";
   13.21      
   13.22 -    status2 = mime_encode_message(enc_msg2, &text2);
   13.23 +    status2 = mime_encode_message(enc_msg2, false, &text2);
   13.24      assert(status2 == PEP_STATUS_OK);
   13.25      assert(text2);
   13.26  
    14.1 --- a/test/mime_test.cc	Sat Mar 14 11:28:14 2015 +0100
    14.2 +++ b/test/mime_test.cc	Sun Mar 15 10:14:43 2015 +0100
    14.3 @@ -34,7 +34,7 @@
    14.4  
    14.5      cout << "encoding message…\n";
    14.6      char *result2;
    14.7 -    PEP_STATUS status2 = mime_encode_message(msg2, &result2);
    14.8 +    PEP_STATUS status2 = mime_encode_message(msg2, false, &result2);
    14.9      assert(result2);
   14.10      assert(status2 == PEP_STATUS_OK);
   14.11