merge 'default' into 'pEpMIME'. pEpMIME
authorRoker <roker@pep-project.org>
Mon, 08 Jun 2020 15:01:34 +0200
branchpEpMIME
changeset 4730a47eadde1552
parent 4577 ffae0defc0a4
parent 4729 3df9a2a67597
merge 'default' into 'pEpMIME'.
Makefile.conf
     1.1 --- a/.hgignore	Thu Apr 16 20:35:53 2020 +0200
     1.2 +++ b/.hgignore	Mon Jun 08 15:01:34 2020 +0200
     1.3 @@ -88,3 +88,16 @@
     1.4  test/EngineTests
     1.5  test/googletest
     1.6  test/tmp/*
     1.7 +
     1.8 +# ignore generated test data
     1.9 +
    1.10 +test/655_16F07F382FB3CF5DF977005D1069C7CACF9C23C6.asc
    1.11 +test/655_5FBDE3C9E10552B1DD6D9763E89759391DE04053.asc
    1.12 +test/655_EB4308E2D5B9FEEF7488D14CFEE4AE51914D566D.asc
    1.13 +test/655_ECBA9555D9ADB1B68861B508032CCA777FFDBA14.asc
    1.14 +test/655_decrypted_only.eml
    1.15 +test/703_key_valid.asc
    1.16 +test/test_keys/736_a.asc
    1.17 +test/test_keys/736_b.asc
    1.18 +test/test_mails/ENGINE-654_bob_mail.eml
    1.19 +
     2.1 --- a/.hgtags	Thu Apr 16 20:35:53 2020 +0200
     2.2 +++ b/.hgtags	Mon Jun 08 15:01:34 2020 +0200
     2.3 @@ -27,12 +27,13 @@
     2.4  0000000000000000000000000000000000000000 2.0.0-RC
     2.5  0000000000000000000000000000000000000000 2.0.0-RC
     2.6  c4eb9bb2008fbe531f892fd56f8edce53048eb62 2.0.0-RC
     2.7 -c71ec33fb34612be1d35629de5169f3489975b05 2.0.1_target
     2.8 -c71ec33fb34612be1d35629de5169f3489975b05 2.0.1_target
     2.9 -73516323c7532d71760515d23dd4b36a510f9117 2.0.1_target
    2.10 -0000000000000000000000000000000000000000 2.0.1_target
    2.11 -a0785e8bca3935e0ab7cd82a5826a0fca8d23ccb 2.0.1_target
    2.12 -0000000000000000000000000000000000000000 2.0.1_target
    2.13 -a0785e8bca3935e0ab7cd82a5826a0fca8d23ccb 2.0.1_target
    2.14 -0000000000000000000000000000000000000000 2.0.1_target
    2.15 -f7633443ef921ed222519347720b0a7276b3ef6a 2.0.1_target
    2.16 +c71ec33fb34612be1d35629de5169f3489975b05 Release_2.0.0
    2.17 +b5ce496201c0e534c81d18f8447101e39762ec36 Release_2.0.1
    2.18 +f7633443ef921ed222519347720b0a7276b3ef6a 2.1.0_target
    2.19 +f089504579b7808e60281ba06c9a4eee750939c6 Release_2.0.3
    2.20 +f0e7ec9616c5aa50b42cef70eff8930feb60f7bd decode-encode-API-change
    2.21 +29ddc8a400abbe9b4e05fc5172e5db9ba99f3515 last-old-mime-api-version
    2.22 +c173428cd2c31fcc8867dc1ac785a6637c001210 Restarting default from postrelease
    2.23 +17e8531e1103d93fd8237525c9ecdc7bc4e329e1 Release_2.0.2
    2.24 +e236798013a6453b5162376fdacacd30c1ad15ea Release_2.1.0-RC0
    2.25 +b4d7c37ac8086c6c2b2ff2eb04cd6c203bdcd368 Release_2.1.0-RC1
     3.1 --- a/Makefile.conf	Thu Apr 16 20:35:53 2020 +0200
     3.2 +++ b/Makefile.conf	Mon Jun 08 15:01:34 2020 +0200
     3.3 @@ -273,11 +273,22 @@
     3.4  
     3.5  ######### Post processing assignments ########
     3.6  # These variables are ineffective when set anywhere else but here.
     3.7 +# KB: I have no idea why we do this - it totally defeats the purpose of
     3.8 +#     local.conf.
     3.9 +#     For now: set if has no value.
    3.10  ifeq ($(OPENPGP),SEQUOIA)
    3.11 +ifeq ($(SEQUOIA_CFLAGS),)
    3.12      SEQUOIA_CFLAGS=$(shell pkg-config --cflags-only-other sequoia-openpgp)
    3.13 +endif
    3.14 +ifeq ($(SEQUOIA_LDFLAGS),)
    3.15      SEQUOIA_LDFLAGS=$(shell pkg-config --libs-only-l --libs-only-other sequoia-openpgp)
    3.16 +endif
    3.17 +ifeq ($(SEQUOIA_LIB),)
    3.18      SEQUOIA_LIB=$(shell pkg-config --libs-only-L sequoia-openpgp)
    3.19 +endif
    3.20 +ifeq ($(SEQUOIA_INC),)
    3.21      SEQUOIA_INC=$(shell pkg-config --cflags-only-I sequoia-openpgp)
    3.22 +endif
    3.23      CFLAGS+= $(SEQUOIA_CFLAGS)
    3.24      LD_FLAGS+= $(SEQUOIA_LDFLAGS)
    3.25  endif
     4.1 --- a/build-mac/pEpEngine.xcodeproj/project.pbxproj	Thu Apr 16 20:35:53 2020 +0200
     4.2 +++ b/build-mac/pEpEngine.xcodeproj/project.pbxproj	Mon Jun 08 15:01:34 2020 +0200
     4.3 @@ -173,6 +173,8 @@
     4.4  		4378C79223D1AF1700D1AF3F /* ElectGroupKeyResetLeader.c in Sources */ = {isa = PBXBuildFile; fileRef = 4378C79023D1AF1700D1AF3F /* ElectGroupKeyResetLeader.c */; };
     4.5  		438C43B52167752C00C7425B /* labeled_int_list.h in Headers */ = {isa = PBXBuildFile; fileRef = 438C43AF2167752C00C7425B /* labeled_int_list.h */; };
     4.6  		438C43B62167752C00C7425B /* labeled_int_list.c in Sources */ = {isa = PBXBuildFile; fileRef = 438C43B42167752C00C7425B /* labeled_int_list.c */; };
     4.7 +		43C3778E246A8C0300962D22 /* internal_format.h in Headers */ = {isa = PBXBuildFile; fileRef = 43C37788246A8C0300962D22 /* internal_format.h */; };
     4.8 +		43C3778F246A8C0300962D22 /* internal_format.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C3778D246A8C0300962D22 /* internal_format.c */; };
     4.9  		43E4FBB22362C05600BC01F4 /* NegotiationRequestGrouped.c in Sources */ = {isa = PBXBuildFile; fileRef = 43E4FBAD2362C05600BC01F4 /* NegotiationRequestGrouped.c */; };
    4.10  		43E4FBB42362C29100BC01F4 /* GroupHandshake.c in Sources */ = {isa = PBXBuildFile; fileRef = 43E4FBB32362C29100BC01F4 /* GroupHandshake.c */; };
    4.11  		43F6921D1F164A47009418F5 /* resource_id.c in Sources */ = {isa = PBXBuildFile; fileRef = 43F6921C1F164A47009418F5 /* resource_id.c */; };
    4.12 @@ -426,6 +428,8 @@
    4.13  		438C43962167582400C7425B /* sync_api.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sync_api.h; path = ../src/sync_api.h; sourceTree = "<group>"; };
    4.14  		438C43AF2167752C00C7425B /* labeled_int_list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = labeled_int_list.h; path = ../src/labeled_int_list.h; sourceTree = "<group>"; };
    4.15  		438C43B42167752C00C7425B /* labeled_int_list.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = labeled_int_list.c; path = ../src/labeled_int_list.c; sourceTree = "<group>"; };
    4.16 +		43C37788246A8C0300962D22 /* internal_format.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = internal_format.h; path = ../src/internal_format.h; sourceTree = "<group>"; };
    4.17 +		43C3778D246A8C0300962D22 /* internal_format.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = internal_format.c; path = ../src/internal_format.c; sourceTree = "<group>"; };
    4.18  		43D47A8A225CC60600E97C5B /* pEpTrustWords-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "pEpTrustWords-Info.plist"; path = "/Users/dirk/projects/pEp/pEpEngine/build-mac/pEpTrustWords-Info.plist"; sourceTree = "<absolute>"; };
    4.19  		43E4FBAD2362C05600BC01F4 /* NegotiationRequestGrouped.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = NegotiationRequestGrouped.c; path = ../asn.1/NegotiationRequestGrouped.c; sourceTree = "<group>"; };
    4.20  		43E4FBB32362C29100BC01F4 /* GroupHandshake.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = GroupHandshake.c; path = ../asn.1/GroupHandshake.c; sourceTree = "<group>"; };
    4.21 @@ -728,6 +732,8 @@
    4.22  		64A8264B1B455C5600EECAF0 /* srcref */ = {
    4.23  			isa = PBXGroup;
    4.24  			children = (
    4.25 +				43C3778D246A8C0300962D22 /* internal_format.c */,
    4.26 +				43C37788246A8C0300962D22 /* internal_format.h */,
    4.27  				43188ABE23C4BBDD008EF79C /* distribution_codec.c */,
    4.28  				43188ABF23C4BBDE008EF79C /* distribution_codec.h */,
    4.29  				43188AA223C4B4B3008EF79C /* keyreset_command.c */,
    4.30 @@ -820,6 +826,7 @@
    4.31  				159EF42822B6D3E900149C0C /* pgp_sequoia.h in Headers */,
    4.32  				15B037E222B2B822002D664C /* per_encoder.h in Headers */,
    4.33  				15B0380F22B2B823002D664C /* Sync.h in Headers */,
    4.34 +				43C3778E246A8C0300962D22 /* internal_format.h in Headers */,
    4.35  				15B0380422B2B822002D664C /* constr_SET_OF.h in Headers */,
    4.36  				15B0381322B2B823002D664C /* asn_application.h in Headers */,
    4.37  				15B0380322B2B822002D664C /* OwnKeysRequester.h in Headers */,
    4.38 @@ -1172,6 +1179,7 @@
    4.39  				64A826811B455D0800EECAF0 /* pEpEngine.c in Sources */,
    4.40  				15B037FF22B2B822002D664C /* per_opentype.c in Sources */,
    4.41  				43188A9823C4B2DE008EF79C /* KeySync_fsm.c in Sources */,
    4.42 +				43C3778F246A8C0300962D22 /* internal_format.c in Sources */,
    4.43  			);
    4.44  			runOnlyForDeploymentPostprocessing = 0;
    4.45  		};
     5.1 --- a/build-windows/pEpEngine.vcxproj	Thu Apr 16 20:35:53 2020 +0200
     5.2 +++ b/build-windows/pEpEngine.vcxproj	Mon Jun 08 15:01:34 2020 +0200
     5.3 @@ -139,6 +139,7 @@
     5.4      <ClCompile Include="..\src\etpan_mime.c" />
     5.5      <ClCompile Include="..\src\growing_buf.c" />
     5.6      <ClCompile Include="..\src\identity_list.c" />
     5.7 +    <ClCompile Include="..\src\internal_format.c" />
     5.8      <ClCompile Include="..\src\keymanagement.c" />
     5.9      <ClCompile Include="..\src\keyreset_command.c" />
    5.10      <ClCompile Include="..\src\KeySync_fsm.c" />
    5.11 @@ -180,6 +181,7 @@
    5.12      <ClInclude Include="..\src\fsm_common.h" />
    5.13      <ClInclude Include="..\src\growing_buf.h" />
    5.14      <ClInclude Include="..\src\identity_list.h" />
    5.15 +    <ClInclude Include="..\src\internal_format.h" />
    5.16      <ClInclude Include="..\src\keymanagement.h" />
    5.17      <ClInclude Include="..\src\KeySync_fsm.h" />
    5.18      <ClInclude Include="..\src\key_reset.h" />
     6.1 --- a/build-windows/pEpEngine.vcxproj.filters	Thu Apr 16 20:35:53 2020 +0200
     6.2 +++ b/build-windows/pEpEngine.vcxproj.filters	Mon Jun 08 15:01:34 2020 +0200
     6.3 @@ -126,6 +126,9 @@
     6.4      <ClCompile Include="..\src\distribution_codec.c">
     6.5        <Filter>Quelldateien</Filter>
     6.6      </ClCompile>
     6.7 +    <ClCompile Include="..\src\internal_format.c">
     6.8 +      <Filter>Quelldateien</Filter>
     6.9 +    </ClCompile>
    6.10    </ItemGroup>
    6.11    <ItemGroup>
    6.12      <ClInclude Include="..\src\keymanagement.h">
    6.13 @@ -266,6 +269,9 @@
    6.14      <ClInclude Include="..\src\sync_codec.h">
    6.15        <Filter>Headerdateien</Filter>
    6.16      </ClInclude>
    6.17 +    <ClInclude Include="..\src\internal_format.h">
    6.18 +      <Filter>Headerdateien</Filter>
    6.19 +    </ClInclude>
    6.20    </ItemGroup>
    6.21    <ItemGroup>
    6.22      <Text Include="..\LICENSE.txt" />
     7.1 --- a/clean_sync_leftovers.sh	Thu Apr 16 20:35:53 2020 +0200
     7.2 +++ b/clean_sync_leftovers.sh	Mon Jun 08 15:01:34 2020 +0200
     7.3 @@ -6,5 +6,5 @@
     7.4  cd ..
     7.5  branch=`hg branch`
     7.6  if [ "$branch" = "sync" ]; then
     7.7 -    rm src/KeySync_fsm.c src/KeySync_fsm.h src/Sync_actions.c src/Sync_event.c src/Sync_event.h src/Sync_func.c src/Sync_func.h src/Sync_impl.c src/Sync_impl.h src/sync_codec.c src/sync_codec.h
     7.8 +    rm -f src/TrustSync_fsm.c src/TrustSync_fsm.h src/KeySync_fsm.c src/KeySync_fsm.h src/Sync_actions.c src/Sync_event.c src/Sync_event.h src/Sync_func.c src/Sync_func.h src/Sync_impl.c src/Sync_impl.h src/sync_codec.c src/sync_codec.h
     7.9  fi	
     8.1 --- a/doc/build-fedora.md	Thu Apr 16 20:35:53 2020 +0200
     8.2 +++ b/doc/build-fedora.md	Mon Jun 08 15:01:34 2020 +0200
     8.3 @@ -48,7 +48,6 @@
     8.4  mkdir -p ~/code/pep-engine
     8.5  hg clone https://pep.foundation/dev/repos/pEpEngine/ ~/code/pep-engine
     8.6  cd ~/code/pep-engine
     8.7 -hg update sync
     8.8  mkdir ~/code/pep-engine/build
     8.9  ~~~
    8.10  
     9.1 --- a/doc/build-macos.md	Thu Apr 16 20:35:53 2020 +0200
     9.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.3 @@ -1,161 +0,0 @@
     9.4 -<!-- Copyright 2015-2017, pEp foundation, Switzerland
     9.5 -This file is part of the pEp Engine
     9.6 -This file may be used under the terms of the Creative Commons Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) License
     9.7 -See CC_BY-SA.txt -->
     9.8 -
     9.9 -# Build instructions for macOS Sierra
    9.10 -
    9.11 -# Installing packaged dependencies
    9.12 -You will find instructions for using either Macports or Homebrew below to install the compile-time dependencies.
    9.13 -
    9.14 -## MacPorts
    9.15 -Install MacPorts according to the instructions found [here](https://www.macports.org/install.php).
    9.16 -Ensure that Macports' binary paths (`/opt/local/bin` and `/opt/local/sbin`) are in your `PATH` environment variable.
    9.17 -
    9.18 -~~~
    9.19 -# general
    9.20 -sudo port install mercurial
    9.21 -# YML2
    9.22 -sudo port install py27-lxml
    9.23 -# libetpan
    9.24 -sudo port install git autoconf automake libtool
    9.25 -# asn1c
    9.26 -sudo port install asn1c
    9.27 -# engine
    9.28 -sudo port install gpgme
    9.29 -~~~
    9.30 -
    9.31 -Ensure that `python` is Python 2.7:
    9.32 -
    9.33 -~~~
    9.34 -sudo port select python python27
    9.35 -~~~
    9.36 -
    9.37 -## Homebrew
    9.38 -Install Homebrew according to the instructions found [here](https://docs.brew.sh/Installation.html).
    9.39 -Ensure that Homebrew's binary path (`/usr/local/bin`) is in your `PATH` environment variable.
    9.40 -
    9.41 -~~~
    9.42 -# general
    9.43 -brew install mercurial
    9.44 -# YML2
    9.45 -# If you don't have pip with your Python 2 distribution, you can install it with brew
    9.46 -brew install python
    9.47 -pip2 install --user lxml
    9.48 -# libetpan
    9.49 -brew install git autoconf automake libtool
    9.50 -# asn1c
    9.51 -brew install asn1c
    9.52 -# engine
    9.53 -brew install gpgme
    9.54 -~~~
    9.55 -
    9.56 -# Installing unpackaged dependencies
    9.57 -## YML2
    9.58 -To check if lxml is properly installed, you can use this lxml "hello world" command:
    9.59 -
    9.60 -~~~
    9.61 -python2 -c 'from lxml import etree; root = etree.Element("root"); print(root.tag)'
    9.62 -~~~
    9.63 -
    9.64 -It should generate the following output:
    9.65 -
    9.66 -~~~
    9.67 -root
    9.68 -~~~
    9.69 -
    9.70 -~~~
    9.71 -mkdir -p ~/code/yml2
    9.72 -hg clone https://pep.foundation/dev/repos/yml2/ ~/code/yml2
    9.73 -~~~
    9.74 -
    9.75 -## libetpan
    9.76 -pEp Engine requires libetpan with a set of patches that have not been upstreamed yet.
    9.77 -
    9.78 -~~~
    9.79 -mkdir -p ~/code/libetpan
    9.80 -git clone https://github.com/fdik/libetpan ~/code/libetpan
    9.81 -cd ~/code/libetpan
    9.82 -mkdir ~/code/libetpan/build
    9.83 -./autogen.sh --prefix="$HOME/code/libetpan/build"
    9.84 -make
    9.85 -make install
    9.86 -~~~
    9.87 -
    9.88 -## GPGME
    9.89 -The MacPorts-packaged GPGME links to a version of GNU libiconv that has files in the same include/library paths as GPGME. This version of libiconv must not be visible to the linker when the pEp Engine is build or run.
    9.90 -
    9.91 -Thus the files of the GPGME distribution will have to be manually copied to separate include/library folders, so that no include or library paths used for building the pEp Engine contains files of MacPorts' libiconv distribution.
    9.92 -
    9.93 -~~~
    9.94 -mkdir -p ~/code/gpgme/build/include
    9.95 -cp /opt/local/include/gpg*.h ~/code/gpgme/build/include
    9.96 -mkdir -p ~/code/gpgme/build/lib
    9.97 -cp -r /opt/local/lib/libgpg* ~/code/gpgme/build/lib
    9.98 -~~~
    9.99 -
   9.100 -It's of course possible to skip MacPort's version, and use a self-compiled GPGME/GPG. The default build configuration assumes this case, and assumes you have installed your GPGME with `$(HOME)` as your prefix.
   9.101 -
   9.102 -# pEp Engine
   9.103 -
   9.104 -~~~
   9.105 -mkdir -p ~/code/pep-engine
   9.106 -hg clone https://pep.foundation/dev/repos/pEpEngine/ ~/code/pep-engine
   9.107 -cd ~/code/pep-engine
   9.108 -mkdir ~/code/pep-engine/build
   9.109 -~~~
   9.110 -
   9.111 -Edit the build configuration to your needs in `Makefile.conf`, or create a `local.conf` that sets any of the make variables documented in `Makefile.conf`. All the default values for the build configuration variables on each platform are documented in `Makefile.conf`.
   9.112 -
   9.113 -If a dependency is not found in your system's default include or library paths, you will have to specify the according paths in a make variable. Typically, this has to be done at least for YML2, and libetpan.
   9.114 -
   9.115 -For a more detailed explanation of the mechanics of these build configuration files, and overriding defaults, see the comments in `Makefile.conf`.
   9.116 -
   9.117 -Below is a sample `./local.conf` file, for orientation.
   9.118 -
   9.119 -~~~
   9.120 -PREFIX=$(HOME)/code/engine/build
   9.121 -PER_MACHINE_DIRECTORY=$(PREFIX)/share/pEp
   9.122 -
   9.123 -YML2_PATH=$(HOME)/code/yml2
   9.124 -
   9.125 -ETPAN_LIB=-L$(HOME)/code/libetpan/build/lib
   9.126 -ETPAN_INC=-I$(HOME)/code/libetpan/build/include
   9.127 -
   9.128 -GPGME_LIB=-L$(HOME)/lib
   9.129 -GPGME_INC=-I$(HOME)/include
   9.130 -~~~
   9.131 -
   9.132 -The engine is built as follows:
   9.133 -
   9.134 -~~~
   9.135 -make all
   9.136 -make db
   9.137 -~~~
   9.138 -
   9.139 -If your build fails with an error message similar to the following:
   9.140 -
   9.141 -~~~
   9.142 -  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/locale.py", line 477, in _parse_localename
   9.143 -    raise ValueError, 'unknown locale: %s' % localename
   9.144 -ValueError: unknown locale: UTF-8
   9.145 -~~~
   9.146 -
   9.147 -or any other locale-related Python error, make sure Python does not have any locale-related environment variables set.
   9.148 -Usually, `unset LC_CTYPE` is sufficient to take care of the problem, but it depends on your macOS's regional and language settings and which terminal emulator you use.
   9.149 -This is a bug in Python, see [https://bugs.python.org/issue18378#msg215215](https://bugs.python.org/issue18378#msg215215).
   9.150 -
   9.151 -The unit tests can be run without the engine library being installed, however `system.db` must be installed:
   9.152 -
   9.153 -~~~
   9.154 -make -C db install
   9.155 -~~~
   9.156 -
   9.157 -Since `system.db` rarely changes, its installation is not needed for every build.
   9.158 -
   9.159 -Tests can be compiled and executed with the following commands:
   9.160 -
   9.161 -~~~
   9.162 -make -C test compile
   9.163 -make test
   9.164 -~~~
    10.1 --- a/doc/build-netpgp.md	Thu Apr 16 20:35:53 2020 +0200
    10.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.3 @@ -1,43 +0,0 @@
    10.4 -# Using NetPGP instead of GnuPG
    10.5 -## Prepare
    10.6 -
    10.7 -Get OpenSSL:
    10.8 -curl -O https://www.openssl.org/source/openssl-1.1.0f.tar.gz
    10.9 -
   10.10 -Build it using the openssl-for-ios build script:
   10.11 -git clone https://github.com/sinofool/build-openssl-ios/ .
   10.12 -
   10.13 -
   10.14 -
   10.15 - and build/install it as shared library.
   10.16 -
   10.17 -```
   10.18 -wget https://www.openssl.org/source/old/1.0.1/openssl-1.0.1u.tar.gz
   10.19 -tar xvfz openssl-1.0.1u.tar.gz
   10.20 -cd openssl-1.0.1u
   10.21 -./Configure darwin64-x86_64-cc --prefix=$HOME shared
   10.22 -make install
   10.23 -```
   10.24 -
   10.25 -Get and autoconf NetPGP
   10.26 -
   10.27 -```
   10.28 -cd $SRC
   10.29 -hg clone https://pep.foundation/dev/repos/netpgp-et/
   10.30 -cd netpgp-et
   10.31 -autoreconf -i
   10.32 -```
   10.33 -
   10.34 -## Build
   10.35 -
   10.36 -Important : LDFLAGS is set to help finding OpenSSL shared lib. If not set,
   10.37 -system's default libcrypto may silently be used instead, causing memory
   10.38 -corruption or crash at runtime.
   10.39 -
   10.40 -```
   10.41 -mkdir netpgp_debug
   10.42 -cd netpgp_debug
   10.43 -$SRC/netpgp-et/configure --with-openssl=$HOME --prefix=$HOME CPPFLAGS=-DDEBUG CXXFLAGS="-g -O0" LDFLAGS="-L${HOME}/lib"
   10.44 -make
   10.45 -make install
   10.46 -```
    11.1 --- a/doc/readme.md	Thu Apr 16 20:35:53 2020 +0200
    11.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.3 @@ -1,58 +0,0 @@
    11.4 -<!-- Copyright 2015-2017, pEp foundation, Switzerland
    11.5 -This file is part of the pEp Engine
    11.6 -This file may be used under the terms of the Creative Commons Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) License
    11.7 -See CC_BY-SA.txt -->
    11.8 -
    11.9 -# Information about the pEp Engine
   11.10 -
   11.11 -# Dependencies
   11.12 -The p≡p Engine depends on the following projects:
   11.13 -
   11.14 -- run-time dependencies
   11.15 -  - One of the following OpenPGP implementations:
   11.16 -    - GnuPG version 2.1.17 or later with GPGME (at least version 1.7.0) [https://gnupg.org/](https://gnupg.org/)
   11.17 -    - For platforms not supporting pinentry (e.g. Android) - GnuPG version 2.0.30 with GPGME version 1.6.0 (or later) [https://gnupg.org/](https://gnupg.org/)
   11.18 -    - a fork of NetPGP, [https://pep.foundation/dev/repos/netpgp-et/](https://pep.foundation/dev/repos/netpgp-et/)
   11.19 -    - Sequoia, which in turn requires:
   11.20 -      - Rust
   11.21 -      - libnettle
   11.22 -  - One of the following MIME libraries:
   11.23 -    - a fork of libetpan, [https://github.com/fdik/libetpan](https://github.com/fdik/libetpan)
   11.24 -    - pEpMIME
   11.25 -  - zlib, [http://zlib.net/](http://zlib.net/)
   11.26 -  - libcurl (Only with NetPGP), [https://curl.haxx.se/libcurl/](https://curl.haxx.se/libcurl/)
   11.27 -  - libuuid, [https://www.kernel.org/pub/linux/utils/util-linux/](https://www.kernel.org/pub/linux/utils/util-linux/)
   11.28 -  - SQLite, [https://sqlite.org](https://sqlite.org)
   11.29 -  - OpenSSL (Only with NetPGP), [https://www.openssl.org](https://www.openssl.org)
   11.30 -- compile-time dependencies
   11.31 -  - asn1c (version v0.9.28), [http://lionet.info/asn1c/blog/](http://lionet.info/asn1c/blog/)
   11.32 -  - yml2, [https://fdik.org/yml//toolchain](https://fdik.org/yml//toolchain)
   11.33 -    - Python 3
   11.34 -    - LXML
   11.35 -  - One of the following build systems:
   11.36 -    - GNU make (on Linux and macOS)
   11.37 -    - MSBuild distributed with Microsoft Visual Studio 2015 (on Windows)
   11.38 -  - One of the following compilers for C and C++:
   11.39 -    - GNU GCC (on Linux)
   11.40 -    - Apple "clang" LLVM (on MacOS)
   11.41 -    - Microsoft MSVC/MSVC++ distributed with Microsoft Visual Studio 2015 (on Windows)
   11.42 -  - A script for compiling OpenSSL for iOS, [https://github.com/sinofool/build-openssl-ios/](https://github.com/sinofool/build-openssl-ios/)
   11.43 -  - binutils
   11.44 -
   11.45 -# The pEp Engine's databases
   11.46 -The p≡p Engine uses two databases:
   11.47 -
   11.48 -- the management database
   11.49 -  - `~/.pEp_management` on \*NIX
   11.50 -  - `%LOCALAPPDATA%\pEp\management.db` on Windows
   11.51 -- the Trustword database
   11.52 -  - `/usr/local/share/system.db` on \*NIX
   11.53 -  - `%ALLUSERSPROFILE%\pEp\system.db` on Windows
   11.54 -
   11.55 -The management db is created by the first call of `init()` of p≡p Engine.
   11.56 -It does not need to be created manually.
   11.57 -`system.db` is created by using the DDL in `db/create_system_db.sql`; the database content is created by `db/dic2csv.py` out of hunspell's dictionary packages (or something similar) and then imported using `sqlite3`'s `.import` command.
   11.58 -Dictionary files for different languages are part of the p≡p Engine source distribution.
   11.59 -
   11.60 -You can test the Trustwords in `system.db` using `db/trustwords.py`.
   11.61 -Both Python tools have a `--help` switch.
    12.1 --- a/doc/testing.md	Thu Apr 16 20:35:53 2020 +0200
    12.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.3 @@ -1,2 +0,0 @@
    12.4 -# Testing
    12.5 -For the documentation of the tests, see `test/README.md`
    13.1 --- a/src/aux_mime_msg.c	Thu Apr 16 20:35:53 2020 +0200
    13.2 +++ b/src/aux_mime_msg.c	Mon Jun 08 15:01:34 2020 +0200
    13.3 @@ -73,7 +73,7 @@
    13.4      message* dec_msg = NULL;
    13.5      *mime_plaintext = NULL;
    13.6  
    13.7 -    status = mime_decode_message(mimetext, size, &tmp_msg);
    13.8 +    status = mime_decode_message(mimetext, size, &tmp_msg, NULL);
    13.9      if (status != PEP_STATUS_OK)
   13.10          goto pEp_error;
   13.11  
   13.12 @@ -120,7 +120,7 @@
   13.13      }
   13.14  
   13.15      if (*flags & PEP_decrypt_flag_src_modified) {
   13.16 -        _mime_encode_message_internal(tmp_msg, false, modified_src, true, false);
   13.17 +        mime_encode_message(tmp_msg, false, modified_src, false);
   13.18          if (!modified_src) {
   13.19              *flags &= (~PEP_decrypt_flag_src_modified);
   13.20              decrypt_status = PEP_CANNOT_REENCRYPT; // Because we couldn't return it, I guess.
   13.21 @@ -128,7 +128,7 @@
   13.22      }
   13.23  
   13.24      // FIXME: test with att
   13.25 -    status = _mime_encode_message_internal(dec_msg, false, mime_plaintext, true, false);
   13.26 +    status = mime_encode_message(dec_msg, false, mime_plaintext, false);
   13.27  
   13.28      if (status == PEP_STATUS_OK)
   13.29      {
   13.30 @@ -161,7 +161,7 @@
   13.31      message* enc_msg = NULL;
   13.32      message* ret_msg = NULL;                             
   13.33  
   13.34 -    status = mime_decode_message(mimetext, size, &tmp_msg);
   13.35 +    status = mime_decode_message(mimetext, size, &tmp_msg, NULL);
   13.36      if (status != PEP_STATUS_OK)
   13.37          goto pEp_error;
   13.38  
   13.39 @@ -217,12 +217,10 @@
   13.40          goto pEp_error;
   13.41      }
   13.42      
   13.43 -    tmp_status = _mime_encode_message_internal(
   13.44 -                                ret_msg, 
   13.45 -                                false, 
   13.46 -                                mime_ciphertext, 
   13.47 -                                false, 
   13.48 -                                false);
   13.49 +    tmp_status = mime_encode_message(ret_msg, 
   13.50 +                                     false, 
   13.51 +                                     mime_ciphertext, 
   13.52 +                                     false);
   13.53      
   13.54      if (tmp_status != PEP_STATUS_OK)
   13.55          status = tmp_status;
   13.56 @@ -250,7 +248,7 @@
   13.57      message* tmp_msg = NULL;
   13.58      message* enc_msg = NULL;
   13.59  
   13.60 -    status = mime_decode_message(mimetext, size, &tmp_msg);
   13.61 +    status = mime_decode_message(mimetext, size, &tmp_msg, NULL);
   13.62      if (status != PEP_STATUS_OK)
   13.63          goto pEp_error;
   13.64  
   13.65 @@ -271,7 +269,7 @@
   13.66          goto pEp_error;
   13.67      }
   13.68  
   13.69 -    status = mime_encode_message(enc_msg, false, mime_ciphertext);
   13.70 +    status = mime_encode_message(enc_msg, false, mime_ciphertext, false);
   13.71  
   13.72  pEp_error:
   13.73      free_message(tmp_msg);
    14.1 --- a/src/baseprotocol.c	Thu Apr 16 20:35:53 2020 +0200
    14.2 +++ b/src/baseprotocol.c	Mon Jun 08 15:01:34 2020 +0200
    14.3 @@ -30,14 +30,26 @@
    14.4      if (!(msg && payload && size && type))
    14.5          return PEP_ILLEGAL_VALUE;
    14.6  
    14.7 -    bloblist_t *bl = bloblist_add(msg->attachments, payload, size,
    14.8 -            _base_type[type], "ignore_this_attachment.pEp");
    14.9 -    if (bl == NULL) {
   14.10 +    bloblist_t *bl;
   14.11 +
   14.12 +    switch (type) {
   14.13 +        case BASE_SYNC:
   14.14 +            bl = bloblist_add(msg->attachments, payload, size,
   14.15 +                    _base_type[type], "sync.pEp");
   14.16 +            break;
   14.17 +        case BASE_KEYRESET:
   14.18 +            bl = bloblist_add(msg->attachments, payload, size,
   14.19 +                    _base_type[type], "distribution.pEp");
   14.20 +            break;
   14.21 +        default:
   14.22 +            bl = bloblist_add(msg->attachments, payload, size,
   14.23 +                    _base_type[type], "ignore_this_attachment.pEp");
   14.24 +    }
   14.25 +
   14.26 +    if (bl == NULL)
   14.27          goto enomem;
   14.28 -    }
   14.29 -    else if (!msg->attachments) {
   14.30 +    else if (!msg->attachments)
   14.31          msg->attachments = bl;
   14.32 -    }
   14.33  
   14.34      if (fpr && fpr[0] != '\0') {
   14.35          char *sign;
    15.1 --- a/src/etpan_mime.c	Thu Apr 16 20:35:53 2020 +0200
    15.2 +++ b/src/etpan_mime.c	Mon Jun 08 15:01:34 2020 +0200
    15.3 @@ -324,8 +324,7 @@
    15.4          const char * mime_type,
    15.5          char * data,
    15.6          size_t length,
    15.7 -        bool transport_encode,
    15.8 -        bool set_attachment_forward_comment
    15.9 +        bool is_nf_message_attachment // non-forwarded msg as att
   15.10      )
   15.11  {
   15.12      char * disposition_name = NULL;
   15.13 @@ -373,7 +372,9 @@
   15.14  
   15.15      encoding = NULL;
   15.16  
   15.17 -    if (transport_encode) {
   15.18 +    bool already_ascii = !(must_chunk_be_encoded(data, length, true));
   15.19 +    
   15.20 +    if (!is_nf_message_attachment && !already_ascii) {
   15.21          encoding_type = MAILMIME_MECHANISM_BASE64;
   15.22          encoding = mailmime_mechanism_new(encoding_type, NULL);
   15.23          if (encoding == NULL)
   15.24 @@ -389,7 +390,7 @@
   15.25  
   15.26      stringpair_list_t* extra_params = NULL;
   15.27      
   15.28 -    if (set_attachment_forward_comment)
   15.29 +    if (is_nf_message_attachment)
   15.30          extra_params = new_stringpair_list(new_stringpair("forwarded", "no"));
   15.31      
   15.32      mime = part_new_empty(content, mime_fields, extra_params, 1);
   15.33 @@ -565,10 +566,25 @@
   15.34      if (_name == NULL)
   15.35          goto enomem;
   15.36  
   15.37 -    _address = strdup(address);
   15.38 -    if (_address == NULL)
   15.39 -        goto enomem;
   15.40 -
   15.41 +    char* at = strstr(address, "@");
   15.42 +    if (!at) {
   15.43 +        // Presumed URI
   15.44 +        int added_char_len = 6; // " " @URI 
   15.45 +        int new_addr_len = strlen(address) + added_char_len + 1;
   15.46 +        _address = calloc(new_addr_len, 1);
   15.47 +        if (_address == NULL)
   15.48 +            goto enomem;
   15.49 +        
   15.50 +        _address[0] = '"';
   15.51 +        strlcat(_address, address, new_addr_len);
   15.52 +        strlcat(_address, "\"@URI", new_addr_len);
   15.53 +    }
   15.54 +    else {
   15.55 +        _address = strdup(address);
   15.56 +        if (_address == NULL)
   15.57 +            goto enomem;
   15.58 +    }
   15.59 +            
   15.60      mb = mailimf_mailbox_new(_name, _address);
   15.61      assert(mb);
   15.62      if (mb == NULL)
   15.63 @@ -1005,7 +1021,7 @@
   15.64  
   15.65  static PEP_STATUS interpret_MIME(struct mailmime *mime,
   15.66                                   message *msg,
   15.67 -                                 bool* raise_msg_attachment);
   15.68 +                                 bool* has_possible_pEp_msg);
   15.69  
   15.70  // This function was rewritten to use in-memory buffers instead of
   15.71  // temporary files when the pgp/mime support was implemented for
   15.72 @@ -1063,8 +1079,7 @@
   15.73  static PEP_STATUS mime_attachment(
   15.74          bloblist_t *blob,
   15.75          struct mailmime **result,
   15.76 -        bool transport_encode,
   15.77 -        bool set_attachment_forward_comment
   15.78 +        bool is_nf_message_attachment // non-forwarded msg as att
   15.79      )
   15.80  {
   15.81      PEP_STATUS status = PEP_STATUS_OK;
   15.82 @@ -1086,11 +1101,8 @@
   15.83  
   15.84      pEp_rid_list_t* resource = parse_uri(blob->filename);
   15.85  
   15.86 -    bool already_ascii = !(must_chunk_be_encoded(blob->value, blob->size, true));
   15.87 -
   15.88      mime = get_file_part(resource, mime_type, blob->value, blob->size, 
   15.89 -                          (already_ascii ? false : transport_encode),
   15.90 -                          set_attachment_forward_comment);
   15.91 +                         is_nf_message_attachment);
   15.92      free_rid_list(resource);
   15.93      
   15.94      assert(mime);
   15.95 @@ -1109,12 +1121,23 @@
   15.96      return status;
   15.97  }
   15.98  
   15.99 +
  15.100 +// This ONLY deals with handling the body 
  15.101 +// content when html parts are present - thus,
  15.102 +// text/plain and text/html of the body, and 
  15.103 +// related inline attachments for the html 
  15.104 +// part. Non-inline attachments are handled 
  15.105 +// outside this call!!!!
  15.106 +//
  15.107 +// N.B. As a result, this will only touch the 
  15.108 +// "contained message" of pEp 2.x messages 
  15.109 +// on the initial encoding where it is turned 
  15.110 +// into attachment data!!
  15.111  static PEP_STATUS mime_html_text(
  15.112          const char *plaintext,
  15.113          const char *htmltext,
  15.114          bloblist_t *attachments,
  15.115 -        struct mailmime **result,
  15.116 -        bool transport_encode
  15.117 +        struct mailmime **result
  15.118      )
  15.119  {
  15.120      PEP_STATUS status = PEP_STATUS_OK;
  15.121 @@ -1129,33 +1152,50 @@
  15.122  
  15.123      *result = NULL;
  15.124  
  15.125 -    mime = part_multiple_new("multipart/alternative");
  15.126 -    assert(mime);
  15.127 -    if (mime == NULL)
  15.128 -        goto enomem;
  15.129 -
  15.130      pEp_rid_list_t* resource = NULL;
  15.131 +        
  15.132 +    bool already_ascii = false;
  15.133 +    int encoding_type = 0;    
  15.134 +    if (*plaintext != '\0') {
  15.135 +        mime = part_multiple_new("multipart/alternative");
  15.136 +        assert(mime);
  15.137 +        if (mime == NULL)
  15.138 +            goto enomem;
  15.139 +            
  15.140 +        // KB: pEpMIME transition comment - if we start getting 
  15.141 +        // underencoding errors here, the change to checking 
  15.142 +        // for ASCII and then encoding - or not - is one place 
  15.143 +        // to start looking.
  15.144 +        int pt_length = strlen(plaintext);
  15.145 +        already_ascii = !(must_chunk_be_encoded(plaintext, pt_length, true));                
  15.146 +        encoding_type = (already_ascii ? 0 : MAILMIME_MECHANISM_QUOTED_PRINTABLE);
  15.147 +                
  15.148 +        submime = get_text_part(NULL, "text/plain", plaintext, 
  15.149 +                                pt_length,
  15.150 +                                encoding_type);
  15.151 +        
  15.152 +        // reset                        
  15.153 +        already_ascii = false;
  15.154 +        encoding_type = 0;
  15.155 +                                    
  15.156 +        free_rid_list(resource);
  15.157 +        resource = NULL;
  15.158 +        
  15.159 +        assert(submime);
  15.160 +        if (submime == NULL)
  15.161 +            goto enomem;
  15.162 +
  15.163 +        r = mailmime_smart_add_part(mime, submime);
  15.164 +        assert(r == MAILIMF_NO_ERROR);
  15.165 +        if (r == MAILIMF_ERROR_MEMORY) {
  15.166 +            goto enomem;
  15.167 +        }
  15.168 +        else {
  15.169 +            // mailmime_smart_add_part() takes ownership of submime
  15.170 +            submime = NULL;
  15.171 +        }
  15.172 +    }
  15.173      
  15.174 -    int encoding_type = (transport_encode ? MAILMIME_MECHANISM_QUOTED_PRINTABLE : 0);
  15.175 -    submime = get_text_part(NULL, "text/plain", plaintext, strlen(plaintext),
  15.176 -            encoding_type);
  15.177 -    free_rid_list(resource);
  15.178 -    resource = NULL;
  15.179 -    
  15.180 -    assert(submime);
  15.181 -    if (submime == NULL)
  15.182 -        goto enomem;
  15.183 -
  15.184 -    r = mailmime_smart_add_part(mime, submime);
  15.185 -    assert(r == MAILIMF_NO_ERROR);
  15.186 -    if (r == MAILIMF_ERROR_MEMORY) {
  15.187 -        goto enomem;
  15.188 -    }
  15.189 -    else {
  15.190 -        // mailmime_smart_add_part() takes ownership of submime
  15.191 -        submime = NULL;
  15.192 -    }
  15.193 -
  15.194      bool inlined_attachments = false;
  15.195      
  15.196      bloblist_t* traversal_ptr = attachments;
  15.197 @@ -1175,60 +1215,88 @@
  15.198          if (submime == NULL)
  15.199              goto enomem;
  15.200  
  15.201 +        // This is where all of the html MIME stuff will go
  15.202          top_level_html_mime = submime;
  15.203          
  15.204 -        r = mailmime_smart_add_part(mime, top_level_html_mime);
  15.205 -        assert(r == MAILIMF_NO_ERROR);
  15.206 -        if (r == MAILIMF_ERROR_MEMORY) {
  15.207 -            goto enomem;
  15.208 -        }
  15.209 -        else {
  15.210 -            // mailmime_smart_add_part() takes ownership of submime
  15.211 -            submime = NULL;
  15.212 -        }
  15.213 +        if (!mime)
  15.214 +            mime = top_level_html_mime;
  15.215 +        else {    
  15.216 +            r = mailmime_smart_add_part(mime, top_level_html_mime);
  15.217 +            assert(r == MAILIMF_NO_ERROR);
  15.218 +            if (r == MAILIMF_ERROR_MEMORY) {
  15.219 +                goto enomem;
  15.220 +            }
  15.221 +            else {
  15.222 +                // mailmime_smart_add_part() takes ownership of submime
  15.223 +                submime = NULL;
  15.224 +            }
  15.225 +        }    
  15.226      }
  15.227      else {
  15.228 +        // Otherwise, html MIME stuff gets added to the top node 
  15.229 +        // - may be NULL if there's no multipart!
  15.230          top_level_html_mime = mime;
  15.231      }
  15.232  
  15.233  //    resource = new_rid_node(PEP_RID_FILENAME, "msg.html");
  15.234 -    submime = get_text_part(NULL, "text/html", htmltext, strlen(htmltext),
  15.235 -            encoding_type);
  15.236 +    int ht_length = strlen(htmltext);
  15.237 +    already_ascii = !(must_chunk_be_encoded(htmltext, ht_length, true));                
  15.238 +    encoding_type = (already_ascii ? 0 : MAILMIME_MECHANISM_QUOTED_PRINTABLE);
  15.239 +            
  15.240 +    submime = get_text_part(NULL, "text/html", htmltext, 
  15.241 +                            ht_length,
  15.242 +                            encoding_type);
  15.243 +
  15.244      free_rid_list(resource);
  15.245      resource = NULL;
  15.246      
  15.247      assert(submime);
  15.248      if (submime == NULL)
  15.249          goto enomem;
  15.250 -
  15.251 -    r = mailmime_smart_add_part(top_level_html_mime, submime);
  15.252 -    assert(r == MAILIMF_NO_ERROR);
  15.253 -    if (r == MAILIMF_ERROR_MEMORY)
  15.254 -        goto enomem;
  15.255 -    else {
  15.256 -        // mailmime_smart_add_part() takes ownership of submime
  15.257 +        
  15.258 +    // IF there are no inlined attachments AND mime is NULL, then 
  15.259 +    // we just have an HTML body here and won't need to 
  15.260 +    // process inlined attachments - submime will actually be 
  15.261 +    // the mime root of from this function, at least.    
  15.262 +
  15.263 +    if (!top_level_html_mime) {
  15.264 +        mime = submime;
  15.265          submime = NULL;
  15.266      }
  15.267 -
  15.268 -    bloblist_t *_a;
  15.269 -    for (_a = attachments; _a != NULL; _a = _a->next) {
  15.270 -        if (_a->disposition != PEP_CONTENT_DISP_INLINE)
  15.271 -            continue;
  15.272 -        status = mime_attachment(_a, &submime, transport_encode, false);
  15.273 -        if (status != PEP_STATUS_OK)
  15.274 -            return PEP_UNKNOWN_ERROR; // FIXME
  15.275 -
  15.276 +    else {    
  15.277          r = mailmime_smart_add_part(top_level_html_mime, submime);
  15.278          assert(r == MAILIMF_NO_ERROR);
  15.279 -        if (r == MAILIMF_ERROR_MEMORY) {
  15.280 +        if (r == MAILIMF_ERROR_MEMORY)
  15.281              goto enomem;
  15.282 -        }
  15.283          else {
  15.284              // mailmime_smart_add_part() takes ownership of submime
  15.285              submime = NULL;
  15.286          }
  15.287 -    }
  15.288 -
  15.289 +
  15.290 +        bloblist_t *_a;
  15.291 +
  15.292 +        // This will never have an embedded pEp message attachment 
  15.293 +        // sent for encoding here, so we don't need to pass down 
  15.294 +        // "(don't) transport encode this" info. If it's here and 
  15.295 +        // it's not an ASCII "text/*" attachment, it'll get encoded
  15.296 +        for (_a = attachments; _a != NULL; _a = _a->next) {
  15.297 +            if (_a->disposition != PEP_CONTENT_DISP_INLINE)
  15.298 +                continue;
  15.299 +            status = mime_attachment(_a, &submime, false);
  15.300 +            if (status != PEP_STATUS_OK)
  15.301 +                return PEP_UNKNOWN_ERROR; // FIXME
  15.302 +
  15.303 +            r = mailmime_smart_add_part(top_level_html_mime, submime);
  15.304 +            assert(r == MAILIMF_NO_ERROR);
  15.305 +            if (r == MAILIMF_ERROR_MEMORY) {
  15.306 +                goto enomem;
  15.307 +            }
  15.308 +            else {
  15.309 +                // mailmime_smart_add_part() takes ownership of submime
  15.310 +                submime = NULL;
  15.311 +            }
  15.312 +        }
  15.313 +    }    
  15.314      *result = mime;
  15.315      return PEP_STATUS_OK;
  15.316  
  15.317 @@ -1245,7 +1313,6 @@
  15.318  }
  15.319  
  15.320  
  15.321 -// FIXME: maybe need to add transport_encode field here
  15.322  static struct mailimf_mailbox * identity_to_mailbox(const pEp_identity *ident)
  15.323  {
  15.324      char *_username = NULL;
  15.325 @@ -1363,6 +1430,9 @@
  15.326      return NULL;
  15.327  }
  15.328  
  15.329 +// KB: This seems to be always called with "true",
  15.330 +//     but there was probably a reason for this. So 
  15.331 +//     leave it for now.
  15.332  static clist * stringlist_to_clist(stringlist_t *sl, bool transport_encode)
  15.333  {
  15.334      clist * cl = clist_new();
  15.335 @@ -1691,8 +1761,7 @@
  15.336          const message *msg,
  15.337          bool omit_fields,
  15.338          struct mailmime **result,
  15.339 -        bool transport_encode,
  15.340 -        bool set_attachment_forward_comment
  15.341 +        bool has_pEp_msg_attachment
  15.342      )
  15.343  {
  15.344      struct mailmime * mime = NULL;
  15.345 @@ -1700,13 +1769,13 @@
  15.346      int r;
  15.347      PEP_STATUS status;
  15.348      //char *subject;
  15.349 -    char *plaintext;
  15.350 +    const char *plaintext;
  15.351      char *htmltext;
  15.352  
  15.353      assert(msg);
  15.354      assert(result);
  15.355 -    
  15.356 -    //subject = (msg->shortmsg) ? msg->shortmsg : "pEp";  // not used, yet.
  15.357 +
  15.358 +    // * Process body content, including html's inlined attachments *
  15.359      plaintext = (msg->longmsg) ? msg->longmsg : "";
  15.360      htmltext = msg->longmsg_formatted;
  15.361  
  15.362 @@ -1714,23 +1783,37 @@
  15.363          /* first, we need to strip out the inlined attachments to ensure this
  15.364             gets set up correctly */
  15.365             
  15.366 -        status = mime_html_text(plaintext, htmltext, msg->attachments, &mime,
  15.367 -                                transport_encode);
  15.368 +        // Note: this only, regardless of whether this is being done 
  15.369 +        // for the to-be-embedded message attachment generation or 
  15.370 +        // an encapsulating message which contains this, touches 
  15.371 +        // the body text of this input message. So transport encoding 
  15.372 +        // only refers to the body content here and inlined-attachments, and 
  15.373 +        // is decided WITHIN this function, not as an argument. 
  15.374 +        status = mime_html_text(plaintext, htmltext, msg->attachments, &mime);
  15.375                  
  15.376          if (status != PEP_STATUS_OK)
  15.377              goto pEp_error;
  15.378      }
  15.379 -    else {
  15.380 +    else { /* body content only consists of a plaintext block */
  15.381          pEp_rid_list_t* resource = NULL;
  15.382 +
  15.383 +        int pt_length = strlen(plaintext);
  15.384 +
  15.385          if (is_PGP_message_text(plaintext)) {
  15.386              resource = NULL;
  15.387 -            int encoding_type = (transport_encode ? MAILMIME_MECHANISM_7BIT : 0);
  15.388 +            
  15.389 +            // So... I think we got overencoding here once, which would be a bug 
  15.390 +            // in libetpan, unless it had to do with whitespace. If removing
  15.391 +            // transport encoding as a calculation here somehow leads to overencoding,
  15.392 +            // either we or libetpan are doing something bad.
  15.393 +//            int encoding_type = (transport_encode ? MAILMIME_MECHANISM_7BIT : 0);
  15.394              mime = get_text_part(resource, "application/octet-stream", plaintext,
  15.395 -                    strlen(plaintext), encoding_type);
  15.396 +                                 pt_length, MAILMIME_MECHANISM_7BIT);
  15.397          }
  15.398          else {
  15.399              resource = NULL;
  15.400 -            int encoding_type = (transport_encode ? MAILMIME_MECHANISM_QUOTED_PRINTABLE : 0);
  15.401 +            bool already_ascii = !(must_chunk_be_encoded(plaintext, pt_length, true));                
  15.402 +            int encoding_type = (already_ascii ? MAILMIME_MECHANISM_7BIT : MAILMIME_MECHANISM_QUOTED_PRINTABLE);
  15.403              mime = get_text_part(resource, "text/plain", plaintext, strlen(plaintext),
  15.404                      encoding_type);
  15.405          }
  15.406 @@ -1741,10 +1824,21 @@
  15.407              goto enomem;
  15.408      }
  15.409  
  15.410 +    /* Body content processed, now process normal attachments */
  15.411 +    
  15.412      bool normal_attachments = false;
  15.413      
  15.414      bloblist_t* traversal_ptr = msg->attachments;
  15.415      
  15.416 +    // If there were any inline attachments, they should have 
  15.417 +    // been stripped out in mime_html_text and dealt with. 
  15.418 +    // I'm not entirely sure what the alternative case 
  15.419 +    // is here. But basically, if there are any non-inlined 
  15.420 +    // attachments to deal with, this is designed to 
  15.421 +    // make sure we process them. So flag it for 
  15.422 +    // "hey, Bob, you got some regular attachments here"
  15.423 +    // so Bob (obviously, the MIME engine is called Bob)
  15.424 +    // can do the right thing in the next block.
  15.425      while (traversal_ptr) {
  15.426          if (traversal_ptr->disposition != PEP_CONTENT_DISP_INLINE) {
  15.427              normal_attachments = true;
  15.428 @@ -1773,13 +1867,18 @@
  15.429          bloblist_t *_a;
  15.430          bool first_one = true;
  15.431          
  15.432 +        // Go through the non-inline attachments and add em.
  15.433          for (_a = msg->attachments; _a != NULL; _a = _a->next) {
  15.434  
  15.435              if (_a->disposition == PEP_CONTENT_DISP_INLINE)
  15.436                  continue;
  15.437  
  15.438 -            status = mime_attachment(_a, &submime, transport_encode,
  15.439 -                                     (first_one && set_attachment_forward_comment));                         
  15.440 +            // solely for readability.
  15.441 +            bool is_pEp_msg_attachment = (first_one && has_pEp_msg_attachment);
  15.442 +
  15.443 +            status = mime_attachment(_a, &submime, 
  15.444 +                                     is_pEp_msg_attachment);                         
  15.445 +
  15.446              if (status != PEP_STATUS_OK)
  15.447                  goto pEp_error;
  15.448              
  15.449 @@ -1891,12 +1990,11 @@
  15.450      return status;
  15.451  }
  15.452  
  15.453 -PEP_STATUS _mime_encode_message_internal(
  15.454 +DYNAMIC_API PEP_STATUS mime_encode_message(
  15.455          const message * msg,
  15.456          bool omit_fields,
  15.457          char **mimetext,
  15.458 -        bool transport_encode,
  15.459 -        bool set_attachment_forward_comment
  15.460 +        bool has_pEp_msg_attachment
  15.461      )
  15.462  {
  15.463      PEP_STATUS status = PEP_STATUS_OK;
  15.464 @@ -1916,12 +2014,12 @@
  15.465  
  15.466      switch (msg->enc_format) {
  15.467          case PEP_enc_none:
  15.468 -            status = mime_encode_message_plain(msg, omit_fields, &mime, transport_encode, set_attachment_forward_comment);
  15.469 +            status = mime_encode_message_plain(msg, omit_fields, &mime, has_pEp_msg_attachment);
  15.470              break;
  15.471  
  15.472 -        // I'm presuming we should hardcore ignoring set_attachment_forward_comment here...
  15.473 +        // I'm presuming we should hardcore ignoring has_pEp_msg_attachment here...
  15.474          case PEP_enc_inline:
  15.475 -            status = mime_encode_message_plain(msg, omit_fields, &mime, transport_encode, false);
  15.476 +            status = mime_encode_message_plain(msg, omit_fields, &mime, false);
  15.477              break;
  15.478  
  15.479          case PEP_enc_S_MIME:
  15.480 @@ -1988,6 +2086,7 @@
  15.481  static pEp_identity *mailbox_to_identity(const struct mailimf_mailbox * mb)
  15.482  {
  15.483      char *username = NULL;
  15.484 +    char *address = NULL;
  15.485  
  15.486      assert(mb);
  15.487      assert(mb->mb_addr_spec);
  15.488 @@ -2003,14 +2102,30 @@
  15.489              goto enomem;
  15.490      }
  15.491  
  15.492 -    pEp_identity *ident = new_identity(mb->mb_addr_spec, NULL, NULL, username);
  15.493 +    const char* raw_addr = mb->mb_addr_spec;
  15.494 +    if (raw_addr && raw_addr[0] == '"') {
  15.495 +        int addr_len = strlen(raw_addr);
  15.496 +        if (addr_len >= 6) { // ""@URI
  15.497 +            const char* endcheck = strstr(raw_addr + 1, "\"@URI");
  15.498 +            if (endcheck && *(endcheck + 5) == '\0') {
  15.499 +                int actual_size = addr_len - 6;
  15.500 +                address = calloc(actual_size + 1, 1);
  15.501 +                if (!address)
  15.502 +                    goto enomem;
  15.503 +                strlcpy(address, raw_addr + 1, actual_size + 1);    
  15.504 +            }
  15.505 +        }
  15.506 +    }
  15.507 +
  15.508 +    pEp_identity *ident = new_identity(address ? address : raw_addr, NULL, NULL, username);
  15.509      if (ident == NULL)
  15.510          goto enomem;
  15.511      free(username);
  15.512 -
  15.513 +    free(address);
  15.514      return ident;
  15.515  
  15.516  enomem:
  15.517 +    free(address);
  15.518      free(username);
  15.519      return NULL;
  15.520  }
  15.521 @@ -2496,10 +2611,30 @@
  15.522      return status;
  15.523  }
  15.524  
  15.525 +static bool _is_marked_as_attachment(struct mailmime_fields *fields)
  15.526 +{
  15.527 +    if (!(fields && fields->fld_list))
  15.528 +        return false;
  15.529 +
  15.530 +    clistiter *cur;
  15.531 +    for (cur = clist_begin(fields->fld_list); cur != NULL ; cur = clist_next(cur)) {
  15.532 +        struct mailmime_field * field = clist_content(cur);
  15.533 +        if (!(field && field->fld_type == MAILMIME_FIELD_DISPOSITION &&
  15.534 +                    field->fld_data.fld_disposition &&
  15.535 +                    field->fld_data.fld_disposition->dsp_type))
  15.536 +            continue;
  15.537 +        if (field->fld_data.fld_disposition->dsp_type->dsp_type ==
  15.538 +                MAILMIME_DISPOSITION_TYPE_ATTACHMENT)
  15.539 +            return true;
  15.540 +    }
  15.541 +
  15.542 +    return false;
  15.543 +}
  15.544 +
  15.545  static PEP_STATUS interpret_MIME(
  15.546          struct mailmime *mime,
  15.547          message *msg,
  15.548 -        bool* raise_msg_attachment
  15.549 +        bool* has_possible_pEp_msg
  15.550      )
  15.551  {
  15.552      PEP_STATUS status = PEP_STATUS_OK;
  15.553 @@ -2507,6 +2642,7 @@
  15.554      assert(mime);
  15.555      assert(msg);
  15.556  
  15.557 +    struct mailmime_fields *fields = mime->mm_mime_fields;
  15.558      struct mailmime_content *content = mime->mm_content_type;
  15.559      if (content) {
  15.560          if (_is_multipart(content, "alternative")) {
  15.561 @@ -2583,21 +2719,22 @@
  15.562                  return PEP_ILLEGAL_VALUE;
  15.563  
  15.564              clistiter *cur;
  15.565 -            // only add raise_msg_attachment on 2nd part!
  15.566 +            // only add has_possible_pEp_msg on 2nd part!
  15.567              int _att_count = 0;
  15.568              for (cur = clist_begin(partlist); cur; cur = clist_next(cur), _att_count++) {
  15.569                  struct mailmime *part= clist_content(cur);
  15.570                  if (part == NULL)
  15.571                      return PEP_ILLEGAL_VALUE;
  15.572 -                status = interpret_MIME(part, msg, _att_count == 1 ? raise_msg_attachment : NULL);
  15.573 +                status = interpret_MIME(part, msg, _att_count == 1 ? has_possible_pEp_msg : NULL);
  15.574                  if (status != PEP_STATUS_OK)
  15.575                      return status;
  15.576              }
  15.577          }
  15.578          else {
  15.579              if (_is_text_part(content, "html") &&
  15.580 -                msg->longmsg_formatted == NULL &&
  15.581 -                msg->longmsg == NULL) {
  15.582 +                    !_is_marked_as_attachment(fields) &&
  15.583 +                    msg->longmsg_formatted == NULL &&
  15.584 +                    msg->longmsg == NULL) {
  15.585                  status = interpret_body(mime, &msg->longmsg_formatted,
  15.586                                          NULL);
  15.587                  if (status)
  15.588 @@ -2609,21 +2746,23 @@
  15.589                      return status;
  15.590              }
  15.591              else if (_is_text_part(content, "plain") && 
  15.592 -                     msg->longmsg == NULL && msg->longmsg_formatted == NULL) {
  15.593 +                    !_is_marked_as_attachment(fields) &&
  15.594 +                    msg->longmsg == NULL && msg->longmsg_formatted == NULL) {
  15.595                  status = interpret_body(mime, &msg->longmsg, NULL);
  15.596                  if (status)
  15.597                      return status;
  15.598              }            
  15.599              else if (_is_text_part(content, NULL) && 
  15.600 -                     !_is_text_part(content, "plain") &&
  15.601 -                     msg->longmsg == NULL) {
  15.602 +                    !_is_marked_as_attachment(fields) &&
  15.603 +                    !_is_text_part(content, "plain") &&
  15.604 +                    msg->longmsg == NULL) {
  15.605                  status = interpret_body(mime, &msg->longmsg, NULL);
  15.606                  if (status)
  15.607                      return status;
  15.608              }
  15.609              else {
  15.610                  // Fixme - we need a control on recursion level here - KG: maybe NOT. We only go to depth 1.
  15.611 -                if (raise_msg_attachment != NULL) {
  15.612 +                if (has_possible_pEp_msg != NULL) {
  15.613                      bool is_msg = (_is_message_part(content, "rfc822") || _is_text_part(content, "rfc822"));
  15.614                      if (is_msg) {
  15.615                          if (content->ct_parameters) {
  15.616 @@ -2633,7 +2772,7 @@
  15.617                                  struct mailmime_parameter * param = clist_content(cur);
  15.618                                  if (param && param->pa_name && strcasecmp(param->pa_name, "forwarded") == 0) {
  15.619                                      if (param->pa_value && strcasecmp(param->pa_value, "no") == 0) {
  15.620 -                                        *raise_msg_attachment = true;
  15.621 +                                        *has_possible_pEp_msg = true;
  15.622                                          break;
  15.623                                      }
  15.624                                  }
  15.625 @@ -2727,18 +2866,8 @@
  15.626  DYNAMIC_API PEP_STATUS mime_decode_message(
  15.627          const char *mimetext,
  15.628          size_t size,
  15.629 -        message **msg
  15.630 -    )
  15.631 -{
  15.632 -    return _mime_decode_message_internal(mimetext, size, msg, NULL);
  15.633 -}        
  15.634 -
  15.635 -
  15.636 -PEP_STATUS _mime_decode_message_internal(
  15.637 -        const char *mimetext,
  15.638 -        size_t size,
  15.639          message **msg,
  15.640 -        bool* raise_msg_attachment
  15.641 +        bool* has_possible_pEp_msg
  15.642      )
  15.643  {
  15.644      PEP_STATUS status = PEP_STATUS_OK;
  15.645 @@ -2782,7 +2911,7 @@
  15.646  
  15.647      if (content) {
  15.648          status = interpret_MIME(mime->mm_data.mm_message.mm_msg_mime,
  15.649 -                _msg, raise_msg_attachment);
  15.650 +                _msg, has_possible_pEp_msg);
  15.651          if (status != PEP_STATUS_OK)
  15.652              goto pEp_error;
  15.653      }
    16.1 --- a/src/etpan_mime.h	Thu Apr 16 20:35:53 2020 +0200
    16.2 +++ b/src/etpan_mime.h	Mon Jun 08 15:01:34 2020 +0200
    16.3 @@ -35,7 +35,6 @@
    16.4          const char * mime_type,
    16.5          char * data,
    16.6          size_t length,
    16.7 -        bool transport_encode,
    16.8          bool set_attachment_forward_comment
    16.9      );
   16.10  
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/src/internal_format.c	Mon Jun 08 15:01:34 2020 +0200
    17.3 @@ -0,0 +1,164 @@
    17.4 +// This file is under GNU General Public License 3.0
    17.5 +// see LICENSE.txt
    17.6 +
    17.7 +#include "platform.h"
    17.8 +
    17.9 +#include "pEp_internal.h"
   17.10 +#include "internal_format.h"
   17.11 +
   17.12 +static struct _internal_message_type {
   17.13 +    char type;
   17.14 +    char subtype;
   17.15 +    const char *mime_type;
   17.16 +} message_type[] = {
   17.17 +    // Keys
   17.18 +    { 'K',  0, "application/keys" },
   17.19 +
   17.20 +    // OpenPGP
   17.21 +    { 'K',  2, "application/pgp-keys" },
   17.22 +
   17.23 +    // x.509
   17.24 +    { 'K',  3, "application/pkcs10" },
   17.25 +    { 'K',  4, "application/pkix-cert" },
   17.26 +    { 'K',  5, "application/pkix-crl" },
   17.27 +    { 'K',  6, "application/pkcs7-mime" },
   17.28 +    { 'K',  7, "application/x-x509-ca-cert" },
   17.29 +    { 'K',  8, "application/x-x509-user-cert" },
   17.30 +    { 'K',  9, "application/x-pkcs7-crl" },
   17.31 +    { 'K', 10, "application/x-pem-file" },
   17.32 +    { 'K', 11, "application/x-pkcs12" },
   17.33 +    { 'K', 12, "application/x-pkcs7-certificates" },
   17.34 +    { 'K', 13, "application/x-pkcs7-certreqresp" },
   17.35 +
   17.36 +    // Sync
   17.37 +    { 'S', 0, "application/pEp.sync" },
   17.38 +
   17.39 +    // Distribution
   17.40 +    { 'D', 0, "application/pEp.distribution" },
   17.41 +    { 'D', 0, "application/pEp.keyreset" },
   17.42 +
   17.43 +    // Authentication
   17.44 +    { 'A', 0, "application/auth" },
   17.45 +    { 'A', 1, "application/signature" },
   17.46 +
   17.47 +    // OpenPGP
   17.48 +    { 'A', 2, "application/pgp-signature" },
   17.49 +
   17.50 +    // x.509
   17.51 +    { 'A', 3, "application/pkcs7-signature" },
   17.52 +    { 'A', 3, "application/x-pkcs7-signature" },
   17.53 +    
   17.54 +    // end marker
   17.55 +    { 0, 0, NULL }
   17.56 +};
   17.57 +
   17.58 +DYNAMIC_API PEP_STATUS encode_internal(
   17.59 +        const char *value,
   17.60 +        size_t size,
   17.61 +        const char *mime_type,
   17.62 +        char **code,
   17.63 +        size_t *code_size
   17.64 +    )
   17.65 +{
   17.66 +    assert(value && size && mime_type && code && code_size);
   17.67 +    if (!(value && size && mime_type && code && code_size))
   17.68 +        return PEP_ILLEGAL_VALUE;
   17.69 +
   17.70 +    *code = NULL;
   17.71 +    *code_size = 0;
   17.72 +
   17.73 +    char type = 0;
   17.74 +    char subtype;
   17.75 +
   17.76 +    struct _internal_message_type *mt;
   17.77 +    for (mt = message_type; mt->type; ++mt) {
   17.78 +        if (strcasecmp(mime_type, mt->mime_type) == 0) {
   17.79 +            type = mt->type;
   17.80 +            subtype = mt->subtype;
   17.81 +            break;
   17.82 +        }
   17.83 +    }
   17.84 +
   17.85 +    // unsupported MIME type
   17.86 +    if (!type)
   17.87 +        return PEP_STATUS_OK;
   17.88 +
   17.89 +    // those are more BSOBs than BLOBS, so we copy
   17.90 +    char *result = malloc(size + 4);
   17.91 +    assert(result);
   17.92 +    if (!result)
   17.93 +        return PEP_OUT_OF_MEMORY;
   17.94 +
   17.95 +    result[0] = 0;
   17.96 +    result[1] = type;
   17.97 +    result[2] = subtype;
   17.98 +    result[3] = 0;
   17.99 +
  17.100 +    memcpy(result + 4, value, size);
  17.101 +    
  17.102 +    *code = result;
  17.103 +    *code_size = size + 4;
  17.104 +
  17.105 +    return PEP_STATUS_OK;
  17.106 +}
  17.107 +
  17.108 +DYNAMIC_API PEP_STATUS decode_internal(
  17.109 +        const char *code,
  17.110 +        size_t code_size,
  17.111 +        char **value,
  17.112 +        size_t *size,
  17.113 +        char **mime_type
  17.114 +    )
  17.115 +{
  17.116 +    assert(value && size && mime_type && code && !code[0] && code_size);
  17.117 +    if (!(value && size && mime_type && code && !code[0] && code_size))
  17.118 +        return PEP_ILLEGAL_VALUE;
  17.119 +
  17.120 +    *value = NULL;
  17.121 +    *size = 0;
  17.122 +    *mime_type = NULL;
  17.123 +
  17.124 +    // elevated attachments have at least 5 bytes
  17.125 +    assert(code_size > 4);
  17.126 +    if (code_size < 5)
  17.127 +        return PEP_ILLEGAL_VALUE;
  17.128 +
  17.129 +    assert(!code[0]);
  17.130 +    char type = code[1];
  17.131 +    char subtype = code[2];
  17.132 +    // char reserved = code[3];
  17.133 +
  17.134 +    char *_mime_type = NULL;
  17.135 +
  17.136 +    struct _internal_message_type *mt;
  17.137 +    for (mt = message_type; mt->type; ++mt) {
  17.138 +        if (type == mt->type && subtype == mt->subtype) {
  17.139 +            assert(mt->mime_type);
  17.140 +            _mime_type = strdup(mt->mime_type);
  17.141 +            assert(_mime_type);
  17.142 +            if (!_mime_type)
  17.143 +                return PEP_OUT_OF_MEMORY;
  17.144 +
  17.145 +            break;
  17.146 +        }
  17.147 +    }
  17.148 +
  17.149 +    if (!_mime_type)
  17.150 +        return PEP_ILLEGAL_VALUE;
  17.151 +
  17.152 +    char *result = malloc(code_size - 4);
  17.153 +    assert(result);
  17.154 +    if (!result) {
  17.155 +        free(_mime_type);
  17.156 +        return PEP_OUT_OF_MEMORY;
  17.157 +    }
  17.158 +
  17.159 +    memcpy(result, code + 4, code_size - 4);
  17.160 +
  17.161 +    *value = result;
  17.162 +    *size = code_size - 4;
  17.163 +    *mime_type = _mime_type;
  17.164 +
  17.165 +    return PEP_STATUS_OK;
  17.166 +}
  17.167 +
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/src/internal_format.h	Mon Jun 08 15:01:34 2020 +0200
    18.3 @@ -0,0 +1,72 @@
    18.4 +// This file is under GNU General Public License 3.0
    18.5 +// see LICENSE.txt
    18.6 +
    18.7 +#pragma once
    18.8 +
    18.9 +#include "message.h"
   18.10 +#include "cryptotech.h"
   18.11 +
   18.12 +#ifdef __cplusplus
   18.13 +extern "C" {
   18.14 +#endif
   18.15 +
   18.16 +// encode_internal() - encode to the internal message format
   18.17 +//
   18.18 +//  parameters:
   18.19 +//      value (in)          blob
   18.20 +//      size (in)           size of value
   18.21 +//      mime_type (in)      string of MIME type
   18.22 +//      code (out)          blob in Internal Message Format
   18.23 +//      code_size (out)     size of code
   18.24 +//
   18.25 +//  caveat:
   18.26 +//      call this for the data in an attachment
   18.27 +//
   18.28 +//      for unsupported MIME types this function is returning NULL for code and
   18.29 +//      does not fail
   18.30 +//
   18.31 +//      for supported MIME types this function is creating the internal message
   18.32 +//      format by copying the data in value
   18.33 +//
   18.34 +//      code goes into the ownership of the caller
   18.35 +//
   18.36 +//  see also:
   18.37 +//      https://dev.pep.foundation/Engine/ElevatedAttachments
   18.38 +
   18.39 +DYNAMIC_API PEP_STATUS encode_internal(
   18.40 +        const char *value,
   18.41 +        size_t size,
   18.42 +        const char *mime_type,
   18.43 +        char **code,
   18.44 +        size_t *code_size
   18.45 +    );
   18.46 +
   18.47 +
   18.48 +// decode_internal() - decode from internal message format
   18.49 +//
   18.50 +//  parameters:
   18.51 +//      code (in)           blob in Internal Message Format
   18.52 +//      code_size (in)      size of code
   18.53 +//      tech (in)           crypto tech for MIME type, PEP_crypt_none for auto
   18.54 +//      value (out)         blob or string for longmsg
   18.55 +//      size (out)          size of value
   18.56 +//      mime_type (out)     string with MIME type or NULL for longmsg
   18.57 +//
   18.58 +//  caveat:
   18.59 +//      this functions copies data from the code
   18.60 +//
   18.61 +//      value goes into the ownership of the caller
   18.62 +//      mime_type goes into the ownership of the caller
   18.63 +
   18.64 +DYNAMIC_API PEP_STATUS decode_internal(
   18.65 +        const char *code,
   18.66 +        size_t code_size,
   18.67 +        char **value,
   18.68 +        size_t *size,
   18.69 +        char **mime_type
   18.70 +    );
   18.71 +
   18.72 +
   18.73 +#ifdef __cplusplus
   18.74 +}
   18.75 +#endif
    19.1 --- a/src/key_reset.c	Thu Apr 16 20:35:53 2020 +0200
    19.2 +++ b/src/key_reset.c	Mon Jun 08 15:01:34 2020 +0200
    19.3 @@ -782,6 +782,16 @@
    19.4          if (is_me(session, curr_id))
    19.5              continue;
    19.6              
    19.7 +        // Also, don't bother to send it to non-pEp-users 
    19.8 +        bool pEp_user = false;
    19.9 +        status = is_pEp_user(session, curr_id, &pEp_user);
   19.10 +
   19.11 +        if (status != PEP_STATUS_OK)
   19.12 +            goto pEp_free;
   19.13 +
   19.14 +        if (!pEp_user)
   19.15 +            continue;
   19.16 +            
   19.17          // Check if they've already been told - this shouldn't be the case, but...
   19.18          bool contacted = false;
   19.19          status = has_key_reset_been_sent(session, from_ident->address, user_id, old_fpr, &contacted);
    20.1 --- a/src/keymanagement.c	Thu Apr 16 20:35:53 2020 +0200
    20.2 +++ b/src/keymanagement.c	Mon Jun 08 15:01:34 2020 +0200
    20.3 @@ -1061,12 +1061,20 @@
    20.4      assert(session);
    20.5      assert(identity);
    20.6      assert(!EMPTYSTR(identity->address));
    20.7 -    assert(!EMPTYSTR(identity->user_id));
    20.8  
    20.9 -    if (!session || !identity || EMPTYSTR(identity->address) ||
   20.10 -        EMPTYSTR(identity->user_id))
   20.11 +    if (!session || EMPTYSTR(identity->address))
   20.12          return PEP_ILLEGAL_VALUE;
   20.13  
   20.14 +    // this is leading to crashes otherwise
   20.15 +
   20.16 +    if (!(identity->user_id && identity->user_id[0])) {
   20.17 +        free(identity->user_id);
   20.18 +        identity->user_id = strdup(PEP_OWN_USERID);
   20.19 +        assert(identity->user_id);
   20.20 +        if (!identity->user_id)
   20.21 +            return PEP_OUT_OF_MEMORY;
   20.22 +    }
   20.23 +
   20.24      pEp_identity *stored_identity = NULL;
   20.25      char* revoked_fpr = NULL; 
   20.26      bool valid_key_found = false;
   20.27 @@ -2022,3 +2030,98 @@
   20.28      sqlite3_reset(session->is_mistrusted_key);
   20.29      return status;
   20.30  }
   20.31 +
   20.32 +static PEP_STATUS _wipe_default_key_if_invalid(PEP_SESSION session,
   20.33 +                                         pEp_identity* ident) {
   20.34 +    
   20.35 +    PEP_STATUS status = PEP_STATUS_OK;
   20.36 +    
   20.37 +    if (!ident->user_id)
   20.38 +        return PEP_ILLEGAL_VALUE;
   20.39 +        
   20.40 +    if (!ident->fpr)
   20.41 +        return status;
   20.42 +    
   20.43 +    char* cached_fpr = strdup(ident->fpr);
   20.44 +    if (!ident->fpr)
   20.45 +        return PEP_OUT_OF_MEMORY;
   20.46 +        
   20.47 +    PEP_STATUS keystatus = validate_fpr(session, ident, true, false);
   20.48 +    switch (keystatus) {
   20.49 +        case PEP_STATUS_OK:
   20.50 +            // Check for non-renewable expiry and 
   20.51 +            // if so, fallthrough
   20.52 +            if (ident->comm_type != PEP_ct_key_expired_but_confirmed &&
   20.53 +                    ident->comm_type != PEP_ct_key_expired) {
   20.54 +                break;
   20.55 +            }        
   20.56 +        case PEP_KEY_UNSUITABLE:
   20.57 +        case PEP_KEY_BLACKLISTED:
   20.58 +            // Remove key as default for all identities and users 
   20.59 +            status = remove_fpr_as_default(session, cached_fpr);
   20.60 +            break;   
   20.61 +        default:
   20.62 +            break;
   20.63 +    }     
   20.64 +    free(cached_fpr);
   20.65 +    
   20.66 +    if (status == PEP_STATUS_OK)
   20.67 +        status = myself(session, ident);
   20.68 +            
   20.69 +    return status;                                        
   20.70 +}
   20.71 +
   20.72 +PEP_STATUS clean_own_key_defaults(PEP_SESSION session) {
   20.73 +    identity_list* idents = NULL;
   20.74 +    PEP_STATUS status = own_identities_retrieve(session, &idents);
   20.75 +    if (status != PEP_STATUS_OK)
   20.76 +        return status;
   20.77 +        
   20.78 +    if (!idents)
   20.79 +        return PEP_STATUS_OK;
   20.80 +
   20.81 +    if (!idents->ident && !idents->next) {
   20.82 +        free_identity_list(idents);
   20.83 +        return PEP_STATUS_OK;
   20.84 +    } // Kludge: FIX own_identities_retrieve. Should return NULL, not empty list    
   20.85 +        
   20.86 +    identity_list* curr = idents;
   20.87 +    
   20.88 +    for ( ; curr ; curr = curr->next) {
   20.89 +        pEp_identity* ident = curr->ident;
   20.90 +        if (!ident)
   20.91 +            continue;
   20.92 +        
   20.93 +        _wipe_default_key_if_invalid(session, ident);    
   20.94 +    }   
   20.95 +    
   20.96 +    free_identity_list(idents);
   20.97 +    
   20.98 +    // Also remove invalid default user key
   20.99 +    char* own_id = NULL;
  20.100 +
  20.101 +    status = get_default_own_userid(session, &own_id);
  20.102 +
  20.103 +    if (status != PEP_STATUS_OK)
  20.104 +        return status;
  20.105 +
  20.106 +    if (own_id) {
  20.107 +        char* user_default_key = NULL;
  20.108 +        status = get_user_default_key(session, own_id, &user_default_key);
  20.109 +        if (status != PEP_STATUS_OK) {
  20.110 +            free(own_id);
  20.111 +            if (status == PEP_KEY_NOT_FOUND)
  20.112 +                status = PEP_STATUS_OK;
  20.113 +            else
  20.114 +                return status;
  20.115 +        }
  20.116 +        else if (user_default_key) {
  20.117 +            pEp_identity* empty_user = new_identity(NULL, user_default_key, NULL, own_id);
  20.118 +            _wipe_default_key_if_invalid(session, empty_user);       
  20.119 +            free(user_default_key);
  20.120 +        }
  20.121 +        free(own_id);    
  20.122 +    }
  20.123 +    return status;
  20.124 +}
  20.125 +
    21.1 --- a/src/keymanagement.h	Thu Apr 16 20:35:53 2020 +0200
    21.2 +++ b/src/keymanagement.h	Mon Jun 08 15:01:34 2020 +0200
    21.3 @@ -408,6 +408,8 @@
    21.4                              bool* is_address_default,
    21.5                              bool check_blacklist);
    21.6  
    21.7 +PEP_STATUS clean_own_key_defaults(PEP_SESSION session);
    21.8 +
    21.9  #ifdef __cplusplus
   21.10  }
   21.11  #endif
    22.1 --- a/src/message.h	Thu Apr 16 20:35:53 2020 +0200
    22.2 +++ b/src/message.h	Mon Jun 08 15:01:34 2020 +0200
    22.3 @@ -35,7 +35,8 @@
    22.4      PEP_enc_S_MIME,                         // RFC5751
    22.5      PEP_enc_PGP_MIME,                       // RFC3156
    22.6      PEP_enc_PEP,                            // pEp encryption format
    22.7 -    PEP_enc_PGP_MIME_Outlook1               // Message B0rken by Outlook type 1
    22.8 +    PEP_enc_PGP_MIME_Outlook1,              // Message B0rken by Outlook type 1
    22.9 +    PEP_enc_inline_EA
   22.10  } PEP_enc_format;
   22.11  
   22.12  struct _message_ref_list;
    23.1 --- a/src/message_api.c	Thu Apr 16 20:35:53 2020 +0200
    23.2 +++ b/src/message_api.c	Mon Jun 08 15:01:34 2020 +0200
    23.3 @@ -11,6 +11,7 @@
    23.4  #include "KeySync_fsm.h"
    23.5  #include "base64.h"
    23.6  #include "resource_id.h"
    23.7 +#include "internal_format.h"
    23.8  
    23.9  #include <assert.h>
   23.10  #include <string.h>
   23.11 @@ -70,8 +71,6 @@
   23.12          return "have_no_key";
   23.13      case PEP_rating_unencrypted:
   23.14          return "unencrypted";
   23.15 -    case PEP_rating_unencrypted_for_some: // don't use this any more
   23.16 -        return "undefined";
   23.17      case PEP_rating_unreliable:
   23.18          return "unreliable";
   23.19      case PEP_rating_reliable:
   23.20 @@ -923,7 +922,7 @@
   23.21                );
   23.22              
   23.23      /* Turn message into a MIME-blob */
   23.24 -    status = _mime_encode_message_internal(attachment, false, &message_text, true, false);
   23.25 +    status = mime_encode_message(attachment, false, &message_text, false);
   23.26          
   23.27      if (status != PEP_STATUS_OK)
   23.28          goto enomem;
   23.29 @@ -961,7 +960,7 @@
   23.30      if (status)
   23.31          return status;
   23.32  
   23.33 -    dst->enc_format = PEP_enc_inline;
   23.34 +    dst->enc_format = src->enc_format;
   23.35  
   23.36      // shortmsg is being copied
   23.37      if (src->shortmsg) {
   23.38 @@ -987,13 +986,81 @@
   23.39  
   23.40      dst->longmsg = _ctext;
   23.41  
   23.42 -    // longmsg_formatted is unsupported
   23.43 -
   23.44 -    // attachments are going unencrypted
   23.45 -    bloblist_t *bl = bloblist_dup(src->attachments);
   23.46 -    if (!bl)
   23.47 +    dst->attachments = new_bloblist(NULL, 0, NULL, NULL);
   23.48 +    if (!dst->attachments)
   23.49          return PEP_OUT_OF_MEMORY;
   23.50 -    dst->attachments = bl;
   23.51 +
   23.52 +    bloblist_t *ad = dst->attachments;
   23.53 +
   23.54 +    if (!EMPTYSTR(src->longmsg_formatted)) {
   23.55 +        status = encrypt_and_sign(session, keys, src->longmsg_formatted,
   23.56 +                strlen(src->longmsg_formatted), &ctext, &csize);
   23.57 +        if (status)
   23.58 +            return status;
   23.59 +
   23.60 +        char *_ctext = realloc(ctext, csize + 1);
   23.61 +        assert(_ctext);
   23.62 +        if (!_ctext)
   23.63 +            return PEP_OUT_OF_MEMORY;
   23.64 +        _ctext[csize] = 0;
   23.65 +
   23.66 +        ad = bloblist_add(ad, _ctext, csize + 1, "text/html", NULL);
   23.67 +        if (!ad)
   23.68 +            return PEP_OUT_OF_MEMORY;
   23.69 +
   23.70 +        ad->disposition = PEP_CONTENT_DISP_INLINE;
   23.71 +    }
   23.72 +
   23.73 +    if (src->attachments && src->attachments->value) {
   23.74 +        bloblist_t *as;
   23.75 +        for (as = src->attachments; as && as->value; as = as->next) {
   23.76 +            char *value = NULL;
   23.77 +            size_t size = 0;
   23.78 +            if (src->enc_format == PEP_enc_inline_EA) {
   23.79 +                status = encode_internal(as->value, as->size, as->mime_type,
   23.80 +                        &value, &size);
   23.81 +                if (status)
   23.82 +                    return status;
   23.83 +                if (!value) {
   23.84 +                    value = as->value;
   23.85 +                    size = as->size;
   23.86 +                }
   23.87 +            }
   23.88 +            else {
   23.89 +                value = as->value;
   23.90 +                size = as->size;
   23.91 +            }
   23.92 +            status = encrypt_and_sign(session, keys, value, size, &ctext,
   23.93 +                    &csize);
   23.94 +            if (value != as->value)
   23.95 +                free(value);
   23.96 +            if (status)
   23.97 +                return status;
   23.98 +
   23.99 +            char *_ctext = realloc(ctext, csize + 1);
  23.100 +            assert(_ctext);
  23.101 +            if (!_ctext)
  23.102 +                return PEP_OUT_OF_MEMORY;
  23.103 +            _ctext[csize] = 0;
  23.104 +
  23.105 +            size_t len = strlen(as->filename);
  23.106 +            char *filename = malloc(len + 5);
  23.107 +            assert(filename);
  23.108 +            if (!filename)
  23.109 +                return PEP_OUT_OF_MEMORY;
  23.110 +
  23.111 +            memcpy(filename, as->filename, len);
  23.112 +            memcpy(filename + len, ".pgp", 5);
  23.113 +
  23.114 +            ad = bloblist_add(ad, _ctext, csize + 1, "application/octet-stream", filename);
  23.115 +            free(filename);
  23.116 +            filename = NULL;
  23.117 +            if (!ad)
  23.118 +                return PEP_OUT_OF_MEMORY;
  23.119 +
  23.120 +            ad->disposition = as->disposition;
  23.121 +        }
  23.122 +    }
  23.123  
  23.124      return PEP_STATUS_OK;
  23.125  }
  23.126 @@ -1029,10 +1096,8 @@
  23.127      _src->attachments = src->attachments;
  23.128      _src->enc_format = PEP_enc_none;
  23.129      
  23.130 -    // These vars are here to be clear, and because I don't know how this may change in the near future.
  23.131      bool wrapped = (wrap_type != PEP_message_unwrapped);
  23.132 -    bool mime_encode = !wrapped;
  23.133 -    status = _mime_encode_message_internal(_src, true, &mimetext, mime_encode, wrapped);
  23.134 +    status = mime_encode_message(_src, true, &mimetext, wrapped);
  23.135      assert(status == PEP_STATUS_OK);
  23.136      if (status != PEP_STATUS_OK)
  23.137          goto pEp_error;
  23.138 @@ -1316,11 +1381,12 @@
  23.139      if (max_comm_type == PEP_ct_mistrusted)
  23.140          return PEP_ct_mistrusted;
  23.141  
  23.142 -    if (!is_me(session, ident))
  23.143 +    if (!is_me(session, ident)) {
  23.144          status = update_identity(session, ident);
  23.145 -    else
  23.146 -        // ???
  23.147 +    }
  23.148 +    else {
  23.149          status = _myself(session, ident, false, false, true);
  23.150 +    }
  23.151  
  23.152      if (status == PEP_STATUS_OK) {
  23.153          if (ident->comm_type == PEP_ct_compromised)
  23.154 @@ -1615,7 +1681,8 @@
  23.155      assert(msg);
  23.156  
  23.157      if (is_PGP_message_text(msg->longmsg)) {
  23.158 -        msg->enc_format = PEP_enc_inline;
  23.159 +        if (msg->enc_format != PEP_enc_inline_EA)
  23.160 +            msg->enc_format = PEP_enc_inline;
  23.161          return PEP_crypt_OpenPGP;
  23.162      }
  23.163      else if (msg->attachments && msg->attachments->next &&
  23.164 @@ -1950,7 +2017,7 @@
  23.165              
  23.166          // FIXME - we need to deal with transport types (via flag)
  23.167          message_wrap_type wrap_type = PEP_message_unwrapped;
  23.168 -        if ((enc_format != PEP_enc_inline) && (!force_v_1) && ((max_comm_type | PEP_ct_confirmed) == PEP_ct_pEp)) {
  23.169 +        if ((enc_format != PEP_enc_inline) && (enc_format != PEP_enc_inline_EA) && (!force_v_1) && ((max_comm_type | PEP_ct_confirmed) == PEP_ct_pEp)) {
  23.170              wrap_type = ((flags & PEP_encrypt_flag_key_reset_only) ? PEP_message_key_reset : PEP_message_default);
  23.171              _src = wrap_message_as_attachment(NULL, src, wrap_type, false, extra, max_version_major, max_version_minor);
  23.172              if (!_src)
  23.173 @@ -1958,7 +2025,7 @@
  23.174          }
  23.175          else {
  23.176              // hide subject
  23.177 -            if (enc_format != PEP_enc_inline) {
  23.178 +            if (enc_format != PEP_enc_inline && enc_format != PEP_enc_inline_EA) {
  23.179                  status = replace_subject(_src);
  23.180                  if (status == PEP_OUT_OF_MEMORY)
  23.181                      goto enomem;
  23.182 @@ -1980,6 +2047,8 @@
  23.183                  break;
  23.184  
  23.185              case PEP_enc_inline:
  23.186 +            case PEP_enc_inline_EA:
  23.187 +                _src->enc_format = enc_format;
  23.188                  status = encrypt_PGP_inline(session, _src, keys, msg, flags);
  23.189                  break;
  23.190  
  23.191 @@ -2318,6 +2387,8 @@
  23.192              break;
  23.193  
  23.194          case PEP_enc_inline:
  23.195 +        case PEP_enc_inline_EA:
  23.196 +            _src->enc_format = enc_format;
  23.197              status = encrypt_PGP_inline(session, _src, keys, msg, flags);
  23.198              break;
  23.199  
  23.200 @@ -2669,6 +2740,7 @@
  23.201      switch (src->enc_format) {
  23.202          case PEP_enc_PGP_MIME:
  23.203          case PEP_enc_inline:
  23.204 +        case PEP_enc_inline_EA:
  23.205          case PEP_enc_PGP_MIME_Outlook1:
  23.206  //        case PEP_enc_none: // FIXME - this is wrong
  23.207  
  23.208 @@ -2779,6 +2851,7 @@
  23.209          break;
  23.210  
  23.211          case PEP_enc_inline:
  23.212 +        case PEP_enc_inline_EA:
  23.213              *crypto_text = src->longmsg;
  23.214              *text_size = strlen(*crypto_text);
  23.215              break;
  23.216 @@ -2926,8 +2999,13 @@
  23.217                          if (!has_uri_prefix)
  23.218                              filename_uri = build_uri("file", pgp_filename);
  23.219  
  23.220 -                        _m = bloblist_add(_m, ptext, psize, mime_type,
  23.221 -                             (filename_uri ? filename_uri : pgp_filename));
  23.222 +                        char *_filename = filename_uri ? filename_uri : pgp_filename;
  23.223 +                        if (strcasecmp(_filename, "file://distribution.pEp") == 0)
  23.224 +                            _m = bloblist_add(_m, ptext, psize, "application/pEp.distribution", _filename);
  23.225 +                        else if (strcasecmp(_filename, "file://sync.pEp") == 0)
  23.226 +                            _m = bloblist_add(_m, ptext, psize, "application/pEp.sync", _filename);
  23.227 +                        else
  23.228 +                            _m = bloblist_add(_m, ptext, psize, mime_type, _filename);
  23.229  
  23.230                          free(pgp_filename);
  23.231                          free(filename_uri);
  23.232 @@ -2943,8 +3021,14 @@
  23.233                          if (!has_uri_prefix)
  23.234                              filename_uri = build_uri("file", filename);
  23.235  
  23.236 -                        _m = bloblist_add(_m, ptext, psize, mime_type,
  23.237 -                             (filename_uri ? filename_uri : filename));
  23.238 +                        char *_filename = filename_uri ? filename_uri : filename;
  23.239 +                        if (strcasecmp(_filename, "file://distribution.pEp") == 0)
  23.240 +                            _m = bloblist_add(_m, ptext, psize, "application/pEp.distribution", _filename);
  23.241 +                        else if (strcasecmp(_filename, "file://sync.pEp") == 0)
  23.242 +                            _m = bloblist_add(_m, ptext, psize, "application/pEp.sync", _filename);
  23.243 +                        else
  23.244 +                            _m = bloblist_add(_m, ptext, psize, mime_type, _filename);
  23.245 +
  23.246                          free(filename);
  23.247                          free(filename_uri);
  23.248                          if (_m == NULL)
  23.249 @@ -3212,8 +3296,11 @@
  23.250  
  23.251      PEP_STATUS status = PEP_STATUS_OK;
  23.252      
  23.253 -    if (strcasecmp(src->from->address, inner_message->from->address) == 0)
  23.254 +    if (src->from && inner_message->from && 
  23.255 +           src->from->address && inner_message->from->address && 
  23.256 +           strcasecmp(src->from->address, inner_message->from->address) == 0) {
  23.257          status = reconcile_identity(src->from, inner_message->from);
  23.258 +    }    
  23.259      
  23.260      if (status == PEP_STATUS_OK && inner_message->to)
  23.261          status = reconcile_identity_lists(src->to, inner_message->to);
  23.262 @@ -3607,13 +3694,8 @@
  23.263          return status;
  23.264          
  23.265      /** Ok, we should be ready to decrypt. Try decrypt and verify first! **/
  23.266 -    status = cryptotech[crypto].decrypt_and_verify(session, ctext,
  23.267 -                                                   csize, dsig_text, dsig_size,
  23.268 -                                                   &ptext, &psize, &_keylist,
  23.269 -                                                   NULL);
  23.270 -
  23.271 -    if (status == PEP_DECRYPT_NO_KEY)
  23.272 -        signal_Sync_event(session, Sync_PR_keysync, CannotDecrypt, NULL);
  23.273 +    status = decrypt_and_verify(session, ctext, csize, dsig_text, dsig_size,
  23.274 +            &ptext, &psize, &_keylist, NULL);
  23.275  
  23.276      if (status > PEP_CANNOT_DECRYPT_UNKNOWN)
  23.277          goto pEp_error;
  23.278 @@ -3631,7 +3713,7 @@
  23.279              case PEP_enc_PGP_MIME:
  23.280              case PEP_enc_PGP_MIME_Outlook1:
  23.281              
  23.282 -                status = _mime_decode_message_internal(ptext, psize, &msg, &has_inner);
  23.283 +                status = mime_decode_message(ptext, psize, &msg, &has_inner);
  23.284                  if (status != PEP_STATUS_OK)
  23.285                      goto pEp_error;
  23.286                                  
  23.287 @@ -3672,8 +3754,9 @@
  23.288                  break;
  23.289  
  23.290              case PEP_enc_inline:
  23.291 +            case PEP_enc_inline_EA:
  23.292 +            {
  23.293                  status = PEP_STATUS_OK;
  23.294 -                
  23.295                  _decrypt_in_pieces_status = _decrypt_in_pieces(session, src, &msg, ptext, psize);
  23.296              
  23.297                  switch (_decrypt_in_pieces_status) {
  23.298 @@ -3688,12 +3771,47 @@
  23.299                          goto enomem;
  23.300                      default:
  23.301                          decrypt_status = _decrypt_in_pieces_status;
  23.302 -                        break;
  23.303 +                }
  23.304 +
  23.305 +                if (src->enc_format == PEP_enc_inline_EA) {
  23.306 +                    char *value;
  23.307 +                    size_t size;
  23.308 +                    char *mime_type;
  23.309 +                    const char *filename = NULL;
  23.310 +                    status = decode_internal(ptext, psize, &value, &size, &mime_type);
  23.311 +                    if (status)
  23.312 +                        goto pEp_error;
  23.313 +                    if (strcasecmp(mime_type, "application/pEp.sync") == 0)
  23.314 +                        filename = "file://sync.pEp";
  23.315 +                    else if (strcasecmp(mime_type, "application/pEp.distribution") == 0)
  23.316 +                        filename = "file://distribution.pEp";
  23.317 +                    else if (strcasecmp(mime_type, "application/pgp-keys") == 0)
  23.318 +                        filename = "file://pEpkey.asc";
  23.319 +                    else if (strcasecmp(mime_type, "application/pgp-signature") == 0)
  23.320 +                        filename = "file://electronic_signature.asc";
  23.321 +                    bloblist_t *bl = new_bloblist(value, size, mime_type, filename);
  23.322 +                    free(mime_type);
  23.323 +                    if (bl) {
  23.324 +                        msg->attachments = bl;
  23.325 +                        if (msg->longmsg != ptext)
  23.326 +                            free(msg->longmsg);
  23.327 +                        msg->longmsg = NULL;
  23.328 +                        free(ptext);
  23.329 +                        ptext = NULL;
  23.330 +                        psize = 0;
  23.331 +                    }
  23.332 +                    else {
  23.333 +                        free(value);
  23.334 +                        status = PEP_OUT_OF_MEMORY;
  23.335 +                        goto pEp_error;
  23.336 +                    }
  23.337                  }
  23.338                  break;
  23.339 +
  23.340              default:
  23.341                  // BUG: must implement more
  23.342                  NOT_IMPLEMENTED
  23.343 +            }
  23.344          }
  23.345  
  23.346          if (status == PEP_OUT_OF_MEMORY)
  23.347 @@ -3766,7 +3884,8 @@
  23.348                  if (message_blob) {              
  23.349                      status = mime_decode_message(message_blob->value, 
  23.350                                                   message_blob->size, 
  23.351 -                                                 &inner_message);
  23.352 +                                                 &inner_message,
  23.353 +                                                 NULL);
  23.354                      if (status != PEP_STATUS_OK)
  23.355                          goto pEp_error;
  23.356                                  
  23.357 @@ -3918,30 +4037,30 @@
  23.358                  
  23.359              } // this we do if this isn't an inner message
  23.360              
  23.361 -            pEp_identity* cs_from = calculated_src->from;
  23.362 -            if (cs_from && !EMPTYSTR(cs_from->address)) {
  23.363 -                if (!is_me(session, cs_from)) {
  23.364 -                    status = update_identity(session, cs_from);
  23.365 +            pEp_identity* msg_from = msg->from;
  23.366 +            if (msg_from && !EMPTYSTR(msg_from->address)) {
  23.367 +                if (!is_me(session, msg_from)) {
  23.368 +                    status = update_identity(session, msg_from);
  23.369                      if (status == PEP_CANNOT_FIND_IDENTITY) {
  23.370 -                        cs_from->user_id = calloc(1, strlen(cs_from->address) + 6);
  23.371 -                        if (!cs_from->user_id)
  23.372 +                        msg_from->user_id = calloc(1, strlen(msg_from->address) + 6);
  23.373 +                        if (!msg_from->user_id)
  23.374                              return PEP_OUT_OF_MEMORY;
  23.375 -                        snprintf(cs_from->user_id, strlen(cs_from->address) + 6,
  23.376 -                                 "TOFU_%s", cs_from->address);        
  23.377 +                        snprintf(msg_from->user_id, strlen(msg_from->address) + 6,
  23.378 +                                 "TOFU_%s", msg_from->address);        
  23.379                          status = PEP_STATUS_OK;
  23.380                      }
  23.381                  }
  23.382                  else {
  23.383                      // update the own from identity, read_only, but preserve username 
  23.384                      // for returned message.
  23.385 -                    char* cached_ownname = cs_from->username;
  23.386 +                    char* cached_ownname = msg_from->username;
  23.387                      // Shouldn't be possible, but just in case.
  23.388                      if (!cached_ownname)
  23.389 -                        cached_ownname = strdup(cs_from->address);
  23.390 -                    cs_from->username = NULL;
  23.391 -                    status = _myself(session, cs_from, false, false, myself_read_only);
  23.392 -                    free(cs_from->username);
  23.393 -                    cs_from->username = cached_ownname;
  23.394 +                        cached_ownname = strdup(msg_from->address);
  23.395 +                    msg_from->username = NULL;
  23.396 +                    status = _myself(session, msg_from, false, false, myself_read_only);
  23.397 +                    free(msg_from->username);
  23.398 +                    msg_from->username = cached_ownname;
  23.399                  }    
  23.400              }                                                                        
  23.401          } // end if (decrypt_status == PEP_DECRYPTED || decrypt_status == PEP_DECRYPTED_AND_VERIFIED)
  23.402 @@ -3952,7 +4071,7 @@
  23.403          // eligible signer comm_types to PEP_ct_pEp_*
  23.404          // This also sets and upgrades pEp version
  23.405          if (decrypt_status == PEP_DECRYPTED_AND_VERIFIED && !is_key_reset && is_pEp_msg && calculated_src->from)
  23.406 -            status = update_sender_to_pEp_trust(session, calculated_src->from, _keylist, major_ver, minor_ver);
  23.407 +            status = update_sender_to_pEp_trust(session, msg->from, _keylist, major_ver, minor_ver);
  23.408  
  23.409          /* Ok, now we have a keylist used for decryption/verification.
  23.410             now we need to update the message rating with the 
  23.411 @@ -3960,7 +4079,7 @@
  23.412             
  23.413          if (!is_key_reset) { // key reset messages invalidate some of the ratings in the DB by now.
  23.414              status = amend_rating_according_to_sender_and_recipients(session,
  23.415 -                     rating, calculated_src->from, _keylist);
  23.416 +                     rating, msg->from, _keylist);
  23.417              if (status != PEP_STATUS_OK)
  23.418                  goto pEp_error;
  23.419           
  23.420 @@ -4019,98 +4138,107 @@
  23.421          }
  23.422      } // End prepare output message for return
  23.423  
  23.424 -    // 3. Check to see if the sender used any of our revoked keys
  23.425 -    if (!is_me(session, msg->from)) {
  23.426 -        status = check_for_own_revoked_key(session, _keylist, &revoke_replace_pairs);
  23.427 -
  23.428 -        //assert(status != PEP_STATUS_OK); // FIXME: FOR DEBUGGING ONLY DO NOT LEAVE IN    
  23.429 -        if (status != PEP_STATUS_OK) {
  23.430 -            // This should really never choke unless the DB is broken.
  23.431 -            status = PEP_UNKNOWN_DB_ERROR;
  23.432 -            goto pEp_error;
  23.433 -        }
  23.434 -        
  23.435 -        if (msg) {
  23.436 -            stringpair_list_t* curr_pair_node;
  23.437 -            stringpair_t* curr_pair;
  23.438 -
  23.439 -            for (curr_pair_node = revoke_replace_pairs; curr_pair_node; curr_pair_node = curr_pair_node->next) {
  23.440 -                curr_pair = curr_pair_node->value;
  23.441 -
  23.442 -                if (!curr_pair)
  23.443 -                    continue; // Again, shouldn't occur
  23.444 -
  23.445 -                if (curr_pair->key && curr_pair->value) {
  23.446 -                    /* Figure out which address(es) this came to so we know who to reply from */                    
  23.447 -
  23.448 -                    identity_list* my_rev_ids = NULL;
  23.449 -                    
  23.450 -                    /* check by replacement ID for identities which used this key? */
  23.451 -                    status = get_identities_by_main_key_id(session, curr_pair->value,
  23.452 -                                                           &my_rev_ids);
  23.453 -                                                                                                                      
  23.454 -                    if (status == PEP_STATUS_OK && my_rev_ids) {
  23.455 -                        // get identities in this list the message was to/cc'd to (not for bcc)
  23.456 -                        identity_list* used_ids_for_key = NULL;
  23.457 -                        status = ident_list_intersect(my_rev_ids, msg->to, &used_ids_for_key);
  23.458 -                        if (status != PEP_STATUS_OK)
  23.459 -                            goto pEp_error; // out of memory
  23.460 -
  23.461 -                        identity_list* used_cc_ids = NULL;    
  23.462 -                        status = ident_list_intersect(my_rev_ids, msg->cc, &used_cc_ids);
  23.463 -                        if (status != PEP_STATUS_OK)
  23.464 -                            goto pEp_error;
  23.465 -
  23.466 -                        used_ids_for_key = identity_list_join(used_ids_for_key, used_cc_ids);
  23.467 -                        
  23.468 -                        identity_list* curr_recip = used_ids_for_key;
  23.469 -                        
  23.470 -                        for ( ; curr_recip && curr_recip->ident; curr_recip = curr_recip->next) {
  23.471 -                            if (!is_me(session, curr_recip->ident))
  23.472 -                                continue;
  23.473 -                        
  23.474 -                            status = create_standalone_key_reset_message(session,
  23.475 -                                &reset_msg,
  23.476 -                                curr_recip->ident,
  23.477 -                                msg->from,
  23.478 -                                curr_pair->key,
  23.479 -                                curr_pair->value);
  23.480 -
  23.481 -                            // If we can't find the identity, this is someone we've never mailed, so we just
  23.482 -                            // go on letting them use the wrong key until we mail them ourselves. (Spammers, etc)
  23.483 -                            if (status != PEP_CANNOT_FIND_IDENTITY) {
  23.484 +    // 3. Check to see if the sender is a pEp user who used any of our revoked keys
  23.485 +    if (msg->from && !is_me(session, msg->from)) {
  23.486 +        bool pEp_peep = false;
  23.487 +
  23.488 +        if (!EMPTYSTR(msg->from->user_id)) {
  23.489 +            status = is_pEp_user(session, msg->from, &pEp_peep);
  23.490 +            
  23.491 +            // If it's a pEp user, check if there was a revoked key used so we can notify
  23.492 +            if (pEp_peep) {
  23.493 +                status = check_for_own_revoked_key(session, _keylist, &revoke_replace_pairs);
  23.494 +
  23.495 +                //assert(status != PEP_STATUS_OK); // FIXME: FOR DEBUGGING ONLY DO NOT LEAVE IN    
  23.496 +                if (status != PEP_STATUS_OK) {
  23.497 +                    // This should really never choke unless the DB is broken.
  23.498 +                    status = PEP_UNKNOWN_DB_ERROR;
  23.499 +                    goto pEp_error;
  23.500 +                }
  23.501 +                
  23.502 +                if (msg) {
  23.503 +                    stringpair_list_t* curr_pair_node;
  23.504 +                    stringpair_t* curr_pair;
  23.505 +
  23.506 +                    for (curr_pair_node = revoke_replace_pairs; curr_pair_node; curr_pair_node = curr_pair_node->next) {
  23.507 +                        curr_pair = curr_pair_node->value;
  23.508 +
  23.509 +                        if (!curr_pair)
  23.510 +                            continue; // Again, shouldn't occur
  23.511 +
  23.512 +                        if (curr_pair->key && curr_pair->value) {
  23.513 +                            /* Figure out which address(es) this came to so we know who to reply from */                    
  23.514 +
  23.515 +                            identity_list* my_rev_ids = NULL;
  23.516 +                            
  23.517 +                            /* check by replacement ID for identities which used this key? */
  23.518 +                            status = get_identities_by_main_key_id(session, curr_pair->value,
  23.519 +                                                                   &my_rev_ids);
  23.520 +                                                                                                                              
  23.521 +                            if (status == PEP_STATUS_OK && my_rev_ids) {
  23.522 +                                // get identities in this list the message was to/cc'd to (not for bcc)
  23.523 +                                identity_list* used_ids_for_key = NULL;
  23.524 +                                status = ident_list_intersect(my_rev_ids, msg->to, &used_ids_for_key);
  23.525 +                                if (status != PEP_STATUS_OK)
  23.526 +                                    goto pEp_error; // out of memory
  23.527 +
  23.528 +                                identity_list* used_cc_ids = NULL;    
  23.529 +                                status = ident_list_intersect(my_rev_ids, msg->cc, &used_cc_ids);
  23.530                                  if (status != PEP_STATUS_OK)
  23.531                                      goto pEp_error;
  23.532  
  23.533 -                                if (!reset_msg) {
  23.534 -                                    status = PEP_OUT_OF_MEMORY;
  23.535 -                                    goto pEp_error;
  23.536 -                                }
  23.537 -                                // insert into queue
  23.538 -                                if (session->messageToSend)
  23.539 -                                    status = session->messageToSend(reset_msg);
  23.540 -                                else
  23.541 -                                    status = PEP_SYNC_NO_MESSAGE_SEND_CALLBACK;
  23.542 -
  23.543 -
  23.544 -                                if (status == PEP_STATUS_OK) {
  23.545 -                                    // Put into notified DB
  23.546 -                                    status = set_reset_contact_notified(session, curr_recip->ident->address, curr_pair->key, msg->from->user_id);
  23.547 -                                    if (status != PEP_STATUS_OK) // It's ok to barf because it's a DB problem??
  23.548 -                                        goto pEp_error;
  23.549 -                                }
  23.550 -                                else {
  23.551 -                                    // According to Volker, this would only be a fatal error, so...
  23.552 -                                    free_message(reset_msg); // ??
  23.553 -                                    reset_msg = NULL; // ??
  23.554 -                                    goto pEp_error;
  23.555 -                                }
  23.556 -                            }
  23.557 -                        }    
  23.558 -                    } // else we couldn't find an ident for replacement key    
  23.559 +                                used_ids_for_key = identity_list_join(used_ids_for_key, used_cc_ids);
  23.560 +                                
  23.561 +                                identity_list* curr_recip = used_ids_for_key;
  23.562 +                                
  23.563 +                                for ( ; curr_recip && curr_recip->ident; curr_recip = curr_recip->next) {
  23.564 +                                    if (!is_me(session, curr_recip->ident))
  23.565 +                                        continue;
  23.566 +                                
  23.567 +                                    status = create_standalone_key_reset_message(session,
  23.568 +                                        &reset_msg,
  23.569 +                                        curr_recip->ident,
  23.570 +                                        msg->from,
  23.571 +                                        curr_pair->key,
  23.572 +                                        curr_pair->value);
  23.573 +
  23.574 +                                    // If we can't find the identity, this is someone we've never mailed, so we just
  23.575 +                                    // go on letting them use the wrong key until we mail them ourselves. (Spammers, etc)
  23.576 +                                    if (status != PEP_CANNOT_FIND_IDENTITY) {
  23.577 +                                        if (status != PEP_STATUS_OK)
  23.578 +                                            goto pEp_error;
  23.579 +
  23.580 +                                        if (!reset_msg) {
  23.581 +                                            status = PEP_OUT_OF_MEMORY;
  23.582 +                                            goto pEp_error;
  23.583 +                                        }
  23.584 +                                        // insert into queue
  23.585 +                                        if (session->messageToSend)
  23.586 +                                            status = session->messageToSend(reset_msg);
  23.587 +                                        else
  23.588 +                                            status = PEP_SYNC_NO_MESSAGE_SEND_CALLBACK;
  23.589 +
  23.590 +
  23.591 +                                        if (status == PEP_STATUS_OK) {
  23.592 +                                            // Put into notified DB
  23.593 +                                            status = set_reset_contact_notified(session, curr_recip->ident->address, curr_pair->key, msg->from->user_id);
  23.594 +                                            if (status != PEP_STATUS_OK) // It's ok to barf because it's a DB problem??
  23.595 +                                                goto pEp_error;
  23.596 +                                        }
  23.597 +                                        else {
  23.598 +                                            // According to Volker, this would only be a fatal error, so...
  23.599 +                                            free_message(reset_msg); // ??
  23.600 +                                            reset_msg = NULL; // ??
  23.601 +                                            goto pEp_error;
  23.602 +                                        }
  23.603 +                                    }
  23.604 +                                }    
  23.605 +                            } // else we couldn't find an ident for replacement key    
  23.606 +                        }
  23.607 +                    }        
  23.608                  }
  23.609              }
  23.610 -        }
  23.611 +        }    
  23.612          free_stringpair_list(revoke_replace_pairs);
  23.613          revoke_replace_pairs = NULL;
  23.614      } // end !is_me(msg->from)    
  23.615 @@ -4204,6 +4332,27 @@
  23.616          }
  23.617      }
  23.618      
  23.619 +    // by convention
  23.620 +
  23.621 +    if (EMPTYSTR(msg->shortmsg) && EMPTYSTR(msg->longmsg) && EMPTYSTR(msg->longmsg_formatted)) {
  23.622 +        free(msg->shortmsg);
  23.623 +        msg->shortmsg = strdup("pEp");
  23.624 +        assert(msg->shortmsg);
  23.625 +        if (!msg->shortmsg)
  23.626 +            goto enomem;
  23.627 +
  23.628 +        if (src->enc_format == PEP_enc_inline_EA) {
  23.629 +            stringpair_t *entry = new_stringpair("pEp-auto-consume", "yes");
  23.630 +            if (!entry)
  23.631 +                goto enomem;
  23.632 +            stringpair_list_t * spl = stringpair_list_add(msg->opt_fields, entry);
  23.633 +            if (!spl)
  23.634 +                goto enomem;
  23.635 +            if (!msg->opt_fields)
  23.636 +                msg->opt_fields = spl;
  23.637 +        }
  23.638 +    }
  23.639 +
  23.640      // 5. Set up return values
  23.641      *dst = msg;
  23.642      *keylist = _keylist;
  23.643 @@ -4260,7 +4409,6 @@
  23.644  
  23.645      if (!(*flags & PEP_decrypt_flag_untrusted_server))
  23.646          *keylist = NULL;
  23.647 -    //*keylist = NULL; // NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO!!!!!! This fucks up reencryption
  23.648      PEP_STATUS status = _decrypt_message(session, src, dst, keylist, rating, flags, NULL);
  23.649  
  23.650      message *msg = *dst ? *dst : src;
  23.651 @@ -4325,7 +4473,7 @@
  23.652      message *dst = NULL;
  23.653      stringlist_t *keylist = NULL;
  23.654      PEP_rating rating;
  23.655 -    PEP_decrypt_flags_t flags;
  23.656 +    PEP_decrypt_flags_t flags = PEP_decrypt_flag_dont_trigger_sync;
  23.657  
  23.658      *ident = NULL;
  23.659  
    24.1 --- a/src/message_api.h	Thu Apr 16 20:35:53 2020 +0200
    24.2 +++ b/src/message_api.h	Mon Jun 08 15:01:34 2020 +0200
    24.3 @@ -47,7 +47,6 @@
    24.4      // This flag is used to let internal functions know that an encryption 
    24.5      // call is being used as part of a reencryption operation
    24.6      PEP_encrypt_reencrypt = 0x40
    24.7 -    
    24.8  } PEP_encrypt_flags; 
    24.9  
   24.10  typedef unsigned int PEP_encrypt_flags_t;
   24.11 @@ -83,6 +82,13 @@
   24.12  //  caveat:
   24.13  //      the ownership of src remains with the caller
   24.14  //      the ownership of dst goes to the caller
   24.15 +//
   24.16 +//      enc_format PEP_enc_inline_EA:
   24.17 +//          internal format of the encrypted attachments is changing, see
   24.18 +//          https://dev.pep.foundation/Engine/ElevatedAttachments
   24.19 +//
   24.20 +//          Only use this for transports without support for attachments
   24.21 +//          when attached data must be sent inline
   24.22  
   24.23  DYNAMIC_API PEP_STATUS encrypt_message(
   24.24          PEP_SESSION session,
   24.25 @@ -169,26 +175,26 @@
   24.26  
   24.27      // no color
   24.28  
   24.29 -    PEP_rating_cannot_decrypt,
   24.30 -    PEP_rating_have_no_key,
   24.31 -    PEP_rating_unencrypted,
   24.32 -    PEP_rating_unencrypted_for_some, // don't use this any more
   24.33 -    PEP_rating_unreliable,
   24.34 +    PEP_rating_cannot_decrypt = 1,
   24.35 +    PEP_rating_have_no_key = 2,
   24.36 +    PEP_rating_unencrypted = 3,
   24.37 +    PEP_rating_unreliable = 5,
   24.38 +
   24.39 +    PEP_rating_b0rken = -2,
   24.40  
   24.41      // yellow
   24.42  
   24.43 -    PEP_rating_reliable,
   24.44 +    PEP_rating_reliable = 6,
   24.45  
   24.46      // green
   24.47  
   24.48 -    PEP_rating_trusted,
   24.49 -    PEP_rating_trusted_and_anonymized,
   24.50 -    PEP_rating_fully_anonymous,   
   24.51 +    PEP_rating_trusted = 7,
   24.52 +    PEP_rating_trusted_and_anonymized = 8,
   24.53 +    PEP_rating_fully_anonymous = 9, 
   24.54  
   24.55      // red
   24.56  
   24.57      PEP_rating_mistrust = -1,
   24.58 -    PEP_rating_b0rken = -2,
   24.59      PEP_rating_under_attack = -3
   24.60  } PEP_rating;
   24.61  
   24.62 @@ -213,9 +219,10 @@
   24.63      PEP_decrypt_flag_consume = 0x2,
   24.64      PEP_decrypt_flag_ignore = 0x4,
   24.65      PEP_decrypt_flag_src_modified = 0x8,
   24.66 +
   24.67      // input flags    
   24.68      PEP_decrypt_flag_untrusted_server = 0x100,
   24.69 -    PEP_decrypt_flag_dont_trigger_sync = 0x200,
   24.70 +    PEP_decrypt_flag_dont_trigger_sync = 0x200
   24.71  } PEP_decrypt_flags; 
   24.72  
   24.73  typedef unsigned int PEP_decrypt_flags_t;
   24.74 @@ -272,7 +279,10 @@
   24.75  //      the ownership of dst goes to the caller
   24.76  //      the ownership of keylist goes to the caller
   24.77  //      if src is unencrypted this function returns PEP_UNENCRYPTED and sets
   24.78 -//         dst to NULL
   24.79 +//          dst to NULL
   24.80 +//      if src->enc_format is PEP_enc_inline_EA on input then elevated attachments
   24.81 +//          will be expected
   24.82 +
   24.83  DYNAMIC_API PEP_STATUS decrypt_message(
   24.84          PEP_SESSION session,
   24.85          message *src,
    25.1 --- a/src/mime.c	Thu Apr 16 20:35:53 2020 +0200
    25.2 +++ b/src/mime.c	Mon Jun 08 15:01:34 2020 +0200
    25.3 @@ -32,12 +32,3 @@
    25.4  
    25.5      return strncmp(text, "-----BEGIN PGP MESSAGE-----", 27) == 0;
    25.6  }
    25.7 -
    25.8 -DYNAMIC_API PEP_STATUS mime_encode_message(
    25.9 -        const message * msg,
   25.10 -        bool omit_fields,
   25.11 -        char **mimetext
   25.12 -    )
   25.13 -{
   25.14 -    return _mime_encode_message_internal(msg, omit_fields, mimetext, true, false);
   25.15 -}
    26.1 --- a/src/mime.h	Thu Apr 16 20:35:53 2020 +0200
    26.2 +++ b/src/mime.h	Mon Jun 08 15:01:34 2020 +0200
    26.3 @@ -23,9 +23,21 @@
    26.4  // mime_encode_message() - encode a MIME message
    26.5  //
    26.6  //  parameters:
    26.7 -//      msg (in)                message to encode
    26.8 -//      omit_fields (in)        only encode message body and attachments
    26.9 -//      mimetext (out)          the resulting encoded text or NULL on any error
   26.10 +//      msg (in)                       message to encode
   26.11 +//      omit_fields (in)               only encode message body and 
   26.12 +//                                     attachments
   26.13 +//      mimetext (out)                 the resulting encoded text or 
   26.14 +//                                     NULL on any error
   26.15 +//      has_pEp_msg_attachment (in)    is the first *attachment* to this 
   26.16 +//                                     message an embedded pEp message
   26.17 +//                                     which needs appropriate marking
   26.18 +//                                     (forwarded=no, etc) and encoding?
   26.19 +//                                     (this argument is internal to 
   26.20 +//                                     pEp and should almost
   26.21 +//                                     ALWAYS be false when used 
   26.22 +//                                     by external callers, including
   26.23 +//                                     adapters!!!)
   26.24 +//                                  
   26.25  //
   26.26  //  return value:
   26.27  //      PEP_STATUS_OK           if everything worked
   26.28 @@ -48,16 +60,24 @@
   26.29  DYNAMIC_API PEP_STATUS mime_encode_message(
   26.30          const message * msg,
   26.31          bool omit_fields,
   26.32 -        char **mimetext
   26.33 +        char **mimetext,
   26.34 +        bool has_pEp_msg_attachment     
   26.35      );
   26.36  
   26.37  
   26.38  // mime_decode_message() - decode a MIME message
   26.39  //
   26.40  //  parameters:
   26.41 -//      mimetext (in)           	MIME encoded text to decode
   26.42 -//      size (in)               	size of text to decode
   26.43 -//      msg (out)               	decoded message
   26.44 +//      mimetext (in)           	   MIME encoded text to decode
   26.45 +//      size (in)               	   size of text to decode
   26.46 +//      msg (out)               	   decoded message
   26.47 +//      has_possible_pEp_msg (inout)   If non-NULL, will return 
   26.48 +//                                     true when the first attachment 
   26.49 +//                                     is a potential pEp message
   26.50 +//                                     (mime-type = message/rfc822 and 
   26.51 +//                                     content-disposition parameter
   26.52 +//                                     forwarded=no) 
   26.53 +//      
   26.54  //
   26.55  //  return value:
   26.56  //      PEP_STATUS_OK           if everything worked
   26.57 @@ -75,27 +95,10 @@
   26.58  DYNAMIC_API PEP_STATUS mime_decode_message(
   26.59          const char *mimetext,
   26.60          size_t size,
   26.61 -        message **msg
   26.62 +        message **msg,
   26.63 +        bool* has_possible_pEp_msg
   26.64      );
   26.65  
   26.66 -/* Carries extra return argument letting message api know if it needs to raise the attachment as 2.0/2.1 */
   26.67 -PEP_STATUS _mime_decode_message_internal(
   26.68 -        const char *mimetext,
   26.69 -        size_t size,
   26.70 -        message **msg,
   26.71 -        bool* raise_msg_attachment
   26.72 -    );
   26.73 -
   26.74 -/* sometimes we don't want to transport encode */
   26.75 -PEP_STATUS _mime_encode_message_internal(
   26.76 -        const message * msg,
   26.77 -        bool omit_fields,
   26.78 -        char **mimetext,
   26.79 -        bool transport_encode,
   26.80 -        bool set_attachment_forward_comment        
   26.81 -    );
   26.82 -
   26.83 -
   26.84  #ifdef __cplusplus
   26.85  }
   26.86  #endif
    27.1 --- a/src/pEpEngine.c	Thu Apr 16 20:35:53 2020 +0200
    27.2 +++ b/src/pEpEngine.c	Mon Jun 08 15:01:34 2020 +0200
    27.3 @@ -85,8 +85,8 @@
    27.4      "   is_own, pEp_version_major, pEp_version_minor"
    27.5      "   from identity"
    27.6      "   join person on id = identity.user_id"
    27.7 -    "   join pgp_keypair on fpr = identity.main_key_id"
    27.8 -    "   join trust on id = trust.user_id"
    27.9 +    "   left join pgp_keypair on fpr = identity.main_key_id"
   27.10 +    "   left join trust on id = trust.user_id"
   27.11      "       and pgp_keypair_fpr = identity.main_key_id"    
   27.12      "   where (case when (address = ?1) then (1)"
   27.13      "               when (lower(address) = lower(?1)) then (1)"
   27.14 @@ -103,8 +103,8 @@
   27.15      "   is_own, pEp_version_major, pEp_version_minor"
   27.16      "   from identity"
   27.17      "   join person on id = identity.user_id"
   27.18 -    "   join pgp_keypair on fpr = identity.main_key_id"
   27.19 -    "   join trust on id = trust.user_id"
   27.20 +    "   left join pgp_keypair on fpr = identity.main_key_id"
   27.21 +    "   left join trust on id = trust.user_id"
   27.22      "       and pgp_keypair_fpr = identity.main_key_id"    
   27.23      "   where identity.main_key_id = ?1" 
   27.24      "   order by is_own desc, "
   27.25 @@ -143,8 +143,8 @@
   27.26      "   is_own, pEp_version_major, pEp_version_minor"
   27.27      "   from identity"
   27.28      "   join person on id = identity.user_id"
   27.29 -    "   join pgp_keypair on fpr = identity.main_key_id"
   27.30 -    "   join trust on id = trust.user_id"
   27.31 +    "   left join pgp_keypair on fpr = identity.main_key_id"
   27.32 +    "   left join trust on id = trust.user_id"
   27.33      "       and pgp_keypair_fpr = identity.main_key_id"    
   27.34      "   where identity.user_id = ?1" 
   27.35      "   order by is_own desc, "
   27.36 @@ -155,10 +155,12 @@
   27.37      "   set main_key_id = ?1 "
   27.38      "   where main_key_id = ?2 ;";
   27.39      
   27.40 -static const char *sql_remove_fpr_as_default =
   27.41 -    "update person set main_key_id = NULL where main_key_id = ?1 ;"
   27.42 +static const char *sql_remove_fpr_as_identity_default =
   27.43      "update identity set main_key_id = NULL where main_key_id = ?1 ;";
   27.44  
   27.45 +static const char *sql_remove_fpr_as_user_default =
   27.46 +    "update person set main_key_id = NULL where main_key_id = ?1 ;";
   27.47 +    
   27.48  // Set person, but if already exist, only update.
   27.49  // if main_key_id already set, don't touch.
   27.50  static const char *sql_set_person = 
   27.51 @@ -431,14 +433,14 @@
   27.52      "   lang, identity.flags | pgp_keypair.flags, pEp_version_major, pEp_version_minor"
   27.53      "   from identity"
   27.54      "   join person on id = identity.user_id"
   27.55 -    "   join pgp_keypair on fpr = identity.main_key_id"
   27.56 -    "   join trust on id = trust.user_id"
   27.57 +    "   left join pgp_keypair on fpr = identity.main_key_id"
   27.58 +    "   left join trust on id = trust.user_id"
   27.59      "       and pgp_keypair_fpr = identity.main_key_id"
   27.60      "   where identity.is_own = 1"
   27.61      "       and (identity.flags & ?1) = 0;";
   27.62  
   27.63  static const char *sql_own_keys_retrieve = 
   27.64 -    "select pgp_keypair_fpr from trust"
   27.65 +    "select distinct pgp_keypair_fpr from trust"
   27.66      "   join identity on trust.user_id = identity.user_id"
   27.67      "   where identity.is_own = 1";
   27.68  
   27.69 @@ -454,7 +456,7 @@
   27.70      "select id from person"
   27.71      "   join identity on id = identity.user_id"
   27.72      "   where identity.is_own = 1";
   27.73 -
   27.74 +    
   27.75  // Sequence
   27.76  static const char *sql_sequence_value1 = 
   27.77      "insert or replace into sequences (name, value) "
   27.78 @@ -1797,9 +1799,14 @@
   27.79              &_session->replace_identities_fpr, NULL);
   27.80      assert(int_result == SQLITE_OK);
   27.81      
   27.82 -    int_result = sqlite3_prepare_v2(_session->db, sql_remove_fpr_as_default,
   27.83 -            (int)strlen(sql_remove_fpr_as_default), 
   27.84 -            &_session->remove_fpr_as_default, NULL);
   27.85 +    int_result = sqlite3_prepare_v2(_session->db, sql_remove_fpr_as_identity_default,
   27.86 +            (int)strlen(sql_remove_fpr_as_identity_default), 
   27.87 +            &_session->remove_fpr_as_identity_default, NULL);
   27.88 +    assert(int_result == SQLITE_OK);
   27.89 +
   27.90 +    int_result = sqlite3_prepare_v2(_session->db, sql_remove_fpr_as_user_default,
   27.91 +            (int)strlen(sql_remove_fpr_as_user_default), 
   27.92 +            &_session->remove_fpr_as_user_default, NULL);
   27.93      assert(int_result == SQLITE_OK);
   27.94  
   27.95      int_result = sqlite3_prepare_v2(_session->db, sql_set_person,
   27.96 @@ -2061,6 +2068,11 @@
   27.97          goto pEp_error;
   27.98  
   27.99      // runtime config
  27.100 +    
  27.101 +    // clean up invalid keys 
  27.102 +    status = clean_own_key_defaults(_session);
  27.103 +    if (status != PEP_STATUS_OK)
  27.104 +        goto pEp_error;
  27.105  
  27.106      *session = _session;
  27.107      
  27.108 @@ -2126,8 +2138,10 @@
  27.109                  sqlite3_finalize(session->add_userid_alias);
  27.110              if (session->replace_identities_fpr)
  27.111                  sqlite3_finalize(session->replace_identities_fpr);        
  27.112 -            if (session->remove_fpr_as_default)
  27.113 -                sqlite3_finalize(session->remove_fpr_as_default);            
  27.114 +            if (session->remove_fpr_as_identity_default)
  27.115 +                sqlite3_finalize(session->remove_fpr_as_identity_default);            
  27.116 +            if (session->remove_fpr_as_user_default)
  27.117 +                sqlite3_finalize(session->remove_fpr_as_user_default);            
  27.118              if (session->set_person)
  27.119                  sqlite3_finalize(session->set_person);
  27.120              if (session->delete_person)
  27.121 @@ -3795,16 +3809,26 @@
  27.122      if (!session || !fpr)
  27.123          return PEP_ILLEGAL_VALUE;
  27.124              
  27.125 -    sqlite3_reset(session->remove_fpr_as_default);
  27.126 -    sqlite3_bind_text(session->remove_fpr_as_default, 1, fpr, -1,
  27.127 +    sqlite3_reset(session->remove_fpr_as_identity_default);
  27.128 +    sqlite3_bind_text(session->remove_fpr_as_identity_default, 1, fpr, -1,
  27.129                        SQLITE_STATIC);
  27.130  
  27.131 -    int result = sqlite3_step(session->remove_fpr_as_default);
  27.132 -    sqlite3_reset(session->remove_fpr_as_default);
  27.133 +    int result = sqlite3_step(session->remove_fpr_as_identity_default);
  27.134 +    sqlite3_reset(session->remove_fpr_as_identity_default);
  27.135      
  27.136      if (result != SQLITE_DONE)
  27.137 -        return PEP_CANNOT_SET_IDENTITY; // misleading - could also be person
  27.138 -
  27.139 +        return PEP_CANNOT_SET_IDENTITY; 
  27.140 +
  27.141 +    sqlite3_reset(session->remove_fpr_as_user_default);
  27.142 +    sqlite3_bind_text(session->remove_fpr_as_user_default, 1, fpr, -1,
  27.143 +                      SQLITE_STATIC);
  27.144 +
  27.145 +    result = sqlite3_step(session->remove_fpr_as_user_default);
  27.146 +    sqlite3_reset(session->remove_fpr_as_user_default);
  27.147 +    
  27.148 +    if (result != SQLITE_DONE)
  27.149 +        return PEP_CANNOT_SET_PERSON; 
  27.150 +        
  27.151      return PEP_STATUS_OK;
  27.152  }
  27.153  
  27.154 @@ -4448,11 +4472,15 @@
  27.155      return PEP_STATUS_OK;
  27.156  }
  27.157  
  27.158 -void pEp_free(void *p)
  27.159 +DYNAMIC_API void pEp_free(void *p)
  27.160  {
  27.161      free(p);
  27.162  }
  27.163  
  27.164 +DYNAMIC_API void *pEp_realloc(void *p, size_t size)
  27.165 +{
  27.166 +    return realloc(p, size);
  27.167 +}
  27.168  
  27.169  DYNAMIC_API PEP_STATUS get_trust(PEP_SESSION session, pEp_identity *identity)
  27.170  {
  27.171 @@ -4534,6 +4562,26 @@
  27.172      return status;
  27.173  }
  27.174  
  27.175 +static void sanitize_pgp_filename(char *filename)
  27.176 +{
  27.177 +    for (int i=0; filename[i]; ++i) {
  27.178 +        switch(filename[i]) {
  27.179 +            // path separators
  27.180 +            case '/':
  27.181 +            case ':':
  27.182 +            case '\\':
  27.183 +            // expansion operators
  27.184 +            case '%':
  27.185 +            case '$':
  27.186 +            // code execution operators
  27.187 +            case '`':
  27.188 +            case '|':
  27.189 +                filename[i] = '-';
  27.190 +                break;
  27.191 +        }
  27.192 +    }
  27.193 +}
  27.194 +
  27.195  DYNAMIC_API PEP_STATUS decrypt_and_verify(
  27.196      PEP_SESSION session, const char *ctext, size_t csize,
  27.197      const char *dsigtext, size_t dsigsize,
  27.198 @@ -4558,6 +4606,9 @@
  27.199      if (status == PEP_DECRYPT_NO_KEY)
  27.200          signal_Sync_event(session, Sync_PR_keysync, CannotDecrypt, NULL);
  27.201  
  27.202 +    if (filename_ptr && *filename_ptr)
  27.203 +        sanitize_pgp_filename(*filename_ptr);
  27.204 +
  27.205      return status;
  27.206  }
  27.207  
    28.1 --- a/src/pEpEngine.h	Thu Apr 16 20:35:53 2020 +0200
    28.2 +++ b/src/pEpEngine.h	Mon Jun 08 15:01:34 2020 +0200
    28.3 @@ -17,7 +17,18 @@
    28.4  #include "labeled_int_list.h"    
    28.5  #include "timestamp.h"
    28.6  
    28.7 -#define PEP_VERSION "2.1" // protocol version
    28.8 +#define PEP_VERSION "2.1" // pEp *protocol* version
    28.9 +
   28.10 +// RELEASE version this targets
   28.11 +// (string: major.minor.patch)
   28.12 +#define PEP_ENGINE_VERSION "2.1.0"
   28.13 +
   28.14 +// Numeric values of above:
   28.15 +#define PEP_ENGINE_VERSION_MAJOR 2
   28.16 +#define PEP_ENGINE_VERSION_MINOR 1
   28.17 +#define PEP_ENGINE_VERSION_PATCH 0
   28.18 +#define PEP_ENGINE_VERSION_RC    2
   28.19 +
   28.20  
   28.21  #define PEP_OWN_USERID "pEp_own_userId"
   28.22      
   28.23 @@ -1011,6 +1022,24 @@
   28.24  DYNAMIC_API void pEp_free(void *p);
   28.25  
   28.26  
   28.27 +// pEp_realloc() - reallocate memory allocated by pEp engine
   28.28 +//
   28.29 +//  parameters:
   28.30 +//      p (in)                  pointer to free
   28.31 +//      size (in)               new memory size
   28.32 +//
   28.33 +//  returns:
   28.34 +//      pointer to allocated memory
   28.35 +//
   28.36 +//  The reason for this function is that heap management can be a pretty
   28.37 +//  complex task with Windoze. This realloc() version calls the realloc()
   28.38 +//  implementation of the C runtime library which was used to build pEp engine,
   28.39 +//  so you're using the correct heap. For more information, see:
   28.40 +//  <http://msdn.microsoft.com/en-us/library/windows/desktop/aa366711(v=vs.85).aspx>
   28.41 +
   28.42 +DYNAMIC_API void *pEp_realloc(void *p, size_t size);
   28.43 +
   28.44 +
   28.45  // get_trust() - get the trust level a key has for a person
   28.46  //
   28.47  //  parameters:
    29.1 --- a/src/pEp_internal.h	Thu Apr 16 20:35:53 2020 +0200
    29.2 +++ b/src/pEp_internal.h	Mon Jun 08 15:01:34 2020 +0200
    29.3 @@ -1,8 +1,6 @@
    29.4  // This file is under GNU General Public License 3.0
    29.5  // see LICENSE.txt
    29.6  
    29.7 -#define PEP_ENGINE_VERSION "1.1.1"
    29.8 -
    29.9  // maximum attachment size to import as key 1MB, maximum of 20 attachments
   29.10  
   29.11  #define MAX_KEY_SIZE (1024 * 1024)
   29.12 @@ -162,7 +160,8 @@
   29.13      sqlite3_stmt *get_main_user_fpr;
   29.14      sqlite3_stmt *refresh_userid_default_key;
   29.15      sqlite3_stmt *delete_key;
   29.16 -    sqlite3_stmt *remove_fpr_as_default;
   29.17 +    sqlite3_stmt *remove_fpr_as_identity_default;
   29.18 +    sqlite3_stmt *remove_fpr_as_user_default;
   29.19      sqlite3_stmt *set_person;
   29.20      sqlite3_stmt *update_person;
   29.21      sqlite3_stmt *delete_person;
    30.1 --- a/src/platform_unix.h	Thu Apr 16 20:35:53 2020 +0200
    30.2 +++ b/src/platform_unix.h	Mon Jun 08 15:01:34 2020 +0200
    30.3 @@ -23,8 +23,12 @@
    30.4  #endif
    30.5  
    30.6  #ifndef PER_MACHINE_DIRECTORY
    30.7 +#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE)
    30.8 +#define PER_MACHINE_DIRECTORY "/Library/Application Support/pEp"
    30.9 +#else
   30.10  #define PER_MACHINE_DIRECTORY "/usr/local/share/pEp"
   30.11  #endif
   30.12 +#endif
   30.13  
   30.14  
   30.15  #ifdef __cplusplus
    31.1 --- a/sync/cond_act_sync.yml2	Thu Apr 16 20:35:53 2020 +0200
    31.2 +++ b/sync/cond_act_sync.yml2	Mon Jun 08 15:01:34 2020 +0200
    31.3 @@ -503,15 +503,15 @@
    31.4  
    31.5      for (identity_list *_il = il; _il && _il->ident ; _il = _il->next) {
    31.6          status = set_own_key(session, _il->ident, _il->ident->fpr);
    31.7 -        if (status) {
    31.8 -            free_identity_list(il);
    31.9 -            free(user_id);
   31.10 -            return status;
   31.11 -        }
   31.12 +        if (status != PEP_STATUS_OK && status != PEP_KEY_UNSUITABLE)
   31.13 +            break;
   31.14      }
   31.15  
   31.16      free_identity_list(il);
   31.17      free(user_id);
   31.18 +
   31.19 +    if (status == PEP_KEY_UNSUITABLE)
   31.20 +        status = PEP_STATUS_OK;
   31.21  ||
   31.22  
   31.23  action useThisKey
    32.1 --- a/sync/sync.fsm	Thu Apr 16 20:35:53 2020 +0200
    32.2 +++ b/sync/sync.fsm	Mon Jun 08 15:01:34 2020 +0200
    32.3 @@ -15,8 +15,10 @@
    32.4  
    32.5          state InitState {
    32.6              on Init {
    32.7 -                if deviceGrouped
    32.8 +                if deviceGrouped {
    32.9 +                    send SynchronizeGroupKeys;
   32.10                      go Grouped;
   32.11 +                }
   32.12                  go Sole;
   32.13              }
   32.14          }
   32.15 @@ -421,12 +423,15 @@
   32.16  
   32.17          state HandshakingToJoinPhase1 {
   32.18              on Rollback {
   32.19 -                if sameNegotiation
   32.20 +                if sameNegotiation {
   32.21 +                    do untrustThisKey;
   32.22                      go Sole;
   32.23 +                }
   32.24              }
   32.25  
   32.26              on CommitReject {
   32.27                  if sameNegotiation {
   32.28 +                    do untrustThisKey;
   32.29                      do disable;
   32.30                      go End;
   32.31                  }
   32.32 @@ -531,13 +536,17 @@
   32.33              }
   32.34  
   32.35              on Rollback {
   32.36 -                if sameNegotiation
   32.37 +                if sameNegotiation {
   32.38 +                    do untrustThisKey;
   32.39                      go Grouped;
   32.40 +                }
   32.41              }
   32.42  
   32.43              on CommitReject {
   32.44 -                if sameNegotiation
   32.45 +                if sameNegotiation {
   32.46 +                    do untrustThisKey;
   32.47                      go Grouped;
   32.48 +                }
   32.49              }
   32.50  
   32.51              on CommitAccept {
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/sync/sync.md	Mon Jun 08 15:01:34 2020 +0200
    33.3 @@ -0,0 +1,664 @@
    33.4 +# p≡p KeySync
    33.5 +
    33.6 +KeySync is a protocol of the p≡p Sync family. It is defined in
    33.7 +`pEpEngine/sync/sync.fsm`.
    33.8 +
    33.9 +The Use Cases of KeySync are:
   33.10 +
   33.11 +- to discover other Devices of the same User, which are using the same Accounts
   33.12 +- to form a Device Group with these Devices
   33.13 +- to join an already existing Device Group in case of a new Device
   33.14 +- to share all Own Identities and all Own Keys within the Device Group
   33.15 +
   33.16 +## Sync Communication Channels
   33.17 +
   33.18 +p≡p Sync is designed for Communication Channels with the following properties:
   33.19 +
   33.20 +- Broadcast: any Message sent will reach all Devices
   33.21 +- Read Protected: while it is not a problem if arbitrary senders can send
   33.22 +  Messages to the Communication Channel, it must be impossible for
   33.23 +  unauthenticated Devices to read from the Channel.
   33.24 +- Offline Channel: there can be no way of deciding, which Devices are on the
   33.25 +  channel and if they're reading or not.
   33.26 +
   33.27 +Examples for Sync Communication Channels are an Inbox of an Account or an MQ
   33.28 +Topic.
   33.29 +
   33.30 +p≡p Sync is requiring at least one common Communication Channel between all
   33.31 +Devices in a Device Group.
   33.32 +
   33.33 +## Graphical representation of the KeySync Finite State Machine
   33.34 +
   33.35 +![Finite State Machine for KeySync](/keysync.svg)
   33.36 +
   33.37 +## State Machine Model
   33.38 +
   33.39 +The p≡p Sync protocols are implemented using a State Machine each. The State
   33.40 +Machine Model for p≡p Sync is defined in `pEpEngine/sync/sync.fsm`. This file
   33.41 +is written using the [YML2 tool chain](https://fdik.org/yml). The syntax of the
   33.42 +Model is defined by [declaring functions](https://fdik.org/yml/features#decl)
   33.43 +in `pEpEngine/sync/fsm.yml2`.
   33.44 +
   33.45 +##### Syntax
   33.46 +
   33.47 +    decl protocol @name (id, threshold=10);
   33.48 +
   33.49 +##### Definition
   33.50 +
   33.51 +    protocol Sync 1
   33.52 +
   33.53 +Defines the Sync Protocol Family with ID 1.
   33.54 +
   33.55 +### State Machine
   33.56 +
   33.57 +KeySync is defined as Finite State Machine.
   33.58 +
   33.59 +##### Syntax
   33.60 +
   33.61 +    decl fsm @name (id, threshold=10);
   33.62 +
   33.63 +##### Definition
   33.64 +
   33.65 +    fsm KeySync 1, threshold=300
   33.66 +
   33.67 +Defines the State Machine for the KeySync Protocol with ID 1 and a Threshold of
   33.68 +300 seconds until a the timeout Event occurs.
   33.69 +
   33.70 +### States
   33.71 +
   33.72 +A State Machine is always in one State.
   33.73 +
   33.74 +##### Syntax
   33.75 +
   33.76 +    decl state @name (timeout=on);
   33.77 +
   33.78 +#### InitState
   33.79 +
   33.80 +    state InitState
   33.81 +
   33.82 +When a State Machine is initialized, it is in InitState.
   33.83 +    
   33.84 +#### Stable States
   33.85 +
   33.86 +The State Machine of KeySync has two Stable States, which are not timing out:
   33.87 +
   33.88 +##### Sole
   33.89 +
   33.90 +    state Sole timeout=off
   33.91 +
   33.92 +KeySync is in this State while the Device is not yet member of a Device Group.
   33.93 +
   33.94 +##### Grouped
   33.95 +
   33.96 +    state Grouped timeout=off
   33.97 +
   33.98 +KeySync is in this State while the Device is member of a Device Group.
   33.99 +
  33.100 +#### Transitional States
  33.101 +
  33.102 +All other states are Transitional States. Those are documented in the [Use
  33.103 +Cases chapter](#use-cases).
  33.104 +
  33.105 +### Events
  33.106 +
  33.107 +While being in a State it can happen that an Event occurs. In this case the
  33.108 +corresponding Event Handler will be executed.
  33.109 +
  33.110 +##### Syntax
  33.111 +
  33.112 +    decl event @name, on is event;
  33.113 +
  33.114 +#### Init Event
  33.115 +
  33.116 +When the State Machine transitions to a State the Init event is happening to
  33.117 +this State. If an Init Event Handler is present for this State this Event
  33.118 +Handler is called. The Event Handler may contain [Conditions](#conditions),
  33.119 +[Actions](#actions), sending of [Messages](#messages) and
  33.120 +[Transitions](#transitions). All States can have a handler for an Init event,
  33.121 +including the `InitState`.
  33.122 +
  33.123 +##### Sample
  33.124 +
  33.125 +    state InitState { on Init { if deviceGrouped { send SynchronizeGroupKeys;
  33.126 +    go Grouped; } go Sole; } }
  33.127 +
  33.128 +#### Message Event
  33.129 +
  33.130 +If a Sync Message arrives through the Network then the Event with the name of
  33.131 +the Message is occuring.
  33.132 +
  33.133 +##### Sample
  33.134 +
  33.135 +In this example an Event Handler is defined, which is executed when a Beacon
  33.136 +Message arrives:
  33.137 +
  33.138 +    on Beacon { do openNegotiation; do tellWeAreGrouped; do useOwnResponse;
  33.139 +    send NegotiationRequestGrouped; do useOwnChallenge; }
  33.140 +
  33.141 +#### Signaled Events
  33.142 +
  33.143 +Events, which don't share their name with a Message, are being signaled from
  33.144 +engine code.
  33.145 +
  33.146 +##### Sample
  33.147 +
  33.148 +The KeyGen Event has no corresponding Message. Therefore, it is not occuring
  33.149 +when a Sync Message arrives but when it is signaled from code:
  33.150 +
  33.151 +    on KeyGen { do prepareOwnKeys; send GroupKeysUpdate; }
  33.152 +
  33.153 +The signalling can be done by calling `signal_Sync_event()`:
  33.154 +
  33.155 +    // call this if you need to signal an external event // caveat: the
  33.156 +    ownership of own_identities goes to the callee
  33.157 +
  33.158 +    PEP_STATUS signal_Sync_event( PEP_SESSION session, Sync_PR fsm, int event,
  33.159 +    identity_list *own_identities);
  33.160 +
  33.161 +##### Sample
  33.162 +
  33.163 +In this example the KeyGen event is signaled to KeySync when a new Own Key is
  33.164 +generated:
  33.165 +
  33.166 +    signal_Sync_event(session, Sync_PR_keysync, KeyGen, NULL);
  33.167 +
  33.168 +#### External Event IDs
  33.169 +
  33.170 +If Events are part of an API then their IDs must be well defined. Therefore, it
  33.171 +is possible to define such IDs in the State Machine.
  33.172 +
  33.173 +##### Syntax
  33.174 +
  33.175 +    decl external @name (id);
  33.176 +
  33.177 +##### Sample
  33.178 +
  33.179 +    external Accept 129;
  33.180 +
  33.181 +### Transitions
  33.182 +
  33.183 +To switch to another State it is possible to write a Transition into an Event
  33.184 +Handler.
  33.185 +
  33.186 +##### Syntax
  33.187 +
  33.188 +    decl transition @target, go is transition;
  33.189 +
  33.190 +##### Sample
  33.191 +
  33.192 +In this example there are two Transitions, one to State Grouped and one to
  33.193 +State Sole:
  33.194 +
  33.195 +    on Init { if deviceGrouped { send SynchronizeGroupKeys; go Grouped; } go
  33.196 +    Sole; }
  33.197 +
  33.198 +### Messages
  33.199 +
  33.200 +KeySync is a Network Protocol, which is implemented using Sync Messages. The
  33.201 +Sync Messages for KeySync are defined at the end of the Finite State Machine in
  33.202 +`pEpEngine/sync/sync.fsm`.
  33.203 +
  33.204 +The wire format of Sync Messages is defined in
  33.205 +[ASN.1](https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One), see
  33.206 +`pEpEngine/asn.1/keysync.asn1`, using
  33.207 +[PER](https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One#Packed_Encoding_Rules).
  33.208 +
  33.209 +Sync Messages are transported as Attachments to p≡p Messages. Hence they're
  33.210 +transported by the same Transports, which are transporting p≡p Messages. Some
  33.211 +Sync Messages must be sent in copy on all Transports. Others are transported on
  33.212 +the Active Transport only. The Active Transport is the Transport, on which the
  33.213 +last Sync Message was received.
  33.214 +
  33.215 +Each Sync Message has a name and an ID. There is different types of Messages:
  33.216 +
  33.217 +- `type=broadcast` for Messages, which are meant to be copied on all Transports
  33.218 +- `type=anycast` for Messages, which are meant to be sent on the Active
  33.219 +  Transport only
  33.220 +
  33.221 +Each Sync Message has a Security Context. The available Security Contexts are:
  33.222 +
  33.223 +- `security=unencrypted`: send and receive as unencrypted but signed Sync
  33.224 +  Message
  33.225 +- `security=untrusted`: only accept when encrypted and signed
  33.226 +- `security=trusted` (default): only accept when coming over a Trusted Channel
  33.227 +  and when originating from the Device Group
  33.228 +- `security=attach_own_keys_for_new_member`: like `security=trusted` but attach
  33.229 +  all Own Keys for a new Member of the Device Group
  33.230 +- `security=attach_own_keys_for_group`: like `security=trusted` but atttach all
  33.231 +  Own Keys for other Device Group Members.
  33.232 +
  33.233 +A Sync Message can have a Rate Limit `ratelimit=<numeric>`. That means it is
  33.234 +only possible to send out one message each `<numeric>` seconds. A Rate Limit of
  33.235 +0 means no Rate Limit checking.
  33.236 +
  33.237 +##### Syntax
  33.238 +
  33.239 +    decl message @name (id, type=anycast, security=trusted, ratelimit=0);
  33.240 +
  33.241 +##### Sample
  33.242 +
  33.243 +    message Beacon 2, type=broadcast, ratelimit=10, security=unencrypted {
  33.244 +    field TID challenge; auto Version version; }
  33.245 +
  33.246 +#### Fields
  33.247 +
  33.248 +A Sync Message can have Fields. There is two types of fields: automatically
  33.249 +calculated fields, defined with the `auto` keyword, and fields, which are
  33.250 +copied in and out from the I/O buffer, marked with the `fields` keyword.
  33.251 +
  33.252 +The wire format of the fields is depending on their type. The types are defined
  33.253 +in `pEpEngine/asn.1/pEp.asn1`. Additionally, the two basic types `bool` (ASN.1:
  33.254 +BOOLEAN) and `int` (ASN.1: INTEGER) are supported.
  33.255 +
  33.256 +##### Syntax
  33.257 +
  33.258 +    decl field @type @name; decl auto < field >;
  33.259 +
  33.260 +##### Sample for an `auto` field:
  33.261 +
  33.262 +    auto Version version;
  33.263 +
  33.264 +This field will be filled with the p≡p Sync Protocol version. The `Version`
  33.265 +type is the only automatically calculated type yet.
  33.266 +
  33.267 +##### Sample for an field coming from I/O buffer
  33.268 +
  33.269 +    field TID challenge;
  33.270 +
  33.271 +#### I/O Buffer
  33.272 +
  33.273 +There is an I/O Buffer for all Fields, which are occuring in Messages. All
  33.274 +Messages share this I/O buffer. Fields with the same name share one space in
  33.275 +the I/O Buffer. Hence, the I/O Buffer is built as superset of all Fields'
  33.276 +buffers.
  33.277 +
  33.278 +#### Sending
  33.279 +
  33.280 +Sending is being done by:
  33.281 +
  33.282 +1. Calculating all `auto` Fields and copying the result into the I/O Buffer
  33.283 +1. Loading all Fields of the Message from I/O Buffer
  33.284 +1. Creating a Sync Message
  33.285 +1. Creating a transporting p≡p Message by attaching the Sync Message using Base
  33.286 +Protocol
  33.287 +1. Calling `messageToSend()` with this p≡p Message
  33.288 +
  33.289 +##### Syntax
  33.290 +
  33.291 +    decl send @name;
  33.292 +
  33.293 +##### Sample
  33.294 +
  33.295 +    send SynchronizeGroupKeys;
  33.296 +
  33.297 +#### Receiving
  33.298 +
  33.299 +When a Message is being received the field values are being copied into the I/O
  33.300 +Buffer and the corresponding [Event](#events) is being signaled.
  33.301 +
  33.302 +### Conditions
  33.303 +
  33.304 +Conditions are implemented in `pEpEngine/sync/cond_act_sync.yml2` with the
  33.305 +keyword `condition`. All implemented Conditions can be used in any Sync
  33.306 +Protocol. A [dangling else](https://en.wikipedia.org/wiki/Dangling_else) and
  33.307 +[nesting](https://en.wikipedia.org/wiki/Nesting_(computing)) of Conditions are
  33.308 +supported. Hence, Conditions can contain all elements, which can be contained
  33.309 +by Event Handlers, too. All Conditions can either be true or false on success,
  33.310 +or they fail and are bringing the State Machine into an error state, and the
  33.311 +State Machine will be initialized.
  33.312 +
  33.313 +##### Syntax
  33.314 +
  33.315 +    decl condition @name, if is condition; decl else;
  33.316 +
  33.317 +##### Sample
  33.318 +
  33.319 +Checking the Condition `sameResponse` and executing Actions and Transitions
  33.320 +depending on its result:
  33.321 +
  33.322 +    if sameResponse { // the first one is from us, we're leading this do
  33.323 +    resetOwnGroupedKeys; go Grouped; } else { // the first one is not from us
  33.324 +    go Grouped; }
  33.325 +
  33.326 +The implemented Conditions are:
  33.327 +
  33.328 +#### condition deviceGrouped
  33.329 +
  33.330 +True if the Device is already member of a Device Group. This is determined by
  33.331 +checking if there are Group Keys already.
  33.332 +
  33.333 +#### condition fromGroupMember
  33.334 +
  33.335 +For double checking. True is the incoming Sync Message is coming from a Device
  33.336 +Group member.
  33.337 +
  33.338 +#### condition keyElectionWon
  33.339 +
  33.340 +True if our Own Keys are going to be used as Group Keys. False if the Own Keys
  33.341 +of the partner will be the Group Keys. Calculated by comparing if the FPR of
  33.342 +the Sender Key of the partner is greater than our Default Key for the Account,
  33.343 +which is being used as Active Transport.
  33.344 +
  33.345 +#### condition sameChallenge
  33.346 +
  33.347 +True if the Challenge of the incoming Sync Message is identical to the
  33.348 +Challenge of the Device. In this case this was a Sync Message sent by the
  33.349 +Device itself.
  33.350 +
  33.351 +#### condition sameNegotiation
  33.352 +
  33.353 +True if the Negotiation of the incoming Sync Message is identical to the
  33.354 +Negotiation the Device is in. In this case the incoming Sync Message is part of
  33.355 +the same Negotiation.
  33.356 +
  33.357 +#### condition sameNegotiationAndPartner
  33.358 +
  33.359 +True if the Negotiation of the incoming Sync Message is identical to the
  33.360 +Negotiation the Device is in and the partner did not change. In this case the
  33.361 +incoming Sync Message is part of the same Negotiation coming from the expected
  33.362 +Device.
  33.363 +
  33.364 +#### condition sameResponse
  33.365 +
  33.366 +True if the Response of the incoming Sync Message is identical to the Response
  33.367 +of the Device. In this case the Response was correctly echoed.
  33.368 +
  33.369 +#### condition weAreOfferer
  33.370 +
  33.371 +True if the Challenge of the incoming Sync Message is greater than the
  33.372 +Challenge of the Device. Otherwise we're Requester.
  33.373 +
  33.374 +### Actions
  33.375 +
  33.376 +Actions are implemented in `pEpEngine/sync/cond_act_sync.yml2` with the keyword
  33.377 +`action`. All implemented Actions can be used in any Sync Protocol. Actions are
  33.378 +unconditionally executing the code of their implementation. All Actions may
  33.379 +fail. In this case they're bringing the State Machine into an error state, and
  33.380 +the State Machine will be initialized.
  33.381 +
  33.382 +##### Syntax
  33.383 +
  33.384 +    decl action @name, do is action;
  33.385 +
  33.386 +##### Sample
  33.387 +
  33.388 +    do useOwnChallenge;
  33.389 +
  33.390 +#### action backupOwnKeys
  33.391 +
  33.392 +Make a backup of all Own Keys.
  33.393 +
  33.394 +#### action disable
  33.395 +
  33.396 +Diable Sync and shut down the State Machine.
  33.397 +
  33.398 +#### action newChallengeAndNegotiationBase
  33.399 +
  33.400 +A new Challenge and a new Response will be computed randomly. Both are copied
  33.401 +into the I/O Buffer. The Negotiation Base is being computed randomly.
  33.402 +
  33.403 +#### action openNegotiation
  33.404 +
  33.405 +Key and Identity of the partner are being cleared. The Negotiation ID is being
  33.406 +calculated by the Negotiation Base XOR the Challenge of the partner.
  33.407 +
  33.408 +#### action ownKeysAreDefaultKeys
  33.409 +
  33.410 +Flag Default Keys of Own Identities as Group Keys.
  33.411 +
  33.412 +#### action prepareOwnKeys
  33.413 +
  33.414 +Write list of Own Identities into the I/O Buffer and load list of Own Keys into
  33.415 +the Device state.
  33.416 +
  33.417 +#### action prepareOwnKeysFromBackup
  33.418 +
  33.419 +Restore the formerly backed up Own Keys into the I/O Buffer.
  33.420 +
  33.421 +#### action receivedKeysAreDefaultKeys
  33.422 +
  33.423 +Set the received Own Keys as Default Keys for the Own Identities.
  33.424 +
  33.425 +#### action resetOwnGroupedKeys
  33.426 +
  33.427 +Do a KeyReset on Own Group Keys.
  33.428 +
  33.429 +#### action resetOwnKeysUngrouped
  33.430 +
  33.431 +Do a KeyReset on all Own Keys.
  33.432 +
  33.433 +#### action saveGroupKeys
  33.434 +
  33.435 +Load Own Identities from the I/O Buffer and store them as Own Identities.
  33.436 +
  33.437 +#### action showBeingInGroup
  33.438 +
  33.439 +Signal `SYNC_NOTIFY_IN_GROUP` to the App.
  33.440 +
  33.441 +#### action showBeingSole
  33.442 +
  33.443 +Signal `SYNC_NOTIFY_SOLE` to the App.
  33.444 +
  33.445 +#### action showDeviceAccepted
  33.446 +
  33.447 +Signal `SYNC_NOTIFY_ACCEPTED_DEVICE_ACCEPTED` to the App.
  33.448 +
  33.449 +#### action showDeviceAdded
  33.450 +
  33.451 +Signal `SYNC_NOTIFY_ACCEPTED_DEVICE_ADDED` to the App.
  33.452 +
  33.453 +#### action showJoinGroupHandshake
  33.454 +
  33.455 +Signal `SYNC_NOTIFY_INIT_ADD_OUR_DEVICE` to the App.
  33.456 +
  33.457 +#### action showGroupCreated
  33.458 +
  33.459 +Signal `SYNC_NOTIFY_ACCEPTED_GROUP_CREATED` to the App.
  33.460 +
  33.461 +#### action showGroupedHandshake
  33.462 +
  33.463 +Signal `SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE` to the App.
  33.464 +
  33.465 +#### action showSoleHandshake
  33.466 +
  33.467 +Signal `SYNC_NOTIFY_INIT_FORM_GROUP` to the App.
  33.468 +
  33.469 +#### action storeNegotiation
  33.470 +
  33.471 +The Negotiation in the I/O Buffer is being stored for the Device. The Sender
  33.472 +FPR and partner's Identity are both stored for later comparison.
  33.473 +
  33.474 +#### action storeThisKey
  33.475 +
  33.476 +Load the Sender Key of the partner from the I/O Buffer and store it for later
  33.477 +use.
  33.478 +
  33.479 +#### action tellWeAreGrouped
  33.480 +
  33.481 +Set the `is_grouped` Field in the I/O Buffer to true.
  33.482 +
  33.483 +#### action tellWeAreNotGrouped
  33.484 +
  33.485 +Set the `is_grouped` Field in the I/O Buffer to false.
  33.486 +
  33.487 +#### action trustThisKey
  33.488 +
  33.489 +Trust the formerly stored Key of the partner. Load this Key into the I/O
  33.490 +Buffer.
  33.491 +
  33.492 +#### action untrustThisKey
  33.493 +
  33.494 +Revoke Trust from the formerly stored Key of the partner. Clear the Key in the
  33.495 +I/O Buffer.
  33.496 +
  33.497 +#### action useOwnChallenge
  33.498 +
  33.499 +The Challenge of the Device is being copied into the I/O Buffer.
  33.500 +
  33.501 +#### action useOwnResponse
  33.502 +
  33.503 +The Response of the Device is being copied into the I/O Buffer.
  33.504 +
  33.505 +#### action useThisKey
  33.506 +
  33.507 +Copy the stored Sender Key of the partner into the I/O Buffer.
  33.508 +
  33.509 +## Use Cases
  33.510 +
  33.511 +### Device Discovery
  33.512 +
  33.513 +If there is more than one Device using the same Sync Channel (i.e. the same
  33.514 +Inbox in one or more Accounts, respectively) then p≡p Sync is there to detect
  33.515 +the other Devices. Therefore, a Device, which is in state Sole, is sending a
  33.516 +Beacon Message, so it can be detected by a second Sole Device or by Devices,
  33.517 +which are already forming a Device Group.
  33.518 +
  33.519 +#### Relating Beacons
  33.520 +
  33.521 +To make it distinguishable, which Device is sending which Beacon, Beacons have
  33.522 +the Field `challenge`. This field is of type `TID` (transaction ID), which is
  33.523 +defined as UUID version 4 variant 1: a completely random UUID (see
  33.524 +`pEpEngine/asn.1/pEp.asn1`).
  33.525 +
  33.526 +The `challenge` is initialized with new random data whenever one of the two
  33.527 +Stable States (Sole or Grouped) are being reached. It is a pseudonym for the
  33.528 +Device. The initialization takes place by executing the Action
  33.529 +`newChallengeAndNegotiationBase`.
  33.530 +
  33.531 +#### The Handshake
  33.532 +
  33.533 +By reading a Beacon, which does not deliver the own `challenge`, a Device can
  33.534 +learn of a new other Device. Beacons are then answered with a
  33.535 +NegotiationRequest Message. This message is repeating the Beacon's `challenge`
  33.536 +and adding an own `response`, which is again a randomly chosen `TID`, and again
  33.537 +a pseudonym. Own NegotiationRequest Messages can be identified and ignored by
  33.538 +the value of the `response`. Additionally, a suggestion for a transaction ID
  33.539 +for a `negotiation` about forming a Device Group or joining an existing Device
  33.540 +group is being sent, together with the field `is_group` to determine between
  33.541 +the two cases.
  33.542 +
  33.543 +When reading the NegotiationRequest of another Device, which is repeating the
  33.544 +own `challenge` a Device learns that it was detected by another Device. It then
  33.545 +is answering with a NegotiationOpen Message by repeating the `response`
  33.546 +pseudonym of the other device and the transaction ID for the `negotiation` to
  33.547 +signal that it is aware of the other Device and ready to execute the
  33.548 +`negotiation` process.
  33.549 +
  33.550 +The three messages Beacon, NegotiationRequest and NegotiationOpen are
  33.551 +fulfilling the pattern of a [three way
  33.552 +handshake](https://en.wikipedia.org/wiki/Handshaking). At the same time
  33.553 +NegotiationOpen is opening a [distributed
  33.554 +transaction](https://en.wikipedia.org/wiki/Distributed_transaction), the
  33.555 +Negotiation.
  33.556 +
  33.557 +### Forming a Device Group by two Sole Devices
  33.558 +
  33.559 +In case there is no Device Group existing yet, then two Sole devices can form
  33.560 +one. There is an extra problem then: the symmetry of the situation. Which
  33.561 +Device does have the role of sending out Beacons and which has the role of
  33.562 +answerng with a NegotiationRequest Message? This must be decided first. Hence
  33.563 +there are two roles a Device can go into: the Offerer, who is sending the
  33.564 +Beacon, and the Requester, who is answering with a NegotiationRequest Message.
  33.565 +
  33.566 +#### Deciding Roles
  33.567 +
  33.568 +Both Devices have to decide their role independently from each other, and it
  33.569 +must be guaranteed that the decision is correspondent on both sides,
  33.570 +respectively.
  33.571 +
  33.572 +To make this possible the criterion to decide whether a Device is Offerer or
  33.573 +Requester there is the Condition `weAreOfferer`. The Device is Offerer if the
  33.574 +`challenge` of the other Device is greater than its own `challenge`, otherwise
  33.575 +it is Requester.
  33.576 +
  33.577 +The decision is being made on a Beacon Message arriving. Then the Device is
  33.578 +knowing both Challenge TIDs.
  33.579 +
  33.580 +#### Starting the Negotiation as Offerer
  33.581 +
  33.582 +If the Device is Offerer and it gets a Beacon it may be the case that the
  33.583 +former own Beacon timed out so the other Device couldn’t see it. Hence another
  33.584 +Beacon is sent out to make sure the other Device can see that we’re Offerer.
  33.585 +
  33.586 +Being Offerer the Device is waiting for a NegotiationRequest coming from the
  33.587 +Requester. When a NegotiationRequest is arriving the Device is checking if the
  33.588 +own `challenge` was repeated. By doing so it is checking if the Requester is
  33.589 +authenticated and can read the Channel. In case it is storing the `negotiation`
  33.590 +TID for further use. From then on it is basing its communication on this TID
  33.591 +while it is in this Negotiation. It tells this to the other Device by sending
  33.592 +the NegotiationOpen Message repeating the `response`. There is no Action to
  33.593 +repeat the `response`, because repeating what is in the I/O Buffer is the
  33.594 +default. Then it is transitioning to the State HandshakingOfferer, which is a
  33.595 +Transitional State to start the Handshake process.
  33.596 +
  33.597 +#### Starting the Negotiation as Requester
  33.598 +
  33.599 +If the Device is Sole and Requester the flag `is_grouped` is cleared in the I/O
  33.600 +Buffer by executing `tellWeAreNotGrouped` to signal its Sole State to the
  33.601 +Offerer. Executing `useOwnResponse` is copying the own Response TID into the
  33.602 +I/O Buffer.
  33.603 +
  33.604 +Executing the Action `openNegotiation` is calculating the Negotiation TID as
  33.605 +Challenge of the other Device XOR Negotiation Base. By doing so each possible
  33.606 +partner is having its own Negotiation ID in case multiple Sole Devices are
  33.607 +active at the same time. Then the Message NegotiationRequest is being sent out.
  33.608 +
  33.609 +After sending the NegotiationRequest the value of the `challenge` in the I/O
  33.610 +Buffer is reverted to the own Challenge TID to answer other Beacons, which may
  33.611 +arrive from other Devices.
  33.612 +
  33.613 +The Requester is then waiting for the NegotiationOpen Message from the Offerer.
  33.614 +It is checking if the `response` was correctly repeated. By doing so it is
  33.615 +checking if the Offerer is authenticated and can read the Channel. The
  33.616 +Requester is storing the `negotiation` TID for further use. The Device is
  33.617 +transitioning to the Transitional State HandshakingRequester to start the
  33.618 +Handshake process.
  33.619 +
  33.620 +#### Handshaking with two Sole Devices
  33.621 +
  33.622 +Each Device is waiting for two Events, which both must happen: the User
  33.623 +must Accept the Handshake on the Offerer Device and the User must Accept the
  33.624 +Handshake on the Requester Device. Only if both Accepts where received the
  33.625 +Handshake is accpeted. 
  33.626 +
  33.627 +The Offerer is sending the Message CommitAcceptOfferer in case it gets
  33.628 +signalled Accept from the User, so the Requester gets informed about this.
  33.629 +Accordingly, the Requester is sending CommitAcceptRequester in case it is
  33.630 +getting signalled Accept from its User.
  33.631 +
  33.632 +The sending of CommitAcceptOfferer and CommitAcceptRequester are not arbitrary
  33.633 +in sequence, though. To keep the wanted asymmetry the Offerer is only sending
  33.634 +CommitAcceptOfferer after it was receiving CommitAcceptRequester AND it was
  33.635 +signalled the Accept Event by the User. The Requester is sending
  33.636 +CommitAcceptRequester immediately after it got signalled the Accept Event from
  33.637 +the User. As a result the CommitAcceptRequester Message is always sent before
  33.638 +the CommitAcceptOfferer is being sent.
  33.639 +
  33.640 +The Negotiation is considered committed with result Accept if and only if both
  33.641 +Commit Messages where received. This is fulfilling the pattern of the
  33.642 +[Two-phase commit
  33.643 +protocol](https://en.wikipedia.org/wiki/Two-phase_commit_protocol).
  33.644 +
  33.645 +#### In case of Reject or Cancel
  33.646 +
  33.647 +If the User selects Reject on Offerer or Requester, then the CommitReject
  33.648 +Message is being sent and p≡p Sync is being disabled.  If the CommitReject
  33.649 +Message is received because the User selected Reject on the other Device, p≡p
  33.650 +Sync is disabled, too.
  33.651 +
  33.652 +The Negotiation is considered committed with result Reject if Offerer OR
  33.653 +Requester sent CommitReject. This is a derivate of the Two-phase commit
  33.654 +protocol.
  33.655 +
  33.656 +In case the User selects Cancel then the Rollback Message is being sent, and
  33.657 +the Device is transitioned to State Sole. The Negotiation is then cancelled,
  33.658 +but a next Negotiation can happen after this.  In case a Rollback Message is
  33.659 +being received then the Device is transitioned to State Sole. The Negotiation
  33.660 +is then cancelled, but a next Negotiation can happen after this.
  33.661 +
  33.662 +The Rollback is fulfilling the pattern of the Two-phase commit protocol.
  33.663 +
  33.664 +### Joining an already existing Device Group
  33.665 +
  33.666 +### Sharing of Own Identities and Own Keys in a Device Group
  33.667 +
    34.1 --- a/test/README.md	Thu Apr 16 20:35:53 2020 +0200
    34.2 +++ b/test/README.md	Mon Jun 08 15:01:34 2020 +0200
    34.3 @@ -197,6 +197,11 @@
    34.4    gdb --args ./EngineTests --gtest_filter=TestSuiteName.test_function_name
    34.5    ```
    34.6  
    34.7 +N.B. The gtest_filter can be globbed and will run all matching tests; if you
    34.8 +want to run every test in a test suite, be sure to use TestSuiteName*.
    34.9 +
   34.10 +(Different shells will require different quoting styles for this - YMMV.)
   34.11 +
   34.12  When debugging a failing test, use '--gtest_break_on_failure' to have
   34.13  gtest automatically break into the debugger where the assertion fails.
   34.14  
    35.1 --- a/test/src/AppleMailTest.cc	Thu Apr 16 20:35:53 2020 +0200
    35.2 +++ b/test/src/AppleMailTest.cc	Mon Jun 08 15:01:34 2020 +0200
    35.3 @@ -123,7 +123,7 @@
    35.4      PEP_decrypt_flags_t flags = 0;
    35.5  
    35.6      message* final_ptr = nullptr;
    35.7 -    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr);
    35.8 +    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr, NULL);
    35.9      ASSERT_EQ(status , PEP_STATUS_OK);
   35.10      ASSERT_NE(msg_ptr, nullptr);
   35.11  
   35.12 @@ -185,7 +185,7 @@
   35.13      const char* mailfile2 = "test_mails/apple_mail_TC_html_signed_encrypted.eml";
   35.14      const string mailtext2 = slurp(mailfile2);
   35.15  
   35.16 -    status = mime_decode_message(mailtext2.c_str(), mailtext2.length(), &msg_ptr);
   35.17 +    status = mime_decode_message(mailtext2.c_str(), mailtext2.length(), &msg_ptr, NULL);
   35.18      ASSERT_EQ(status, PEP_STATUS_OK);
   35.19      ASSERT_NE(msg_ptr, nullptr);
   35.20      final_ptr = msg_ptr;
    36.1 --- a/test/src/BlacklistAcceptNewKeyTest.cc	Thu Apr 16 20:35:53 2020 +0200
    36.2 +++ b/test/src/BlacklistAcceptNewKeyTest.cc	Mon Jun 08 15:01:34 2020 +0200
    36.3 @@ -142,7 +142,7 @@
    36.4      PEP_rating rating;
    36.5      PEP_decrypt_flags_t flags = 0;
    36.6  
    36.7 -    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr);
    36.8 +    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr, NULL);
    36.9      ASSERT_EQ(status , PEP_STATUS_OK);
   36.10      status = decrypt_message(session, msg_ptr, &dest_msg, &keylist, &rating, &flags);
   36.11  
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/test/src/CleanInvalidOwnKeysTest.cc	Mon Jun 08 15:01:34 2020 +0200
    37.3 @@ -0,0 +1,124 @@
    37.4 +#include <stdlib.h>
    37.5 +#include <string>
    37.6 +#include <cstring>
    37.7 +
    37.8 +#include "pEpEngine.h"
    37.9 +#include "test_util.h"
   37.10 +#include "TestConstants.h"
   37.11 +#include "Engine.h"
   37.12 +
   37.13 +#include <gtest/gtest.h>
   37.14 +
   37.15 +
   37.16 +namespace {
   37.17 +
   37.18 +	//The fixture for CleanInvalidOwnKeysTest
   37.19 +    class CleanInvalidOwnKeysTest : public ::testing::Test {
   37.20 +        public:
   37.21 +            Engine* engine;
   37.22 +            PEP_SESSION session;
   37.23 +
   37.24 +        protected:
   37.25 +            // You can remove any or all of the following functions if its body
   37.26 +            // is empty.
   37.27 +            CleanInvalidOwnKeysTest() {
   37.28 +                // You can do set-up work for each test here.
   37.29 +                test_suite_name = ::testing::UnitTest::GetInstance()->current_test_info()->GTEST_SUITE_SYM();
   37.30 +                test_name = ::testing::UnitTest::GetInstance()->current_test_info()->name();
   37.31 +                test_path = get_main_test_home_dir() + "/" + test_suite_name + "/" + test_name;
   37.32 +            }
   37.33 +
   37.34 +            ~CleanInvalidOwnKeysTest() override {
   37.35 +                // You can do clean-up work that doesn't throw exceptions here.
   37.36 +            }
   37.37 +
   37.38 +            // If the constructor and destructor are not enough for setting up
   37.39 +            // and cleaning up each test, you can define the following methods:
   37.40 +
   37.41 +            void SetUp() override {
   37.42 +                // Code here will be called immediately after the constructor (right
   37.43 +                // before each test).
   37.44 +
   37.45 +                // Leave this empty if there are no files to copy to the home directory path
   37.46 +                std::vector<std::pair<std::string, std::string>> init_files = std::vector<std::pair<std::string, std::string>>();
   37.47 +                string keyfile = string("test_files/ENGINE-750_") + test_name + "_keys.db";
   37.48 +                string mgmtfile = string("test_files/ENGINE-750_") + test_name + "_mgmt.db";
   37.49 +                init_files.push_back(std::pair<std::string, std::string>(keyfile, std::string("keys.db")));                
   37.50 +                init_files.push_back(std::pair<std::string, std::string>(mgmtfile, std::string("management.db")));
   37.51 +                
   37.52 +                // Get a new test Engine.
   37.53 +                engine = new Engine(test_path);
   37.54 +                ASSERT_NE(engine, nullptr);
   37.55 +
   37.56 +                // Ok, let's initialize test directories etc.
   37.57 +                engine->prep(NULL, NULL, init_files);
   37.58 +
   37.59 +                // Ok, try to start this bugger.
   37.60 +                engine->start();
   37.61 +                ASSERT_NE(engine->session, nullptr);
   37.62 +                session = engine->session;
   37.63 +
   37.64 +                // Engine is up. Keep on truckin'
   37.65 +            }
   37.66 +
   37.67 +            void TearDown() override {
   37.68 +                // Code here will be called immediately after each test (right
   37.69 +                // before the destructor).
   37.70 +                engine->shut_down();
   37.71 +                delete engine;
   37.72 +                engine = NULL;
   37.73 +                session = NULL;
   37.74 +            }
   37.75 +
   37.76 +        private:
   37.77 +            const char* test_suite_name;
   37.78 +            const char* test_name;
   37.79 +            string test_path;
   37.80 +            // Objects declared here can be used by all tests in the CleanInvalidOwnKeysTest suite.
   37.81 +
   37.82 +    };
   37.83 +
   37.84 +}  // namespace
   37.85 +
   37.86 +
   37.87 +TEST_F(CleanInvalidOwnKeysTest, check_clean_invalid_own_keys_no_alts_revoked) {
   37.88 +    // This is just a dummy test case. The convention is check_whatever_you_are_checking
   37.89 +    // so for multiple test cases in a suite, be more explicit ;)   
   37.90 +    pEp_identity* alice = NULL;
   37.91 +    PEP_STATUS status = get_identity(session, "pep.test.alice@pep-project.org", "ALICE", &alice);
   37.92 +    ASSERT_EQ(status, PEP_STATUS_OK);
   37.93 +    ASSERT_STRNE(alice->fpr, "4ABE3AAF59AC32CFE4F86500A9411D176FF00E97");
   37.94 +    char* fpr = NULL;
   37.95 +    status = get_user_default_key(session, "ALICE", &fpr);
   37.96 +    ASSERT_STREQ(fpr, alice->fpr);
   37.97 +    ASSERT_EQ(status, PEP_STATUS_OK);    
   37.98 +}
   37.99 +
  37.100 +TEST_F(CleanInvalidOwnKeysTest, check_clean_invalid_own_keys_no_alts_mistrusted) {
  37.101 +    // This is just a dummy test case. The convention is check_whatever_you_are_checking
  37.102 +    // so for multiple test cases in a suite, be more explicit ;)   
  37.103 +    pEp_identity* alice = NULL;
  37.104 +    PEP_STATUS status = get_identity(session, "pep.test.alice@pep-project.org", "ALICE", &alice);
  37.105 +    ASSERT_EQ(status, PEP_STATUS_OK);
  37.106 +    ASSERT_STRNE(alice->fpr, "4ABE3AAF59AC32CFE4F86500A9411D176FF00E97");
  37.107 +    char* fpr = NULL;
  37.108 +    status = get_user_default_key(session, "ALICE", &fpr);
  37.109 +    ASSERT_STREQ(fpr, alice->fpr);
  37.110 +    ASSERT_EQ(status, PEP_STATUS_OK);    
  37.111 +}
  37.112 +
  37.113 +TEST_F(CleanInvalidOwnKeysTest, check_clean_invalid_own_keys_no_alts_expired) {
  37.114 +    // This is just a dummy test case. The convention is check_whatever_you_are_checking
  37.115 +    // so for multiple test cases in a suite, be more explicit ;)   
  37.116 +    pEp_identity* bob = NULL;
  37.117 +    PEP_STATUS status = get_identity(session, "expired_bob_0@darthmama.org", "BOB", &bob);
  37.118 +    ASSERT_EQ(status, PEP_STATUS_OK);
  37.119 +    ASSERT_STREQ(bob->fpr, "E4A8CD51C25D0ED5BAD0834BD2FDE305A35FE3F5");
  37.120 +    char* fpr = NULL;
  37.121 +    status = get_user_default_key(session, "BOB", &fpr);
  37.122 +    ASSERT_STREQ(fpr, "E4A8CD51C25D0ED5BAD0834BD2FDE305A35FE3F5");
  37.123 +    ASSERT_EQ(status, PEP_STATUS_OK);    
  37.124 +    bool expired = true;
  37.125 +    status = key_expired(session, bob->fpr, time(NULL), &expired);
  37.126 +    ASSERT_FALSE(expired);
  37.127 +}
    38.1 --- a/test/src/DecorateTest.cc	Thu Apr 16 20:35:53 2020 +0200
    38.2 +++ b/test/src/DecorateTest.cc	Mon Jun 08 15:01:34 2020 +0200
    38.3 @@ -129,7 +129,7 @@
    38.4      ASSERT_NE(encrypted_msg, nullptr);
    38.5      output_stream << "message encrypted.\n";
    38.6  
    38.7 -    status = mime_encode_message(encrypted_msg, false, &encoded_text);
    38.8 +    status = mime_encode_message(encrypted_msg, false, &encoded_text, false);
    38.9      ASSERT_EQ(status , PEP_STATUS_OK);
   38.10      ASSERT_NE(encoded_text, nullptr);
   38.11  
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/test/src/ElevatedAttachmentsTest.cc	Mon Jun 08 15:01:34 2020 +0200
    39.3 @@ -0,0 +1,418 @@
    39.4 +#include <stdlib.h>
    39.5 +#include <string>
    39.6 +#include <cstring>
    39.7 +
    39.8 +#include "internal_format.h"
    39.9 +
   39.10 +#include "test_util.h"
   39.11 +#include "TestConstants.h"
   39.12 +#include "Engine.h"
   39.13 +
   39.14 +#include <gtest/gtest.h>
   39.15 +
   39.16 +
   39.17 +namespace {
   39.18 +
   39.19 +	//The fixture for ElevatedAttachmentsTest
   39.20 +    class ElevatedAttachmentsTest : public ::testing::Test {
   39.21 +        public:
   39.22 +            Engine* engine;
   39.23 +            PEP_SESSION session;
   39.24 +
   39.25 +        protected:
   39.26 +            // You can remove any or all of the following functions if its body
   39.27 +            // is empty.
   39.28 +            ElevatedAttachmentsTest() {
   39.29 +                // You can do set-up work for each test here.
   39.30 +                test_suite_name = ::testing::UnitTest::GetInstance()->current_test_info()->GTEST_SUITE_SYM();
   39.31 +                test_name = ::testing::UnitTest::GetInstance()->current_test_info()->name();
   39.32 +                test_path = get_main_test_home_dir() + "/" + test_suite_name + "/" + test_name;
   39.33 +            }
   39.34 +
   39.35 +            ~ElevatedAttachmentsTest() override {
   39.36 +                // You can do clean-up work that doesn't throw exceptions here.
   39.37 +            }
   39.38 +
   39.39 +            // If the constructor and destructor are not enough for setting up
   39.40 +            // and cleaning up each test, you can define the following methods:
   39.41 +
   39.42 +            void SetUp() override {
   39.43 +                // Code here will be called immediately after the constructor (right
   39.44 +                // before each test).
   39.45 +
   39.46 +                // Leave this empty if there are no files to copy to the home directory path
   39.47 +                std::vector<std::pair<std::string, std::string>> init_files = std::vector<std::pair<std::string, std::string>>();
   39.48 +
   39.49 +                // Get a new test Engine.
   39.50 +                engine = new Engine(test_path);
   39.51 +                ASSERT_NE(engine, nullptr);
   39.52 +
   39.53 +                // Ok, let's initialize test directories etc.
   39.54 +                engine->prep(NULL, NULL, init_files);
   39.55 +
   39.56 +                // Ok, try to start this bugger.
   39.57 +                engine->start();
   39.58 +                ASSERT_NE(engine->session, nullptr);
   39.59 +                session = engine->session;
   39.60 +
   39.61 +                // Engine is up. Keep on truckin'
   39.62 +            }
   39.63 +
   39.64 +            void TearDown() override {
   39.65 +                // Code here will be called immediately after each test (right
   39.66 +                // before the destructor).
   39.67 +                engine->shut_down();
   39.68 +                delete engine;
   39.69 +                engine = NULL;
   39.70 +                session = NULL;
   39.71 +            }
   39.72 +
   39.73 +        private:
   39.74 +            const char* test_suite_name;
   39.75 +            const char* test_name;
   39.76 +            string test_path;
   39.77 +            // Objects declared here can be used by all tests in the ElevatedAttachmentsTest suite.
   39.78 +
   39.79 +    };
   39.80 +
   39.81 +}  // namespace
   39.82 +
   39.83 +
   39.84 +TEST_F(ElevatedAttachmentsTest, check_internal_format) {
   39.85 +    const char *data = "simulated data";
   39.86 +    size_t data_size = strlen(data) + 1;
   39.87 +
   39.88 +    char *code;
   39.89 +    size_t code_size;
   39.90 +
   39.91 +    // test PGP keys
   39.92 +
   39.93 +    PEP_STATUS status = encode_internal(data, data_size, "application/pgp-keys", &code, &code_size);
   39.94 +    ASSERT_EQ(status, PEP_STATUS_OK);
   39.95 +    
   39.96 +    ASSERT_EQ(code_size, data_size + 4);
   39.97 +
   39.98 +    ASSERT_EQ(code[0], 0);
   39.99 +    ASSERT_EQ(code[1], 'K');
  39.100 +    ASSERT_EQ(code[2], 2);
  39.101 +
  39.102 +    ASSERT_STREQ(code + 4, data);
  39.103 +
  39.104 +    // decode
  39.105 +
  39.106 +    char *value;
  39.107 +    size_t size;
  39.108 +    char *mime_type;
  39.109 +
  39.110 +    status = decode_internal(code, code_size, &value, &size, &mime_type);
  39.111 +    ASSERT_EQ(status, PEP_STATUS_OK);
  39.112 +
  39.113 +    ASSERT_EQ(size, data_size);
  39.114 +    ASSERT_STREQ(value, data);
  39.115 +    ASSERT_STREQ(mime_type, "application/pgp-keys");
  39.116 +
  39.117 +    free(value);
  39.118 +    free(code);
  39.119 +
  39.120 +    // test Sync
  39.121 +
  39.122 +    status = encode_internal(data, data_size, "application/pEp.sync", &code, &code_size);
  39.123 +    ASSERT_EQ(status, PEP_STATUS_OK);
  39.124 +    
  39.125 +    ASSERT_EQ(code_size, data_size + 4);
  39.126 +
  39.127 +    ASSERT_EQ(code[0], 0);
  39.128 +    ASSERT_EQ(code[1], 'S');
  39.129 +    ASSERT_EQ(code[2], 0);
  39.130 +
  39.131 +    ASSERT_STREQ(code + 4, data);
  39.132 +
  39.133 +    // decode
  39.134 +
  39.135 +    status = decode_internal(code, code_size, &value, &size, &mime_type);
  39.136 +    ASSERT_EQ(status, PEP_STATUS_OK);
  39.137 +
  39.138 +    ASSERT_EQ(size, data_size);
  39.139 +    ASSERT_STREQ(value, data);
  39.140 +    ASSERT_STREQ(mime_type, "application/pEp.sync");
  39.141 +
  39.142 +    free(value);
  39.143 +    free(code);
  39.144 +
  39.145 +    // test Distribution
  39.146 +
  39.147 +    status = encode_internal(data, data_size, "application/pEp.distribution", &code, &code_size);
  39.148 +    ASSERT_EQ(status, PEP_STATUS_OK);
  39.149 +    
  39.150 +    ASSERT_EQ(code_size, data_size + 4);
  39.151 +
  39.152 +    ASSERT_EQ(code[0], 0);
  39.153 +    ASSERT_EQ(code[1], 'D');
  39.154 +    ASSERT_EQ(code[2], 0);
  39.155 +
  39.156 +    ASSERT_STREQ(code + 4, data);
  39.157 +
  39.158 +    // decode
  39.159 +
  39.160 +    status = decode_internal(code, code_size, &value, &size, &mime_type);
  39.161 +    ASSERT_EQ(status, PEP_STATUS_OK);
  39.162 +
  39.163 +    ASSERT_EQ(size, data_size);
  39.164 +    ASSERT_STREQ(value, data);
  39.165 +    ASSERT_STREQ(mime_type, "application/pEp.distribution");
  39.166 +
  39.167 +    free(value);
  39.168 +    free(code);
  39.169 +
  39.170 +    // test PGP signature
  39.171 +
  39.172 +    status = encode_internal(data, data_size, "application/pgp-signature", &code, &code_size);
  39.173 +    ASSERT_EQ(status, PEP_STATUS_OK);
  39.174 +    
  39.175 +    ASSERT_EQ(code_size, data_size + 4);
  39.176 +
  39.177 +    ASSERT_EQ(code[0], 0);
  39.178 +    ASSERT_EQ(code[1], 'A');
  39.179 +    ASSERT_EQ(code[2], 2);
  39.180 +
  39.181 +    ASSERT_STREQ(code + 4, data);
  39.182 +
  39.183 +    // decode
  39.184 +
  39.185 +    status = decode_internal(code, code_size, &value, &size, &mime_type);
  39.186 +    ASSERT_EQ(status, PEP_STATUS_OK);
  39.187 +
  39.188 +    ASSERT_EQ(size, data_size);
  39.189 +    ASSERT_STREQ(value, data);
  39.190 +    ASSERT_STREQ(mime_type, "application/pgp-signature");
  39.191 +
  39.192 +    free(value);
  39.193 +    free(code);
  39.194 +}
  39.195 +
  39.196 +TEST_F(ElevatedAttachmentsTest, check_encrypt_decrypt_message) {
  39.197 +    // a message from me, Alice, to Bob
  39.198 +
  39.199 +    const char* alice_fpr = "4ABE3AAF59AC32CFE4F86500A9411D176FF00E97";
  39.200 +    const char* bob_fpr = "BFCDB7F301DEEEBBF947F29659BFF488C9C2EE39";
  39.201 +    PEP_STATUS status = read_file_and_import_key(session,
  39.202 +                "test_keys/pub/pep-test-alice-0x6FF00E97_pub.asc");
  39.203 +    ASSERT_EQ(status , PEP_KEY_IMPORTED);
  39.204 +    status = set_up_ident_from_scratch(session,
  39.205 +                "test_keys/priv/pep-test-alice-0x6FF00E97_priv.asc",
  39.206 +                "pep.test.alice@pep-project.org", alice_fpr,
  39.207 +                PEP_OWN_USERID, "Alice in Wonderland", NULL, true
  39.208 +            );
  39.209 +    ASSERT_EQ(status , PEP_STATUS_OK);
  39.210 +    ASSERT_TRUE(slurp_and_import_key(session, "test_keys/pub/pep-test-bob-0xC9C2EE39_pub.asc"));
  39.211 +
  39.212 +    message* msg = new_message(PEP_dir_outgoing);
  39.213 +    pEp_identity* alice = new_identity("pep.test.alice@pep-project.org", NULL, PEP_OWN_USERID, NULL);
  39.214 +    pEp_identity* bob = new_identity("pep.test.bob@pep-project.org", NULL, "Bob", NULL);
  39.215 +    status = myself(session, alice);
  39.216 +    ASSERT_EQ(status , PEP_STATUS_OK);
  39.217 +    status = update_identity(session, bob);
  39.218 +    ASSERT_EQ(status , PEP_STATUS_OK);
  39.219 +
  39.220 +    status = set_as_pEp_user(session, bob);
  39.221 +    ASSERT_EQ(status , PEP_STATUS_OK);
  39.222 +
  39.223 +    msg->to = new_identity_list(bob);
  39.224 +    msg->from = alice;
  39.225 +    msg->shortmsg = strdup("Yo Bob!");
  39.226 +    msg->longmsg = strdup("Look at my hot new sender fpr field!");
  39.227 +
  39.228 +    const char *distribution = "simulation of distribution data";
  39.229 +    msg->attachments = new_bloblist(strdup(distribution), strlen(distribution)
  39.230 +            + 1, "application/pEp.distribution", "distribution.pEp");
  39.231 +
  39.232 +    // encrypt this message inline
  39.233 +
  39.234 +    message* enc_msg = NULL;
  39.235 +    status = encrypt_message(session, msg, NULL, &enc_msg, PEP_enc_inline, 0);
  39.236 +    ASSERT_EQ(status , PEP_STATUS_OK);
  39.237 +    
  39.238 +    // .shortmsg will stay unencrypted
  39.239 +    ASSERT_STREQ(msg->shortmsg, enc_msg->shortmsg);
  39.240 +
  39.241 +    // .longmsg will go encrypted
  39.242 +    ASSERT_TRUE(is_PGP_message_text(enc_msg->longmsg));
  39.243 +
  39.244 +    ASSERT_TRUE(enc_msg->attachments);
  39.245 +    ASSERT_TRUE(enc_msg->attachments->value);
  39.246 +
  39.247 +    bloblist_t *ad = enc_msg->attachments;
  39.248 +
  39.249 +    // distribution message is encrypted
  39.250 +    ASSERT_TRUE(is_PGP_message_text(ad->value));
  39.251 +    ASSERT_STREQ(ad->mime_type, "application/octet-stream");
  39.252 +    ASSERT_STREQ(ad->filename, "distribution.pEp.pgp");
  39.253 +
  39.254 +    // next attachment
  39.255 +    ASSERT_TRUE(ad->next);
  39.256 +    ad = ad->next;
  39.257 +
  39.258 +    // attached key is encrypted
  39.259 +    ASSERT_TRUE(is_PGP_message_text(ad->value));
  39.260 +    ASSERT_STREQ(ad->mime_type, "application/octet-stream");
  39.261 +    ASSERT_STREQ(ad->filename, "file://pEpkey.asc.pgp");
  39.262 +
  39.263 +    // decrypt this message
  39.264 +    
  39.265 +    message *dec_msg = NULL;
  39.266 +    stringlist_t *keylist = NULL;
  39.267 +    PEP_rating rating;
  39.268 +    PEP_decrypt_flags_t flags = 0;
  39.269 +
  39.270 +    status = decrypt_message(session, enc_msg, &dec_msg, &keylist, &rating, &flags);
  39.271 +    ASSERT_EQ(status, PEP_STATUS_OK);
  39.272 +    ASSERT_STREQ(dec_msg->shortmsg, enc_msg->shortmsg);
  39.273 +    ASSERT_STREQ(msg->longmsg, dec_msg->longmsg);
  39.274 +    
  39.275 +    // check attachments
  39.276 +    ASSERT_TRUE(dec_msg->attachments);
  39.277 +    ASSERT_TRUE(dec_msg->attachments->value);
  39.278 +    bloblist_t *as = dec_msg->attachments;
  39.279 +    bloblist_t *bl = msg->attachments;
  39.280 +
  39.281 +    ASSERT_STREQ(as->filename, "file://distribution.pEp");
  39.282 +    // the MIME will be derived from filename
  39.283 +    ASSERT_STREQ(as->mime_type, "application/pEp.distribution");
  39.284 +
  39.285 +    free_message(msg);
  39.286 +    free_message(enc_msg);
  39.287 +    free_message(dec_msg);
  39.288 +}
  39.289 +
  39.290 +TEST_F(ElevatedAttachmentsTest, check_encrypt_decrypt_message_elevated) {
  39.291 +    // a message from me, Alice, to Bob
  39.292 +
  39.293 +    const char* alice_fpr = "4ABE3AAF59AC32CFE4F86500A9411D176FF00E97";
  39.294 +    const char* bob_fpr = "BFCDB7F301DEEEBBF947F29659BFF488C9C2EE39";
  39.295 +    PEP_STATUS status = read_file_and_import_key(session,
  39.296 +                "test_keys/pub/pep-test-alice-0x6FF00E97_pub.asc");
  39.297 +    ASSERT_EQ(status , PEP_KEY_IMPORTED);
  39.298 +    status = set_up_ident_from_scratch(session,
  39.299 +                "test_keys/priv/pep-test-alice-0x6FF00E97_priv.asc",
  39.300 +                "pep.test.alice@pep-project.org", alice_fpr,
  39.301 +                PEP_OWN_USERID, "Alice in Wonderland", NULL, true
  39.302 +            );
  39.303 +    ASSERT_EQ(status , PEP_STATUS_OK);
  39.304 +    ASSERT_TRUE(slurp_and_import_key(session, "test_keys/pub/pep-test-bob-0xC9C2EE39_pub.asc"));
  39.305 +
  39.306 +    message* msg = new_message(PEP_dir_outgoing);
  39.307 +    pEp_identity* alice = new_identity("pep.test.alice@pep-project.org", NULL, PEP_OWN_USERID, NULL);
  39.308 +    pEp_identity* bob = new_identity("pep.test.bob@pep-project.org", NULL, "Bob", NULL);
  39.309 +    status = myself(session, alice);
  39.310 +    ASSERT_EQ(status , PEP_STATUS_OK);
  39.311 +    status = update_identity(session, bob);
  39.312 +    ASSERT_EQ(status , PEP_STATUS_OK);
  39.313 +
  39.314 +    status = set_as_pEp_user(session, bob);
  39.315 +    ASSERT_EQ(status , PEP_STATUS_OK);
  39.316 +
  39.317 +    msg->to = new_identity_list(bob);
  39.318 +    msg->from = alice;
  39.319 +    msg->shortmsg = strdup("Yo Bob!");
  39.320 +    msg->longmsg = strdup("Look at my hot new sender fpr field!");
  39.321 +
  39.322 +    const char *distribution = "simulation of distribution data";
  39.323 +    msg->attachments = new_bloblist(strdup(distribution), strlen(distribution)
  39.324 +            + 1, "application/pEp.distribution", "distribution.pEp");
  39.325 +
  39.326 +    // encrypt this message inline
  39.327 +
  39.328 +    message* enc_msg = NULL;
  39.329 +    status = encrypt_message(session, msg, NULL, &enc_msg, PEP_enc_inline_EA, 0);
  39.330 +    ASSERT_EQ(status , PEP_STATUS_OK);
  39.331 +    
  39.332 +    // .longmsg will go encrypted
  39.333 +    ASSERT_TRUE(is_PGP_message_text(enc_msg->longmsg));
  39.334 +
  39.335 +    ASSERT_TRUE(enc_msg->attachments);
  39.336 +    ASSERT_TRUE(enc_msg->attachments->value);
  39.337 +
  39.338 +    bloblist_t *ad = enc_msg->attachments;
  39.339 +
  39.340 +    // distribution message is encrypted
  39.341 +    ASSERT_TRUE(is_PGP_message_text(ad->value));
  39.342 +    ASSERT_STREQ(ad->mime_type, "application/octet-stream");
  39.343 +    ASSERT_STREQ(ad->filename, "distribution.pEp.pgp");
  39.344 +
  39.345 +    // next attachment
  39.346 +    ASSERT_TRUE(ad->next);
  39.347 +    ad = ad->next;
  39.348 +
  39.349 +    // attached key is encrypted
  39.350 +    ASSERT_TRUE(is_PGP_message_text(ad->value));
  39.351 +    ASSERT_STREQ(ad->mime_type, "application/octet-stream");
  39.352 +    ASSERT_STREQ(ad->filename, "file://pEpkey.asc.pgp");
  39.353 +
  39.354 +    char *ct = strdup(ad->value);
  39.355 +
  39.356 +    {
  39.357 +        // test if this is an elevated attachment
  39.358 +
  39.359 +        char *pt;
  39.360 +        size_t pt_size;
  39.361 +        stringlist_t *keylist;
  39.362 +
  39.363 +        // decrypt this part
  39.364 +
  39.365 +        status = decrypt_and_verify(session, ct, strlen(ct) + 1, NULL, 0, &pt, &pt_size, &keylist, NULL);
  39.366 +        ASSERT_EQ(status, PEP_DECRYPTED_AND_VERIFIED);
  39.367 +
  39.368 +        // decode internal message format
  39.369 +
  39.370 +        char *dt;
  39.371 +        size_t dt_size;
  39.372 +        char *mime_type;
  39.373 +        status = decode_internal(pt, pt_size, &dt, &dt_size, &mime_type);
  39.374 +        ASSERT_EQ(status, PEP_STATUS_OK);
  39.375 +        ASSERT_TRUE(dt);
  39.376 +        ASSERT_STREQ(mime_type, "application/pgp-keys");
  39.377 +
  39.378 +        free(pt);
  39.379 +        free(dt);
  39.380 +        free(mime_type);
  39.381 +        free_stringlist(keylist);
  39.382 +    }
  39.383 +
  39.384 +    // create artificial message for Key like a transport would do
  39.385 +
  39.386 +    message *art_msg = new_message(PEP_dir_incoming);
  39.387 +    art_msg->enc_format = PEP_enc_inline_EA;
  39.388 +    art_msg->from = identity_dup(enc_msg->to->ident);
  39.389 +    art_msg->to = new_identity_list(identity_dup(enc_msg->from));
  39.390 +    art_msg->longmsg = ct;
  39.391 +
  39.392 +    // decrypt this message
  39.393 +    
  39.394 +    message *dec_msg = NULL;
  39.395 +    stringlist_t *keylist = NULL;
  39.396 +    PEP_rating rating;
  39.397 +    PEP_decrypt_flags_t flags = 0;
  39.398 +
  39.399 +    status = decrypt_message(session, art_msg, &dec_msg, &keylist, &rating, &flags);
  39.400 +    ASSERT_EQ(status, PEP_STATUS_OK);
  39.401 +    ASSERT_TRUE(dec_msg);
  39.402 +    ASSERT_STREQ(dec_msg->attachments->mime_type, "application/pgp-keys");
  39.403 +    ASSERT_STREQ(dec_msg->shortmsg, "pEp");
  39.404 +
  39.405 +    stringpair_list_t *of;
  39.406 +    bool pEp_auto_consume_found = false;
  39.407 +    for (of = dec_msg->opt_fields; of && of->value; of = of->next) {
  39.408 +        if (strcasecmp(of->value->key, "pEp-auto-consume") == 0) {
  39.409 +            ASSERT_STREQ(of->value->value, "yes");
  39.410 +            pEp_auto_consume_found = true;
  39.411 +            break;
  39.412 +        }
  39.413 +    }
  39.414 +    ASSERT_TRUE(pEp_auto_consume_found);
  39.415 +
  39.416 +    free_message(msg);
  39.417 +    free_message(enc_msg);
  39.418 +    free_message(dec_msg);
  39.419 +    free_message(art_msg);
  39.420 +}
  39.421 +
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/test/src/EmptyLongmsgFullHtmlTest.cc	Mon Jun 08 15:01:34 2020 +0200
    40.3 @@ -0,0 +1,587 @@
    40.4 +#include <stdlib.h>
    40.5 +#include <string>
    40.6 +#include <cstring>
    40.7 +#include <iostream>
    40.8 +#include <fstream>
    40.9 +#include <sys/types.h>
   40.10 +#include <sys/stat.h>
   40.11 +#include <unistd.h>
   40.12 +
   40.13 +#include "pEpEngine.h"
   40.14 +#include "test_util.h"
   40.15 +#include "TestConstants.h"
   40.16 +#include "Engine.h"
   40.17 +
   40.18 +#include <gtest/gtest.h>
   40.19 +
   40.20 +
   40.21 +namespace {
   40.22 +
   40.23 +	//The fixture for EmptyLongmsgFullHtmlTest
   40.24 +    class EmptyLongmsgFullHtmlTest : public ::testing::Test {
   40.25 +        public:
   40.26 +            Engine* engine;
   40.27 +            PEP_SESSION session;
   40.28 +
   40.29 +        protected:
   40.30 +            // You can remove any or all of the following functions if its body
   40.31 +            // is empty.
   40.32 +            EmptyLongmsgFullHtmlTest() {
   40.33 +                // You can do set-up work for each test here.
   40.34 +                test_suite_name = ::testing::UnitTest::GetInstance()->current_test_info()->GTEST_SUITE_SYM();
   40.35 +                test_name = ::testing::UnitTest::GetInstance()->current_test_info()->name();
   40.36 +                test_path = get_main_test_home_dir() + "/" + test_suite_name + "/" + test_name;
   40.37 +            }
   40.38 +
   40.39 +            ~EmptyLongmsgFullHtmlTest() override {
   40.40 +                // You can do clean-up work that doesn't throw exceptions here.
   40.41 +            }
   40.42 +
   40.43 +            // If the constructor and destructor are not enough for setting up
   40.44 +            // and cleaning up each test, you can define the following methods:
   40.45 +
   40.46 +            void SetUp() override {
   40.47 +                // Code here will be called immediately after the constructor (right
   40.48 +                // before each test).
   40.49 +
   40.50 +                // Leave this empty if there are no files to copy to the home directory path
   40.51 +                std::vector<std::pair<std::string, std::string>> init_files = std::vector<std::pair<std::string, std::string>>();
   40.52 +
   40.53 +                // Get a new test Engine.
   40.54 +                engine = new Engine(test_path);
   40.55 +                ASSERT_NE(engine, nullptr);
   40.56 +
   40.57 +                // Ok, let's initialize test directories etc.
   40.58 +                engine->prep(NULL, NULL, init_files);
   40.59 +
   40.60 +                // Ok, try to start this bugger.
   40.61 +                engine->start();
   40.62 +                ASSERT_NE(engine->session, nullptr);
   40.63 +                session = engine->session;
   40.64 +
   40.65 +                // Engine is up. Keep on truckin'
   40.66 +            }
   40.67 +
   40.68 +            const char* html_text =
   40.69 +                "<html>\n"
   40.70 +                "  <head>\n"
   40.71 +                "    <meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n"
   40.72 +                "  </head>\n"
   40.73 +                "  <body>\n"
   40.74 +                "    <table width=\"100%\" cellspacing=\"2\" cellpadding=\"2\" border=\"1\"\n"
   40.75 +                "      bgcolor=\"pink\">\n"
   40.76 +                "      <tbody>\n"
   40.77 +                "        <tr>\n"
   40.78 +                "          <td valign=\"top\" bgcolor=\"pink\"><img moz-do-not-send=\"false\"\n"
   40.79 +                "              src=\"cid:part1.21156198.7E41C8BF@darthmama.org\" alt=\"Tiny\n"
   40.80 +                "              Canth cat\" width=\"144\" height=\"204\"><br>\n"
   40.81 +                "          </td>\n"
   40.82 +                "          <td valign=\"top\"><br>\n"
   40.83 +                "          </td>\n"
   40.84 +                "        </tr>\n"
   40.85 +                "        <tr>\n"
   40.86 +                "          <td valign=\"top\"><br>\n"
   40.87 +                "          </td>\n"
   40.88 +                "          <td valign=\"top\"><br>\n"
   40.89 +                "          </td>\n"
   40.90 +                "        </tr>\n"
   40.91 +                "        <tr>\n"
   40.92 +                "          <td valign=\"top\"><br>\n"
   40.93 +                "          </td>\n"
   40.94 +                "          <td valign=\"top\"><br>\n"
   40.95 +                "          </td>\n"
   40.96 +                "        </tr>\n"
   40.97 +                "      </tbody>\n"
   40.98 +                "    </table>\n"
   40.99 +                "    <p><br>\n"
  40.100 +                "    </p>\n"
  40.101 +                "  </body>\n"
  40.102 +                "</html>\n";
  40.103 +
  40.104 +            void TearDown() override {
  40.105 +                // Code here will be called immediately after each test (right
  40.106 +                // before the destructor).
  40.107 +                engine->shut_down();
  40.108 +                delete engine;
  40.109 +                engine = NULL;
  40.110 +                session = NULL;
  40.111 +            }
  40.112 +
  40.113 +        private:
  40.114 +            const char* test_suite_name;
  40.115 +            const char* test_name;
  40.116 +            string test_path;
  40.117 +            // Objects declared here can be used by all tests in the EmptyLongmsgFullHtmlTest suite.
  40.118 +
  40.119 +    };
  40.120 +
  40.121 +}  // namespace
  40.122 +
  40.123 +
  40.124 +TEST_F(EmptyLongmsgFullHtmlTest, check_empty_longmsg_full_html_NULL) {
  40.125 +    // This is just a dummy test case. The convention is check_whatever_you_are_checking
  40.126 +    // so for multiple test cases in a suite, be more explicit ;)
  40.127 +    pEp_identity* carol = NULL;
  40.128 +    PEP_STATUS status = set_up_preset(session, CAROL, true, true, true, true, true, &carol); 
  40.129 +    pEp_identity* dave = NULL;
  40.130 +    status = set_up_preset(session, DAVE, true, true, true, false, false, &dave);
  40.131 +    
  40.132 +    message* msg = new_message(PEP_dir_outgoing);
  40.133 +    msg->from = carol;
  40.134 +    msg->to = new_identity_list(dave);
  40.135 +    msg->longmsg_formatted = strdup("<html>\n<body>\n<h1>HTML Mail is For Losers</h1>\n<p>But people use it.</p>\n</body>\n</html>\n");
  40.136 +    msg->shortmsg = strdup("Eat Moar Cheese");
  40.137 +    
  40.138 +    char* outmsg = NULL;
  40.139 +    mime_encode_message(msg, false, &outmsg, false);
  40.140 +    
  40.141 +    cout << outmsg << endl;
  40.142 +    
  40.143 +}
  40.144 +
  40.145 +TEST_F(EmptyLongmsgFullHtmlTest, check_empty_longmsg_full_html_text_att) {
  40.146 +    // This is just a dummy test case. The convention is check_whatever_you_are_checking
  40.147 +    // so for multiple test cases in a suite, be more explicit ;)
  40.148 +    pEp_identity* carol = NULL;
  40.149 +    PEP_STATUS status = set_up_preset(session, CAROL, true, true, true, true, true, &carol); 
  40.150 +    pEp_identity* dave = NULL;
  40.151 +    status = set_up_preset(session, DAVE, true, true, true, false, false, &dave);
  40.152 +    
  40.153 +    message* msg = new_message(PEP_dir_outgoing);
  40.154 +    msg->from = carol;
  40.155 +    msg->to = new_identity_list(dave);
  40.156 +    msg->longmsg_formatted = strdup("<html>\n<body>\n<h1>HTML Mail is For Losers</h1>\n<p>But people use it.</p>\n</body>\n</html>\n");
  40.157 +    msg->shortmsg = strdup("Eat Moar Cheese");
  40.158 +    
  40.159 +    char* text_att = strdup("This is a text attachment.\n");
  40.160 +    msg->attachments = new_bloblist(text_att, strlen(text_att), "text/plain", NULL);
  40.161 +    
  40.162 +    char* outmsg = NULL;
  40.163 +    mime_encode_message(msg, false, &outmsg, false);
  40.164 +    
  40.165 +    ASSERT_EQ(strstr(outmsg, "alternative"), nullptr);
  40.166 +    
  40.167 +    cout << outmsg << endl;
  40.168 +    
  40.169 +}
  40.170 +
  40.171 +TEST_F(EmptyLongmsgFullHtmlTest, check_empty_longmsg_full_html_html_att) {
  40.172 +    // This is just a dummy test case. The convention is check_whatever_you_are_checking
  40.173 +    // so for multiple test cases in a suite, be more explicit ;)
  40.174 +    pEp_identity* carol = NULL;
  40.175 +    PEP_STATUS status = set_up_preset(session, CAROL, true, true, true, true, true, &carol); 
  40.176 +    pEp_identity* dave = NULL;
  40.177 +    status = set_up_preset(session, DAVE, true, true, true, false, false, &dave);
  40.178 +    
  40.179 +    message* msg = new_message(PEP_dir_outgoing);
  40.180 +    msg->from = carol;
  40.181 +    msg->to = new_identity_list(dave);
  40.182 +    msg->longmsg_formatted = strdup("<html>\n<body>\n<h1>HTML Mail is For Losers</h1>\n<p>But people use it.</p>\n</body>\n</html>\n");
  40.183 +    msg->shortmsg = strdup("Eat Moar Cheese");
  40.184 +    
  40.185 +    char* text_att = strdup("This is a text attachment.\n");
  40.186 +    msg->attachments = new_bloblist(text_att, strlen(text_att), "text/plain", NULL);
  40.187 +    
  40.188 +    char* outmsg = NULL;
  40.189 +    mime_encode_message(msg, false, &outmsg, false);
  40.190 +    
  40.191 +    ASSERT_EQ(strstr(outmsg, "alternative"), nullptr);
  40.192 +    ASSERT_EQ(strstr(outmsg, "related"), nullptr);
  40.193 +    ASSERT_NE(strstr(outmsg, "mixed"), nullptr);
  40.194 +            
  40.195 +    cout << outmsg << endl;
  40.196 +    
  40.197 +}
  40.198 +
  40.199 +TEST_F(EmptyLongmsgFullHtmlTest, check_empty_longmsg_full_html_text_html_atts) {
  40.200 +    // This is just a dummy test case. The convention is check_whatever_you_are_checking
  40.201 +    // so for multiple test cases in a suite, be more explicit ;)
  40.202 +    pEp_identity* carol = NULL;
  40.203 +    PEP_STATUS status = set_up_preset(session, CAROL, true, true, true, true, true, &carol); 
  40.204 +    pEp_identity* dave = NULL;
  40.205 +    status = set_up_preset(session, DAVE, true, true, true, false, false, &dave);
  40.206 +    
  40.207 +    message* msg = new_message(PEP_dir_outgoing);
  40.208 +    msg->from = carol;
  40.209 +    msg->to = new_identity_list(dave);
  40.210 +    msg->longmsg_formatted = strdup("<html>\n<body>\n<h1>HTML Mail is For Losers</h1>\n<p>But people use it.</p>\n</body>\n</html>\n");
  40.211 +    msg->shortmsg = strdup("Eat Moar Cheese");
  40.212 +    
  40.213 +    char* text_att = strdup("This is a text attachment.\n");
  40.214 +    msg->attachments = new_bloblist(text_att, strlen(text_att), "text/plain", "texty.txt");
  40.215 +    char* html_att = strdup("<html>\n<body>\n<h1>Warning!</h1>\n<p>Totally wasn't kidding about html mail.</p>\n</body>\n</html>\n");
  40.216 +    bloblist_add(msg->attachments, html_att, strlen(html_att), "text/html", "stupid_msg.html");
  40.217 +
  40.218 +    char* outmsg = NULL;
  40.219 +    mime_encode_message(msg, false, &outmsg, false);
  40.220 +    
  40.221 +    // Could do more here, but honestly, these are just sanity checks, as mostly this is getting checked by inspection
  40.222 +    ASSERT_EQ(strstr(outmsg, "alternative"), nullptr);
  40.223 +    ASSERT_EQ(strstr(outmsg, "related"), nullptr);
  40.224 +    ASSERT_NE(strstr(outmsg, "mixed"), nullptr);
  40.225 +    
  40.226 +    cout << outmsg << endl;
  40.227 +    
  40.228 +    const char* body_html_text = strstr(outmsg, "HTML Mail");
  40.229 +    ASSERT_NE(body_html_text, nullptr);
  40.230 +    const char* att_html_text = strstr(body_html_text + 1, "Warning");
  40.231 +    ASSERT_GT(att_html_text, body_html_text);
  40.232 +
  40.233 +            
  40.234 +    const char* chkstr = strstr(outmsg, "Content-Disposition: attachment");
  40.235 +    ASSERT_NE(chkstr, nullptr);
  40.236 +    chkstr = strstr(chkstr + strlen("Content-Disposition: attachment"), "Content-Disposition: attachment");    
  40.237 +    ASSERT_NE(chkstr, nullptr);        
  40.238 +    chkstr = strstr(chkstr + strlen("Content-Disposition: attachment"), "Content-Disposition: attachment");
  40.239 +    ASSERT_EQ(chkstr, nullptr);
  40.240 +    
  40.241 +}
  40.242 +
  40.243 +TEST_F(EmptyLongmsgFullHtmlTest, check_empty_longmsg_full_html_html_text_atts) {
  40.244 +    pEp_identity* carol = NULL;
  40.245 +    PEP_STATUS status = set_up_preset(session, CAROL, true, true, true, true, true, &carol); 
  40.246 +    pEp_identity* dave = NULL;
  40.247 +    status = set_up_preset(session, DAVE, true, true, true, false, false, &dave);
  40.248 +    
  40.249 +    message* msg = new_message(PEP_dir_outgoing);
  40.250 +    msg->from = carol;
  40.251 +    msg->to = new_identity_list(dave);
  40.252 +    msg->longmsg_formatted = strdup("<html>\n<body>\n<h1>HTML Mail is For Losers</h1>\n<p>But people use it.</p>\n</body>\n</html>\n");
  40.253 +    msg->shortmsg = strdup("Eat Moar Cheese");
  40.254 +    
  40.255 +    char* html_att = strdup("<html>\n<body>\n<h1>Warning!</h1>\n<p>Totally wasn't kidding about html mail.</p>\n</body>\n</html>\n");
  40.256 +    msg->attachments = new_bloblist(html_att, strlen(html_att), "text/html", "blargh.html");    
  40.257 +    char* text_att = strdup("This is a text attachment.\n");
  40.258 +    msg->attachments->next = new_bloblist(text_att, strlen(text_att), "text/plain", "blargh.txt");
  40.259 +    
  40.260 +    char* outmsg = NULL;
  40.261 +    mime_encode_message(msg, false, &outmsg, false);
  40.262 +    
  40.263 +    cout << outmsg << endl;
  40.264 +        
  40.265 +    // Could do more here, but honestly, these are just sanity checks, as mostly this is getting checked by inspection
  40.266 +    ASSERT_EQ(strstr(outmsg, "alternative"), nullptr);
  40.267 +    ASSERT_EQ(strstr(outmsg, "related"), nullptr);    
  40.268 +    ASSERT_NE(strstr(outmsg, "mixed"), nullptr);    
  40.269 +    const char* body_html_text = strstr(outmsg, "HTML Mail");
  40.270 +    ASSERT_NE(body_html_text, nullptr);
  40.271 +    const char* att_html_text = strstr(body_html_text + 1, "Warning");
  40.272 +    ASSERT_GT(att_html_text, body_html_text);
  40.273 +        
  40.274 +    const char* chkstr = strstr(outmsg, "Content-Disposition: attachment");
  40.275 +    ASSERT_NE(chkstr, nullptr);
  40.276 +    chkstr = strstr(chkstr + strlen("Content-Disposition: attachment"), "Content-Disposition: attachment");    
  40.277 +    ASSERT_NE(chkstr, nullptr);        
  40.278 +    chkstr = strstr(chkstr + strlen("Content-Disposition: attachment"), "Content-Disposition: attachment");
  40.279 +    ASSERT_EQ(chkstr, nullptr);
  40.280 +    
  40.281 +}
  40.282 +
  40.283 +TEST_F(EmptyLongmsgFullHtmlTest, check_empty_longmsg_full_html_text_empty) {
  40.284 +    // This is just a dummy test case. The convention is check_whatever_you_are_checking
  40.285 +    // so for multiple test cases in a suite, be more explicit ;)
  40.286 +    pEp_identity* carol = NULL;
  40.287 +    PEP_STATUS status = set_up_preset(session, CAROL, true, true, true, true, true, &carol); 
  40.288 +    pEp_identity* dave = NULL;
  40.289 +    status = set_up_preset(session, DAVE, true, true, true, false, false, &dave);
  40.290 +    
  40.291 +    message* msg = new_message(PEP_dir_outgoing);
  40.292 +    msg->from = carol;
  40.293 +    msg->to = new_identity_list(dave);
  40.294 +    msg->longmsg_formatted = strdup("<html>\n<body>\n<h1>HTML Mail is For Losers</h1>\n<p>But people use it.</p>\n</body>\n</html>\n");
  40.295 +    msg->shortmsg = strdup("Eat Moar Cheese");
  40.296 +    msg->longmsg = strdup("");
  40.297 +        
  40.298 +    char* outmsg = NULL;
  40.299 +    mime_encode_message(msg, false, &outmsg, false);
  40.300 +        
  40.301 +    cout << outmsg << endl;
  40.302 +    
  40.303 +}
  40.304 +
  40.305 +TEST_F(EmptyLongmsgFullHtmlTest, check_empty_longmsg_full_html_text_inline_att) {
  40.306 +    // This is just a dummy test case. The convention is check_whatever_you_are_checking
  40.307 +    // so for multiple test cases in a suite, be more explicit ;)
  40.308 +    pEp_identity* carol = NULL;
  40.309 +    PEP_STATUS status = set_up_preset(session, CAROL, true, true, true, true, true, &carol); 
  40.310 +    pEp_identity* dave = NULL;
  40.311 +    status = set_up_preset(session, DAVE, true, true, true, false, false, &dave);
  40.312 +    
  40.313 +    message* msg = new_message(PEP_dir_outgoing);
  40.314 +    msg->from = carol;
  40.315 +    msg->to = new_identity_list(dave);
  40.316 +        
  40.317 +    msg->longmsg_formatted = strdup(html_text);
  40.318 +    msg->shortmsg = strdup("Eat Moar Cheese");
  40.319 +        
  40.320 +    
  40.321 +    int retval = 0;
  40.322 +    
  40.323 +#ifndef WIN32
  40.324 +    struct stat fst;    
  40.325 +    retval = stat("test_files/meow.jpeg", &fst);
  40.326 +#else 
  40.327 +    struct _stat fst;
  40.328 +    retval = _stat("test_files/meow.jpeg", &fst);
  40.329 +#endif 
  40.330 +    
  40.331 +    ASSERT_EQ(retval, 0);
  40.332 +    size_t img_size = (size_t)(fst.st_size);
  40.333 +    ASSERT_NE(img_size, 0);
  40.334 +    char* img = (char*)calloc(1, img_size);
  40.335 +    
  40.336 +    ifstream img_file("test_files/meow.jpeg", ios::in | ios::binary);
  40.337 +    
  40.338 +    img_file.read(img, img_size);
  40.339 +    img_file.close();
  40.340 +    
  40.341 +    msg->attachments = new_bloblist(img, img_size, "image/jpeg", "cid://part1.21156198.7E41C8BF@darthmama.org");
  40.342 +        
  40.343 +    char* outmsg = NULL;
  40.344 +    mime_encode_message(msg, false, &outmsg, false);
  40.345 +        
  40.346 +    ASSERT_EQ(strstr(outmsg, "alternative"), nullptr);
  40.347 +    ASSERT_NE(strstr(outmsg, "related"), nullptr);
  40.348 +    ASSERT_EQ(strstr(outmsg, "Content-Disposition: attachment"), nullptr);
  40.349 +            
  40.350 +    cout << outmsg << endl;
  40.351 +    
  40.352 +}
  40.353 +
  40.354 +TEST_F(EmptyLongmsgFullHtmlTest, check_empty_longmsg_full_html_text_inline_att_plus_att) {
  40.355 +    // This is just a dummy test case. The convention is check_whatever_you_are_checking
  40.356 +    // so for multiple test cases in a suite, be more explicit ;)
  40.357 +    pEp_identity* carol = NULL;
  40.358 +    PEP_STATUS status = set_up_preset(session, CAROL, true, true, true, true, true, &carol); 
  40.359 +    pEp_identity* dave = NULL;
  40.360 +    status = set_up_preset(session, DAVE, true, true, true, false, false, &dave);
  40.361 +    
  40.362 +    message* msg = new_message(PEP_dir_outgoing);
  40.363 +    msg->from = carol;
  40.364 +    msg->to = new_identity_list(dave);
  40.365 +    msg->longmsg_formatted = strdup(html_text);
  40.366 +    msg->shortmsg = strdup("Eat Moar Cheese");
  40.367 +            
  40.368 +    int retval = 0;
  40.369 +    
  40.370 +#ifndef WIN32
  40.371 +    struct stat fst;    
  40.372 +    retval = stat("test_files/meow.jpeg", &fst);
  40.373 +#else 
  40.374 +    struct _stat fst;
  40.375 +    retval = _stat("test_files/meow.jpeg", &fst);
  40.376 +#endif 
  40.377 +    
  40.378 +    ASSERT_EQ(retval, 0);
  40.379 +    size_t img_size = (size_t)(fst.st_size);
  40.380 +    ASSERT_NE(img_size, 0);
  40.381 +    char* img = (char*)calloc(1, img_size);
  40.382 +    
  40.383 +    ifstream img_file("test_files/meow.jpeg", ios::in | ios::binary);
  40.384 +    
  40.385 +    img_file.read(img, img_size);
  40.386 +    img_file.close();
  40.387 +    
  40.388 +    // FIXME: When we clean up this test and actually, you know, free the memory, be careful -
  40.389 +    // both data parts of the bloblist are actually the same pointer. Bad form :)
  40.390 +    msg->attachments = new_bloblist(img, img_size, "image/jpeg", "cid://part1.21156198.7E41C8BF@darthmama.org");
  40.391 +    bloblist_add(msg->attachments, img, img_size, "image/jpeg", "meow.jpg");
  40.392 +        
  40.393 +    char* outmsg = NULL;
  40.394 +    mime_encode_message(msg, false, &outmsg, false);
  40.395 +        
  40.396 +    ASSERT_EQ(strstr(outmsg, "alternative"), nullptr);
  40.397 +    ASSERT_NE(strstr(outmsg, "related"), nullptr);
  40.398 +    ASSERT_NE(strstr(outmsg, "mixed"), nullptr);      
  40.399 +    ASSERT_NE(strstr(outmsg, "Content-ID: <part1.21156198.7E41C8BF@darthmama.org>"), nullptr);
  40.400 +    ASSERT_NE(strstr(outmsg, "Content-Disposition: attachment; filename=\"meow.jpg\""), nullptr);
  40.401 +    cout << outmsg << endl;
  40.402 +}
  40.403 +
  40.404 +// Ok, let's check the same for the empty html parsing problem
  40.405 +TEST_F(EmptyLongmsgFullHtmlTest, check_parse_simple_html_only) {
  40.406 +    string msg_str = slurp("test_mails/htmlonly_simple.eml");
  40.407 +    message* msg = NULL;
  40.408 +    int size = 0;
  40.409 +    mime_decode_message(msg_str.c_str(), msg_str.size(), &msg, NULL);
  40.410 +    
  40.411 +    ASSERT_NE(msg, nullptr);
  40.412 +    ASSERT_EQ(msg->longmsg, nullptr);
  40.413 +    ASSERT_NE(msg->longmsg_formatted, nullptr);
  40.414 +    ASSERT_EQ(msg->attachments, nullptr);
  40.415 +    
  40.416 +    cout << msg->longmsg_formatted << endl;
  40.417 +}
  40.418 +
  40.419 +TEST_F(EmptyLongmsgFullHtmlTest, check_parse_simple_html_text_attachment) {
  40.420 +    string msg_str = slurp("test_mails/html_with_text_attachment.eml");
  40.421 +    message* msg = NULL;
  40.422 +    int size = 0;
  40.423 +    mime_decode_message(msg_str.c_str(), msg_str.size(), &msg, NULL);
  40.424 +    
  40.425 +    ASSERT_NE(msg, nullptr);
  40.426 +    ASSERT_EQ(msg->longmsg, nullptr);
  40.427 +    ASSERT_NE(msg->longmsg_formatted, nullptr);
  40.428 +    ASSERT_NE(msg->attachments, nullptr);
  40.429 +    ASSERT_STREQ(msg->attachments->mime_type, "text/plain");
  40.430 +    string att_txt = "Your mother was a hamster\nAnd your father smelt of elterberries";
  40.431 +    ASSERT_EQ(memcmp(att_txt.c_str(), msg->attachments->value, att_txt.size()), 0);
  40.432 +    ASSERT_EQ(msg->attachments->next, nullptr);    
  40.433 +    cout << msg->longmsg_formatted << endl;
  40.434 +}
  40.435 +
  40.436 +TEST_F(EmptyLongmsgFullHtmlTest, check_parse_simple_html_text_html_attachment) {
  40.437 +    string msg_str = slurp("test_mails/htmlonly_simple_text_html.eml");
  40.438 +    message* msg = NULL;
  40.439 +    int size = 0;
  40.440 +    mime_decode_message(msg_str.c_str(), msg_str.size(), &msg, NULL);
  40.441 +    
  40.442 +    ASSERT_NE(msg, nullptr);
  40.443 +    ASSERT_EQ(msg->longmsg, nullptr);
  40.444 +    ASSERT_NE(msg->longmsg_formatted, nullptr);
  40.445 +    ASSERT_NE(msg->attachments, nullptr);
  40.446 +    ASSERT_STREQ(msg->attachments->mime_type, "text/plain");
  40.447 +    string att_txt = "\nBAH.\n";
  40.448 +    ASSERT_EQ(memcmp(att_txt.c_str(), msg->attachments->value, att_txt.size()), 0);
  40.449 +    ASSERT_NE(msg->attachments->next, nullptr);    
  40.450 +    ASSERT_STREQ(msg->attachments->next->mime_type, "text/html");
  40.451 +    string html_txt = "<html>\n<body>\n<h1>HTML Mail is For Losers</h1>\n<p>But people use it.</p>\n</body>\n</html>\n";
  40.452 +    ASSERT_EQ(memcmp(html_txt.c_str(), msg->attachments->next->value, html_txt.size()), 0);        
  40.453 +    ASSERT_EQ(msg->attachments->next->next, nullptr);
  40.454 +}
  40.455 +
  40.456 +
  40.457 +TEST_F(EmptyLongmsgFullHtmlTest, check_parse_simple_html_html_text_attachment) {
  40.458 +    string msg_str = slurp("test_mails/htmlonly_simple_html_text.eml");
  40.459 +    message* msg = NULL;
  40.460 +    int size = 0;
  40.461 +    mime_decode_message(msg_str.c_str(), msg_str.size(), &msg, NULL);
  40.462 +
  40.463 +    ASSERT_EQ(msg->longmsg, nullptr);
  40.464 +    ASSERT_NE(msg->longmsg_formatted, nullptr);
  40.465 +    ASSERT_NE(msg->attachments, nullptr);
  40.466 +    ASSERT_NE(msg->attachments->next, nullptr);    
  40.467 +    ASSERT_STREQ(msg->attachments->mime_type, "text/html");
  40.468 +    string att_txt = "\nBAH.\n";
  40.469 +    string html_txt = "<html>\n<body>\n<h1>HTML Mail is For Losers</h1>\n<p>But people use it.</p>\n</body>\n</html>\n";
  40.470 +    ASSERT_EQ(memcmp(html_txt.c_str(), msg->attachments->value, html_txt.size()), 0);        
  40.471 +    ASSERT_STREQ(msg->attachments->next->mime_type, "text/plain");
  40.472 +    ASSERT_EQ(memcmp(att_txt.c_str(), msg->attachments->next->value, att_txt.size()), 0);
  40.473 +    ASSERT_EQ(msg->attachments->next->next, nullptr);
  40.474 +}
  40.475 +
  40.476 +
  40.477 +TEST_F(EmptyLongmsgFullHtmlTest, check_parse_simple_inline_html) {
  40.478 +    string msg_str = slurp("test_mails/inlinecat.eml");
  40.479 +    message* msg = NULL;
  40.480 +    int size = 0;
  40.481 +    mime_decode_message(msg_str.c_str(), msg_str.size(), &msg, NULL);
  40.482 +    
  40.483 +    ASSERT_NE(msg, nullptr);
  40.484 +    ASSERT_EQ(msg->longmsg, nullptr);
  40.485 +    ASSERT_NE(msg->longmsg_formatted, nullptr);
  40.486 +    ASSERT_NE(msg->attachments, nullptr);
  40.487 +    ASSERT_STREQ(msg->attachments->mime_type, "image/jpeg");
  40.488 +
  40.489 +    int retval = 0;
  40.490 +#ifndef WIN32
  40.491 +    struct stat fst;    
  40.492 +    retval = stat("test_files/meow.jpeg", &fst);
  40.493 +#else 
  40.494 +    struct _stat fst;
  40.495 +    retval = _stat("test_files/meow.jpeg", &fst);
  40.496 +#endif 
  40.497 +    
  40.498 +    ASSERT_EQ(retval, 0);
  40.499 +    size_t img_size = (size_t)(fst.st_size);
  40.500 +    ASSERT_NE(img_size, 0);
  40.501 +    char* img = (char*)calloc(1, img_size);
  40.502 +
  40.503 +    ifstream img_file("test_files/meow.jpeg", ios::in | ios::binary);
  40.504 +    
  40.505 +    img_file.read(img, img_size);
  40.506 +    img_file.close();
  40.507 +    
  40.508 +    ASSERT_EQ(memcmp(img, msg->attachments->value, msg->attachments->size), 0);
  40.509 +    ASSERT_EQ(msg->attachments->disposition, PEP_CONTENT_DISP_INLINE);    
  40.510 +    ASSERT_EQ(msg->attachments->next, nullptr);    
  40.511 +    cout << msg->longmsg_formatted << endl;    
  40.512 +}
  40.513 +
  40.514 +TEST_F(EmptyLongmsgFullHtmlTest, check_parse_inline_html_text_attachment) {
  40.515 +    string msg_str = slurp("test_mails/htmlonlycatwtextatt.eml");
  40.516 +    message* msg = NULL;
  40.517 +    int size = 0;
  40.518 +    mime_decode_message(msg_str.c_str(), msg_str.size(), &msg, NULL);
  40.519 +    
  40.520 +    ASSERT_NE(msg, nullptr);
  40.521 +    ASSERT_EQ(msg->longmsg, nullptr);
  40.522 +    ASSERT_NE(msg->longmsg_formatted, nullptr);
  40.523 +    ASSERT_NE(msg->attachments, nullptr);
  40.524 +    
  40.525 +    // there should be 2 attachments
  40.526 +    ASSERT_NE(msg->attachments->next, nullptr);
  40.527 +    ASSERT_EQ(msg->attachments->next->next, nullptr);    
  40.528 +    
  40.529 +    bloblist_t* text_att = NULL;
  40.530 +    bloblist_t* img_att = NULL;    
  40.531 +    if (strcmp("text/plain", msg->attachments->mime_type) == 0) {
  40.532 +        text_att = msg->attachments;
  40.533 +        img_att = msg->attachments->next;        
  40.534 +        ASSERT_STREQ(img_att->mime_type, "image/jpeg");
  40.535 +    }
  40.536 +    else {
  40.537 +        img_att = msg->attachments;
  40.538 +        text_att = msg->attachments->next;
  40.539 +        ASSERT_STREQ(img_att->mime_type, "image/jpeg");
  40.540 +        ASSERT_STREQ(text_att->mime_type, "text/plain");        
  40.541 +    }
  40.542 +        
  40.543 +    string att_txt = "Your mother was a hamster\nAnd your father smelt of elterberries";
  40.544 +    ASSERT_EQ(memcmp(att_txt.c_str(), text_att->value, att_txt.size()), 0);
  40.545 +    ASSERT_EQ(text_att->disposition, PEP_CONTENT_DISP_ATTACHMENT);    
  40.546 +    ASSERT_STREQ(text_att->filename, "file://blargh.txt");
  40.547 +    
  40.548 +    ASSERT_EQ(img_att->disposition, PEP_CONTENT_DISP_INLINE);
  40.549 +    ASSERT_STREQ(img_att->filename, "cid://part1.21156198.7E41C8BF@darthmama.org");
  40.550 +    
  40.551 +    cout << msg->longmsg_formatted << endl;    
  40.552 +}
  40.553 +
  40.554 +TEST_F(EmptyLongmsgFullHtmlTest, check_parse_inline_html_img_attachment) {
  40.555 +    string msg_str = slurp("test_mails/htmlonlycatwithMOARCAT.eml");
  40.556 +    message* msg = NULL;
  40.557 +    int size = 0;
  40.558 +    mime_decode_message(msg_str.c_str(), msg_str.size(), &msg, NULL);
  40.559 +    
  40.560 +    ASSERT_NE(msg, nullptr);
  40.561 +    ASSERT_EQ(msg->longmsg, nullptr);
  40.562 +    ASSERT_NE(msg->longmsg_formatted, nullptr);
  40.563 +    ASSERT_NE(msg->attachments, nullptr);
  40.564 +    
  40.565 +    // there should be 2 attachments
  40.566 +    ASSERT_NE(msg->attachments->next, nullptr);
  40.567 +    ASSERT_EQ(msg->attachments->next->next, nullptr);    
  40.568 +    
  40.569 +    bloblist_t* img_not_inline_att = NULL;
  40.570 +    bloblist_t* img_inline_att = NULL;
  40.571 +    
  40.572 +    if (msg->attachments->disposition == PEP_CONTENT_DISP_INLINE) {
  40.573 +        img_inline_att = msg->attachments;
  40.574 +        img_not_inline_att = msg->attachments->next;
  40.575 +    }   
  40.576 +    else {
  40.577 +        img_inline_att = msg->attachments;
  40.578 +        img_not_inline_att = msg->attachments->next;
  40.579 +        ASSERT_EQ(img_inline_att->disposition, PEP_CONTENT_DISP_INLINE);        
  40.580 +    }     
  40.581 +    ASSERT_EQ(img_not_inline_att->disposition, PEP_CONTENT_DISP_ATTACHMENT);
  40.582 +    ASSERT_STREQ(img_inline_att->mime_type, "image/jpeg");
  40.583 +    ASSERT_STREQ(img_not_inline_att->mime_type, "image/jpeg");
  40.584 +                
  40.585 +    string att_txt = "Your mother was a hamster\nAnd your father smelt of elterberries";
  40.586 +    ASSERT_STREQ(img_not_inline_att->filename, "file://meow.jpeg");   
  40.587 +    ASSERT_STREQ(img_inline_att->filename, "cid://part1.AC060ED3.AD29176B@darthmama.org");
  40.588 +    
  40.589 +    output_stream << msg->longmsg_formatted << endl;
  40.590 +}
    41.1 --- a/test/src/EncryptAttachPrivateKeyTest.cc	Thu Apr 16 20:35:53 2020 +0200
    41.2 +++ b/test/src/EncryptAttachPrivateKeyTest.cc	Mon Jun 08 15:01:34 2020 +0200
    41.3 @@ -346,7 +346,7 @@
    41.4  
    41.5      output_stream << "Correctly encrypted message:" << endl << endl;
    41.6      char* encrypted_msg_text = NULL;
    41.7 -    mime_encode_message(enc_same_addr_same_uid_trusted, false, &encrypted_msg_text);
    41.8 +    mime_encode_message(enc_same_addr_same_uid_trusted, false, &encrypted_msg_text, false);
    41.9      output_stream << encrypted_msg_text << endl << endl;
   41.10  
   41.11      // FIXME: Free all the damned things
    42.1 --- a/test/src/EncryptForIdentityTest.cc	Thu Apr 16 20:35:53 2020 +0200
    42.2 +++ b/test/src/EncryptForIdentityTest.cc	Mon Jun 08 15:01:34 2020 +0200
    42.3 @@ -133,7 +133,7 @@
    42.4      output_stream << "message created.\n";
    42.5  
    42.6      char* encoded_text = nullptr;
    42.7 -    PEP_STATUS status = mime_encode_message(outgoing_message, false, &encoded_text);
    42.8 +    PEP_STATUS status = mime_encode_message(outgoing_message, false, &encoded_text, false);
    42.9      ASSERT_EQ(status, PEP_STATUS_OK);
   42.10      ASSERT_NE(encoded_text, nullptr);
   42.11  
   42.12 @@ -150,7 +150,7 @@
   42.13      ASSERT_NE(encrypted_msg, nullptr);
   42.14      output_stream << "message encrypted.\n";
   42.15  
   42.16 -    status = mime_encode_message(encrypted_msg, false, &encoded_text);
   42.17 +    status = mime_encode_message(encrypted_msg, false, &encoded_text, false);
   42.18      ASSERT_EQ(status, PEP_STATUS_OK);
   42.19      ASSERT_NE(encoded_text, nullptr);
   42.20  
   42.21 @@ -158,7 +158,7 @@
   42.22      output_stream << encoded_text << "\n";
   42.23  
   42.24      message* decoded_msg = nullptr;
   42.25 -    status = mime_decode_message(encoded_text, strlen(encoded_text), &decoded_msg);
   42.26 +    status = mime_decode_message(encoded_text, strlen(encoded_text), &decoded_msg, NULL);
   42.27      ASSERT_EQ(status, PEP_STATUS_OK);
   42.28      const string string3 = encoded_text;
   42.29  
   42.30 @@ -353,3 +353,268 @@
   42.31      }
   42.32      output_stream << "Encrypted ONLY for Alice! Test passed. Move along. These are not the bugs you are looking for." << endl;
   42.33  }
   42.34 +
   42.35 +TEST_F(EncryptForIdentityTest, check_encrypt_for_identity_with_URI) {
   42.36 +
   42.37 +    // message_api test code
   42.38 +
   42.39 +    const string alice_pub_key = slurp("test_keys/pub/pep-test-alice-0x6FF00E97_pub.asc");
   42.40 +    const string alice_priv_key = slurp("test_keys/priv/pep-test-alice-0x6FF00E97_priv.asc");
   42.41 +    const string gabrielle_pub_key = slurp("test_keys/pub/pep-test-gabrielle-0xE203586C_pub.asc");
   42.42 +    const string bella_pub_key = slurp("test_keys/pub/pep.test.bella-0xAF516AAE_pub.asc");
   42.43 +
   42.44 +    PEP_STATUS statuspub = import_key(session, alice_pub_key.c_str(), alice_pub_key.length(), NULL);
   42.45 +    PEP_STATUS statuspriv = import_key(session, alice_priv_key.c_str(), alice_priv_key.length(), NULL);
   42.46 +    ASSERT_EQ(statuspub, PEP_TEST_KEY_IMPORT_SUCCESS);
   42.47 +    ASSERT_EQ(statuspriv, PEP_TEST_KEY_IMPORT_SUCCESS);
   42.48 +
   42.49 +    statuspub = import_key(session, gabrielle_pub_key.c_str(), gabrielle_pub_key.length(), NULL);
   42.50 +    ASSERT_EQ(statuspub, PEP_TEST_KEY_IMPORT_SUCCESS);
   42.51 +    statuspub = import_key(session, bella_pub_key.c_str(), bella_pub_key.length(), NULL);
   42.52 +    ASSERT_EQ(statuspub, PEP_TEST_KEY_IMPORT_SUCCESS);
   42.53 +
   42.54 +    const char* alice_fpr = "4ABE3AAF59AC32CFE4F86500A9411D176FF00E97";
   42.55 +    const char* gabrielle_fpr = "906C9B8349954E82C5623C3C8C541BD4E203586C";
   42.56 +    const char* bella_fpr = "5631BF1357326A02AA470EEEB815EF7FA4516AAE";
   42.57 +    const char* nobody_fpr = "1111111111111111111111111111111111111111";
   42.58 +
   42.59 +    output_stream << "creating message…\n";
   42.60 +    pEp_identity* alice = new_identity("payto://BIC/SYSTEMA", alice_fpr, PEP_OWN_USERID, "Alice Test");
   42.61 +    pEp_identity* bob = new_identity("payto://BIC/SYSTEMB", NULL, "42", "Bob Test");
   42.62 +
   42.63 +    alice->me = true;
   42.64 +
   42.65 +    PEP_STATUS mystatus = set_own_key(session, alice, alice_fpr);
   42.66 +    ASSERT_EQ(mystatus, PEP_STATUS_OK);
   42.67 +
   42.68 +    identity_list* to_list = new_identity_list(bob); // to bob
   42.69 +    message* outgoing_message = new_message(PEP_dir_outgoing);
   42.70 +    ASSERT_NE(outgoing_message, nullptr);
   42.71 +    outgoing_message->from = alice;
   42.72 +    outgoing_message->to = to_list;
   42.73 +    outgoing_message->shortmsg = strdup("Greetings, humans!");
   42.74 +    outgoing_message->longmsg = strdup("This is a test of the emergency message system. This is only a test. BEEP.");
   42.75 +    outgoing_message->attachments = new_bloblist(NULL, 0, "application/octet-stream", NULL);
   42.76 +    output_stream << "message created.\n";
   42.77 +
   42.78 +    char* encoded_text = nullptr;
   42.79 +    PEP_STATUS status = mime_encode_message(outgoing_message, false, &encoded_text, false);
   42.80 +    ASSERT_EQ(status, PEP_STATUS_OK);
   42.81 +    ASSERT_NE(encoded_text, nullptr);
   42.82 +
   42.83 +    output_stream << "decrypted:\n\n";
   42.84 +    output_stream << encoded_text << "\n";
   42.85 +
   42.86 +    free(encoded_text);
   42.87 +
   42.88 +    message* encrypted_msg = nullptr;
   42.89 +    output_stream << "calling encrypt_message_for_identity()\n";
   42.90 +    status = encrypt_message_for_self(session, alice, outgoing_message, NULL, &encrypted_msg, PEP_enc_PGP_MIME, PEP_encrypt_flag_force_unsigned | PEP_encrypt_flag_force_no_attached_key);
   42.91 +    output_stream << "encrypt_message() returns " << tl_status_string(status) << '.' << endl;
   42.92 +    ASSERT_EQ(status, PEP_STATUS_OK);
   42.93 +    ASSERT_NE(encrypted_msg, nullptr);
   42.94 +    output_stream << "message encrypted.\n";
   42.95 +
   42.96 +    status = mime_encode_message(encrypted_msg, false, &encoded_text, false);
   42.97 +    ASSERT_EQ(status, PEP_STATUS_OK);
   42.98 +    ASSERT_NE(encoded_text, nullptr);
   42.99 +
  42.100 +    output_stream << "encrypted:\n\n";
  42.101 +    output_stream << encoded_text << "\n";
  42.102 +
  42.103 +    message* decoded_msg = nullptr;
  42.104 +    status = mime_decode_message(encoded_text, strlen(encoded_text), &decoded_msg, NULL);
  42.105 +    ASSERT_EQ(status, PEP_STATUS_OK);
  42.106 +    const string string3 = encoded_text;
  42.107 +
  42.108 +    unlink("tmp/msg_encrypt_for_self.asc");
  42.109 +    ofstream outFile3("tmp/msg_encrypt_for_self.asc");
  42.110 +    outFile3.write(string3.c_str(), string3.size());
  42.111 +    outFile3.close();
  42.112 +
  42.113 +    message* decrypted_msg = nullptr;
  42.114 +    stringlist_t* keylist_used = nullptr;
  42.115 +
  42.116 +    PEP_rating rating;
  42.117 +    PEP_decrypt_flags_t flags;
  42.118 +
  42.119 +    flags = 0;
  42.120 +    status = decrypt_message(session, encrypted_msg, &decrypted_msg, &keylist_used, &rating, &flags);
  42.121 +    ASSERT_NE(decrypted_msg, nullptr);
  42.122 +    ASSERT_NE(keylist_used, nullptr);
  42.123 +    ASSERT_NE(rating, 0);
  42.124 +    ASSERT_TRUE(status == PEP_DECRYPTED && rating == PEP_rating_unreliable);
  42.125 +    PEP_comm_type ct = encrypted_msg->from->comm_type;
  42.126 +    ASSERT_TRUE(ct == PEP_ct_pEp || ct == PEP_ct_pEp_unconfirmed || ct == PEP_ct_OpenPGP || ct == PEP_ct_OpenPGP_unconfirmed);
  42.127 +
  42.128 +    output_stream << "keys used:\n";
  42.129 +
  42.130 +    int i = 0;
  42.131 +
  42.132 +    for (stringlist_t* kl4 = keylist_used; kl4 && kl4->value; kl4 = kl4->next, i++)
  42.133 +    {
  42.134 +        if (i == 0) {
  42.135 +            ASSERT_STRCASEEQ("",kl4->value);
  42.136 +        }
  42.137 +        else {
  42.138 +            output_stream << "\t " << kl4->value << endl;
  42.139 +            ASSERT_STRCASEEQ("4ABE3AAF59AC32CFE4F86500A9411D176FF00E97", kl4->value);
  42.140 +            output_stream << "Encrypted for Alice! Yay! It worked!" << endl;
  42.141 +        }
  42.142 +        ASSERT_LT(i , 2);
  42.143 +    }
  42.144 +    output_stream << "Encrypted ONLY for Alice! Test passed. Move along. These are not the bugs you are looking for." << endl;
  42.145 +
  42.146 +    output_stream << "freeing messages…\n";
  42.147 +    free_message(encrypted_msg);
  42.148 +    free_message(decrypted_msg);
  42.149 +    free_stringlist (keylist_used);
  42.150 +    output_stream << "done.\n";
  42.151 +
  42.152 +    output_stream << "Now encrypt for self with extra keys." << endl;
  42.153 +    stringlist_t* extra_keys = new_stringlist(gabrielle_fpr);
  42.154 +    stringlist_add(extra_keys, bella_fpr);
  42.155 +    encrypted_msg = NULL;
  42.156 +    decrypted_msg = NULL;
  42.157 +    keylist_used = NULL;
  42.158 +
  42.159 +    output_stream << "calling encrypt_message_for_identity()\n";
  42.160 +    status = encrypt_message_for_self(session, alice, outgoing_message, extra_keys, &encrypted_msg, PEP_enc_PGP_MIME, PEP_encrypt_flag_force_unsigned | PEP_encrypt_flag_force_no_attached_key);
  42.161 +    output_stream << "encrypt_message() returns " << tl_status_string(status) << '.' << endl;
  42.162 +    ASSERT_EQ(status, PEP_STATUS_OK);
  42.163 +    ASSERT_NE(encrypted_msg, nullptr);
  42.164 +    output_stream << "message encrypted.\n";
  42.165 +
  42.166 +    flags = 0;
  42.167 +    status = decrypt_message(session, encrypted_msg, &decrypted_msg, &keylist_used, &rating, &flags);
  42.168 +    ASSERT_NE(decrypted_msg, nullptr);
  42.169 +    ASSERT_NE(keylist_used, nullptr);
  42.170 +    ASSERT_NE(rating, 0);
  42.171 +    ASSERT_TRUE(status == PEP_DECRYPTED && rating == PEP_rating_unreliable);
  42.172 +    ct = encrypted_msg->from->comm_type;
  42.173 +    ASSERT_TRUE(ct == PEP_ct_pEp || ct == PEP_ct_pEp_unconfirmed || ct == PEP_ct_OpenPGP || ct == PEP_ct_OpenPGP_unconfirmed);
  42.174 +
  42.175 +    output_stream << "keys used:\n";
  42.176 +
  42.177 +    for (stringlist_t* incoming_kl = extra_keys; incoming_kl && incoming_kl->value; incoming_kl = incoming_kl->next) {
  42.178 +        bool found = false;
  42.179 +        output_stream << "Encrypted for: ";
  42.180 +        for (stringlist_t* kl4 = keylist_used; kl4 && kl4->value; kl4 = kl4->next, i++) {
  42.181 +            if (strcasecmp(incoming_kl->value, kl4->value) == 0) {
  42.182 +                output_stream << "\t " << kl4->value;
  42.183 +                found = true;
  42.184 +                break;
  42.185 +            }
  42.186 +        }
  42.187 +        output_stream << endl;
  42.188 +        ASSERT_TRUE(found);
  42.189 +    }
  42.190 +    output_stream << "Encrypted for all the extra keys!" << endl;
  42.191 +
  42.192 +    bool found = false;
  42.193 +    for (stringlist_t* kl4 = keylist_used; kl4 && kl4->value; kl4 = kl4->next)
  42.194 +    {
  42.195 +        if (strcasecmp(alice_fpr, kl4->value) == 0) {
  42.196 +            found = true;
  42.197 +            output_stream << "Encrypted also for Alice! Yay!" << endl;
  42.198 +            break;
  42.199 +        }
  42.200 +    }
  42.201 +    ASSERT_TRUE(found);
  42.202 +
  42.203 +    free_message(encrypted_msg);
  42.204 +    encrypted_msg = NULL;
  42.205 +    free_message(decrypted_msg);
  42.206 +    decrypted_msg = NULL;
  42.207 +    free_stringlist(keylist_used);
  42.208 +    keylist_used = NULL;
  42.209 +
  42.210 +    output_stream << "Now add a bad fpr." << endl;
  42.211 +
  42.212 +    stringlist_add(extra_keys, nobody_fpr);
  42.213 +
  42.214 +    output_stream << "calling encrypt_message_for_identity()\n";
  42.215 +    status = encrypt_message_for_self(session, alice, outgoing_message, extra_keys, &encrypted_msg, PEP_enc_PGP_MIME, PEP_encrypt_flag_force_unsigned | PEP_encrypt_flag_force_no_attached_key);
  42.216 +    output_stream << "encrypt_message() returns " << tl_status_string(status) << '.' << endl;
  42.217 +    ASSERT_NE(status, PEP_STATUS_OK);
  42.218 +
  42.219 +    free_message(outgoing_message);
  42.220 +    outgoing_message = NULL;
  42.221 +    free_message(encrypted_msg);
  42.222 +    encrypted_msg = NULL;
  42.223 +    free_message(decrypted_msg);
  42.224 +    decrypted_msg = NULL;
  42.225 +    free_stringlist(keylist_used);
  42.226 +    keylist_used = NULL;
  42.227 +
  42.228 +
  42.229 +    output_stream << "*** Now testing MIME_encrypt_for_self ***" << endl;
  42.230 +
  42.231 +    alice = new_identity("payto://BIC/SYSTEMA", NULL, PEP_OWN_USERID, "Alice Test");
  42.232 +    bob = new_identity("payto://BIC/SYSTEMB", NULL, "42", "Bob Test");
  42.233 +
  42.234 +    output_stream << "Reading in alice_bob_encrypt_test_plaintext_mime.eml..." << endl;
  42.235 +
  42.236 +    const string mimetext = slurp("test_mails/alice_bob_encrypt_test_plaintext_mime.eml");
  42.237 +
  42.238 +    output_stream << "Text read:" << endl;
  42.239 +    output_stream << mimetext.c_str() << endl;
  42.240 +    char* encrypted_mimetext = nullptr;
  42.241 +
  42.242 +    output_stream << "Calling MIME_encrypt_message_for_self" << endl;
  42.243 +    status = MIME_encrypt_message_for_self(session, alice, mimetext.c_str(),
  42.244 +                                           mimetext.size(),
  42.245 +                                           NULL,
  42.246 +                                           &encrypted_mimetext,
  42.247 +                                           PEP_enc_PGP_MIME,
  42.248 +                                           PEP_encrypt_flag_force_unsigned | PEP_encrypt_flag_force_no_attached_key);
  42.249 +
  42.250 +    output_stream << "Encrypted message:" << endl;
  42.251 +    output_stream << encrypted_mimetext << endl;
  42.252 +
  42.253 +    output_stream << "Calling MIME_decrypt_message" << endl;
  42.254 +
  42.255 +    char* decrypted_mimetext = nullptr;
  42.256 +    free_stringlist(keylist_used);
  42.257 +    keylist_used = nullptr;
  42.258 +    PEP_decrypt_flags_t mimeflags;
  42.259 +    PEP_rating mimerating;
  42.260 +    char* modified_src = NULL;
  42.261 +
  42.262 +    mimeflags = 0;
  42.263 +    status = MIME_decrypt_message(session,
  42.264 +                                  encrypted_mimetext,
  42.265 +                                  strlen(encrypted_mimetext),
  42.266 +                                  &decrypted_mimetext,
  42.267 +                                  &keylist_used,
  42.268 +                                  &mimerating,
  42.269 +                                  &mimeflags,
  42.270 +				  &modified_src);
  42.271 +
  42.272 +    ASSERT_NE(decrypted_mimetext, nullptr);
  42.273 +    ASSERT_NE(keylist_used, nullptr);
  42.274 +    ASSERT_NE(mimerating, 0);
  42.275 +
  42.276 +    ASSERT_TRUE(status == PEP_DECRYPTED && mimerating == PEP_rating_unreliable);
  42.277 +
  42.278 +    output_stream << "Decrypted message:" << endl;
  42.279 +    output_stream << decrypted_mimetext << endl;
  42.280 +
  42.281 +    output_stream << "keys used:\n";
  42.282 +
  42.283 +    i = 0;
  42.284 +
  42.285 +    for (stringlist_t* kl4 = keylist_used; kl4 && kl4->value; kl4 = kl4->next, i++)
  42.286 +    {
  42.287 +        if (i == 0) {
  42.288 +            ASSERT_STRCASEEQ("",kl4->value);
  42.289 +        }
  42.290 +        else {
  42.291 +            output_stream << "\t " << kl4->value << endl;
  42.292 +            ASSERT_STRCASEEQ("4ABE3AAF59AC32CFE4F86500A9411D176FF00E97", kl4->value);
  42.293 +            output_stream << "Encrypted for Alice! Yay! It worked!" << endl;
  42.294 +        }
  42.295 +        ASSERT_LT(i , 2);
  42.296 +    }
  42.297 +    output_stream << "Encrypted ONLY for Alice! Test passed. Move along. These are not the bugs you are looking for." << endl;
  42.298 +}
    43.1 --- a/test/src/EncryptMissingPrivateKeyTest.cc	Thu Apr 16 20:35:53 2020 +0200
    43.2 +++ b/test/src/EncryptMissingPrivateKeyTest.cc	Mon Jun 08 15:01:34 2020 +0200
    43.3 @@ -113,7 +113,7 @@
    43.4  
    43.5      const string mailtext = slurp("test_mails/blacklist_no_key.eml");
    43.6  
    43.7 -    PEP_STATUS status = mime_decode_message(mailtext.c_str(), mailtext.length(), &tmp_msg);
    43.8 +    PEP_STATUS status = mime_decode_message(mailtext.c_str(), mailtext.length(), &tmp_msg, NULL);
    43.9      ASSERT_EQ(status, PEP_STATUS_OK);
   43.10  
   43.11      status = update_identity(session, tmp_msg->from);
    44.1 --- a/test/src/Engine514Test.cc	Thu Apr 16 20:35:53 2020 +0200
    44.2 +++ b/test/src/Engine514Test.cc	Mon Jun 08 15:01:34 2020 +0200
    44.3 @@ -92,7 +92,7 @@
    44.4      not_the_msg->shortmsg = strdup("This is an ATTACHMENT");
    44.5      not_the_msg->longmsg = strdup("Some body text here.");
    44.6  
    44.7 -    mime_encode_message(not_the_msg, false, &attachment_text);
    44.8 +    mime_encode_message(not_the_msg, false, &attachment_text, false);
    44.9      ASSERT_NE(attachment_text, nullptr);
   44.10      free_message(not_the_msg);
   44.11          
   44.12 @@ -120,7 +120,7 @@
   44.13      
   44.14      // Funny, it's not reproduceable here.
   44.15      char* output_str = NULL;
   44.16 -    mime_encode_message(msg, false, &output_str);
   44.17 +    mime_encode_message(msg, false, &output_str, false);
   44.18      char* find_the_mimetype = strstr(output_str, "message/rfc822");
   44.19      ASSERT_NE(find_the_mimetype, nullptr);
   44.20      find_the_mimetype = strstr(output_str, "text/rfc822");
   44.21 @@ -143,7 +143,7 @@
   44.22      not_the_msg->shortmsg = strdup("This is an ATTACHMENT");
   44.23      not_the_msg->longmsg = strdup("Some body text here.");
   44.24  
   44.25 -    mime_encode_message(not_the_msg, false, &attachment_text);
   44.26 +    mime_encode_message(not_the_msg, false, &attachment_text, false);
   44.27      ASSERT_NE(attachment_text, nullptr);
   44.28      free_message(not_the_msg);
   44.29          
   44.30 @@ -173,7 +173,7 @@
   44.31      
   44.32      // Still not reproduceable
   44.33      char* output_str = NULL;
   44.34 -    mime_encode_message(msg, false, &output_str);
   44.35 +    mime_encode_message(msg, false, &output_str, false);
   44.36      cout << output_str << endl;
   44.37      char* find_the_mimetype = strstr(output_str, "message/rfc822");
   44.38      ASSERT_NE(find_the_mimetype, nullptr);
   44.39 @@ -192,7 +192,7 @@
   44.40      not_the_msg->shortmsg = strdup("This is an ATTACHMENT");
   44.41      not_the_msg->longmsg = strdup("Some body text here.");
   44.42  
   44.43 -    mime_encode_message(not_the_msg, false, &attachment_text);
   44.44 +    mime_encode_message(not_the_msg, false, &attachment_text, false);
   44.45      ASSERT_NE(attachment_text, nullptr);
   44.46      free_message(not_the_msg);
   44.47          
   44.48 @@ -213,7 +213,7 @@
   44.49      msg->attachments = new_bloblist(attachment_text, strlen(attachment_text), "message/rfc822", NULL); 
   44.50      
   44.51      char* output_str = NULL;
   44.52 -    mime_encode_message(msg, false, &output_str);
   44.53 +    mime_encode_message(msg, false, &output_str, false);
   44.54      cout << output_str << endl;
   44.55      char* find_the_mimetype = strstr(output_str, "message/rfc822");
   44.56      ASSERT_NE(find_the_mimetype, nullptr);
   44.57 @@ -221,7 +221,7 @@
   44.58      ASSERT_EQ(find_the_mimetype, nullptr);            
   44.59  
   44.60      message* checker = NULL;
   44.61 -    mime_decode_message(output_str, strlen(output_str), &checker);    
   44.62 +    mime_decode_message(output_str, strlen(output_str), &checker, NULL);    
   44.63      ASSERT_STREQ(checker->attachments->mime_type, "message/rfc822");    
   44.64  }
   44.65  
   44.66 @@ -239,7 +239,7 @@
   44.67      not_the_msg->shortmsg = strdup("This is an ATTACHMENT");
   44.68      not_the_msg->longmsg = strdup("Some body text here.");
   44.69  
   44.70 -    mime_encode_message(not_the_msg, false, &attachment_text);
   44.71 +    mime_encode_message(not_the_msg, false, &attachment_text, false);
   44.72      ASSERT_NE(attachment_text, nullptr);
   44.73      free_message(not_the_msg);
   44.74          
   44.75 @@ -276,7 +276,7 @@
   44.76      
   44.77      // Funny, it's not reproduceable here.
   44.78      // char* output_str = NULL;
   44.79 -    // mime_encode_message(msg, false, &output_str);
   44.80 +    // mime_encode_message(msg, false, &output_str, false);
   44.81      // char* find_the_mimetype = strstr(output_str, "message/rfc822");
   44.82      // ASSERT_NE(find_the_mimetype, nullptr);
   44.83      // find_the_mimetype = strstr(output_str, "text/rfc822");
    45.1 --- a/test/src/Engine655Test.cc	Thu Apr 16 20:35:53 2020 +0200
    45.2 +++ b/test/src/Engine655Test.cc	Mon Jun 08 15:01:34 2020 +0200
    45.3 @@ -84,7 +84,7 @@
    45.4  TEST_F(Engine655Test, check_engine655) {
    45.5      string msg_block = slurp("test_mails/655_msg_huss.eml"); 
    45.6      message* msg = NULL;
    45.7 -    PEP_STATUS status = mime_decode_message(msg_block.c_str(), msg_block.size(), &msg);
    45.8 +    PEP_STATUS status = mime_decode_message(msg_block.c_str(), msg_block.size(), &msg, NULL);
    45.9          
   45.10      for (int i = 0; i < 1; i++) {
   45.11          char* ptext = NULL;
   45.12 @@ -138,7 +138,7 @@
   45.13          
   45.14          // // Let's see what this does...
   45.15          // message* parse_verify;
   45.16 -        // status = mime_decode_message(ptext, psize, &parse_verify);    
   45.17 +        // status = mime_decode_message(ptext, psize, &parse_verify, NULL);    
   45.18          // 
   45.19          keylist = NULL;
   45.20          message* dec_msg = NULL;
    46.1 --- a/test/src/IOS1664Test.cc	Thu Apr 16 20:35:53 2020 +0200
    46.2 +++ b/test/src/IOS1664Test.cc	Mon Jun 08 15:01:34 2020 +0200
    46.3 @@ -92,7 +92,7 @@
    46.4      message* message_mail = NULL;
    46.5      bool raise_att;
    46.6  
    46.7 -    PEP_STATUS status = _mime_decode_message_internal(email.c_str(), email.size(), &message_mail, &raise_att);
    46.8 +    PEP_STATUS status = mime_decode_message(email.c_str(), email.size(), &message_mail, &raise_att);
    46.9      ASSERT_EQ(status , PEP_STATUS_OK && message_mail);
   46.10  
   46.11      // create own identity here, because we want to reply, before we start.
    47.1 --- a/test/src/KeyAttachmentTest.cc	Thu Apr 16 20:35:53 2020 +0200
    47.2 +++ b/test/src/KeyAttachmentTest.cc	Mon Jun 08 15:01:34 2020 +0200
    47.3 @@ -97,7 +97,7 @@
    47.4      message* enc_msg = NULL;
    47.5      message* dec_msg = NULL;
    47.6  
    47.7 -    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg);
    47.8 +    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg, NULL);
    47.9      ASSERT_EQ(status , PEP_STATUS_OK);
   47.10      ASSERT_NE(enc_msg, nullptr);
   47.11      stringlist_t* keylist = NULL;
   47.12 @@ -117,7 +117,7 @@
   47.13      message* enc_msg = NULL;
   47.14      message* dec_msg = NULL;
   47.15  
   47.16 -    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg);
   47.17 +    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg, NULL);
   47.18      ASSERT_EQ(status , PEP_STATUS_OK);
   47.19      ASSERT_NE(enc_msg, nullptr);
   47.20      stringlist_t* keylist = NULL;
   47.21 @@ -143,7 +143,7 @@
   47.22      message* enc_msg = NULL;
   47.23      message* dec_msg = NULL;
   47.24  
   47.25 -    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg);
   47.26 +    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg, NULL);
   47.27      ASSERT_EQ(status , PEP_STATUS_OK);
   47.28      ASSERT_NE(enc_msg, nullptr);
   47.29      stringlist_t* keylist = NULL;
   47.30 @@ -169,7 +169,7 @@
   47.31      message* enc_msg = NULL;
   47.32      message* dec_msg = NULL;
   47.33  
   47.34 -    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg);
   47.35 +    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg, NULL);
   47.36      ASSERT_EQ(status , PEP_STATUS_OK);
   47.37      ASSERT_NE(enc_msg, nullptr);
   47.38      stringlist_t* keylist = NULL;
   47.39 @@ -195,7 +195,7 @@
   47.40      message* enc_msg = NULL;
   47.41      message* dec_msg = NULL;
   47.42  
   47.43 -    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg);
   47.44 +    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg, NULL);
   47.45      ASSERT_EQ(status , PEP_STATUS_OK);
   47.46      ASSERT_NE(enc_msg, nullptr);
   47.47      stringlist_t* keylist = NULL;
   47.48 @@ -225,7 +225,7 @@
   47.49      message* enc_msg = NULL;
   47.50      message* dec_msg = NULL;
   47.51  
   47.52 -    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg);
   47.53 +    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg, NULL);
   47.54      ASSERT_EQ(status , PEP_STATUS_OK);
   47.55      ASSERT_NE(enc_msg, nullptr);
   47.56      stringlist_t* keylist = NULL;
   47.57 @@ -245,7 +245,7 @@
   47.58      message* enc_msg = NULL;
   47.59      message* dec_msg = NULL;
   47.60  
   47.61 -    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg);
   47.62 +    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg, NULL);
   47.63      ASSERT_EQ(status , PEP_STATUS_OK);
   47.64      ASSERT_NE(enc_msg, nullptr);
   47.65      stringlist_t* keylist = NULL;
   47.66 @@ -271,7 +271,7 @@
   47.67      message* enc_msg = NULL;
   47.68      message* dec_msg = NULL;
   47.69  
   47.70 -    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg);
   47.71 +    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg, NULL);
   47.72      ASSERT_EQ(status , PEP_STATUS_OK);
   47.73      ASSERT_NE(enc_msg, nullptr);
   47.74      stringlist_t* keylist = NULL;
   47.75 @@ -297,7 +297,7 @@
   47.76      message* enc_msg = NULL;
   47.77      message* dec_msg = NULL;
   47.78  
   47.79 -    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg);
   47.80 +    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg, NULL);
   47.81      ASSERT_EQ(status , PEP_STATUS_OK);
   47.82      ASSERT_NE(enc_msg, nullptr);
   47.83      stringlist_t* keylist = NULL;
   47.84 @@ -348,7 +348,7 @@
   47.85      message* enc_msg = NULL;
   47.86      message* dec_msg = NULL;
   47.87  
   47.88 -    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg);
   47.89 +    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg, NULL);
   47.90      ASSERT_EQ(status , PEP_STATUS_OK);
   47.91      ASSERT_NE(enc_msg, nullptr);
   47.92      stringlist_t* keylist = NULL;
   47.93 @@ -368,7 +368,7 @@
   47.94      message* enc_msg = NULL;
   47.95      message* dec_msg = NULL;
   47.96  
   47.97 -    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg);
   47.98 +    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg, NULL);
   47.99      ASSERT_EQ(status , PEP_STATUS_OK);
  47.100      ASSERT_NE(enc_msg, nullptr);
  47.101      stringlist_t* keylist = NULL;
  47.102 @@ -393,7 +393,7 @@
  47.103      message* enc_msg = NULL;
  47.104      message* dec_msg = NULL;
  47.105  
  47.106 -    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg);
  47.107 +    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg, NULL);
  47.108      ASSERT_EQ(status , PEP_STATUS_OK);
  47.109      ASSERT_NE(enc_msg, nullptr);
  47.110      stringlist_t* keylist = NULL;
  47.111 @@ -419,7 +419,7 @@
  47.112      message* enc_msg = NULL;
  47.113      message* dec_msg = NULL;
  47.114  
  47.115 -    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg);
  47.116 +    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg, NULL);
  47.117      ASSERT_EQ(status , PEP_STATUS_OK);
  47.118      ASSERT_NE(enc_msg, nullptr);
  47.119      stringlist_t* keylist = NULL;
  47.120 @@ -444,7 +444,7 @@
  47.121      message* enc_msg = NULL;
  47.122      message* dec_msg = NULL;
  47.123  
  47.124 -    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg);
  47.125 +    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg, NULL);
  47.126      ASSERT_EQ(status , PEP_STATUS_OK);
  47.127      ASSERT_NE(enc_msg, nullptr);
  47.128      stringlist_t* keylist = NULL;
  47.129 @@ -469,7 +469,7 @@
  47.130      message* enc_msg = NULL;
  47.131      message* dec_msg = NULL;
  47.132  
  47.133 -    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg);
  47.134 +    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg, NULL);
  47.135      ASSERT_EQ(status , PEP_STATUS_OK);
  47.136      ASSERT_NE(enc_msg, nullptr);
  47.137      stringlist_t* keylist = NULL;
  47.138 @@ -489,7 +489,7 @@
  47.139      message* enc_msg = NULL;
  47.140      message* dec_msg = NULL;
  47.141  
  47.142 -    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg);
  47.143 +    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg, NULL);
  47.144      ASSERT_EQ(status , PEP_STATUS_OK);
  47.145      ASSERT_NE(enc_msg, nullptr);
  47.146      stringlist_t* keylist = NULL;
  47.147 @@ -514,7 +514,7 @@
  47.148      message* enc_msg = NULL;
  47.149      message* dec_msg = NULL;
  47.150  
  47.151 -    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg);
  47.152 +    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg, NULL);
  47.153      ASSERT_EQ(status , PEP_STATUS_OK);
  47.154      ASSERT_NE(enc_msg, nullptr);
  47.155      stringlist_t* keylist = NULL;
  47.156 @@ -539,7 +539,7 @@
  47.157      message* enc_msg = NULL;
  47.158      message* dec_msg = NULL;
  47.159  
  47.160 -    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg);
  47.161 +    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &enc_msg, NULL);
  47.162      ASSERT_EQ(status , PEP_STATUS_OK);
  47.163      ASSERT_NE(enc_msg, nullptr);
  47.164      stringlist_t* keylist = NULL;
    48.1 --- a/test/src/KeyResetMessageTest.cc	Thu Apr 16 20:35:53 2020 +0200
    48.2 +++ b/test/src/KeyResetMessageTest.cc	Mon Jun 08 15:01:34 2020 +0200
    48.3 @@ -217,7 +217,7 @@
    48.4              ASSERT_NE(enc_outgoing_msg, nullptr);
    48.5              output_stream << "Message encrypted.\n";
    48.6              char* outstring = NULL;
    48.7 -            mime_encode_message(enc_outgoing_msg, false, &outstring);
    48.8 +            mime_encode_message(enc_outgoing_msg, false, &outstring, false);
    48.9              output_stream << outstring << endl;
   48.10              free_message(enc_outgoing_msg);
   48.11              free(outstring);
   48.12 @@ -262,6 +262,8 @@
   48.13  
   48.14      for (curr_ident = send_idents; curr_ident && curr_ident->ident; curr_ident = curr_ident->next) {
   48.15          status = update_identity(session, curr_ident->ident);
   48.16 +        
   48.17 +        // Poor Bob. He doesn't get to be a pEp user.
   48.18          if (strcmp(curr_ident->ident->user_id, bob_user_id.c_str()) == 0)
   48.19              continue;
   48.20  
   48.21 @@ -324,7 +326,7 @@
   48.22      hashmap[fenris_user_id] = false;
   48.23  
   48.24      // Number of messages we SHOULD be sending.
   48.25 -    ASSERT_EQ(m_queue.size(), 4);
   48.26 +    ASSERT_EQ(m_queue.size(), 3);
   48.27  
   48.28      for (vector<message*>::iterator it = m_queue.begin(); it != m_queue.end(); it++) {
   48.29          message* curr_sent_msg = *it;
   48.30 @@ -350,7 +352,7 @@
   48.31                  ofstream outfile;
   48.32                  outfile.open("test_files/398_reset_from_alice_to_bob.eml");
   48.33                  char* bob_msg = NULL;
   48.34 -                mime_encode_message(curr_sent_msg, false, &bob_msg);
   48.35 +                mime_encode_message(curr_sent_msg, false, &bob_msg, false);
   48.36                  outfile << bob_msg;
   48.37                  outfile.close();
   48.38              }
   48.39 @@ -358,7 +360,7 @@
   48.40                  ofstream outfile;
   48.41                  outfile.open("test_files/398_reset_from_alice_to_fenris.eml");
   48.42                  char* fenris_msg = NULL;
   48.43 -                mime_encode_message(curr_sent_msg, false, &fenris_msg);
   48.44 +                mime_encode_message(curr_sent_msg, false, &fenris_msg, false);
   48.45                  outfile << fenris_msg;
   48.46                  outfile.close();
   48.47              }
   48.48 @@ -370,7 +372,7 @@
   48.49  
   48.50      // Make sure we have messages only to desired recips
   48.51      ASSERT_FALSE(hashmap[alice_user_id]);
   48.52 -    ASSERT_TRUE(hashmap[bob_user_id]);
   48.53 +    ASSERT_FALSE(hashmap[bob_user_id]); // non-pEp user
   48.54      ASSERT_TRUE(hashmap[carol_user_id]);
   48.55      ASSERT_FALSE(hashmap[dave_user_id]);
   48.56      ASSERT_TRUE(hashmap[erin_user_id]);
   48.57 @@ -462,6 +464,40 @@
   48.58      free(keylist);
   48.59  }
   48.60  
   48.61 +TEST_F(KeyResetMessageTest, revoke_and_check_receive_message) {
   48.62 +    pEp_identity* me = new_identity("inquisitor@darthmama.org", NULL, PEP_OWN_USERID, "INQUISITOR");
   48.63 +    string inbox = slurp("test_mails/to_inquisitor_pgp.eml");
   48.64 +    slurp_and_import_key(session, "test_keys/pub/inquisitor-0xA4728718_renewed_pub.asc");
   48.65 +    slurp_and_import_key(session, "test_keys/priv/inquisitor-0xA4728718_renewed_priv.asc");
   48.66 +
   48.67 +    PEP_STATUS status = set_own_key(session, me, "8E8D2381AE066ABE1FEE509821BA977CA4728718");
   48.68 +    ASSERT_EQ(status, PEP_STATUS_OK);
   48.69 +    status = key_reset(session, "8E8D2381AE066ABE1FEE509821BA977CA4728718", me);
   48.70 +    ASSERT_EQ(status, PEP_STATUS_OK);
   48.71 +    status = myself(session, me);
   48.72 +    ASSERT_NE(me->fpr, nullptr);
   48.73 +    ASSERT_STRNE(me->fpr, "8E8D2381AE066ABE1FEE509821BA977CA4728718");
   48.74 +    ASSERT_EQ(m_queue.size() , 0);
   48.75 +    m_queue.clear();
   48.76 +    
   48.77 +    message* enc_msg = NULL;
   48.78 +    mime_decode_message(inbox.c_str(), inbox.size(), &enc_msg, NULL);
   48.79 +    
   48.80 +    message* dec_msg = NULL;
   48.81 +    stringlist_t* keylist = NULL;
   48.82 +    PEP_decrypt_flags_t flags = 0;
   48.83 +    PEP_rating rating;
   48.84 +    
   48.85 +    status = decrypt_message(session, enc_msg, &dec_msg, &keylist, &rating, &flags);
   48.86 +    ASSERT_EQ(status, PEP_STATUS_OK);        
   48.87 +    ASSERT_NE(dec_msg, nullptr);
   48.88 +    ASSERT_EQ(m_queue.size() , 0);
   48.89 +    m_queue.clear();
   48.90 +    free_stringlist(keylist);
   48.91 +    free_message(enc_msg);
   48.92 +    free_message(dec_msg);
   48.93 +}
   48.94 +
   48.95  
   48.96  TEST_F(KeyResetMessageTest, check_receive_message_to_revoked_key_from_unknown) {
   48.97      // create_msg_for_revoked_key(); // call to recreate msg
   48.98 @@ -656,7 +692,7 @@
   48.99          outfile.open("test_mails/check_reset_grouped_own_recv.eml");
  48.100          message* curr_sent_msg = m_queue.at(0);
  48.101          char* msg_txt = NULL;
  48.102 -        mime_encode_message(curr_sent_msg, false, &msg_txt);
  48.103 +        mime_encode_message(curr_sent_msg, false, &msg_txt, false);
  48.104          outfile << msg_txt;
  48.105          outfile.close();
  48.106          cout << "    ASSERT_STREQ(alice->fpr, \"" << alice_new_fpr << "\");" << endl;
  48.107 @@ -670,11 +706,11 @@
  48.108                                                         &ptext, &psize, &_keylist,
  48.109                                                         NULL);
  48.110          message* inner_msg = NULL;
  48.111 -        status = mime_decode_message(ptext, psize, &inner_msg);
  48.112 +        status = mime_decode_message(ptext, psize, &inner_msg, NULL);
  48.113          
  48.114          bloblist_t* key_reset_payload = inner_msg->attachments;  
  48.115          message* keyreset_msg = NULL;
  48.116 -        status = mime_decode_message(key_reset_payload->value, key_reset_payload->size, &keyreset_msg);
  48.117 +        status = mime_decode_message(key_reset_payload->value, key_reset_payload->size, &keyreset_msg, NULL);
  48.118          keyreset_command_list* cl = NULL;
  48.119          status = PER_to_key_reset_commands(keyreset_msg->attachments->value, keyreset_msg->attachments->size, &cl);                                             
  48.120          ASSERT_NE(cl, nullptr);
  48.121 @@ -814,7 +850,7 @@
  48.122          string fname = "test_mails/check_reset_grouped_own_multi_ident_one_fpr.eml";
  48.123          outfile.open(fname);
  48.124          char* msg_txt = NULL;
  48.125 -        mime_encode_message(curr_sent_msg, false, &msg_txt);
  48.126 +        mime_encode_message(curr_sent_msg, false, &msg_txt, false);
  48.127          outfile << msg_txt;
  48.128          outfile.close();        
  48.129          cout <<  "    // check_reset_grouped_own_multi_ident_one_fpr_recv" << endl;
  48.130 @@ -896,7 +932,7 @@
  48.131      string fname = "test_mails/check_reset_grouped_own_multi_ident_one_fpr.eml";
  48.132      string mailstr = slurp(fname.c_str());
  48.133      message* new_msg = NULL;
  48.134 -    status = mime_decode_message(mailstr.c_str(), mailstr.size(), &new_msg);
  48.135 +    status = mime_decode_message(mailstr.c_str(), mailstr.size(), &new_msg, NULL);
  48.136      ASSERT_NE(new_msg, nullptr);
  48.137      ASSERT_EQ(status, PEP_STATUS_OK);
  48.138  
  48.139 @@ -1032,7 +1068,7 @@
  48.140              string fname = string("test_mails/check_reset_grouped_own_multiple_keys_multiple_idents_reset_all_") + to_string(i) + ".eml";
  48.141              outfile.open(fname);
  48.142              char* msg_txt = NULL;
  48.143 -            mime_encode_message(curr_sent_msg, false, &msg_txt);
  48.144 +            mime_encode_message(curr_sent_msg, false, &msg_txt, false);
  48.145              outfile << msg_txt;
  48.146              outfile.close();        
  48.147          }
  48.148 @@ -1161,7 +1197,7 @@
  48.149              string fname = string("test_mails/check_reset_all_own_grouped") + to_string(i) + ".eml";
  48.150              outfile.open(fname);
  48.151              char* msg_txt = NULL;
  48.152 -            mime_encode_message(curr_sent_msg, false, &msg_txt);
  48.153 +            mime_encode_message(curr_sent_msg, false, &msg_txt, false);
  48.154              outfile << msg_txt;
  48.155              outfile.close();        
  48.156          }
  48.157 @@ -1256,7 +1292,7 @@
  48.158          string fname = string("test_mails/check_reset_all_own_grouped") + to_string(i) + ".eml";
  48.159          string mailstr = slurp(fname.c_str());
  48.160          message* new_msg = NULL;
  48.161 -        status = mime_decode_message(mailstr.c_str(), mailstr.size(), &new_msg);
  48.162 +        status = mime_decode_message(mailstr.c_str(), mailstr.size(), &new_msg, NULL);
  48.163          ASSERT_NE(new_msg, nullptr);
  48.164          ASSERT_EQ(status, PEP_STATUS_OK);
  48.165  
  48.166 @@ -1359,7 +1395,7 @@
  48.167          string fname = string("test_mails/check_reset_grouped_own_multiple_keys_multiple_idents_reset_all_") + to_string(i) + ".eml";
  48.168          string mailstr = slurp(fname.c_str());
  48.169          message* new_msg = NULL;
  48.170 -        status = mime_decode_message(mailstr.c_str(), mailstr.size(), &new_msg);
  48.171 +        status = mime_decode_message(mailstr.c_str(), mailstr.size(), &new_msg, NULL);
  48.172          ASSERT_NE(new_msg, nullptr);
  48.173          ASSERT_EQ(status, PEP_STATUS_OK);
  48.174  
  48.175 @@ -1495,7 +1531,7 @@
  48.176          string fname = "test_mails/check_reset_grouped_own_multiple_keys_multiple_idents_reset_one.eml";
  48.177          outfile.open(fname);
  48.178          char* msg_txt = NULL;
  48.179 -        mime_encode_message(curr_sent_msg, false, &msg_txt);
  48.180 +        mime_encode_message(curr_sent_msg, false, &msg_txt, false);
  48.181          outfile << msg_txt;
  48.182          outfile.close();   
  48.183          cout <<  "    // check_reset_grouped_own_multiple_keys_multiple_idents_reset_one_recv" << endl;  
  48.184 @@ -1577,7 +1613,7 @@
  48.185      string fname = "test_mails/check_reset_grouped_own_multiple_keys_multiple_idents_reset_one.eml";
  48.186      string mailstr = slurp(fname.c_str());
  48.187      message* new_msg = NULL;
  48.188 -    status = mime_decode_message(mailstr.c_str(), mailstr.size(), &new_msg);
  48.189 +    status = mime_decode_message(mailstr.c_str(), mailstr.size(), &new_msg, NULL);
  48.190      ASSERT_NE(new_msg, nullptr);
  48.191      ASSERT_EQ(status, PEP_STATUS_OK);
  48.192  
  48.193 @@ -2320,7 +2356,7 @@
  48.194  
  48.195      status = encrypt_message(session, bob_msg, NULL, &enc_msg, PEP_enc_PGP_MIME, 0);
  48.196      ASSERT_EQ(status, PEP_STATUS_OK);
  48.197 -    status = mime_encode_message(enc_msg, false, &enc_msg_str);
  48.198 +    status = mime_encode_message(enc_msg, false, &enc_msg_str, false);
  48.199  
  48.200      ofstream myfile;
  48.201      myfile.open("test_mails/ENGINE-654_bob_mail.eml");
  48.202 @@ -2381,7 +2417,7 @@
  48.203      // // Ok, so let's see if the thing is mistrusted
  48.204      message* bob_enc_msg = NULL;
  48.205      //
  48.206 -    // mime_decode_message(mail_from_bob.c_str(), mail_from_bob.size(), &bob_enc_msg);
  48.207 +    // mime_decode_message(mail_from_bob.c_str(), mail_from_bob.size(), &bob_enc_msg, NULL);
  48.208      //
  48.209      message* bob_dec_msg = NULL;
  48.210      stringlist_t* keylist = NULL;
  48.211 @@ -2408,7 +2444,7 @@
  48.212      //update_identity(session, bob);
  48.213              //    ASSERT_EQ(bob->fpr, nullptr);
  48.214  
  48.215 -    mime_decode_message(mail_from_bob.c_str(), mail_from_bob.size(), &bob_enc_msg);
  48.216 +    mime_decode_message(mail_from_bob.c_str(), mail_from_bob.size(), &bob_enc_msg, NULL);
  48.217  
  48.218      bob_dec_msg = NULL;
  48.219      free_stringlist(keylist);
    49.1 --- a/test/src/LeastColorGroupTest.cc	Thu Apr 16 20:35:53 2020 +0200
    49.2 +++ b/test/src/LeastColorGroupTest.cc	Mon Jun 08 15:01:34 2020 +0200
    49.3 @@ -131,7 +131,7 @@
    49.4      PEP_rating rating;
    49.5      PEP_decrypt_flags_t flags;
    49.6  
    49.7 -    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr);
    49.8 +    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr, NULL);
    49.9      ASSERT_EQ(status , PEP_STATUS_OK);
   49.10      ASSERT_NE(msg_ptr, nullptr);
   49.11      final_ptr = msg_ptr;
    50.1 --- a/test/src/LeastCommonDenomColorTest.cc	Thu Apr 16 20:35:53 2020 +0200
    50.2 +++ b/test/src/LeastCommonDenomColorTest.cc	Mon Jun 08 15:01:34 2020 +0200
    50.3 @@ -130,7 +130,7 @@
    50.4      PEP_rating rating;
    50.5      PEP_decrypt_flags_t flags;
    50.6  
    50.7 -    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr);
    50.8 +    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr, NULL);
    50.9      ASSERT_EQ(status , PEP_STATUS_OK);
   50.10      ASSERT_NE(msg_ptr, nullptr);
   50.11  
   50.12 @@ -179,7 +179,7 @@
   50.13      keylist = nullptr;
   50.14      rating = PEP_rating_unreliable;
   50.15  
   50.16 -    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr);
   50.17 +    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr, NULL);
   50.18      ASSERT_EQ(status , PEP_STATUS_OK);
   50.19      ASSERT_NE(msg_ptr, nullptr);
   50.20      flags = 0;
    51.1 --- a/test/src/MessageApiTest.cc	Thu Apr 16 20:35:53 2020 +0200
    51.2 +++ b/test/src/MessageApiTest.cc	Mon Jun 08 15:01:34 2020 +0200
    51.3 @@ -117,7 +117,7 @@
    51.4      output_stream << "message created.\n";
    51.5  
    51.6      char *text2 = nullptr;
    51.7 -    PEP_STATUS status2 = mime_encode_message(msg2, false, &text2);
    51.8 +    PEP_STATUS status2 = mime_encode_message(msg2, false, &text2, false);
    51.9      ASSERT_EQ(status2 , PEP_STATUS_OK);
   51.10      ASSERT_NE(text2, nullptr);
   51.11  
   51.12 @@ -135,7 +135,7 @@
   51.13      ASSERT_NE(enc_msg2, nullptr);
   51.14      output_stream << "message encrypted.\n";
   51.15  
   51.16 -    status2 = mime_encode_message(enc_msg2, false, &text2);
   51.17 +    status2 = mime_encode_message(enc_msg2, false, &text2, false);
   51.18      ASSERT_EQ(status2 , PEP_STATUS_OK);
   51.19      ASSERT_NE(text2, nullptr);
   51.20  
   51.21 @@ -143,7 +143,7 @@
   51.22      output_stream << text2 << "\n";
   51.23  
   51.24      message *msg3 = nullptr;
   51.25 -    PEP_STATUS status3 = mime_decode_message(text2, strlen(text2), &msg3);
   51.26 +    PEP_STATUS status3 = mime_decode_message(text2, strlen(text2), &msg3, NULL);
   51.27      ASSERT_EQ(status3 , PEP_STATUS_OK);
   51.28      const string string3 = text2;
   51.29      //free(text2);
   51.30 @@ -195,7 +195,7 @@
   51.31      inFile3.close();
   51.32  
   51.33      message *msg5 = nullptr;
   51.34 -    PEP_STATUS status5 = mime_decode_message(text3.c_str(), text3.length(), &msg5);
   51.35 +    PEP_STATUS status5 = mime_decode_message(text3.c_str(), text3.length(), &msg5, NULL);
   51.36      ASSERT_EQ(status5 , PEP_STATUS_OK);
   51.37  
   51.38      message *msg6 = nullptr;
    52.1 --- a/test/src/MessageTwoPointOhTest.cc	Thu Apr 16 20:35:53 2020 +0200
    52.2 +++ b/test/src/MessageTwoPointOhTest.cc	Mon Jun 08 15:01:34 2020 +0200
    52.3 @@ -142,7 +142,7 @@
    52.4      output_stream << "message created.\n";
    52.5  
    52.6      char* encoded_text = nullptr;
    52.7 -    status = mime_encode_message(outgoing_message, false, &encoded_text);
    52.8 +    status = mime_encode_message(outgoing_message, false, &encoded_text, false);
    52.9      ASSERT_EQ(status , PEP_STATUS_OK);
   52.10      ASSERT_NE(encoded_text, nullptr);
   52.11  
   52.12 @@ -162,7 +162,7 @@
   52.13      output_stream << "message encrypted.\n";
   52.14  
   52.15      encrypted_msg->enc_format = PEP_enc_none;
   52.16 -    status = mime_encode_message(encrypted_msg, false, &encoded_text);
   52.17 +    status = mime_encode_message(encrypted_msg, false, &encoded_text, false);
   52.18      ASSERT_EQ(status , PEP_STATUS_OK);
   52.19      ASSERT_NE(encoded_text, nullptr);
   52.20  
   52.21 @@ -183,7 +183,7 @@
   52.22  //    output_stream << decrypted_text << endl;
   52.23  
   52.24      message* decoded_msg = nullptr;
   52.25 -    status = mime_decode_message(encoded_text, strlen(encoded_text), &decoded_msg);
   52.26 +    status = mime_decode_message(encoded_text, strlen(encoded_text), &decoded_msg, NULL);
   52.27      ASSERT_EQ(status , PEP_STATUS_OK);
   52.28      const string string3 = encoded_text;
   52.29  
   52.30 @@ -217,7 +217,7 @@
   52.31      }
   52.32  
   52.33      decrypted_msg->enc_format = PEP_enc_none;
   52.34 -    status = _mime_encode_message_internal(decrypted_msg, false, &encoded_text, false, false);
   52.35 +    status = mime_encode_message(decrypted_msg, false, &encoded_text, false);
   52.36      ASSERT_EQ(status , PEP_STATUS_OK);
   52.37      ASSERT_NE(encoded_text, nullptr);
   52.38      output_stream << "Decrypted message: " << endl;
    53.1 --- a/test/src/MimeTest.cc	Thu Apr 16 20:35:53 2020 +0200
    53.2 +++ b/test/src/MimeTest.cc	Mon Jun 08 15:01:34 2020 +0200
    53.3 @@ -93,7 +93,7 @@
    53.4  
    53.5                  output_stream << "decoding message…\n";
    53.6                  message *msg3;
    53.7 -                PEP_STATUS status3 = mime_decode_message(mimetext3.c_str(), mimetext3.length(), &msg3);
    53.8 +                PEP_STATUS status3 = mime_decode_message(mimetext3.c_str(), mimetext3.length(), &msg3, NULL);
    53.9                  assert(status3 == PEP_STATUS_OK);
   53.10                  assert(msg3);
   53.11                  output_stream << "decoded.\n\n";
   53.12 @@ -147,7 +147,7 @@
   53.13  
   53.14      output_stream << "encoding message…\n";
   53.15      char *result2;
   53.16 -    PEP_STATUS status2 = mime_encode_message(msg2, false, &result2);
   53.17 +    PEP_STATUS status2 = mime_encode_message(msg2, false, &result2, false);
   53.18      ASSERT_NE(result2, nullptr);
   53.19      ASSERT_EQ(status2, PEP_STATUS_OK);
   53.20  
    54.1 --- a/test/src/PepSubjectReceivedTest.cc	Thu Apr 16 20:35:53 2020 +0200
    54.2 +++ b/test/src/PepSubjectReceivedTest.cc	Mon Jun 08 15:01:34 2020 +0200
    54.3 @@ -123,7 +123,7 @@
    54.4      PEP_rating rating;
    54.5      PEP_decrypt_flags_t flags;
    54.6  
    54.7 -    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr);
    54.8 +    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr, NULL);
    54.9      ASSERT_EQ(status , PEP_STATUS_OK);
   54.10      ASSERT_NE(msg_ptr, nullptr);
   54.11      final_ptr = msg_ptr;
   54.12 @@ -157,7 +157,7 @@
   54.13      keylist = nullptr;
   54.14      rating = PEP_rating_unreliable;
   54.15  
   54.16 -    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr);
   54.17 +    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr, NULL);
   54.18      ASSERT_EQ(status , PEP_STATUS_OK);
   54.19      ASSERT_NE(msg_ptr, nullptr);
   54.20      final_ptr = msg_ptr;
   54.21 @@ -191,7 +191,7 @@
   54.22  
   54.23      mailtext = slurp("test_mails/pEp_subject_normal_signed_2a.eml");
   54.24  
   54.25 -    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr);
   54.26 +    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr, NULL);
   54.27      ASSERT_EQ(status , PEP_STATUS_OK);
   54.28      ASSERT_NE(msg_ptr, nullptr);
   54.29      final_ptr = msg_ptr;
   54.30 @@ -224,7 +224,7 @@
   54.31  
   54.32      mailtext = slurp("test_mails/p3p_subject_normal_signed_2b.eml");
   54.33  
   54.34 -    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr);
   54.35 +    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr, NULL);
   54.36      ASSERT_EQ(status , PEP_STATUS_OK);
   54.37      ASSERT_NE(msg_ptr, nullptr);
   54.38      final_ptr = msg_ptr;
   54.39 @@ -258,7 +258,7 @@
   54.40  
   54.41      mailtext = slurp("test_mails/pEp_encrypted_subject_IS_pEp_3a.eml");
   54.42  
   54.43 -    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr);
   54.44 +    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr, NULL);
   54.45      ASSERT_EQ(status , PEP_STATUS_OK);
   54.46      ASSERT_NE(msg_ptr, nullptr);
   54.47      final_ptr = msg_ptr;
   54.48 @@ -292,7 +292,7 @@
   54.49  
   54.50      mailtext = slurp("test_mails/p3p_encrypted_subject_IS_pEp_3b.eml");
   54.51  
   54.52 -    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr);
   54.53 +    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr, NULL);
   54.54      ASSERT_EQ(status , PEP_STATUS_OK);
   54.55      ASSERT_NE(msg_ptr, nullptr);
   54.56      final_ptr = msg_ptr;
   54.57 @@ -327,7 +327,7 @@
   54.58  
   54.59      mailtext = slurp("test_mails/pEp_subject_pEp_replaced_w_pEp_4a.eml");
   54.60  
   54.61 -    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr);
   54.62 +    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr, NULL);
   54.63      ASSERT_EQ(status , PEP_STATUS_OK);
   54.64      ASSERT_NE(msg_ptr, nullptr);
   54.65      final_ptr = msg_ptr;
   54.66 @@ -361,7 +361,7 @@
   54.67  
   54.68      mailtext = slurp("test_mails/pEp_subject_pEp_replaced_w_p3p_4b.eml");
   54.69  
   54.70 -    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr);
   54.71 +    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr, NULL);
   54.72      ASSERT_EQ(status , PEP_STATUS_OK);
   54.73      ASSERT_NE(msg_ptr, nullptr);
   54.74      final_ptr = msg_ptr;
   54.75 @@ -395,7 +395,7 @@
   54.76  
   54.77      mailtext = slurp("test_mails/pEp_subject_p3p_replaced_w_pEp_4c.eml");
   54.78  
   54.79 -    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr);
   54.80 +    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr, NULL);
   54.81      ASSERT_EQ(status , PEP_STATUS_OK);
   54.82      ASSERT_NE(msg_ptr, nullptr);
   54.83      final_ptr = msg_ptr;
   54.84 @@ -429,7 +429,7 @@
   54.85  
   54.86      mailtext = slurp("test_mails/pEp_subject_p3p_replaced_w_p3p_4d.eml");
   54.87  
   54.88 -    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr);
   54.89 +    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr, NULL);
   54.90      ASSERT_EQ(status , PEP_STATUS_OK);
   54.91      ASSERT_NE(msg_ptr, nullptr);
   54.92      final_ptr = msg_ptr;
   54.93 @@ -464,7 +464,7 @@
   54.94  
   54.95      mailtext = slurp("test_mails/pEp_unencrypted_pEp_subject_5a.eml");
   54.96  
   54.97 -    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr);
   54.98 +    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr, NULL);
   54.99      ASSERT_EQ(status , PEP_STATUS_OK);
  54.100      ASSERT_NE(msg_ptr, nullptr);
  54.101      final_ptr = msg_ptr;
  54.102 @@ -499,7 +499,7 @@
  54.103  
  54.104      mailtext = slurp("test_mails/pEp_unencrypted_p3p_subject_5b.eml");
  54.105  
  54.106 -    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr);
  54.107 +    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr, NULL);
  54.108      ASSERT_EQ(status , PEP_STATUS_OK);
  54.109      ASSERT_NE(msg_ptr, nullptr);
  54.110      final_ptr = msg_ptr;
  54.111 @@ -533,7 +533,7 @@
  54.112  
  54.113      mailtext = slurp("test_mails/pEp_subject_normal_unencrypted_6.eml");
  54.114  
  54.115 -    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr);
  54.116 +    status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr, NULL);
  54.117      ASSERT_EQ(status , PEP_STATUS_OK);
  54.118      ASSERT_NE(msg_ptr, nullptr);
  54.119      final_ptr = msg_ptr;
    55.1 --- a/test/src/ReencryptPlusExtraKeysTest.cc	Thu Apr 16 20:35:53 2020 +0200
    55.2 +++ b/test/src/ReencryptPlusExtraKeysTest.cc	Mon Jun 08 15:01:34 2020 +0200
    55.3 @@ -179,13 +179,13 @@
    55.4      ASSERT_NE(decrypted_text , nullptr);
    55.5      ASSERT_NE(modified_src , nullptr);
    55.6      message* checker = NULL;
    55.7 -    status = mime_decode_message(modified_src, strlen(modified_src), &checker);
    55.8 +    status = mime_decode_message(modified_src, strlen(modified_src), &checker, NULL);
    55.9      ASSERT_NE(checker, nullptr);
   55.10      ASSERT_STREQ(checker->shortmsg, "Boom shaka laka");
   55.11      config_unencrypted_subject(session, false);
   55.12      cout << modified_src << endl;
   55.13      message* src_msg = NULL;
   55.14 -    status = mime_decode_message(mailfile.c_str(), mailfile.size(), &src_msg);
   55.15 +    status = mime_decode_message(mailfile.c_str(), mailfile.size(), &src_msg, NULL);
   55.16      ASSERT_NE(src_msg, nullptr);
   55.17      ASSERT_STREQ(src_msg->attachments->next->value, checker->attachments->next->value);
   55.18      config_unencrypted_subject(session, false);
   55.19 @@ -226,12 +226,12 @@
   55.20      ASSERT_NE(decrypted_text , nullptr);
   55.21      ASSERT_NE(modified_src , nullptr);
   55.22      message* checker = NULL;
   55.23 -    status = mime_decode_message(modified_src, strlen(modified_src), &checker);
   55.24 +    status = mime_decode_message(modified_src, strlen(modified_src), &checker, NULL);
   55.25      ASSERT_NE(checker, nullptr);
   55.26      ASSERT_STREQ(checker->shortmsg, "Boom shaka laka");
   55.27      cout << modified_src << endl;
   55.28      message* src_msg = NULL;
   55.29 -    status = mime_decode_message(mailfile.c_str(), mailfile.size(), &src_msg);
   55.30 +    status = mime_decode_message(mailfile.c_str(), mailfile.size(), &src_msg, NULL);
   55.31      ASSERT_NE(src_msg, nullptr);
   55.32      ASSERT_STREQ(src_msg->attachments->next->value, checker->attachments->next->value);
   55.33      
   55.34 @@ -293,12 +293,12 @@
   55.35      ASSERT_NE(decrypted_text , nullptr);
   55.36      ASSERT_NE(modified_src , nullptr);
   55.37      message* checker = NULL;
   55.38 -    status = mime_decode_message(modified_src, strlen(modified_src), &checker);
   55.39 +    status = mime_decode_message(modified_src, strlen(modified_src), &checker, NULL);
   55.40      ASSERT_NE(checker, nullptr);
   55.41      ASSERT_STREQ(checker->shortmsg, "Boom shaka laka");
   55.42      cout << modified_src << endl;
   55.43      message* src_msg = NULL;
   55.44 -    status = mime_decode_message(mailfile.c_str(), mailfile.size(), &src_msg);
   55.45 +    status = mime_decode_message(mailfile.c_str(), mailfile.size(), &src_msg, NULL);
   55.46      ASSERT_NE(src_msg, nullptr);
   55.47      ASSERT_STRNE(src_msg->attachments->next->value, checker->attachments->next->value);
   55.48  
   55.49 @@ -376,12 +376,12 @@
   55.50      ASSERT_NE(decrypted_text , nullptr);
   55.51      ASSERT_NE(modified_src , nullptr);
   55.52      message* checker = NULL;
   55.53 -    status = mime_decode_message(modified_src, strlen(modified_src), &checker);
   55.54 +    status = mime_decode_message(modified_src, strlen(modified_src), &checker, NULL);
   55.55      ASSERT_NE(checker, nullptr);
   55.56      ASSERT_STREQ(checker->shortmsg, "Boom shaka laka");
   55.57      cout << modified_src << endl;
   55.58      message* src_msg = NULL;
   55.59 -    status = mime_decode_message(mailfile.c_str(), mailfile.size(), &src_msg);
   55.60 +    status = mime_decode_message(mailfile.c_str(), mailfile.size(), &src_msg, NULL);
   55.61      ASSERT_NE(src_msg, nullptr);
   55.62      ASSERT_STRNE(src_msg->attachments->next->value, checker->attachments->next->value);
   55.63  
   55.64 @@ -447,12 +447,12 @@
   55.65      ASSERT_NE(decrypted_text , nullptr);
   55.66      ASSERT_NE(modified_src , nullptr);
   55.67      message* checker = NULL;
   55.68 -    status = mime_decode_message(modified_src, strlen(modified_src), &checker);
   55.69 +    status = mime_decode_message(modified_src, strlen(modified_src), &checker, NULL);
   55.70      ASSERT_NE(checker, nullptr);
   55.71      ASSERT_STREQ(checker->shortmsg, "Boom shaka laka");
   55.72      cout << modified_src << endl;
   55.73      message* src_msg = NULL;
   55.74 -    status = mime_decode_message(mailfile.c_str(), mailfile.size(), &src_msg);
   55.75 +    status = mime_decode_message(mailfile.c_str(), mailfile.size(), &src_msg, NULL);
   55.76      ASSERT_NE(src_msg, nullptr);
   55.77      ASSERT_STRNE(src_msg->attachments->next->value, checker->attachments->next->value);
   55.78  
   55.79 @@ -897,7 +897,7 @@
   55.80      flags = PEP_decrypt_flag_untrusted_server;
   55.81  
   55.82      // Put the original message into a message struct
   55.83 -    status = mime_decode_message(to_reencrypt_from_enigmail.c_str(), to_reencrypt_from_enigmail.size(), &enc_msg);
   55.84 +    status = mime_decode_message(to_reencrypt_from_enigmail.c_str(), to_reencrypt_from_enigmail.size(), &enc_msg, NULL);
   55.85  
   55.86      ASSERT_EQ(status , PEP_STATUS_OK);
   55.87      ASSERT_NE(enc_msg , nullptr);
   55.88 @@ -970,7 +970,7 @@
   55.89  
   55.90      // Put the original message into a message struct
   55.91  
   55.92 -    status = mime_decode_message(to_reencrypt_from_enigmail_BCC.c_str(), to_reencrypt_from_enigmail_BCC.size(), &enc_msg);
   55.93 +    status = mime_decode_message(to_reencrypt_from_enigmail_BCC.c_str(), to_reencrypt_from_enigmail_BCC.size(), &enc_msg, NULL);
   55.94  
   55.95      ASSERT_EQ(status , PEP_STATUS_OK);
   55.96      ASSERT_NE(enc_msg , nullptr);
   55.97 @@ -1042,7 +1042,7 @@
   55.98      flags = PEP_decrypt_flag_untrusted_server;
   55.99  
  55.100      // Put the original message into a message struct
  55.101 -    status = mime_decode_message(to_reencrypt_from_pEp.c_str(), to_reencrypt_from_pEp.size(), &enc_msg);
  55.102 +    status = mime_decode_message(to_reencrypt_from_pEp.c_str(), to_reencrypt_from_pEp.size(), &enc_msg, NULL);
  55.103  
  55.104      ASSERT_EQ(status , PEP_STATUS_OK);
  55.105      ASSERT_NE(enc_msg , nullptr);
    56.1 --- a/test/src/SenderFPRTest.cc	Thu Apr 16 20:35:53 2020 +0200
    56.2 +++ b/test/src/SenderFPRTest.cc	Mon Jun 08 15:01:34 2020 +0200
    56.3 @@ -129,7 +129,7 @@
    56.4      ASSERT_EQ(status , PEP_STATUS_OK);
    56.5  
    56.6      char* text = NULL;
    56.7 -    mime_encode_message(dec_msg, false, &text);
    56.8 +    mime_encode_message(dec_msg, false, &text, false);
    56.9      output_stream << text << endl;
   56.10      free(text);
   56.11  
    57.1 --- a/test/src/SimpleBodyNotAltTest.cc	Thu Apr 16 20:35:53 2020 +0200
    57.2 +++ b/test/src/SimpleBodyNotAltTest.cc	Mon Jun 08 15:01:34 2020 +0200
    57.3 @@ -89,7 +89,7 @@
    57.4      string msg = slurp("test_mails/text message with html attach.eml");
    57.5      message* parsed = NULL;
    57.6  
    57.7 -    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &parsed);
    57.8 +    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &parsed, NULL);
    57.9      ASSERT_EQ(status , PEP_STATUS_OK);
   57.10      ASSERT_NE(parsed, nullptr);
   57.11      ASSERT_NE(parsed->longmsg, nullptr);
   57.12 @@ -107,7 +107,7 @@
   57.13      string msg = slurp("test_mails/HTML-only body w text attachment.eml");
   57.14      message* parsed = NULL;
   57.15  
   57.16 -    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &parsed);
   57.17 +    PEP_STATUS status = mime_decode_message(msg.c_str(), msg.size(), &parsed, NULL);
   57.18      ASSERT_EQ(status , PEP_STATUS_OK);
   57.19      ASSERT_NE(parsed, nullptr);
   57.20      ASSERT_EQ(parsed->longmsg , nullptr);
    58.1 --- a/test/src/URIAddressTest.cc	Thu Apr 16 20:35:53 2020 +0200
    58.2 +++ b/test/src/URIAddressTest.cc	Mon Jun 08 15:01:34 2020 +0200
    58.3 @@ -273,3 +273,99 @@
    58.4      
    58.5      // We don't check for anything here??? FIXME! WTF!
    58.6  }
    58.7 +
    58.8 +TEST_F(URIAddressTest, check_uri_address_tofu_1) {
    58.9 +    const char* sys_a_addr = "payto://BIC/SYSTEMA";
   58.10 +    const char* sys_b_addr = "payto://BIC/SYSTEMB";
   58.11 +    const char* sys_a_fpr = "4334D6DB751A8CA2B4944075462AFDB6DA3FB4B9";
   58.12 +    const char* sys_b_fpr = "F5199E0B0AC4059572DAD8EA76B63B2954139F26";
   58.13 +    
   58.14 +    slurp_and_import_key(session, "test_keys/priv/BIC_SYSTEMA_0xDA3FB4B9_priv.asc");
   58.15 +    slurp_and_import_key(session, "test_keys/pub/BIC_SYSTEMA_0xDA3FB4B9_pub.asc");
   58.16 +    slurp_and_import_key(session, "test_keys/pub/BIC_SYSTEMB_0x54139F26_pub.asc");
   58.17 +
   58.18 +    pEp_identity* me = new_identity(sys_a_addr, NULL, PEP_OWN_USERID, sys_a_addr);
   58.19 +    PEP_STATUS status = set_own_key(session, me, sys_a_fpr);
   58.20 +    ASSERT_EQ(status , PEP_STATUS_OK);
   58.21 +
   58.22 +    status = myself(session, me);
   58.23 +    ASSERT_EQ(status , PEP_STATUS_OK);
   58.24 +    ASSERT_TRUE(me->fpr && me->fpr[0] != '\0');
   58.25 +
   58.26 +    pEp_identity* you = new_identity(sys_b_addr, NULL, "SYSTEM_B", NULL);
   58.27 +
   58.28 +/*
   58.29 +    stringlist_t* keylist = NULL;
   58.30 +    status = update_identity(session, you);
   58.31 +    ASSERT_EQ(status , PEP_STATUS_OK);
   58.32 +    ASSERT_TRUE(you->fpr && you->fpr[0] != '\0');
   58.33 +*/
   58.34 +    message* msg = new_message(PEP_dir_outgoing);
   58.35 +
   58.36 +    msg->from = me;
   58.37 +    msg->to = new_identity_list(you);
   58.38 +    msg->shortmsg = strdup("Smurfs");
   58.39 +    msg->longmsg = strdup("Are delicious?");
   58.40 +
   58.41 +    message* enc_msg = NULL;
   58.42 +    
   58.43 +    // We are doing key election here on purpose.
   58.44 +    status = encrypt_message(session, msg, NULL, &enc_msg, PEP_enc_PGP_MIME, 0);
   58.45 +    ASSERT_EQ(status, PEP_STATUS_OK);
   58.46 +
   58.47 +    char* outmsg = NULL;
   58.48 +    mime_encode_message(enc_msg, false, &outmsg, false);
   58.49 +    output_stream << outmsg << endl;
   58.50 +    
   58.51 +    if (false) {
   58.52 +        ofstream outfile;
   58.53 +        outfile.open("test_mails/system_a_to_b_755_part_1.eml");
   58.54 +        outfile << outmsg;    
   58.55 +        outfile.close();    
   58.56 +    }
   58.57 +    free(outmsg);
   58.58 +    free_message(msg);
   58.59 +    free_message(enc_msg);
   58.60 +}
   58.61 +
   58.62 +TEST_F(URIAddressTest, check_uri_address_tofu_2) {
   58.63 +    const char* sys_a_addr = "payto://BIC/SYSTEMA";
   58.64 +    const char* sys_b_addr = "payto://BIC/SYSTEMB";
   58.65 +    const char* sys_a_fpr = "4334D6DB751A8CA2B4944075462AFDB6DA3FB4B9";
   58.66 +    const char* sys_b_fpr = "F5199E0B0AC4059572DAD8EA76B63B2954139F26";
   58.67 +    
   58.68 +    slurp_and_import_key(session, "test_keys/pub/BIC_SYSTEMB_0x54139F26_pub.asc");
   58.69 +    slurp_and_import_key(session, "test_keys/priv/BIC_SYSTEMB_0x54139F26_priv.asc");
   58.70 +    slurp_and_import_key(session, "test_keys/pub/BIC_SYSTEMA_0xDA3FB4B9_pub.asc");
   58.71 +
   58.72 +    pEp_identity* me = new_identity(sys_b_addr, NULL, PEP_OWN_USERID, sys_b_addr);
   58.73 +    PEP_STATUS status = set_own_key(session, me, sys_b_fpr);
   58.74 +    ASSERT_EQ(status , PEP_STATUS_OK);
   58.75 +
   58.76 +    status = myself(session, me);
   58.77 +    ASSERT_EQ(status , PEP_STATUS_OK);
   58.78 +    ASSERT_TRUE(me->fpr && me->fpr[0] != '\0');  
   58.79 +    
   58.80 +    pEp_identity* you = new_identity(sys_b_addr, NULL, "SYSTEM_B", NULL);
   58.81 +    status = update_identity(session, you);
   58.82 +        
   58.83 +    string msg_txt = slurp("test_mails/system_a_to_b_755_part_1.eml");
   58.84 +    message* msg = NULL;
   58.85 +    
   58.86 +    mime_decode_message(msg_txt.c_str(), msg_txt.size(), &msg, NULL);
   58.87 +
   58.88 +    message* dec_msg = NULL;
   58.89 +    stringlist_t* keylist = NULL;
   58.90 +    PEP_rating rating;
   58.91 +    PEP_decrypt_flags_t flags = 0;
   58.92 +
   58.93 +    status = decrypt_message(session, msg, &dec_msg, &keylist, &rating, &flags); 
   58.94 +
   58.95 +    ASSERT_EQ(status, PEP_STATUS_OK);
   58.96 +    ASSERT_NE(dec_msg, nullptr);
   58.97 +    ASSERT_NE(dec_msg->from, nullptr);
   58.98 +    ASSERT_NE(dec_msg->to, nullptr);
   58.99 +    ASSERT_NE(dec_msg->to->ident, nullptr);
  58.100 +    ASSERT_STREQ(dec_msg->from->address, "payto://BIC/SYSTEMA");
  58.101 +    ASSERT_STREQ(dec_msg->to->ident->address, "payto://BIC/SYSTEMB");    
  58.102 +}
    59.1 --- a/test/src/UnencryptedPepMailTest.cc	Thu Apr 16 20:35:53 2020 +0200
    59.2 +++ b/test/src/UnencryptedPepMailTest.cc	Mon Jun 08 15:01:34 2020 +0200
    59.3 @@ -120,7 +120,7 @@
    59.4      ASSERT_TRUE(is_pEpmsg(msg));
    59.5      
    59.6      // char* outmsg = NULL;
    59.7 -    // mime_encode_message(msg, false, &outmsg);
    59.8 +    // mime_encode_message(msg, false, &outmsg, false);
    59.9      // ofstream outfile;
   59.10      // outfile.open("tmp/unenc_pep_msg_test_1.eml");
   59.11      // outfile << outmsg;
   59.12 @@ -161,7 +161,7 @@
   59.13                            "I do not want a cup of 'Hoffee', and you are not singlehandedly\n" 
   59.14                            "responsible for bringing down the Berlin Wall.\n\nGo away. - Alice");
   59.15      char* outmsg = NULL;
   59.16 -    mime_encode_message(msg, false, &outmsg);
   59.17 +    mime_encode_message(msg, false, &outmsg, false);
   59.18      char* encmsg = NULL;
   59.19          
   59.20      status = MIME_encrypt_message(session, outmsg, strlen(outmsg), NULL, &encmsg, PEP_enc_PGP_MIME, 0);
   59.21 @@ -174,7 +174,7 @@
   59.22      ASSERT_NE(encmsg, nullptr);
   59.23      
   59.24      // char* outmsg = NULL;
   59.25 -    // mime_encode_message(msg, false, &outmsg);
   59.26 +    // mime_encode_message(msg, false, &outmsg, false);
   59.27      // ofstream outfile;
   59.28      // outfile.open("tmp/unenc_pep_msg_test_1.eml");
   59.29      // outfile << outmsg;
   59.30 @@ -193,7 +193,7 @@
   59.31      PEP_rating rating;
   59.32      PEP_decrypt_flags_t flags = 0;
   59.33      
   59.34 -    mime_decode_message(msgstr.c_str(), msgstr.size(), &enc_msg);
   59.35 +    mime_decode_message(msgstr.c_str(), msgstr.size(), &enc_msg, NULL);
   59.36      ASSERT_TRUE(is_pEpmsg(enc_msg));
   59.37      
   59.38      status = decrypt_message(session, enc_msg, &dec_msg, &keylist, &rating, &flags);
    60.1 --- a/test/src/test_util.cc	Thu Apr 16 20:35:53 2020 +0200
    60.2 +++ b/test/src/test_util.cc	Mon Jun 08 15:01:34 2020 +0200
    60.3 @@ -340,8 +340,6 @@
    60.4              return "PEP_rating_have_no_key";
    60.5          case PEP_rating_unencrypted:
    60.6              return "PEP_rating_unencrypted";
    60.7 -        case PEP_rating_unencrypted_for_some:
    60.8 -            return "PEP_rating_unencrypted_for_some";
    60.9          case PEP_rating_unreliable:
   60.10              return "PEP_rating_unreliable";
   60.11          case PEP_rating_reliable:
   60.12 @@ -548,7 +546,7 @@
   60.13      message* dec_msg = NULL;
   60.14      *mime_plaintext = NULL;
   60.15  
   60.16 -    status = mime_decode_message(mimetext, size, &tmp_msg);
   60.17 +    status = mime_decode_message(mimetext, size, &tmp_msg, NULL);
   60.18      if (status != PEP_STATUS_OK)
   60.19          goto pEp_error;
   60.20  
   60.21 @@ -595,7 +593,7 @@
   60.22      }
   60.23  
   60.24      if (*flags & PEP_decrypt_flag_src_modified) {
   60.25 -        _mime_encode_message_internal(tmp_msg, false, modified_src, true, false);
   60.26 +        mime_encode_message(tmp_msg, false, modified_src, false);
   60.27          if (!modified_src) {
   60.28              *flags &= (~PEP_decrypt_flag_src_modified);
   60.29              decrypt_status = PEP_CANNOT_REENCRYPT; // Because we couldn't return it, I guess.
   60.30 @@ -603,7 +601,7 @@
   60.31      }
   60.32  
   60.33      // FIXME: test with att
   60.34 -    status = _mime_encode_message_internal(dec_msg, false, mime_plaintext, true, false);
   60.35 +    status = mime_encode_message(dec_msg, false, mime_plaintext, false);
   60.36  
   60.37      if (status == PEP_STATUS_OK)
   60.38      {
   60.39 @@ -635,7 +633,7 @@
   60.40      message* enc_msg = NULL;
   60.41      message* ret_msg = NULL;                             
   60.42  
   60.43 -    status = mime_decode_message(mimetext, size, &tmp_msg);
   60.44 +    status = mime_decode_message(mimetext, size, &tmp_msg, NULL);
   60.45      if (status != PEP_STATUS_OK)
   60.46          goto pEp_error;
   60.47  
   60.48 @@ -691,13 +689,7 @@
   60.49          goto pEp_error;
   60.50      }
   60.51      
   60.52 -    tmp_status = _mime_encode_message_internal(
   60.53 -                    ret_msg, 
   60.54 -                    false, 
   60.55 -                    mime_ciphertext, 
   60.56 -                    false, 
   60.57 -                    false);
   60.58 -    
   60.59 +    tmp_status = mime_encode_message(ret_msg, false, mime_ciphertext, false);     
   60.60      if (tmp_status != PEP_STATUS_OK)
   60.61          status = tmp_status;
   60.62  
   60.63 @@ -724,7 +716,7 @@
   60.64      message* tmp_msg = NULL;
   60.65      message* enc_msg = NULL;
   60.66  
   60.67 -    status = mime_decode_message(mimetext, size, &tmp_msg);
   60.68 +    status = mime_decode_message(mimetext, size, &tmp_msg, NULL);
   60.69      if (status != PEP_STATUS_OK)
   60.70          goto pEp_error;
   60.71  
   60.72 @@ -745,7 +737,7 @@
   60.73          goto pEp_error;
   60.74      }
   60.75  
   60.76 -    status = mime_encode_message(enc_msg, false, mime_ciphertext);
   60.77 +    status = mime_encode_message(enc_msg, false, mime_ciphertext, false);
   60.78  
   60.79  pEp_error:
   60.80      free_message(tmp_msg);
    61.1 Binary file test/test_files/ENGINE-750_check_clean_invalid_own_keys_no_alts_expired_keys.db has changed
    62.1 Binary file test/test_files/ENGINE-750_check_clean_invalid_own_keys_no_alts_expired_mgmt.db has changed
    63.1 Binary file test/test_files/ENGINE-750_check_clean_invalid_own_keys_no_alts_mistrusted_keys.db has changed
    64.1 Binary file test/test_files/ENGINE-750_check_clean_invalid_own_keys_no_alts_mistrusted_mgmt.db has changed
    65.1 Binary file test/test_files/ENGINE-750_check_clean_invalid_own_keys_no_alts_revoked_keys.db has changed
    66.1 Binary file test/test_files/ENGINE-750_check_clean_invalid_own_keys_no_alts_revoked_mgmt.db has changed
    67.1 Binary file test/test_files/meow.jpeg has changed
    68.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    68.2 +++ b/test/test_keys/priv/BIC_SYSTEMA_0xDA3FB4B9_priv.asc	Mon Jun 08 15:01:34 2020 +0200
    68.3 @@ -0,0 +1,57 @@
    68.4 +-----BEGIN PGP PRIVATE KEY BLOCK-----
    68.5 +
    68.6 +lQOYBF7XOv0BCADt8KEWRj8gmT5M7OASVr3qBwIldU6MXGlVqSJU5a3tGxGSyjlf
    68.7 +j8fn5PNoIna0VK+ECHOUAp1Y3sDzBgSm1wHGq4mU9yvCYeLjasrGOYhGT6QciRAC
    68.8 +0yXw8KSAc+rAOL1Wk/+GzHU0DJ0MWpw31cz1ePvFWCfo3Y/oztj/lVPtADaMsXl6
    68.9 ++KEgTpoXBGGQ4VUrs3YF8rWxldko4Hv/kOpyTofioTvUNI09I1zfIUYs9htxwZcD
   68.10 +3mUUtOlMWTYguHRjCX+T39dB5AT8UIAx0rlSD8hnNLF6Evkd6QTsOFKkL6innXUq
   68.11 +R0RjbPQNTkkVHbKZYDRSPbm5pjf6tjyihxFlABEBAAEAB/0SibbjN2HftlDGSYZD
   68.12 +p4JwY09lf7g481I5nE3Sc3qTiJJb72l86oTWql3UdSrubdKm5MmsdG+x5tj9ljBy
   68.13 +lznKMr8rXf6IzHuS4FUgEIdvgvD0UDFxJuZD2VvXrjBR/ZmyzyEPbYqMHZd2yPB2
   68.14 +4S9wyJZFD9M8L1bw+nypnQbG5iDjpDqSmMS0p3UX6+SQ25oj5xjbTf0Y8R5UCpUc
   68.15 +0gf3eicdm2h3Ko65Wz5KQqUzo12SlVq/WiqMEr6PtisdvvWLvD7hNx7v7qjtf5o9
   68.16 +/0mCYnW0ffcCidgRzN7VsyQZC2c/pdTfB5DXVAl2fSIwoKAfIK90s4ZvpNTyNMuh
   68.17 +Te5BBADzPrK75cK2KMYMu1Yltb0W+swEbTx7G4/0ghz4zySnlu3u3zWAETPFL19z
   68.18 +pmHiIr0JuV1eXjTiHWenhfnd/XND+DYAmvbq72+aTDVKxwN7++CMMJm451FG0irV
   68.19 +8JAtuKGhAfo7AoFPwwau4noHWcliHtMN3aGie/S5eEnpe7Z7GQQA+mq3vFaSgYHn
   68.20 +Uu3uYoYzbz/7wuYUxGqX7dGI/qgXynPJwW+XJgYJAmrr8CpcjCKpUMuY/8GXxKI0
   68.21 +W2wWzfbYU63R3FrHBdbWPcHUBuj6YdpY8dzGtytUxKn0GWU/KtO27VKOccOtfsJy
   68.22 +3XUaNtBYlq7aogYonkBv/E0wxSiKni0EAKlFTluoNsxIh7zv1U+H43GfL7mWBAM7
   68.23 +FHcr8E0IqXlLa2TDQxrODH7ExkQ/7nIvgs7YSKmLiiSIISxA+h8xQIiCUWLucWMe
   68.24 +YEnAY2kGP8q4pyvtU/5ivT3cYBK4KNvVR9JmTLrNi4yhollKtYtomip49BVrV9wv
   68.25 +9SCw/jLcQ9zjTia0E3BheXRvOi8vQklDL1NZU1RFTUGJAU4EEwEIADgCGwMFCwkI
   68.26 +BwIGFQoJCAsCBBYCAwECHgECF4AWIQRDNNbbdRqMorSUQHVGKv222j+0uQUCXtc7
   68.27 +YAAKCRBGKv222j+0uSCNCADFY6dhEfOTGs+dCZMF5DE8VGfj8zu6uHDwvv3v5h30
   68.28 +lEBjjwcpas1oGas0Tetg8YCCk7JQpAh2ditT1w5RIwn9KKX+pa082ozsSTA6iMi1
   68.29 +ltxaXxSFgy/KPf1jzjJbpb0Euf3UV44NP7Ts4Hxf+OxkQeQKjJ2xCMI2ooZVwojI
   68.30 +7GTrE2K5oz7WgOyJIzidZC8UyEX6+YkW02Ohgz6ShVNbU9Iz3MqBCrSnU1QVREcM
   68.31 +DZ3bjxqiPZ92l7Z3voA8z84QFuANx+2JJEvJUhPeGAHHJ+BwBGMkZLyVCNTqsGwL
   68.32 +E1s6y481vFiO09IcRyeoeB9bqu8ZFWTp5hkFvAYeLvImnQOYBF7XOv0BCADHsTuW
   68.33 +RwK0hHActKkF66JIrlIh7Mta6fWJq78lVMh+fWw8YQqkJXiVO9YCh5O81hlp5Gll
   68.34 +mnexcsNQqSbQZy45elNjunDlfOZd8U7kXxmk4wyLLQdpHBEK7Ssp+/GKt3Bva2nS
   68.35 +bGAtIzvHVhVpb8+UDz1jhO+sK5OcG4CA/gV0sszeSk7QMHLkDWNPYlcOV1HNN1j4
   68.36 +0VDsc5BgYv4L4KsFjCIsh59sI6nQVXRSbVbH4ElQ01iVzPqjhWY4aG9/u12QDt5K
   68.37 +ZYsZ7AA319aAX3V2n4H5kcv1mgvaCPLv+HAkNFv97dGbG/+pb2TfwGSDWnePc1Hh
   68.38 +93IcEuIf00BYDCLLABEBAAEAB/wJBN8oaSui4Upo/GdSE/9CynaUuZRlIerL7vP+
   68.39 +Rd6EfXRTOxHi1KngPLQbEN6cdQCqBRrnhxgRHA5/mlq6YYgUnPOHf5tUMVtZT6n/
   68.40 +vSRirmiITqoDhPrEnm48yCbFOW7wzmteckug0S0+9Tneb4sKC3a1SY6Jbr3eYSQn
   68.41 +EjTqDqELdHFz21gZkQsyaDOQWBUsd+MXZNnjNF7xjm38QXKAZS9t+2w8k2E5GCRA
   68.42 +6Gm5seIJLmLSHwJyTkWEkKvFZlPAU/qEFVhTCsJLfpwcjfKJ9cebIf80dOQP25e3
   68.43 +5KTmCkWo+tWaJO7huvZaI03PiorGerco/1iF7SSfTEbsuo3BBADelnN9HuPGWOxw
   68.44 +p46t+aWdPZI0N2GNvl+Z92xggOAkcLnq+yUGM8QbdZ1r+XDQlwfwpGlUIs7UbZnl
   68.45 +xFaOfh7Rja2ky5SnmuksTCoPgQ5Kb5iR0D++2kHbfhVlOLXyzpByEQSd3cqv6kN/
   68.46 +qX2TtFaOAjaJ/bDdilI5Nh5Skkg5wQQA5ar2jGnZw1EwaQvBrGwi6pSDvQdK0M4L
   68.47 +2fAvq4/Cwk+UUTgYxyk9WA3Wx8e5PalUOGBk6BSgKqIwEAOCX9qt+BD681UqGdgF
   68.48 +/KdzvR+efOt1BQU4/Nnjdc+cjVLvGBKkBbKbWiBQy1TiMVgRc4d6n/XkdPN9OyMW
   68.49 +vhB1RCxgh4sEAMcW2wYE+EAcrUXizMCQf7FpB2PUICrJtgp9BA7gN6tZQgUEsJM3
   68.50 +ZZox0L/D0gpWix2HAILOaVLdvPMAe5B1KndQ8LlkHWmtfi5cJcBHXge3C6uApYej
   68.51 +bIrddSVy53SW0C0Eann89xr30PM1UnQOpZA+DyOxPRPl9a6YP2MH2ND4O3qJATwE
   68.52 +GAEIACYWIQRDNNbbdRqMorSUQHVGKv222j+0uQUCXtc6/QIbDAUJA8JnAAAKCRBG
   68.53 +Kv222j+0uUWGB/4s2rwO3HflWfZdcAb3xmw72w6YXGn9Cb2G8uUQOzFKvOPotxDH
   68.54 +sKlqT9JIUVgzC3z6JCQMB+VidSH+2cdXxKFH2Lrw7uKgnXhYXoatGZ8jn10lA3O8
   68.55 +ymozJmIs0en4AyiEwIwDGO0x7/3CyOL+BDO+Wwb4FVw7XG/Jx49AxF7xm1BKNLIn
   68.56 +Ki8ZWJRzQfTOKCClngcvq0ChqRsuu/5retlVJg16+z/Ry27fhRNEBxPznt7pFZ6d
   68.57 +MMOudwTnS5T+Dez9lB8d1E/Vw5knnRSaEQX9eBOAJAJUKObMjJihbCppfMA7SENl
   68.58 +9npXecnVx7fcLY8x1ZxXsU88IMeAWK6JMTAJ
   68.59 +=W+er
   68.60 +-----END PGP PRIVATE KEY BLOCK-----
    69.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    69.2 +++ b/test/test_keys/priv/BIC_SYSTEMB_0x54139F26_priv.asc	Mon Jun 08 15:01:34 2020 +0200
    69.3 @@ -0,0 +1,57 @@
    69.4 +-----BEGIN PGP PRIVATE KEY BLOCK-----
    69.5 +
    69.6 +lQOYBF7XOyYBCADZHqjf8V0oKzbjRcZf0VPt5tIHLT+cZwXGzEujDrBG1ZFKqPJB
    69.7 +vzScQz+t3Kqkn2gPKfdxL3GLgFbSc7BhSv5N+FMGP3fpM+y965Fmc0uexaq6D1Zp
    69.8 +p2NT36cv97tF3K5ScDouXM9v6Lm/gACFOwW3iLqfhIv+raKswAn28OZvdWDPJHGq
    69.9 +sfeXkGzGUFTQ4DuwqgW0U+pXoh1RXbIzu9wh3zG2rKa6LfdS5tbcez+UPNT1UvJ2
   69.10 +Hm65pkSMAPvCJPs1ZzBxzvcGXpdyXYSihVlEDK7LTq9tVyFFBrocc/F0h7b7jbAe
   69.11 +DZo7Kp2j+dzlEAH/GCfF1d1aNJf4bVeF3BHBABEBAAEAB/sF8e941lCRMYG6vmXc
   69.12 +qMwuBvR4StZjj3SaiWyGxfewsNdeHnsnrrcfkj3Tomevw0ejpqgGWuC2i6iU8aMC
   69.13 +Pv3wn5ySXrmHUqsoViNwlTacXdg7aQEaOoGfQc//ob5ofs7tJfKJ43OwokQ3yKb6
   69.14 +/u88o8tMY+I7coCyTz3Wm6kLozO44jkSvJu0iCFftlbyPwkPihzsL/AeAo84yduW
   69.15 +uXj1BYGhoQnaPYWb9QtUHT5gyQc0ULQOFFw4d53zP2+nSq7gjFnsQeiUnFXoq7TQ
   69.16 +tozeAl4r1bw9nMKeqZTrKpmLpHMn4zQbqCOpfuNUWfwlv6tAmtvAdL3s3Zv8osVt
   69.17 +BLOTBADeOGg7OLP8jN4NYXjbpg7ujBVZMBlHblFgbN1OcPPGaFl6LtntqjUpeiyd
   69.18 +IP4ifkm1NeV0U5JARof0v8/QvEJW7z4skCjKj21f1cUb6aJVRph+Y65srrCtWVv2
   69.19 +KalrhwUS6BAf5JD5j61VY2jI4Zt9LbsjdQljzfE1T1FURLTXgwQA+h/EIugokoZV
   69.20 +X3zZYGdg6g5fZYBTalrYli6+ZGQegoCbYQ93fuOxyCSrxroxyo3LwHl3kZFDK0O1
   69.21 +LzgzUm95w430vC4jTtetKqEAVmby6RcrjOPAfZzpU4xXuhHRDiG5TsovLGJAc6RZ
   69.22 +bby0q+k7dJZJfj5TTbyMTgLyfYrjqmsD/jjWxOTFzX4LZ0MhX4DcOVzbPw00TWhr
   69.23 +kDDYIYaZnojAGAt5TDEbtcX83l5UCLdOzOT/s4+UqWGBlEEg4HDDpIjuW+WzzIOu
   69.24 +JxoNQnqJVgi3uS1Ro1aZWc6aBmyepVvAPrPc9jB3P7OgwDg8RNvqqCUNX7O2FYbW
   69.25 +jr96rxQeiB/TRUK0E3BheXRvOi8vQklDL1NZU1RFTUKJAU4EEwEIADgCGwMFCwkI
   69.26 +BwIGFQoJCAsCBBYCAwECHgECF4AWIQT1GZ4LCsQFlXLa2Op2tjspVBOfJgUCXtc7
   69.27 +fAAKCRB2tjspVBOfJgwgCAC4uXbY7xb//XnNZhDVOFLGn3tWwRwhrVOLa54BR8ah
   69.28 +V6UIAoGYhG/aoczcKpO87cZLZ+AuTuEqoMbfyJoTYChjRQho8G6UgTK48viuAfw/
   69.29 +Fi0yOUMd24i/l/oIf2LB3N5cBm33OL9fxs82ApwDveQ0+iBlylCrf6h0D1cFKlz1
   69.30 +oSna6u1E4NqzTbMtAgkjSKgzKv3BuBAWGe5Q1pDJZBWMgDWwUdj/QhQ0CXoPDaJc
   69.31 +5IRMubxdNO+0lia+8UZMbqnuVGxh4zz7ZQfqQRku1Ju4a2tx+rivPAP9ZviUTn+Y
   69.32 +Q4XJQzw1qonyB5pj8xXfXXHWCf8Dpk+LknjQuLNrYjxrnQOYBF7XOyYBCACzYQwT
   69.33 +wp4kLMLsV9rY753bpj9cLf6HUJQc0rn1NUrK+R1YeiL+tMMpDSxosvAw0HuVXmFd
   69.34 +vrthJ3KRJNSeyDxpXGMirLGLe6GXbHBt4jDMGni4TovIkOZcsHUa6Pd39XU23prZ
   69.35 +lUqomFM8ev/alqNs6UdltHRUWA8KHU19V6rV8t+lzTr48NfGXPyrFGumEXPTPXDW
   69.36 +J6X78NU3ae4J3ZmBhR5lWr0UWq/BsKkZMCXyrMtJ9BWXaeF/O9oBnGpv084Az6Kg
   69.37 +yEWoRWnV8V+a7r4KIhVM1X6qdHIkeWSAyZhL6LJnQyoFqbFbVvYrVSejhdf9NMy/
   69.38 ++HyECnPBKGTuL+9bABEBAAEAB/9SdJpWHQCPtWm2tZ3aWa8xMCbw6w2UyvQCmdU0
   69.39 +Q9aJHeEg8ifS+Gm7nZwb1qE1dyhP3Y4ZRxsgSj9OO+VmxbmLXxYM8uA8M0zw6750
   69.40 +rGRs9gAnDKgRvpW95rk18QAMiu7iFYqN2SP0Au1EIHAq3VLrNgKFXGGbAc2MAzND
   69.41 +GkDjzlZ9Vv95WbOC++LCpwmvL723dXOZaVUkih7Otf99862H2S/2J6TdhHs2gj90
   69.42 ++aO0DXbetiODr6S8R2531ovTZ6fdOK9I2t2PX41S5UCM5EIxADq0FDmv1lmt+xo4
   69.43 +GO8MDLIL2SpY7YrF4iw11+WaEEgtud90j2WblTPP0myg2g3FBADBps3+Gzt0yRve
   69.44 +NTB5gpYsUjFs6hOVEorhFdlBBPi8232GbxxbyUySpV3Rk5GPwUvcwOF80/sldGuw
   69.45 +x9Lqk4sPKKukqDtyz/CtYmQfqM2ERonzn1d6HMtpY4H73/adYtgveGJIvENSu/QB
   69.46 +Uh+pFxdNMc6QY1/pxPNDgv3O0ds91QQA7SHfPa3K0+gAlbFN7FDSdpE/HKxTB6m3
   69.47 +xp5Qc76WDKKkNZnz3OEcPUQuy2kkgHMdtwfZ2/6//+Bfr79jn1QEoipSfwN/itQb
   69.48 +TVw7sm9sON2FjKZByq7Tqtz6G/sS1MxI4XU1qSdgLWIA1gKHTY8l2IcnOSITxuSt
   69.49 +imd0gCIPoG8D/3rMV9sIAUdQsZ/mGBpJveGpRAO6RLfTLHcWZvTrKnZDTbxVeRV1
   69.50 +wzA7tZq+RSREXU6sDIjbF7LfJoNiyFD8vcrSjzLChMHnTdBcpERP+T9d8X8RK9aj
   69.51 +o16tyaNncubEpjHqTkoeshRVzGhUw+BqetoymbiqrOzmLsXxR9s/pBh0R1aJATwE
   69.52 +GAEIACYWIQT1GZ4LCsQFlXLa2Op2tjspVBOfJgUCXtc7JgIbDAUJA8JnAAAKCRB2
   69.53 +tjspVBOfJpakB/wJt41fkYOthT5cVh716ByW38uYcC3AOh7oOYL+CEpzQWb+I9K9
   69.54 +cqn26bPm8ftnF8Aa1F0kfhzQjYX6a+L4M2iN+rqr9738Mp8JvTBeRPgrLXd2eTB2
   69.55 +pOXvazpLv72ntCBaUFDdUyap19M0PF7/ZXYs8NFBj5y1jgpwC6i6tBR7VmpZGOR5
   69.56 +h8O9d7fqquMUGboX5waScGCLN9ULuYtz0veXwDY9R5/NytGvIwiAqUnoUtTtE1x2
   69.57 +u4VNVBJTzIWK+TjrYqCtKrxRvSwGwhB6Jk/lass6dT6+s+GJTJQv7WZ6lvwswrGS
   69.58 +SORL9hYbZohklI5JMh0DBmTUxghj2DV9tJir
   69.59 +=z2Kx
   69.60 +-----END PGP PRIVATE KEY BLOCK-----
    70.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    70.2 +++ b/test/test_keys/pub/BIC_SYSTEMA_0xDA3FB4B9_pub.asc	Mon Jun 08 15:01:34 2020 +0200
    70.3 @@ -0,0 +1,30 @@
    70.4 +-----BEGIN PGP PUBLIC KEY BLOCK-----
    70.5 +
    70.6 +mQENBF7XOv0BCADt8KEWRj8gmT5M7OASVr3qBwIldU6MXGlVqSJU5a3tGxGSyjlf
    70.7 +j8fn5PNoIna0VK+ECHOUAp1Y3sDzBgSm1wHGq4mU9yvCYeLjasrGOYhGT6QciRAC
    70.8 +0yXw8KSAc+rAOL1Wk/+GzHU0DJ0MWpw31cz1ePvFWCfo3Y/oztj/lVPtADaMsXl6
    70.9 ++KEgTpoXBGGQ4VUrs3YF8rWxldko4Hv/kOpyTofioTvUNI09I1zfIUYs9htxwZcD
   70.10 +3mUUtOlMWTYguHRjCX+T39dB5AT8UIAx0rlSD8hnNLF6Evkd6QTsOFKkL6innXUq
   70.11 +R0RjbPQNTkkVHbKZYDRSPbm5pjf6tjyihxFlABEBAAG0E3BheXRvOi8vQklDL1NZ
   70.12 +U1RFTUGJAU4EEwEIADgCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AWIQRDNNbb
   70.13 +dRqMorSUQHVGKv222j+0uQUCXtc7YAAKCRBGKv222j+0uSCNCADFY6dhEfOTGs+d
   70.14 +CZMF5DE8VGfj8zu6uHDwvv3v5h30lEBjjwcpas1oGas0Tetg8YCCk7JQpAh2ditT
   70.15 +1w5RIwn9KKX+pa082ozsSTA6iMi1ltxaXxSFgy/KPf1jzjJbpb0Euf3UV44NP7Ts
   70.16 +4Hxf+OxkQeQKjJ2xCMI2ooZVwojI7GTrE2K5oz7WgOyJIzidZC8UyEX6+YkW02Oh
   70.17 +gz6ShVNbU9Iz3MqBCrSnU1QVREcMDZ3bjxqiPZ92l7Z3voA8z84QFuANx+2JJEvJ
   70.18 +UhPeGAHHJ+BwBGMkZLyVCNTqsGwLE1s6y481vFiO09IcRyeoeB9bqu8ZFWTp5hkF
   70.19 +vAYeLvImuQENBF7XOv0BCADHsTuWRwK0hHActKkF66JIrlIh7Mta6fWJq78lVMh+
   70.20 +fWw8YQqkJXiVO9YCh5O81hlp5GllmnexcsNQqSbQZy45elNjunDlfOZd8U7kXxmk
   70.21 +4wyLLQdpHBEK7Ssp+/GKt3Bva2nSbGAtIzvHVhVpb8+UDz1jhO+sK5OcG4CA/gV0
   70.22 +sszeSk7QMHLkDWNPYlcOV1HNN1j40VDsc5BgYv4L4KsFjCIsh59sI6nQVXRSbVbH
   70.23 +4ElQ01iVzPqjhWY4aG9/u12QDt5KZYsZ7AA319aAX3V2n4H5kcv1mgvaCPLv+HAk
   70.24 +NFv97dGbG/+pb2TfwGSDWnePc1Hh93IcEuIf00BYDCLLABEBAAGJATwEGAEIACYW
   70.25 +IQRDNNbbdRqMorSUQHVGKv222j+0uQUCXtc6/QIbDAUJA8JnAAAKCRBGKv222j+0
   70.26 +uUWGB/4s2rwO3HflWfZdcAb3xmw72w6YXGn9Cb2G8uUQOzFKvOPotxDHsKlqT9JI
   70.27 +UVgzC3z6JCQMB+VidSH+2cdXxKFH2Lrw7uKgnXhYXoatGZ8jn10lA3O8ymozJmIs
   70.28 +0en4AyiEwIwDGO0x7/3CyOL+BDO+Wwb4FVw7XG/Jx49AxF7xm1BKNLInKi8ZWJRz
   70.29 +QfTOKCClngcvq0ChqRsuu/5retlVJg16+z/Ry27fhRNEBxPznt7pFZ6dMMOudwTn
   70.30 +S5T+Dez9lB8d1E/Vw5knnRSaEQX9eBOAJAJUKObMjJihbCppfMA7SENl9npXecnV
   70.31 +x7fcLY8x1ZxXsU88IMeAWK6JMTAJ
   70.32 +=kPWB
   70.33 +-----END PGP PUBLIC KEY BLOCK-----
    71.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    71.2 +++ b/test/test_keys/pub/BIC_SYSTEMB_0x54139F26_pub.asc	Mon Jun 08 15:01:34 2020 +0200
    71.3 @@ -0,0 +1,30 @@
    71.4 +-----BEGIN PGP PUBLIC KEY BLOCK-----
    71.5 +
    71.6 +mQENBF7XOyYBCADZHqjf8V0oKzbjRcZf0VPt5tIHLT+cZwXGzEujDrBG1ZFKqPJB
    71.7 +vzScQz+t3Kqkn2gPKfdxL3GLgFbSc7BhSv5N+FMGP3fpM+y965Fmc0uexaq6D1Zp
    71.8 +p2NT36cv97tF3K5ScDouXM9v6Lm/gACFOwW3iLqfhIv+raKswAn28OZvdWDPJHGq
    71.9 +sfeXkGzGUFTQ4DuwqgW0U+pXoh1RXbIzu9wh3zG2rKa6LfdS5tbcez+UPNT1UvJ2
   71.10 +Hm65pkSMAPvCJPs1ZzBxzvcGXpdyXYSihVlEDK7LTq9tVyFFBrocc/F0h7b7jbAe
   71.11 +DZo7Kp2j+dzlEAH/GCfF1d1aNJf4bVeF3BHBABEBAAG0E3BheXRvOi8vQklDL1NZ
   71.12 +U1RFTUKJAU4EEwEIADgCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AWIQT1GZ4L
   71.13 +CsQFlXLa2Op2tjspVBOfJgUCXtc7fAAKCRB2tjspVBOfJgwgCAC4uXbY7xb//XnN
   71.14 +ZhDVOFLGn3tWwRwhrVOLa54BR8ahV6UIAoGYhG/aoczcKpO87cZLZ+AuTuEqoMbf
   71.15 +yJoTYChjRQho8G6UgTK48viuAfw/Fi0yOUMd24i/l/oIf2LB3N5cBm33OL9fxs82
   71.16 +ApwDveQ0+iBlylCrf6h0D1cFKlz1oSna6u1E4NqzTbMtAgkjSKgzKv3BuBAWGe5Q
   71.17 +1pDJZBWMgDWwUdj/QhQ0CXoPDaJc5IRMubxdNO+0lia+8UZMbqnuVGxh4zz7ZQfq
   71.18 +QRku1Ju4a2tx+rivPAP9ZviUTn+YQ4XJQzw1qonyB5pj8xXfXXHWCf8Dpk+LknjQ
   71.19 +uLNrYjxruQENBF7XOyYBCACzYQwTwp4kLMLsV9rY753bpj9cLf6HUJQc0rn1NUrK
   71.20 ++R1YeiL+tMMpDSxosvAw0HuVXmFdvrthJ3KRJNSeyDxpXGMirLGLe6GXbHBt4jDM
   71.21 +Gni4TovIkOZcsHUa6Pd39XU23prZlUqomFM8ev/alqNs6UdltHRUWA8KHU19V6rV
   71.22 +8t+lzTr48NfGXPyrFGumEXPTPXDWJ6X78NU3ae4J3ZmBhR5lWr0UWq/BsKkZMCXy
   71.23 +rMtJ9BWXaeF/O9oBnGpv084Az6KgyEWoRWnV8V+a7r4KIhVM1X6qdHIkeWSAyZhL
   71.24 +6LJnQyoFqbFbVvYrVSejhdf9NMy/+HyECnPBKGTuL+9bABEBAAGJATwEGAEIACYW
   71.25 +IQT1GZ4LCsQFlXLa2Op2tjspVBOfJgUCXtc7JgIbDAUJA8JnAAAKCRB2tjspVBOf
   71.26 +JpakB/wJt41fkYOthT5cVh716ByW38uYcC3AOh7oOYL+CEpzQWb+I9K9cqn26bPm
   71.27 +8ftnF8Aa1F0kfhzQjYX6a+L4M2iN+rqr9738Mp8JvTBeRPgrLXd2eTB2pOXvazpL
   71.28 +v72ntCBaUFDdUyap19M0PF7/ZXYs8NFBj5y1jgpwC6i6tBR7VmpZGOR5h8O9d7fq
   71.29 +quMUGboX5waScGCLN9ULuYtz0veXwDY9R5/NytGvIwiAqUnoUtTtE1x2u4VNVBJT
   71.30 +zIWK+TjrYqCtKrxRvSwGwhB6Jk/lass6dT6+s+GJTJQv7WZ6lvwswrGSSORL9hYb
   71.31 +ZohklI5JMh0DBmTUxghj2DV9tJir
   71.32 +=863w
   71.33 +-----END PGP PUBLIC KEY BLOCK-----
    72.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    72.2 +++ b/test/test_mails/html_with_text_attachment.eml	Mon Jun 08 15:01:34 2020 +0200
    72.3 @@ -0,0 +1,59 @@
    72.4 +From: Krista Bennett <krista@darthmama.org>
    72.5 +To: Krista Bennett <krista@pep-project.org>
    72.6 +Message-ID: <cf2b0a5e-6067-cd9f-a12e-c7fb35d9b22a@darthmama.org>
    72.7 +Date: Sun, 19 Apr 2020 21:22:11 +0200
    72.8 +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:68.0)
    72.9 + Gecko/20100101 Thunderbird/68.6.0
   72.10 +MIME-Version: 1.0
   72.11 +Content-Type: multipart/mixed;
   72.12 + boundary="------------E013C00060D993E4C8673318"
   72.13 +Content-Language: en-GB
   72.14 +
   72.15 +This is a multi-part message in MIME format.
   72.16 +--------------E013C00060D993E4C8673318
   72.17 +Content-Type: text/html; charset=utf-8
   72.18 +Content-Transfer-Encoding: 7bit
   72.19 +
   72.20 +<html>
   72.21 +  <head>
   72.22 +    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
   72.23 +  </head>
   72.24 +  <body>
   72.25 +    <table width="100%" cellspacing="2" cellpadding="2" border="1"
   72.26 +      bgcolor="pink">
   72.27 +      <tbody>
   72.28 +        <tr>
   72.29 +          <td valign="top" bgcolor="pink"><br>
   72.30 +          </td>
   72.31 +          <td valign="top"><br>
   72.32 +          </td>
   72.33 +        </tr>
   72.34 +        <tr>
   72.35 +          <td valign="top"><br>
   72.36 +          </td>
   72.37 +          <td valign="top"><br>
   72.38 +          </td>
   72.39 +        </tr>
   72.40 +        <tr>
   72.41 +          <td valign="top"><br>
   72.42 +          </td>
   72.43 +          <td valign="top"><br>
   72.44 +          </td>
   72.45 +        </tr>
   72.46 +      </tbody>
   72.47 +    </table>
   72.48 +    <p><br>
   72.49 +    </p>
   72.50 +  </body>
   72.51 +</html>
   72.52 +
   72.53 +--------------E013C00060D993E4C8673318
   72.54 +Content-Type: text/plain; charset=UTF-8; x-mac-type="0"; x-mac-creator="0";
   72.55 + name="blargh.txt"
   72.56 +Content-Transfer-Encoding: base64
   72.57 +Content-Disposition: attachment;
   72.58 + filename="blargh.txt"
   72.59 +
   72.60 +WW91ciBtb3RoZXIgd2FzIGEgaGFtc3RlcgpBbmQgeW91ciBmYXRoZXIgc21lbHQgb2YgZWx0
   72.61 +ZXJiZXJyaWVzCg==
   72.62 +--------------E013C00060D993E4C8673318--
    73.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    73.2 +++ b/test/test_mails/htmlonly_simple.eml	Mon Jun 08 15:01:34 2020 +0200
    73.3 @@ -0,0 +1,43 @@
    73.4 +From: Krista Bennett <krista@darthmama.org>
    73.5 +To: Krista Bennett <krista@pep-project.org>
    73.6 +Message-ID: <eea822c9-1786-9c9a-b818-9a0a00f2ff9e@darthmama.org>
    73.7 +Date: Sun, 19 Apr 2020 21:16:07 +0200
    73.8 +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:68.0)
    73.9 + Gecko/20100101 Thunderbird/68.6.0
   73.10 +MIME-Version: 1.0
   73.11 +Content-Type: text/html; charset=utf-8
   73.12 +Content-Language: en-GB
   73.13 +Content-Transfer-Encoding: 7bit
   73.14 +
   73.15 +<html>
   73.16 +  <head>
   73.17 +    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
   73.18 +  </head>
   73.19 +  <body>
   73.20 +    <table width="100%" cellspacing="2" cellpadding="2" border="1"
   73.21 +      bgcolor="pink">
   73.22 +      <tbody>
   73.23 +        <tr>
   73.24 +          <td valign="top" bgcolor="pink"><br>
   73.25 +          </td>
   73.26 +          <td valign="top"><br>
   73.27 +          </td>
   73.28 +        </tr>
   73.29 +        <tr>
   73.30 +          <td valign="top"><br>
   73.31 +          </td>
   73.32 +          <td valign="top"><br>
   73.33 +          </td>
   73.34 +        </tr>
   73.35 +        <tr>
   73.36 +          <td valign="top"><br>
   73.37 +          </td>
   73.38 +          <td valign="top"><br>
   73.39 +          </td>
   73.40 +        </tr>
   73.41 +      </tbody>
   73.42 +    </table>
   73.43 +    <p><br>
   73.44 +    </p>
   73.45 +  </body>
   73.46 +</html>
    74.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    74.2 +++ b/test/test_mails/htmlonly_simple_html_text.eml	Mon Jun 08 15:01:34 2020 +0200
    74.3 @@ -0,0 +1,123 @@
    74.4 +X-Envelope-From: <SRS0=I20PID=6G=darthmama.org=krista@srs.smtpin.rzone.de>
    74.5 +X-Envelope-To: <krista@darthmama.org>
    74.6 +X-Delivery-Time: 1587540868
    74.7 +X-UID: 6191
    74.8 +Return-Path: <SRS0=I20PID=6G=darthmama.org=krista@srs.smtpin.rzone.de>
    74.9 +Authentication-Results: strato.com; dmarc=none header.from=darthmama.org
   74.10 +Authentication-Results: strato.com; arc=none
   74.11 +Authentication-Results: strato.com; dkim=pass header.d=darthmama.org
   74.12 +Authentication-Results: strato.com; dkim-adsp=pass header.from="krista@darthmama.org"
   74.13 +Authentication-Results: strato.com; spf=pass smtp.mailfrom="SRS0=I20PID=6G=darthmama.org=krista@srs.smtpin.rzone.de"
   74.14 +X-RZG-Expurgate: clean/normal
   74.15 +X-RZG-Expurgate-ID: 149500::1587540868-00004BAD-469590D0/0/0
   74.16 +X-RZG-CLASS-ID: mi00
   74.17 +Received-SPF: pass
   74.18 +	(strato.com: domain _spf.strato.com designates 2a01:238:20a:202:5100::11 as permitted sender)
   74.19 +	mechanism=ip6;
   74.20 +	client-ip=2a01:238:20a:202:5100::11;
   74.21 +	helo="mi6-p00-ob.smtp.rzone.de";
   74.22 +	envelope-from="SRS0=I20PID=6G=darthmama.org=krista@srs.smtpin.rzone.de";
   74.23 +	receiver=smtpin.rzone.de;
   74.24 +	identity=mailfrom;
   74.25 +Received: from mi6-p00-ob.smtp.rzone.de ([IPv6:2a01:238:20a:202:5100::11])
   74.26 +	by smtpin.rzone.de (RZmta 46.6.0 OK)
   74.27 +	with ESMTPS id 20aea8w3M7YSAKT
   74.28 +	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits))
   74.29 +	(Client CN "*.smtp.rzone.de", Issuer "TeleSec ServerPass Class 2 CA" (verified OK (+EmiG)))
   74.30 +	(Client hostname verified OK)
   74.31 +	for <krista@darthmama.org>;
   74.32 +	Wed, 22 Apr 2020 09:34:28 +0200 (CEST)
   74.33 +X-RZG-FWD-BY: julio_iglesias@darthmama.org
   74.34 +Received: from mailin.rzone.de ([unix socket])
   74.35 +	by mailin.rzone.de (RZmta 46.6.2) with LMTPA;
   74.36 +	Wed, 22 Apr 2020 09:34:24 +0200 (CEST)
   74.37 +Authentication-Results: strato.com; dmarc=none header.from=darthmama.org
   74.38 +Authentication-Results: strato.com; arc=none
   74.39 +Authentication-Results: strato.com; dkim=pass header.d=darthmama.org
   74.40 +Authentication-Results: strato.com; dkim-adsp=pass header.from="krista@darthmama.org"
   74.41 +Authentication-Results: strato.com; spf=none smtp.mailfrom="krista@darthmama.org"
   74.42 +X-RZG-Expurgate: clean/normal
   74.43 +X-RZG-Expurgate-ID: 149500::1587540864-00004380-B43F2B11/0/0
   74.44 +X-RZG-CLASS-ID: mi00
   74.45 +Received-SPF: none
   74.46 +	client-ip=2a01:238:20a:202:5307::5;
   74.47 +	helo="mo6-p07-ob.smtp.rzone.de";
   74.48 +	envelope-from="krista@darthmama.org";
   74.49 +	receiver=smtpin.rzone.de;
   74.50 +	identity=mailfrom;
   74.51 +Received: from mo6-p07-ob.smtp.rzone.de ([IPv6:2a01:238:20a:202:5307::5])
   74.52 +	by smtpin.rzone.de (RZmta 46.6.2 OK)
   74.53 +	with ESMTPS id A057bew3M7YO00a
   74.54 +	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits))
   74.55 +	(Client CN "*.smtp.rzone.de", Issuer "TeleSec ServerPass Class 2 CA" (verified OK (+EmiG)))
   74.56 +	(Client hostname verified OK)
   74.57 +	for <julio_iglesias@darthmama.org>;
   74.58 +	Wed, 22 Apr 2020 09:34:24 +0200 (CEST)
   74.59 +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1587540864;
   74.60 +	s=strato-dkim-0002; d=darthmama.org;
   74.61 +	h=Date:Message-ID:Subject:From:To:X-RZG-AUTH:X-RZG-CLASS-ID:From:
   74.62 +	Subject:Sender;
   74.63 +	bh=J+wH7gYfbTPhHjSM+qD4mLbO30Me/SfkoBOvO/SonPI=;
   74.64 +	b=PC+SuL/unD4gntJjDRBnZAqVL6uM3dCHMl4rFWgjxrROrdgVKPq4s2R3khdCEx8Vj2
   74.65 +	X9wu8f4/LhBoJtFNMO8QZf0LkFEt9UEDwekfs9wYtmNiJO0uoS6zzferhH0bqQMIu8xD
   74.66 +	+GZC/CG5yR5PmYv4ES6ROq74W9PyRq9ji/2LXShPwlaGllQXpA0/9e3PTpf9HiKWefNS
   74.67 +	wPa1MLC6XDVOsiCMU61QtTniNsAVdPyiCbK+JTgUsJw13Cwd43FsLfi8IlHPtSqs8i7E
   74.68 +	q5fc26LO/4JzB0kO6OP4g067ud5B9E/pzD2yfjURXGTNh0uv18uMqICVZmlicpVOIRTw
   74.69 +	tpTw==
   74.70 +X-RZG-CLASS-ID: mo07
   74.71 +X-RZG-AUTH: ":J34NZlSpW/vPDlKSRxUBevLT/2WDdlCqkty/deruLplgoO4nY+csF8wOXLHBXKAYNsYMbdY="
   74.72 +Received: from rylen.home
   74.73 +	by smtp.strato.de (RZmta 46.5.0 DYNA|AUTH)
   74.74 +	with ESMTPSA id U08b44w3M7YOIJ6
   74.75 +	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits))
   74.76 +	(Client did not present a certificate)
   74.77 +	for <julio_iglesias@darthmama.org>;
   74.78 +	Wed, 22 Apr 2020 09:34:24 +0200 (CEST)
   74.79 +To: julio_iglesias@darthmama.org
   74.80 +From: Krista Bennett <krista@darthmama.org>
   74.81 +Subject: Your Mama
   74.82 +Message-ID: <e31f5f3d-35cf-2d9e-222b-6a8b5b9eb57a@darthmama.org>
   74.83 +Date: Wed, 22 Apr 2020 09:34:24 +0200
   74.84 +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:68.0)
   74.85 + Gecko/20100101 Thunderbird/68.6.0
   74.86 +MIME-Version: 1.0
   74.87 +Content-Type: multipart/mixed;
   74.88 + boundary="------------693FCCD6AEE78505BE42C641"
   74.89 +Content-Language: en-GB
   74.90 +
   74.91 +This is a multi-part message in MIME format.
   74.92 +--------------693FCCD6AEE78505BE42C641
   74.93 +Content-Type: text/html; charset=utf-8
   74.94 +Content-Transfer-Encoding: 8bit
   74.95 +
   74.96 +<html>
   74.97 +  <head>
   74.98 +
   74.99 +    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  74.100 +  </head>
  74.101 +  <body>
  74.102 +    <h1>This is the most fun I have ever had</h1>
  74.103 +    <p><font color="#ff0000">I'm a crappy liar.</font></p>
  74.104 +    <p><font color="#ff0000"><br>
  74.105 +      </font></p>
  74.106 +  </body>
  74.107 +</html>
  74.108 +
  74.109 +--------------693FCCD6AEE78505BE42C641
  74.110 +Content-Type: text/html; charset=UTF-8; x-mac-type="0"; x-mac-creator="0";
  74.111 + name="meh.html"
  74.112 +Content-Transfer-Encoding: base64
  74.113 +Content-Disposition: attachment;
  74.114 + filename="meh.html"
  74.115 +
  74.116 +PGh0bWw+Cjxib2R5Pgo8aDE+SFRNTCBNYWlsIGlzIEZvciBMb3NlcnM8L2gxPgo8cD5CdXQg
  74.117 +cGVvcGxlIHVzZSBpdC48L3A+CjwvYm9keT4KPC9odG1sPgo=
  74.118 +--------------693FCCD6AEE78505BE42C641
  74.119 +Content-Type: text/plain; charset=UTF-8; x-mac-type="0"; x-mac-creator="0";
  74.120 + name="bah.text"
  74.121 +Content-Transfer-Encoding: base64
  74.122 +Content-Disposition: attachment;
  74.123 + filename="bah.text"
  74.124 +
  74.125 +CkJBSC4K
  74.126 +--------------693FCCD6AEE78505BE42C641--
    75.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    75.2 +++ b/test/test_mails/htmlonly_simple_text_html.eml	Mon Jun 08 15:01:34 2020 +0200
    75.3 @@ -0,0 +1,122 @@
    75.4 +X-Envelope-From: <SRS0=I20PID=6G=darthmama.org=krista@srs.smtpin.rzone.de>
    75.5 +X-Envelope-To: <krista@darthmama.org>
    75.6 +X-Delivery-Time: 1587540917
    75.7 +X-UID: 6192
    75.8 +Return-Path: <SRS0=I20PID=6G=darthmama.org=krista@srs.smtpin.rzone.de>
    75.9 +Authentication-Results: strato.com; dmarc=none header.from=darthmama.org
   75.10 +Authentication-Results: strato.com; arc=none
   75.11 +Authentication-Results: strato.com; dkim=pass header.d=darthmama.org
   75.12 +Authentication-Results: strato.com; dkim-adsp=pass header.from="krista@darthmama.org"
   75.13 +Authentication-Results: strato.com; spf=pass smtp.mailfrom="SRS0=I20PID=6G=darthmama.org=krista@srs.smtpin.rzone.de"
   75.14 +X-RZG-Expurgate: clean/normal
   75.15 +X-RZG-Expurgate-ID: 149500::1587540916-0000EE76-29019E4A/0/0
   75.16 +X-RZG-CLASS-ID: mi00
   75.17 +Received-SPF: pass
   75.18 +	(strato.com: domain _spf.strato.com designates 2a01:238:20a:202:5100::3 as permitted sender)
   75.19 +	mechanism=ip6;
   75.20 +	client-ip=2a01:238:20a:202:5100::3;
   75.21 +	helo="mi6-p00-ob.smtp.rzone.de";
   75.22 +	envelope-from="SRS0=I20PID=6G=darthmama.org=krista@srs.smtpin.rzone.de";
   75.23 +	receiver=smtpin.rzone.de;
   75.24 +	identity=mailfrom;
   75.25 +Received: from mi6-p00-ob.smtp.rzone.de ([IPv6:2a01:238:20a:202:5100::3])
   75.26 +	by smtpin.rzone.de (RZmta 46.6.1 OK)
   75.27 +	with ESMTPS id B07b2cw3M7ZG2bx
   75.28 +	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits))
   75.29 +	(Client CN "*.smtp.rzone.de", Issuer "TeleSec ServerPass Class 2 CA" (verified OK (+EmiG)))
   75.30 +	(Client hostname verified OK)
   75.31 +	for <krista@darthmama.org>;
   75.32 +	Wed, 22 Apr 2020 09:35:16 +0200 (CEST)
   75.33 +X-RZG-FWD-BY: julio_iglesias@darthmama.org
   75.34 +Received: from mailin.rzone.de ([unix socket])
   75.35 +	by mailin.rzone.de (RZmta 46.6.0) with LMTPA;
   75.36 +	Wed, 22 Apr 2020 09:35:11 +0200 (CEST)
   75.37 +Authentication-Results: strato.com; dmarc=none header.from=darthmama.org
   75.38 +Authentication-Results: strato.com; arc=none
   75.39 +Authentication-Results: strato.com; dkim=pass header.d=darthmama.org
   75.40 +Authentication-Results: strato.com; dkim-adsp=pass header.from="krista@darthmama.org"
   75.41 +Authentication-Results: strato.com; spf=none smtp.mailfrom="krista@darthmama.org"
   75.42 +X-RZG-Expurgate: clean/normal
   75.43 +X-RZG-Expurgate-ID: 149500::1587540911-00004380-31579719/0/0
   75.44 +X-RZG-CLASS-ID: mi00
   75.45 +Received-SPF: none
   75.46 +	client-ip=2a01:238:20a:202:5307::11;
   75.47 +	helo="mo6-p07-ob.smtp.rzone.de";
   75.48 +	envelope-from="krista@darthmama.org";
   75.49 +	receiver=smtpin.rzone.de;
   75.50 +	identity=mailfrom;
   75.51 +Received: from mo6-p07-ob.smtp.rzone.de ([IPv6:2a01:238:20a:202:5307::11])
   75.52 +	by smtpin.rzone.de (RZmta 46.6.0 OK)
   75.53 +	with ESMTPS id t0828bw3M7ZB8R0
   75.54 +	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits))
   75.55 +	(Client CN "*.smtp.rzone.de", Issuer "TeleSec ServerPass Class 2 CA" (verified OK (+EmiG)))
   75.56 +	(Client hostname verified OK)
   75.57 +	for <julio_iglesias@darthmama.org>;
   75.58 +	Wed, 22 Apr 2020 09:35:11 +0200 (CEST)
   75.59 +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1587540911;
   75.60 +	s=strato-dkim-0002; d=darthmama.org;
   75.61 +	h=Date:Message-ID:To:Subject:From:X-RZG-AUTH:X-RZG-CLASS-ID:From:
   75.62 +	Subject:Sender;
   75.63 +	bh=TnyvEYioxm6/d8GUeB2sTvctvd3PuTUf1kvffvjwrrQ=;
   75.64 +	b=kYzNyo+tcGBHFOAYThKRGdd59W9f0CcYRtI/1x/a21xi24+vYMJyc6pfdJoYttR2Qc
   75.65 +	kpWNcX7T/yE9INIPlxjIDwo8CiNdrTd3hnLvvDB6bnyYtDjwKwvw5e3yJMtkB3U8qcUz
   75.66 +	CDF74GOTsPDn+GV3tbsJaSqi5d9P8FpW8lw+7aXUTldBSf1mwBxttq7CVGfwXbnz6HPV
   75.67 +	IEBOfURwKwqXGOiwc8GlugbNnldjEazJam7XNZ0GNgayGWCA3vtR9shfbrQfOYA8Oyey
   75.68 +	JnR/bqxJXDUsIhmYv0tGyNdZgPz9ojMUtgk7Aly1NKKp/LN6nRUet7TuRuE3INSnGt/n
   75.69 +	YoXg==
   75.70 +X-RZG-CLASS-ID: mo07
   75.71 +X-RZG-AUTH: ":J34NZlSpW/vPDlKSRxUBevLT/2WDdlCqkty/deruLplgoO4nY+csF8wOXLHBXKAYNsYMbdY="
   75.72 +Received: from rylen.home
   75.73 +	by smtp.strato.de (RZmta 46.5.0 DYNA|AUTH)
   75.74 +	with ESMTPSA id U08b44w3M7ZBIJO
   75.75 +	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits))
   75.76 +	(Client did not present a certificate)
   75.77 +	for <julio_iglesias@darthmama.org>;
   75.78 +	Wed, 22 Apr 2020 09:35:11 +0200 (CEST)
   75.79 +From: Krista Bennett <krista@darthmama.org>
   75.80 +Subject: Your Mama
   75.81 +To: julio_iglesias@darthmama.org
   75.82 +Message-ID: <0f2a1bba-a6d8-781c-124c-e949ddeae1a9@darthmama.org>
   75.83 +Date: Wed, 22 Apr 2020 09:35:11 +0200
   75.84 +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:68.0)
   75.85 + Gecko/20100101 Thunderbird/68.6.0
   75.86 +MIME-Version: 1.0
   75.87 +Content-Type: multipart/mixed;
   75.88 + boundary="------------40D9CF2870171E386694EDAD"
   75.89 +Content-Language: en-GB
   75.90 +
   75.91 +This is a multi-part message in MIME format.
   75.92 +--------------40D9CF2870171E386694EDAD
   75.93 +Content-Type: text/html; charset=utf-8
   75.94 +Content-Transfer-Encoding: 7bit
   75.95 +
   75.96 +<html>
   75.97 +  <head>
   75.98 +    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
   75.99 +  </head>
  75.100 +  <body>
  75.101 +    <h1>This is the most fun I have ever had</h1>
  75.102 +    <p><font color="#ff0000">I'm a crappy liar.</font></p>
  75.103 +    <p><font color="#ff0000"><br>
  75.104 +      </font></p>
  75.105 +  </body>
  75.106 +</html>
  75.107 +
  75.108 +--------------40D9CF2870171E386694EDAD
  75.109 +Content-Type: text/plain; charset=UTF-8; x-mac-type="0"; x-mac-creator="0";
  75.110 + name="bah.text"
  75.111 +Content-Transfer-Encoding: base64
  75.112 +Content-Disposition: attachment;
  75.113 + filename="bah.text"
  75.114 +
  75.115 +CkJBSC4K
  75.116 +--------------40D9CF2870171E386694EDAD
  75.117 +Content-Type: text/html; charset=UTF-8; x-mac-type="0"; x-mac-creator="0";
  75.118 + name="meh.html"
  75.119 +Content-Transfer-Encoding: base64
  75.120 +Content-Disposition: attachment;
  75.121 + filename="meh.html"
  75.122 +
  75.123 +PGh0bWw+Cjxib2R5Pgo8aDE+SFRNTCBNYWlsIGlzIEZvciBMb3NlcnM8L2gxPgo8cD5CdXQg
  75.124 +cGVvcGxlIHVzZSBpdC48L3A+CjwvYm9keT4KPC9odG1sPgo=
  75.125 +--------------40D9CF2870171E386694EDAD--
    76.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    76.2 +++ b/test/test_mails/htmlonlycatwithMOARCAT.eml	Mon Jun 08 15:01:34 2020 +0200
    76.3 @@ -0,0 +1,277 @@
    76.4 +Return-Path: <krista@darthmama.org>
    76.5 +X-Original-To: krista@pep-project.org
    76.6 +Delivered-To: krista@pep-project.org
    76.7 +Received: from localhost (localhost [127.0.0.1])
    76.8 +	by dragon.pibit.ch (Postfix) with ESMTP id 2C082171C08E
    76.9 +	for <krista@pep-project.org>; Mon, 20 Apr 2020 17:26:30 +0200 (CEST)
   76.10 +Received: from dragon.pibit.ch ([127.0.0.1])
   76.11 +	by localhost (dragon.pibit.ch [127.0.0.1]) (amavisd-new, port 10024)
   76.12 +	with ESMTP id GEkhRf3rBF1K for <krista@pep-project.org>;
   76.13 +	Mon, 20 Apr 2020 17:26:30 +0200 (CEST)
   76.14 +Received: from mo4-p00-ob.smtp.rzone.de (mo4-p00-ob.smtp.rzone.de [85.215.255.23])
   76.15 +	by dragon.pibit.ch (Postfix) with ESMTPS id 00DAA171C08B
   76.16 +	for <krista@pep-project.org>; Mon, 20 Apr 2020 17:26:29 +0200 (CEST)
   76.17 +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1587396389;
   76.18 +	s=strato-dkim-0002; d=darthmama.org;
   76.19 +	h=Date:Message-ID:To:From:X-RZG-CLASS-ID:X-RZG-AUTH:From:Subject:
   76.20 +	Sender;
   76.21 +	bh=rMsKWqstinPku0D0vpqeEbtu4WyNhFoHJvAIhrq8Pf8=;
   76.22 +	b=AOU12h4tx7Xp2CelzJKlZunns2n5X8k/hPstXRNNMPq5gjieabsE0I+fXNdpOEK7u4
   76.23 +	aUeiffeBfOoiPVZhZUUyV7uALgmUYi/V8kONxE3HFrZg9E29bJHVKZDH6kS+Sr23MHOQ
   76.24 +	KgNhOLrUeOji4KTywSaWbCo+C80lSvG5ivspGX7faDq62vjRcZLWSJ2UJ1kPQNSD2ift
   76.25 +	oqQ7M5dMFAtInI0NM7M5NfCBX3br1fPTpVK7UnoX8dkaRGxrDgFmR52YaJKaNafgjuCX
   76.26 +	UgXPWLKwnephfcI6RBMm54+4z3l3SLd9/0dFTbkLb5+ZXQDxu9v2vRA8lIA0PmKACEEx
   76.27 +	/eKg==
   76.28 +X-RZG-AUTH: ":J34NZlSpW/vPDlKSRxUBevLT/2WDdlCqkty/deruLplgoO4nY+csF8wOXLHBXKAYNsYMbdY="
   76.29 +X-RZG-CLASS-ID: mo00
   76.30 +Received: from rylen.home
   76.31 +	by smtp.strato.de (RZmta 46.5.0 DYNA|AUTH)
   76.32 +	with ESMTPSA id U08b44w3KFQTCI6
   76.33 +	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits))
   76.34 +	(Client did not present a certificate)
   76.35 +	for <krista@pep-project.org>;
   76.36 +	Mon, 20 Apr 2020 17:26:29 +0200 (CEST)
   76.37 +From: Krista Bennett <krista@darthmama.org>
   76.38 +To: Krista Bennett <krista@pep-project.org>
   76.39 +Message-ID: <2aac170e-4ffa-5f66-c1ab-0252d4e89924@darthmama.org>
   76.40 +Date: Mon, 20 Apr 2020 17:26:29 +0200
   76.41 +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:68.0)
   76.42 + Gecko/20100101 Thunderbird/68.6.0
   76.43 +MIME-Version: 1.0
   76.44 +Content-Type: multipart/mixed;
   76.45 + boundary="------------EC543696A16813A5DAA28AB1"
   76.46 +Content-Language: en-GB
   76.47 +
   76.48 +This is a multi-part message in MIME format.
   76.49 +--------------EC543696A16813A5DAA28AB1
   76.50 +Content-Type: multipart/related;
   76.51 + boundary="------------6AB84297773D6C43C8ED3ABC"
   76.52 +
   76.53 +
   76.54 +--------------6AB84297773D6C43C8ED3ABC
   76.55 +Content-Type: text/html; charset=utf-8
   76.56 +Content-Transfer-Encoding: 7bit
   76.57 +
   76.58 +<html>
   76.59 +  <head>
   76.60 +    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
   76.61 +  </head>
   76.62 +  <body>
   76.63 +    <table width="100%" cellspacing="2" cellpadding="2" border="1"
   76.64 +      bgcolor="pink">
   76.65 +      <tbody>
   76.66 +        <tr>
   76.67 +          <td valign="top" bgcolor="pink"><img moz-do-not-send="false"
   76.68 +              src="cid:part1.AC060ED3.AD29176B@darthmama.org" alt="Tiny
   76.69 +              Canth cat" class="" width="144" height="204"><br>
   76.70 +          </td>
   76.71 +          <td valign="top"><br>
   76.72 +          </td>
   76.73 +        </tr>
   76.74 +        <tr>
   76.75 +          <td valign="top"><br>
   76.76 +          </td>
   76.77 +          <td valign="top"><br>
   76.78 +          </td>
   76.79 +        </tr>
   76.80 +        <tr>
   76.81 +          <td valign="top"><br>
   76.82 +          </td>
   76.83 +          <td valign="top"><br>
   76.84 +          </td>
   76.85 +        </tr>
   76.86 +      </tbody>
   76.87 +    </table>
   76.88 +    <p><br>
   76.89 +    </p>
   76.90 +  </body>
   76.91 +</html>
   76.92 +
   76.93 +--------------6AB84297773D6C43C8ED3ABC
   76.94 +Content-Type: image/jpeg;
   76.95 + name="meow.jpeg"
   76.96 +Content-Transfer-Encoding: base64
   76.97 +Content-ID: <part1.AC060ED3.AD29176B@darthmama.org>
   76.98 +Content-Disposition: inline;
   76.99 + filename="meow.jpeg"
  76.100 +
  76.101 +/9j/4AAQSkZJRgABAQAASABIAAD/4QCMRXhpZgAATU0AKgAAAAgABQESAAMAAAABAAEAAAEa
  76.102 +AAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAAAAAAAABI
  76.103 +AAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAAJCgAwAEAAAAAQAAAMwAAAAA
  76.104 +/+0AOFBob3Rvc2hvcCAzLjAAOEJJTQQEAAAAAAAAOEJJTQQlAAAAAAAQ1B2M2Y8AsgTpgAmY
  76.105 +7PhCfv/AABEIAMwAkAMBIgACEQEDEQH/xAAfAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJ
  76.106 +Cgv/xAC1EAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYTUWEHInEUMoGRoQgjQrHBFVLR
  76.107 +8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2
  76.108 +d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX
  76.109 +2Nna4eLj5OXm5+jp6vHy8/T19vf4+fr/xAAfAQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJ
  76.110 +Cgv/xAC1EQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS
  76.111 +8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1
  76.112 +dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV
  76.113 +1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkM
  76.114 +EQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4e
  76.115 +FBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/
  76.116 +3QAEAAn/2gAMAwEAAhEDEQA/AO5GD7U7Ge9AH5UuM9K8JpntgvGKeMUij8acAcdKEAdulKfQ
  76.117 +0tQXc6wQtI38IzSYEWpX0NlB5krAZ6DPJrCXxAJJCFbj2rhvF+sXN/qTgSEInAGelZlneyxO
  76.118 +Mkn8aycnfQ6I0tD2Gx1ESAZPP1rUicMMgivLtJ1obgC4rsdJ1MOq/MOapSuRKnY6Uc04c1FB
  76.119 +Ksigg5qYdKu5mJyO1AGRTgPWimIQUU4DpQRRqAhpMc0/FGOOlAH/0O6B4pw60gNKuOleEe2P
  76.120 +HWn9uaaM+tOU0gHfhWH4oc/ZmQelbg+tYviOPfHz6UPYa3PJL1d1656ZPNRMgxxWhqaf6c4C
  76.121 +8etRFBjmsEjuT0M8M8ThlYgjpW/oWsFCqlufQmsW4jwCSKoNKY23DtTfkVZSR7PoeqK6rl+K
  76.122 +6WCRXjBBzXivhvWmWRY3PPQV6boGoiVACwwferT01OWrTaOixQKarAinDrVmAoXmlI9BSg0o
  76.123 +9qoVxMdsUU6gjNAH/9HuScKTngV5rrPjq7g1+WBYSltG20Y5J9zXpTqChXsRivJPGWl+Vqjy
  76.124 +hflzzXzlRtI+ioRjKVpHd+H/ABXZagi7pFVvrXSwyJIoZGBB968Cj3QvviJVh3FdBo/im/sy
  76.125 +oZ/MUcVKq9zWeF/lPY6ztaTfb9M1haR4xtp0Hnjaxrfnube6s90cqnIrVTUkcrhKL1R5dr6+
  76.126 +Xetxyapp0LGtLxYqLe5H5CsuM7sCskzrjsV7wsxPvWLfArk9P610jRDbyMn0rG1SAAHOCcdK
  76.127 +3irjUrGTb3TRygqeRXb6L4hnt41OC2a87nbZJ0/CtzQrvem09j60VabSuaKSnoz0eLxtNCR5
  76.128 +i4B6k81rWHjqxl+TLLnu/f8ACvM7pfMUDNVIFYPn0rkdWSB4aLPfbDVIblA4bAPTPetOM5XO
  76.129 +K8M0rVryzkDpKzfU5rtdD8bxyERXZbf0GMn+VbU6ye5y1MPKOx6CtO+tULG/iuI1dGGCPWrq
  76.130 +nPJrZHM1Y//S7oVzfjHTUuLQvjkV0SdKjvohLbsCM14EldHuRdnc8QvYjBMyMDwagVwCMmun
  76.131 +8Z2BjZpUXHpXETzFTgmua2tj04T5lc1pL0ImAw49KjTxDqEX7qG4dQeOvSueuLkg/e4pqyk4
  76.132 +J4JNX7MiczrIbiS4y8kjSH1JqzCwHesvTHDQ4XoBWhDyfepjuSi+hJWs/UYsj3FaEBULioNS
  76.133 +TdCwHXGa6oGcjgtXZWuSEzV/w7bSSuSTsUdWqndwFroknoTVqy1NYXFu+EUVrNPlsgpvXU6h
  76.134 +41QDaSwquygSHAOKm0+X7RbEfwjoTTXHzeleZUWp3Rd0SRYA4qTCnOcj6VAje9OMm0VhrcZu
  76.135 +aNq93ZOoiuHKj+Aniu70DxK07eXMkaN6g5/U15bbuFOeenrWjbXIGOSfxraFWUWc9SjGR//T
  76.136 +7aM1N2IqBDUwPFeCe2cv4tsxJE4VBjGa8T179xfSIOADX0TqkKSW77uuK8G8W2yJrU49Oayf
  76.137 +uyOilPSxzqgyuGboO2KsFTjdRjayxAfM3J9qmkjZmWNB7cUNlt3N3RolFmCOc9a0IlAqtZ4S
  76.138 +JEHYd6vxr8vAqIK7KvZBv2Y+anyMJExwc00Wzu/ArQtbHYmWx+NdcY2MpTOWvLeNWbYnzY6k
  76.139 +Vzc9gwvDK2SOld/dWgMjYHNZGrWR8oJHgdyabkugRV9xbG5SO2Cqe3Ap/mbvmrDlc2y7ckkU
  76.140 +QXkkkgUYArjnT6nXGdjdR6GbNV4mJUY/OpMNiuZo2uSxyHNTrIexxx2qkSV6UscjZABo5bgf
  76.141 +/9TtI6mHSoI6mWvAR7ZX1Di3fkdK8N8bsq6xIo/ib9BXsviS6FvZu2R0rwjxBObnUppCc5ba
  76.142 +P61EviNaZTtFLTeYRyelaEUSiXIx6VntIIpViXtxVpZtq/X1qXdmqNe2LFhuNbNpjgVzVrcB
  76.143 +ep5rTtLo5BJPNZ3sy7XOmtwirzUzyLs4rHiucr97ipDOzNwa1VRkchNPtL1Rv1XyznHtUxmV
  76.144 +WyTzWXq92FQ8j060c5aiYOqYLnHSqlqNsgNPuJNxOTkmi3Ulhk0m3YtI2bXkVa2+o/Cqtmdq
  76.145 +9PxqySMZ7fzrmlubojxu/pTQAD1p5b/CosnJwPxpK4z/1exQmp1IqnE/SrCvxXz6Z7jMLx1H
  76.146 +/wASWaQHoK8Pc7rz/dya9v8AiBKF8NXBzjjFeIwhfOnkOOO9TLc0g9CmwzdnnkVNgk/jUNoN
  76.147 +87E8c9auxxHHSiWhpEbFndmr9u5GD3qusR3Vaii+tZ+pqkaFvNjGcmrKTgDPSs5cqMCq11dF
  76.148 +VKgmhWKsT6hqaxBgrZPesG4vnnk65FUr+d2lKg55qFSV6da0UETzGjGfWrcLKB14rOtgx5JN
  76.149 +W0RicD86mSKTNSGXgBetTgsxAz9aoRypCP7x7e5qe3uM/ePJ7CsZRNEzRVAF6fjTGTnjmpYm
  76.150 +DLTZg2Rg4qNUWf/W6JHx3qZZjjrxiqQbFP3+9fN3Pfsc/wDE24K6AUBx5kig/SvIoGJiuAvV
  76.151 +nxXpHxNn32QhGflUvXn3h5BJOysP4i5p30bKSGxwmOYRDhjgVpsixx7j0qu4zqwyPugkfWrG
  76.152 +oONyxKeBUNmsUNgG5s44q3wo6CqsDcZzinyzLggmla5omhJJOoHFZ9y3Uk9BxUs86IpLHAAr
  76.153 +ndT1JpMpHnbnGauEHJilJInmCZ3e/wCdRqylsZrJM07NuGcDpSRyXB/hNdXs9NzH2mux0kLI
  76.154 +oySOKfJexRjGevYVjWlteTn5iQPat7StJRHDyfM/oawkoo1TbCCCa4PmSDYnYY61ZjULIAOA
  76.155 +DV2VQiYHSqPPnAqcHNZXuaJm9ajKA06aIls4pLBSIlL8mpZn25wv1zWDNEz/19k57UHpTCRn
  76.156 +INKDxXzLPoDlPGWnzXJZ0GV2YxXnujsbW9mVuGDEYr2yRFkXDqCK8m8cacdO8SO6LiOdd6/W
  76.157 +hdUMz5pMXhmXjisfV9XEV0UJ5xmtWDEqYJya5nxNZFLlZTnBPNdFGKcrMic5JaCy+I9h256U
  76.158 +7T9da7uBGW4Nc9qVsceYvc9Ki0QSLqUQ2nBODx2rt9jDkbRye3qKaTO9khkmTkkL9apyWsSs
  76.159 +c4x3rVeRY4gCR0rFkdri9EScjvXnxbZ6d0WktY3C4QY61cgsI8E7Rk1LAgXBI+gq9EgCDPPr
  76.160 +WUpspJDLeBETCgZqWa4itLcuTjHX3pTIqjArFug99dCMZMadTSir7jbJhetOTKfujgVPp4eW
  76.161 +YNtOKqhAXEKYVV9q3dOhVEAXn3pzdkOLNK2JCAdTUN1nH9asRrtT+dVrueONfmGR6VztMtM/
  76.162 +/9DSJJ708Goc/WnIfqa+YPoSbNcp8TLD7RoovUXL2zZP+6etdTk1DeQpdW0ltKMrKpUg+9NM
  76.163 +DxSybayt24pPFMCvZBh3NEsT2lzLavkNDIUP4HFQa1eZstvUrzWsG1JA1c51oH+6QWogg23a
  76.164 +BUIGQWY+lXtNInkXIyO9S6kUUBYwAT1NdEp62M3BbkNzftNI5Xp0AFWNFRI/nk5kbtWci7eg
  76.165 +q5p5fzC+0s2MLUySSsVFu5oX2oLBIqD5mPYVp2t4Bbb5PTOKzLTT2aVpZBukbnntWnFYPLgO
  76.166 +DtzyKwko7I2TZQ33N9dbI/lTPJ9q0JFEMQiiABI5atKGzjhTai4qpfQZX5TyanQTlcohCGGD
  76.167 +kmtnT4iFGSwPrVCyhKncVzjmtCO5RUIIzxxipkrjUi7JKIflfPI6isbUJ1fnJHbHvTb6/feU
  76.168 +xnHQeorHeeSVmCjIPYjpSUGaJn//0bin2p6t+dQhsHrShua+ZZ9CifdS96hDc+lSg8UgPHvG
  76.169 +m1fE+o7RjM+f0Fc3qDK0RBrqviLD5Xii7wOJNsn5qP8ACuPvhlh6dK6KZTWg3S/kbGeO1X5I
  76.170 +RKo4qDToCVGMd6sXHmwkYGRkVUnqSkJBppYjPrzmtmxsY4woVRnFV9NSefKopzkAk+lb9taM
  76.171 +siHOcDmuec3extGKSuRw24jTJFW7cKMDGc+1OlgLFQBgVsaRo81xhsBY+xPepuRJmPcfKOOa
  76.172 +oTK7tnHetrxBCttdvCg6Y/CseWVlKJtJPei9zMhOY2JHBwCagnuAin1bgU+dmIJAOFBBP1qJ
  76.173 +oVAUyNySWApK5ojPuA08jPn8qmsrdcElhuAzzVzylgBJAKBc/Sq2ozxBJWBC7QCrDsCBn+dX
  76.174 +zN6F3P/SkDDr0pwY9hUOT704N7181Y+gJkbnrU27iqqNzzgVKG7UWGcT8TLAvNDegZDR+WT6
  76.175 +EHI/Qn8q86nULG2R8wz1r3a8t4by3a3nUMjdQa4jV/AAmd2tJ9oPY9q0pzUdGWmranLaXasl
  76.176 +ksjDBYZpfLMjMrDjI211DaFfQ26QvFllA5HSmJ4bvXO4RgZOaL3Zm2yjp5CnKKFHetaAKOnX
  76.177 +1qWHw9eox3RZ+lbthoLBQ0pHuKzlEpSZS0mxa4mXIwOue1dbbwrBFtQY4os7WG3ACIBj0q1g
  76.178 +EVDQXPNfFMrRaxKZCQGORu7msF5y0hYsCCMACup8e6ez3RuXXK4wDXI+QSX+cDuahNLQdhJ5
  76.179 +2ZZcOqqxyP8AdFQXTlo/MaUbVjIyf4R61Wv7SXaXjO4ntngCqb2d5JCsbs2SRx7VtFJ63GWJ
  76.180 +dYiQeXvLEkMQKy3uZJyVijLAhQwP41YGj7huLkkDJI6GtDTYI0jffGVYAA5HXn/CteaC2CzP
  76.181 +/9OMEU4njrUYJJFKDjNfOn0BMh7g1ItQZIH0qZSduamwCk09WycUztSp60rDJ19CKlA9qgi5
  76.182 +IqRSeaQycYp68dqiWpE5pASD9KetNHFPJIGaAOf8X2/nWm/H3Oa84uky+3aRk5x/ePvXreqR
  76.183 +LLaOHyRg8fhXmN8oW4lAHCsQKlx1uMy5MgqPlIXkjtQCy73bqeckcD6VIwH2uNP4cFsetVpG
  76.184 +aSWBWPyyOWYdjgU7FIkgbDEhV2rgqDUV5GXRQGIORu98cYqcqMFccZP8qjmz5AYEg7s8exFC
  76.185 +3Gf/2Q==
  76.186 +--------------6AB84297773D6C43C8ED3ABC--
  76.187 +
  76.188 +--------------EC543696A16813A5DAA28AB1
  76.189 +Content-Type: image/jpeg; x-mac-type="0"; x-mac-creator="0";
  76.190 + name="meow.jpeg"
  76.191 +Content-Transfer-Encoding: base64
  76.192 +Content-Disposition: attachment;
  76.193 + filename="meow.jpeg"
  76.194 +
  76.195 +/9j/4AAQSkZJRgABAQAASABIAAD/4QCMRXhpZgAATU0AKgAAAAgABQESAAMAAAABAAEAAAEa
  76.196 +AAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAAAAAAAABI
  76.197 +AAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAAJCgAwAEAAAAAQAAAMwAAAAA
  76.198 +/+0AOFBob3Rvc2hvcCAzLjAAOEJJTQQEAAAAAAAAOEJJTQQlAAAAAAAQ1B2M2Y8AsgTpgAmY
  76.199 +7PhCfv/AABEIAMwAkAMBIgACEQEDEQH/xAAfAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJ
  76.200 +Cgv/xAC1EAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYTUWEHInEUMoGRoQgjQrHBFVLR
  76.201 +8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2
  76.202 +d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX
  76.203 +2Nna4eLj5OXm5+jp6vHy8/T19vf4+fr/xAAfAQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJ
  76.204 +Cgv/xAC1EQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS
  76.205 +8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1
  76.206 +dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV
  76.207 +1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkM
  76.208 +EQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4e
  76.209 +FBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/
  76.210 +3QAEAAn/2gAMAwEAAhEDEQA/AO5GD7U7Ge9AH5UuM9K8JpntgvGKeMUij8acAcdKEAdulKfQ
  76.211 +0tQXc6wQtI38IzSYEWpX0NlB5krAZ6DPJrCXxAJJCFbj2rhvF+sXN/qTgSEInAGelZlneyxO
  76.212 +Mkn8aycnfQ6I0tD2Gx1ESAZPP1rUicMMgivLtJ1obgC4rsdJ1MOq/MOapSuRKnY6Uc04c1FB
  76.213 +Ksigg5qYdKu5mJyO1AGRTgPWimIQUU4DpQRRqAhpMc0/FGOOlAH/0O6B4pw60gNKuOleEe2P
  76.214 +HWn9uaaM+tOU0gHfhWH4oc/ZmQelbg+tYviOPfHz6UPYa3PJL1d1656ZPNRMgxxWhqaf6c4C
  76.215 +8etRFBjmsEjuT0M8M8ThlYgjpW/oWsFCqlufQmsW4jwCSKoNKY23DtTfkVZSR7PoeqK6rl+K
  76.216 +6WCRXjBBzXivhvWmWRY3PPQV6boGoiVACwwferT01OWrTaOixQKarAinDrVmAoXmlI9BSg0o
  76.217 +9qoVxMdsUU6gjNAH/9HuScKTngV5rrPjq7g1+WBYSltG20Y5J9zXpTqChXsRivJPGWl+Vqjy
  76.218 +hflzzXzlRtI+ioRjKVpHd+H/ABXZagi7pFVvrXSwyJIoZGBB968Cj3QvviJVh3FdBo/im/sy
  76.219 +oZ/MUcVKq9zWeF/lPY6ztaTfb9M1haR4xtp0Hnjaxrfnube6s90cqnIrVTUkcrhKL1R5dr6+
  76.220 +Xetxyapp0LGtLxYqLe5H5CsuM7sCskzrjsV7wsxPvWLfArk9P610jRDbyMn0rG1SAAHOCcdK
  76.221 +3irjUrGTb3TRygqeRXb6L4hnt41OC2a87nbZJ0/CtzQrvem09j60VabSuaKSnoz0eLxtNCR5
  76.222 +i4B6k81rWHjqxl+TLLnu/f8ACvM7pfMUDNVIFYPn0rkdWSB4aLPfbDVIblA4bAPTPetOM5XO
  76.223 +K8M0rVryzkDpKzfU5rtdD8bxyERXZbf0GMn+VbU6ye5y1MPKOx6CtO+tULG/iuI1dGGCPWrq
  76.224 +nPJrZHM1Y//S7oVzfjHTUuLQvjkV0SdKjvohLbsCM14EldHuRdnc8QvYjBMyMDwagVwCMmun
  76.225 +8Z2BjZpUXHpXETzFTgmua2tj04T5lc1pL0ImAw49KjTxDqEX7qG4dQeOvSueuLkg/e4pqyk4
  76.226 +J4JNX7MiczrIbiS4y8kjSH1JqzCwHesvTHDQ4XoBWhDyfepjuSi+hJWs/UYsj3FaEBULioNS
  76.227 +TdCwHXGa6oGcjgtXZWuSEzV/w7bSSuSTsUdWqndwFroknoTVqy1NYXFu+EUVrNPlsgpvXU6h
  76.228 +41QDaSwquygSHAOKm0+X7RbEfwjoTTXHzeleZUWp3Rd0SRYA4qTCnOcj6VAje9OMm0VhrcZu
  76.229 +aNq93ZOoiuHKj+Aniu70DxK07eXMkaN6g5/U15bbuFOeenrWjbXIGOSfxraFWUWc9SjGR//T
  76.230 +7aM1N2IqBDUwPFeCe2cv4tsxJE4VBjGa8T179xfSIOADX0TqkKSW77uuK8G8W2yJrU49Oayf
  76.231 +uyOilPSxzqgyuGboO2KsFTjdRjayxAfM3J9qmkjZmWNB7cUNlt3N3RolFmCOc9a0IlAqtZ4S
  76.232 +JEHYd6vxr8vAqIK7KvZBv2Y+anyMJExwc00Wzu/ArQtbHYmWx+NdcY2MpTOWvLeNWbYnzY6k
  76.233 +Vzc9gwvDK2SOld/dWgMjYHNZGrWR8oJHgdyabkugRV9xbG5SO2Cqe3Ap/mbvmrDlc2y7ckkU
  76.234 +QXkkkgUYArjnT6nXGdjdR6GbNV4mJUY/OpMNiuZo2uSxyHNTrIexxx2qkSV6UscjZABo5bgf
  76.235 +/9TtI6mHSoI6mWvAR7ZX1Di3fkdK8N8bsq6xIo/ib9BXsviS6FvZu2R0rwjxBObnUppCc5ba
  76.236 +P61EviNaZTtFLTeYRyelaEUSiXIx6VntIIpViXtxVpZtq/X1qXdmqNe2LFhuNbNpjgVzVrcB
  76.237 +ep5rTtLo5BJPNZ3sy7XOmtwirzUzyLs4rHiucr97ipDOzNwa1VRkchNPtL1Rv1XyznHtUxmV
  76.238 +WyTzWXq92FQ8j060c5aiYOqYLnHSqlqNsgNPuJNxOTkmi3Ulhk0m3YtI2bXkVa2+o/Cqtmdq
  76.239 +9PxqySMZ7fzrmlubojxu/pTQAD1p5b/CosnJwPxpK4z/1exQmp1IqnE/SrCvxXz6Z7jMLx1H
  76.240 +/wASWaQHoK8Pc7rz/dya9v8AiBKF8NXBzjjFeIwhfOnkOOO9TLc0g9CmwzdnnkVNgk/jUNoN
  76.241 +87E8c9auxxHHSiWhpEbFndmr9u5GD3qusR3Vaii+tZ+pqkaFvNjGcmrKTgDPSs5cqMCq11dF
  76.242 +VKgmhWKsT6hqaxBgrZPesG4vnnk65FUr+d2lKg55qFSV6da0UETzGjGfWrcLKB14rOtgx5JN
  76.243 +W0RicD86mSKTNSGXgBetTgsxAz9aoRypCP7x7e5qe3uM/ePJ7CsZRNEzRVAF6fjTGTnjmpYm
  76.244 +DLTZg2Rg4qNUWf/W6JHx3qZZjjrxiqQbFP3+9fN3Pfsc/wDE24K6AUBx5kig/SvIoGJiuAvV
  76.245 +nxXpHxNn32QhGflUvXn3h5BJOysP4i5p30bKSGxwmOYRDhjgVpsixx7j0qu4zqwyPugkfWrG
  76.246 +oONyxKeBUNmsUNgG5s44q3wo6CqsDcZzinyzLggmla5omhJJOoHFZ9y3Uk9BxUs86IpLHAAr
  76.247 +ndT1JpMpHnbnGauEHJilJInmCZ3e/wCdRqylsZrJM07NuGcDpSRyXB/hNdXs9NzH2mux0kLI
  76.248 +oySOKfJexRjGevYVjWlteTn5iQPat7StJRHDyfM/oawkoo1TbCCCa4PmSDYnYY61ZjULIAOA
  76.249 +DV2VQiYHSqPPnAqcHNZXuaJm9ajKA06aIls4pLBSIlL8mpZn25wv1zWDNEz/19k57UHpTCRn
  76.250 +INKDxXzLPoDlPGWnzXJZ0GV2YxXnujsbW9mVuGDEYr2yRFkXDqCK8m8cacdO8SO6LiOdd6/W
  76.251 +hdUMz5pMXhmXjisfV9XEV0UJ5xmtWDEqYJya5nxNZFLlZTnBPNdFGKcrMic5JaCy+I9h256U
  76.252 +7T9da7uBGW4Nc9qVsceYvc9Ki0QSLqUQ2nBODx2rt9jDkbRye3qKaTO9khkmTkkL9apyWsSs
  76.253 +c4x3rVeRY4gCR0rFkdri9EScjvXnxbZ6d0WktY3C4QY61cgsI8E7Rk1LAgXBI+gq9EgCDPPr
  76.254 +WUpspJDLeBETCgZqWa4itLcuTjHX3pTIqjArFug99dCMZMadTSir7jbJhetOTKfujgVPp4eW
  76.255 +YNtOKqhAXEKYVV9q3dOhVEAXn3pzdkOLNK2JCAdTUN1nH9asRrtT+dVrueONfmGR6VztMtM/
  76.256 +/9DSJJ708Goc/WnIfqa+YPoSbNcp8TLD7RoovUXL2zZP+6etdTk1DeQpdW0ltKMrKpUg+9NM
  76.257 +DxSybayt24pPFMCvZBh3NEsT2lzLavkNDIUP4HFQa1eZstvUrzWsG1JA1c51oH+6QWogg23a
  76.258 +BUIGQWY+lXtNInkXIyO9S6kUUBYwAT1NdEp62M3BbkNzftNI5Xp0AFWNFRI/nk5kbtWci7eg
  76.259 +q5p5fzC+0s2MLUySSsVFu5oX2oLBIqD5mPYVp2t4Bbb5PTOKzLTT2aVpZBukbnntWnFYPLgO
  76.260 +DtzyKwko7I2TZQ33N9dbI/lTPJ9q0JFEMQiiABI5atKGzjhTai4qpfQZX5TyanQTlcohCGGD
  76.261 +kmtnT4iFGSwPrVCyhKncVzjmtCO5RUIIzxxipkrjUi7JKIflfPI6isbUJ1fnJHbHvTb6/feU
  76.262 +xnHQeorHeeSVmCjIPYjpSUGaJn//0bin2p6t+dQhsHrShua+ZZ9CifdS96hDc+lSg8UgPHvG
  76.263 +m1fE+o7RjM+f0Fc3qDK0RBrqviLD5Xii7wOJNsn5qP8ACuPvhlh6dK6KZTWg3S/kbGeO1X5I
  76.264 +RKo4qDToCVGMd6sXHmwkYGRkVUnqSkJBppYjPrzmtmxsY4woVRnFV9NSefKopzkAk+lb9taM
  76.265 +siHOcDmuec3extGKSuRw24jTJFW7cKMDGc+1OlgLFQBgVsaRo81xhsBY+xPepuRJmPcfKOOa
  76.266 +oTK7tnHetrxBCttdvCg6Y/CseWVlKJtJPei9zMhOY2JHBwCagnuAin1bgU+dmIJAOFBBP1qJ
  76.267 +oVAUyNySWApK5ojPuA08jPn8qmsrdcElhuAzzVzylgBJAKBc/Sq2ozxBJWBC7QCrDsCBn+dX
  76.268 +zN6F3P/SkDDr0pwY9hUOT704N7181Y+gJkbnrU27iqqNzzgVKG7UWGcT8TLAvNDegZDR+WT6
  76.269 +EHI/Qn8q86nULG2R8wz1r3a8t4by3a3nUMjdQa4jV/AAmd2tJ9oPY9q0pzUdGWmranLaXasl
  76.270 +ksjDBYZpfLMjMrDjI211DaFfQ26QvFllA5HSmJ4bvXO4RgZOaL3Zm2yjp5CnKKFHetaAKOnX
  76.271 +1qWHw9eox3RZ+lbthoLBQ0pHuKzlEpSZS0mxa4mXIwOue1dbbwrBFtQY4os7WG3ACIBj0q1g
  76.272 +EVDQXPNfFMrRaxKZCQGORu7msF5y0hYsCCMACup8e6ez3RuXXK4wDXI+QSX+cDuahNLQdhJ5
  76.273 +2ZZcOqqxyP8AdFQXTlo/MaUbVjIyf4R61Wv7SXaXjO4ntngCqb2d5JCsbs2SRx7VtFJ63GWJ
  76.274 +dYiQeXvLEkMQKy3uZJyVijLAhQwP41YGj7huLkkDJI6GtDTYI0jffGVYAA5HXn/CteaC2CzP
  76.275 +/9OMEU4njrUYJJFKDjNfOn0BMh7g1ItQZIH0qZSduamwCk09WycUztSp60rDJ19CKlA9qgi5
  76.276 +IqRSeaQycYp68dqiWpE5pASD9KetNHFPJIGaAOf8X2/nWm/H3Oa84uky+3aRk5x/ePvXreqR
  76.277 +LLaOHyRg8fhXmN8oW4lAHCsQKlx1uMy5MgqPlIXkjtQCy73bqeckcD6VIwH2uNP4cFsetVpG
  76.278 +aSWBWPyyOWYdjgU7FIkgbDEhV2rgqDUV5GXRQGIORu98cYqcqMFccZP8qjmz5AYEg7s8exFC
  76.279 +3Gf/2Q==
  76.280 +--------------EC543696A16813A5DAA28AB1--
    77.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    77.2 +++ b/test/test_mails/htmlonlycatwtextatt.eml	Mon Jun 08 15:01:34 2020 +0200
    77.3 @@ -0,0 +1,161 @@
    77.4 +From: Krista Bennett <krista@darthmama.org>
    77.5 +To: Krista Bennett <krista@pep-project.org>
    77.6 +Message-ID: <94ddfc77-1493-83c2-a5d2-f07d0418a958@darthmama.org>
    77.7 +Date: Sun, 19 Apr 2020 21:32:54 +0200
    77.8 +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:68.0)
    77.9 + Gecko/20100101 Thunderbird/68.6.0
   77.10 +MIME-Version: 1.0
   77.11 +Content-Type: multipart/mixed;
   77.12 + boundary="------------21C7903EAEF51008232F5B50"
   77.13 +Content-Language: en-GB
   77.14 +
   77.15 +This is a multi-part message in MIME format.
   77.16 +--------------21C7903EAEF51008232F5B50
   77.17 +Content-Type: multipart/related;
   77.18 + boundary="------------6E81B545B2A1BC54B46F88E5"
   77.19 +
   77.20 +
   77.21 +--------------6E81B545B2A1BC54B46F88E5
   77.22 +Content-Type: text/html; charset=utf-8
   77.23 +Content-Transfer-Encoding: 8bit
   77.24 +
   77.25 +<html>
   77.26 +  <head>
   77.27 +    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
   77.28 +  </head>
   77.29 +  <body>
   77.30 +    <table width="100%" cellspacing="2" cellpadding="2" border="1"
   77.31 +      bgcolor="pink">
   77.32 +      <tbody>
   77.33 +        <tr>
   77.34 +          <td valign="top" bgcolor="pink"><img moz-do-not-send="false"
   77.35 +              src="cid:part1.21156198.7E41C8BF@darthmama.org" alt="Tiny
   77.36 +              Canth cat" width="144" height="204"><br>
   77.37 +          </td>
   77.38 +          <td valign="top"><br>
   77.39 +          </td>
   77.40 +        </tr>
   77.41 +        <tr>
   77.42 +          <td valign="top"><br>
   77.43 +          </td>
   77.44 +          <td valign="top"><br>
   77.45 +          </td>
   77.46 +        </tr>
   77.47 +        <tr>
   77.48 +          <td valign="top"><br>
   77.49 +          </td>
   77.50 +          <td valign="top"><br>
   77.51 +          </td>
   77.52 +        </tr>
   77.53 +      </tbody>
   77.54 +    </table>
   77.55 +    <p><br>
   77.56 +    </p>
   77.57 +  </body>
   77.58 +</html>
   77.59 +
   77.60 +--------------6E81B545B2A1BC54B46F88E5
   77.61 +Content-Type: image/jpeg;
   77.62 + name="meow.jpeg"
   77.63 +Content-Transfer-Encoding: base64
   77.64 +Content-ID: <part1.21156198.7E41C8BF@darthmama.org>
   77.65 +Content-Disposition: inline;
   77.66 + filename="meow.jpeg"
   77.67 +
   77.68 +/9j/4AAQSkZJRgABAQAASABIAAD/4QCMRXhpZgAATU0AKgAAAAgABQESAAMAAAABAAEAAAEa
   77.69 +AAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAAAAAAAABI
   77.70 +AAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAAJCgAwAEAAAAAQAAAMwAAAAA
   77.71 +/+0AOFBob3Rvc2hvcCAzLjAAOEJJTQQEAAAAAAAAOEJJTQQlAAAAAAAQ1B2M2Y8AsgTpgAmY
   77.72 +7PhCfv/AABEIAMwAkAMBIgACEQEDEQH/xAAfAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJ
   77.73 +Cgv/xAC1EAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYTUWEHInEUMoGRoQgjQrHBFVLR
   77.74 +8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2
   77.75 +d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX
   77.76 +2Nna4eLj5OXm5+jp6vHy8/T19vf4+fr/xAAfAQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJ
   77.77 +Cgv/xAC1EQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS
   77.78 +8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1
   77.79 +dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV
   77.80 +1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkM
   77.81 +EQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4e
   77.82 +FBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/
   77.83 +3QAEAAn/2gAMAwEAAhEDEQA/AO5GD7U7Ge9AH5UuM9K8JpntgvGKeMUij8acAcdKEAdulKfQ
   77.84 +0tQXc6wQtI38IzSYEWpX0NlB5krAZ6DPJrCXxAJJCFbj2rhvF+sXN/qTgSEInAGelZlneyxO
   77.85 +Mkn8aycnfQ6I0tD2Gx1ESAZPP1rUicMMgivLtJ1obgC4rsdJ1MOq/MOapSuRKnY6Uc04c1FB
   77.86 +Ksigg5qYdKu5mJyO1AGRTgPWimIQUU4DpQRRqAhpMc0/FGOOlAH/0O6B4pw60gNKuOleEe2P
   77.87 +HWn9uaaM+tOU0gHfhWH4oc/ZmQelbg+tYviOPfHz6UPYa3PJL1d1656ZPNRMgxxWhqaf6c4C
   77.88 +8etRFBjmsEjuT0M8M8ThlYgjpW/oWsFCqlufQmsW4jwCSKoNKY23DtTfkVZSR7PoeqK6rl+K
   77.89 +6WCRXjBBzXivhvWmWRY3PPQV6boGoiVACwwferT01OWrTaOixQKarAinDrVmAoXmlI9BSg0o
   77.90 +9qoVxMdsUU6gjNAH/9HuScKTngV5rrPjq7g1+WBYSltG20Y5J9zXpTqChXsRivJPGWl+Vqjy
   77.91 +hflzzXzlRtI+ioRjKVpHd+H/ABXZagi7pFVvrXSwyJIoZGBB968Cj3QvviJVh3FdBo/im/sy
   77.92 +oZ/MUcVKq9zWeF/lPY6ztaTfb9M1haR4xtp0Hnjaxrfnube6s90cqnIrVTUkcrhKL1R5dr6+
   77.93 +Xetxyapp0LGtLxYqLe5H5CsuM7sCskzrjsV7wsxPvWLfArk9P610jRDbyMn0rG1SAAHOCcdK
   77.94 +3irjUrGTb3TRygqeRXb6L4hnt41OC2a87nbZJ0/CtzQrvem09j60VabSuaKSnoz0eLxtNCR5
   77.95 +i4B6k81rWHjqxl+TLLnu/f8ACvM7pfMUDNVIFYPn0rkdWSB4aLPfbDVIblA4bAPTPetOM5XO
   77.96 +K8M0rVryzkDpKzfU5rtdD8bxyERXZbf0GMn+VbU6ye5y1MPKOx6CtO+tULG/iuI1dGGCPWrq
   77.97 +nPJrZHM1Y//S7oVzfjHTUuLQvjkV0SdKjvohLbsCM14EldHuRdnc8QvYjBMyMDwagVwCMmun
   77.98 +8Z2BjZpUXHpXETzFTgmua2tj04T5lc1pL0ImAw49KjTxDqEX7qG4dQeOvSueuLkg/e4pqyk4
   77.99 +J4JNX7MiczrIbiS4y8kjSH1JqzCwHesvTHDQ4XoBWhDyfepjuSi+hJWs/UYsj3FaEBULioNS
  77.100 +TdCwHXGa6oGcjgtXZWuSEzV/w7bSSuSTsUdWqndwFroknoTVqy1NYXFu+EUVrNPlsgpvXU6h
  77.101 +41QDaSwquygSHAOKm0+X7RbEfwjoTTXHzeleZUWp3Rd0SRYA4qTCnOcj6VAje9OMm0VhrcZu
  77.102 +aNq93ZOoiuHKj+Aniu70DxK07eXMkaN6g5/U15bbuFOeenrWjbXIGOSfxraFWUWc9SjGR//T
  77.103 +7aM1N2IqBDUwPFeCe2cv4tsxJE4VBjGa8T179xfSIOADX0TqkKSW77uuK8G8W2yJrU49Oayf
  77.104 +uyOilPSxzqgyuGboO2KsFTjdRjayxAfM3J9qmkjZmWNB7cUNlt3N3RolFmCOc9a0IlAqtZ4S
  77.105 +JEHYd6vxr8vAqIK7KvZBv2Y+anyMJExwc00Wzu/ArQtbHYmWx+NdcY2MpTOWvLeNWbYnzY6k
  77.106 +Vzc9gwvDK2SOld/dWgMjYHNZGrWR8oJHgdyabkugRV9xbG5SO2Cqe3Ap/mbvmrDlc2y7ckkU
  77.107 +QXkkkgUYArjnT6nXGdjdR6GbNV4mJUY/OpMNiuZo2uSxyHNTrIexxx2qkSV6UscjZABo5bgf
  77.108 +/9TtI6mHSoI6mWvAR7ZX1Di3fkdK8N8bsq6xIo/ib9BXsviS6FvZu2R0rwjxBObnUppCc5ba
  77.109 +P61EviNaZTtFLTeYRyelaEUSiXIx6VntIIpViXtxVpZtq/X1qXdmqNe2LFhuNbNpjgVzVrcB
  77.110 +ep5rTtLo5BJPNZ3sy7XOmtwirzUzyLs4rHiucr97ipDOzNwa1VRkchNPtL1Rv1XyznHtUxmV
  77.111 +WyTzWXq92FQ8j060c5aiYOqYLnHSqlqNsgNPuJNxOTkmi3Ulhk0m3YtI2bXkVa2+o/Cqtmdq
  77.112 +9PxqySMZ7fzrmlubojxu/pTQAD1p5b/CosnJwPxpK4z/1exQmp1IqnE/SrCvxXz6Z7jMLx1H
  77.113 +/wASWaQHoK8Pc7rz/dya9v8AiBKF8NXBzjjFeIwhfOnkOOO9TLc0g9CmwzdnnkVNgk/jUNoN
  77.114 +87E8c9auxxHHSiWhpEbFndmr9u5GD3qusR3Vaii+tZ+pqkaFvNjGcmrKTgDPSs5cqMCq11dF
  77.115 +VKgmhWKsT6hqaxBgrZPesG4vnnk65FUr+d2lKg55qFSV6da0UETzGjGfWrcLKB14rOtgx5JN
  77.116 +W0RicD86mSKTNSGXgBetTgsxAz9aoRypCP7x7e5qe3uM/ePJ7CsZRNEzRVAF6fjTGTnjmpYm
  77.117 +DLTZg2Rg4qNUWf/W6JHx3qZZjjrxiqQbFP3+9fN3Pfsc/wDE24K6AUBx5kig/SvIoGJiuAvV
  77.118 +nxXpHxNn32QhGflUvXn3h5BJOysP4i5p30bKSGxwmOYRDhjgVpsixx7j0qu4zqwyPugkfWrG
  77.119 +oONyxKeBUNmsUNgG5s44q3wo6CqsDcZzinyzLggmla5omhJJOoHFZ9y3Uk9BxUs86IpLHAAr
  77.120 +ndT1JpMpHnbnGauEHJilJInmCZ3e/wCdRqylsZrJM07NuGcDpSRyXB/hNdXs9NzH2mux0kLI
  77.121 +oySOKfJexRjGevYVjWlteTn5iQPat7StJRHDyfM/oawkoo1TbCCCa4PmSDYnYY61ZjULIAOA
  77.122 +DV2VQiYHSqPPnAqcHNZXuaJm9ajKA06aIls4pLBSIlL8mpZn25wv1zWDNEz/19k57UHpTCRn
  77.123 +INKDxXzLPoDlPGWnzXJZ0GV2YxXnujsbW9mVuGDEYr2yRFkXDqCK8m8cacdO8SO6LiOdd6/W
  77.124 +hdUMz5pMXhmXjisfV9XEV0UJ5xmtWDEqYJya5nxNZFLlZTnBPNdFGKcrMic5JaCy+I9h256U
  77.125 +7T9da7uBGW4Nc9qVsceYvc9Ki0QSLqUQ2nBODx2rt9jDkbRye3qKaTO9khkmTkkL9apyWsSs
  77.126 +c4x3rVeRY4gCR0rFkdri9EScjvXnxbZ6d0WktY3C4QY61cgsI8E7Rk1LAgXBI+gq9EgCDPPr
  77.127 +WUpspJDLeBETCgZqWa4itLcuTjHX3pTIqjArFug99dCMZMadTSir7jbJhetOTKfujgVPp4eW
  77.128 +YNtOKqhAXEKYVV9q3dOhVEAXn3pzdkOLNK2JCAdTUN1nH9asRrtT+dVrueONfmGR6VztMtM/
  77.129 +/9DSJJ708Goc/WnIfqa+YPoSbNcp8TLD7RoovUXL2zZP+6etdTk1DeQpdW0ltKMrKpUg+9NM
  77.130 +DxSybayt24pPFMCvZBh3NEsT2lzLavkNDIUP4HFQa1eZstvUrzWsG1JA1c51oH+6QWogg23a
  77.131 +BUIGQWY+lXtNInkXIyO9S6kUUBYwAT1NdEp62M3BbkNzftNI5Xp0AFWNFRI/nk5kbtWci7eg
  77.132 +q5p5fzC+0s2MLUySSsVFu5oX2oLBIqD5mPYVp2t4Bbb5PTOKzLTT2aVpZBukbnntWnFYPLgO
  77.133 +DtzyKwko7I2TZQ33N9dbI/lTPJ9q0JFEMQiiABI5atKGzjhTai4qpfQZX5TyanQTlcohCGGD
  77.134 +kmtnT4iFGSwPrVCyhKncVzjmtCO5RUIIzxxipkrjUi7JKIflfPI6isbUJ1fnJHbHvTb6/feU
  77.135 +xnHQeorHeeSVmCjIPYjpSUGaJn//0bin2p6t+dQhsHrShua+ZZ9CifdS96hDc+lSg8UgPHvG
  77.136 +m1fE+o7RjM+f0Fc3qDK0RBrqviLD5Xii7wOJNsn5qP8ACuPvhlh6dK6KZTWg3S/kbGeO1X5I
  77.137 +RKo4qDToCVGMd6sXHmwkYGRkVUnqSkJBppYjPrzmtmxsY4woVRnFV9NSefKopzkAk+lb9taM
  77.138 +siHOcDmuec3extGKSuRw24jTJFW7cKMDGc+1OlgLFQBgVsaRo81xhsBY+xPepuRJmPcfKOOa
  77.139 +oTK7tnHetrxBCttdvCg6Y/CseWVlKJtJPei9zMhOY2JHBwCagnuAin1bgU+dmIJAOFBBP1qJ
  77.140 +oVAUyNySWApK5ojPuA08jPn8qmsrdcElhuAzzVzylgBJAKBc/Sq2ozxBJWBC7QCrDsCBn+dX
  77.141 +zN6F3P/SkDDr0pwY9hUOT704N7181Y+gJkbnrU27iqqNzzgVKG7UWGcT8TLAvNDegZDR+WT6
  77.142 +EHI/Qn8q86nULG2R8wz1r3a8t4by3a3nUMjdQa4jV/AAmd2tJ9oPY9q0pzUdGWmranLaXasl
  77.143 +ksjDBYZpfLMjMrDjI211DaFfQ26QvFllA5HSmJ4bvXO4RgZOaL3Zm2yjp5CnKKFHetaAKOnX
  77.144 +1qWHw9eox3RZ+lbthoLBQ0pHuKzlEpSZS0mxa4mXIwOue1dbbwrBFtQY4os7WG3ACIBj0q1g
  77.145 +EVDQXPNfFMrRaxKZCQGORu7msF5y0hYsCCMACup8e6ez3RuXXK4wDXI+QSX+cDuahNLQdhJ5
  77.146 +2ZZcOqqxyP8AdFQXTlo/MaUbVjIyf4R61Wv7SXaXjO4ntngCqb2d5JCsbs2SRx7VtFJ63GWJ
  77.147 +dYiQeXvLEkMQKy3uZJyVijLAhQwP41YGj7huLkkDJI6GtDTYI0jffGVYAA5HXn/CteaC2CzP
  77.148 +/9OMEU4njrUYJJFKDjNfOn0BMh7g1ItQZIH0qZSduamwCk09WycUztSp60rDJ19CKlA9qgi5
  77.149 +IqRSeaQycYp68dqiWpE5pASD9KetNHFPJIGaAOf8X2/nWm/H3Oa84uky+3aRk5x/ePvXreqR
  77.150 +LLaOHyRg8fhXmN8oW4lAHCsQKlx1uMy5MgqPlIXkjtQCy73bqeckcD6VIwH2uNP4cFsetVpG
  77.151 +aSWBWPyyOWYdjgU7FIkgbDEhV2rgqDUV5GXRQGIORu98cYqcqMFccZP8qjmz5AYEg7s8exFC
  77.152 +3Gf/2Q==
  77.153 +--------------6E81B545B2A1BC54B46F88E5--
  77.154 +
  77.155 +--------------21C7903EAEF51008232F5B50
  77.156 +Content-Type: text/plain; charset=UTF-8; x-mac-type="0"; x-mac-creator="0";
  77.157 + name="blargh.txt"
  77.158 +Content-Transfer-Encoding: base64
  77.159 +Content-Disposition: attachment;
  77.160 + filename="blargh.txt"
  77.161 +
  77.162 +WW91ciBtb3RoZXIgd2FzIGEgaGFtc3RlcgpBbmQgeW91ciBmYXRoZXIgc21lbHQgb2YgZWx0
  77.163 +ZXJiZXJyaWVzCg==
  77.164 +--------------21C7903EAEF51008232F5B50--
    78.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    78.2 +++ b/test/test_mails/inlinecat.eml	Mon Jun 08 15:01:34 2020 +0200
    78.3 @@ -0,0 +1,179 @@
    78.4 +Return-Path: <krista@darthmama.org>
    78.5 +X-Original-To: krista@pep-project.org
    78.6 +Delivered-To: krista@pep-project.org
    78.7 +Received: from localhost (localhost [127.0.0.1])
    78.8 +	by dragon.pibit.ch (Postfix) with ESMTP id 13405171C08F
    78.9 +	for <krista@pep-project.org>; Tue, 21 Apr 2020 14:33:15 +0200 (CEST)
   78.10 +Received: from dragon.pibit.ch ([127.0.0.1])
   78.11 +	by localhost (dragon.pibit.ch [127.0.0.1]) (amavisd-new, port 10024)
   78.12 +	with ESMTP id lZOL-1QF8OSc for <krista@pep-project.org>;
   78.13 +	Tue, 21 Apr 2020 14:33:15 +0200 (CEST)
   78.14 +Received: from mo4-p00-ob.smtp.rzone.de (mo4-p00-ob.smtp.rzone.de [85.215.255.22])
   78.15 +	by dragon.pibit.ch (Postfix) with ESMTPS id E7ED1171C053
   78.16 +	for <krista@pep-project.org>; Tue, 21 Apr 2020 14:33:14 +0200 (CEST)
   78.17 +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1587472394;
   78.18 +	s=strato-dkim-0002; d=darthmama.org;
   78.19 +	h=Date:Message-ID:To:Subject:From:X-RZG-CLASS-ID:X-RZG-AUTH:From:
   78.20 +	Subject:Sender;
   78.21 +	bh=RDYGdSUCcp/euKret4IVdgjTPTvpGdL2sNCuAm6pfPI=;
   78.22 +	b=rfl4zIC+CaySL9ylAmareUkX2CzJYdRrZnuGDnG2bunKz1Prr7AyC9IQMM2iO6qTym
   78.23 +	PFn9PuqgDcmw5syi1mnsMRZG/iD9wtbn0NITRDLf7VAD8rnoBvF0XTD5WOtFk/PF3NSJ
   78.24 +	E3NP0yUOMzcKEDVtDHRfCD++fRuPtUwVq2628AMAmwKYheeiqylQ3FtUH7VyrcYBc/Iq
   78.25 +	Jt6qtlmgsVVxBD3Des9yPR8YpBVxqzPsq+5wMxHZWtxZ0JAcHL3RfPylT0jqct9yEmGu
   78.26 +	9kMxichTKbjzJKPjMzGycDETamT5B6xYe0bwg7GtxsVTTSd6tMMSuT9QMyVJdj+xj48p
   78.27 +	l+Qg==
   78.28 +X-RZG-AUTH: ":J34NZlSpW/vPDlKSRxUBevLT/2WDdlCqkty/deruLplgoO4nY+csF8wOXLHBXKAYNsYMbdY="
   78.29 +X-RZG-CLASS-ID: mo00
   78.30 +Received: from rylen.home
   78.31 +	by smtp.strato.de (RZmta 46.5.0 DYNA|AUTH)
   78.32 +	with ESMTPSA id U08b44w3LCXEFjB
   78.33 +	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits))
   78.34 +	(Client did not present a certificate)
   78.35 +	for <krista@pep-project.org>;
   78.36 +	Tue, 21 Apr 2020 14:33:14 +0200 (CEST)
   78.37 +From: Krista Bennett <krista@darthmama.org>
   78.38 +Subject: Inline cat
   78.39 +To: Krista Bennett <krista@pep-project.org>
   78.40 +Message-ID: <c71bd2d5-08d2-5907-ed1c-f9cee476208b@darthmama.org>
   78.41 +Date: Tue, 21 Apr 2020 14:33:14 +0200
   78.42 +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:68.0)
   78.43 + Gecko/20100101 Thunderbird/68.6.0
   78.44 +MIME-Version: 1.0
   78.45 +Content-Type: multipart/related;
   78.46 + boundary="------------5E6D12749B807346B74C125E"
   78.47 +Content-Language: en-GB
   78.48 +
   78.49 +This is a multi-part message in MIME format.
   78.50 +--------------5E6D12749B807346B74C125E
   78.51 +Content-Type: text/html; charset=utf-8
   78.52 +Content-Transfer-Encoding: 7bit
   78.53 +
   78.54 +<html>
   78.55 +  <head>
   78.56 +    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
   78.57 +  </head>
   78.58 +  <body>
   78.59 +    <table width="100%" cellspacing="2" cellpadding="2" border="1"
   78.60 +      bgcolor="pink">
   78.61 +      <tbody>
   78.62 +        <tr>
   78.63 +          <td valign="top" bgcolor="pink"><img moz-do-not-send="false"
   78.64 +              src="cid:part1.E3CD5C3E.91A2C688@darthmama.org" alt="Tiny
   78.65 +              Canth cat" class="" width="144" height="204"><br>
   78.66 +          </td>
   78.67 +          <td valign="top"><br>
   78.68 +          </td>
   78.69 +        </tr>
   78.70 +        <tr>
   78.71 +          <td valign="top"><br>
   78.72 +          </td>
   78.73 +          <td valign="top"><br>
   78.74 +          </td>
   78.75 +        </tr>
   78.76 +        <tr>
   78.77 +          <td valign="top"><br>
   78.78 +          </td>
   78.79 +          <td valign="top"><br>
   78.80 +          </td>
   78.81 +        </tr>
   78.82 +      </tbody>
   78.83 +    </table>
   78.84 +    <p><br>
   78.85 +    </p>
   78.86 +  </body>
   78.87 +</html>
   78.88 +
   78.89 +--------------5E6D12749B807346B74C125E
   78.90 +Content-Type: image/jpeg;
   78.91 + name="meow.jpeg"
   78.92 +Content-Transfer-Encoding: base64
   78.93 +Content-ID: <part1.E3CD5C3E.91A2C688@darthmama.org>
   78.94 +Content-Disposition: inline;
   78.95 + filename="meow.jpeg"
   78.96 +
   78.97 +/9j/4AAQSkZJRgABAQAASABIAAD/4QCMRXhpZgAATU0AKgAAAAgABQESAAMAAAABAAEAAAEa
   78.98 +AAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAAAAAAAABI
   78.99 +AAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAAJCgAwAEAAAAAQAAAMwAAAAA
  78.100 +/+0AOFBob3Rvc2hvcCAzLjAAOEJJTQQEAAAAAAAAOEJJTQQlAAAAAAAQ1B2M2Y8AsgTpgAmY
  78.101 +7PhCfv/AABEIAMwAkAMBIgACEQEDEQH/xAAfAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJ
  78.102 +Cgv/xAC1EAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYTUWEHInEUMoGRoQgjQrHBFVLR
  78.103 +8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2
  78.104 +d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX
  78.105 +2Nna4eLj5OXm5+jp6vHy8/T19vf4+fr/xAAfAQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJ
  78.106 +Cgv/xAC1EQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS
  78.107 +8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1
  78.108 +dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV
  78.109 +1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkM
  78.110 +EQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4e
  78.111 +FBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/
  78.112 +3QAEAAn/2gAMAwEAAhEDEQA/AO5GD7U7Ge9AH5UuM9K8JpntgvGKeMUij8acAcdKEAdulKfQ
  78.113 +0tQXc6wQtI38IzSYEWpX0NlB5krAZ6DPJrCXxAJJCFbj2rhvF+sXN/qTgSEInAGelZlneyxO
  78.114 +Mkn8aycnfQ6I0tD2Gx1ESAZPP1rUicMMgivLtJ1obgC4rsdJ1MOq/MOapSuRKnY6Uc04c1FB
  78.115 +Ksigg5qYdKu5mJyO1AGRTgPWimIQUU4DpQRRqAhpMc0/FGOOlAH/0O6B4pw60gNKuOleEe2P
  78.116 +HWn9uaaM+tOU0gHfhWH4oc/ZmQelbg+tYviOPfHz6UPYa3PJL1d1656ZPNRMgxxWhqaf6c4C
  78.117 +8etRFBjmsEjuT0M8M8ThlYgjpW/oWsFCqlufQmsW4jwCSKoNKY23DtTfkVZSR7PoeqK6rl+K
  78.118 +6WCRXjBBzXivhvWmWRY3PPQV6boGoiVACwwferT01OWrTaOixQKarAinDrVmAoXmlI9BSg0o
  78.119 +9qoVxMdsUU6gjNAH/9HuScKTngV5rrPjq7g1+WBYSltG20Y5J9zXpTqChXsRivJPGWl+Vqjy
  78.120 +hflzzXzlRtI+ioRjKVpHd+H/ABXZagi7pFVvrXSwyJIoZGBB968Cj3QvviJVh3FdBo/im/sy
  78.121 +oZ/MUcVKq9zWeF/lPY6ztaTfb9M1haR4xtp0Hnjaxrfnube6s90cqnIrVTUkcrhKL1R5dr6+
  78.122 +Xetxyapp0LGtLxYqLe5H5CsuM7sCskzrjsV7wsxPvWLfArk9P610jRDbyMn0rG1SAAHOCcdK
  78.123 +3irjUrGTb3TRygqeRXb6L4hnt41OC2a87nbZJ0/CtzQrvem09j60VabSuaKSnoz0eLxtNCR5
  78.124 +i4B6k81rWHjqxl+TLLnu/f8ACvM7pfMUDNVIFYPn0rkdWSB4aLPfbDVIblA4bAPTPetOM5XO
  78.125 +K8M0rVryzkDpKzfU5rtdD8bxyERXZbf0GMn+VbU6ye5y1MPKOx6CtO+tULG/iuI1dGGCPWrq
  78.126 +nPJrZHM1Y//S7oVzfjHTUuLQvjkV0SdKjvohLbsCM14EldHuRdnc8QvYjBMyMDwagVwCMmun
  78.127 +8Z2BjZpUXHpXETzFTgmua2tj04T5lc1pL0ImAw49KjTxDqEX7qG4dQeOvSueuLkg/e4pqyk4
  78.128 +J4JNX7MiczrIbiS4y8kjSH1JqzCwHesvTHDQ4XoBWhDyfepjuSi+hJWs/UYsj3FaEBULioNS
  78.129 +TdCwHXGa6oGcjgtXZWuSEzV/w7bSSuSTsUdWqndwFroknoTVqy1NYXFu+EUVrNPlsgpvXU6h
  78.130 +41QDaSwquygSHAOKm0+X7RbEfwjoTTXHzeleZUWp3Rd0SRYA4qTCnOcj6VAje9OMm0VhrcZu
  78.131 +aNq93ZOoiuHKj+Aniu70DxK07eXMkaN6g5/U15bbuFOeenrWjbXIGOSfxraFWUWc9SjGR//T
  78.132 +7aM1N2IqBDUwPFeCe2cv4tsxJE4VBjGa8T179xfSIOADX0TqkKSW77uuK8G8W2yJrU49Oayf
  78.133 +uyOilPSxzqgyuGboO2KsFTjdRjayxAfM3J9qmkjZmWNB7cUNlt3N3RolFmCOc9a0IlAqtZ4S
  78.134 +JEHYd6vxr8vAqIK7KvZBv2Y+anyMJExwc00Wzu/ArQtbHYmWx+NdcY2MpTOWvLeNWbYnzY6k
  78.135 +Vzc9gwvDK2SOld/dWgMjYHNZGrWR8oJHgdyabkugRV9xbG5SO2Cqe3Ap/mbvmrDlc2y7ckkU
  78.136 +QXkkkgUYArjnT6nXGdjdR6GbNV4mJUY/OpMNiuZo2uSxyHNTrIexxx2qkSV6UscjZABo5bgf
  78.137 +/9TtI6mHSoI6mWvAR7ZX1Di3fkdK8N8bsq6xIo/ib9BXsviS6FvZu2R0rwjxBObnUppCc5ba
  78.138 +P61EviNaZTtFLTeYRyelaEUSiXIx6VntIIpViXtxVpZtq/X1qXdmqNe2LFhuNbNpjgVzVrcB
  78.139 +ep5rTtLo5BJPNZ3sy7XOmtwirzUzyLs4rHiucr97ipDOzNwa1VRkchNPtL1Rv1XyznHtUxmV
  78.140 +WyTzWXq92FQ8j060c5aiYOqYLnHSqlqNsgNPuJNxOTkmi3Ulhk0m3YtI2bXkVa2+o/Cqtmdq
  78.141 +9PxqySMZ7fzrmlubojxu/pTQAD1p5b/CosnJwPxpK4z/1exQmp1IqnE/SrCvxXz6Z7jMLx1H
  78.142 +/wASWaQHoK8Pc7rz/dya9v8AiBKF8NXBzjjFeIwhfOnkOOO9TLc0g9CmwzdnnkVNgk/jUNoN
  78.143 +87E8c9auxxHHSiWhpEbFndmr9u5GD3qusR3Vaii+tZ+pqkaFvNjGcmrKTgDPSs5cqMCq11dF
  78.144 +VKgmhWKsT6hqaxBgrZPesG4vnnk65FUr+d2lKg55qFSV6da0UETzGjGfWrcLKB14rOtgx5JN
  78.145 +W0RicD86mSKTNSGXgBetTgsxAz9aoRypCP7x7e5qe3uM/ePJ7CsZRNEzRVAF6fjTGTnjmpYm
  78.146 +DLTZg2Rg4qNUWf/W6JHx3qZZjjrxiqQbFP3+9fN3Pfsc/wDE24K6AUBx5kig/SvIoGJiuAvV
  78.147 +nxXpHxNn32QhGflUvXn3h5BJOysP4i5p30bKSGxwmOYRDhjgVpsixx7j0qu4zqwyPugkfWrG
  78.148 +oONyxKeBUNmsUNgG5s44q3wo6CqsDcZzinyzLggmla5omhJJOoHFZ9y3Uk9BxUs86IpLHAAr
  78.149 +ndT1JpMpHnbnGauEHJilJInmCZ3e/wCdRqylsZrJM07NuGcDpSRyXB/hNdXs9NzH2mux0kLI
  78.150 +oySOKfJexRjGevYVjWlteTn5iQPat7StJRHDyfM/oawkoo1TbCCCa4PmSDYnYY61ZjULIAOA
  78.151 +DV2VQiYHSqPPnAqcHNZXuaJm9ajKA06aIls4pLBSIlL8mpZn25wv1zWDNEz/19k57UHpTCRn
  78.152 +INKDxXzLPoDlPGWnzXJZ0GV2YxXnujsbW9mVuGDEYr2yRFkXDqCK8m8cacdO8SO6LiOdd6/W
  78.153 +hdUMz5pMXhmXjisfV9XEV0UJ5xmtWDEqYJya5nxNZFLlZTnBPNdFGKcrMic5JaCy+I9h256U
  78.154 +7T9da7uBGW4Nc9qVsceYvc9Ki0QSLqUQ2nBODx2rt9jDkbRye3qKaTO9khkmTkkL9apyWsSs
  78.155 +c4x3rVeRY4gCR0rFkdri9EScjvXnxbZ6d0WktY3C4QY61cgsI8E7Rk1LAgXBI+gq9EgCDPPr
  78.156 +WUpspJDLeBETCgZqWa4itLcuTjHX3pTIqjArFug99dCMZMadTSir7jbJhetOTKfujgVPp4eW
  78.157 +YNtOKqhAXEKYVV9q3dOhVEAXn3pzdkOLNK2JCAdTUN1nH9asRrtT+dVrueONfmGR6VztMtM/
  78.158 +/9DSJJ708Goc/WnIfqa+YPoSbNcp8TLD7RoovUXL2zZP+6etdTk1DeQpdW0ltKMrKpUg+9NM
  78.159 +DxSybayt24pPFMCvZBh3NEsT2lzLavkNDIUP4HFQa1eZstvUrzWsG1JA1c51oH+6QWogg23a
  78.160 +BUIGQWY+lXtNInkXIyO9S6kUUBYwAT1NdEp62M3BbkNzftNI5Xp0AFWNFRI/nk5kbtWci7eg
  78.161 +q5p5fzC+0s2MLUySSsVFu5oX2oLBIqD5mPYVp2t4Bbb5PTOKzLTT2aVpZBukbnntWnFYPLgO
  78.162 +DtzyKwko7I2TZQ33N9dbI/lTPJ9q0JFEMQiiABI5atKGzjhTai4qpfQZX5TyanQTlcohCGGD
  78.163 +kmtnT4iFGSwPrVCyhKncVzjmtCO5RUIIzxxipkrjUi7JKIflfPI6isbUJ1fnJHbHvTb6/feU
  78.164 +xnHQeorHeeSVmCjIPYjpSUGaJn//0bin2p6t+dQhsHrShua+ZZ9CifdS96hDc+lSg8UgPHvG
  78.165 +m1fE+o7RjM+f0Fc3qDK0RBrqviLD5Xii7wOJNsn5qP8ACuPvhlh6dK6KZTWg3S/kbGeO1X5I
  78.166 +RKo4qDToCVGMd6sXHmwkYGRkVUnqSkJBppYjPrzmtmxsY4woVRnFV9NSefKopzkAk+lb9taM
  78.167 +siHOcDmuec3extGKSuRw24jTJFW7cKMDGc+1OlgLFQBgVsaRo81xhsBY+xPepuRJmPcfKOOa
  78.168 +oTK7tnHetrxBCttdvCg6Y/CseWVlKJtJPei9zMhOY2JHBwCagnuAin1bgU+dmIJAOFBBP1qJ
  78.169 +oVAUyNySWApK5ojPuA08jPn8qmsrdcElhuAzzVzylgBJAKBc/Sq2ozxBJWBC7QCrDsCBn+dX
  78.170 +zN6F3P/SkDDr0pwY9hUOT704N7181Y+gJkbnrU27iqqNzzgVKG7UWGcT8TLAvNDegZDR+WT6
  78.171 +EHI/Qn8q86nULG2R8wz1r3a8t4by3a3nUMjdQa4jV/AAmd2tJ9oPY9q0pzUdGWmranLaXasl
  78.172 +ksjDBYZpfLMjMrDjI211DaFfQ26QvFllA5HSmJ4bvXO4RgZOaL3Zm2yjp5CnKKFHetaAKOnX
  78.173 +1qWHw9eox3RZ+lbthoLBQ0pHuKzlEpSZS0mxa4mXIwOue1dbbwrBFtQY4os7WG3ACIBj0q1g
  78.174 +EVDQXPNfFMrRaxKZCQGORu7msF5y0hYsCCMACup8e6ez3RuXXK4wDXI+QSX+cDuahNLQdhJ5
  78.175 +2ZZcOqqxyP8AdFQXTlo/MaUbVjIyf4R61Wv7SXaXjO4ntngCqb2d5JCsbs2SRx7VtFJ63GWJ
  78.176 +dYiQeXvLEkMQKy3uZJyVijLAhQwP41YGj7huLkkDJI6GtDTYI0jffGVYAA5HXn/CteaC2CzP
  78.177 +/9OMEU4njrUYJJFKDjNfOn0BMh7g1ItQZIH0qZSduamwCk09WycUztSp60rDJ19CKlA9qgi5
  78.178 +IqRSeaQycYp68dqiWpE5pASD9KetNHFPJIGaAOf8X2/nWm/H3Oa84uky+3aRk5x/ePvXreqR
  78.179 +LLaOHyRg8fhXmN8oW4lAHCsQKlx1uMy5MgqPlIXkjtQCy73bqeckcD6VIwH2uNP4cFsetVpG
  78.180 +aSWBWPyyOWYdjgU7FIkgbDEhV2rgqDUV5GXRQGIORu98cYqcqMFccZP8qjmz5AYEg7s8exFC
  78.181 +3Gf/2Q==
  78.182 +--------------5E6D12749B807346B74C125E--
    79.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    79.2 +++ b/test/test_mails/system_a_to_b_755_part_1.eml	Mon Jun 08 15:01:34 2020 +0200
    79.3 @@ -0,0 +1,88 @@
    79.4 +From: "payto://BIC/SYSTEMA" <"payto://BIC/SYSTEMA"@URI>
    79.5 +To: "payto://BIC/SYSTEMB" <"payto://BIC/SYSTEMB"@URI>
    79.6 +Subject: =?utf-8?Q?p=E2=89=A1p?=
    79.7 +X-pEp-Version: 2.1
    79.8 +MIME-Version: 1.0
    79.9 +Content-Type: multipart/encrypted; boundary="74b0dc5119495cff2ae8944a625558ec"; 
   79.10 + protocol="application/pgp-encrypted"
   79.11 +
   79.12 +--74b0dc5119495cff2ae8944a625558ec
   79.13 +Content-Type: application/pgp-encrypted
   79.14 +
   79.15 +Version: 1
   79.16 +--74b0dc5119495cff2ae8944a625558ec
   79.17 +Content-Type: application/octet-stream
   79.18 +Content-Transfer-Encoding: 7bit
   79.19 +Content-Disposition: inline; filename="msg.asc"
   79.20 +
   79.21 +-----BEGIN PGP MESSAGE-----
   79.22 +
   79.23 +wcBMA0wujQbo9SW+AQf/SuuMOivq5s8pdoD7rlqC82fCdAXXZC23KYfZeCczQN5J
   79.24 +C0pzv+htEGt/vKbfvyk3AvKoJuhNo3ATTvyceZQNtDxyaTrC/xLG3OCWpPJ2sFFE
   79.25 +XD9SL0kolYLYdNNGedxgoObc3D2rPk94LFTXjVPmTcjtxWCVziKcvvKAodAkyUhT
   79.26 +6noi/3Nj9ZWFNVAkHKk1v7BsTluAHP6uYGTnBkbxLjPEvc2TT3mJRpZ7U2cCe5gK
   79.27 +qzrDIBPq6FC7BKp9MYOGk8piQH4n/GP58rtiJVFhO8MghMLOjf1bDsflBqorneR/
   79.28 +AXHyvf9Q0vLXYhxtNWTAVu12ICe9ZL/5F/MhjZVefcHATAPh3U/MnRbw5QEIAJg2
   79.29 +rpSbs++EvkktWXhgRwcewtedKVxdh+b+vm2Vl1o353YtwyMRnhnDuYhFWpwvOT8F
   79.30 +IM2UJDSTM8UXYahksI4PMkQ+r6M11tVi56ltnUy3xkjSltRWyzS+/JgPe9BZx8nk
   79.31 +6+EwDeAjK0Q4YBqb44pha1fS7z0Wj00/c0+YjC4605+6mwN6lTDExbV56CB+Zgfn
   79.32 +Q8h7Pwa4fzaTImsUVUKOWoOzVudj1kthxuRle9f4hck5WGsaIBx/+jXSdRcBHTD0
   79.33 +lxYS8CXywQCIInYQhVPq7At9GAbeiYcU3mrP1x2c321gMmVI+GXLrwZabdKObrBS
   79.34 +SPpe46IJquDRl96Lwd7SySkBjxh9CgJUCNjlvdNaCS1A3Q5wl7Lj9dc4Et6VK8/i
   79.35 +XROOkJjPZmLJGHKj/UirgW0ZW8iTeoaNAMUwuWQgwORuacqW3SOohPjhplG5W8N6
   79.36 +AScVz1GbcfqCBeXbobVATEgNsdGfV8kpTfGeJDN5kL7gJ8Y5T1ITYPjOW9Lk37c9
   79.37 +Y0QIiahjfeR9JVMpxcaAYg4cqqYTdQfAL9IImHLGpePZXEiSQMQgxEVIoyiVwrkQ
   79.38 +08SIXPQDHd1bj4pPO+Hkj9vDf5x9DQWs8R8c/dJ1niWlgTek4y5QFl1yKrXp2URb
   79.39 +Jb1TnFPxSVF1oC7iEy/hI/Mrwo2Oqv1dDVOfD66Yn+OHTd4Mu8jft3RvrGsmZzZP
   79.40 +PIIxjNZ3Z5RkJMTeUN+3LMZVrV7zjwgmPwZawJ/hfOysZ0gBZGkUAzt9DAJwPyS6
   79.41 +Ai1UWl1+8wTeIqIYI9cLfSBgU3S5s7CZr/whQhLTF+kRfRhn70hM7cxh3Cmn0uMm
   79.42 +rrFRdnRuhUdTXO70BN48hKbJDMpIcziE9nMGObNEXT3PzI88ctG1Iw3kywZV7xMV
   79.43 +8owem1tp7/b6+KEswLk4Dq7S8OIf5jlniOKAm0TlFETrKTh3XKPpGa/YKg/sS+yM
   79.44 +BFyoIzZujxx/75mub8FSUZv+r58HzYOXntJdIICaiNG5TwKJtj70xR+KQzDSKM3/
   79.45 +8mq2pjI+1saJ+71Nl24MFW6Mzr7y92vRUvmM+QwuqiF4/bZo1ys5iIHv6s5opSqz
   79.46 +o27sJypv3Es8AmErTBvNfqY/XJqY27jCL4stSBMQY3BmsK0DEQrGsF+zUL9g50F/
   79.47 +hSFcznUcHqJZwmdP0O5VeE1XJS9L5grjEd6JI3Caux1GZGcYVeZcoLCelGJaQ7R6
   79.48 +tL4MmgVJSbFIboXLpOp6x/9jfPaRyTBBifpoaQYUOzAQ/5fD2+kqDPsdAM0XfYlY
   79.49 +eMxsG7HwpG+1M4WasO2vOBh1Ddwwde2fHu2MHh5zWwnfypzFbdZCEqjCkg/Gpx2W
   79.50 +LEtlzhCJAWVtKOnPEv6pjItgIK2jzyu/I6iJn05LzXMbhhScLxOHEP8mgmXFDsL4
   79.51 +zEdSCFuCmZWhE2ffUXaVS1eRogRDuG8xnjoGLo4m0B/oi27HX6+BnhvigxdvTi6M
   79.52 +FZhSGK4bbbHwkTfwtM+8mhJUGRTBvmRUko/1RL3baIC6G8kxQS88qCV++C16+pZJ
   79.53 +L98WkLyXkTJJzcbUKmWmAfaq8V9MkPH8X1uJHSg/g3cu+NDRht1PP+FsoEhRhXu/
   79.54 +Bd4gAyzGy4CnKfX9621bs9Qiq6Wh7Uan8aMRNnnxZLp9L8j9t64o8sFNQghqZE+B
   79.55 +zikMS2ePeRQKoBO5pCddP3/wiB4+koLx2mML1LNX5/yPf4XBFIgmojLVR6x2DOty
   79.56 +GVYg7eTFt9EtbW/EodX2WbseW45k0n9s5aSrt9Qv9TFa4NbNlX1BDn4MfF23S286
   79.57 +kmKe/+yyPdyMRQyx80rtNl8dCNFdtWjFBpCiXjXdXBiWYdJOi7wTgdEsXx4b0oGb
   79.58 +v/1DluUJ51oFWDNXg/Jhg4OJRGeOeXjEXgcgRZ3+NzP3RyUIdIRHKk/5zHcrAag3
   79.59 +DlIq9t/tO/y8hTXqg6DRNoCKNrTBlX5cG7eCryaEf7PBoQodWNu6wOvlq3pH+1WR
   79.60 +wKf4PVGmUKxSf863mYmiACsOzyN5MtzRoDwIN5Kre7YGS8Heyv11tI1z7PARTgCv
   79.61 +90HZ+mOZ2AA5Eg5/jLPYProLbP9ltIj7QVEManbM8eLN+Fe71TBBBpwY1Q9sj6qB
   79.62 +qTxlcpcjE2VbejH2LeIlAS2hMMC2MfmVzJvKUTHkdgImbLvmE0ithuikBcMmzzk0
   79.63 +7n7juGIB3McWrnAHndMnU1l63cZrzjrfGauhdpRy4J3Kltn7AGG83Pk98LPeKfpl
   79.64 +9LxFD+G5ekCcEyu4WITT0CJj7muf0O3pvE3fz36ybpqvMRgc5XloA//J4nuz9kBt
   79.65 +igcKwxLTI3V+askdm7PXlhO+LUdFQ9e9/JxsTFijmRsHBcUCEWghwFfC/8QuclnG
   79.66 +627yuNLTc0QDolXjaoVHa7UiF7NTAoiftMxFqwWPAhxpddr3MIF9FWLerYrDy9mA
   79.67 +n0WDcxYXYky8a0V+Hhz0/Clemgt9MVs95fu+KHUyzmC5TelFUYnyKp5g9dL8ebAg
   79.68 +MQHWF4m111hgaKxVdrx7IG3vzYvQAh6bcTdbEsiQbdRiIQVRjdB7waTLBuiT73qi
   79.69 +ZK23+wUtO5BxYliOMeP+EMGdnO6ukJ5UUwvEFUGqqzcbfRNYRfCB8c2IAwPk1Fqh
   79.70 +6ZkuXisduguPSdcQEpIbKjyBY6TQ5JlugNWyOqiNvrDd4r0zPd1yKujRxCGYN/Bt
   79.71 +13KB5uL66TjEENEi4m+U6ep76oub1VKmCpKmtrfXU7q2zm/8YXhBM1vBBV3JOJHX
   79.72 +5Bm5KR5gKj2vl9yBLQ4KvcpdsYtLLzCr8co4JNa18MGs3ei5NTl76BD/yhzo1S3/
   79.73 +hlJaD7G3GZpX6/s4sDxDEYTGZmURWmyretrtpksuBAwr2E2vvqRTZ1upLtWjlkFu
   79.74 +WWFlqq2d2lZmFKjISy26RreAbX1EzME7NCqDFzwfKB5zpv98FfvW+C6IKotZ3LM+
   79.75 +X2gjZ+dacyWI7azFaVJabpyOBKUe83y+N0Ea7hH+1W0huPHoG4sNNISC47ksKBc0
   79.76 +svVU6NduN4UqdLduyfrxj9N0oxD/PrayNkDoqdYz7zhE4UK7B0XzeP4r3oyPjHbh
   79.77 +hvjzc1sIrxKY/Lk7RVX9HGFKjgvtgqSmZbrX/zaM7oRK9P2AZQi8L5obEQRd3T+z
   79.78 +oTlIXaQrcSdYtqgYQO/R44aqdb7K5UbDmVOq8MOcWkgdICJ8zlQCfSeU1U6hD30N
   79.79 +nNn6zTCoVX+45Qw7cuoJx95Wa/JyzZaIpMkghLCgLq8+WzX5pzmBVYrydPVoO/3I
   79.80 +mibBx/cOT9EFbInPV/V6oBCiRfMZKLzPUTV6VwI4qvtLPoI7nS7rAC5Gjhp0/rQj
   79.81 +Vamj1gFhdCJI3+kJVj5RNbIUIkhzSVbljRME3po+xVwRy6OjC5IPDytqqYZtr3ET
   79.82 +6xIm2AaIlRXKjNKiYxPAJaNGK61lSGwTiwjJ3o7zzCIY097YS5jhgd5NZrO0QayX
   79.83 +5C2la1BnwqKr2GIvJkCh5Gnqj7d2rTQPHxvufJmRSSyDMTcYAxiujSwdvr0ylNA4
   79.84 +6Qsf5w1Vry6t32hZlMNWJlrdI2F0n1W5NjoFOamAI5DoVrE5UtFGJPEhFcWWG5Zn
   79.85 +jD8YhUCFcQcZwsSb3teEysv7oVsiuS6nLtlTI5W61y1ZCO+rk+BJSofTExmqTvxv
   79.86 +JZny+O8ui5tDn/rcxbzImp2oDlz3ql0IHz2tSKDkrBdGKj50XnVr0+39tjT3Hqqh
   79.87 +9z8v4BvQv/ZbXQ==
   79.88 +=Rajf
   79.89 +-----END PGP MESSAGE-----
   79.90 +
   79.91 +--74b0dc5119495cff2ae8944a625558ec--
    80.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    80.2 +++ b/test/test_mails/to_inquisitor_pgp.eml	Mon Jun 08 15:01:34 2020 +0200
    80.3 @@ -0,0 +1,765 @@
    80.4 +X-Envelope-From: <SRS0=Sf25ok=6W=darthmama.org=krista@srs.smtpin.rzone.de>
    80.5 +X-Envelope-To: <krista@darthmama.org>
    80.6 +X-Delivery-Time: 1588897873
    80.7 +X-UID: 6466
    80.8 +Return-Path: <SRS0=Sf25ok=6W=darthmama.org=krista@srs.smtpin.rzone.de>
    80.9 +Authentication-Results: strato.com; dmarc=none header.from=darthmama.org
   80.10 +Authentication-Results: strato.com; arc=none
   80.11 +Authentication-Results: strato.com; dkim=pass header.d=darthmama.org
   80.12 +Authentication-Results: strato.com; dkim-adsp=pass header.from="krista@darthmama.org"
   80.13 +Authentication-Results: strato.com; spf=pass smtp.mailfrom="SRS0=Sf25ok=6W=darthmama.org=krista@srs.smtpin.rzone.de"
   80.14 +X-RZG-Expurgate: clean/normal
   80.15 +X-RZG-Expurgate-ID: 149500::1588897873-00004380-D28A6FC2/0/0
   80.16 +X-RZG-CLASS-ID: mi00
   80.17 +Received-SPF: pass
   80.18 +	(strato.com: domain _spf.strato.com designates 2a01:238:20a:202:5100::6 as permitted sender)
   80.19 +	mechanism=ip6;
   80.20 +	client-ip=2a01:238:20a:202:5100::6;
   80.21 +	helo="mi6-p00-ob.smtp.rzone.de";
   80.22 +	envelope-from="SRS0=Sf25ok=6W=darthmama.org=krista@srs.smtpin.rzone.de";
   80.23 +	receiver=smtpin.rzone.de;
   80.24 +	identity=mailfrom;
   80.25 +Received: from mi6-p00-ob.smtp.rzone.de ([IPv6:2a01:238:20a:202:5100::6])
   80.26 +	by smtpin.rzone.de (RZmta 46.6.2 OK)
   80.27 +	with ESMTPS id Q0a3c8w480VD0zj
   80.28 +	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits))
   80.29 +	(Client CN "*.smtp.rzone.de", Issuer "TeleSec ServerPass Class 2 CA" (verified OK (+EmiG)))
   80.30 +	(Client hostname verified OK)
   80.31 +	for <krista@darthmama.org>;
   80.32 +	Fri, 8 May 2020 02:31:13 +0200 (CEST)
   80.33 +X-RZG-FWD-BY: inquisitor@darthmama.org
   80.34 +Received: from mailin.rzone.de ([unix socket])
   80.35 +	by mailin.rzone.de (RZmta 46.6.2) with LMTPA;
   80.36 +	Fri, 8 May 2020 02:31:07 +0200 (CEST)
   80.37 +Authentication-Results: strato.com; dmarc=none header.from=darthmama.org
   80.38 +Authentication-Results: strato.com; arc=none
   80.39 +Authentication-Results: strato.com; dkim=pass header.d=darthmama.org
   80.40 +Authentication-Results: strato.com; dkim-adsp=pass header.from="krista@darthmama.org"
   80.41 +Authentication-Results: strato.com; spf=none smtp.mailfrom="krista@darthmama.org"
   80.42 +X-RZG-Expurgate: clean/normal
   80.43 +X-RZG-Expurgate-ID: 149500::1588897867-00004380-41362A9C/0/0
   80.44 +X-RZG-CLASS-ID: mi00
   80.45 +Received-SPF: none
   80.46 +	client-ip=2a01:238:20a:202:5300::3;
   80.47 +	helo="mo6-p00-ob.smtp.rzone.de";
   80.48 +	envelope-from="krista@darthmama.org";
   80.49 +	receiver=smtpin.rzone.de;
   80.50 +	identity=mailfrom;
   80.51 +Received: from mo6-p00-ob.smtp.rzone.de ([IPv6:2a01:238:20a:202:5300::3])
   80.52 +	by smtpin.rzone.de (RZmta 46.6.2 OK)
   80.53 +	with ESMTPS id r02502w480V7gac
   80.54 +	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits))
   80.55 +	(Client CN "*.smtp.rzone.de", Issuer "TeleSec ServerPass Class 2 CA" (verified OK (+EmiG)))
   80.56 +	(Client hostname verified OK)
   80.57 +	for <inquisitor@darthmama.org>;
   80.58 +	Fri, 8 May 2020 02:31:07 +0200 (CEST)
   80.59 +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1588897867;
   80.60 +	s=strato-dkim-0002; d=darthmama.org;
   80.61 +	h=Date:Message-ID:To:Subject:From:X-RZG-CLASS-ID:X-RZG-AUTH:From:
   80.62 +	Subject:Sender;
   80.63 +	bh=YYer0uSoiOgJ77eFeeovG22OZfDg58Ga6HhfZT93RvE=;
   80.64 +	b=W8kkT9lAt0789JHmnbapULjgkN8JPLwNxAdtCMMeYoPTlYU/YNl8aBR0FI9TX0NrAZ
   80.65 +	J+TbJzMXz01ZjtWnqDukrBZAZYD3GsvoBMWFsk9G3NN0Ihgra2yksE3ujAwcWqT9IEd6
   80.66 +	HdkBjCzK9ZUGpUTp8uhaOm+4GqgVpqIMEDEKnUUCr9vkqXRSOrF49uMIuIw/qgPsJGH9
   80.67 +	/6zRVpj9Im7NcaX1Bc1kG7brTGu3gKbylOWVHHeyzxXClN5EqJuXWEfL8AfeHqOD7UL9
   80.68 +	ncXFOlndjlpI7e30qaq1716/9XVLMZk6+eevChGu5XSq+TcAPwDeFeu1PhdqTPG8xwvB
   80.69 +	pjUQ==
   80.70 +X-RZG-AUTH: ":J34NZlSpW/vPDlKSRxUBevLT/2WDdlCqkty/deruLplgoO4nY+csF8UMSq7eV60EBzWpdqTDlA=="
   80.71 +X-RZG-CLASS-ID: mo00
   80.72 +Received: from rylen.home
   80.73 +	by smtp.strato.de (RZmta 46.6.2 DYNA|AUTH)
   80.74 +	with ESMTPSA id y0bcedw480V7ayt
   80.75 +	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits))
   80.76 +	(Client did not present a certificate)
   80.77 +	for <inquisitor@darthmama.org>;
   80.78 +	Fri, 8 May 2020 02:31:07 +0200 (CEST)
   80.79 +From: Krista Bennett <krista@darthmama.org>
   80.80 +Subject: Blah
   80.81 +To: inquisitor@darthmama.org
   80.82 +Message-ID: <01fa2c62-776e-fbae-f787-f9831efbca32@darthmama.org>
   80.83 +Date: Fri, 8 May 2020 02:30:58 +0200
   80.84 +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:68.0)
   80.85 + Gecko/20100101 Thunderbird/68.7.0
   80.86 +MIME-Version: 1.0
   80.87 +Content-Type: multipart/encrypted;
   80.88 + protocol="application/pgp-encrypted";
   80.89 + boundary="bHdb4jRQ1Alf8hprJbzzy5JjoPaLaP4zx"
   80.90 +
   80.91 +This is an OpenPGP/MIME encrypted message (RFC 4880 and 3156)
   80.92 +--bHdb4jRQ1Alf8hprJbzzy5JjoPaLaP4zx
   80.93 +Content-Type: application/pgp-encrypted
   80.94 +Content-Description: PGP/MIME version identification
   80.95 +
   80.96 +Version: 1
   80.97 +
   80.98 +--bHdb4jRQ1Alf8hprJbzzy5JjoPaLaP4zx
   80.99 +Content-Type: application/octet-stream; name="encrypted.asc"
  80.100 +Content-Description: OpenPGP encrypted message
  80.101 +Content-Disposition: inline; filename="encrypted.asc"
  80.102 +
  80.103 +-----BEGIN PGP MESSAGE-----
  80.104 +
  80.105 +hQGMA63tzBCSYvxEAQwApX3xOnajhdW/Vs2QYBWflr1NTGYK4ohUZSv5506xglg4
  80.106 ++Fy5DfaSkJSAH4K0oVdlhQW0yuoNT2y0IJk6068FfKZLbFrVgPt+mHvXbDx1K2R/
  80.107 +qFpdcdhG65zAzIiKXt45aPTEuj7B1SG6m95f5joXzgoiUK0Se2ixvK8Sru+4GYTS
  80.108 +MT5M764g0pQgM+ac3y4qwTPsUPVTShn2iU4JqWZKwxVuayA9kzA01+VM6hChhGwt
  80.109 +248KtiEtpDTjvsSB7G4r9DuCNeAoL03BFKPPVvnNhfiQLNKtl3xwXkZGy3O73PZp
  80.110 +2TyytnwXfDrVwfRmfj1V8SQx7/Y/Kj5YmAqdzggdZWg8hKr7bXwhJ9XZA3t+wb4d
  80.111 +3DRY4uVKQATi6tsV6x5kDP1ExKUY77Me2PW07vDBQ/v8Dt54Dsm4uqWzLsviWBT1
  80.112 +dEzYTxabGY3pBAXs/w+ra2MZWCUc/eYTSs+D/bZ33hLd3NcMsNB5VoRNXVzWFRKE
  80.113 +HKIJMAUtbIR2H1ZzCJT0hQIMA+WNs84HPA1TARAAqJ9qjrARSAhBMHgAkleih4eV
  80.114 +DRySqN8SmgVOaq9+z/Mh/x74QIio3eI7ondrgbBPXydrAKr6kQH44+cdRI+ayuXY
  80.115 +4X4buaKPY/BwawXZHgu498T4ix1whNl1J0US+qh2rgq5nQv8pF87SQQjBZjaqnkb
  80.116 +cCEdVngGiSFglfhj0qRaF1OWtqC3LXaWSTQEbt8YbN/9puuEUwIOgpPtFONQJ1IA
  80.117 +icBiyHd3C9tBKGanRCSlcKRGGPuNmqFDF9/3ldgpEAWMzF+HqODkfqheP6G7Y5y+
  80.118 +arXBiYqWOhpZ7bX4SUq3jFJaZm35nJjjU9FOcZ/FOnUpGD/Gcm1hq/8cgITcatat
  80.119 +gt4H9yXLckuAn/12jcPSPp9q7AMkO1vdNWfAEtTq3+pf/QjIwtCHgG/LKhE2D+2H
  80.120 +lgdFcubIlLNZpp/HD0jdJalbvrkciysONCCOg/fQt0VZrMa8SDv3Mr7N4kwfCebk
  80.121 +bhsJDi/7DXJx/EIL8hFAQOHoGf8UTKmMu4UTQ+g2KM4XdgLf2gTProbz+JwBemwE
  80.122 +/D34N3nLyQTDt1iJLgREkE5zxJk+A2cjzluAJRDsEkbQQJcatbea5rubxaAhzTVq
  80.123 +fMD+ljjymMjYp04nQNS5ekjs50IQk3+lf3ANN9p65b7m2ePMG27d97Cy9EhLZjBL
  80.124 +/7jp6ZrTBOvnUpYDn/bS7QFBD81C8Sw/OYLVGf6hsSmU5UO2J7u98Z8x7Cu5r4Zj
  80.125 +UDmjNROqLOUjJpoYkZil2r4OTSbmLcw9Oqci1h+nLhsutidpx3aSDKnmni0Vc9uL
  80.126 +TQ7qlm9qqQScaRWO8oaoAoVc+fxNoNlV4eRwy+Ra66MTjzL+MacBLsftrHH8pZux
  80.127 +ZTn3cjSRJlkruTK5ymSCYH6/B/OJJCa2LVutjFcH2xVs4AHeVG9ly/74x8mEv9jG
  80.128 +ZXHawc43ns2619QMKim54xty6y4F2w8YmRlZtzDjAFdbA3s8/gqqbpuQv3Ry48PF
  80.129 +jjPkBDSqCMggthPnYiLDt6fk5//aKVZNSuqGjtqyBI6vBl42tULhnWxM0uvIk4z2
  80.130 +M6pFFjmRrAHj01ayA/gjHCR3M67h3pHDrd2dt22iW/2Oq4PS90zgwVRmXqza1SiS
  80.131 +bnjnwJkVLo9XwjIjBT2djO3/gsJiNlgtXWJCJ14gA3A6pqZh7qDVPx7RRVUgzOp0
  80.132 +4KxrSyOieSOEz6LzsU38iN2obZqs0m2sz36j9YRGyo1hD/mBJ9EEplAV0bMs+RmQ
  80.133 +Kj12vArpR5nWEf+aX2qufboqMHeLbPMfc+YhxFXvnOIjrXKzvop+PdOC5E/8AEJ7
  80.134 +oV2WU4Bf8Jt4T7NF//acSxHCQfGdFlEyYFRmLWF1UZoz2pZ0VI+zomTAOs56n1Xd
  80.135 +pBDlLJbpIVYVfuoA7Z2UG3fGRYDYUuK+gH9f+RZ0mp+eKu+i5X36Ty9KlyFvMIf+
  80.136 +x1fT1Pt9WRFq9nvo+R5ibe7CpbLPgsR3i3bPVJyiQuOOupPLRlq5rLkP8ObgR2bo
  80.137 ++Vc61YKNq+AQaklECAawPqd0yiRsKms3YfVf3e8OzfJecRvuq2m8CoGO5L2ZFBQq
  80.138 +EV1oxH1dbR8TkErcgBKvFiiN0R9vAemBL8aDEB0E9vhD8qQPSAp/OsFaec1iJfA9
  80.139 +RKyLazrrT8yTnmo+ygAEQfrp/W67BayC5Re+CfWh7b4J50xNqpi+VEmozg2QvPjz
  80.140 +1haDtb149bPvVFMyUQF9U5ILqN1J74h08sgx8B30BVYU5R9urgdsofIOjBA3Rgrj
  80.141 +XpC0ib+wDGBdbaXS4IyTiQ/EsSj6VbmKGVOyw7v8gTlUyfsvvLC5VuGzg5NBy/Uv
  80.142 +wSVGV8f5/Ic7gKbUIzwrG/pFGh7A53QkSA/WanlFwEdaFgp6/tN/Egq59brg8PTu
  80.143 +GkB5P9Tb83tAne/m126C0lpMN6yKPTT2w19L/q3kbkX37YHZYabdoQZqdtnhqXiC
  80.144 +u2mfpae3VOoeL46UjuBcO7R+ckr8UMp9IWJU1liKv0HayCZC5lhv6wiIU74T0oLy
  80.145 +/ggAfHam8HCxLb+lasgsdR/mGktOpHgbWZAoq2LFyb6v0utVTgdseJeHF0HWt4oC
  80.146 +CVuohZNcRdQ3mbOVX0Zk0dF7KjFl9q1/tZ/PhVGu7PFKuBDYAK7ElsPDhNgqWJaD
  80.147 +bOrIfOXNqcE3B+udjKkNUx3yCx8jhzJjXPweqzzz/51gYfgHuDJXIHWstNlw8F25
  80.148 +62NZx+PvAH23VXoXU+O5E7Sx1krQTaejs+HHCRnaO5atWuDtQncr2JZ/eE49Hu/I
  80.149 +WOdkY58pAfJbTPgqIIWM1aLvHDLkAos409dcV+gAMN7iPw2vZDwdkz7Fvq9B6G6k
  80.150 +jL5rUgdreuaFAsvIlCWz58LOjfUU3t1/3UVVy51cGfllLfG0P3wLM9D5CzX3wA1l
  80.151 +RpuPbWImhpFYsXRc3J8yB5EQGIcweOW5q9vp7dq+yy7krk/a7MOCiABVaY1Yvfmw
  80.152 +6mSAOa8FN+3VRDuowRR/4+iWMLG4iK3sgKI3HH9q812fpVPRrjUmw1UVGUia3gcx
  80.153 +AfAJfIT8ZGsefTzfDcLsiqE1lLS81s7bxqWIxDlKNLFUhyRXeh924w704iw9WT6N
  80.154 +o/FPqpyrfnteAL/IYxvE9aNB7i5frIEfXkucN813S4CE9vpO+OnJYkbblPXis+ps
  80.155 +jxfgdKYl7QEHVFJl/bKacZ7VQCpHQEbsS3X1Sbglbd7csXn/2JMYUox7TTwNLj+5
  80.156 +zrvypGjBHf8I4YV+uVR/U15JOVogcnT/EO24bfyJtEhqoOJB1Cs3YxRi/8UhT2Bc
  80.157 +jGMmQfpsHjpOqcnqQHxWASN/T9Ay54WwIudmhvVxzO2m2cRlRUvexunjFdYX0ouo
  80.158 +Sgldh2/9CNeheXY27YRYDkWt+4flO2Rk6Nu/UP1qo5bMNJvKIoVVZCAysljzqOxr
  80.159 +xAnj7xFUCupwPL1wR5URUfUCCjrt++HEPEhYwjpO6ek9gya+Dyz3tiQnZOLpZ9I4
  80.160 +kijNrJ1PDy768WdaIpdNHFV7EXFAbYuTkLh+wzJnVA9bQf/NzC2S6FV5NymJIiD4
  80.161 +8uNtYrKLADOInRQkqSHWRy9VYhwO+R7tsokkkYr5jQ7+VOQsr6//OEZW3AzwGVi3
  80.162 +FDfc11lwWiA+UOJu9DxLm80GurMrJAg81idbEDr838ndRxRzowY+XHk/MklJXWZw
  80.163 +RG26+FOZJ6IRk+X9AlYld/qk/rJLPhR0w7gAjKxEl5eWpXd/ugTyhkqEa7GLQpIj
  80.164 +aYQbkonC0idtwjZF93xylxokGSOfgrlug8Gmno6Hdvd250syHoEtJ/JCH/5Og2EX
  80.165 +xixcn5mFK9p+DXgAuhXjuHm9G0/biBsJgo2stNDtWu4jAV9Gxi8u2hKvYB3th9xo
  80.166 +7X+pFLJshUWbo4Y1/wVfzOXmT92wNE2YMgJko3MP8bb+p7cfmaDkXsdCKiTBgwoS
  80.167 +SeMHJ/qbQ7OLzFfTYUmhiFnCJdHPT5Y5+ath6c8HWgsKO9voY7wBO5yaMWwA3rlX
  80.168 ++lJA72NY6aUomkHvD9cvu4U/A29ahCceYNJeFyWDFDQ3twXIWKzGY7QPd1Y56PY3
  80.169 +JxWRya0ZJ428wO0teIv1WZCXYH0I9qRhbClbzaTwu6+gYlxBOW9t29VmkKLOqCmK
  80.170 +BnoNowemle+fZnWfF+gXOP8ezi8fX4u7eqiFtIvl8XrUOK4xTnd1TtWj/hvc9z1b
  80.171 +xUQK/VoHV+BsYD9y/E6rwyvjF8Svw2swp8x17GVNAIWFN1huQ6cxpCQiFdsVWvhA
  80.172 +gjz2v0mHbKsYDCuNxHR6KiW1Ry0JonsN1Qru/DiuU62+GFyshooVfs4KYM3FZLzF
  80.173 +xDMIKoAqjLg33PSdmoElAnf5tGG/VQM2lk6ajOIa8yEaPm6r/MGqISZjHScIDNa9
  80.174 +PFfEnY7wUbW6ivHy3CljoT5GOFr4dkMHD5GzqBJ5493r1Hi/kaUJOLD3e2ogKDts
  80.175 +I3c1JhlmLESKI+r1Q8COiJ+jFxMI3dc2T2PYv2Y0Yqih4rYfuSBDGiIwc+oYbo4L
  80.176 +XtJsJqL9TYhhxJmct32GEABWRCoOhGXbMAwtGX9xatEgemmKDwAk7PikIFGcZ9Vu
  80.177 +dt8bHznU6DxwDkHxHaYNKSe7us6qFQfJwAU2LYVuvmpL/TXnVkZqpdNQwbgP+XRe
  80.178 +SuvvBcFDi3hsu2DFJbhdsGNvSYPnJxSVNMvwskp5PfeVACkwF7kYzFw0YUNBcW82
  80.179 +RLX5aYjMTxlV2FOqiGRPGs2hROcwRb591dy/1+WzlhpDPP28UWrAvMSSyN3/P5mm
  80.180 +JbdLU7s2GFddeiU0NEr4lZbGEkR8pakuaOQmmN8OlW9O+CDr+bDYcrhFAsDfR4QN
  80.181 +zB6BGqWFdrLUhb54rYYU8PDYO441Pk9V6CFSKgMO3mwa3cnXkaM0OMJKaiJ3ktUp
  80.182 +6AghuHgKYQwhxXbMl4BpJkuP6XTfkYRzm2D63dSYv9enQug0X+IjvgqZP5/UI3Po
  80.183 +1KRfx/pxXLWvmQUu5AkD9eZW5b/fO+bbR3K849Ct1DsDzLH0wD5SHK7fW0Qsfsvu
  80.184 +elhli9slR03c0rI4GJdw4SBKD2CB9h8MRuMbv7mogRszoX3ZnTSNMhSp/mZ2vsdf
  80.185 +B+vzRaD3ZUUD1Rhc3jSeYvyT7879rBPgqAvut0vMLZcNAMkbJRJKCwcWFf9+UzFB
  80.186 +S8TaNHbTN9SpvL90j6B7DkxOHvLkxsSWund1m0/+T6ZkXIG57Qp51x2jgCvox7P6
  80.187 +Nalof0i8/t6+bx3K+UsajEsJ8/Ebx3A3hTLdl+qODm8gvU7k5CXelSVvIWUdibLp
  80.188 +tafd+ENdpq7FMK3h9fbExSaIcj70+3id4SVIcA5m2xxz2U5wDEAlAEPqLF5ZPwoz
  80.189 +xss7OkDiXRircR6tx1coEF5monduqkwrN3sv1DbopKGruTUZKAxAgnhbsaM635HV
  80.190 +NGGgIRjoz2udcuriaHydHscfg1e3LmlLY9uX1QQQMhaqjeXLPx2j1jORy1rMc+l0
  80.191 ++WyakIvraaq1zDmzcpE16T8ERkRXFcTDTBS21IzbL2Ty3RT0HdGVQCI7i9/IGCut
  80.192 +0tMghxcxS72CVCB5asKF8sm5BwcpRb0Iq7NvcfEwAZguWxeY0n7W/bGfbrUxg4Vp
  80.193 +0kui5w4VRFlR56T+X7WfsTeSuNgtJLwHga/BN/03Ry7OU8l4TFbZSIeZXESW/ZYp
  80.194 +v//3r10vs5MnU8EsLypGG8xkv4I19lxFrtaaqWB9fFUE5mWmso+xwW159zv4FDVQ
  80.195 +/gV8oyIMR0GMFReBAaZuRHG6fUFaS/OBmSZXeosCst1w+DpWsFa3ezvYMfop3LRW
  80.196 +bhSQ6MnJlBYySCuzoT+qCfGfcL5w+TNCt0R5utbigz1tEKOHAdW6SQ1ZSq+rdkra
  80.197 +1EHAe/jhNmMb10FYzIVMciouXykzdXieK2h1pUibYL/HUYUOSNaeWsr8iQMsNEu1
  80.198 +BlO2l4fJq2iulM3p0xL/D1dCka/NcskjbiIX1U09+W1dcwum/qZ4ZMYiuWxTsrm3
  80.199 +ohBqW4LuuTsW3hcoUOEFESWtWGA9J0lzW0TQ7/eZnEsBKiN+ZumDB9GlhWrbhtvp
  80.200 +vMb3+5QanNt72aA/fCD5oUWQklBv1Udmlm+RlI1uP14MahjcK9VJG/w+fNDEW5/Z
  80.201 +Goyuyux9guTScfZTgzxmvSW5GUxqsoYDxmJLsuMsTBXkBZ931FgihVZ+YEnQrXMn
  80.202 +/o9qeQ2ux20teONop5zdl/th/na4G9GUMO9V0PVlsFPnK7mNu1S2gXDLYhsjWtU6
  80.203 +au5bGVDR8X8eOF0Qzx1M38nnt7vYX0ITKkyejHDCV/y2EwbjNmksxkAg17e0C7nA
  80.204 +y8uTq9Ky8xssJURApvylBjXDSI+difoG7KOuZ0i0HtFfmGxRdqxRcYIYpJXfIGLT
  80.205 +OhfX9OeQx6ei2yaFrRdDVphWr31tLViC494IEZlYeMQFliedUwRIkNCcNFWECZsF
  80.206 +TLS8xBl/4Onx/v9dfDWc2+/c9VYuZC3Nc754fSq8RWZY0+pUrkarjBbOJcWPJc44
  80.207 +xViETmrNqONNDUdwVLIDl5ve6VqSZPB0ooP2rBGIv96CqYFy96ciuzEZ/zCaSOMr
  80.208 +dTLXoW5aRABn7EZmOEiP+1rO5jHrdsAoD8+jT1nve0NZPrTcq9e/eqBwzpCH5+vt
  80.209 +qU68lC9wGf053OlKtIo3X26HpjGxMXBJ2CiOE//cOyBwJCPUYQJNgrz4Dv2n9YOp
  80.210 +HJZOROd04DIOHyKQ0NkPb6wPzujjfvtn+aQgEYMR5M7qP5LBMSvq7MNwQgwPFLd3
  80.211 +KnvCskmry61OAINZSiIxstkDRJlYaDqsfYwxYobVsLQurGddr/8CTbYbMLtaawZy
  80.212 +OnOi0zg81IvsOdtuwVPMfi6DjXZ9gHpPD9OA7qmrav2IGKJzg6mTV22xyKvZaIQP
  80.213 +oJJDPcSUEzSLVpn58Y5brC9892pSI+xKRiuwp5p7BVXzXCNWqkmtcG0lm+zrxVzP
  80.214 +bfLRzbmiSoir1iMMy3TMXCzcx4DORxbGQicm7phDwyrzMulzskbDoVAoQzmVTkk7
  80.215 +yJ3aW05biPZgfnP2qyyn9fUYRxfpPZMLgkk8B56FdGqtRCA+xrnNEJIj+aIJcr8C
  80.216 +cL+VFaniV7NEjld8pEIPTbzZ7AmXtqe8h7MEwDW9eFPFPjLzi0DFe3VGg7r/1GTQ
  80.217 +QPOoHnZRWkiQS0DxqFe1+/LPHW92FtMKYYugXBQ8xjpjQAIBn3O3AiCFesYsrADH
  80.218 +o/ofiNn2L6Wg9RmYBd2dh5J21YYvVIMvo8u7TMkTCDV3oIkkNS/viIDcnh+3axx4
  80.219 +Dz3Ew7/PLgMVqMWcC0iL/7MCxGrnZnUd7+h7ZDca4Ms5zsIXoJRRqKV7BL5vTthM
  80.220 +n3DhPEVvfqgRxtsrawzekEaVeA6UHEgjmDQbw30EWBIvf3fPMAjJN/FmIJa3O/XV
  80.221 +jTP2rWVk2HRwIIAEEED5ddCvNKClhja+YDqFGNTIf3MiOdT6Oorpv+A3XSFdxf5a
  80.222 +Ur/3NEvyjgkQBpzZRqfn5+HKGFReLpBWFBKtn/7HI9FROSQPmgc4qNFD6MnlZnHI
  80.223 +NN3L8F5JRj6UGk5dJ+LUsvhdrffr9AhNtZ1ER+WHhQrE5DUk9/vBztz1BmaGR60n
  80.224 +VoW7E2AFL31HkxSjFlLFipXvLmuDteit5GfkJYIqsn8wtOZ9fADZTf51nBnb3ndL
  80.225 +8XQsjVEgCXxToWpRZ41HABZKl0YeOq9qbBpOGkBZLcBC12rfH5fxL2Ms174dv44b
  80.226 +V8eCqPd8/08z3zHqdcfmv/FIzR7vBU6lX95DZfD4FO+vg/YlInbspjxXKEHuAleO
  80.227 ++8EOT+UzHRqZywoJOOOJuKCjJI2mpPayUMg0Lj0YmL6DfnN1ZW/sr5lmNuvv0ZLg
  80.228 +GtZMf9zPuEm2ZcaMvjjel8XTO1fG2YSIKoCbjy186EW64hP65MjsoOGVr3urWWE3
  80.229 +SdX3Cvn93HqJJtK5IMBHUGO6olfUBFyyqseYwUyYj7b2hiQPVvxtBdvRssRajwaJ
  80.230 +VKiJIdAsEh89HjSLEqeutVqu8ItCfxSXQPpPC6A80SjmS8nP4XCyrevWT6S+Uxmo
  80.231 +MvFcsRuynYU2h8XHHO4kygDv1E0V43voZGnCrg5et3IcRs/PbmQBmGZuYZN2LXhl
  80.232 +qnwdrmAZcRszmen3011tzObArWbiFhICODkK9VQyK4kADdFMW6BuGtW/sug0hsDv
  80.233 ++RJ+2/ItdcF/9AnIJvcyTTyNrcW1W3JwCKWcKuizkRw4CIrdiMupHMA93gvTUGXt
  80.234 +FFqHsyPhEqWLQl+RKcjEAotOMasz3EUT+wBfIHe2Ll0S3ig2/KhyuokskO0dZ4XX
  80.235 +Lrr6113nRYWS1v6XGjasx5x3UDwO5LvCnncCvQ/3/Y7Rp4FVviezylyJ2AV5Nipm
  80.236 ++HeZsBVPgsY3dK+POKiTEGszv4Njnm8VGfnsqpNh9Iw1TuI+pSw8FX1/KdH+tAAD
  80.237 +AjaVQUOf+X2GmNqohVNp2UbCK93nhzKZdFmr9qCn3oflJFf6t0CSp7yllisdpREZ
  80.238 +cuNvEhIZPtldT3e4Wuc9vEBOpja+eXOH7HALta7bxT7bF+w/Dh035nTnezwOmO+B
  80.239 +ob7lKkphKhuyGFRCONrJxOc3GHe+o7o2gdO7r8S36zZVbaNM0shqY0y11aqtXFdK
  80.240 +WvYyRadEsSPJ/fYWgV+hDkYsobhDIXFFk+R4o1xJ9LtDvZDt2Jl3gTpuDAv19IQj
  80.241 +lnZ6UhsEuCyjwoqcBC2Xxw41IWtTorcAiJTvSywbmriCO16lp9KWfU56gSt4dmN5
  80.242 +GWic7N4oR8HMMh777MaJsz0WbE9f/ZhtIhBDgFWuWs8vVUTkdEqqxPr0aU4ac7PW
  80.243 +c/pLWmLi/jj4m2XHsGLoaQC+JWgQZ0qofGBbTKaqZeAgQ8IAcwo4S2BGvKSbylO5
  80.244 +IPNtuSGcWDmRJIysgl49V+2PwsheSCs7DRo3CHCgLlQr56vlif3vTGzRiyDNmBry
  80.245 +X35yEl1rXQ3RW+LNl0L43UMUPFuCcclkv/XOWrXX7HaeZlaJE9GF+syn1kHsobtC
  80.246 +HOwKWb9GKrfCiotbsYCYE40+HEm0WEuKkv02hssYz5iZS47UyhQGu7X6UbfmtqBt
  80.247 +phiTRvwQFhfm7HIE0h1sJ5iZ/xhbWOOWkrb/5CdBkZI+mzBprnOoGhg3Sv4cS8j7
  80.248 +w3rLSwsDpi0WPRXNCdA+guqVdlnlgeiqTEeA+LhMwwhDP4BcOeLxY95M3OL46cmB
  80.249 +jd+xskVdRD6sIZJY2BlQFZm9o7iIqosBn22Sk6biDdUpSfMpxX/0tDYWmKNwvbNf
  80.250 +TZBUz/okuvN4iB7SoxTwpkdZVnAqvrhuhB7wS4MO9TM0i7gT3s4QwnF39/YsVFVg
  80.251 +NrWwPJk0Tq8cV+og2d/utnqNAMFAgnku0WYLqVm3+X0QI1AB8oLwMKwz2sTfTSH1
  80.252 +NIrluYrV5D2yta4hod3nkrsYs5QN7sAS0+8XGWRchOr7nIv2bCVDZdOvrasFdIc4
  80.253 +6X74Txroq0oaRfUgbUcrMlolEKkBHhe1atuCAcFQH1ubJZaV3rt78vrL2/uj6sxp
  80.254 +YgeC4c9fU0Mmi6PUMH4raO+5bH+PWnnDYfRnVrZ1CDCfGCZNEeI0Oi8rJB6KR759
  80.255 +jOu8qWsl62G9m6S+oqeaoM46WkDhHmrpZuRDIDJmuIEh3MpuJ7PbWSIa3smgQBgR
  80.256 +Uklt5kraPlJbRmvS2MN+HJRf0PJGz7DvpnwDs/Wk9PaYvrF4ElNA07hvORrXoS6L
  80.257 +3FnItgO5dqTOGlCIigfHDq+0JtILLRbzemueru04/PRTum1553rGDCjudJzQc716
  80.258 +nDh03Y2VvRppzuMqqQ+98Q0SEop9hTXrz1VBPKrw2jDbxYqisdiEmp4zMWf5FVtX
  80.259 +29/fDE3aZfwDHZ2glWhEiC4qrnkTf/BX/LmhFwwydbySsGdL+WKeEHl6/SpTFbhN
  80.260 +wSClg+TVWDEjs2csOoR2aYgOg9b6aG5yUTuv9efWeiBFy/1LAoUyaTZZ4BI79xoP
  80.261 +6bHETTbBL2urjxWm7R06P9S7nJU2/dGKFreXV4IRnh1d+eKH7iec5EAa3UeS4RCl
  80.262 +ga2OGP9t3DEi63+ujA5NRzX/iG+ruVMEmwyd6NpseDU3bHKZesiUBOtjFhyKegw6
  80.263 +e43nydsKF6YPOzIkq/cYVdzPGpMPw/l3vpCdhSz0k10+kbqEbRdBelSPT/dtk9jS
  80.264 +W5Lc2CTnu2VuixmrpJx+UuM69qw2IYX6bCD/KkYoaAdWyeiMrxb6uzj3e1GBm2Yi
  80.265 +/yLoXFk3GoQR9UdoG+vbgvsgxtHgz0umNgWqJs7uufm4hTCUW2mOQxr72vNS1CHS
  80.266 +8V1qLw0IX05mJ51S+ZmhDSULiEwJI3Am1OIVDMikty8VRo+1fUnyDC24V7D7VTII
  80.267 +xIwyhRf8Wxf12/fhmx5fOUHN8UlSX8nKoW7LOISaB0hyVvEN12KMHb2mtNUouqPZ
  80.268 +1nqBztHr1Zv5TrO6JMGRKS+/CEvvgqFKZt2gSLVtdzYZTvh0kn3dMhNU59O/Uf8m
  80.269 +AC6iATRWLhwP5c83tw3eH6rLmPsrLBtSJhztnc0+xkQVag9JvW2/z6b5H3wd8TJ1
  80.270 ++zgW/2+LoBXI2mUZwZiGxLvMGhfzHZg24X4S6d5TPOTpxeTMMF1VTWlqKOl9inMV
  80.271 +XKWaYXLQ7x+FARvMKEhLdn8aG3CgSOx9wACk+qU+w3gClH7v6ddL0F5oobpdBzu6
  80.272 +b3EVri1KMbhDMWCaed1/P5PvqGDBJK/ftOhjoaDOr/hER3QVH/hynEDaBfr6n7Xo
  80.273 +axWX6zWxqp3inTIxD3QWy7owYehqGC9rp5mvwHzpnNSye0jdzR1nt5CA9Q96Lnon
  80.274 +KNB40W3+gbIseIcDGcY5irneacYTeajkC3q42atwtuEsMAFxhKTF/Wo5FTN9c5HU
  80.275 +Hbtij1WgiaVwQAtFwRGTGTC1GCKFNbaTSWm7lxkP29akbEtW6NyEb4DqeTkwQQLG
  80.276 +6e1/zGYwjBwwsOM+voREODyemNH9T06HgSKXxkstZbwkjp7jI5iinj1qtDlCy3xT
  80.277 +606lLrhkDxgjaBPxrP6E76bUiuffXUe5mKE8SrK8NOvqz1xNbCyX9Lmqifx7x6Sy
  80.278 +hU4upfAbSdy/7Vtnp2OMVa4i7xPYj2B0tFow7KXaks9khqIS9FTiTbXbW4gdQaKD
  80.279 +xS7oaZfCFLapbUTaUl6TFw/JIkpRfhgZiArs/rW8aZYWsT1jJ0wirkZjL/3bWDPC
  80.280 +6wejJQ4tmAg94G6bsUREZuKMa99h4klY9B9wi9M8A4wvqof0HZRkrCFcU/UmerYP
  80.281 +XjRbBox2DTv+UBNgMl2jxh5JbEg+CrjDM18e0wabapTUu72RnF9rutDD9LP1F0Mb
  80.282 +Yzow+I1t1xoypXFiqYy1+8RBqhvWSaameIYcsfaEdlTCCjKGoFE0pCs1w8M0OpcY
  80.283 +4G30rZY/5OUWMYGyPgY9dzO3lMtpzBCRIdVMJ79opta+IPSSruMnA8srA41Uscc9
  80.284 +2sOUCyd6cvCXsdxIFoY/0YeP+uOMCkPRScBHzAfHHDahQugc8ycSUAGMCDXqSjaQ
  80.285 +dp+276cIwOlNFZTVe6oi4LK5rJlQOcFpzqK86NvAs380qKt8+9iPeBndWf2p9vvy
  80.286 +0BaLsSHuPlIWwWhzj46Xow89fEm4wotufY2vkKNAapw64oNahlKexyWL9naPkjvy
  80.287 +8yNxvo34VQBoqdrCnyf1V0eVQ1Y6ZcETWYiMkmFEGKs8Vteq0J47mFMyb7bguQa/
  80.288 +GSEYLerLW2QS8Ypv8aGCinZalADODPmhE8r893Tikyn1VPvAFnG08FBtcyav50Pv
  80.289 +zgWHhKqYrhH718Gq3AjsUULvbYJPjkbFNzVsh1rp/9APilIlHTmyU+tPeFrttlMQ
  80.290 +Xzm8qXFdBHI1R1lnJFFiAKR74TK96tJdNf1OMYdz52oy/RbxKw8ZoI/EOZwMXzV/
  80.291 +ENkBVHDsjIM6Wqsl+TVZJjB+OBNK+ELdq5zOaz6wGAG7mnHU8Imn+rJ/eD3+RcEA
  80.292 +HIcdQQzyoXps1Uzi6dzp69nxR7Ub1JrYYAYMtpdUHqd7nhRwUEM1RkMY3iVLMrVp
  80.293 +3azwJY6GX30w8VUhhFsnLDhnlNoZ7F66w1/J0bl52lJgRyVZuItyeIoXIuwC4v7C
  80.294 +UOdBA+C1LfbuyhHk5JKTwX0g2KCx94X6MQen7xNzhsxXDL2UfYavFScP+bkQ1NqZ
  80.295 +7TNcnivuvXn84QzV/H0HG4qJRLONc/GdJMbj5G3QbteZkB27bRvi5Xa/R5MiPT5P
  80.296 +UxJasbM8pCcQc/DSnqs5q2XDzNTRTF0iTVTwXeQn1O7/9VQ5bDubsh/eCxdUN8Fj
  80.297 +Q1WH6aVz2U6n9YUpQ++L9PcyGJCq7lcLdtCpFId375VILOnqbMawobiXK2LGsTeF
  80.298 +o3RhWfIlYtIk7m/zrlPwURWMMOtuZM03aIXzZKlfxXCEnon0pn/5C0p2qJ0yVd3N
  80.299 +oXMLaxx6vm15SVRimsmDsyjH6p8/ukZnzwaTe5A64LnGWV6W5gKPNYOd7Ax7lee8
  80.300 +7cR5SuDjZ/q9R1mMdFE19oJRMVkrUjY4vNRm4siCdT8Qglk9m0BN8JYGG5SaY0tG
  80.301 +mg5ieYnDnQGP6m6c+3+ou0XYYAhN4SixI1+udAUdkWEYVwMr9OMAGUG5gNYFIHcE
  80.302 +hETRYhvmN6BtdqYjCAO/ih6DB9eZT3H8p+oVH/bhvEC5xVhitRxRqyZLQfgVYwbx
  80.303 +Dge9+lou635tC0sSno2oKuXThFH7n8l3CI0QGvUzCA2O3qh7gUj55k1lyXNTKh9H
  80.304 +vi3UARdf1ra6YtwJ4XZr3vrlvoeA7xgJ3BfRPLD2BlishmtmZGtEvQpI+S66TGaL
  80.305 +JGFTtshTyA+5Yr6se0aS2sQnBkRvFiZLBW/YukK5E7wb3mCwkPL/THYXwHGLb5lr
  80.306 +BOYQWSx+C/wX6phkMCds6TJ1dbthEHYM9vBmv7RCtbe9i9QmxYQnlGwxpxZTiP4J
  80.307 +yw35AclrETOALfhlLMVAMuu+YQEdqYo/odfdriXi/SFWK+IP0bjAHR2I/qgRhANj
  80.308 +rfoJ6Xmr4lOS5R7i4H6t8gekUNe4vcMa2dYFIiH/2BGa7cCQ09UyOXXy7L+CGoC1
  80.309 +ozxMPDnu65hjzHBGN88AtQ0fSGZFH0qrRAKRHYaEoEKvqxwYSc0iSTBiTuC2j5YI
  80.310 +MTo2zPCWNmyClOkIQC0RZH2L/BLLOh82/VNZ2vko70pF2xYzSkb6fqBHbNnJFaWT
  80.311 +bj0J4TUa08JdxozGTM8KiRk7F9eb1hrtXMW25mRMysdhomkzBOJ4rBJTDPZTBSh6
  80.312 +9rZproo7ylTNCRjJV/FBNp6K62LA9qEAH+rvfhPw88mJddmsWb5iY5AJtUNwLhJ6
  80.313 +rHDnoc5OEkoORtR2Lstmo8f91wZ1qbgAwtN6fxEYrQMzVWjWsTGlE8QmdHgY0qd8
  80.314 +SN9tP7jEXWU0xPO/q4Ry6ZLYFrs1U45tYas+9kD6pTknjB3LWLMGT7g/16zG5GNo
  80.315 ++vAfol4FzWBeD3EjJkInTZsnV98ZtICliByPBVVp78rYgFjFKeQpx00e54nMRpSv
  80.316 +QL9c5GfXnLMJfjDqbQEMF7OzzdYIgTQjuMNQS1TGD1aVrYc6026BsDdqezxElRrM
  80.317 +ebN4NLyMF+/hCUDschA+igGBF6fyHyqSpz2JUp66rjFmK0Lsjvkez+U8wW5lr7jn
  80.318 +bOy6/vXMGiGymqZN8MxNFqFLZKcG1n6Vhw2IrgjuvxtiNTYlU2elCpgEhRDcd3Ye
  80.319 +PNBJ3idEW59JviIvUnaRGxokp9dpqXZ7T+NhyNGZgqpyA+prGqj3CQAGaNBb6ORW
  80.320 +X19qdiZyu5ZiziujfDLqSFfuGAL3jNfGq9FG083W6KSWkHrHPwsOS4lVENNkZ1ZL
  80.321 +6p/a2gffNodDClhGdIDGMlpF6tsSXNF/M8fIEgEaZI/2HY5hDVjyrxAKA/3xBYSW
  80.322 +Eofu0dQrovvq4LJVlspB6AxOQ59wfrVWFBUEN3K+fWpxN7UYiIFWfN4mdubImn9r
  80.323 +of3v3Lu+HRCjdG74B7PTrY2PXpd8Al6b8qV+tal5YRjGmzP9ByKf/f5LyqteBdrm
  80.324 +CqJij983RqNhq0lHSnkXuxSnUE+Yc5Rei3RZhx3YGramHepY8jbnEqjjlhEwDdOt
  80.325 +K3/vDQe1lD9FLMb1Se/1xDVdYv397TnOK1WYeD8D2Q5Adtje+d1roGm+enZQR8Jr
  80.326 +Q2TaYMYU+CJDeoaM3j3W2M2CKFEkQwC5+Fn2beSsqtXYkdFVia9rktTZ4lElCr/1
  80.327 +pUMqBpUPK//u1pACC2t9LdnA6clVZvB/qCGTJz3PglEmFz3oXagn9wSGLrfwmOre
  80.328 +lW/AR1d9uqd/MRlTojrDG9G+C2f+Vyy+LQgDhwnoFRzt8WVWcBnbNFSHwxCi4Utp
  80.329 +SixGEsrG4cOCdC6PJw1lQKWe84txqq7lz/MdX92SjlttXCaHuxfdxH/iaEiciXpi
  80.330 +6iNXNyyANZnhhtglQRVES+7j8svYONUOJvimc046dynuWUMcT7726XoBDeqYY6Qj
  80.331 +2jBSv/x8pZEMqtmXltcOCYT/F1bApi/wFKKarb5puZD9MO+0EMYi2Nj1Mz9/UCp7
  80.332 +fA0lPa/ji7u6N0V+JA4pHDZf+GpXE7SM0ikJQhFhGismeDBQXjNxAy0DfVr6FfMm
  80.333 +MLww7FXSA6y/veyA1npbSdthPUx5gTWt6pr4lEhMWRGBXjRPRKhr3shZNzyHb1TG
  80.334 +w8UaD4kzs0XJx2kgZWKnyQ+7KZ58rGk59HW/2BI452UxvJrPCy4ezQVyYargdku3
  80.335 +ISLFOECZ8EfC0IpJDXqaojlXiyfNllxX0um4fKuyrfbwgpwCTLrA7j+lJqgwqHav
  80.336 +O5pbw9YJ037m/1XDHo+8SAe0coYix5H8twgKPUCny4Klljz3H5XCKyFptBG/Gv64
  80.337 +95+BztvFp4jfwsv8CX9N9/L4LKr1kqOG27yIX70ZUF/2xIGD0lQalMIPrteDJjYT
  80.338 +mP4jwV9L/HR3UQYCSo4n4V+kww4UDF6qez6G0dsgP8wWCpXO4afloZPwcxLa2UPm
  80.339 +O1BB7UQZiJwvFAge03IZq7fZK/X2QCTFFqC+O/4wg3isfReZkCmSkcfc4YWBjYQB
  80.340 +YYVZGMHM+Ai2qKkxGLY94Is7HXeaLkCULwi54crcAnLVjbD0Hk441ha3a0EtS0B9
  80.341 +mtFcYvRVx4uQnPH49yTEYqCuJRQbqXqWbNQcfqRfI9cZ9URKJlQViw0LGDk4VXLP
  80.342 ++DFFjgkJqv7Mvswhv4vbiWsU8072HOZj+vIlu5UyDSeoKoRN4rtCMK0la43n0Iea
  80.343 +lCEoKvV+ad8PiVttH96oVbrceFJueKpm3mv0QhMYvyKDJU0BNTWdEXCRt8EfFP5z
  80.344 +WBqet2gzfmiqipSs7s74m1FDKiex7Q//88aYKhDjzG1tw9/uDLo8NW15wKY2vv7M
  80.345 +NjIGWeLxb3heRgZiyDFP3y8az/pi5j9GxOFd7Tx0a6nBuHMA3KEdA5gTNXHiVKOd
  80.346 +d5wTmJQ+PHLXbSxFIEUm0hiT2FyEY/ZXo//wf1mLwp1ImLeFhJPyKrWbIkwvJ0H3
  80.347 +hO6bzQjB7f5/9cV/PBdoYffZRnA/vEXzwBoRxZtsjUdyLyY160SAKdafEaZ4fvOG
  80.348 +D58+TEI1lij57+mY7mN+7dBBh9Npltc9hr8s0dyJMVXKvLnnj4i8ItsopFL5Ms+y
  80.349 +mrgqy2vUArSTFJRJ5GflWp7Ms3ze+HgidVPKeMC7sz89mOMvfAvbTofhD0cjID9H
  80.350 +q+RsfLFxRxs538vyGu+d+B1l5dUZPMxRyAR7JuA5sdg3CdwK2en4vfBjug03UtMH
  80.351 +kpBNs1Caop/jull5R9b2aWAIFvQ5P0lvjjk4XWa0vfJZ6XYBI/j1vXwAE7VA05nu
  80.352 +YSldEgp4hPuHd9vVfr4CSF8EmXHVD0hpxnfD8g+PZyvnX7gbsd7pyR7VHAoaO08O
  80.353 +d6KSVVNpIGsAwKfBM3lQdxE/JJIVYtkpCi/yruy4e/xX99dlNgoWhuKOM3UITqqL
  80.354 +hc27zpwd8kYrFDurfCG7WaivYheDM9Nbd3Kb/2IFFBH/KlS+muUNpuXsQADnkqfY
  80.355 +s3Awd885PYlZcCBe3gsPWpIuUxBtCd1Oe64ZGQa30UoSMaIPsUeb3/NTEomULx5A
  80.356 +BdOy5mf6xXsx5JzzN212YJ3mbPdNTTwXDLC3hYgGiLSu5LcjshfP0aTNwWqvyogm
  80.357 +G0uft1zbjO9xA30lM12HKgZV8O/GNBzqa8uMSMX+DtoubsWYqmTQDo130aurzbnu
  80.358 +mOuQCFFtM6MxNBwyE3boHn5+W/IwCZU00dBBrPe3sCSfaEDmf+kJfbGb7Rq/jVgP
  80.359 +ZGKVH66W/k7cVQK/TWQadL0zqqkbELBWUacdk+UdX6QhEbXniOVQa80e1uDR9QH8
  80.360 +TjzWP5MIrf5EaM78YKum4/2Qy8+SWIfGr/dO/EaTWgh/ftrQfuAip7H/0b/X4sYD
  80.361 +eXySeDHSNrkGg1Rs6EUKJSh6dAzmrcaMvIH6Y/nOwuXDCFV7vjc8lZ5oz3hSOahR
  80.362 +hOUm0kP0k+6V3HkK9dyMzTY77WPxd4+OetTQ9nidgvbP4g5LlH/wmLUVs1w2kW1h
  80.363 +QyTZt7/ii9cYEPQePdL0FOkayujvKZqPw4c1tY+zwKrYcQ5hj0JIfZVKzEBjaF64
  80.364 +MLmaivnL/9MGIog7354PDUZslmjoZzvSnU6RKAO2yOdwsvwbQm2B2Kv37B024DeQ
  80.365 +jJnYzyZFab2Gu2PhCgu/KHEIDrbJfXG3xO8BibpaKn4kJ8pU1GudmARhOqdMMFzY
  80.366 +/D+5gn5CZV8IjUDnE012cq9wWqgIluBxyew1PLlzC1J/GMdAnkVh++TC1Vzvw+R9
  80.367 +vYSqnq4P7qkwIt2001JelMlSSrFIxUw301/S99k2Ikjunku5QX0aCqJrGA//zUbP
  80.368 +pxQjuOc0ndCK6TGL2v0UnYM5+75E2AU4Vy5scpXeuBau6pKzZJ23rkmQ+ERzqZJj
  80.369 +LWbb+/X84oWgIFvCu6E8NwrCAYbB94Fu6gkcZSj8UpIUuuxqT8G8MriVdFKDSxVv
  80.370 +YiJtaLoqsNBia0p35Odmfe/wSd0fd8cybUg69A1p1Z9ZPmU6BhfupOctdj/jUDJZ
  80.371 +OgN0paAyKa3NXY/V+cPBfmwMWsehVWtpTdxSCRuiOtjt5mTWteYs3EBz6GR/sGsb
  80.372 +5S1hYmgga0B66tgOmULPi1TogIfag9YHX5cy/KVvdEeAdsUEuQMJYLbBsVP35ioX
  80.373 +Jk6A9KI6nfjFTPXhMakmpL3125P7iR9vnvVpS1Sp8qxlvkofOf5EGEvaH3uyvqYJ
  80.374 +VrekvrzNPgruW36zdkhwaVfpYQ0t6+06YCs8SnH1S6hwQJQrikEEblwM+nP0nQb8
  80.375 +dWWmCdjXGIgZFV0vc7/9Wmvwt8HAeUQfZn7NCbbGjFyRQwecmFHHem6jo+ty/WcM
  80.376 +RoN6OOqs/498MblTfoxDDVnBK02+xv64Z4dXbz36oKULQvxzgiDVkP4IySi3UnAj
  80.377 +syQ9sZEsKSbZ56KURDRrbY1I0E6lPX+M5ASZodp9OTlmT2jGnxQCL4zPVfid7d32
  80.378 +XOq+yBybkXB7sz9aD2PBJMqxvgbO+c1rmWj8S4xYsHIurOFVl1l+MP7jHX6H+2EA
  80.379 +TP2MEMzmmYzcH8EpiTHugzKFjWM15PsOo+DyuqdPUk87QaYfNU9X3AUuPqtu4EQC
  80.380 +Z4Gel1CtFJPPOulZeMTsII9p8yZmnRhhRIlgzviSfwrp3JeSgmMdbAXQhtErANcz
  80.381 +XgLu9uvqeg1Cuf6cYjYA84Y5A30YjAoVG7BRyMOz5+51VMDmFxtCTt4oYKD4VmLt
  80.382 +Sq4V4lE6a4Lsk9WyrqRmbJ74GRRxiooUEUM8Siun7gbxD3ybw71OmZa2cbV8+YuO
  80.383 +fYYfZhsO0yYf8cE57xSQCQOH3CphI6rPKbPkw73l2Y0DDD1ajIqyvIPfisc8NCLy
  80.384 +Dla71U9TAP6MlUS15Wx9Cz3a805zZRurK/nlB8O1jYQKo7/UHNnSHw8cndoo7Ngl
  80.385 +mlyaQbtFvc/plkw0zvbRiLTKqXKUzDvmuTd8sVTRt7Ooo9ZGdV+0aHXDnPVXM8wF
  80.38