Merge default ENGINE-261
authorDamiano Boppart <damiano@pep-security.net>
Thu, 26 Oct 2017 14:09:20 +0200
branchENGINE-261
changeset 2209b81b671adac1
parent 2087 b78cf1185fe4
parent 2204 765c6ff31183
child 2210 17c30881c885
Merge default
     1.1 --- a/Makefile	Thu Sep 21 15:46:18 2017 +0200
     1.2 +++ b/Makefile	Thu Oct 26 14:09:20 2017 +0200
     1.3 @@ -7,9 +7,6 @@
     1.4  
     1.5  include Makefile.conf
     1.6  
     1.7 -# YML_PATH is needed in the environment of every call to a program of the YML2 distribution
     1.8 -export YML_PATH=$(YML2_PATH)
     1.9 -
    1.10  .PHONY: all
    1.11  all: _override_info
    1.12  	$(MAKE) -C asn.1 generate
     2.1 --- a/Makefile.conf	Thu Sep 21 15:46:18 2017 +0200
     2.2 +++ b/Makefile.conf	Thu Oct 26 14:09:20 2017 +0200
     2.3 @@ -45,12 +45,12 @@
     2.4  
     2.5  # If empty, create a release build.
     2.6  # Otherwise, create a debug build.
     2.7 -# This variable is ineffective in your override.conf file.
     2.8 -DEBUG=
     2.9 +# This variable is ineffective in your local.conf file.
    2.10 +DEBUG=YES
    2.11  
    2.12  # If empty, suppress compiler warnings.
    2.13  # Otherwise, print warnings.
    2.14 -# This variable is ineffective in your override.conf file.
    2.15 +# This variable is ineffective in your local.conf file.
    2.16  WARN=placeholder
    2.17  
    2.18  
    2.19 @@ -98,7 +98,7 @@
    2.20      else
    2.21          CFLAGS+= -O3 -DNDEBUG
    2.22      endif
    2.23 -else ifeq ($(BUILD_FOR),Darwin)    
    2.24 +else ifeq ($(BUILD_FOR),Darwin)
    2.25      ifdef WARN
    2.26          # FIXME Remove 'no-extended-offsetof' after ENGINE-236 is closed.
    2.27          CFLAGS+= -Wall -pedantic -Wno-extended-offsetof
    2.28 @@ -169,6 +169,8 @@
    2.29  
    2.30  YML2_OPTS=--encoding=utf8
    2.31  
    2.32 +# YML_PATH is needed in the environment of every call to a program of the YML2 distribution
    2.33 +export YML_PATH=$(YML2_PATH)
    2.34  
    2.35  ######### asn1c #########
    2.36  # asn1c binary
    2.37 @@ -195,6 +197,7 @@
    2.38  
    2.39  ######### OpenPGP #########
    2.40  # Path of GPG binary
    2.41 +# gpgconf is not available for old version of GPG, for example GPG 2.0.30. Override this variable, if you compile the engine for such an old version.
    2.42  GPG_CMD:=$(shell gpgconf --list-components | awk -F: '/^gpg:/ { print $$3; exit 0; }')
    2.43  
    2.44  # Selects OpenPGP implementation. must be either `GPG` or `NETPGP`
     3.1 --- a/build-mac/pEpEngine.xcodeproj/project.pbxproj	Thu Sep 21 15:46:18 2017 +0200
     3.2 +++ b/build-mac/pEpEngine.xcodeproj/project.pbxproj	Thu Oct 26 14:09:20 2017 +0200
     3.3 @@ -123,7 +123,6 @@
     3.4  		64A826811B455D0800EECAF0 /* pEpEngine.c in Sources */ = {isa = PBXBuildFile; fileRef = 64A826601B455D0800EECAF0 /* pEpEngine.c */; };
     3.5  		64A826821B455D0800EECAF0 /* pgp_netpgp.c in Sources */ = {isa = PBXBuildFile; fileRef = 64A826631B455D0800EECAF0 /* pgp_netpgp.c */; };
     3.6  		64A826831B455D0800EECAF0 /* platform_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 64A826651B455D0800EECAF0 /* platform_unix.c */; };
     3.7 -		64A826851B455D0800EECAF0 /* sqlite3.c in Sources */ = {isa = PBXBuildFile; fileRef = 64A8266B1B455D0800EECAF0 /* sqlite3.c */; };
     3.8  		64A826861B455D0800EECAF0 /* stringlist.c in Sources */ = {isa = PBXBuildFile; fileRef = 64A8266D1B455D0800EECAF0 /* stringlist.c */; };
     3.9  		64A826871B455D0800EECAF0 /* stringpair.c in Sources */ = {isa = PBXBuildFile; fileRef = 64A8266F1B455D0800EECAF0 /* stringpair.c */; };
    3.10  		64A826881B455D0800EECAF0 /* timestamp.c in Sources */ = {isa = PBXBuildFile; fileRef = 64A826711B455D0800EECAF0 /* timestamp.c */; };
    3.11 @@ -815,7 +814,6 @@
    3.12  				64A826861B455D0800EECAF0 /* stringlist.c in Sources */,
    3.13  				4354FF651D6EDF300033069C /* sync_impl.c in Sources */,
    3.14  				64A8267E1B455D0800EECAF0 /* message_api.c in Sources */,
    3.15 -				64A826851B455D0800EECAF0 /* sqlite3.c in Sources */,
    3.16  				43E9BC7F1DB6720E00AD2352 /* UpdateRequest.c in Sources */,
    3.17  				646C41361D510CD800C63EFF /* Version.c in Sources */,
    3.18  				646C41081D510CD800C63EFF /* constr_TYPE.c in Sources */,
    3.19 @@ -959,6 +957,7 @@
    3.20  				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
    3.21  				MTL_ENABLE_DEBUG_INFO = YES;
    3.22  				ONLY_ACTIVE_ARCH = YES;
    3.23 +				OTHER_CFLAGS = "-DSQLITE3_FROM_OS";
    3.24  				SDKROOT = iphoneos;
    3.25  			};
    3.26  			name = Debug;
    3.27 @@ -1006,6 +1005,7 @@
    3.28  				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
    3.29  				MTL_ENABLE_DEBUG_INFO = NO;
    3.30  				ONLY_ACTIVE_ARCH = NO;
    3.31 +				OTHER_CFLAGS = "-DSQLITE3_FROM_OS";
    3.32  				SDKROOT = iphoneos;
    3.33  				VALIDATE_PRODUCT = YES;
    3.34  			};
     4.1 --- a/build-windows/pEpEngine.vcxproj	Thu Sep 21 15:46:18 2017 +0200
     4.2 +++ b/build-windows/pEpEngine.vcxproj	Thu Oct 26 14:09:20 2017 +0200
     4.3 @@ -43,12 +43,12 @@
     4.4    <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     4.5      <LinkIncremental>true</LinkIncremental>
     4.6      <RunCodeAnalysis>false</RunCodeAnalysis>
     4.7 -    <IncludePath>$(ProjectDir)\..\..\libetpan\build-windows\include;C:\Program Files %28x86%29\GNU\GnuPG\include;$(IncludePath);$(ProjectDir)\asn.1;%ASN1C%\share\asn1c</IncludePath>
     4.8 +	<IncludePath>$(ProjectDir)\..\..\libetpan\build-windows\include;C:\Program Files %28x86%29\GnuPG\include;$(IncludePath);$(ProjectDir)\asn.1;%ASN1C%\share\asn1c</IncludePath>
     4.9      <LibraryPath>$(ProjectDir)\..\..\libetpan\build-windows\Debug;$(LibraryPath)</LibraryPath>
    4.10    </PropertyGroup>
    4.11    <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    4.12      <LinkIncremental>false</LinkIncremental>
    4.13 -    <IncludePath>$(ProjectDir)\..\..\libetpan\build-windows\include;C:\Program Files %28x86%29\GNU\GnuPG\include;$(IncludePath);$(ProjectDir)\asn.1;%ASN1C%\share\asn1c</IncludePath>
    4.14 +	<IncludePath>$(ProjectDir)\..\..\libetpan\build-windows\include;C:\Program Files %28x86%29\GnuPG\include;$(IncludePath);$(ProjectDir)\asn.1;%ASN1C%\share\asn1c</IncludePath>
    4.15      <LibraryPath>$(ProjectDir)\..\..\libetpan\build-windows\Release;$(LibraryPath)</LibraryPath>
    4.16    </PropertyGroup>
    4.17    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     5.1 --- a/doc/build-debian.md	Thu Sep 21 15:46:18 2017 +0200
     5.2 +++ b/doc/build-debian.md	Thu Oct 26 14:09:20 2017 +0200
     5.3 @@ -17,7 +17,7 @@
     5.4  # asn1c
     5.5  apt install -y git build-essential automake libtool
     5.6  # engine
     5.7 -apt install -y uuid-dev libgpgme11-dev libsqlite3-dev sqlite3
     5.8 +apt install -y uuid-dev libgpgme-dev libsqlite3-dev sqlite3
     5.9  ~~~
    5.10  
    5.11  # Installing unpackaged dependencies
     6.1 --- a/src/etpan_mime.c	Thu Sep 21 15:46:18 2017 +0200
     6.2 +++ b/src/etpan_mime.c	Thu Oct 26 14:09:20 2017 +0200
     6.3 @@ -284,7 +284,8 @@
     6.4          pEp_rid_list_t* resource,
     6.5          const char * mime_type,
     6.6          char * data,
     6.7 -        size_t length
     6.8 +        size_t length,
     6.9 +        bool transport_encode
    6.10      )
    6.11  {
    6.12      char * disposition_name = NULL;
    6.13 @@ -330,10 +331,14 @@
    6.14      if (content == NULL)
    6.15          goto enomem;
    6.16  
    6.17 -    encoding_type = MAILMIME_MECHANISM_BASE64;
    6.18 -    encoding = mailmime_mechanism_new(encoding_type, NULL);
    6.19 -    if (encoding == NULL)
    6.20 -        goto enomem;
    6.21 +    encoding = NULL;
    6.22 +
    6.23 +    if (transport_encode) {
    6.24 +        encoding_type = MAILMIME_MECHANISM_BASE64;
    6.25 +        encoding = mailmime_mechanism_new(encoding_type, NULL);
    6.26 +        if (encoding == NULL)
    6.27 +            goto enomem;
    6.28 +    }
    6.29  
    6.30      mime_fields = mailmime_fields_new_with_data(encoding, content_id, NULL,
    6.31              disposition, NULL);
     7.1 --- a/src/etpan_mime.h	Thu Sep 21 15:46:18 2017 +0200
     7.2 +++ b/src/etpan_mime.h	Thu Oct 26 14:09:20 2017 +0200
     7.3 @@ -29,7 +29,8 @@
     7.4          pEp_rid_list_t* resource,
     7.5          const char * mime_type,
     7.6          char * data,
     7.7 -        size_t length
     7.8 +        size_t length,
     7.9 +        bool transport_encode
    7.10      );
    7.11  
    7.12  struct mailmime * part_multiple_new(const char *type);
     8.1 --- a/src/keymanagement.c	Thu Sep 21 15:46:18 2017 +0200
     8.2 +++ b/src/keymanagement.c	Thu Oct 26 14:09:20 2017 +0200
     8.3 @@ -723,12 +723,38 @@
     8.4      }
     8.5      else
     8.6      {
     8.7 +        // for undo
     8.8 +        if (session->cached_mistrusted)
     8.9 +            free(session->cached_mistrusted);
    8.10 +        session->cached_mistrusted = identity_dup(ident);
    8.11          status = mark_as_compromized(session, ident->fpr);
    8.12      }
    8.13  
    8.14      return status;
    8.15  }
    8.16  
    8.17 +DYNAMIC_API PEP_STATUS undo_last_mistrust(PEP_SESSION session) {
    8.18 +    assert(session);
    8.19 +    
    8.20 +    if (!session)
    8.21 +        return PEP_ILLEGAL_VALUE;
    8.22 +    
    8.23 +    PEP_STATUS status = PEP_STATUS_OK;
    8.24 +        
    8.25 +    pEp_identity* cached_ident = session->cached_mistrusted;
    8.26 +    
    8.27 +    if (!cached_ident)
    8.28 +        status = PEP_CANNOT_FIND_IDENTITY;
    8.29 +    else {
    8.30 +        status = set_identity(session, cached_ident);            
    8.31 +        free_identity(session->cached_mistrusted);
    8.32 +    }
    8.33 +    
    8.34 +    session->cached_mistrusted = NULL;
    8.35 +
    8.36 +    return status;
    8.37 +}
    8.38 +
    8.39  DYNAMIC_API PEP_STATUS key_reset_trust(
    8.40          PEP_SESSION session,
    8.41          pEp_identity *ident
     9.1 --- a/src/keymanagement.h	Thu Sep 21 15:46:18 2017 +0200
     9.2 +++ b/src/keymanagement.h	Thu Oct 26 14:09:20 2017 +0200
     9.3 @@ -125,17 +125,35 @@
     9.4      );
     9.5  
     9.6  
     9.7 -// key_mistrusted() - mark key as being compromized
     9.8 +// key_mistrusted() - mark key as being compromised
     9.9  //
    9.10  //  parameters:
    9.11  //      session (in)        session to use
    9.12 -//      ident (in)          person and key which was compromized
    9.13 +//      ident (in)          person and key which was compromised
    9.14  
    9.15  DYNAMIC_API PEP_STATUS key_mistrusted(
    9.16          PEP_SESSION session,
    9.17          pEp_identity *ident
    9.18      );
    9.19  
    9.20 +// undo_last_mistrust() - reset identity and trust status for the last
    9.21 +//                        identity in this session marked as mistrusted
    9.22 +//                        to their cached values from the time of mistrust
    9.23 +//  parameters:
    9.24 +//      session (in)        session to use
    9.25 +//
    9.26 +//  return value:
    9.27 +//      PEP_STATUS_OK if identity and trust were successfully restored.
    9.28 +//      Otherwise, error status from attempts to set.
    9.29 +//
    9.30 +//  caveat:
    9.31 +//      only works for this session, and only once. cache is invalidated
    9.32 +//      upon use.
    9.33 +//
    9.34 +//      WILL NOT WORK ON MISTRUSTED OWN KEY
    9.35 +
    9.36 +DYNAMIC_API PEP_STATUS undo_last_mistrust(PEP_SESSION session);
    9.37 +
    9.38  
    9.39  // trust_personal_key() - mark a key as trusted with a person
    9.40  //
    10.1 --- a/src/message.h	Thu Sep 21 15:46:18 2017 +0200
    10.2 +++ b/src/message.h	Thu Oct 26 14:09:20 2017 +0200
    10.3 @@ -163,4 +163,3 @@
    10.4  #ifdef __cplusplus
    10.5  }
    10.6  #endif
    10.7 -
    11.1 --- a/src/message_api.c	Thu Sep 21 15:46:18 2017 +0200
    11.2 +++ b/src/message_api.c	Thu Oct 26 14:09:20 2017 +0200
    11.3 @@ -11,6 +11,7 @@
    11.4  #include <assert.h>
    11.5  #include <string.h>
    11.6  #include <stdlib.h>
    11.7 +#include <math.h>
    11.8  
    11.9  
   11.10  #ifndef _MIN
   11.11 @@ -20,629 +21,6 @@
   11.12  #define _MAX(A, B) ((B) > (A) ? (B) : (A))
   11.13  #endif
   11.14  
   11.15 -static char* _get_resource_ptr_noown(char* uri) {
   11.16 -    char* uri_delim = strstr(uri, "://");
   11.17 -    if (!uri_delim)
   11.18 -        return uri;
   11.19 -    else
   11.20 -        return uri + 3;
   11.21 -}
   11.22 -
   11.23 -static bool is_file_uri(char* str) {
   11.24 -    return(strncmp(str, "file://", 7) == 0);
   11.25 -}
   11.26 -
   11.27 -static bool is_cid_uri(const char* str) {
   11.28 -    return(strncmp(str, "cid://", 6) == 0);
   11.29 -}
   11.30 -
   11.31 -static bool string_equality(const char *s1, const char *s2)
   11.32 -{
   11.33 -    if (s1 == NULL || s2 == NULL)
   11.34 -        return false;
   11.35 -
   11.36 -    assert(s1 && s2);
   11.37 -
   11.38 -    return strcmp(s1, s2) == 0;
   11.39 -}
   11.40 -
   11.41 -static bool is_mime_type(const bloblist_t *bl, const char *mt)
   11.42 -{
   11.43 -    assert(mt);
   11.44 -
   11.45 -    return bl && string_equality(bl->mime_type, mt);
   11.46 -}
   11.47 -
   11.48 -//
   11.49 -// This function presumes the file ending is a proper substring of the
   11.50 -// filename (i.e. if bl->filename is "a.pgp" and fe is ".pgp", it will
   11.51 -// return true, but if bl->filename is ".pgp" and fe is ".pgp", it will
   11.52 -// return false. This is desired behaviour.
   11.53 -//
   11.54 -static bool is_fileending(const bloblist_t *bl, const char *fe)
   11.55 -{
   11.56 -    assert(fe);
   11.57 -
   11.58 -    if (bl == NULL || bl->filename == NULL || fe == NULL || is_cid_uri(bl->filename))
   11.59 -        return false;
   11.60 -
   11.61 -    assert(bl && bl->filename);
   11.62 -
   11.63 -    size_t fe_len = strlen(fe);
   11.64 -    size_t fn_len = strlen(bl->filename);
   11.65 -
   11.66 -    if (fn_len <= fe_len)
   11.67 -        return false;
   11.68 -
   11.69 -    assert(fn_len > fe_len);
   11.70 -
   11.71 -    return strcmp(bl->filename + (fn_len - fe_len), fe) == 0;
   11.72 -}
   11.73 -
   11.74 -void add_opt_field(message *msg, const char *name, const char *value)
   11.75 -{
   11.76 -    assert(msg && name && value);
   11.77 -
   11.78 -    if (msg && name && value) {
   11.79 -        stringpair_t *pair = new_stringpair(name, value);
   11.80 -        if (pair == NULL)
   11.81 -            return;
   11.82 -
   11.83 -        stringpair_list_t *field = stringpair_list_add(msg->opt_fields, pair);
   11.84 -        if (field == NULL)
   11.85 -        {
   11.86 -            free_stringpair(pair);
   11.87 -            return;
   11.88 -        }
   11.89 -
   11.90 -        if (msg->opt_fields == NULL)
   11.91 -            msg->opt_fields = field;
   11.92 -    }
   11.93 -}
   11.94 -
   11.95 -static char * combine_short_and_long(const char *shortmsg, const char *longmsg)
   11.96 -{
   11.97 -    assert(shortmsg);
   11.98 -    
   11.99 -    unsigned char pepstr[] = PEP_SUBJ_STRING;
  11.100 -    assert(strcmp(shortmsg, "pEp") != 0 && _unsigned_signed_strcmp(pepstr, shortmsg, PEP_SUBJ_BYTELEN) != 0); 
  11.101 -    
  11.102 -    if (!shortmsg || strcmp(shortmsg, "pEp") == 0 || 
  11.103 -                     _unsigned_signed_strcmp(pepstr, shortmsg, PEP_SUBJ_BYTELEN) == 0) {
  11.104 -        if (!longmsg) {
  11.105 -            return NULL;
  11.106 -        }
  11.107 -        else {
  11.108 -            char *result = strdup(longmsg);
  11.109 -            assert(result);
  11.110 -            return result;
  11.111 -        }
  11.112 -    }
  11.113 -
  11.114 -    if (longmsg == NULL)
  11.115 -        longmsg = "";
  11.116 -
  11.117 -    const char * const subject = "Subject: ";
  11.118 -    const size_t SUBJ_LEN = 9;
  11.119 -    const char * const newlines = "\n\n";
  11.120 -    const size_t NL_LEN = 2;
  11.121 -
  11.122 -    const size_t bufsize = SUBJ_LEN + strlen(shortmsg) + NL_LEN + strlen(longmsg) + 1;
  11.123 -    char * ptext = calloc(1, bufsize);
  11.124 -    assert(ptext);
  11.125 -    if (ptext == NULL)
  11.126 -        return NULL;
  11.127 -
  11.128 -    strlcpy(ptext, subject, bufsize);
  11.129 -    strlcat(ptext, shortmsg, bufsize);
  11.130 -    strlcat(ptext, newlines, bufsize);
  11.131 -    strlcat(ptext, longmsg, bufsize);
  11.132 -
  11.133 -    return ptext;
  11.134 -}
  11.135 -
  11.136 -static int separate_short_and_long(const char *src, char **shortmsg, char **longmsg)
  11.137 -{
  11.138 -    char *_shortmsg = NULL;
  11.139 -    char *_longmsg = NULL;
  11.140 -
  11.141 -    assert(src);
  11.142 -    assert(shortmsg);
  11.143 -    assert(longmsg);
  11.144 -
  11.145 -    if (src == NULL || shortmsg == NULL || longmsg == NULL)
  11.146 -        return -1;
  11.147 -
  11.148 -    *shortmsg = NULL;
  11.149 -    *longmsg = NULL;
  11.150 -
  11.151 -    if (strncasecmp(src, "subject: ", 9) == 0) {
  11.152 -        char *line_end = strchr(src, '\n');
  11.153 -
  11.154 -        if (line_end == NULL) {
  11.155 -            _shortmsg = strdup(src + 9);
  11.156 -            assert(_shortmsg);
  11.157 -            if (_shortmsg == NULL)
  11.158 -                goto enomem;
  11.159 -            // _longmsg = NULL;
  11.160 -        }
  11.161 -        else {
  11.162 -            size_t n = line_end - src;
  11.163 -
  11.164 -            if (*(line_end - 1) == '\r')
  11.165 -                _shortmsg = strndup(src + 9, n - 10);
  11.166 -            else
  11.167 -                _shortmsg = strndup(src + 9, n - 9);
  11.168 -            assert(_shortmsg);
  11.169 -            if (_shortmsg == NULL)
  11.170 -                goto enomem;
  11.171 -
  11.172 -            while (*(src + n) && (*(src + n) == '\n' || *(src + n) == '\r'))
  11.173 -                ++n;
  11.174 -
  11.175 -            if (*(src + n)) {
  11.176 -                _longmsg = strdup(src + n);
  11.177 -                assert(_longmsg);
  11.178 -                if (_longmsg == NULL)
  11.179 -                    goto enomem;
  11.180 -            }
  11.181 -        }
  11.182 -        *shortmsg = _shortmsg;
  11.183 -    }
  11.184 -    else {
  11.185 -        // If there's no "Subject: " and the shortmsg is
  11.186 -        // pEp (or anything else), then we shouldn't be replacing it.
  11.187 -        // Chances are that the message wasn't encrypted
  11.188 -        // using pEp and that the actually subject IS pEp. In any event,
  11.189 -        // erasing the subject line when we don't have one in the plaintext
  11.190 -        // isn't the right behaviour.
  11.191 -        // _shortmsg = strdup("");
  11.192 -        _longmsg = strdup(src);
  11.193 -        assert(_longmsg);
  11.194 -        if (_longmsg == NULL)
  11.195 -            goto enomem;
  11.196 -    }
  11.197 -    
  11.198 -    *longmsg = _longmsg;
  11.199 -
  11.200 -    return 0;
  11.201 -
  11.202 -enomem:
  11.203 -    free(_shortmsg);
  11.204 -    free(_longmsg);
  11.205 -
  11.206 -    return -1;
  11.207 -}
  11.208 -
  11.209 -static PEP_STATUS copy_fields(message *dst, const message *src)
  11.210 -{
  11.211 -    assert(dst);
  11.212 -    assert(src);
  11.213 -
  11.214 -    if(!(dst && src))
  11.215 -        return PEP_ILLEGAL_VALUE;
  11.216 -
  11.217 -    free_timestamp(dst->sent);
  11.218 -    dst->sent = NULL;
  11.219 -    if (src->sent) {
  11.220 -        dst->sent = timestamp_dup(src->sent);
  11.221 -        if (dst->sent == NULL)
  11.222 -            return PEP_OUT_OF_MEMORY;
  11.223 -    }
  11.224 -
  11.225 -    free_timestamp(dst->recv);
  11.226 -    dst->recv = NULL;
  11.227 -    if (src->recv) {
  11.228 -        dst->recv = timestamp_dup(src->recv);
  11.229 -        if (dst->recv == NULL)
  11.230 -            return PEP_OUT_OF_MEMORY;
  11.231 -    }
  11.232 -
  11.233 -    free_identity(dst->from);
  11.234 -    dst->from = NULL;
  11.235 -    if (src->from) {
  11.236 -        dst->from = identity_dup(src->from);
  11.237 -        if (dst->from == NULL)
  11.238 -            return PEP_OUT_OF_MEMORY;
  11.239 -    }
  11.240 -
  11.241 -    free_identity_list(dst->to);
  11.242 -    dst->to = NULL;
  11.243 -    if (src->to && src->to->ident) {
  11.244 -        dst->to = identity_list_dup(src->to);
  11.245 -        if (dst->to == NULL)
  11.246 -            return PEP_OUT_OF_MEMORY;
  11.247 -    }
  11.248 -
  11.249 -    free_identity(dst->recv_by);
  11.250 -    dst->recv_by = NULL;
  11.251 -    if (src->recv_by) {
  11.252 -        dst->recv_by = identity_dup(src->recv_by);
  11.253 -        if (dst->recv_by == NULL)
  11.254 -            return PEP_OUT_OF_MEMORY;
  11.255 -    }
  11.256 -
  11.257 -    free_identity_list(dst->cc);
  11.258 -    dst->cc = NULL;
  11.259 -    if (src->cc && src->cc->ident) {
  11.260 -        dst->cc = identity_list_dup(src->cc);
  11.261 -        if (dst->cc == NULL)
  11.262 -            return PEP_OUT_OF_MEMORY;
  11.263 -    }
  11.264 -
  11.265 -    free_identity_list(dst->bcc);
  11.266 -    dst->bcc = NULL;
  11.267 -    if (src->bcc && src->bcc->ident) {
  11.268 -        dst->bcc = identity_list_dup(src->bcc);
  11.269 -        if (dst->bcc == NULL)
  11.270 -            return PEP_OUT_OF_MEMORY;
  11.271 -    }
  11.272 -
  11.273 -    free_identity_list(dst->reply_to);
  11.274 -    dst->reply_to = NULL;
  11.275 -    if (src->reply_to && src->reply_to->ident) {
  11.276 -        dst->reply_to = identity_list_dup(src->reply_to);
  11.277 -        if (dst->reply_to == NULL)
  11.278 -            return PEP_OUT_OF_MEMORY;
  11.279 -    }
  11.280 -
  11.281 -    free_stringlist(dst->in_reply_to);
  11.282 -    dst->in_reply_to = NULL;
  11.283 -    if (src->in_reply_to && src->in_reply_to->value) {
  11.284 -        dst->in_reply_to = stringlist_dup(src->in_reply_to);
  11.285 -        if (dst->in_reply_to == NULL)
  11.286 -            return PEP_OUT_OF_MEMORY;
  11.287 -    }
  11.288 -
  11.289 -    free_stringlist(dst->references);
  11.290 -    dst->references = NULL;
  11.291 -    if (src->references) {
  11.292 -        dst->references = stringlist_dup(src->references);
  11.293 -        if (dst->references == NULL)
  11.294 -            return PEP_OUT_OF_MEMORY;
  11.295 -    }
  11.296 -
  11.297 -    free_stringlist(dst->keywords);
  11.298 -    dst->keywords = NULL;
  11.299 -    if (src->keywords && src->keywords->value) {
  11.300 -        dst->keywords = stringlist_dup(src->keywords);
  11.301 -        if (dst->keywords == NULL)
  11.302 -            return PEP_OUT_OF_MEMORY;
  11.303 -    }
  11.304 -
  11.305 -    free(dst->comments);
  11.306 -    dst->comments = NULL;
  11.307 -    if (src->comments) {
  11.308 -        dst->comments = strdup(src->comments);
  11.309 -        assert(dst->comments);
  11.310 -        if (dst->comments == NULL)
  11.311 -            return PEP_OUT_OF_MEMORY;
  11.312 -    }
  11.313 -
  11.314 -    free_stringpair_list(dst->opt_fields);
  11.315 -    dst->opt_fields = NULL;
  11.316 -    if (src->opt_fields) {
  11.317 -        dst->opt_fields = stringpair_list_dup(src->opt_fields);
  11.318 -        if (dst->opt_fields == NULL)
  11.319 -            return PEP_OUT_OF_MEMORY;
  11.320 -    }
  11.321 -
  11.322 -    return PEP_STATUS_OK;
  11.323 -}
  11.324 -
  11.325 -static message * clone_to_empty_message(const message * src)
  11.326 -{
  11.327 -    PEP_STATUS status;
  11.328 -    message * msg = NULL;
  11.329 -
  11.330 -    assert(src);
  11.331 -    if (src == NULL)
  11.332 -        return NULL;
  11.333 -
  11.334 -    msg = calloc(1, sizeof(message));
  11.335 -    assert(msg);
  11.336 -    if (msg == NULL)
  11.337 -        goto enomem;
  11.338 -
  11.339 -    msg->dir = src->dir;
  11.340 -
  11.341 -    status = copy_fields(msg, src);
  11.342 -    if (status != PEP_STATUS_OK)
  11.343 -        goto enomem;
  11.344 -
  11.345 -    return msg;
  11.346 -
  11.347 -enomem:
  11.348 -    free_message(msg);
  11.349 -    return NULL;
  11.350 -}
  11.351 -
  11.352 -static PEP_STATUS encrypt_PGP_MIME(
  11.353 -    PEP_SESSION session,
  11.354 -    const message *src,
  11.355 -    stringlist_t *keys,
  11.356 -    message *dst,
  11.357 -    PEP_encrypt_flags_t flags
  11.358 -    )
  11.359 -{
  11.360 -    PEP_STATUS status = PEP_STATUS_OK;
  11.361 -    bool free_ptext = false;
  11.362 -    char *ptext = NULL;
  11.363 -    char *ctext = NULL;
  11.364 -    char *mimetext = NULL;
  11.365 -    size_t csize;
  11.366 -    assert(dst->longmsg == NULL);
  11.367 -    dst->enc_format = PEP_enc_PGP_MIME;
  11.368 -    unsigned char pepstr[] = PEP_SUBJ_STRING;
  11.369 -
  11.370 -    if (src->shortmsg && strcmp(src->shortmsg, "pEp") != 0 
  11.371 -                      && _unsigned_signed_strcmp(pepstr, src->shortmsg, PEP_SUBJ_BYTELEN) != 0) {
  11.372 -        if (session->unencrypted_subject) {
  11.373 -            dst->shortmsg = strdup(src->shortmsg);
  11.374 -            assert(dst->shortmsg);
  11.375 -            if (dst->shortmsg == NULL)
  11.376 -                goto enomem;
  11.377 -            ptext = src->longmsg;
  11.378 -        }
  11.379 -        else {
  11.380 -            ptext = combine_short_and_long(src->shortmsg, src->longmsg);
  11.381 -            if (ptext == NULL)
  11.382 -                goto enomem;
  11.383 -            free_ptext = true;
  11.384 -        }
  11.385 -    }
  11.386 -    else if (src->longmsg) {
  11.387 -        ptext = src->longmsg;
  11.388 -    }
  11.389 -    else {
  11.390 -        ptext = (char*)pepstr;
  11.391 -    }
  11.392 -
  11.393 -    message *_src = calloc(1, sizeof(message));
  11.394 -    assert(_src);
  11.395 -    if (_src == NULL)
  11.396 -        goto enomem;
  11.397 -    _src->longmsg = ptext;
  11.398 -    _src->longmsg_formatted = src->longmsg_formatted;
  11.399 -    _src->attachments = src->attachments;
  11.400 -    _src->enc_format = PEP_enc_none;
  11.401 -    status = mime_encode_message(_src, true, &mimetext);
  11.402 -    assert(status == PEP_STATUS_OK);
  11.403 -    if (status != PEP_STATUS_OK)
  11.404 -        goto pep_error;
  11.405 -
  11.406 -    if (free_ptext){
  11.407 -        free(ptext);
  11.408 -        free_ptext=0;
  11.409 -    }
  11.410 -    free(_src);
  11.411 -    assert(mimetext);
  11.412 -    if (mimetext == NULL)
  11.413 -        goto pep_error;
  11.414 -
  11.415 -    if (flags & PEP_encrypt_flag_force_unsigned)
  11.416 -        status = encrypt_only(session, keys, mimetext, strlen(mimetext),
  11.417 -            &ctext, &csize);
  11.418 -    else
  11.419 -        status = encrypt_and_sign(session, keys, mimetext, strlen(mimetext),
  11.420 -            &ctext, &csize);
  11.421 -    free(mimetext);
  11.422 -    if (ctext == NULL)
  11.423 -        goto pep_error;
  11.424 -
  11.425 -    dst->longmsg = strdup("this message was encrypted with p≡p "
  11.426 -        "https://pEp-project.org");
  11.427 -    assert(dst->longmsg);
  11.428 -    if (dst->longmsg == NULL)
  11.429 -        goto enomem;
  11.430 -
  11.431 -    char *v = strdup("Version: 1");
  11.432 -    assert(v);
  11.433 -    if (v == NULL)
  11.434 -        goto enomem;
  11.435 -
  11.436 -    bloblist_t *_a = new_bloblist(v, strlen(v), "application/pgp-encrypted", NULL);
  11.437 -    if (_a == NULL)
  11.438 -        goto enomem;
  11.439 -    dst->attachments = _a;
  11.440 -
  11.441 -    _a = bloblist_add(_a, ctext, csize, "application/octet-stream",
  11.442 -        "file://msg.asc");
  11.443 -    if (_a == NULL)
  11.444 -        goto enomem;
  11.445 -
  11.446 -    return PEP_STATUS_OK;
  11.447 -
  11.448 -enomem:
  11.449 -    status = PEP_OUT_OF_MEMORY;
  11.450 -
  11.451 -pep_error:
  11.452 -    if (free_ptext)
  11.453 -        free(ptext);
  11.454 -    free(ctext);
  11.455 -    return status;
  11.456 -}
  11.457 -
  11.458 -static PEP_STATUS encrypt_PGP_in_pieces(
  11.459 -    PEP_SESSION session,
  11.460 -    const message *src,
  11.461 -    stringlist_t *keys,
  11.462 -    message *dst,
  11.463 -    PEP_encrypt_flags_t flags
  11.464 -    )
  11.465 -{
  11.466 -    PEP_STATUS status = PEP_STATUS_OK;
  11.467 -    char *ctext = NULL;
  11.468 -    size_t csize;
  11.469 -    char *ptext = NULL;
  11.470 -    bool free_ptext = false;
  11.471 -    unsigned char pepstr[] = PEP_SUBJ_STRING;
  11.472 -    
  11.473 -    assert(dst->longmsg == NULL);
  11.474 -    assert(dst->attachments == NULL);
  11.475 -
  11.476 -    dst->enc_format = PEP_enc_pieces;
  11.477 -
  11.478 -    bool nosign = (flags & PEP_encrypt_flag_force_unsigned);
  11.479 -
  11.480 -    if (src->shortmsg && src->shortmsg[0] && strcmp(src->shortmsg, "pEp") != 0 && 
  11.481 -        _unsigned_signed_strcmp(pepstr, src->shortmsg, PEP_SUBJ_BYTELEN) != 0) {
  11.482 -        if (session->unencrypted_subject) {
  11.483 -            dst->shortmsg = strdup(src->shortmsg);
  11.484 -            assert(dst->shortmsg);
  11.485 -            if (dst->shortmsg == NULL)
  11.486 -                goto enomem;
  11.487 -            ptext = src->longmsg;
  11.488 -        }
  11.489 -        else {
  11.490 -            ptext = combine_short_and_long(src->shortmsg, src->longmsg);
  11.491 -            if (ptext == NULL)
  11.492 -                goto enomem;
  11.493 -            free_ptext = true;
  11.494 -        }
  11.495 -
  11.496 -        if (nosign)
  11.497 -            status = encrypt_only(session, keys, ptext, strlen(ptext), &ctext,
  11.498 -                &csize);
  11.499 -        else 
  11.500 -            status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
  11.501 -                &csize);
  11.502 -        if (free_ptext)
  11.503 -            free(ptext);
  11.504 -        free_ptext = false;
  11.505 -        if (ctext) {
  11.506 -            dst->longmsg = ctext;
  11.507 -        }
  11.508 -        else {
  11.509 -            goto pep_error;
  11.510 -        }
  11.511 -    }
  11.512 -    else if (src->longmsg && src->longmsg[0]) {
  11.513 -        ptext = src->longmsg;
  11.514 -        if (nosign)
  11.515 -            status = encrypt_only(session, keys, ptext, strlen(ptext), &ctext,
  11.516 -                &csize);
  11.517 -        else 
  11.518 -            status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
  11.519 -                &csize);
  11.520 -        if (ctext) {
  11.521 -            dst->longmsg = ctext;
  11.522 -        }
  11.523 -        else {
  11.524 -            goto pep_error;
  11.525 -        }
  11.526 -    }
  11.527 -    else {
  11.528 -        dst->longmsg = strdup("");
  11.529 -        assert(dst->longmsg);
  11.530 -        if (dst->longmsg == NULL)
  11.531 -            goto enomem;
  11.532 -    }
  11.533 -
  11.534 -    if (src->longmsg_formatted && src->longmsg_formatted[0]) {
  11.535 -        ptext = src->longmsg_formatted;
  11.536 -        if (nosign)
  11.537 -            status = encrypt_only(session, keys, ptext, strlen(ptext), &ctext,
  11.538 -                &csize);
  11.539 -        else 
  11.540 -            status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
  11.541 -                &csize);
  11.542 -        if (ctext) {
  11.543 -
  11.544 -            bloblist_t *_a = bloblist_add(dst->attachments, ctext, csize,
  11.545 -                "application/octet-stream", "file://PGPexch.htm.pgp");
  11.546 -            if (_a == NULL)
  11.547 -                goto enomem;
  11.548 -            if (dst->attachments == NULL)
  11.549 -                dst->attachments = _a;
  11.550 -        }
  11.551 -        else {
  11.552 -            goto pep_error;
  11.553 -        }
  11.554 -    }
  11.555 -
  11.556 -    if (src->attachments) {
  11.557 -        if (dst->attachments == NULL) {
  11.558 -            dst->attachments = new_bloblist(NULL, 0, NULL, NULL);
  11.559 -            if (dst->attachments == NULL)
  11.560 -                goto enomem;
  11.561 -        }
  11.562 -
  11.563 -        bloblist_t *_s = src->attachments;
  11.564 -        bloblist_t *_d = dst->attachments;
  11.565 -
  11.566 -        for (int n = 0; _s; _s = _s->next) {
  11.567 -            if (_s->value == NULL && _s->size == 0) {
  11.568 -                _d = bloblist_add(_d, NULL, 0, _s->mime_type, _s->filename);
  11.569 -                if (_d == NULL)
  11.570 -                    goto enomem;
  11.571 -            }
  11.572 -            else {
  11.573 -                size_t psize = _s->size;
  11.574 -                ptext = _s->value;
  11.575 -                if (nosign)
  11.576 -                    status = encrypt_only(session, keys, ptext, psize, &ctext,
  11.577 -                        &csize);
  11.578 -                else 
  11.579 -                    status = encrypt_and_sign(session, keys, ptext, psize, &ctext,
  11.580 -                        &csize);
  11.581 -                if (ctext) {
  11.582 -                    char *filename = NULL;
  11.583 -
  11.584 -                    char *attach_fn = _s->filename;
  11.585 -                    if (attach_fn && !is_cid_uri(attach_fn)) {
  11.586 -                        size_t len = strlen(_s->filename);
  11.587 -                        size_t bufsize = len + 5; // length of .pgp extension + NUL
  11.588 -                        bool already_uri = false;
  11.589 -                        if (is_file_uri(attach_fn))
  11.590 -                            already_uri = true;
  11.591 -                        else
  11.592 -                            bufsize += 7; // length of file://
  11.593 -                            
  11.594 -                        filename = calloc(1, bufsize);
  11.595 -                        if (filename == NULL)
  11.596 -                            goto enomem;
  11.597 -
  11.598 -                        if (!already_uri)
  11.599 -                            strlcpy(filename, "file://", bufsize);
  11.600 -                        // First char is NUL, so we're ok, even if not copying above. (calloc)
  11.601 -                        strlcat(filename, _s->filename, bufsize);
  11.602 -                        strlcat(filename, ".pgp", bufsize);
  11.603 -                    }
  11.604 -                    else {
  11.605 -                        filename = calloc(1, 27);
  11.606 -                        if (filename == NULL)
  11.607 -                            goto enomem;
  11.608 -
  11.609 -                        ++n;
  11.610 -                        n &= 0xffff;
  11.611 -                        snprintf(filename, 20, "file://Attachment%d.pgp", n);
  11.612 -                    }
  11.613 -
  11.614 -                    _d = bloblist_add(_d, ctext, csize, "application/octet-stream",
  11.615 -                        filename);
  11.616 -                    free(filename);
  11.617 -                    if (_d == NULL)
  11.618 -                        goto enomem;
  11.619 -                }
  11.620 -                else {
  11.621 -                    goto pep_error;
  11.622 -                }
  11.623 -            }
  11.624 -        }
  11.625 -    }
  11.626 -
  11.627 -    return PEP_STATUS_OK;
  11.628 -
  11.629 -enomem:
  11.630 -    status = PEP_OUT_OF_MEMORY;
  11.631 -
  11.632 -pep_error:
  11.633 -    if (free_ptext)
  11.634 -        free(ptext);
  11.635 -    return status;
  11.636 -}
  11.637 -
  11.638  static char * keylist_to_string(const stringlist_t *keylist)
  11.639  {
  11.640      if (keylist) {
  11.641 @@ -653,7 +31,7 @@
  11.642              size += strlen(_kl->value);
  11.643          }
  11.644  
  11.645 -        char *result = calloc(1, size);
  11.646 +        char *result = calloc(size, 1);
  11.647          if (result == NULL)
  11.648              return NULL;
  11.649  
  11.650 @@ -703,6 +81,56 @@
  11.651      }
  11.652  }
  11.653  
  11.654 +void add_opt_field(message *msg, const char *name, const char *value)
  11.655 +{
  11.656 +    assert(msg && name && value);
  11.657 +
  11.658 +    if (msg && name && value) {
  11.659 +        stringpair_t *pair = new_stringpair(name, value);
  11.660 +        if (pair == NULL)
  11.661 +            return;
  11.662 +
  11.663 +        stringpair_list_t *field = stringpair_list_add(msg->opt_fields, pair);
  11.664 +        if (field == NULL)
  11.665 +        {
  11.666 +            free_stringpair(pair);
  11.667 +            return;
  11.668 +        }
  11.669 +
  11.670 +        if (msg->opt_fields == NULL)
  11.671 +            msg->opt_fields = field;
  11.672 +    }
  11.673 +}
  11.674 +
  11.675 +void replace_opt_field(message *msg, const char *name, const char *value)
  11.676 +{
  11.677 +    assert(msg && name && value);
  11.678 +    
  11.679 +    if (msg && name && value) {
  11.680 +        stringpair_list_t* opt_fields = msg->opt_fields;
  11.681 +        stringpair_t* pair = NULL;
  11.682 +        if (opt_fields) {
  11.683 +            while (opt_fields) {
  11.684 +                pair = opt_fields->value;
  11.685 +                if (pair && (strcmp(name, pair->key) == 0))
  11.686 +                    break;
  11.687 +                    
  11.688 +                pair = NULL;
  11.689 +                opt_fields = opt_fields->next;
  11.690 +            }
  11.691 +        }
  11.692 +        
  11.693 +        if (pair) {
  11.694 +            free(pair->value);
  11.695 +            pair->value = strdup(value);
  11.696 +        }
  11.697 +        else {
  11.698 +            add_opt_field(msg, name, value);
  11.699 +        }
  11.700 +    }
  11.701 +}
  11.702 +
  11.703 +
  11.704  static void decorate_message(
  11.705      message *msg,
  11.706      PEP_rating rating,
  11.707 @@ -711,18 +139,784 @@
  11.708  {
  11.709      assert(msg);
  11.710  
  11.711 -    add_opt_field(msg, "X-pEp-Version", PEP_VERSION);
  11.712 +    replace_opt_field(msg, "X-pEp-Version", PEP_VERSION);
  11.713  
  11.714      if (rating != PEP_rating_undefined)
  11.715 -        add_opt_field(msg, "X-EncStatus", rating_to_string(rating));
  11.716 +        replace_opt_field(msg, "X-EncStatus", rating_to_string(rating));
  11.717  
  11.718      if (keylist) {
  11.719          char *_keylist = keylist_to_string(keylist);
  11.720 -        add_opt_field(msg, "X-KeyList", _keylist);
  11.721 +        replace_opt_field(msg, "X-KeyList", _keylist);
  11.722          free(_keylist);
  11.723      }
  11.724  }
  11.725  
  11.726 +static char* _get_resource_ptr_noown(char* uri) {
  11.727 +    char* uri_delim = strstr(uri, "://");
  11.728 +    if (!uri_delim)
  11.729 +        return uri;
  11.730 +    else
  11.731 +        return uri + 3;
  11.732 +}
  11.733 +
  11.734 +// static bool is_file_uri(char* str) {
  11.735 +//     return(strncmp(str, "file://", 7) == 0);
  11.736 +// }
  11.737 +
  11.738 +static bool is_cid_uri(const char* str) {
  11.739 +    return(strncmp(str, "cid://", 6) == 0);
  11.740 +}
  11.741 +
  11.742 +static bool string_equality(const char *s1, const char *s2)
  11.743 +{
  11.744 +    if (s1 == NULL || s2 == NULL)
  11.745 +        return false;
  11.746 +
  11.747 +    assert(s1 && s2);
  11.748 +
  11.749 +    return strcmp(s1, s2) == 0;
  11.750 +}
  11.751 +
  11.752 +static bool is_mime_type(const bloblist_t *bl, const char *mt)
  11.753 +{
  11.754 +    assert(mt);
  11.755 +
  11.756 +    return bl && string_equality(bl->mime_type, mt);
  11.757 +}
  11.758 +
  11.759 +//
  11.760 +// This function presumes the file ending is a proper substring of the
  11.761 +// filename (i.e. if bl->filename is "a.pgp" and fe is ".pgp", it will
  11.762 +// return true, but if bl->filename is ".pgp" and fe is ".pgp", it will
  11.763 +// return false. This is desired behaviour.
  11.764 +//
  11.765 +static bool is_fileending(const bloblist_t *bl, const char *fe)
  11.766 +{
  11.767 +    assert(fe);
  11.768 +
  11.769 +    if (bl == NULL || bl->filename == NULL || fe == NULL || is_cid_uri(bl->filename))
  11.770 +        return false;
  11.771 +
  11.772 +    assert(bl && bl->filename);
  11.773 +
  11.774 +    size_t fe_len = strlen(fe);
  11.775 +    size_t fn_len = strlen(bl->filename);
  11.776 +
  11.777 +    if (fn_len <= fe_len)
  11.778 +        return false;
  11.779 +
  11.780 +    assert(fn_len > fe_len);
  11.781 +
  11.782 +    return strcmp(bl->filename + (fn_len - fe_len), fe) == 0;
  11.783 +}
  11.784 +
  11.785 +
  11.786 +static char * encapsulate_message_wrap_info(const char *msg_wrap_info, const char *longmsg)
  11.787 +{
  11.788 +    assert(msg_wrap_info);
  11.789 +    
  11.790 +    if (!msg_wrap_info) {
  11.791 +        if (!longmsg)
  11.792 +            return NULL;
  11.793 +        else {
  11.794 +            char *result = strdup(longmsg);
  11.795 +            assert(result);
  11.796 +            return result;            
  11.797 +        }    
  11.798 +    }
  11.799 +    
  11.800 +    if (longmsg == NULL)
  11.801 +        longmsg = "";
  11.802 +        
  11.803 +    const char * const newlines = "\n\n";
  11.804 +    const size_t NL_LEN = 2;
  11.805 +        
  11.806 +    const size_t bufsize = PEP_MSG_WRAP_KEY_LEN + strlen(msg_wrap_info) + NL_LEN + strlen(longmsg) + 1;
  11.807 +    char * ptext = calloc(bufsize, 1);
  11.808 +    assert(ptext);
  11.809 +    if (ptext == NULL)
  11.810 +        return NULL;
  11.811 +
  11.812 +    strlcpy(ptext, PEP_MSG_WRAP_KEY, bufsize);
  11.813 +    strlcat(ptext, msg_wrap_info, bufsize);
  11.814 +    strlcat(ptext, newlines, bufsize);
  11.815 +    strlcat(ptext, longmsg, bufsize);
  11.816 +
  11.817 +    return ptext;
  11.818 +}
  11.819 +
  11.820 +static char * combine_short_and_long(const char *shortmsg, const char *longmsg)
  11.821 +{
  11.822 +    assert(shortmsg);
  11.823 +    
  11.824 +    unsigned char pepstr[] = PEP_SUBJ_STRING;
  11.825 +    assert(strcmp(shortmsg, "pEp") != 0 && _unsigned_signed_strcmp(pepstr, shortmsg, PEP_SUBJ_BYTELEN) != 0); 
  11.826 +    
  11.827 +    if (!shortmsg || strcmp(shortmsg, "pEp") == 0 || 
  11.828 +                     _unsigned_signed_strcmp(pepstr, shortmsg, PEP_SUBJ_BYTELEN) == 0) {
  11.829 +        if (!longmsg) {
  11.830 +            return NULL;
  11.831 +        }
  11.832 +        else {
  11.833 +            char *result = strdup(longmsg);
  11.834 +            assert(result);
  11.835 +            return result;
  11.836 +        }
  11.837 +    }
  11.838 +
  11.839 +    if (longmsg == NULL)
  11.840 +        longmsg = "";
  11.841 +
  11.842 +    const char * const newlines = "\n\n";
  11.843 +    const size_t NL_LEN = 2;
  11.844 +
  11.845 +    const size_t bufsize = PEP_SUBJ_KEY_LEN + strlen(shortmsg) + NL_LEN + strlen(longmsg) + 1;
  11.846 +    char * ptext = calloc(bufsize, 1);
  11.847 +    assert(ptext);
  11.848 +    if (ptext == NULL)
  11.849 +        return NULL;
  11.850 +
  11.851 +    strlcpy(ptext, PEP_SUBJ_KEY, bufsize);
  11.852 +    strlcat(ptext, shortmsg, bufsize);
  11.853 +    strlcat(ptext, newlines, bufsize);
  11.854 +    strlcat(ptext, longmsg, bufsize);
  11.855 +
  11.856 +    return ptext;
  11.857 +}
  11.858 +
  11.859 +static PEP_STATUS replace_subject(message* msg) {
  11.860 +    unsigned char pepstr[] = PEP_SUBJ_STRING;
  11.861 +    if (msg->shortmsg && *(msg->shortmsg) != '\0') {
  11.862 +        char* longmsg = combine_short_and_long(msg->shortmsg, msg->longmsg);
  11.863 +        if (!longmsg)
  11.864 +            return PEP_OUT_OF_MEMORY;
  11.865 +        else {
  11.866 +            free(msg->longmsg);
  11.867 +            msg->longmsg = longmsg;
  11.868 +        }
  11.869 +    }
  11.870 +    free(msg->shortmsg);
  11.871 +    msg->shortmsg = strdup((char*)pepstr);
  11.872 +    
  11.873 +    if (!msg->shortmsg)
  11.874 +        return PEP_OUT_OF_MEMORY;
  11.875 +    
  11.876 +    return PEP_STATUS_OK;
  11.877 +}
  11.878 +
  11.879 +unsigned long long get_bitmask(int num_bits) {
  11.880 +    if (num_bits <= 0)
  11.881 +        return 0;
  11.882 +        
  11.883 +    unsigned long long bitmask = 0;
  11.884 +    int i;
  11.885 +    for (i = 1; i < num_bits; i++) {
  11.886 +        bitmask = bitmask << 1;
  11.887 +        bitmask |= 1;
  11.888 +    }
  11.889 +    return bitmask;
  11.890 +}
  11.891 +
  11.892 +static char* get_base_36_rep(unsigned long long value, int num_sig_bits) {
  11.893 +        
  11.894 +    int bufsize = ceil(num_sig_bits / _pEp_log2_36) + 1;
  11.895 +    
  11.896 +    // based on
  11.897 +    // https://en.wikipedia.org/wiki/Base36#C_implementation
  11.898 +    // ok, we supposedly have a 64-bit kinda sorta random blob
  11.899 +    const char base_36_symbols[36] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  11.900 +
  11.901 +    char* retbuf = calloc(bufsize, 1); 
  11.902 +
  11.903 +    int i = bufsize - 1; // (end index)
  11.904 +
  11.905 +    while (i > 0) {
  11.906 +        retbuf[--i] = base_36_symbols[value % 36];
  11.907 +        value /= 36;
  11.908 +    }
  11.909 +
  11.910 +    return retbuf;
  11.911 +}
  11.912 +
  11.913 +
  11.914 +static char* message_id_prand_part(void) {
  11.915 +    // RAND modulus
  11.916 +    int num_bits = _pEp_rand_max_bits;
  11.917 +
  11.918 +    if (num_bits < 0)
  11.919 +        return NULL;
  11.920 +        
  11.921 +    const int DESIRED_BITS = 64;
  11.922 +
  11.923 +    num_bits = _MIN(num_bits, DESIRED_BITS);
  11.924 +    
  11.925 +    int i;
  11.926 +    
  11.927 +    // at least 64 bits
  11.928 +    unsigned long long bitmask = get_bitmask(num_bits);
  11.929 +    
  11.930 +    unsigned long long output_value = 0;
  11.931 +    
  11.932 +    i = DESIRED_BITS;
  11.933 +    
  11.934 +    int bitshift = 0;
  11.935 +    
  11.936 +    while (i > 0) {
  11.937 +        int randval = rand();
  11.938 +        unsigned long long temp_val = randval & bitmask;
  11.939 +
  11.940 +        output_value |= temp_val;
  11.941 +
  11.942 +        i -= num_bits; 
  11.943 +        
  11.944 +        bitshift = _MIN(num_bits, i);
  11.945 +        output_value <<= bitshift;        
  11.946 +        bitmask = get_bitmask(bitshift);
  11.947 +    }
  11.948 +
  11.949 +    return get_base_36_rep(output_value, DESIRED_BITS);
  11.950 +}
  11.951 +
  11.952 +static PEP_STATUS generate_message_id(message* msg) {
  11.953 +
  11.954 +    if (!msg || !msg->from || !msg->from->address)
  11.955 +        return PEP_ILLEGAL_VALUE;
  11.956 +
  11.957 +    char* time_prefix = NULL;
  11.958 +    char* random_id = NULL;
  11.959 +    char* retval = NULL;
  11.960 +    
  11.961 +    size_t buf_len = 2; // NUL + @
  11.962 +    
  11.963 +    char* from_addr = msg->from->address;
  11.964 +    char* domain_ptr = strstr(from_addr, "@");
  11.965 +    if (!domain_ptr || *(domain_ptr + 1) == '\0')
  11.966 +        domain_ptr = "localhost";
  11.967 +    else
  11.968 +        domain_ptr++;
  11.969 +
  11.970 +    buf_len += strlen(domain_ptr);
  11.971 +    
  11.972 +    if (msg->id)
  11.973 +        free(msg->id);
  11.974 +
  11.975 +    msg->id = NULL;
  11.976 +    
  11.977 +    time_t curr_time = time(NULL);
  11.978 +    
  11.979 +    time_prefix = get_base_36_rep(curr_time, ceil(log2(curr_time)));
  11.980 +
  11.981 +    if (!time_prefix)
  11.982 +        goto enomem;
  11.983 +    
  11.984 +    buf_len += strlen(time_prefix);
  11.985 +
  11.986 +    random_id = message_id_prand_part();
  11.987 +
  11.988 +    if (!random_id)
  11.989 +        goto enomem;
  11.990 +    
  11.991 +        
  11.992 +    buf_len += strlen(random_id);
  11.993 +    
  11.994 +    // make a new uuid - depending on rand() impl, time precision, etc,
  11.995 +    // we may still not be unique. We'd better make sure. So. 
  11.996 +    char new_uuid[37];
  11.997 +    pEpUUID uuid;
  11.998 +    uuid_generate_random(uuid);
  11.999 +    uuid_unparse_upper(uuid, new_uuid);
 11.1000 +
 11.1001 +    buf_len += strlen(new_uuid);
 11.1002 +
 11.1003 +    buf_len += 6; // "pEp" and 3 '.' chars
 11.1004 +
 11.1005 +    retval = calloc(buf_len, 1);
 11.1006 +    
 11.1007 +    if (!retval)
 11.1008 +        goto enomem;
 11.1009 +    
 11.1010 +    strlcpy(retval, "pEp.", buf_len);
 11.1011 +    strlcat(retval, time_prefix, buf_len);
 11.1012 +    strlcat(retval, ".", buf_len);
 11.1013 +    strlcat(retval, random_id, buf_len);
 11.1014 +    strlcat(retval, ".", buf_len);
 11.1015 +    strlcat(retval, new_uuid, buf_len);        
 11.1016 +    strlcat(retval, "@", buf_len);    
 11.1017 +    strlcat(retval, domain_ptr, buf_len);    
 11.1018 +
 11.1019 +    msg->id = retval;
 11.1020 +    
 11.1021 +    free(time_prefix);
 11.1022 +    free(random_id);
 11.1023 +    
 11.1024 +    return PEP_STATUS_OK;
 11.1025 +        
 11.1026 +enomem:
 11.1027 +    free(time_prefix);
 11.1028 +    free(random_id);
 11.1029 +    return PEP_OUT_OF_MEMORY;
 11.1030 +}
 11.1031 +
 11.1032 +/* 
 11.1033 +   WARNING: For the moment, this only works for the first line of decrypted
 11.1034 +   plaintext because we don't need more. IF WE DO, THIS MUST BE EXPANDED, or
 11.1035 +   we need a delineated section to parse separately
 11.1036 +   
 11.1037 +   Does case-insensitive compare of keys, so sending in a lower-cased
 11.1038 +   string constant saves a bit of computation
 11.1039 + */
 11.1040 +static PEP_STATUS get_data_from_encapsulated_line(const char* plaintext, const char* key, 
 11.1041 +                                                  const size_t keylen, char** data, 
 11.1042 +                                                  char** modified_msg) {
 11.1043 +    char* _data = NULL;
 11.1044 +    char* _modified = NULL;
 11.1045 +    
 11.1046 +    if (strncasecmp(plaintext, key, keylen) == 0) {
 11.1047 +        const char *line_end = strchr(plaintext, '\n');
 11.1048 +
 11.1049 +        if (line_end == NULL) {
 11.1050 +            _data = strdup(plaintext + keylen);
 11.1051 +            assert(_data);
 11.1052 +            if (_data == NULL)
 11.1053 +                return PEP_OUT_OF_MEMORY;
 11.1054 +        }
 11.1055 +        else {
 11.1056 +            size_t n = line_end - plaintext;
 11.1057 +
 11.1058 +            if (*(line_end - 1) == '\r')
 11.1059 +                _data = strndup(plaintext + keylen, n - (keylen + 1));
 11.1060 +            else
 11.1061 +                _data = strndup(plaintext + keylen, n - keylen);
 11.1062 +            assert(_data);
 11.1063 +            if (_data == NULL)
 11.1064 +                return PEP_OUT_OF_MEMORY;
 11.1065 +
 11.1066 +            while (*(plaintext + n) && (*(plaintext + n) == '\n' || *(plaintext + n) == '\r'))
 11.1067 +                ++n;
 11.1068 +
 11.1069 +            if (*(plaintext + n)) {
 11.1070 +                _modified = strdup(plaintext + n);
 11.1071 +                assert(_modified);
 11.1072 +                if (_modified == NULL)
 11.1073 +                    return PEP_OUT_OF_MEMORY;
 11.1074 +            }
 11.1075 +        }
 11.1076 +    }
 11.1077 +    *data = _data;
 11.1078 +    *modified_msg = _modified;
 11.1079 +    return PEP_STATUS_OK;
 11.1080 +}
 11.1081 +
 11.1082 +
 11.1083 +static int separate_short_and_long(const char *src, char **shortmsg, char** msg_wrap_info, char **longmsg)
 11.1084 +{
 11.1085 +    char *_shortmsg = NULL;
 11.1086 +    char *_msg_wrap_info = NULL;
 11.1087 +    char *_longmsg = NULL;
 11.1088 +
 11.1089 +    assert(src);
 11.1090 +    assert(shortmsg);
 11.1091 +    assert(msg_wrap_info);
 11.1092 +    assert(longmsg);
 11.1093 +
 11.1094 +    if (src == NULL || shortmsg == NULL || msg_wrap_info == NULL || longmsg == NULL)
 11.1095 +        return -1;
 11.1096 +
 11.1097 +    *shortmsg = NULL;
 11.1098 +    *longmsg = NULL;
 11.1099 +    *msg_wrap_info = NULL;
 11.1100 +
 11.1101 +    // We generated the input here. If we ever need more than one header value to be
 11.1102 +    // encapsulated and hidden in the encrypted text, we will have to modify this.
 11.1103 +    // As is, we're either doing this with a version 1.0 client, in which case
 11.1104 +    // the only encapsulated header value is subject, or 2.0+, in which the
 11.1105 +    // message wrap info is the only encapsulated header value. If we need this
 11.1106 +    // to be more complex, we're going to have to do something more elegant
 11.1107 +    // and efficient.    
 11.1108 +    PEP_STATUS status = get_data_from_encapsulated_line(src, PEP_SUBJ_KEY_LC, 
 11.1109 +                                                        PEP_SUBJ_KEY_LEN, 
 11.1110 +                                                        &_shortmsg, &_longmsg);
 11.1111 +                                                        
 11.1112 +    if (_shortmsg) {
 11.1113 +        if (status == PEP_STATUS_OK)
 11.1114 +            *shortmsg = _shortmsg;
 11.1115 +        else
 11.1116 +            goto enomem;
 11.1117 +    }
 11.1118 +    else {
 11.1119 +        status = get_data_from_encapsulated_line(src, PEP_MSG_WRAP_KEY_LC, 
 11.1120 +                                                 PEP_MSG_WRAP_KEY_LEN, 
 11.1121 +                                                 &_msg_wrap_info, &_longmsg);
 11.1122 +        if (_msg_wrap_info) {
 11.1123 +            if (status == PEP_STATUS_OK)
 11.1124 +                *msg_wrap_info = _msg_wrap_info;
 11.1125 +            else
 11.1126 +                goto enomem;
 11.1127 +        }
 11.1128 +    }
 11.1129 +    
 11.1130 +    // If there was no secret data hiding in the first line...
 11.1131 +    if (!_shortmsg && !_msg_wrap_info) {
 11.1132 +        _longmsg = strdup(src);
 11.1133 +        assert(_longmsg);
 11.1134 +        if (_longmsg == NULL)
 11.1135 +            goto enomem;
 11.1136 +    }
 11.1137 +    
 11.1138 +    *longmsg = _longmsg;
 11.1139 +
 11.1140 +    return 0;
 11.1141 +
 11.1142 +enomem:
 11.1143 +    free(_shortmsg);
 11.1144 +    free(_msg_wrap_info);
 11.1145 +    free(_longmsg);
 11.1146 +
 11.1147 +    return -1;
 11.1148 +}
 11.1149 +
 11.1150 +static PEP_STATUS copy_fields(message *dst, const message *src)
 11.1151 +{
 11.1152 +    assert(dst);
 11.1153 +    assert(src);
 11.1154 +
 11.1155 +    if(!(dst && src))
 11.1156 +        return PEP_ILLEGAL_VALUE;
 11.1157 +
 11.1158 +    free_timestamp(dst->sent);
 11.1159 +    dst->sent = NULL;
 11.1160 +    if (src->sent) {
 11.1161 +        dst->sent = timestamp_dup(src->sent);
 11.1162 +        if (dst->sent == NULL)
 11.1163 +            return PEP_OUT_OF_MEMORY;
 11.1164 +    }
 11.1165 +
 11.1166 +    free_timestamp(dst->recv);
 11.1167 +    dst->recv = NULL;
 11.1168 +    if (src->recv) {
 11.1169 +        dst->recv = timestamp_dup(src->recv);
 11.1170 +        if (dst->recv == NULL)
 11.1171 +            return PEP_OUT_OF_MEMORY;
 11.1172 +    }
 11.1173 +
 11.1174 +    free_identity(dst->from);
 11.1175 +    dst->from = NULL;
 11.1176 +    if (src->from) {
 11.1177 +        dst->from = identity_dup(src->from);
 11.1178 +        if (dst->from == NULL)
 11.1179 +            return PEP_OUT_OF_MEMORY;
 11.1180 +    }
 11.1181 +
 11.1182 +    free_identity_list(dst->to);
 11.1183 +    dst->to = NULL;
 11.1184 +    if (src->to && src->to->ident) {
 11.1185 +        dst->to = identity_list_dup(src->to);
 11.1186 +        if (dst->to == NULL)
 11.1187 +            return PEP_OUT_OF_MEMORY;
 11.1188 +    }
 11.1189 +
 11.1190 +    free_identity(dst->recv_by);
 11.1191 +    dst->recv_by = NULL;
 11.1192 +    if (src->recv_by) {
 11.1193 +        dst->recv_by = identity_dup(src->recv_by);
 11.1194 +        if (dst->recv_by == NULL)
 11.1195 +            return PEP_OUT_OF_MEMORY;
 11.1196 +    }
 11.1197 +
 11.1198 +    free_identity_list(dst->cc);
 11.1199 +    dst->cc = NULL;
 11.1200 +    if (src->cc && src->cc->ident) {
 11.1201 +        dst->cc = identity_list_dup(src->cc);
 11.1202 +        if (dst->cc == NULL)
 11.1203 +            return PEP_OUT_OF_MEMORY;
 11.1204 +    }
 11.1205 +
 11.1206 +    free_identity_list(dst->bcc);
 11.1207 +    dst->bcc = NULL;
 11.1208 +    if (src->bcc && src->bcc->ident) {
 11.1209 +        dst->bcc = identity_list_dup(src->bcc);
 11.1210 +        if (dst->bcc == NULL)
 11.1211 +            return PEP_OUT_OF_MEMORY;
 11.1212 +    }
 11.1213 +
 11.1214 +    free_identity_list(dst->reply_to);
 11.1215 +    dst->reply_to = NULL;
 11.1216 +    if (src->reply_to && src->reply_to->ident) {
 11.1217 +        dst->reply_to = identity_list_dup(src->reply_to);
 11.1218 +        if (dst->reply_to == NULL)
 11.1219 +            return PEP_OUT_OF_MEMORY;
 11.1220 +    }
 11.1221 +
 11.1222 +    free_stringlist(dst->in_reply_to);
 11.1223 +    dst->in_reply_to = NULL;
 11.1224 +    if (src->in_reply_to && src->in_reply_to->value) {
 11.1225 +        dst->in_reply_to = stringlist_dup(src->in_reply_to);
 11.1226 +        if (dst->in_reply_to == NULL)
 11.1227 +            return PEP_OUT_OF_MEMORY;
 11.1228 +    }
 11.1229 +
 11.1230 +    free_stringlist(dst->references);
 11.1231 +    dst->references = NULL;
 11.1232 +    if (src->references) {
 11.1233 +        dst->references = stringlist_dup(src->references);
 11.1234 +        if (dst->references == NULL)
 11.1235 +            return PEP_OUT_OF_MEMORY;
 11.1236 +    }
 11.1237 +
 11.1238 +    free_stringlist(dst->keywords);
 11.1239 +    dst->keywords = NULL;
 11.1240 +    if (src->keywords && src->keywords->value) {
 11.1241 +        dst->keywords = stringlist_dup(src->keywords);
 11.1242 +        if (dst->keywords == NULL)
 11.1243 +            return PEP_OUT_OF_MEMORY;
 11.1244 +    }
 11.1245 +
 11.1246 +    free(dst->comments);
 11.1247 +    dst->comments = NULL;
 11.1248 +    if (src->comments) {
 11.1249 +        dst->comments = strdup(src->comments);
 11.1250 +        assert(dst->comments);
 11.1251 +        if (dst->comments == NULL)
 11.1252 +            return PEP_OUT_OF_MEMORY;
 11.1253 +    }
 11.1254 +
 11.1255 +    free_stringpair_list(dst->opt_fields);
 11.1256 +    dst->opt_fields = NULL;
 11.1257 +    if (src->opt_fields) {
 11.1258 +        dst->opt_fields = stringpair_list_dup(src->opt_fields);
 11.1259 +        if (dst->opt_fields == NULL)
 11.1260 +            return PEP_OUT_OF_MEMORY;
 11.1261 +    }
 11.1262 +
 11.1263 +    return PEP_STATUS_OK;
 11.1264 +}
 11.1265 +
 11.1266 +
 11.1267 +static message* extract_minimal_envelope(const message* src, 
 11.1268 +                                         PEP_msg_direction direct) {
 11.1269 +                                                 
 11.1270 +    message* envelope = new_message(direct);
 11.1271 +    if (!envelope)
 11.1272 +        return NULL;
 11.1273 +        
 11.1274 +    envelope->shortmsg = _pep_subj_copy();
 11.1275 +    if (!envelope->shortmsg)
 11.1276 +        return NULL;
 11.1277 +
 11.1278 +    if (src->from) {
 11.1279 +        envelope->from = identity_dup(src->from);
 11.1280 +        if (!envelope->from)
 11.1281 +            return NULL;
 11.1282 +    }
 11.1283 +
 11.1284 +    if (src->to) {
 11.1285 +        envelope->to = identity_list_dup(src->to);
 11.1286 +        if (!envelope->to)
 11.1287 +            return NULL;
 11.1288 +    }
 11.1289 +
 11.1290 +    if (src->cc) {
 11.1291 +        envelope->cc = identity_list_dup(src->cc);
 11.1292 +        if (!envelope->cc)
 11.1293 +            return NULL;
 11.1294 +    }
 11.1295 +
 11.1296 +    if (src->bcc) {
 11.1297 +        envelope->bcc = identity_list_dup(src->bcc);
 11.1298 +        if (!envelope->bcc)
 11.1299 +            return NULL;
 11.1300 +    }
 11.1301 +
 11.1302 +    envelope->enc_format = src->enc_format;        
 11.1303 +    
 11.1304 +    return envelope;
 11.1305 +}
 11.1306 +
 11.1307 +static message * clone_to_empty_message(const message * src)
 11.1308 +{
 11.1309 +    PEP_STATUS status;
 11.1310 +    message * msg = NULL;
 11.1311 +
 11.1312 +    assert(src);
 11.1313 +    if (src == NULL)
 11.1314 +        return NULL;
 11.1315 +
 11.1316 +    msg = calloc(1, sizeof(message));
 11.1317 +    assert(msg);
 11.1318 +    if (msg == NULL)
 11.1319 +        goto enomem;
 11.1320 +
 11.1321 +    msg->dir = src->dir;
 11.1322 +
 11.1323 +    status = copy_fields(msg, src);
 11.1324 +    if (status != PEP_STATUS_OK)
 11.1325 +        goto enomem;
 11.1326 +
 11.1327 +    return msg;
 11.1328 +
 11.1329 +enomem:
 11.1330 +    free_message(msg);
 11.1331 +    return NULL;
 11.1332 +}
 11.1333 +
 11.1334 +static message* wrap_message_as_attachment(message* envelope, 
 11.1335 +    message* attachment, bool keep_orig_subject) {
 11.1336 +    
 11.1337 +    if (!attachment)
 11.1338 +        return NULL;
 11.1339 +    
 11.1340 +    message* _envelope = envelope;
 11.1341 +
 11.1342 +    PEP_STATUS status = PEP_STATUS_OK;
 11.1343 +
 11.1344 +    replace_opt_field(attachment, "X-pEp-Version", PEP_VERSION);
 11.1345 +        
 11.1346 +    if (!_envelope) {
 11.1347 +        _envelope = extract_minimal_envelope(attachment, PEP_dir_outgoing);
 11.1348 +        status = generate_message_id(_envelope);
 11.1349 +        
 11.1350 +        if (status != PEP_STATUS_OK)
 11.1351 +            goto enomem;
 11.1352 +        
 11.1353 +        attachment->longmsg = encapsulate_message_wrap_info("INNER", attachment->longmsg);
 11.1354 +        _envelope->longmsg = encapsulate_message_wrap_info("OUTER", _envelope->longmsg);
 11.1355 +    }
 11.1356 +    else {
 11.1357 +        _envelope->longmsg = encapsulate_message_wrap_info("TRANSPORT", _envelope->longmsg);
 11.1358 +    }
 11.1359 +    
 11.1360 +    if (!attachment->id || attachment->id[0] == "\0") {
 11.1361 +        free(attachment->id);
 11.1362 +        if (!_envelope->id) {
 11.1363 +            status = generate_message_id(_envelope);
 11.1364 +        
 11.1365 +            if (status != PEP_STATUS_OK)
 11.1366 +                goto enomem;
 11.1367 +        }
 11.1368 +            
 11.1369 +        attachment->id = strdup(_envelope->id);
 11.1370 +    }
 11.1371 +    
 11.1372 +    char* message_text = NULL;
 11.1373 +
 11.1374 +    /* prevent introduction of pEp in inner message */
 11.1375 +
 11.1376 +    if (!attachment->shortmsg) {
 11.1377 +        attachment->shortmsg = strdup("");
 11.1378 +        if (!attachment->shortmsg)
 11.1379 +            goto enomem;
 11.1380 +    }
 11.1381 +            
 11.1382 +    /* Turn message into a MIME-blob */
 11.1383 +    status = _mime_encode_message_internal(attachment, false, &message_text, false);
 11.1384 +        
 11.1385 +    if (status != PEP_STATUS_OK)
 11.1386 +        goto enomem;
 11.1387 +    
 11.1388 +    size_t message_len = strlen(message_text);
 11.1389 +    
 11.1390 +    bloblist_t* message_blob = new_bloblist(message_text, message_len,
 11.1391 +                                            "message/rfc822", NULL);
 11.1392 +    
 11.1393 +    _envelope->attachments = message_blob;
 11.1394 +    if (keep_orig_subject && attachment->shortmsg)
 11.1395 +        _envelope->shortmsg = strdup(attachment->shortmsg);
 11.1396 +    return _envelope;
 11.1397 +    
 11.1398 +enomem:
 11.1399 +    if (!envelope) {
 11.1400 +        free_message(_envelope);
 11.1401 +    }
 11.1402 +    return NULL;    
 11.1403 +}
 11.1404 +
 11.1405 +static PEP_STATUS encrypt_PGP_MIME(
 11.1406 +    PEP_SESSION session,
 11.1407 +    const message *src,
 11.1408 +    stringlist_t *keys,
 11.1409 +    message *dst,
 11.1410 +    PEP_encrypt_flags_t flags
 11.1411 +    )
 11.1412 +{
 11.1413 +    PEP_STATUS status = PEP_STATUS_OK;
 11.1414 +    bool free_ptext = false;
 11.1415 +    char *ptext = NULL;
 11.1416 +    char *ctext = NULL;
 11.1417 +    char *mimetext = NULL;
 11.1418 +    size_t csize;
 11.1419 +    assert(dst->longmsg == NULL);
 11.1420 +    dst->enc_format = PEP_enc_PGP_MIME;
 11.1421 +
 11.1422 +    if (src->shortmsg)
 11.1423 +        dst->shortmsg = strdup(src->shortmsg);
 11.1424 +        
 11.1425 +    message *_src = calloc(1, sizeof(message));
 11.1426 +    assert(_src);
 11.1427 +    if (_src == NULL)
 11.1428 +        goto enomem;
 11.1429 +//    _src->longmsg = ptext;
 11.1430 +    _src->longmsg = src->longmsg;
 11.1431 +    _src->longmsg_formatted = src->longmsg_formatted;
 11.1432 +    _src->attachments = src->attachments;
 11.1433 +    _src->enc_format = PEP_enc_none;
 11.1434 +    status = _mime_encode_message_internal(_src, true, &mimetext, false);
 11.1435 +    assert(status == PEP_STATUS_OK);
 11.1436 +    if (status != PEP_STATUS_OK)
 11.1437 +        goto pep_error;
 11.1438 +
 11.1439 +    if (free_ptext){
 11.1440 +        free(ptext);
 11.1441 +        free_ptext=0;
 11.1442 +    }
 11.1443 +    free(_src);
 11.1444 +    assert(mimetext);
 11.1445 +    if (mimetext == NULL)
 11.1446 +        goto pep_error;
 11.1447 +
 11.1448 +    if (flags & PEP_encrypt_flag_force_unsigned)
 11.1449 +        status = encrypt_only(session, keys, mimetext, strlen(mimetext),
 11.1450 +            &ctext, &csize);
 11.1451 +    else
 11.1452 +        status = encrypt_and_sign(session, keys, mimetext, strlen(mimetext),
 11.1453 +            &ctext, &csize);
 11.1454 +    free(mimetext);
 11.1455 +    if (ctext == NULL)
 11.1456 +        goto pep_error;
 11.1457 +
 11.1458 +    dst->longmsg = strdup("this message was encrypted with p≡p "
 11.1459 +        "https://pEp-project.org");
 11.1460 +    assert(dst->longmsg);
 11.1461 +    if (dst->longmsg == NULL)
 11.1462 +        goto enomem;
 11.1463 +
 11.1464 +    char *v = strdup("Version: 1");
 11.1465 +    assert(v);
 11.1466 +    if (v == NULL)
 11.1467 +        goto enomem;
 11.1468 +
 11.1469 +    bloblist_t *_a = new_bloblist(v, strlen(v), "application/pgp-encrypted", NULL);
 11.1470 +    if (_a == NULL)
 11.1471 +        goto enomem;
 11.1472 +    dst->attachments = _a;
 11.1473 +
 11.1474 +    _a = bloblist_add(_a, ctext, csize, "application/octet-stream",
 11.1475 +        "file://msg.asc");
 11.1476 +    if (_a == NULL)
 11.1477 +        goto enomem;
 11.1478 +
 11.1479 +    return PEP_STATUS_OK;
 11.1480 +
 11.1481 +enomem:
 11.1482 +    status = PEP_OUT_OF_MEMORY;
 11.1483 +
 11.1484 +pep_error:
 11.1485 +    if (free_ptext)
 11.1486 +        free(ptext);
 11.1487 +    free(ctext);
 11.1488 +    return status;
 11.1489 +}
 11.1490 +
 11.1491 +
 11.1492  static PEP_rating _rating(PEP_comm_type ct, PEP_rating rating)
 11.1493  {
 11.1494      if (ct == PEP_ct_unknown)
 11.1495 @@ -1127,7 +1321,8 @@
 11.1496      PEP_STATUS status = PEP_STATUS_OK;
 11.1497      message * msg = NULL;
 11.1498      stringlist_t * keys = NULL;
 11.1499 -
 11.1500 +    message* _src = src;
 11.1501 +    
 11.1502      assert(session);
 11.1503      assert(src);
 11.1504      assert(dst);
 11.1505 @@ -1254,31 +1449,45 @@
 11.1506          return ADD_TO_LOG(PEP_UNENCRYPTED);
 11.1507      }
 11.1508      else {
 11.1509 -        msg = clone_to_empty_message(src);
 11.1510 +        // FIXME - we need to deal with transport types (via flag)
 11.1511 +        if ((max_comm_type | PEP_ct_confirmed) == PEP_ct_pEp) {
 11.1512 +            _src = wrap_message_as_attachment(NULL, src, session->unencrypted_subject);
 11.1513 +            if (!_src)
 11.1514 +                goto pep_error;
 11.1515 +        }
 11.1516 +        else {
 11.1517 +            // hide subject
 11.1518 +            if (!session->unencrypted_subject) {
 11.1519 +                status = replace_subject(_src);
 11.1520 +                if (status == PEP_OUT_OF_MEMORY)
 11.1521 +                    goto enomem;
 11.1522 +            }
 11.1523 +        }
 11.1524 +        if (!(flags & PEP_encrypt_flag_force_no_attached_key))
 11.1525 +            attach_own_key(session, _src);
 11.1526 +
 11.1527 +        msg = clone_to_empty_message(_src);
 11.1528          if (msg == NULL)
 11.1529              goto enomem;
 11.1530  
 11.1531 -        if (!(flags & PEP_encrypt_flag_force_no_attached_key))
 11.1532 -            attach_own_key(session, src);
 11.1533 -
 11.1534          switch (enc_format) {
 11.1535 -        case PEP_enc_PGP_MIME:
 11.1536 -        case PEP_enc_PEP: // BUG: should be implemented extra
 11.1537 -            status = encrypt_PGP_MIME(session, src, keys, msg, flags);
 11.1538 -            break;
 11.1539 -
 11.1540 -        case PEP_enc_pieces:
 11.1541 -            status = encrypt_PGP_in_pieces(session, src, keys, msg, flags);
 11.1542 -            break;
 11.1543 -
 11.1544 -        /* case PEP_enc_PEP:
 11.1545 -            // TODO: implement
 11.1546 -            NOT_IMPLEMENTED */
 11.1547 -
 11.1548 -        default:
 11.1549 -            assert(0);
 11.1550 -            status = PEP_ILLEGAL_VALUE;
 11.1551 -            GOTO(pep_error);
 11.1552 +            case PEP_enc_PGP_MIME:
 11.1553 +            case PEP_enc_PEP: // BUG: should be implemented extra
 11.1554 +                status = encrypt_PGP_MIME(session, _src, keys, msg, flags);
 11.1555 +                break;
 11.1556 +
 11.1557 +            // case PEP_enc_pieces:
 11.1558 +            //     status = encrypt_PGP_in_pieces(session, src, keys, msg, flags);
 11.1559 +            //     break;
 11.1560 +
 11.1561 +            /* case PEP_enc_PEP:
 11.1562 +                // TODO: implement
 11.1563 +                NOT_IMPLEMENTED */
 11.1564 +
 11.1565 +            default:
 11.1566 +                assert(0);
 11.1567 +                status = PEP_ILLEGAL_VALUE;
 11.1568 +                GOTO(pep_error);
 11.1569          }
 11.1570  
 11.1571          if (status == PEP_OUT_OF_MEMORY)
 11.1572 @@ -1291,7 +1500,7 @@
 11.1573      free_stringlist(keys);
 11.1574  
 11.1575      if (msg && msg->shortmsg == NULL) {
 11.1576 -        msg->shortmsg = _pep_subj_copy();
 11.1577 +        msg->shortmsg = strdup("");
 11.1578          assert(msg->shortmsg);
 11.1579          if (msg->shortmsg == NULL)
 11.1580              goto enomem;
 11.1581 @@ -1299,8 +1508,8 @@
 11.1582  
 11.1583      if (msg) {
 11.1584          decorate_message(msg, PEP_rating_undefined, NULL);
 11.1585 -        if (src->id) {
 11.1586 -            msg->id = strdup(src->id);
 11.1587 +        if (_src->id) {
 11.1588 +            msg->id = strdup(_src->id);
 11.1589              assert(msg->id);
 11.1590              if (msg->id == NULL)
 11.1591                  goto enomem;
 11.1592 @@ -1308,6 +1517,12 @@
 11.1593      }
 11.1594  
 11.1595      *dst = msg;
 11.1596 +    
 11.1597 +    // ??? FIXME: Check to be sure we don't have references btw _src and msg. 
 11.1598 +    // I don't think we do.
 11.1599 +    if (_src && _src != src)
 11.1600 +        free_message(_src);
 11.1601 +        
 11.1602      return ADD_TO_LOG(status);
 11.1603  
 11.1604  enomem:
 11.1605 @@ -1316,6 +1531,8 @@
 11.1606  pep_error:
 11.1607      free_stringlist(keys);
 11.1608      free_message(msg);
 11.1609 +    if (_src && _src != src)
 11.1610 +        free_message(_src);
 11.1611  
 11.1612      return ADD_TO_LOG(status);
 11.1613  }
 11.1614 @@ -1332,6 +1549,7 @@
 11.1615      PEP_STATUS status = PEP_STATUS_OK;
 11.1616      message * msg = NULL;
 11.1617      stringlist_t * keys = NULL;
 11.1618 +    message* _src = src;
 11.1619  
 11.1620      assert(session);
 11.1621      assert(src);
 11.1622 @@ -1371,24 +1589,20 @@
 11.1623      if (!(flags & PEP_encrypt_flag_force_no_attached_key))
 11.1624          _attach_key(session, target_fpr, src);
 11.1625  
 11.1626 -    msg = clone_to_empty_message(src);
 11.1627 +    _src = wrap_message_as_attachment(NULL, src, session->unencrypted_subject);
 11.1628 +    if (!_src)
 11.1629 +        goto pep_error;
 11.1630 +
 11.1631 +    msg = clone_to_empty_message(_src);
 11.1632      if (msg == NULL)
 11.1633          goto enomem;
 11.1634  
 11.1635      switch (enc_format) {
 11.1636          case PEP_enc_PGP_MIME:
 11.1637          case PEP_enc_PEP: // BUG: should be implemented extra
 11.1638 -            status = encrypt_PGP_MIME(session, src, keys, msg, flags);
 11.1639 +            status = encrypt_PGP_MIME(session, _src, keys, msg, flags);
 11.1640              break;
 11.1641  
 11.1642 -        case PEP_enc_pieces:
 11.1643 -            status = encrypt_PGP_in_pieces(session, src, keys, msg, flags);
 11.1644 -            break;
 11.1645 -
 11.1646 -        /* case PEP_enc_PEP:
 11.1647 -            NOT_IMPLEMENTED */
 11.1648 -            // TODO: implement
 11.1649 -
 11.1650          default:
 11.1651              assert(0);
 11.1652              status = PEP_ILLEGAL_VALUE;
 11.1653 @@ -1409,8 +1623,8 @@
 11.1654       }
 11.1655  
 11.1656       if (msg) {
 11.1657 -         if (src->id) {
 11.1658 -             msg->id = strdup(src->id);
 11.1659 +         if (_src->id) {
 11.1660 +             msg->id = strdup(_src->id);
 11.1661               assert(msg->id);
 11.1662               if (msg->id == NULL)
 11.1663                   goto enomem;
 11.1664 @@ -1418,6 +1632,10 @@
 11.1665       }
 11.1666  
 11.1667      *dst = msg;
 11.1668 +    
 11.1669 +    if (src != _src)
 11.1670 +        free_message(_src);
 11.1671 +
 11.1672      return status;
 11.1673  
 11.1674  enomem:
 11.1675 @@ -1426,6 +1644,8 @@
 11.1676  pep_error:
 11.1677      free_stringlist(keys);
 11.1678      free_message(msg);
 11.1679 +    if (src != _src)
 11.1680 +        free_message(_src);
 11.1681  
 11.1682      return ADD_TO_LOG(status);
 11.1683  }
 11.1684 @@ -1464,7 +1684,8 @@
 11.1685  }
 11.1686  
 11.1687  
 11.1688 -PEP_STATUS _get_detached_signature(message* msg, bloblist_t** signature_blob) {
 11.1689 +static PEP_STATUS _get_detached_signature(message* msg, 
 11.1690 +                                          bloblist_t** signature_blob) {
 11.1691      bloblist_t* attach_curr = msg->attachments;
 11.1692  
 11.1693      *signature_blob = NULL;
 11.1694 @@ -1480,8 +1701,8 @@
 11.1695      return PEP_STATUS_OK;
 11.1696  }
 11.1697  
 11.1698 -PEP_STATUS _get_signed_text(const char* ptext, const size_t psize,
 11.1699 -                            char** stext, size_t* ssize) {
 11.1700 +static PEP_STATUS _get_signed_text(const char* ptext, const size_t psize,
 11.1701 +                                   char** stext, size_t* ssize) {
 11.1702  
 11.1703      char* signed_boundary = NULL;
 11.1704      char* signpost = strstr(ptext, "Content-Type: multipart/signed");
 11.1705 @@ -1516,7 +1737,7 @@
 11.1706      // Add space for the "--"
 11.1707      size_t boundary_strlen = (end_boundary - start_boundary) + 2;
 11.1708  
 11.1709 -    signed_boundary = calloc(1, boundary_strlen + 1);
 11.1710 +    signed_boundary = calloc(boundary_strlen + 1, 1);
 11.1711      strlcpy(signed_boundary, "--", boundary_strlen + 1);
 11.1712      strlcat(signed_boundary, start_boundary, boundary_strlen + 1);
 11.1713  
 11.1714 @@ -1551,9 +1772,9 @@
 11.1715      return PEP_STATUS_OK;
 11.1716  }
 11.1717  
 11.1718 -PEP_STATUS combine_keylists(PEP_SESSION session, stringlist_t** verify_in, 
 11.1719 -                            stringlist_t** keylist_in_out, 
 11.1720 -                            pEp_identity* from) {
 11.1721 +static PEP_STATUS combine_keylists(PEP_SESSION session, stringlist_t** verify_in, 
 11.1722 +                                   stringlist_t** keylist_in_out, 
 11.1723 +                                   pEp_identity* from) {
 11.1724      
 11.1725      if (!verify_in || !(*verify_in)) // this isn't really a problem.
 11.1726          return PEP_STATUS_OK;
 11.1727 @@ -1628,11 +1849,11 @@
 11.1728      return status;
 11.1729  }
 11.1730  
 11.1731 -PEP_STATUS amend_rating_according_to_sender_and_recipients(
 11.1732 -    PEP_SESSION session,
 11.1733 -    PEP_rating *rating,
 11.1734 -    pEp_identity *sender,
 11.1735 -    stringlist_t *recipients) {
 11.1736 +static PEP_STATUS amend_rating_according_to_sender_and_recipients(
 11.1737 +       PEP_SESSION session,
 11.1738 +       PEP_rating *rating,
 11.1739 +       pEp_identity *sender,
 11.1740 +       stringlist_t *recipients) {
 11.1741      
 11.1742      PEP_STATUS status = PEP_STATUS_OK;
 11.1743  
 11.1744 @@ -1668,6 +1889,350 @@
 11.1745      return status;
 11.1746  }
 11.1747  
 11.1748 +static PEP_STATUS check_for_sync_msg(PEP_SESSION session, 
 11.1749 +                                     message* src,
 11.1750 +                                     PEP_rating* rating, 
 11.1751 +                                     PEP_decrypt_flags_t* flags,
 11.1752 +                                     stringlist_t** keylist) {
 11.1753 +    assert(session);
 11.1754 +    assert(src);
 11.1755 +    assert(rating);
 11.1756 +    assert(keylist);
 11.1757 +    
 11.1758 +    if (session->sync_session->inject_sync_msg){
 11.1759 +        PEP_STATUS status = receive_DeviceState_msg(session, src, *rating, *keylist);
 11.1760 +        if (status == PEP_MESSAGE_CONSUME ||
 11.1761 +            status == PEP_MESSAGE_IGNORE) {
 11.1762 +            *flags |= (status == PEP_MESSAGE_IGNORE) ?
 11.1763 +                        PEP_decrypt_flag_ignore :
 11.1764 +                        PEP_decrypt_flag_consume;
 11.1765 +        }
 11.1766 +        else if (status != PEP_STATUS_OK) {
 11.1767 +            return ADD_TO_LOG(status);
 11.1768 +        }
 11.1769 +    }
 11.1770 +    return PEP_STATUS_OK;
 11.1771 +}
 11.1772 +
 11.1773 +static PEP_STATUS sync_if_no_key(PEP_STATUS decrypt_status, PEP_SESSION session) {
 11.1774 +    if (decrypt_status == PEP_DECRYPT_NO_KEY) {
 11.1775 +        PEP_STATUS sync_status = inject_DeviceState_event(session, CannotDecrypt, NULL, NULL);
 11.1776 +        if (sync_status == PEP_OUT_OF_MEMORY){
 11.1777 +            return PEP_OUT_OF_MEMORY;
 11.1778 +        }
 11.1779 +    }
 11.1780 +    return PEP_STATUS_OK;
 11.1781 +}
 11.1782 +
 11.1783 +// FIXME: Do we need to remove the attachment? I think we do...
 11.1784 +static bool pull_up_attached_main_msg(message* src) {
 11.1785 +    char* slong = src->longmsg;
 11.1786 +    char* sform = src->longmsg_formatted;
 11.1787 +    bloblist_t* satt = src->attachments;
 11.1788 +    
 11.1789 +    if ((!slong || slong[0] == '\0')
 11.1790 +         && (!sform || sform[0] == '\0')) {
 11.1791 +        if (satt) {
 11.1792 +            const char* inner_mime_type = satt->mime_type;
 11.1793 +            if (strcasecmp(inner_mime_type, "text/plain") == 0) {
 11.1794 +                free(slong); /* in case of "" */
 11.1795 +                src->longmsg = strndup(satt->value, satt->size); 
 11.1796 +                
 11.1797 +                bloblist_t* next_node = satt->next;
 11.1798 +                if (next_node) {
 11.1799 +                    inner_mime_type = next_node->mime_type;
 11.1800 +                    if (strcasecmp(inner_mime_type, "text/html") == 0) {
 11.1801 +                        free(sform);
 11.1802 +                        src->longmsg_formatted = strndup(next_node->value, next_node->size);
 11.1803 +                    }
 11.1804 +                }
 11.1805 +            }
 11.1806 +            else if (strcasecmp(inner_mime_type, "text/html") == 0) {
 11.1807 +                free(sform);
 11.1808 +                src->longmsg_formatted = strndup(satt->value, satt->size);
 11.1809 +            }
 11.1810 +        }
 11.1811 +        return true;
 11.1812 +    }
 11.1813 +    return false;
 11.1814 +}
 11.1815 +
 11.1816 +static PEP_STATUS unencapsulate_hidden_fields(message* src, message* msg,
 11.1817 +                                              char** msg_wrap_info) {
 11.1818 +    if (!src)
 11.1819 +        return PEP_ILLEGAL_VALUE;
 11.1820 +    unsigned char pepstr[] = PEP_SUBJ_STRING;
 11.1821 +    PEP_STATUS status = PEP_STATUS_OK;
 11.1822 +
 11.1823 +    bool change_source_in_place = (msg ? false : true);
 11.1824 +    
 11.1825 +    if (change_source_in_place)
 11.1826 +        msg = src;
 11.1827 +        
 11.1828 +//    const char* version_string = get_message_version_string(src);
 11.1829 +    
 11.1830 +    switch (src->enc_format) {
 11.1831 +        case PEP_enc_PGP_MIME:
 11.1832 +        case PEP_enc_pieces:
 11.1833 +        case PEP_enc_PGP_MIME_Outlook1:
 11.1834 +//        case PEP_enc_none: // FIXME - this is wrong
 11.1835 +
 11.1836 +            if (!change_source_in_place)
 11.1837 +                status = copy_fields(msg, src);
 11.1838 +                
 11.1839 +            if (status != PEP_STATUS_OK)
 11.1840 +                return status;
 11.1841 +                
 11.1842 +            // FIXME: This is a mess. Talk with VB about how far we go to identify
 11.1843 +            if (is_a_pEpmessage(src) || (src->shortmsg == NULL || strcmp(src->shortmsg, "pEp") == 0 ||
 11.1844 +                _unsigned_signed_strcmp(pepstr, src->shortmsg, PEP_SUBJ_BYTELEN) == 0))
 11.1845 +            {
 11.1846 +                char * shortmsg = NULL;
 11.1847 +                char * longmsg = NULL;
 11.1848 +        
 11.1849 +                if (msg->longmsg) {
 11.1850 +                    int r = separate_short_and_long(msg->longmsg, 
 11.1851 +                                                    &shortmsg, 
 11.1852 +                                                    msg_wrap_info,
 11.1853 +                                                    &longmsg);
 11.1854 +                
 11.1855 +                    if (r == -1)
 11.1856 +                        return PEP_OUT_OF_MEMORY;
 11.1857 +                }
 11.1858 +
 11.1859 +                // We only use the shortmsg in version 1.0 messages; if it occurs where we
 11.1860 +                // didn't replace the subject, we ignore this all
 11.1861 +                if (!(*msg_wrap_info || change_source_in_place)) {
 11.1862 +                    if (!shortmsg || 
 11.1863 +                        (src->shortmsg != NULL && strcmp(src->shortmsg, "pEp") != 0 &&
 11.1864 +                         _unsigned_signed_strcmp(pepstr, src->shortmsg, PEP_SUBJ_BYTELEN) != 0)) {
 11.1865 +                             
 11.1866 +                        if (shortmsg != NULL)
 11.1867 +                            free(shortmsg);                        
 11.1868 +                            
 11.1869 +                        if (src->shortmsg == NULL) {
 11.1870 +                            shortmsg = strdup("");
 11.1871 +                        }
 11.1872 +                        else {
 11.1873 +                            // FIXME: is msg->shortmsg always a copy of
 11.1874 +                            // src->shortmsg already?
 11.1875 +                            // if so, we need to change the logic so
 11.1876 +                            // that in this case, we don't free msg->shortmsg
 11.1877 +                            // and do this strdup, etc
 11.1878 +                            shortmsg = strdup(src->shortmsg);
 11.1879 +                        }        
 11.1880 +                    }
 11.1881 +                    free(msg->shortmsg);
 11.1882 +                    msg->shortmsg = shortmsg;
 11.1883 +                }
 11.1884 +                
 11.1885 +                free(msg->longmsg);
 11.1886 +
 11.1887 +                msg->longmsg = longmsg;
 11.1888 +            }
 11.1889 +            else {
 11.1890 +                if (!change_source_in_place) {
 11.1891 +                    msg->shortmsg = strdup(src->shortmsg);
 11.1892 +                    assert(msg->shortmsg);
 11.1893 +                    if (msg->shortmsg == NULL)
 11.1894 +                        return PEP_OUT_OF_MEMORY;
 11.1895 +                }
 11.1896 +            }
 11.1897 +            break;
 11.1898 +        default:
 11.1899 +                // BUG: must implement more
 11.1900 +                NOT_IMPLEMENTED
 11.1901 +    }
 11.1902 +    return PEP_STATUS_OK;
 11.1903 +
 11.1904 +}
 11.1905 +
 11.1906 +static PEP_STATUS verify_decrypted(PEP_SESSION session,
 11.1907 +                                   message* msg, 
 11.1908 +                                   pEp_identity* sender,
 11.1909 +                                   char* plaintext, 
 11.1910 +                                   size_t plaintext_size,
 11.1911 +                                   stringlist_t** keylist,
 11.1912 +                                   PEP_STATUS* decrypt_status,
 11.1913 +                                   PEP_cryptotech crypto) {
 11.1914 +    bloblist_t* detached_sig = NULL;
 11.1915 +    PEP_STATUS status = _get_detached_signature(msg, &detached_sig);
 11.1916 +    
 11.1917 +    if (detached_sig) {
 11.1918 +        char* dsig_text = detached_sig->value;
 11.1919 +        size_t dsig_size = detached_sig->size;
 11.1920 +        size_t ssize = 0;
 11.1921 +        char* stext = NULL;
 11.1922 +
 11.1923 +        status = _get_signed_text(plaintext, plaintext_size, &stext, &ssize);
 11.1924 +        stringlist_t *verify_keylist = NULL;
 11.1925 +
 11.1926 +        if (ssize > 0 && stext) {
 11.1927 +            status = cryptotech[crypto].verify_text(session, stext,
 11.1928 +                                                    ssize, dsig_text, dsig_size,
 11.1929 +                                                    &verify_keylist);
 11.1930 +
 11.1931 +            if (status == PEP_VERIFIED || status == PEP_VERIFIED_AND_TRUSTED)
 11.1932 +            {
 11.1933 +                *decrypt_status = PEP_DECRYPTED_AND_VERIFIED;
 11.1934 +            
 11.1935 +                status = combine_keylists(session, &verify_keylist, keylist, sender);
 11.1936 +            }
 11.1937 +        }
 11.1938 +    }
 11.1939 +    return status;
 11.1940 +}
 11.1941 +
 11.1942 +static PEP_STATUS _decrypt_in_pieces(PEP_SESSION session, 
 11.1943 +                                     message* src, 
 11.1944 +                                     message** msg_ptr, 
 11.1945 +                                     char* ptext,
 11.1946 +                                     size_t psize) {
 11.1947 +                            
 11.1948 +    PEP_STATUS status = PEP_UNKNOWN_ERROR;
 11.1949 +    
 11.1950 +    *msg_ptr = clone_to_empty_message(src);
 11.1951 +
 11.1952 +    if (*msg_ptr == NULL)
 11.1953 +        return PEP_OUT_OF_MEMORY;
 11.1954 +
 11.1955 +    message* msg = *msg_ptr;
 11.1956 +
 11.1957 +    msg->longmsg = ptext;
 11.1958 +    ptext = NULL;
 11.1959 +
 11.1960 +    bloblist_t *_m = msg->attachments;
 11.1961 +    if (_m == NULL && src->attachments && src->attachments->value) {
 11.1962 +        msg->attachments = new_bloblist(NULL, 0, NULL, NULL);
 11.1963 +        _m = msg->attachments;
 11.1964 +    }
 11.1965 +
 11.1966 +    bloblist_t *_s;
 11.1967 +    for (_s = src->attachments; _s; _s = _s->next) {
 11.1968 +        if (_s->value == NULL && _s->size == 0){
 11.1969 +            _m = bloblist_add(_m, NULL, 0, _s->mime_type, _s->filename);
 11.1970 +            if (_m == NULL)
 11.1971 +                return PEP_OUT_OF_MEMORY;
 11.1972 +
 11.1973 +        }
 11.1974 +        else if (is_encrypted_attachment(_s)) {
 11.1975 +            stringlist_t *_keylist = NULL;
 11.1976 +            char *attctext  = _s->value;
 11.1977 +            size_t attcsize = _s->size;
 11.1978 +
 11.1979 +            free(ptext);
 11.1980 +            ptext = NULL;
 11.1981 +
 11.1982 +            // FIXME: What about attachments with separate sigs???
 11.1983 +            status = decrypt_and_verify(session, attctext, attcsize,
 11.1984 +                                        NULL, 0,
 11.1985 +                                        &ptext, &psize, &_keylist);
 11.1986 +            free_stringlist(_keylist); // FIXME: Why do we do this?
 11.1987 +
 11.1988 +            if (ptext) {
 11.1989 +                if (is_encrypted_html_attachment(_s)) {
 11.1990 +                    msg->longmsg_formatted = ptext;
 11.1991 +                    ptext = NULL;
 11.1992 +                }
 11.1993 +                else {
 11.1994 +                    static const char * const mime_type = "application/octet-stream";
 11.1995 +                    char * const filename =
 11.1996 +                        without_double_ending(_s->filename);
 11.1997 +                    if (filename == NULL)
 11.1998 +                        return PEP_OUT_OF_MEMORY;
 11.1999 +
 11.2000 +                    _m = bloblist_add(_m, ptext, psize, mime_type,
 11.2001 +                        filename);
 11.2002 +                    free(filename);
 11.2003 +                    if (_m == NULL)
 11.2004 +                        return PEP_OUT_OF_MEMORY;
 11.2005 +
 11.2006 +                    ptext = NULL;
 11.2007 +
 11.2008 +                    if (msg->attachments == NULL)
 11.2009 +                        msg->attachments = _m;
 11.2010 +                }
 11.2011 +            }
 11.2012 +            else {
 11.2013 +                char *copy = malloc(_s->size);
 11.2014 +                assert(copy);
 11.2015 +                if (copy == NULL)
 11.2016 +                    return PEP_OUT_OF_MEMORY;
 11.2017 +                memcpy(copy, _s->value, _s->size);
 11.2018 +                _m = bloblist_add(_m, copy, _s->size, _s->mime_type, _s->filename);
 11.2019 +                if (_m == NULL)
 11.2020 +                    return PEP_OUT_OF_MEMORY;
 11.2021 +            }
 11.2022 +        }
 11.2023 +        else {
 11.2024 +            char *copy = malloc(_s->size);
 11.2025 +            assert(copy);
 11.2026 +            if (copy == NULL)
 11.2027 +                return PEP_OUT_OF_MEMORY;
 11.2028 +            memcpy(copy, _s->value, _s->size);
 11.2029 +            _m = bloblist_add(_m, copy, _s->size, _s->mime_type, _s->filename);
 11.2030 +            if (_m == NULL)
 11.2031 +                return PEP_OUT_OF_MEMORY;
 11.2032 +        }
 11.2033 +    }
 11.2034 +    return status;
 11.2035 +}
 11.2036 +
 11.2037 +static PEP_STATUS get_crypto_text(message* src, char** crypto_text, size_t* text_size) {
 11.2038 +                
 11.2039 +    // this is only here because of how NOT_IMPLEMENTED works            
 11.2040 +    PEP_STATUS status = PEP_STATUS_OK;
 11.2041 +                    
 11.2042 +    switch (src->enc_format) {
 11.2043 +        case PEP_enc_PGP_MIME:
 11.2044 +            *crypto_text = src->attachments->next->value;
 11.2045 +            *text_size = src->attachments->next->size;
 11.2046 +            break;
 11.2047 +
 11.2048 +        case PEP_enc_PGP_MIME_Outlook1:
 11.2049 +            *crypto_text = src->attachments->value;
 11.2050 +            *text_size = src->attachments->size;
 11.2051 +            break;
 11.2052 +
 11.2053 +        case PEP_enc_pieces:
 11.2054 +            *crypto_text = src->longmsg;
 11.2055 +            *text_size = strlen(*crypto_text);
 11.2056 +            break;
 11.2057 +
 11.2058 +        default:
 11.2059 +            NOT_IMPLEMENTED
 11.2060 +    }
 11.2061 +    
 11.2062 +    return status;
 11.2063 +}
 11.2064 +
 11.2065 +static PEP_STATUS import_priv_keys_from_decrypted_msg(PEP_SESSION session,
 11.2066 +                                                      message* src, 
 11.2067 +                                                      message* msg,
 11.2068 +                                                      bool* imported_keys,
 11.2069 +                                                      bool* imported_private,
 11.2070 +                                                      identity_list** private_il) {
 11.2071 +                                                          
 11.2072 +    PEP_STATUS status = PEP_STATUS_OK;
 11.2073 +    
 11.2074 +    // check for private key in decrypted message attachment while importing
 11.2075 +    identity_list *_private_il = NULL;
 11.2076 +    *imported_keys = import_attached_keys(session, msg, &_private_il);
 11.2077 +    
 11.2078 +    if (_private_il && identity_list_length(_private_il) == 1 &&
 11.2079 +        _private_il->ident->address)
 11.2080 +        *imported_private = true;
 11.2081 +
 11.2082 +    if (private_il && imported_private)
 11.2083 +        *private_il = _private_il;
 11.2084 +    else
 11.2085 +        free_identity_list(_private_il);
 11.2086 +
 11.2087 +    if (imported_keys)
 11.2088 +        status = _update_identity_for_incoming_message(session, src);
 11.2089 +        
 11.2090 +    return status;
 11.2091 +}
 11.2092  
 11.2093  DYNAMIC_API PEP_STATUS _decrypt_message(
 11.2094          PEP_SESSION session,
 11.2095 @@ -1679,6 +2244,18 @@
 11.2096          identity_list **private_il
 11.2097      )
 11.2098  {
 11.2099 +    
 11.2100 +    assert(session);
 11.2101 +    assert(src);
 11.2102 +    assert(dst);
 11.2103 +    assert(keylist);
 11.2104 +    assert(rating);
 11.2105 +    assert(flags);
 11.2106 +
 11.2107 +    if (!(session && src && dst && keylist && rating && flags))
 11.2108 +        return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
 11.2109 +
 11.2110 +    /*** Begin init ***/
 11.2111      PEP_STATUS status = PEP_STATUS_OK;
 11.2112      PEP_STATUS decrypt_status = PEP_CANNOT_DECRYPT_UNKNOWN;
 11.2113      message *msg = NULL;
 11.2114 @@ -1687,19 +2264,15 @@
 11.2115      char *ptext = NULL;
 11.2116      size_t psize;
 11.2117      stringlist_t *_keylist = NULL;
 11.2118 -    unsigned char pepstr[] = PEP_SUBJ_STRING;
 11.2119 -
 11.2120 -    assert(session);
 11.2121 -    assert(src);
 11.2122 -    assert(dst);
 11.2123 -    assert(keylist);
 11.2124 -    assert(rating);
 11.2125 -    assert(flags);
 11.2126 -
 11.2127 -    if (!(session && src && dst && keylist && rating && flags))
 11.2128 -        return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
 11.2129 +
 11.2130 +    *dst = NULL;
 11.2131 +    *keylist = NULL;
 11.2132 +    *rating = PEP_rating_undefined;
 11.2133  
 11.2134      *flags = 0;
 11.2135 +    /*** End init ***/
 11.2136 +
 11.2137 +    /*** Begin Import any attached public keys and update identities accordingly ***/
 11.2138  
 11.2139      // Private key in unencrypted mail are ignored -> NULL
 11.2140      bool imported_keys = import_attached_keys(session, src, NULL);
 11.2141 @@ -1710,6 +2283,9 @@
 11.2142      if(status != PEP_STATUS_OK)
 11.2143          return ADD_TO_LOG(status);
 11.2144  
 11.2145 +    /*** End Import any attached public keys and update identities accordingly ***/
 11.2146 +    
 11.2147 +    /*** Begin get detached signatures that are attached to the encrypted message ***/
 11.2148      // Get detached signature, if any
 11.2149      bloblist_t* detached_sig = NULL;
 11.2150      char* dsig_text = NULL;
 11.2151 @@ -1719,250 +2295,93 @@
 11.2152          dsig_text = detached_sig->value;
 11.2153          dsig_size = detached_sig->size;
 11.2154      }
 11.2155 -
 11.2156 +    /*** End get detached signatures that are attached to the encrypted message ***/
 11.2157 +
 11.2158 +    /*** Determine encryption format ***/
 11.2159      PEP_cryptotech crypto = determine_encryption_format(src);
 11.2160  
 11.2161 -    *dst = NULL;
 11.2162 -    *keylist = NULL;
 11.2163 -    *rating = PEP_rating_undefined;
 11.2164 -
 11.2165 -    switch (src->enc_format) {
 11.2166 -        case PEP_enc_none:
 11.2167 -            *rating = PEP_rating_unencrypted;
 11.2168 -            if (imported_keys)
 11.2169 -                remove_attached_keys(src);
 11.2170 -            if(session->sync_session->inject_sync_msg){
 11.2171 -                status = receive_DeviceState_msg(session, src, *rating, *keylist);
 11.2172 -                if (status == PEP_MESSAGE_CONSUME ||
 11.2173 -                    status == PEP_MESSAGE_IGNORE) {
 11.2174 -                    free_message(msg);
 11.2175 -                    msg = NULL;
 11.2176 -                    *flags |= (status == PEP_MESSAGE_IGNORE) ?
 11.2177 -                                PEP_decrypt_flag_ignore :
 11.2178 -                                PEP_decrypt_flag_consume;
 11.2179 -                }
 11.2180 -                else if (status != PEP_STATUS_OK) {
 11.2181 -                    return ADD_TO_LOG(status);
 11.2182 -                }
 11.2183 -            }
 11.2184 -            
 11.2185 -            char* slong = src->longmsg;
 11.2186 -            char* sform = src->longmsg_formatted;
 11.2187 -            bloblist_t* satt = src->attachments;
 11.2188 -            
 11.2189 -            if ((!slong || slong[0] == '\0')
 11.2190 -                 && (!sform || sform[0] == '\0')) {
 11.2191 -                if (satt) {
 11.2192 -                    const char* inner_mime_type = satt->mime_type;
 11.2193 -                    if (strcasecmp(inner_mime_type, "text/plain") == 0) {
 11.2194 -                        free(slong); /* in case of "" */
 11.2195 -                        src->longmsg = strndup(satt->value, satt->size); // N.B.: longmsg might be shorter, if attachment contains NUL bytes which are not allowed in text/plain!
 11.2196 -                        
 11.2197 -                        bloblist_t* next_node = satt->next;
 11.2198 -                        if (next_node) {
 11.2199 -                            inner_mime_type = next_node->mime_type;
 11.2200 -                            if (strcasecmp(inner_mime_type, "text/html") == 0) {
 11.2201 -                                free(sform);
 11.2202 -                                src->longmsg_formatted = strndup(next_node->value, next_node->size);  // N.B.: longmsg might be shorter, if attachment contains NUL bytes which are not allowed in text/plain!
 11.2203 -                            }
 11.2204 -                        }
 11.2205 -                    }
 11.2206 -                    else if (strcasecmp(inner_mime_type, "text/html") == 0) {
 11.2207 -                        free(sform);
 11.2208 -                        src->longmsg_formatted = strndup(satt->value, satt->size);  // N.B.: longmsg might be shorter, if attachment contains NUL bytes which are not allowed in text/plain!
 11.2209 -                    }
 11.2210 -                }
 11.2211 -            }
 11.2212 -            
 11.2213 -            return ADD_TO_LOG(PEP_UNENCRYPTED);
 11.2214 -
 11.2215 -        case PEP_enc_PGP_MIME:
 11.2216 -            ctext = src->attachments->next->value;
 11.2217 -            csize = src->attachments->next->size;
 11.2218 -            break;
 11.2219 -
 11.2220 -        case PEP_enc_PGP_MIME_Outlook1:
 11.2221 -            ctext = src->attachments->value;
 11.2222 -            csize = src->attachments->size;
 11.2223 -            break;
 11.2224 -
 11.2225 -        case PEP_enc_pieces:
 11.2226 -            ctext = src->longmsg;
 11.2227 -            csize = strlen(ctext);
 11.2228 -            break;
 11.2229 -
 11.2230 -        default:
 11.2231 -            NOT_IMPLEMENTED
 11.2232 +    // Check for and deal with unencrypted messages
 11.2233 +    if (src->enc_format == PEP_enc_none) {
 11.2234 +
 11.2235 +        *rating = PEP_rating_unencrypted;
 11.2236 +
 11.2237 +        if (imported_keys)
 11.2238 +            remove_attached_keys(src);
 11.2239 +
 11.2240 +        status = check_for_sync_msg(session, src, rating, flags, keylist);
 11.2241 +        
 11.2242 +        if (status != PEP_STATUS_OK)
 11.2243 +            return ADD_TO_LOG(status);
 11.2244 +                                    
 11.2245 +        pull_up_attached_main_msg(src);
 11.2246 +        
 11.2247 +        return ADD_TO_LOG(PEP_UNENCRYPTED);
 11.2248      }
 11.2249 +
 11.2250 +    status = get_crypto_text(src, &ctext, &csize);
 11.2251 +    if (status != PEP_STATUS_OK)
 11.2252 +        return status;
 11.2253 +    
 11.2254 +    /** Ok, we should be ready to decrypt. Try decrypt and verify first! **/
 11.2255      status = cryptotech[crypto].decrypt_and_verify(session, ctext,
 11.2256                                                     csize, dsig_text, dsig_size,
 11.2257                                                     &ptext, &psize, &_keylist);
 11.2258 -    if (status > PEP_CANNOT_DECRYPT_UNKNOWN){
 11.2259 +
 11.2260 +    if (status > PEP_CANNOT_DECRYPT_UNKNOWN)
 11.2261          GOTO(pep_error);
 11.2262 -    }
 11.2263  
 11.2264      decrypt_status = status;
 11.2265 -
 11.2266 -    if (status == PEP_DECRYPT_NO_KEY){
 11.2267 -        PEP_STATUS sync_status = inject_DeviceState_event(session, CannotDecrypt, NULL, NULL);
 11.2268 -        if (sync_status == PEP_OUT_OF_MEMORY){
 11.2269 -            status = PEP_OUT_OF_MEMORY;
 11.2270 -            goto pep_error;
 11.2271 -        }
 11.2272 -    }
 11.2273 +    
 11.2274 +    /* inject appropriate sync message if we couldn't decrypt due to no key */
 11.2275 +    if (sync_if_no_key(decrypt_status, session) == PEP_OUT_OF_MEMORY)
 11.2276 +        goto pep_error;
 11.2277  
 11.2278      bool imported_private_key_address = false;
 11.2279  
 11.2280 -    if (ptext) {
 11.2281 +    if (ptext) { 
 11.2282 +        /* we got a plaintext from decryption */
 11.2283          switch (src->enc_format) {
 11.2284 +            
 11.2285              case PEP_enc_PGP_MIME:
 11.2286              case PEP_enc_PGP_MIME_Outlook1:
 11.2287 +            
 11.2288                  status = mime_decode_message(ptext, psize, &msg);
 11.2289                  if (status != PEP_STATUS_OK)
 11.2290                      goto pep_error;
 11.2291                  
 11.2292 -                char* mlong = msg->longmsg;
 11.2293 -                char* mform = msg->longmsg_formatted;
 11.2294 -                bloblist_t* matt = msg->attachments;
 11.2295 -                
 11.2296 -                if ((!mlong || mlong[0] == '\0')
 11.2297 -                     && (!mform || mform[0] == '\0')) {
 11.2298 -                    if (matt) {
 11.2299 -                        const char* inner_mime_type = matt->mime_type;
 11.2300 -                        if (strcasecmp(inner_mime_type, "text/plain") == 0) {
 11.2301 -                            free(mlong); /* in case of "" */
 11.2302 -                            msg->longmsg = strndup(matt->value, matt->size);
 11.2303 -                            
 11.2304 -                            bloblist_t* next_node = matt->next;
 11.2305 -                            if (next_node) {
 11.2306 -                                inner_mime_type = next_node->mime_type;
 11.2307 -                                if (strcasecmp(inner_mime_type, "text/html") == 0) {
 11.2308 -                                    free(mform);
 11.2309 -                                    msg->longmsg_formatted = strndup(next_node->value, next_node->size);
 11.2310 -                                }
 11.2311 -                            }
 11.2312 -                        }
 11.2313 -                        else if (strcasecmp(inner_mime_type, "text/html") == 0) {
 11.2314 -                            free(mform);
 11.2315 -                            msg->longmsg_formatted = strndup(matt->value, matt->size);
 11.2316 -                        }
 11.2317 -                    }
 11.2318 -                    if (msg->shortmsg) {
 11.2319 -                        free(src->shortmsg);
 11.2320 -                        src->shortmsg = strdup(msg->shortmsg);
 11.2321 -                    }
 11.2322 +                /* Ensure messages whose maintext is in the attachments
 11.2323 +                   move main text into message struct longmsg et al */
 11.2324 +                if (pull_up_attached_main_msg(msg) && msg->shortmsg) {
 11.2325 +                    free(src->shortmsg);
 11.2326 +                    src->shortmsg = strdup(msg->shortmsg);
 11.2327                  }
 11.2328  
 11.2329 -                if (decrypt_status != PEP_DECRYPTED_AND_VERIFIED) {
 11.2330 -                    status = _get_detached_signature(msg, &detached_sig);
 11.2331 -                    if (decrypt_status == PEP_DECRYPTED && detached_sig) {
 11.2332 -                        dsig_text = detached_sig->value;
 11.2333 -                        dsig_size = detached_sig->size;
 11.2334 -                        size_t ssize = 0;
 11.2335 -                        char* stext = NULL;
 11.2336 -
 11.2337 -                        status = _get_signed_text(ptext, psize, &stext, &ssize);
 11.2338 -                        stringlist_t *_verify_keylist = NULL;
 11.2339 -
 11.2340 -                        if (ssize > 0 && stext) {
 11.2341 -                            status = cryptotech[crypto].verify_text(session, stext,
 11.2342 -                                                                    ssize, dsig_text, dsig_size,
 11.2343 -                                                                    &_verify_keylist);
 11.2344 -
 11.2345 -                            if (status == PEP_VERIFIED || status == PEP_VERIFIED_AND_TRUSTED)
 11.2346 -                            {
 11.2347 -                                decrypt_status = PEP_DECRYPTED_AND_VERIFIED;
 11.2348 -                            
 11.2349 -                                status = combine_keylists(session, &_verify_keylist, &_keylist, src->from);
 11.2350 -                            }
 11.2351 -                        }
 11.2352 -                    }
 11.2353 +                /* if decrypted, but not verified... */
 11.2354 +                if (decrypt_status == PEP_DECRYPTED) {
 11.2355 +                    
 11.2356 +                    // check for private key in decrypted message attachment while importing
 11.2357 +                    status = import_priv_keys_from_decrypted_msg(session, src, msg,
 11.2358 +                                                                 &imported_keys,
 11.2359 +                                                                 &imported_private_key_address,
 11.2360 +                                                                 private_il);
 11.2361 +                    if (status != PEP_STATUS_OK)
 11.2362 +                        GOTO(pep_error);            
 11.2363 +                                                                 
 11.2364 +                    status = verify_decrypted(session,
 11.2365 +                                              msg, src->from,
 11.2366 +                                              ptext, psize,
 11.2367 +                                              &_keylist,
 11.2368 +                                              &decrypt_status,
 11.2369 +                                              crypto);
 11.2370                  }
 11.2371                  break;
 11.2372  
 11.2373              case PEP_enc_pieces:
 11.2374 -                msg = clone_to_empty_message(src);
 11.2375 -                if (msg == NULL)
 11.2376 +                status = _decrypt_in_pieces(session, src, &msg, ptext, psize);
 11.2377 +            
 11.2378 +                if (status == PEP_OUT_OF_MEMORY)
 11.2379                      goto enomem;
 11.2380  
 11.2381 -                msg->longmsg = ptext;
 11.2382 -                ptext = NULL;
 11.2383 -
 11.2384 -                bloblist_t *_m = msg->attachments;
 11.2385 -                if (_m == NULL && src->attachments && src->attachments->value) {
 11.2386 -                    msg->attachments = new_bloblist(NULL, 0, NULL, NULL);
 11.2387 -                    _m = msg->attachments;
 11.2388 -                }
 11.2389 -
 11.2390 -                bloblist_t *_s;
 11.2391 -                for (_s = src->attachments; _s; _s = _s->next) {
 11.2392 -                    if (_s->value == NULL && _s->size == 0){
 11.2393 -                        _m = bloblist_add(_m, NULL, 0, _s->mime_type, _s->filename);
 11.2394 -                        if (_m == NULL)
 11.2395 -                            goto enomem;
 11.2396 -
 11.2397 -                    }
 11.2398 -                    else if (is_encrypted_attachment(_s)) {
 11.2399 -                        stringlist_t *_keylist = NULL;
 11.2400 -                        char *attctext  = _s->value;
 11.2401 -                        size_t attcsize = _s->size;
 11.2402 -
 11.2403 -                        free(ptext);
 11.2404 -                        ptext = NULL;
 11.2405 -
 11.2406 -                        // FIXME: What about attachments with separate sigs???
 11.2407 -                        status = decrypt_and_verify(session, attctext, attcsize,
 11.2408 -                                                    NULL, 0,
 11.2409 -                                                    &ptext, &psize, &_keylist);
 11.2410 -                        free_stringlist(_keylist); // FIXME: Why do we do this?
 11.2411 -
 11.2412 -                        if (ptext) {
 11.2413 -                            if (is_encrypted_html_attachment(_s)) {
 11.2414 -                                msg->longmsg_formatted = ptext;
 11.2415 -                                ptext = NULL;
 11.2416 -                            }
 11.2417 -                            else {
 11.2418 -                                static const char * const mime_type = "application/octet-stream";
 11.2419 -                                char * const filename =
 11.2420 -                                    without_double_ending(_s->filename);
 11.2421 -                                if (filename == NULL)
 11.2422 -                                    goto enomem;
 11.2423 -
 11.2424 -                                _m = bloblist_add(_m, ptext, psize, mime_type,
 11.2425 -                                    filename);
 11.2426 -                                free(filename);
 11.2427 -                                if (_m == NULL)
 11.2428 -                                    goto enomem;
 11.2429 -
 11.2430 -                                ptext = NULL;
 11.2431 -
 11.2432 -                                if (msg->attachments == NULL)
 11.2433 -                                    msg->attachments = _m;
 11.2434 -                            }
 11.2435 -                        }
 11.2436 -                        else {
 11.2437 -                            char *copy = malloc(_s->size);
 11.2438 -                            assert(copy);
 11.2439 -                            if (copy == NULL)
 11.2440 -                                goto enomem;
 11.2441 -                            memcpy(copy, _s->value, _s->size);
 11.2442 -                            _m = bloblist_add(_m, copy, _s->size, _s->mime_type, _s->filename);
 11.2443 -                            if (_m == NULL)
 11.2444 -                                goto enomem;
 11.2445 -                        }
 11.2446 -                    }
 11.2447 -                    else {
 11.2448 -                        char *copy = malloc(_s->size);
 11.2449 -                        assert(copy);
 11.2450 -                        if (copy == NULL)
 11.2451 -                            goto enomem;
 11.2452 -                        memcpy(copy, _s->value, _s->size);
 11.2453 -                        _m = bloblist_add(_m, copy, _s->size, _s->mime_type, _s->filename);
 11.2454 -                        if (_m == NULL)
 11.2455 -                            goto enomem;
 11.2456 -                    }
 11.2457 -                }
 11.2458 -
 11.2459                  break;
 11.2460  
 11.2461              default:
 11.2462 @@ -1970,113 +2389,91 @@
 11.2463                  NOT_IMPLEMENTED
 11.2464          }
 11.2465  
 11.2466 -        switch (src->enc_format) {
 11.2467 -            case PEP_enc_PGP_MIME:
 11.2468 -            case PEP_enc_pieces:
 11.2469 -            case PEP_enc_PGP_MIME_Outlook1:
 11.2470 -                status = copy_fields(msg, src);
 11.2471 -                if (status != PEP_STATUS_OK)
 11.2472 -                {
 11.2473 -                    GOTO(pep_error);
 11.2474 +        if (status == PEP_OUT_OF_MEMORY)
 11.2475 +            goto enomem;
 11.2476 +            
 11.2477 +        if (status != PEP_STATUS_OK)
 11.2478 +            goto pep_error;
 11.2479 +
 11.2480 +        if (decrypt_status == PEP_DECRYPTED || decrypt_status == PEP_DECRYPTED_AND_VERIFIED) {
 11.2481 +            char* wrap_info = NULL;
 11.2482 +            status = unencapsulate_hidden_fields(src, msg, &wrap_info);
 11.2483 +
 11.2484 +//            bool is_transport_wrapper = false;
 11.2485 +            
 11.2486 +            // FIXME: replace with enums, check status
 11.2487 +            if (wrap_info) {
 11.2488 +                if (strcmp(wrap_info, "OUTER") == 0) {
 11.2489 +                    // this only occurs in with a direct outer wrapper
 11.2490 +                    // where the actual content is in the inner wrapper
 11.2491 +                    message* inner_message = NULL;                    
 11.2492 +                    bloblist_t* actual_message = msg->attachments;
 11.2493 +                    
 11.2494 +                    while (actual_message) {
 11.2495 +                        char* mime_type = actual_message->mime_type;
 11.2496 +                        if (mime_type) {
 11.2497 +                            
 11.2498 +                            // libetpan appears to change the mime_type on this one.
 11.2499 +                            // *growl*
 11.2500 +                            if (strcmp("message/rfc822", mime_type) == 0 ||
 11.2501 +                                strcmp("text/rfc822", mime_type) == 0) {
 11.2502 +                                    
 11.2503 +                                status = mime_decode_message(actual_message->value, 
 11.2504 +                                                             actual_message->size, 
 11.2505 +                                                             &inner_message);
 11.2506 +                                if (status != PEP_STATUS_OK)
 11.2507 +                                    GOTO(pep_error);
 11.2508 +                                
 11.2509 +                                if (inner_message) {
 11.2510 +                                    // Though this will strip any message info on the
 11.2511 +                                    // attachment, this is safe, as we do not
 11.2512 +                                    // produce more than one attachment-as-message,
 11.2513 +                                    // and those are the only ones with such info.
 11.2514 +                                    // Since we capture the information, this is ok.
 11.2515 +                                    wrap_info = NULL;
 11.2516 +                                    inner_message->enc_format = src->enc_format;
 11.2517 +                                    // FIXME
 11.2518 +                                    status = unencapsulate_hidden_fields(inner_message, NULL, &wrap_info);
 11.2519 +                                    if (wrap_info) {
 11.2520 +                                        // useless check, but just in case we screw up?
 11.2521 +                                        if (strcmp(wrap_info, "INNER") == 0) {
 11.2522 +                                            // THIS is our message
 11.2523 +                                            // FIXME: free msg, but check references
 11.2524 +                                            src = msg = inner_message;
 11.2525 +                                            
 11.2526 +                                            if (src->from)
 11.2527 +                                                update_identity(session, src->from);
 11.2528 +                                            break;        
 11.2529 +                                        }
 11.2530 +                                        else { // should never happen
 11.2531 +                                            status = PEP_UNKNOWN_ERROR;
 11.2532 +                                            free_message(inner_message);
 11.2533 +                                            GOTO(pep_error);
 11.2534 +                                        }
 11.2535 +                                    }
 11.2536 +                                    inner_message->enc_format = PEP_enc_none;
 11.2537 +                                }
 11.2538 +                                else { // forwarded message, leave it alone
 11.2539 +                                    free_message(inner_message);
 11.2540 +                                }
 11.2541 +                            }
 11.2542 +                        }
 11.2543 +                        actual_message = actual_message->next;
 11.2544 +                    }                    
 11.2545                  }
 11.2546 -
 11.2547 -                if (src->shortmsg == NULL || strcmp(src->shortmsg, "pEp") == 0 ||
 11.2548 -                    _unsigned_signed_strcmp(pepstr, src->shortmsg, PEP_SUBJ_BYTELEN) == 0)
 11.2549 -                {
 11.2550 -                    char * shortmsg;
 11.2551 -                    char * longmsg;
 11.2552 -
 11.2553 -                    int r = separate_short_and_long(msg->longmsg, &shortmsg,
 11.2554 -                            &longmsg);
 11.2555 -                    
 11.2556 -                    if (r == -1)
 11.2557 -                        goto enomem;
 11.2558 -
 11.2559 -                    if (shortmsg == NULL) {
 11.2560 -                        if (src->shortmsg == NULL)
 11.2561 -                            shortmsg = strdup("");
 11.2562 -                        else {
 11.2563 -                            // FIXME: is msg->shortmsg always a copy of
 11.2564 -                            // src->shortmsg already?
 11.2565 -                            // if so, we need to change the logic so
 11.2566 -                            // that in this case, we don't free msg->shortmsg
 11.2567 -                            // and do this strdup, etc.
 11.2568 -                            shortmsg = strdup(src->shortmsg);
 11.2569 -                        }
 11.2570 -                    }
 11.2571 -
 11.2572 -
 11.2573 -                    free(msg->shortmsg);
 11.2574 -                    free(msg->longmsg);
 11.2575 -
 11.2576 -                    msg->shortmsg = shortmsg;
 11.2577 -                    msg->longmsg = longmsg;
 11.2578 +                else if (strcmp(wrap_info, "TRANSPORT") == 0) {
 11.2579 +                    // FIXME: this gets even messier.
 11.2580 +                    // (TBI in ENGINE-278)
 11.2581                  }
 11.2582 -                else {
 11.2583 -                    msg->shortmsg = strdup(src->shortmsg);
 11.2584 -                    assert(msg->shortmsg);
 11.2585 -                    if (msg->shortmsg == NULL)
 11.2586 -                        goto enomem;
 11.2587 -                }
 11.2588 -                break;
 11.2589 -            default:
 11.2590 -                    // BUG: must implement more
 11.2591 -                    NOT_IMPLEMENTED
 11.2592 +                else {} // shouldn't be anything to be done here
 11.2593 +            }
 11.2594          }
 11.2595 -
 11.2596 -        // check for private key in decrypted message attachement while inporting
 11.2597 -        identity_list *_private_il = NULL;
 11.2598 -        imported_keys = import_attached_keys(session, msg, &_private_il);
 11.2599 -        if (_private_il &&
 11.2600 -            identity_list_length(_private_il) == 1 &&
 11.2601 -            _private_il->ident->address)
 11.2602 -        {
 11.2603 -            imported_private_key_address = true;
 11.2604 -        }
 11.2605 -
 11.2606 -        if(private_il && imported_private_key_address){
 11.2607 -            *private_il = _private_il;
 11.2608 -        }else{
 11.2609 -            free_identity_list(_private_il);
 11.2610 -        }
 11.2611 -
 11.2612 -        if(decrypt_status == PEP_DECRYPTED){
 11.2613 -
 11.2614 -            // TODO optimize if import_attached_keys didn't import any key
 11.2615 -
 11.2616 -            // In case message did decrypt, but no valid signature could be found
 11.2617 -            // then retry decrypt+verify after importing key.
 11.2618 -
 11.2619 -            // Update msg->from in case we just imported a key
 11.2620 -            // we would need to check signature
 11.2621 -
 11.2622 -            status = _update_identity_for_incoming_message(session, src);
 11.2623 -            if(status != PEP_STATUS_OK)
 11.2624 -            {
 11.2625 -                GOTO(pep_error);
 11.2626 -            }
 11.2627 -
 11.2628 -            char *re_ptext = NULL;
 11.2629 -            size_t re_psize;
 11.2630 -
 11.2631 -            free_stringlist(_keylist);
 11.2632 -            _keylist = NULL;
 11.2633 -
 11.2634 -            status = cryptotech[crypto].decrypt_and_verify(session, ctext,
 11.2635 -                csize, dsig_text, dsig_size, &re_ptext, &re_psize, &_keylist);
 11.2636 -
 11.2637 -            free(re_ptext);
 11.2638 -
 11.2639 -            if (status > PEP_CANNOT_DECRYPT_UNKNOWN)
 11.2640 -            {
 11.2641 -                GOTO(pep_error);
 11.2642 -            }
 11.2643 -
 11.2644 -            decrypt_status = status;
 11.2645 -        }
 11.2646 -
 11.2647 +        
 11.2648          *rating = decrypt_rating(decrypt_status);
 11.2649  
 11.2650 +        /* Ok, now we have a keylist used for decryption/verification.
 11.2651 +           now we need to update the message rating with the 
 11.2652 +           sender and recipients in mind */
 11.2653          status = amend_rating_according_to_sender_and_recipients(session,
 11.2654                                                                   rating,
 11.2655                                                                   src->from,
 11.2656 @@ -2084,55 +2481,53 @@
 11.2657  
 11.2658          if (status != PEP_STATUS_OK)
 11.2659              GOTO(pep_error);
 11.2660 -    }
 11.2661 -    else
 11.2662 -    {
 11.2663 +            
 11.2664 +    } 
 11.2665 +    else {
 11.2666 +        // We did not get a plaintext out of the decryption process.
 11.2667 +        // Abort and return error.
 11.2668          *rating = decrypt_rating(decrypt_status);
 11.2669          goto pep_error;
 11.2670      }
 11.2671  
 11.2672 -    // Case of own key imported from own trusted message
 11.2673 -    if (// Message have been reliably decrypted
 11.2674 -        msg &&
 11.2675 -        *rating >= PEP_rating_trusted &&
 11.2676 -        imported_private_key_address &&
 11.2677 -        // to is [own]
 11.2678 +    /* 
 11.2679 +       Ok, at this point, we know we have a reliably decrypted message.
 11.2680 +       Prepare the output message for return.
 11.2681 +    */
 11.2682 +    
 11.2683 +    // 1. Check to see if this message is to us and contains an own key imported 
 11.2684 +    // from own trusted message 
 11.2685 +    if (msg && *rating >= PEP_rating_trusted && imported_private_key_address &&
 11.2686          msg->to->ident->user_id &&
 11.2687 -        strcmp(msg->to->ident->user_id, PEP_OWN_USERID) == 0
 11.2688 -        )
 11.2689 -    {
 11.2690 +        strcmp(msg->to->ident->user_id, PEP_OWN_USERID) == 0) {
 11.2691 +
 11.2692 +        // flag it as such
 11.2693          *flags |= PEP_decrypt_flag_own_private_key;
 11.2694      }
 11.2695  
 11.2696 +    // 2. Clean up message and prepare for return 
 11.2697      if (msg) {
 11.2698 +        
 11.2699 +        /* add pEp-related status flags to header */
 11.2700          decorate_message(msg, *rating, _keylist);
 11.2701 +        
 11.2702          if (imported_keys)
 11.2703              remove_attached_keys(msg);
 11.2704 -        if (*rating >= PEP_rating_reliable &&
 11.2705 -            session->sync_session->inject_sync_msg) {
 11.2706 -            status = receive_DeviceState_msg(session, msg, *rating, _keylist);
 11.2707 -            if (status == PEP_MESSAGE_CONSUME ||
 11.2708 -                status == PEP_MESSAGE_IGNORE) {
 11.2709 -                free_message(msg);
 11.2710 -                msg = NULL;
 11.2711 -                *flags |= (status == PEP_MESSAGE_IGNORE) ?
 11.2712 -                            PEP_decrypt_flag_ignore :
 11.2713 -                            PEP_decrypt_flag_consume;
 11.2714 -
 11.2715 -            }
 11.2716 -            else if (status != PEP_STATUS_OK){
 11.2717 +            
 11.2718 +        if (*rating >= PEP_rating_reliable) { 
 11.2719 +            status = check_for_sync_msg(session, src, rating, flags, &_keylist);
 11.2720 +        
 11.2721 +            if (status != PEP_STATUS_OK)
 11.2722                  goto pep_error;
 11.2723 -            }
 11.2724          }
 11.2725 -    }
 11.2726 -    if (msg) {
 11.2727 -        if (src->id) {
 11.2728 +        
 11.2729 +        if (src->id && src != msg) {
 11.2730              msg->id = strdup(src->id);
 11.2731              assert(msg->id);
 11.2732              if (msg->id == NULL)
 11.2733                  goto enomem;
 11.2734          }
 11.2735 -    }
 11.2736 +    } // End prepare output message for return
 11.2737  
 11.2738      *dst = msg;
 11.2739      *keylist = _keylist;
 11.2740 @@ -2431,7 +2826,7 @@
 11.2741  
 11.2742      max_len = (source1_len > source2_len ? source1_len : source2_len);
 11.2743      
 11.2744 -    char* XORed_fpr = (char*)(calloc(1,max_len + 1));
 11.2745 +    char* XORed_fpr = (char*)(calloc(max_len + 1, 1));
 11.2746      *(XORed_fpr + max_len) = '\0';
 11.2747      char* result_curr = XORed_fpr + max_len - 1;
 11.2748      char* source1_curr = source1 + source1_len - 1;
 11.2749 @@ -2671,7 +3066,8 @@
 11.2750          GOTO(pep_error);
 11.2751      }
 11.2752  
 11.2753 -    status = mime_encode_message(dec_msg, false, mime_plaintext);
 11.2754 +    dec_msg->enc_format = PEP_enc_none; // is this the right thing to do? FIXME
 11.2755 +    status = _mime_encode_message_internal(dec_msg, false, mime_plaintext, false);
 11.2756  
 11.2757      if (status == PEP_STATUS_OK)
 11.2758      {
 11.2759 @@ -2723,6 +3119,9 @@
 11.2760          GOTO(pep_error);
 11.2761      }
 11.2762  
 11.2763 +    // Clear the encryption status, or mime_encode will ignore
 11.2764 +    // the plaintext and do all sorts of other stupid things
 11.2765 +    enc_msg->enc_format = PEP_enc_none;
 11.2766      status = mime_encode_message(enc_msg, false, mime_ciphertext);
 11.2767  
 11.2768  pep_error:
    12.1 --- a/src/message_api.h	Thu Sep 21 15:46:18 2017 +0200
    12.2 +++ b/src/message_api.h	Thu Oct 26 14:09:20 2017 +0200
    12.3 @@ -33,7 +33,11 @@
    12.4      // This flag is for special use cases and should not be used
    12.5      // by normal pEp clients!
    12.6      PEP_encrypt_flag_force_unsigned = 0x2,
    12.7 -    PEP_encrypt_flag_force_no_attached_key = 0x4
    12.8 +    PEP_encrypt_flag_force_no_attached_key = 0x4,
    12.9 +    
   12.10 +    // This is used for outer messages (used to wrap the real message)
   12.11 +    // This is only used internally and (eventually) by transport functions
   12.12 +    PEP_encrypt_flag_inner_message = 0x8
   12.13  } PEP_encrypt_flags; 
   12.14  
   12.15  typedef unsigned int PEP_encrypt_flags_t;
    13.1 --- a/src/mime.c	Thu Sep 21 15:46:18 2017 +0200
    13.2 +++ b/src/mime.c	Thu Oct 26 14:09:20 2017 +0200
    13.3 @@ -100,7 +100,8 @@
    13.4  
    13.5  static PEP_STATUS mime_attachment(
    13.6          bloblist_t *blob,
    13.7 -        struct mailmime **result
    13.8 +        struct mailmime **result,
    13.9 +        bool transport_encode
   13.10      )
   13.11  {
   13.12      PEP_STATUS status = PEP_STATUS_OK;
   13.13 @@ -121,7 +122,7 @@
   13.14          mime_type = blob->mime_type;
   13.15  
   13.16      pEp_rid_list_t* resource = parse_uri(blob->filename);
   13.17 -    mime = get_file_part(resource, mime_type, blob->value, blob->size);
   13.18 +    mime = get_file_part(resource, mime_type, blob->value, blob->size, transport_encode);
   13.19      free_rid_list(resource);
   13.20      
   13.21      assert(mime);
   13.22 @@ -144,7 +145,8 @@
   13.23          const char *plaintext,
   13.24          const char *htmltext,
   13.25          bloblist_t *attachments,
   13.26 -        struct mailmime **result
   13.27 +        struct mailmime **result,
   13.28 +        bool transport_encode
   13.29      )
   13.30  {
   13.31      PEP_STATUS status = PEP_STATUS_OK;
   13.32 @@ -166,8 +168,9 @@
   13.33  
   13.34      pEp_rid_list_t* resource = new_rid_node(PEP_RID_FILENAME, "msg.txt");
   13.35      
   13.36 +    int encoding_type = (transport_encode ? MAILMIME_MECHANISM_QUOTED_PRINTABLE : 0);
   13.37      submime = get_text_part(NULL, "text/plain", plaintext, strlen(plaintext),
   13.38 -            MAILMIME_MECHANISM_QUOTED_PRINTABLE);
   13.39 +            encoding_type);
   13.40      free_rid_list(resource);
   13.41      resource = NULL;
   13.42      
   13.43 @@ -222,7 +225,7 @@
   13.44  
   13.45  //    resource = new_rid_node(PEP_RID_FILENAME, "msg.html");
   13.46      submime = get_text_part(NULL, "text/html", htmltext, strlen(htmltext),
   13.47 -            MAILMIME_MECHANISM_QUOTED_PRINTABLE);
   13.48 +            encoding_type);
   13.49      free_rid_list(resource);
   13.50      resource = NULL;
   13.51      
   13.52 @@ -243,7 +246,7 @@
   13.53      for (_a = attachments; _a != NULL; _a = _a->next) {
   13.54          if (_a->disposition != PEP_CONTENT_DISP_INLINE)
   13.55              continue;
   13.56 -        status = mime_attachment(_a, &submime);
   13.57 +        status = mime_attachment(_a, &submime, transport_encode);
   13.58          if (status != PEP_STATUS_OK)
   13.59              return PEP_UNKNOWN_ERROR; // FIXME
   13.60  
   13.61 @@ -273,6 +276,8 @@
   13.62      return status;
   13.63  }
   13.64  
   13.65 +
   13.66 +// FIXME: maybe need to add transport_encode field here
   13.67  static struct mailimf_mailbox * identity_to_mailbox(const pEp_identity *ident)
   13.68  {
   13.69      char *_username = NULL;
   13.70 @@ -384,17 +389,22 @@
   13.71      return NULL;
   13.72  }
   13.73  
   13.74 -static clist * stringlist_to_clist(stringlist_t *sl)
   13.75 +static clist * stringlist_to_clist(stringlist_t *sl, bool transport_encode)
   13.76  {
   13.77      clist * cl = clist_new();
   13.78      assert(cl);
   13.79      if (cl == NULL)
   13.80          return NULL;
   13.81  
   13.82 +    if (!sl || ((!sl->value || sl->value[0] == '\0') && sl->next == NULL))
   13.83 +        return cl;
   13.84 +        
   13.85      stringlist_t *_sl;
   13.86      for (_sl = sl; _sl; _sl = _sl->next) {
   13.87          int r;
   13.88 -        char * value = mailmime_encode_subject_header("utf-8", _sl->value, 0);
   13.89 +        char * value = (transport_encode ?
   13.90 +                        mailmime_encode_subject_header("utf-8", _sl->value, 0) :
   13.91 +                        strdup(_sl->value));
   13.92          assert(value);
   13.93          if (value == NULL) {
   13.94              clist_free(cl);
   13.95 @@ -412,7 +422,8 @@
   13.96      return cl;
   13.97  }
   13.98  
   13.99 -static PEP_STATUS build_fields(const message *msg, struct mailimf_fields **result)
  13.100 +static PEP_STATUS build_fields(const message *msg, struct mailimf_fields **result,
  13.101 +                               bool transport_encode)
  13.102  {
  13.103      PEP_STATUS status = PEP_STATUS_OK;
  13.104      struct mailimf_fields * fields = NULL;
  13.105 @@ -487,7 +498,9 @@
  13.106      }
  13.107  
  13.108      /* if (subject) */ {
  13.109 -        char *_subject = mailmime_encode_subject_header("utf-8", subject, 1);
  13.110 +        char *_subject = (transport_encode ? 
  13.111 +                          mailmime_encode_subject_header("utf-8", subject, 1) :
  13.112 +                          strdup(subject));
  13.113          if (_subject == NULL)
  13.114              goto enomem;
  13.115  
  13.116 @@ -539,7 +552,7 @@
  13.117      }
  13.118  
  13.119      if (msg->in_reply_to) {
  13.120 -        clist *in_reply_to = stringlist_to_clist(msg->in_reply_to);
  13.121 +        clist *in_reply_to = stringlist_to_clist(msg->in_reply_to, transport_encode);
  13.122          if (in_reply_to == NULL)
  13.123              goto enomem;
  13.124  
  13.125 @@ -552,7 +565,7 @@
  13.126      }
  13.127  
  13.128      if (msg->references) {
  13.129 -        clist *references = stringlist_to_clist(msg->references);
  13.130 +        clist *references = stringlist_to_clist(msg->references, transport_encode);
  13.131          if (references == NULL)
  13.132              goto enomem;
  13.133  
  13.134 @@ -565,7 +578,7 @@
  13.135      }
  13.136  
  13.137      if (msg->keywords) {
  13.138 -        clist *keywords = stringlist_to_clist(msg->keywords);
  13.139 +        clist *keywords = stringlist_to_clist(msg->keywords, transport_encode);
  13.140          if (keywords == NULL)
  13.141              goto enomem;
  13.142  
  13.143 @@ -578,8 +591,9 @@
  13.144      }
  13.145  
  13.146      if (msg->comments) {
  13.147 -        char *comments = mailmime_encode_subject_header("utf-8", msg->comments,
  13.148 -                0);
  13.149 +        char *comments = (transport_encode ?
  13.150 +                          mailmime_encode_subject_header("utf-8", msg->comments, 0) :
  13.151 +                          strdup(msg->comments));
  13.152          if (comments == NULL)
  13.153              goto enomem;
  13.154  
  13.155 @@ -597,7 +611,9 @@
  13.156              char *key = _l->value->key;
  13.157              char *value = _l->value->value;
  13.158              if (key && value) {
  13.159 -                char *_value = mailmime_encode_subject_header("utf-8", value, 0);
  13.160 +                char *_value = (transport_encode ?
  13.161 +                                mailmime_encode_subject_header("utf-8", value, 0) :
  13.162 +                                strdup(value));
  13.163                  if (_value == NULL)
  13.164                      goto enomem;
  13.165  
  13.166 @@ -695,7 +711,8 @@
  13.167  static PEP_STATUS mime_encode_message_plain(
  13.168          const message *msg,
  13.169          bool omit_fields,
  13.170 -        struct mailmime **result
  13.171 +        struct mailmime **result,
  13.172 +        bool transport_encode
  13.173      )
  13.174  {
  13.175      struct mailmime * mime = NULL;
  13.176 @@ -717,7 +734,8 @@
  13.177          /* first, we need to strip out the inlined attachments to ensure this
  13.178             gets set up correctly */
  13.179             
  13.180 -        status = mime_html_text(plaintext, htmltext, msg->attachments, &mime);
  13.181 +        status = mime_html_text(plaintext, htmltext, msg->attachments, &mime,
  13.182 +                                transport_encode);
  13.183                  
  13.184          if (status != PEP_STATUS_OK)
  13.185              goto pep_error;
  13.186 @@ -726,13 +744,15 @@
  13.187          pEp_rid_list_t* resource = NULL;
  13.188          if (is_PGP_message_text(plaintext)) {
  13.189              resource = new_rid_node(PEP_RID_FILENAME, "msg.asc");
  13.190 +            int encoding_type = (transport_encode ? MAILMIME_MECHANISM_7BIT : 0);
  13.191              mime = get_text_part(resource, "application/octet-stream", plaintext,
  13.192 -                    strlen(plaintext), MAILMIME_MECHANISM_7BIT);
  13.193 +                    strlen(plaintext), encoding_type);
  13.194          }
  13.195          else {
  13.196              resource = new_rid_node(PEP_RID_FILENAME, "msg.txt");
  13.197 +            int encoding_type = (transport_encode ? MAILMIME_MECHANISM_QUOTED_PRINTABLE : 0);
  13.198              mime = get_text_part(resource, "text/plain", plaintext, strlen(plaintext),
  13.199 -                    MAILMIME_MECHANISM_QUOTED_PRINTABLE);
  13.200 +                    encoding_type);
  13.201          }
  13.202          free_rid_list(resource);
  13.203          
  13.204 @@ -776,7 +796,7 @@
  13.205              if (_a->disposition == PEP_CONTENT_DISP_INLINE)
  13.206                  continue;
  13.207  
  13.208 -            status = mime_attachment(_a, &submime);
  13.209 +            status = mime_attachment(_a, &submime, transport_encode);
  13.210              if (status != PEP_STATUS_OK)
  13.211                  goto pep_error;
  13.212  
  13.213 @@ -819,14 +839,12 @@
  13.214  	struct mailmime_parameter * param;
  13.215      int r;
  13.216      PEP_STATUS status;
  13.217 -    //char *subject;
  13.218      char *plaintext;
  13.219      size_t plaintext_size;
  13.220  
  13.221      assert(msg->attachments && msg->attachments->next &&
  13.222              msg->attachments->next->value);
  13.223  
  13.224 -    //subject = (msg->shortmsg) ? msg->shortmsg : "pEp"; // not used, yet.
  13.225      plaintext = msg->attachments->next->value;
  13.226      plaintext_size = msg->attachments->next->size;
  13.227  
  13.228 @@ -894,6 +912,16 @@
  13.229          char **mimetext
  13.230      )
  13.231  {
  13.232 +    return _mime_encode_message_internal(msg, omit_fields, mimetext, true);
  13.233 +}
  13.234 +
  13.235 +PEP_STATUS _mime_encode_message_internal(
  13.236 +        const message * msg,
  13.237 +        bool omit_fields,
  13.238 +        char **mimetext,
  13.239 +        bool transport_encode
  13.240 +    )
  13.241 +{
  13.242      PEP_STATUS status = PEP_STATUS_OK;
  13.243      struct mailmime * msg_mime = NULL;
  13.244      struct mailmime * mime = NULL;
  13.245 @@ -911,11 +939,11 @@
  13.246  
  13.247      switch (msg->enc_format) {
  13.248          case PEP_enc_none:
  13.249 -            status = mime_encode_message_plain(msg, omit_fields, &mime);
  13.250 +            status = mime_encode_message_plain(msg, omit_fields, &mime, transport_encode);
  13.251              break;
  13.252  
  13.253          case PEP_enc_pieces:
  13.254 -            status = mime_encode_message_plain(msg, omit_fields, &mime);
  13.255 +            status = mime_encode_message_plain(msg, omit_fields, &mime, transport_encode);
  13.256              break;
  13.257  
  13.258          case PEP_enc_S_MIME:
  13.259 @@ -948,7 +976,7 @@
  13.260      mime = NULL;
  13.261  
  13.262      if (!omit_fields) {
  13.263 -        status = build_fields(msg, &fields);
  13.264 +        status = build_fields(msg, &fields, transport_encode);
  13.265          if (status != PEP_STATUS_OK)
  13.266              goto pep_error;
  13.267  
  13.268 @@ -1093,7 +1121,7 @@
  13.269          text = NULL;
  13.270      }
  13.271  
  13.272 -    return _sl;
  13.273 +    return sl;
  13.274  
  13.275  enomem:
  13.276      free_stringlist(sl);
    14.1 --- a/src/mime.h	Thu Sep 21 15:46:18 2017 +0200
    14.2 +++ b/src/mime.h	Thu Oct 26 14:09:20 2017 +0200
    14.3 @@ -40,6 +40,10 @@
    14.4  //      the resulttext will go to the ownership of the caller
    14.5  //      the message will remain in the ownership of the caller
    14.6  //      omit_fields is true for payload of PGP/MIME messages
    14.7 +//
    14.8 +//      also: note that the encryption type will be used to determine what
    14.9 +//      gets encoded from the message struct, so if using this on an 
   14.10 +//      already-encrypted message, set the enc_format of the msg to PEP_enc_none.
   14.11  
   14.12  DYNAMIC_API PEP_STATUS mime_encode_message(
   14.13          const message * msg,
   14.14 @@ -74,6 +78,15 @@
   14.15          message **msg
   14.16      );
   14.17  
   14.18 +/* sometimes we don't want to transport encode */
   14.19 +PEP_STATUS _mime_encode_message_internal(
   14.20 +        const message * msg,
   14.21 +        bool omit_fields,
   14.22 +        char **mimetext,
   14.23 +        bool transport_encode
   14.24 +    );
   14.25 +
   14.26 +
   14.27  #ifdef __cplusplus
   14.28  }
   14.29  #endif
    15.1 --- a/src/pEpEngine.c	Thu Sep 21 15:46:18 2017 +0200
    15.2 +++ b/src/pEpEngine.c	Thu Oct 26 14:09:20 2017 +0200
    15.3 @@ -8,7 +8,10 @@
    15.4  #include "blacklist.h"
    15.5  #include "sync_fsm.h"
    15.6  
    15.7 -static int init_count = -1;
    15.8 +#include <time.h>
    15.9 +#include <stdlib.h>
   15.10 +
   15.11 +static volatile int init_count = -1;
   15.12  
   15.13  // sql overloaded functions - modified from sqlite3.c
   15.14  static void _sql_lower(sqlite3_context* ctx, int argc, sqlite3_value** argv) {
   15.15 @@ -264,9 +267,25 @@
   15.16      // a little race condition - but still a race condition
   15.17      // mitigated by calling caveat (see documentation)
   15.18  
   15.19 -    ++init_count;
   15.20 -    if (init_count == 0)
   15.21 +    // this increment is made atomic IN THE ADAPTERS by
   15.22 +    // guarding the call to init with the appropriate mutex.
   15.23 +    int _count = ++init_count;
   15.24 +    if (_count == 0)
   15.25          in_first = true;
   15.26 +    
   15.27 +    // Race condition mitigated by calling caveat starts here :
   15.28 +    // If another call to init() preempts right now, then preemptive call
   15.29 +    // will have in_first false, will not create SQL tables, and following
   15.30 +    // calls relying on those tables will fail.
   15.31 +    //
   15.32 +    // Therefore, as above, adapters MUST guard init() with a mutex.
   15.33 +    // 
   15.34 +    // Therefore, first session
   15.35 +    // is to be created and last session to be deleted alone, and not
   15.36 +    // concurently to other sessions creation or deletion.
   15.37 +    // We expect adapters to enforce this either by implicitely creating a
   15.38 +    // client session, or by using synchronization primitive to protect
   15.39 +    // creation/deletion of first/last session from the app.
   15.40  
   15.41      assert(session);
   15.42      if (session == NULL)
   15.43 @@ -306,6 +325,16 @@
   15.44          goto pep_error;
   15.45      }
   15.46  
   15.47 +    int_result = sqlite3_exec(
   15.48 +            _session->db,
   15.49 +            "PRAGMA locking_mode=NORMAL;\n"
   15.50 +            "PRAGMA journal_mode=WAL;\n",
   15.51 +            NULL,
   15.52 +            NULL,
   15.53 +            NULL
   15.54 +        );
   15.55 +
   15.56 +
   15.57      sqlite3_busy_timeout(_session->db, BUSY_WAIT_TIME);
   15.58  
   15.59      assert(SYSTEM_DB);
   15.60 @@ -352,8 +381,8 @@
   15.61                  "create table if not exists log (\n"
   15.62                  "   timestamp integer default (datetime('now')),\n"
   15.63                  "   title text not null,\n"
   15.64 +                "   description text,\n"
   15.65                  "   entity text not null,\n"
   15.66 -                "   description text,\n"
   15.67                  "   comment text\n"
   15.68                  ");\n"
   15.69                  "create index if not exists log_timestamp on log (\n"
   15.70 @@ -546,6 +575,10 @@
   15.71              );
   15.72              assert(int_result == SQLITE_OK);
   15.73          }
   15.74 +        
   15.75 +        // We need to init a few globals for message id that we'd rather not
   15.76 +        // calculate more than once.
   15.77 +        _init_globals();
   15.78      }
   15.79  
   15.80      int_result = sqlite3_prepare_v2(_session->db, sql_log,
   15.81 @@ -759,6 +792,12 @@
   15.82      _session->sync_session = _session;
   15.83  
   15.84      *session = _session;
   15.85 +    
   15.86 +    // Note: Following statement is NOT for any cryptographic/secure functionality; it is
   15.87 +    //       ONLY used for some randomness in generated outer message ID, which are
   15.88 +    //       required by the RFC to be globally unique!
   15.89 +    srand(time(NULL));
   15.90 +    
   15.91      return PEP_STATUS_OK;
   15.92  
   15.93  enomem:
   15.94 @@ -772,19 +811,19 @@
   15.95  DYNAMIC_API void release(PEP_SESSION session)
   15.96  {
   15.97      bool out_last = false;
   15.98 -
   15.99 -    assert(init_count >= 0);
  15.100 +    int _count = --init_count;
  15.101 +    
  15.102 +    assert(_count >= -1);
  15.103      assert(session);
  15.104  
  15.105 -    if (!((init_count >= 0) && session))
  15.106 +    if (!((_count >= -1) && session))
  15.107          return;
  15.108  
  15.109      // a small race condition but still a race condition
  15.110      // mitigated by calling caveat (see documentation)
  15.111 -
  15.112 -    if (init_count == 0)
  15.113 +    // (release() is to be guarded by a mutex by the caller)
  15.114 +    if (_count == -1)
  15.115          out_last = true;
  15.116 -    --init_count;
  15.117  
  15.118      if (session) {
  15.119          if (session->sync_state != DeviceState_state_NONE)
    16.1 --- a/src/pEpEngine.h	Thu Sep 21 15:46:18 2017 +0200
    16.2 +++ b/src/pEpEngine.h	Thu Oct 26 14:09:20 2017 +0200
    16.3 @@ -16,7 +16,7 @@
    16.4  #include "stringpair.h"    
    16.5  #include "timestamp.h"
    16.6  
    16.7 -#define PEP_VERSION "1.0" // protocol version
    16.8 +#define PEP_VERSION "2.0" // protocol version
    16.9  
   16.10  #define PEP_OWN_USERID "pEp_own_userId"
   16.11      
   16.12 @@ -129,6 +129,9 @@
   16.13  //                                            opened
   16.14  //
   16.15  //  caveat:
   16.16 +//      THE CALLER MUST GUARD THIS CALL EXTERNALLY WITH A MUTEX. release() should
   16.17 +//      be similarly guarded.
   16.18 +//
   16.19  //      the pointer is valid only if the return value is PEP_STATUS_OK
   16.20  //      in other case a NULL pointer will be returned; a valid handle must
   16.21  //      be released using release() when it's no longer needed
   16.22 @@ -145,6 +148,9 @@
   16.23  //        session (in)    session handle to release
   16.24  //
   16.25  //    caveat:
   16.26 +//        THE CALLER MUST GUARD THIS CALL EXTERNALLY WITH A MUTEX. init() should
   16.27 +//        be similarly guarded.
   16.28 +//       
   16.29  //        the last release() can be called only when all other release() calls
   16.30  //        are done
   16.31  
   16.32 @@ -856,6 +862,7 @@
   16.33  
   16.34  DYNAMIC_API PEP_STATUS get_trust(PEP_SESSION session, pEp_identity *identity);
   16.35  
   16.36 +
   16.37  PEP_STATUS set_trust(PEP_SESSION session, 
   16.38                              const char* user_id,
   16.39                              const char* fpr, 
    17.1 --- a/src/pEp_internal.h	Thu Sep 21 15:46:18 2017 +0200
    17.2 +++ b/src/pEp_internal.h	Thu Oct 26 14:09:20 2017 +0200
    17.3 @@ -1,7 +1,7 @@
    17.4  // This file is under GNU General Public License 3.0
    17.5  // see LICENSE.txt
    17.6  
    17.7 -#define PEP_ENGINE_VERSION "0.8.0"
    17.8 +#define PEP_ENGINE_VERSION "0.9.0"
    17.9  
   17.10  // maximum attachment size to import as key 1MB, maximum of 20 attachments
   17.11  
   17.12 @@ -37,6 +37,19 @@
   17.13  #define PEP_SUBJ_BYTELEN 5
   17.14  #endif
   17.15  
   17.16 +#ifndef PEP_SUBJ_KEY
   17.17 +#define PEP_SUBJ_KEY "Subject: "
   17.18 +#define PEP_SUBJ_KEY_LC "subject: "
   17.19 +#define PEP_SUBJ_KEY_LEN 9
   17.20 +#endif
   17.21 +
   17.22 +#ifndef PEP_MSG_WRAP_KEY
   17.23 +#define PEP_MSG_WRAP_KEY "pEp-Wrapped-Message-Info: "
   17.24 +#define PEP_MSG_WRAP_KEY_LC "pep-wrapped-message-info: "
   17.25 +#define PEP_MSG_WRAP_KEY_LEN 26
   17.26 +#endif
   17.27 +
   17.28 +
   17.29  #include "platform.h"
   17.30  
   17.31  #ifdef WIN32
   17.32 @@ -61,6 +74,7 @@
   17.33  #include <assert.h>
   17.34  #include <stdio.h>
   17.35  #include <ctype.h>
   17.36 +#include <math.h>
   17.37  
   17.38  #ifdef SQLITE3_FROM_OS
   17.39  #include <sqlite3.h>
   17.40 @@ -173,6 +187,9 @@
   17.41      bool unencrypted_subject;
   17.42      bool keep_sync_msg;
   17.43      bool service_log;
   17.44 +
   17.45 +    // mistrust undo cache
   17.46 +    pEp_identity* cached_mistrusted;
   17.47      
   17.48  #ifdef DEBUG_ERRORSTACK
   17.49      stringlist_t* errorstack;
   17.50 @@ -348,6 +365,17 @@
   17.51      return (char*)retval;
   17.52  }
   17.53  
   17.54 +// These are globals used in generating message IDs and should only be
   17.55 +// computed once, as they're either really constants or OS-dependent
   17.56 +
   17.57 +int _pEp_rand_max_bits;
   17.58 +double _pEp_log2_36;
   17.59 +
   17.60 +static inline void _init_globals() {
   17.61 +    _pEp_rand_max_bits = ceil(log2(RAND_MAX));
   17.62 +    _pEp_log2_36 = log2(36);
   17.63 +}
   17.64 +
   17.65  #ifdef DEBUG_ERRORSTACK
   17.66      PEP_STATUS session_add_error(PEP_SESSION session, const char* file, unsigned line, PEP_STATUS status);
   17.67      #define ADD_TO_LOG(status)   session_add_error(session, __FILE__, __LINE__, (status))
    18.1 --- a/src/pgp_gpg.c	Thu Sep 21 15:46:18 2017 +0200
    18.2 +++ b/src/pgp_gpg.c	Thu Oct 26 14:09:20 2017 +0200
    18.3 @@ -1837,18 +1837,20 @@
    18.4          free_stringlist(_keylist);
    18.5          _keylist = NULL;
    18.6          
    18.7 -        // If match failed, check to see if we've got a dotted address in the pattern.
    18.8 -        // (last chance of the heuristic, really)
    18.9 -        // If so, try again without any dots.
   18.10 -        const char* dotpos = strstr(pattern, ".");
   18.11 -        const char* atpos = strstr(pattern, "@");
   18.12 -        if (dotpos && atpos && (dotpos < atpos)) {
   18.13 -            char* undotted = _undot_address(pattern);
   18.14 -            if (undotted) {
   18.15 -                PEP_STATUS status = _pgp_search_keys(session, undotted,
   18.16 -                                                     keylist, private_only);
   18.17 -                free(undotted);
   18.18 -                return status;
   18.19 +        if (pattern != NULL) {
   18.20 +            // If match failed, check to see if we've got a dotted address in the pattern.
   18.21 +            // (last chance of the heuristic, really)
   18.22 +            // If so, try again without any dots.
   18.23 +            const char* dotpos = strstr(pattern, ".");
   18.24 +            const char* atpos = strstr(pattern, "@");
   18.25 +            if (dotpos && atpos && (dotpos < atpos)) {
   18.26 +                char* undotted = _undot_address(pattern);
   18.27 +                if (undotted) {
   18.28 +                    PEP_STATUS status = _pgp_search_keys(session, undotted,
   18.29 +                                                         keylist, private_only);
   18.30 +                    free(undotted);
   18.31 +                    return status;
   18.32 +                }
   18.33              }
   18.34          }
   18.35      }    
    19.1 --- a/src/platform_unix.c	Thu Sep 21 15:46:18 2017 +0200
    19.2 +++ b/src/platform_unix.c	Thu Oct 26 14:09:20 2017 +0200
    19.3 @@ -297,8 +297,14 @@
    19.4              fd = open(path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
    19.5  
    19.6              if(fd>0) {
    19.7 -                write(fd, gpg_conf_empty, strlen(gpg_conf_empty));
    19.8 +                ssize_t res;
    19.9 +                len = strlen(gpg_conf_empty);
   19.10 +                res = write(fd, gpg_conf_empty, len);
   19.11                  close(fd);
   19.12 +                if(res < len) {
   19.13 +                    assert(0);
   19.14 +                    return false;
   19.15 +                }
   19.16              }
   19.17          }
   19.18  
   19.19 @@ -344,8 +350,14 @@
   19.20              fd = open(agent_path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
   19.21  
   19.22              if(fd>0) {
   19.23 -                write(fd, gpg_conf_empty, strlen(gpg_conf_empty));
   19.24 +                ssize_t res;
   19.25 +                len = strlen(gpg_conf_empty);
   19.26 +                res = write(fd, gpg_conf_empty, len);
   19.27                  close(fd);
   19.28 +                if(res < len) {
   19.29 +                    assert(0);
   19.30 +                    return false;
   19.31 +                }
   19.32              }
   19.33          }
   19.34          done = true;
    20.1 --- a/src/platform_windows.cpp	Thu Sep 21 15:46:18 2017 +0200
    20.2 +++ b/src/platform_windows.cpp	Thu Oct 26 14:09:20 2017 +0200
    20.3 @@ -141,12 +141,12 @@
    20.4  
    20.5  	// Look up GnuPG installation in current user scope
    20.6  	bool result = readRegistryString(HKEY_CURRENT_USER,
    20.7 -		TEXT("SOFTWARE\\GNU\\GnuPG"), TEXT("Install Directory"), path,
    20.8 +		TEXT("SOFTWARE\\GnuPG"), TEXT("Install Directory"), path,
    20.9  		PATH_BUF_SIZE, NULL);
   20.10  	// If not found in current user, look up in local machine
   20.11  	if (!result)
   20.12  		result = readRegistryString(HKEY_LOCAL_MACHINE,
   20.13 -			TEXT("SOFTWARE\\GNU\\GnuPG"), TEXT("Install Directory"), path,
   20.14 +			TEXT("SOFTWARE\\GnuPG"), TEXT("Install Directory"), path,
   20.15  			PATH_BUF_SIZE, NULL);
   20.16  	assert(result);
   20.17  	if (!result)
    21.1 --- a/test/Makefile	Thu Sep 21 15:46:18 2017 +0200
    21.2 +++ b/test/Makefile	Thu Oct 26 14:09:20 2017 +0200
    21.3 @@ -10,8 +10,8 @@
    21.4  TARGET=pEpEngineTest
    21.5  
    21.6  unexport GNUPGHOME
    21.7 -TEST_HOME=$(HERE)/test_home
    21.8 -TEST_GNUPGHOME=$(TEST_HOME)/.gnupg
    21.9 +TEST_HOME=$(HERE)test_home
   21.10 +TEST_GNUPGHOME=$(TEST_HOME)/gnupg
   21.11  
   21.12  LDFLAGS+= $(ETPAN_LIB) -L../asn.1 -L../src
   21.13  LDLIBS+= -letpan -lpEpEngine -lstdc++ -lasn1
   21.14 @@ -51,7 +51,7 @@
   21.15  # Remove trailing ':'
   21.16  EXTRA_LIB_PATHS:=$(EXTRA_LIB_PATHS::=)
   21.17  
   21.18 -TEST_CMD_PFX=$(LIBPATH)=$(EXTRA_LIB_PATHS) HOME=$(TEST_HOME)
   21.19 +TEST_CMD_PFX=$(LIBPATH)=$(EXTRA_LIB_PATHS) HOME=$(TEST_HOME) GNUPGHOME=$(TEST_GNUPGHOME)
   21.20  
   21.21  UNIT_TESTS_SOURCE=$(wildcard *_test.cc)
   21.22  UNIT_TESTS=$(subst .cc,,$(UNIT_TESTS_SOURCE))
   21.23 @@ -79,16 +79,14 @@
   21.24  
   21.25  .PHONY: test_home_
   21.26  test_home_: 
   21.27 -	-gpgconf --kill gpg-agent
   21.28 -	-HOME=$(TEST_HOME) gpgconf --kill gpg-agent
   21.29 -	-killall gpg-agent
   21.30 +	-GNUPGHOME=$(TEST_GNUPGHOME) gpgconf --kill gpg-agent
   21.31  	rm -rf $(TEST_HOME)
   21.32  	mkdir -p $(TEST_GNUPGHOME)/private-keys-v1.d
   21.33  	$(GPG_CMD) --import --batch --homedir $(TEST_GNUPGHOME) 0x*.asc *_sec.asc
   21.34  
   21.35  .PHONY: clean
   21.36  clean:
   21.37 -	rm -f *.o $(TARGET) *.a *~ $(UNIT_TESTS) pep_Dokument_Titel.pdf msg4.asc
   21.38 +	rm -f *.o $(TARGET) *.a *~ $(UNIT_TESTS) pep_Dokument_Titel.pdf msg4.asc msg_encrypt_for_self.asc
   21.39  	rm -Rf *.dSYM $(TEST_HOME) pubring.gpg secring.gpg random_seed *.conf trustdb.gpg
   21.40  
   21.41  .PHONY: test
    22.1 --- a/test/external_revoke_test.cc	Thu Sep 21 15:46:18 2017 +0200
    22.2 +++ b/test/external_revoke_test.cc	Thu Oct 26 14:09:20 2017 +0200
    22.3 @@ -247,6 +247,9 @@
    22.4      
    22.5      // encrypt something to the key
    22.6      cout << "Creating message…\n";
    22.7 +    
    22.8 +    // cout << "First, update identity though!\n";
    22.9 +    // status = update_identity(session, recip1);
   22.10      to_list = new_identity_list(identity_dup(recip1)); // to bob
   22.11      outgoing_msg = new_message(PEP_dir_outgoing);
   22.12      assert(outgoing_msg);
   22.13 @@ -258,8 +261,8 @@
   22.14      cout << "Message created.\n";
   22.15  
   22.16      status = encrypt_message(session, outgoing_msg, NULL, &encrypted_outgoing_msg, PEP_enc_PGP_MIME, 0);
   22.17 -
   22.18      ct = (encrypted_outgoing_msg ? encrypted_outgoing_msg->to->ident->comm_type : outgoing_msg->to->ident->comm_type);
   22.19 +    
   22.20  
   22.21      // CHECK STATUS???
   22.22      cout << "Encryption returns with status " << tl_status_string(status) << endl;
   22.23 @@ -285,11 +288,13 @@
   22.24      status = decrypt_message(session, encrypted_outgoing_msg, &decrypted_msg, &keylist, &rating, &flags);
   22.25      cout << "Decryption returns with status " << tl_status_string(status) << endl;
   22.26      assert(status == PEP_STATUS_OK);
   22.27 -
   22.28 +    assert(decrypted_msg);
   22.29 +    
   22.30      // check rating
   22.31      cout << "Rating of decrypted message to trusted recip: " << tl_rating_string(rating) << endl;
   22.32      assert(rating == PEP_rating_reliable);
   22.33  
   22.34 +    status = update_identity(session, decrypted_msg->to->ident);
   22.35      ct = (decrypted_msg ? decrypted_msg->to->ident->comm_type : outgoing_msg->to->ident->comm_type);
   22.36  
   22.37      cout << "comm_type: " << tl_ct_string(ct) << endl;
    23.1 --- a/test/mime_test.cc	Thu Sep 21 15:46:18 2017 +0200
    23.2 +++ b/test/mime_test.cc	Thu Oct 26 14:09:20 2017 +0200
    23.3 @@ -102,4 +102,3 @@
    23.4      release(session);
    23.5      return 0;
    23.6  }
    23.7 -
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/test/mistrust_undo_test.cc	Thu Oct 26 14:09:20 2017 +0200
    24.3 @@ -0,0 +1,75 @@
    24.4 +// This file is under GNU General Public License 3.0
    24.5 +// see LICENSE.txt
    24.6 +
    24.7 +#include <stdlib.h>
    24.8 +#include <string.h>
    24.9 +#include <time.h>
   24.10 +#include "platform.h"
   24.11 +#include <iostream>
   24.12 +#include <fstream>
   24.13 +#include <assert.h>
   24.14 +#include "mime.h"
   24.15 +#include "message_api.h"
   24.16 +#include "test_util.h"
   24.17 +
   24.18 +using namespace std;
   24.19 +
   24.20 +int main() {
   24.21 +    cout << "\n*** mistrust_undo_test ***\n\n";
   24.22 +
   24.23 +    PEP_SESSION session;
   24.24 +    
   24.25 +    cout << "calling init()\n";
   24.26 +    PEP_STATUS status = init(&session);   
   24.27 +    assert(status == PEP_STATUS_OK);
   24.28 +    assert(session);
   24.29 +    cout << "init() completed.\n";
   24.30 +
   24.31 +    cout << "importing key 0x39E5DAB5." << endl;
   24.32 +    const string pub_key = slurp("test_keys/pub/mistrust.undo.test-0x39E5DAB5_pub.asc");
   24.33 +
   24.34 +    assert(pub_key.length() != 0);
   24.35 +    
   24.36 +    PEP_STATUS statuspub = import_key(session, pub_key.c_str(), pub_key.length(), NULL);
   24.37 +    assert(statuspub == PEP_STATUS_OK);
   24.38 +    cout << "Key imported." << endl << endl;
   24.39 +    
   24.40 +    cout << "Setting up identity for mistrust.undo.test@pep-project.org and making comm_type PEP_ct_pEp."  << endl;
   24.41 +    pEp_identity* recip1 = new_identity("mistrust.undo.test@pep-project.org", NULL, "TOFU_mistrust.undo.test@pep-project.org", "Mistrust Undo");
   24.42 +    status = update_identity(session,recip1);
   24.43 +    assert(status == PEP_STATUS_OK);
   24.44 +    assert(strcmp(recip1->fpr, "BACC7A60A88A39A25D99B4A545D7542F39E5DAB5") == 0);
   24.45 +    
   24.46 +    // This is not an external function. We use it to expedite the test since we don't do a sync exchange here.
   24.47 +    status = update_trust_for_fpr(session, recip1->fpr, PEP_ct_pEp);
   24.48 +    status = update_identity(session,recip1);
   24.49 +    assert(status == PEP_STATUS_OK);
   24.50 +    assert(recip1->comm_type == PEP_ct_pEp);
   24.51 +    assert(strcmp(recip1->fpr, "BACC7A60A88A39A25D99B4A545D7542F39E5DAB5") == 0);
   24.52 +    cout << "mistrust.undo.test@pep-project.org set up and comm_type is PEP_ct_pEp."  << endl << endl;
   24.53 +
   24.54 +    // Ok, mistrust away
   24.55 +    cout << "Mistrusting mistrust.undo.test@pep-project.org (BACC7A60A88A39A25D99B4A545D7542F39E5DAB5)."  << endl;   
   24.56 +    status = key_mistrusted(session, recip1);
   24.57 +    assert(status == PEP_STATUS_OK);
   24.58 +    status = update_identity(session,recip1);
   24.59 +    assert(status == PEP_STATUS_OK);
   24.60 +    assert(recip1->comm_type == PEP_ct_mistrusted);
   24.61 +    cout << "Mistrusted mistrust.undo.test@pep-project.org (BACC7A60A88A39A25D99B4A545D7542F39E5DAB5) and comm_type set to PEP_ct_mistrusted)." << endl  << endl;    
   24.62 +    
   24.63 +    cout << "Undo mistrust (restore identity and trust in DB)" << endl;
   24.64 +    // Undo it
   24.65 +    status = undo_last_mistrust(session);
   24.66 +    assert(status == PEP_STATUS_OK);
   24.67 +    status = update_identity(session, recip1);
   24.68 +    assert(recip1->comm_type == PEP_ct_pEp);
   24.69 +    assert(strcmp(recip1->fpr, "BACC7A60A88A39A25D99B4A545D7542F39E5DAB5") == 0);
   24.70 +    cout << "Undo mistrust (restore identity and trust in DB) - trust is now PEP_ct_pEp." << endl << endl;
   24.71 +
   24.72 +    cout << "Success!!!" << endl << endl;
   24.73 +    
   24.74 +    free_identity(recip1);
   24.75 +    release(session);
   24.76 +
   24.77 +    return 0;
   24.78 +}
    25.1 --- a/test/pEpEngineTest.cc	Thu Sep 21 15:46:18 2017 +0200
    25.2 +++ b/test/pEpEngineTest.cc	Thu Oct 26 14:09:20 2017 +0200
    25.3 @@ -9,15 +9,29 @@
    25.4  
    25.5  #include <assert.h>
    25.6  #include <string.h>
    25.7 +#include <sstream>
    25.8 +
    25.9  
   25.10  #include "../src/pEpEngine.h"
   25.11  #include "../src/keymanagement.h"
   25.12  
   25.13 -
   25.14  using namespace std;
   25.15  
   25.16  typedef std::string Buffer;
   25.17  
   25.18 +std::string slurp(const std::string& filename)
   25.19 +{
   25.20 +        std::ifstream input(filename.c_str());
   25.21 +        if(!input)
   25.22 +        {
   25.23 +                throw std::runtime_error("Cannot read file \"" + filename + "\"! ");
   25.24 +        }
   25.25 +
   25.26 +        std::stringstream sstr;
   25.27 +        sstr << input.rdbuf();
   25.28 +        return sstr.str();
   25.29 +}
   25.30 +
   25.31  // no C++11, yet? So do our own implementation:
   25.32  namespace{
   25.33      std::string to_string(unsigned long u)
   25.34 @@ -96,6 +110,35 @@
   25.35      cout << "dropping second session\n";
   25.36      release(second_session);
   25.37  
   25.38 +    cout << "Importing keys...";
   25.39 +    string pub_key = slurp("test_keys/pub/pep-test-alice-0x6FF00E97_pub.asc");
   25.40 +    string priv_key = slurp("test_keys/priv/pep-test-alice-0x6FF00E97_priv.asc");
   25.41 +
   25.42 +    PEP_STATUS statuspub = import_key(session, pub_key.c_str(), pub_key.length(), NULL);
   25.43 +    PEP_STATUS statuspriv = import_key(session, priv_key.c_str(), priv_key.length(), NULL);
   25.44 +    assert(statuspub == PEP_STATUS_OK);
   25.45 +    assert(statuspriv == PEP_STATUS_OK);
   25.46 +
   25.47 +    pub_key = slurp("test_keys/pub/pep-test-john-0x70DCF575_pub.asc");
   25.48 +    priv_key = slurp("test_keys/priv/pep-test-john-0x70DCF575_priv.asc");
   25.49 +
   25.50 +    statuspub = import_key(session, pub_key.c_str(), pub_key.length(), NULL);
   25.51 +    statuspriv = import_key(session, priv_key.c_str(), priv_key.length(), NULL);
   25.52 +    assert(statuspub == PEP_STATUS_OK);
   25.53 +    assert(statuspriv == PEP_STATUS_OK);
   25.54 +
   25.55 +    pub_key = slurp("test_keys/pub/pep-test-bob-0xC9C2EE39_pub.asc");
   25.56 +
   25.57 +    statuspub = import_key(session, pub_key.c_str(), pub_key.length(), NULL);
   25.58 +    assert(statuspub == PEP_STATUS_OK);
   25.59 +    assert(statuspriv == PEP_STATUS_OK);
   25.60 +
   25.61 +
   25.62 +    cout << "creating message…\n";
   25.63 +    pEp_identity* alice = new_identity("pep.test.alice@pep-project.org", "4ABE3AAF59AC32CFE4F86500A9411D176FF00E97", PEP_OWN_USERID, "Alice Test");
   25.64 +    pEp_identity* bob = new_identity("pep.test.bob@pep-project.org", NULL, "42", "Bob Test");
   25.65 +
   25.66 +
   25.67      cout << "logging test\n";
   25.68      log_event(session, "log test", "pEp Engine Test", "This is a logging test sample.", "please ignore this line");
   25.69  
    26.1 --- a/test/revoke_regen_attach_test.cc	Thu Sep 21 15:46:18 2017 +0200
    26.2 +++ b/test/revoke_regen_attach_test.cc	Thu Oct 26 14:09:20 2017 +0200
    26.3 @@ -61,7 +61,6 @@
    26.4      message *enc_msg;
    26.5      cout << "calling encrypt_message()\n";
    26.6      status = encrypt_message(session, msg, NULL, &enc_msg, PEP_enc_PGP_MIME, 0);
    26.7 -    cout << status;
    26.8      assert(status == PEP_STATUS_OK);
    26.9      assert(enc_msg);
   26.10      cout << "message encrypted.\n";
   26.11 @@ -71,7 +70,7 @@
   26.12      assert(strcmp(msg->attachments->filename, "file://pEpkey.asc") == 0);
   26.13      assert(strcmp(msg->attachments->next->filename, "file://pEpkey.asc") == 0);
   26.14  
   26.15 -    cout << "message contains 2 key attachements.\n";
   26.16 +    cout << "message contains 2 key attachments.\n";
   26.17  
   26.18      free_message(msg);
   26.19      free_message(enc_msg);
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/test/test_keys/priv/mistrust.undo.test-0x39E5DAB5_priv.asc	Thu Oct 26 14:09:20 2017 +0200
    27.3 @@ -0,0 +1,57 @@
    27.4 +-----BEGIN PGP PRIVATE KEY BLOCK-----
    27.5 +
    27.6 +lQOYBFnTjWIBCAC78lI82/kYpsd/bQ7iUkQyKlOhT4e2MdnaaiTOSJf6N0liSjnt
    27.7 +Ah49e5+qus4Z3zAHgDWOZxSa7fOSPlVSAj35yM2X2Xn1nDJ5CxTYNCqluK5f811a
    27.8 +cUmvC166ZTsjdjmgNDAwzNpwmjbAEhKyibxnTd2vpJlW3+nVCCXg9JHMfuSj71t8
    27.9 +0OpZNZ3uqVqAekcY7SvMcaCQ41A44IkN/gAOK3Z/Cml62mRpsaKss85ZBJKXP7n+
   27.10 +61mKvT7EK1zc5dD2pdxROnjxDYaAGuJKtLwzoSm2/syvMY2VpTrh2rSQVI7gR+ep
   27.11 +WcGkT4kTFFP5mSrOYL5bKnUjfaybk/26G8TFABEBAAEAB/4lOJlGyj2rvyPVPZDs
   27.12 +C2TMFovXb3ut/nNpiQne/It0l0xmNdMA+CFrBbeaRUKZ5xSI98AjgpCXGjbZqJSX
   27.13 +GDCT7kuhHgXEOXnZdPNc2f/0L/4ArJ65UaRJEVRiT7gFjt1ct9kvYPKFyFS9dxbS
   27.14 +2uo//zC/Hzbq+I9DjEiMI4NYXxW9jh93UB0CpJ+mbEb1F58Yh9GfXTwZbResO2ET
   27.15 +Ws6Puhm71/EHOAHZoKjNTND2oz1Aoy4IyXrJ1M0sFJNvfHLfOfvg5GL1Q0CC1pFY
   27.16 +X0Ap60Odj/8cRR3S5l327ZZZwl+2xheCP4M9ypHBlGC0z+4iNRXJQ71fFZRIRDSQ
   27.17 +vb8FBADHjrH66y+tMkRnbvm+bjmncFkHjx6H1nojBVj6SfMsTCqCd9ZAhbhH7F2c
   27.18 +/2jO3Od8uYdHvg0ze4eR8XlbkwFNwXNxOZvvqmUO+rlJP7Ks8zN8XBxwOazE7d48
   27.19 +urzL7BV6kw2xjaWbuxXi25rG+VpYsSNW+5aErjxUZvIapGVTBwQA8RrsSm4EKz9U
   27.20 +GqW3Mio5wYWcAiwbs7UpEjFHqj8uvx2mHUXBaETbjnuVGnyZ/POAARlWj80EgDZj
   27.21 +1F9QXDdBbRBf8IxmnwTapk4St53cykDQgSMIdHpTsEGaM62qCyHgBOn1n/YMwlZh
   27.22 +6k01TK07yMgvVzFQeFdfxY83QvIBetMD/0+uk1tum1ZTw5iA+vJaxggVQDJeC0SD
   27.23 +lVZnAqXrG52Cu9yvCN2+PzNB2Zxcxds426EGokV/JdDMDe7FuLLjFckNKVwrN/qg
   27.24 +wRi0eS00JOhuPXye0cmEyhIb0NenGDNT92n2ePUo5cIG5654pK2s9OwtaLj83rUg
   27.25 +/PVeg+dAPxsHPeC0P01pc3RydXN0IFVuZG8gKERPIE5PVCBVU0UpIDxtaXN0cnVz
   27.26 +dC51bmRvLnRlc3RAcGVwLXByb2plY3Qub3JnPokBOAQTAQgAIgUCWdONYgIbAwYL
   27.27 +CQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQRddULznl2rUL3ggAlg6bnLr+Cw7e
   27.28 +/yYDk3Mdo0M5hN8cmeMC95CY4iwiiDjbCK2AsSCjhTGWM59hJ3pSA8x+GGBBeFCi
   27.29 +Gu0GLciEKuBPoJ1C4OFTUq5goDxvyysGHZ6OwRyfnHLl4mSEW86op0fkSHle25V9
   27.30 +lO/WjuWNwjoi9hLoW8IoN51dY0PZK69EeKuaX588nGJrOJeuZr3zLlziu9Km24Y5
   27.31 +El6M3GIZkaQcbiW2nbM/WkkRNDgRJbCp1wZIHledC6hgTjObaae1iXHzByM/62t1
   27.32 +u/GzixLaccfC5GAFGBtFI338pWaLarfSRVVbT6YBEMDJhrIcKtDWBi22yjRGxg/7
   27.33 +2Gz+mj0lLZ0DmARZ041iAQgAz34Vh5+c8qRa11f5nbWDssmC/2jxZdsX0cqSSozX
   27.34 +xuJ4l5lor/2dfqq2WCNWzdj+n8JGJrFVmpEL9rVTAARkUbNHzWv5pAe353JWkuTM
   27.35 +LIVFzdNIXymHyKck7S4QSohpoT/UA6gTtQD6kLbSFqycfkRlRWw0qYpPJEYiIdCz
   27.36 +lwEMffpu6ltzCXi3He6K7+S/XA5DXTIdArx3UMB/rJ69WCeEh77S7i5l223MmZLj
   27.37 +FIM9VRLP7SyIaOxnn1LlLCjbgT7gAX7S9aYeAWi8aZqtBcQ/wrSlvKPNYElEvFsG
   27.38 +kxrUCKYg6T1cWfU1ch4uCDqrrKdNQFpRF4NgUuFIOcnt8QARAQABAAf/YE0jjvO8
   27.39 +sz0m0EWLm+/P9R3jx8kcKOr77im3phQiXbNkxu+zj+MEwvJWeSfFtPpeiyVuy6yI
   27.40 +j5l8VP+pSxu+t9Cepa/UiJXwe+IsXjcEsDEWycWjFE/BLpas48v6Ua1oYSevrhbH
   27.41 +Nr4CjUHc1hs88rmpywPCmWGRA8PtOYaUo6NJMmTJYeDW4xqTvHu5R38iWUwAXwwP
   27.42 +JZIV7qm6ruzdfhLWYlRFGaiijPjSO6tkuP0EuYnqcD8ETgXg+zyNRdTCcBw1T6Z/
   27.43 +lVvx+LwG0f4ZmNdzN4InUEd63kPkxSXYNSEwlFPMX7iWkIjYg6DT0kLxqoMGrZQg
   27.44 +I27EQXlBLS3wNQQA0upHKHsDnCDIiZw7zxxbISTWgoclpSn1kXgS9MpriNBMITEf
   27.45 +DS3rVKnw9YteKFGnhBoI5UebdoDL1O/SjXH+a93u6mnTitYkW1W5EVybZMC3GzYc
   27.46 +HQbb98uhWi+wmz/3mS7yHc2p9LnBuMJr25Mb3ruSbd6DjFhRUoLrkURP9MMEAPvY
   27.47 +gzHGj1JvphioqXgj5LN2nXwD599Lku5bgSKMjyAA9P7A0xEE3agm9s7alU/t5Kws
   27.48 +E9bzfWNNB34Dl82cm3chLGFBa4JU68UbDSKsERpo2H1XjYs0wn9BoXPAnVh9O5sn
   27.49 +gC2qMOw3Qz32tfiUHqQpIxHB4SgdLFms3ibgNRc7A/4/xxamL2OJW9ujcBXwnX5a
   27.50 +n4mhQ2rRBnJw8vTYukJyJCZ4lN3ODUp9fKDHR5b9nddn+N89mO+AWVEm5ChjNGyT
   27.51 +hy+8AttETE9+2NtkCJVTIC49V9PBqMrYpnXz2SG4hW/koPB/rRz0ubFBAIi2M1aI
   27.52 +kB5KjFUNK/4BuGnpT69pAEeniQEfBBgBCAAJBQJZ041iAhsMAAoJEEXXVC855dq1
   27.53 +RHAH/iogJhtuUKPaec9Mu+W9g3+lcfh+QAHvqeIuzo6ff0OJn1hQXkG8lfclhHhD
   27.54 +w0dngLaxeTV3ZOYy08ScRWxWIz01BKeWXXM47MO2+qOpZsdZLwwpFb1FG7wOdsfr
   27.55 +QWGWxfJ7bew7HZOL8jG3xvWeCbXSt1BJGjA0hN1Oa9x02lwL5M/ALyYOGD0Z/F/8
   27.56 +FG8gyQnykuAnoT8zifzsv7keQDiJ+xQSrvWPAcsDsJ9XZxPd+jZ2b1q/xvMWD2WD
   27.57 +UU4FB91uKruSXnEOMo+/mr6NoSqKrkfvoQOep8Uz/2rr7Z5qwvRfV4aMtrz4aGh4
   27.58 +u/rtL+cuYZ38+YOc2vW35FVeMhU=
   27.59 +=pD3o
   27.60 +-----END PGP PRIVATE KEY BLOCK-----
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/test/test_keys/pub/mistrust.undo.test-0x39E5DAB5_pub.asc	Thu Oct 26 14:09:20 2017 +0200
    28.3 @@ -0,0 +1,30 @@
    28.4 +-----BEGIN PGP PUBLIC KEY BLOCK-----
    28.5 +
    28.6 +mQENBFnTjWIBCAC78lI82/kYpsd/bQ7iUkQyKlOhT4e2MdnaaiTOSJf6N0liSjnt
    28.7 +Ah49e5+qus4Z3zAHgDWOZxSa7fOSPlVSAj35yM2X2Xn1nDJ5CxTYNCqluK5f811a
    28.8 +cUmvC166ZTsjdjmgNDAwzNpwmjbAEhKyibxnTd2vpJlW3+nVCCXg9JHMfuSj71t8
    28.9 +0OpZNZ3uqVqAekcY7SvMcaCQ41A44IkN/gAOK3Z/Cml62mRpsaKss85ZBJKXP7n+
   28.10 +61mKvT7EK1zc5dD2pdxROnjxDYaAGuJKtLwzoSm2/syvMY2VpTrh2rSQVI7gR+ep
   28.11 +WcGkT4kTFFP5mSrOYL5bKnUjfaybk/26G8TFABEBAAG0P01pc3RydXN0IFVuZG8g
   28.12 +KERPIE5PVCBVU0UpIDxtaXN0cnVzdC51bmRvLnRlc3RAcGVwLXByb2plY3Qub3Jn
   28.13 +PokBOAQTAQgAIgUCWdONYgIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQ
   28.14 +RddULznl2rUL3ggAlg6bnLr+Cw7e/yYDk3Mdo0M5hN8cmeMC95CY4iwiiDjbCK2A
   28.15 +sSCjhTGWM59hJ3pSA8x+GGBBeFCiGu0GLciEKuBPoJ1C4OFTUq5goDxvyysGHZ6O
   28.16 +wRyfnHLl4mSEW86op0fkSHle25V9lO/WjuWNwjoi9hLoW8IoN51dY0PZK69EeKua
   28.17 +X588nGJrOJeuZr3zLlziu9Km24Y5El6M3GIZkaQcbiW2nbM/WkkRNDgRJbCp1wZI
   28.18 +HledC6hgTjObaae1iXHzByM/62t1u/GzixLaccfC5GAFGBtFI338pWaLarfSRVVb
   28.19 +T6YBEMDJhrIcKtDWBi22yjRGxg/72Gz+mj0lLbkBDQRZ041iAQgAz34Vh5+c8qRa
   28.20 +11f5nbWDssmC/2jxZdsX0cqSSozXxuJ4l5lor/2dfqq2WCNWzdj+n8JGJrFVmpEL
   28.21 +9rVTAARkUbNHzWv5pAe353JWkuTMLIVFzdNIXymHyKck7S4QSohpoT/UA6gTtQD6
   28.22 +kLbSFqycfkRlRWw0qYpPJEYiIdCzlwEMffpu6ltzCXi3He6K7+S/XA5DXTIdArx3
   28.23 +UMB/rJ69WCeEh77S7i5l223MmZLjFIM9VRLP7SyIaOxnn1LlLCjbgT7gAX7S9aYe
   28.24 +AWi8aZqtBcQ/wrSlvKPNYElEvFsGkxrUCKYg6T1cWfU1ch4uCDqrrKdNQFpRF4Ng
   28.25 +UuFIOcnt8QARAQABiQEfBBgBCAAJBQJZ041iAhsMAAoJEEXXVC855dq1RHAH/iog
   28.26 +JhtuUKPaec9Mu+W9g3+lcfh+QAHvqeIuzo6ff0OJn1hQXkG8lfclhHhDw0dngLax
   28.27 +eTV3ZOYy08ScRWxWIz01BKeWXXM47MO2+qOpZsdZLwwpFb1FG7wOdsfrQWGWxfJ7
   28.28 +bew7HZOL8jG3xvWeCbXSt1BJGjA0hN1Oa9x02lwL5M/ALyYOGD0Z/F/8FG8gyQny
   28.29 +kuAnoT8zifzsv7keQDiJ+xQSrvWPAcsDsJ9XZxPd+jZ2b1q/xvMWD2WDUU4FB91u
   28.30 +KruSXnEOMo+/mr6NoSqKrkfvoQOep8Uz/2rr7Z5qwvRfV4aMtrz4aGh4u/rtL+cu
   28.31 +YZ38+YOc2vW35FVeMhU=
   28.32 +=cCkg
   28.33 +-----END PGP PUBLIC KEY BLOCK-----