Merged default into diphoton, enforcing 2 devices and 1 account limit test_diphoton
authorEdouard Tisserant <edouard@pep-project.org>
Thu, 04 May 2017 15:16:47 +0200
branchtest_diphoton
changeset 174932084f52dada
parent 1686 46fa9082dd6b
parent 1747 061d8bf91506
child 1751 1312137788d5
Merged default into diphoton, enforcing 2 devices and 1 account limit
src/keymanagement.c
src/pEpEngine.c
sync/devicegroup.fsm
sync/generated/sync_fsm.c
sync/generated/sync_fsm.h
sync/skeletons/sync_actions.c
     1.1 --- a/Makefile.conf	Tue Mar 21 15:26:12 2017 +0100
     1.2 +++ b/Makefile.conf	Thu May 04 15:16:47 2017 +0200
     1.3 @@ -10,10 +10,11 @@
     1.4  SYSTEM_DB=/usr/local/share/pEp/system.db
     1.5  PREFIX=$(HOME)
     1.6  YML2PROC=$(HOME)/yml2/yml2proc
     1.7 +YML_OPTS=--encoding=utf8
     1.8  YML_PATH=$(HOME)/yml2
     1.9  ASN1C=asn1c
    1.10  ASN1C_INCLUDE=/opt/local/share/asn1c
    1.11 -#LIBGPGME=/opt/local/lib/libgpgme-pthread.11.dylib
    1.12 +#LIBGPGME=/opt/local/lib/libgpgme.11.dylib
    1.13  
    1.14  # C makros (not environment variables) to overwrite:
    1.15  #
     2.1 --- a/README-OSX.md	Tue Mar 21 15:26:12 2017 +0100
     2.2 +++ b/README-OSX.md	Thu May 04 15:16:47 2017 +0200
     2.3 @@ -1,38 +1,30 @@
     2.4 -# this file is under Creative Commons License 3.0 cc-by-sa
     2.5 +This file is under Creative Commons License 3.0 cc-by-sa
     2.6  
     2.7  # Building for OS X/macOS
     2.8 -
     2.9  See also README.txt for general information.
    2.10  
    2.11 -## Environment
    2.12 +For compiling pEp Engine and its dependencies, make sure you have the LANG variable set. Some source files contain unicode characters, and python (assuming files are ascii) will fail.
    2.13  
    2.14 -`export LANG=en_US.UTF-8` is recommended on OS X.
    2.15 -
    2.16 -`export DYLD_FALLBACK_LIBRARY_PATH=$HOME/lib:/opt/local/lib` will help if you
    2.17 -build in your home and with MacPorts.
    2.18 +```
    2.19 +export LANG=en_US.UTF-8
    2.20 +```
    2.21  
    2.22  ## Dependencies
    2.23  
    2.24  ### MacPorts
    2.25 +[Install MacPorts](https://www.macports.org/install.php) for your version of OS X/macOS.
    2.26  
    2.27 -Install [MacPorts](https://www.macports.org/) for your
    2.28 -[version of OS X/macOS](https://www.macports.org/install.php).
    2.29 -
    2.30 -Note that you need [Xcode installed](https://www.macports.org/install.php)
    2.31 -for MacPorts, and for building the engine. You also need to accept Xcode's EULA.
    2.32 -
    2.33 -#### MacPorts dependencies
    2.34 +If MacPorts is already installed on your machine, but was installed by a different user, make sure your `PATH` variable is set as follows in `~/.profile`:
    2.35  
    2.36  ```
    2.37 -sudo port install mercurial
    2.38 -sudo port install py27-lxml
    2.39 -sudo port install gpgme
    2.40 -sudo port install automake
    2.41 -sudo port install asn1c
    2.42 -sudo port install zlib
    2.43 +export PATH="/opt/local/bin:/opt/local/sbin:$PATH"
    2.44  ```
    2.45  
    2.46 -There are others, please refer to the engine README.txt.
    2.47 +Install dependencies packaged with MacPorts as follows.
    2.48 +
    2.49 +```
    2.50 +sudo port install mercurial py27-lxml gpgme autoconf automake libtool asn1c zlib openssl libiconv cyrus-sasl2
    2.51 +```
    2.52  
    2.53  Make sure that `python` is a version 2 one:
    2.54  
    2.55 @@ -40,10 +32,46 @@
    2.56  sudo port select python python27
    2.57  ```
    2.58  
    2.59 -### Other dependecies
    2.60 +### NetPGP (if not GPGME)
    2.61 +
    2.62 +#### Prepare :
    2.63 +
    2.64 +Get OpenSSL and build/install it as shared library.
    2.65 +
    2.66 +```
    2.67 +wget https://www.openssl.org/source/old/1.0.1/openssl-1.0.1u.tar.gz
    2.68 +tar xvfz openssl-1.0.1u.tar.gz
    2.69 +cd openssl-1.0.1u
    2.70 +./Configure darwin64-x86_64-cc --prefix=$HOME shared
    2.71 +make install
    2.72 +```
    2.73 +
    2.74 +Get and autoconf NetPGP
    2.75 +
    2.76 +```
    2.77 +cd $SRC
    2.78 +hg clone https://cacert.pep.foundation/dev/repos/netpgp-et/
    2.79 +cd netpgp-et
    2.80 +autoreconf -i
    2.81 +```
    2.82 +
    2.83 +#### Build
    2.84 +
    2.85 +Important : LDFLAGS is set to help finding OpenSSL shared lib. If not set,
    2.86 +system's default libcrypto may silently be used instead, causing memory
    2.87 +corruption or crash at runtime.
    2.88 +
    2.89 +```
    2.90 +mkdir netpgp_debug
    2.91 +cd netpgp_debug
    2.92 +$SRC/netpgp-et/configure --with-openssl=$HOME --prefix=$HOME CPPFLAGS=-DDEBUG CXXFLAGS="-g -O0" LDFLAGS="-L${HOME}/lib"
    2.93 +make
    2.94 +make install
    2.95 +```
    2.96 +
    2.97 +### Other Dependecies
    2.98  
    2.99  #### [yml2](https://fdik.org/yml/toolchain)
   2.100 -
   2.101  Install into your home directory:
   2.102  
   2.103  ```
   2.104 @@ -58,16 +86,21 @@
   2.105  functions seem to have been renamed there. Therefore the dynlib from OS X is used.
   2.106  
   2.107  ```
   2.108 -git clone https://github.com/fdik/libetpan libetpan-osx
   2.109 -cd libetpan-osx/
   2.110 -./autogen.sh
   2.111 +git clone https://github.com/fdik/libetpan
   2.112 +cd libetpan
   2.113 +./autogen.sh --prefix "$HOME"
   2.114  make
   2.115 -cp ./src/.libs/libetpan.a ~/lib/
   2.116 +make install
   2.117  ```
   2.118  
   2.119 +## Building pEp Engine
   2.120 +
   2.121  ### Configuration
   2.122 +You can change some defaults by editing `Makefile.conf`. The following variable needs to be set appropriately:
   2.123  
   2.124 -You can change some defaults by editing `Makefile.conf`. But this readme assumes you don't.
   2.125 +```
   2.126 +LIBGPGME=/opt/local/lib/libgpgme.11.dylib
   2.127 +```
   2.128  
   2.129  ### Build
   2.130  
   2.131 @@ -77,30 +110,21 @@
   2.132  make db
   2.133  ```
   2.134  
   2.135 -Done! The result should be (among others):
   2.136 -
   2.137 -```
   2.138 -./src/libpEpEngine.a
   2.139 -./src/libpEpEngine.dylib
   2.140 -```
   2.141 -
   2.142 -### Install
   2.143 -
   2.144 -Install (you might need sudo for some commands, depending on how your system is set up):
   2.145 +### Installation
   2.146  
   2.147  ```
   2.148  make install
   2.149 -make -C db install
   2.150 +sudo make -C db install
   2.151  ```
   2.152  
   2.153 -Since the `system.db` rarely changes, `make -C db install` is not needed for every build.
   2.154 +Since the `system.db` rarely changes, the last step is not needed for every build. If you would like to be able to install the engine without `sudo`, ensure that your user can write the file `/usr/local/share/pEp/system.db`. This is not recommended for production machines.
   2.155  
   2.156  ### Run tests
   2.157  
   2.158 -If you installed the test keys in your keyring (README.txt),
   2.159 -this should just work:
   2.160 +If you installed the test keys in your keyring (see: README.txt), this should just work:
   2.161  
   2.162  ```
   2.163 +cd test
   2.164  make test
   2.165  ```
   2.166  
     3.1 --- a/README.txt	Tue Mar 21 15:26:12 2017 +0100
     3.2 +++ b/README.txt	Thu May 04 15:16:47 2017 +0200
     3.3 @@ -56,7 +56,7 @@
     3.4  
     3.5  * Cyrus SASL, see http://cyrusimap.org/
     3.6  
     3.7 -* GnuPG via GPGME, see https://gnupg.org/
     3.8 +* GnuPG via GPGME, version 1.6.0 or newer, see https://gnupg.org/
     3.9  
    3.10  * NetPGP/p≡p, see https://cacert.pep.foundation/dev/repos/netpgp-et/
    3.11  
     4.1 --- a/build-mac/pEpEngine.xcodeproj/project.pbxproj	Tue Mar 21 15:26:12 2017 +0100
     4.2 +++ b/build-mac/pEpEngine.xcodeproj/project.pbxproj	Thu May 04 15:16:47 2017 +0200
     4.3 @@ -292,7 +292,7 @@
     4.4  		646C414C1D510D8800C63EFF /* baseprotocol.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = baseprotocol.c; path = ../src/baseprotocol.c; sourceTree = "<group>"; };
     4.5  		646C414D1D510D8800C63EFF /* baseprotocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = baseprotocol.h; path = ../src/baseprotocol.h; sourceTree = "<group>"; };
     4.6  		64796A3F1B455AA5004B1C24 /* libpEpEngine.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libpEpEngine.a; sourceTree = BUILT_PRODUCTS_DIR; };
     4.7 -		64951A1B1BE0FCD800B10E71 /* system.db */ = {isa = PBXFileReference; lastKnownFileType = file; name = system.db; path = ../db/system.db; sourceTree = "<group>"; };
     4.8 +		64951A1B1BE0FCD800B10E71 /* system.db */ = {isa = PBXFileReference; lastKnownFileType = text; name = system.db; path = ../db/system.db; sourceTree = "<group>"; };
     4.9  		649DE08A1B45C19100912F72 /* libcurl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libcurl.a; sourceTree = "<group>"; };
    4.10  		64A8264C1B455D0800EECAF0 /* bloblist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bloblist.c; path = ../src/bloblist.c; sourceTree = "<group>"; };
    4.11  		64A8264D1B455D0800EECAF0 /* bloblist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bloblist.h; path = ../src/bloblist.h; sourceTree = "<group>"; };
    4.12 @@ -947,7 +947,7 @@
    4.13  					"$(SRCROOT)",
    4.14  					"$(SRCROOT)/../../netpgp-et/include/",
    4.15  					"$(SRCROOT)/../../netpgp-et/src/",
    4.16 -					"$(SRCROOT)/../../netpgp-et/netpgp-xcode/openssl/include/",
    4.17 +					"$(SRCROOT)/../../OpenSSL-for-iPhone/include",
    4.18  					"$(SRCROOT)/../asn.1/",
    4.19  				);
    4.20  				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
    4.21 @@ -994,7 +994,7 @@
    4.22  					"$(SRCROOT)",
    4.23  					"$(SRCROOT)/../../netpgp-et/include/",
    4.24  					"$(SRCROOT)/../../netpgp-et/src/",
    4.25 -					"$(SRCROOT)/../../netpgp-et/netpgp-xcode/openssl/include/",
    4.26 +					"$(SRCROOT)/../../OpenSSL-for-iPhone/include",
    4.27  					"$(SRCROOT)/../asn.1/",
    4.28  				);
    4.29  				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
     5.1 --- a/src/Makefile	Tue Mar 21 15:26:12 2017 +0100
     5.2 +++ b/src/Makefile	Thu May 04 15:16:47 2017 +0200
     5.3 @@ -1,20 +1,19 @@
     5.4  include ../Makefile.conf
     5.5  
     5.6 -OPENPGP?=GPG
     5.7 +ETPAN_IN?=$(HOME)
     5.8  
     5.9  ifeq ($(BUILD_ON),Darwin)
    5.10  ifeq ($(BUILD_FOR),Darwin)
    5.11  
    5.12  TARGET?=libpEpEngine.dylib
    5.13  MACOSX_VERSION_MIN=10.6
    5.14 -GPGME_IN=$(HOME)
    5.15  LIBGPGME?=libgpgme.dylib
    5.16  CC?=clang -std=c99 -pthread
    5.17  LD?=clang
    5.18 -CFLAGS?=-I$(GPGME_IN)/include -I$(HOME)/include -I/opt/local/include $(OPTIMIZE) -pedantic \
    5.19 -	-DSYSTEM_DB=\"$(SYSTEM_DB)\" -DLIBGPGME=\"$(LIBGPGME)\" -DNDEBUG -I../asn.1 $(EXTRAMACROS)
    5.20 -LDFLAGS?=-lc -shared -arch x86_64 \
    5.21 -	-L$(HOME)/lib -L/usr/lib -L/opt/local/lib -letpan -lsqlite3 -L../asn.1 -lasn1 -lz -liconv
    5.22 +CFLAGS?= -I$(ETPAN_IN)/include -I/opt/local/include $(OPTIMIZE) -pedantic \
    5.23 +	-DSYSTEM_DB=\"$(SYSTEM_DB)\" -I../asn.1 $(EXTRAMACROS)
    5.24 +LDFLAGS?= -lc -shared -arch x86_64 \
    5.25 +	-L$(ETPAN_IN)/lib -L/usr/lib -L/opt/local/lib -letpan -lsqlite3 -L../asn.1 -lasn1 -lz -liconv
    5.26  
    5.27  else
    5.28  $(error don't know how to make for $(BUILD_FOR) on $(BUILD_ON))
    5.29 @@ -24,13 +23,11 @@
    5.30  ifeq ($(BUILD_FOR),Linux)
    5.31  
    5.32  TARGET=libpEpEngine.so
    5.33 -GPGME_IN=$(HOME)
    5.34 -LIBGPGME=libgpgme.so.11
    5.35 +LIBGPGME?=libgpgme.so.11
    5.36  CC=gcc -std=c99
    5.37 -CFLAGS?=-I$(GPGME_IN)/include $(OPTIMIZE) -fPIC -pedantic \
    5.38 -	-DSYSTEM_DB=\"$(SYSTEM_DB)\" -DLIBGPGME=\"$(LIBGPGME)\" \
    5.39 -	-DSQLITE_THREADSAFE=1 -D_GNU_SOURCE -DNDEBUG -I../asn.1 $(EXTRAMACROS)
    5.40 -LDFLAGS?=-L$(GPGME_IN)/lib -shared -lc -ldl -letpan -lpthread -L../asn.1 -lasn1 -luuid
    5.41 +CFLAGS?= $(OPTIMIZE) -fPIC -pedantic -DSYSTEM_DB=\"$(SYSTEM_DB)\" \
    5.42 +	-DSQLITE_THREADSAFE=1 -D_GNU_SOURCE -I../asn.1 $(EXTRAMACROS)
    5.43 +LDFLAGS?= -L$(ETPAN_IN)/lib -shared -lc -ldl -letpan -lpthread -L../asn.1 -lasn1 -luuid
    5.44  
    5.45  else
    5.46  $(error don't know how to make for $(BUILD_FOR) on $(BUILD_ON))
    5.47 @@ -40,14 +37,22 @@
    5.48  $(error don't know how to make for $(BUILD_FOR) on $(BUILD_ON))
    5.49  endif
    5.50  
    5.51 +DEBUG?=NO
    5.52 +ifeq ("$(DEBUG)","NO")
    5.53 +    CFLAGS+= -DNDEBUG
    5.54 +endif
    5.55 +
    5.56 +OPENPGP?=GPG
    5.57  ifeq ("$(OPENPGP)","GPG")
    5.58 -	NO_SOURCE=pgp_netpgp.c
    5.59 -	CFLAGS+= -DUSE_GPG
    5.60 -	LDFLAGS+= -lgpgme
    5.61 +    NO_SOURCE=pgp_netpgp.c
    5.62 +    GPGME_IN?=$(HOME)
    5.63 +    CFLAGS+= -DUSE_GPG -I$(GPGME_IN)/include -DLIBGPGME=\"$(LIBGPGME)\"
    5.64 +    #LDFLAGS+= -L$(GPGME_IN)/lib -lgpgme
    5.65  else ifeq ("$(OPENPGP)","NETPGP")
    5.66 -	NO_SOURCE=pgp_gpg.c
    5.67 -	CFLAGS+= -DUSE_NETPGP
    5.68 -	LDFLAGS+= -lnetpgp -lcurl
    5.69 +    NO_SOURCE=pgp_gpg.c
    5.70 +    NETPGP_IN?=$(HOME)
    5.71 +    CFLAGS+= -DUSE_NETPGP -I$(NETPGP_IN)/include
    5.72 +    LDFLAGS+= -L$(NETPGP_IN)/lib -lnetpgp -lcurl
    5.73  else
    5.74  	$(error Unknown OpenPGP library : $(OPENPGP))
    5.75  endif
     6.1 --- a/src/keymanagement.c	Tue Mar 21 15:26:12 2017 +0100
     6.2 +++ b/src/keymanagement.c	Thu May 04 15:16:47 2017 +0200
     6.3 @@ -179,10 +179,11 @@
     6.4                         downgrade eventually trusted comm_type */
     6.5                      temp_id->comm_type = _comm_type_key;
     6.6                  } else {
     6.7 -                    /* otherwise take stored comm_type as-is */
     6.8 +                    /* otherwise take stored comm_type as-is except if 
     6.9 +                       is unknown or is expired (but key not expired anymore) */
    6.10                      temp_id->comm_type = stored_identity->comm_type;
    6.11 -                    if (temp_id->comm_type == PEP_ct_unknown) {
    6.12 -                        /* except if unknown */
    6.13 +                    if (temp_id->comm_type == PEP_ct_unknown ||
    6.14 +                        temp_id->comm_type == PEP_ct_key_expired) {
    6.15                          temp_id->comm_type = _comm_type_key;
    6.16                      }
    6.17                  }
    6.18 @@ -430,6 +431,19 @@
    6.19      identity->me = true;
    6.20      if(ignore_flags)
    6.21          identity->flags = 0;
    6.22 +    else {
    6.23 +        // test_diphoton : dirty hack to prevent more than one sync enabled account
    6.24 +        identity_list *own_identities = NULL;
    6.25 +        if (_own_identities_retrieve(session, &own_identities, PEP_idf_not_for_sync) == PEP_STATUS_OK)
    6.26 +            // if at least one _other_ own address is sync enabled, set exclusion flag
    6.27 +            for (identity_list *_i = own_identities; _i && _i->ident; _i = _i->next) {
    6.28 +                pEp_identity *me = _i->ident;
    6.29 +                if(me->address && strcmp(me->address, identity->address) != 0)
    6.30 +                identity->flags |= PEP_idf_not_for_sync;
    6.31 +                break;
    6.32 +            }
    6.33 +        free_identity_list(own_identities);
    6.34 +    }
    6.35      
    6.36      if (EMPTYSTR(identity->user_id))
    6.37      {
     7.1 --- a/src/map_asn1.c	Tue Mar 21 15:26:12 2017 +0100
     7.2 +++ b/src/map_asn1.c	Thu May 04 15:16:47 2017 +0200
     7.3 @@ -9,12 +9,15 @@
     7.4          Identity_t *result
     7.5      )
     7.6  {
     7.7 +    bool allocated = !result;
     7.8 +
     7.9      assert(ident);
    7.10      if (!ident)
    7.11          return NULL;
    7.12  
    7.13 -    if (!result)
    7.14 +    if (allocated){
    7.15          result = (Identity_t *) calloc(1, sizeof(Identity_t));
    7.16 +    }
    7.17      assert(result);
    7.18      if (!result)
    7.19          return NULL;
    7.20 @@ -56,26 +59,34 @@
    7.21      if (ident->lang[0]) {
    7.22          int r = OCTET_STRING_fromBuf(&result->lang, ident->lang, 2);
    7.23          assert(r == 0);
    7.24 +        if(r != 0)
    7.25 +            goto enomem;
    7.26      }
    7.27      else {
    7.28          int r = OCTET_STRING_fromBuf(&result->lang, "en", 2);
    7.29          assert(r == 0);
    7.30 +        if(r != 0)
    7.31 +            goto enomem;
    7.32      }
    7.33  
    7.34      return result;
    7.35  
    7.36  enomem:
    7.37 -    ASN_STRUCT_FREE(asn_DEF_Identity, result);
    7.38 +    if (allocated){
    7.39 +        ASN_STRUCT_FREE(asn_DEF_Identity, result);
    7.40 +    }
    7.41      return NULL;
    7.42  }
    7.43  
    7.44  pEp_identity *Identity_to_Struct(Identity_t *ident, pEp_identity *result)
    7.45  {
    7.46 +    bool allocated = !result;
    7.47 +
    7.48      assert(ident);
    7.49      if (!ident)
    7.50          return NULL;
    7.51      
    7.52 -    if (!result)
    7.53 +    if (allocated)
    7.54          result = new_identity(NULL, NULL, NULL, NULL);
    7.55      if (!result)
    7.56          return NULL;
    7.57 @@ -121,7 +132,8 @@
    7.58      return result;
    7.59  
    7.60  enomem:
    7.61 -    free_identity(result);
    7.62 +    if (allocated)
    7.63 +        free_identity(result);
    7.64      return NULL;
    7.65  }
    7.66  
    7.67 @@ -130,11 +142,13 @@
    7.68          IdentityList_t *result
    7.69      )
    7.70  {
    7.71 +    bool allocated = !result;
    7.72 +
    7.73      assert(list);
    7.74      if (!list)
    7.75          return NULL;
    7.76  
    7.77 -    if (!result)
    7.78 +    if (allocated)
    7.79          result = (IdentityList_t *) calloc(1, sizeof(IdentityList_t));
    7.80      assert(result);
    7.81      if (!result)
    7.82 @@ -151,17 +165,20 @@
    7.83      return result;
    7.84  
    7.85  enomem:
    7.86 -    ASN_STRUCT_FREE(asn_DEF_IdentityList, result);
    7.87 +    if (allocated)
    7.88 +        ASN_STRUCT_FREE(asn_DEF_IdentityList, result);
    7.89      return NULL;
    7.90  }
    7.91  
    7.92  identity_list *IdentityList_to_identity_list(IdentityList_t *list, identity_list *result)
    7.93  {
    7.94 +    bool allocated = !result;
    7.95 +
    7.96      assert(list);
    7.97      if (!list)
    7.98          return NULL;
    7.99  
   7.100 -    if (!result)
   7.101 +    if (allocated)
   7.102          result = new_identity_list(NULL);
   7.103      if (!result)
   7.104          return NULL;
   7.105 @@ -177,7 +194,8 @@
   7.106      return result;
   7.107  
   7.108  enomem:
   7.109 -    free_identity_list(result);
   7.110 +    if (allocated)
   7.111 +        free_identity_list(result);
   7.112      return NULL;
   7.113  }
   7.114  
     8.1 --- a/src/message_api.c	Tue Mar 21 15:26:12 2017 +0100
     8.2 +++ b/src/message_api.c	Thu May 04 15:16:47 2017 +0200
     8.3 @@ -2244,88 +2244,6 @@
     8.4  	return PEP_color_no_color;
     8.5  }
     8.6  
     8.7 -static bool _is_valid_hex(const char* hexstr) {
     8.8 -    if (!hexstr)
     8.9 -        return false;
    8.10 -
    8.11 -    const char* curr = hexstr;
    8.12 -    char currchar;
    8.13 -
    8.14 -    for (currchar = *curr; currchar != '\0'; currchar = *(++curr)) {
    8.15 -        if ((currchar >= '0' && currchar <= '9') ||
    8.16 -            (currchar >= 'a' && currchar <= 'f') ||
    8.17 -            (currchar >= 'A' && currchar <= 'F'))
    8.18 -        {
    8.19 -            continue;
    8.20 -        }
    8.21 -        return false;
    8.22 -    }
    8.23 -    return true;
    8.24 -}
    8.25 -
    8.26 -// Returns, in comparison: 1 if fpr1 > fpr2, 0 if equal, -1 if fpr1 < fpr2
    8.27 -static PEP_STATUS _compare_fprs(const char* fpr1, const char* fpr2, int* comparison) {
    8.28 -
    8.29 -    const int _FULL_FINGERPRINT_LENGTH = 40;
    8.30 -    const int _ASCII_LOWERCASE_OFFSET = 32;
    8.31 -
    8.32 -    size_t fpr1_len = strlen(fpr1);
    8.33 -    size_t fpr2_len = strlen(fpr2);
    8.34 -
    8.35 -    if (fpr1_len != _FULL_FINGERPRINT_LENGTH || fpr2_len != _FULL_FINGERPRINT_LENGTH)
    8.36 -        return PEP_TRUSTWORDS_FPR_WRONG_LENGTH;
    8.37 -
    8.38 -    if (!_is_valid_hex(fpr1) || !_is_valid_hex(fpr2))
    8.39 -        return PEP_ILLEGAL_VALUE;
    8.40 -
    8.41 -    const char* fpr1_curr = fpr1;
    8.42 -    const char* fpr2_curr = fpr2;
    8.43 -
    8.44 -    char current;
    8.45 -
    8.46 -    // Advance past leading zeros.
    8.47 -    for (current = *fpr1_curr; current != '0' && current != '\0'; current = *(++fpr1_curr), fpr1_len--);
    8.48 -    for (current = *fpr2_curr; current != '0' && current != '\0'; current = *(++fpr2_curr), fpr2_len--);
    8.49 -
    8.50 -    if (fpr1_len == fpr2_len) {
    8.51 -        char digit1;
    8.52 -        char digit2;
    8.53 -
    8.54 -        while (fpr1_curr && *fpr1_curr != '\0') {
    8.55 -            digit1 = *fpr1_curr++;
    8.56 -            digit2 = *fpr2_curr++;
    8.57 -
    8.58 -            // Adjust for case-insensitive compare
    8.59 -            if (digit1 >= 'a' && digit1 <= 'f')
    8.60 -                digit1 -= _ASCII_LOWERCASE_OFFSET;
    8.61 -            if (digit2 >= 'a' && digit2 <= 'f')
    8.62 -                digit2 -= _ASCII_LOWERCASE_OFFSET;
    8.63 -
    8.64 -            // We take advantage of the fact that 'a'-'f' are larger
    8.65 -            // integer values in the ASCII table than '0'-'9'.
    8.66 -            // This allows us to compare digits directly.
    8.67 -            if (digit1 > digit2) {
    8.68 -                *comparison = 1;
    8.69 -                return PEP_STATUS_OK;
    8.70 -            } else if (digit1 < digit2) {
    8.71 -                *comparison = -1;
    8.72 -                return PEP_STATUS_OK;
    8.73 -            }
    8.74 -
    8.75 -            // pointers already advanced above. Keep going.
    8.76 -        }
    8.77 -        *comparison = 0;
    8.78 -        return PEP_STATUS_OK;
    8.79 -    }
    8.80 -    else if (fpr1_len > fpr2_len) {
    8.81 -        *comparison = 1;
    8.82 -        return PEP_STATUS_OK;
    8.83 -    }
    8.84 -    // Otherwise, fpr1_len < fpr2_len
    8.85 -    *comparison = -1;
    8.86 -    return PEP_STATUS_OK;
    8.87 -}
    8.88 -
    8.89  DYNAMIC_API PEP_STATUS get_trustwords(
    8.90      PEP_SESSION session, const pEp_identity* id1, const pEp_identity* id2,
    8.91      const char* lang, char **words, size_t *wsize, bool full
    8.92 @@ -2361,7 +2279,7 @@
    8.93      size_t second_wsize = 0;
    8.94  
    8.95      int fpr_comparison = -255;
    8.96 -    PEP_STATUS status = _compare_fprs(source1, source2, &fpr_comparison);
    8.97 +    PEP_STATUS status = _compare_fprs(source1, strlen(source1), source2, strlen(source2), &fpr_comparison);
    8.98      if (status != PEP_STATUS_OK)
    8.99          return status;
   8.100  
   8.101 @@ -2549,6 +2467,12 @@
   8.102      PEP_decrypt_flags_t *flags
   8.103  )
   8.104  {
   8.105 +    assert(mimetext);
   8.106 +    assert(mime_plaintext);
   8.107 +    assert(keylist);
   8.108 +    assert(rating);
   8.109 +    assert(flags);
   8.110 +
   8.111      PEP_STATUS status = PEP_STATUS_OK;
   8.112      message* tmp_msg = NULL;
   8.113      message* dec_msg = NULL;
   8.114 @@ -2564,11 +2488,32 @@
   8.115                                                  rating,
   8.116                                                  flags);
   8.117                                                  
   8.118 +    if (!dec_msg && (decrypt_status == PEP_UNENCRYPTED || decrypt_status == PEP_VERIFIED)) {
   8.119 +        dec_msg = message_dup(tmp_msg);
   8.120 +    }
   8.121 +        
   8.122 +    if (decrypt_status > PEP_CANNOT_DECRYPT_UNKNOWN)
   8.123 +    {
   8.124 +        status = decrypt_status;
   8.125 +        goto pep_error;
   8.126 +    }
   8.127 +
   8.128 +    assert(dec_msg);
   8.129 +    
   8.130 +    if (!dec_msg) {
   8.131 +        status = PEP_UNKNOWN_ERROR;
   8.132 +        goto pep_error;
   8.133 +    }
   8.134 +
   8.135      status = mime_encode_message(dec_msg, false, mime_plaintext);
   8.136  
   8.137      if (status == PEP_STATUS_OK)
   8.138 +    {
   8.139 +        free(tmp_msg);
   8.140 +        free(dec_msg);
   8.141          return decrypt_status;
   8.142 -        
   8.143 +    }
   8.144 +    
   8.145  pep_error:
   8.146      free_message(tmp_msg);
   8.147      free_message(dec_msg);
   8.148 @@ -2606,6 +2551,12 @@
   8.149      if (status != PEP_STATUS_OK)
   8.150          goto pep_error;
   8.151  
   8.152 +
   8.153 +    if (!enc_msg) {
   8.154 +        status = PEP_UNKNOWN_ERROR;
   8.155 +        goto pep_error;
   8.156 +    }
   8.157 +
   8.158      status = mime_encode_message(enc_msg, false, mime_ciphertext);
   8.159  
   8.160  pep_error:
   8.161 @@ -2644,6 +2595,11 @@
   8.162                                        flags);
   8.163      if (status != PEP_STATUS_OK)
   8.164          goto pep_error;
   8.165 + 
   8.166 +    if (!enc_msg) {
   8.167 +        status = PEP_UNKNOWN_ERROR;
   8.168 +        goto pep_error;
   8.169 +    }
   8.170  
   8.171      status = mime_encode_message(enc_msg, false, mime_ciphertext);
   8.172  
     9.1 --- a/src/pEpEngine.c	Tue Mar 21 15:26:12 2017 +0100
     9.2 +++ b/src/pEpEngine.c	Thu May 04 15:16:47 2017 +0200
     9.3 @@ -1318,6 +1318,20 @@
     9.4      if (!(session && identity && identity->address && identity->user_id))
     9.5          return PEP_ILLEGAL_VALUE;
     9.6  
     9.7 +    // test_diphoton : dirty hack to prevent more than one sync enabled account
     9.8 +    if (flags & PEP_idf_not_for_sync){
     9.9 +        identity_list *own_identities = NULL;
    9.10 +        if (_own_identities_retrieve(session, &own_identities, PEP_idf_not_for_sync) == PEP_STATUS_OK)
    9.11 +            // if at least one _other_ own address is sync enabled, prevent unseting exclusion
    9.12 +            for (identity_list *_i = own_identities; _i && _i->ident; _i = _i->next) {
    9.13 +                pEp_identity *me = _i->ident;
    9.14 +                if(me->address && strcmp(me->address, identity->address) != 0)
    9.15 +                flags &= ~PEP_idf_not_for_sync;
    9.16 +                break;
    9.17 +            }
    9.18 +        free_identity_list(own_identities);
    9.19 +    }
    9.20 +
    9.21      sqlite3_reset(session->unset_identity_flags);
    9.22      sqlite3_bind_int(session->unset_identity_flags, 1, flags);
    9.23      sqlite3_bind_text(session->unset_identity_flags, 2, identity->address, -1,
    9.24 @@ -2267,5 +2281,8 @@
    9.25      );
    9.26      assert(int_result == SQLITE_OK);
    9.27  
    9.28 +    if (int_result != SQLITE_OK)
    9.29 +        return PEP_UNKNOWN_ERROR;
    9.30 +
    9.31      return PEP_STATUS_OK;
    9.32  }
    10.1 --- a/src/pEp_internal.h	Tue Mar 21 15:26:12 2017 +0100
    10.2 +++ b/src/pEp_internal.h	Thu May 04 15:16:47 2017 +0200
    10.3 @@ -189,7 +189,109 @@
    10.4  }
    10.5  #endif
    10.6  
    10.7 +typedef enum _normalize_hex_rest_t {
    10.8 +    accept_hex,
    10.9 +    ignore_hex,
   10.10 +    reject_hex
   10.11 +} normalize_hex_res_t;
   10.12 +
   10.13 +static inline normalize_hex_res_t _normalize_hex(char *hex) 
   10.14 +{
   10.15 +    if (*hex >= '0' && *hex <= '9')
   10.16 +        return accept_hex;
   10.17 +
   10.18 +    if (*hex >= 'A' && *hex <= 'F') {
   10.19 +        *hex += 'a' - 'A';
   10.20 +        return accept_hex;
   10.21 +    }
   10.22 +
   10.23 +    if (*hex >= 'a' && *hex <= 'f') 
   10.24 +        return accept_hex;
   10.25 +
   10.26 +    if (*hex == ' ') 
   10.27 +        return ignore_hex;
   10.28 +
   10.29 +    return reject_hex;
   10.30 +}
   10.31 +
   10.32  // Space tolerant and case insensitive fingerprint string compare
   10.33 +static inline PEP_STATUS _compare_fprs(
   10.34 +        const char* fpra,
   10.35 +        size_t fpras,
   10.36 +        const char* fprb,
   10.37 +        size_t fprbs,
   10.38 +        int* comparison)
   10.39 +{
   10.40 +
   10.41 +    size_t ai = 0;
   10.42 +    size_t bi = 0;
   10.43 +    size_t significant = 0;
   10.44 +    int _comparison = 0;
   10.45 +    const int _FULL_FINGERPRINT_LENGTH = 40;
   10.46 +   
   10.47 +    // First compare every non-ignored chars until an end is reached
   10.48 +    while(ai < fpras && bi < fprbs)
   10.49 +    {
   10.50 +        char fprac = fpra[ai];
   10.51 +        char fprbc = fprb[bi];
   10.52 +        normalize_hex_res_t fprah = _normalize_hex(&fprac);
   10.53 +        normalize_hex_res_t fprbh = _normalize_hex(&fprbc);
   10.54 +
   10.55 +        if(fprah == reject_hex || fprbh == reject_hex)
   10.56 +            return PEP_ILLEGAL_VALUE;
   10.57 +
   10.58 +        if ( fprah == ignore_hex )
   10.59 +        {
   10.60 +            ai++;
   10.61 +        }
   10.62 +        else if ( fprbh == ignore_hex )
   10.63 +        {
   10.64 +            bi++;
   10.65 +        }
   10.66 +        else
   10.67 +        {
   10.68 +            if(fprac != fprbc && _comparison == 0 )
   10.69 +            {
   10.70 +                _comparison = fprac > fprbc ? 1 : -1;
   10.71 +            }
   10.72 +
   10.73 +            significant++;
   10.74 +            ai++;
   10.75 +            bi++;
   10.76 +
   10.77 +        } 
   10.78 +    }
   10.79 +
   10.80 +    // Bail out if we didn't got enough significnt chars
   10.81 +    if (significant != _FULL_FINGERPRINT_LENGTH )
   10.82 +        return PEP_TRUSTWORDS_FPR_WRONG_LENGTH;
   10.83 +
   10.84 +    // Then purge remaining chars, all must be ignored chars
   10.85 +    while ( ai < fpras )
   10.86 +    {
   10.87 +        char fprac = fpra[ai];
   10.88 +        normalize_hex_res_t fprah = _normalize_hex(&fprac);
   10.89 +        if( fprah == reject_hex )
   10.90 +            return PEP_ILLEGAL_VALUE;
   10.91 +        if ( fprah != ignore_hex )
   10.92 +            return PEP_TRUSTWORDS_FPR_WRONG_LENGTH;
   10.93 +        ai++;
   10.94 +    }
   10.95 +    while ( bi < fprbs )
   10.96 +    {
   10.97 +        char fprbc = fprb[bi];
   10.98 +        normalize_hex_res_t fprbh = _normalize_hex(&fprbc);
   10.99 +        if( fprbh == reject_hex )
  10.100 +            return PEP_ILLEGAL_VALUE;
  10.101 +        if ( fprbh != ignore_hex )
  10.102 +            return PEP_TRUSTWORDS_FPR_WRONG_LENGTH;
  10.103 +        bi++;
  10.104 +    }
  10.105 +
  10.106 +    *comparison = _comparison;
  10.107 +    return PEP_STATUS_OK;
  10.108 +}
  10.109 +
  10.110  static inline int _same_fpr(
  10.111          const char* fpra,
  10.112          size_t fpras,
  10.113 @@ -197,35 +299,10 @@
  10.114          size_t fprbs
  10.115      )
  10.116  {
  10.117 -    size_t ai = 0;
  10.118 -    size_t bi = 0;
  10.119 -    
  10.120 -    do
  10.121 -    {
  10.122 -        if(fpra[ai] == 0 || fprb[bi] == 0)
  10.123 -        {
  10.124 -            return 0;
  10.125 -        }
  10.126 -        else if(fpra[ai] == ' ')
  10.127 -        {
  10.128 -            ai++;
  10.129 -        }
  10.130 -        else if(fprb[bi] == ' ')
  10.131 -        {
  10.132 -            bi++;
  10.133 -        }
  10.134 -        else if(toupper(fpra[ai]) == toupper(fprb[bi]))
  10.135 -        {
  10.136 -            ai++;
  10.137 -            bi++;
  10.138 -        }
  10.139 -        else
  10.140 -        {
  10.141 -            return 0;
  10.142 -        }
  10.143 -        
  10.144 -    }
  10.145 -    while(ai < fpras && bi < fprbs);
  10.146 -    
  10.147 -    return ai == fpras && bi == fprbs;
  10.148 +    // illegal values are ignored, and considered not same.
  10.149 +    int comparison = 1;
  10.150 +
  10.151 +    _compare_fprs(fpra, fpras, fprb, fprbs, &comparison);
  10.152 +
  10.153 +    return comparison == 0;
  10.154  }
    11.1 --- a/src/pgp_netpgp.c	Tue Mar 21 15:26:12 2017 +0100
    11.2 +++ b/src/pgp_netpgp.c	Thu May 04 15:16:47 2017 +0200
    11.3 @@ -227,7 +227,7 @@
    11.4          return 0;
    11.5  
    11.6      for (n = 0, i = 0 ; i < length; i += 2) {
    11.7 -        n += snprintf(&((*str)[n]), 5, "%02x%02x", fpr[i], fpr[i+1]);
    11.8 +        n += snprintf(&((*str)[n]), 5, "%02X%02X", fpr[i], fpr[i+1]);
    11.9      }
   11.10  
   11.11      return 1;
   11.12 @@ -273,12 +273,14 @@
   11.13  static PEP_STATUS _validation_results(
   11.14          netpgp_t *netpgp,
   11.15          pgp_validation_t *vresult,
   11.16 -        stringlist_t **_keylist
   11.17 +        stringlist_t **keylist
   11.18      )
   11.19  {
   11.20      time_t    now;
   11.21      time_t    t;
   11.22  
   11.23 +    *keylist = NULL;
   11.24 +
   11.25      now = time(NULL);
   11.26      if (now < vresult->birthtime) {
   11.27          // signature is not valid yet
   11.28 @@ -292,14 +294,17 @@
   11.29      if (vresult->validc && vresult->valid_sigs &&
   11.30          !vresult->invalidc && !vresult->unknownc ) {
   11.31          
   11.32 +        stringlist_t *_keylist;
   11.33 +
   11.34          // caller responsible to free
   11.35 -        *_keylist = new_stringlist(NULL);
   11.36 -        assert(*_keylist);
   11.37 -        if (*_keylist == NULL) {
   11.38 +        _keylist = new_stringlist(NULL);
   11.39 +        assert(_keylist);
   11.40 +        if (_keylist == NULL) {
   11.41              return PEP_OUT_OF_MEMORY;
   11.42          }
   11.43          
   11.44 -        stringlist_t *k = *_keylist;
   11.45 +        stringlist_t *k = _keylist;
   11.46 +        unsigned c = 0;
   11.47          for (unsigned n = 0; n < vresult->validc; ++n) {
   11.48              unsigned from = 0;
   11.49              const pgp_key_t	 *signer;
   11.50 @@ -315,21 +320,31 @@
   11.51                             signer->pubkeyfpr.fingerprint,
   11.52                             signer->pubkeyfpr.length);
   11.53              else
   11.54 -                return PEP_VERIFY_NO_KEY;
   11.55 +                continue;
   11.56  
   11.57 -            if (fprstr == NULL)
   11.58 +            if (fprstr == NULL){
   11.59 +                free_stringlist(_keylist);
   11.60                  return PEP_OUT_OF_MEMORY;
   11.61 +            }
   11.62  
   11.63              k = stringlist_add(k, fprstr);
   11.64  
   11.65              free(fprstr);
   11.66  
   11.67              if(!k){
   11.68 -                free_stringlist(*_keylist);
   11.69 +                free_stringlist(_keylist);
   11.70                  return PEP_OUT_OF_MEMORY;
   11.71              }
   11.72 +
   11.73 +            c++;
   11.74          }
   11.75 -        return PEP_STATUS_OK;
   11.76 +        if(c > 0) {
   11.77 +            *keylist = _keylist;
   11.78 +            return PEP_STATUS_OK;
   11.79 +        }
   11.80 +
   11.81 +        free_stringlist(_keylist);
   11.82 +        return PEP_VERIFY_NO_KEY;
   11.83      }
   11.84      if (vresult->validc + vresult->invalidc + vresult->unknownc == 0) {
   11.85          // No signatures found - is this memory signed?
   11.86 @@ -379,11 +394,14 @@
   11.87      pgp_validation_t *vresult = malloc(sizeof(pgp_validation_t));
   11.88      memset(vresult, 0x0, sizeof(pgp_validation_t));
   11.89  
   11.90 +    key_id_t *recipients_key_ids = NULL;
   11.91 +    unsigned recipients_count = 0;
   11.92 +
   11.93      pgp_memory_t *mem = pgp_decrypt_and_validate_buf(netpgp.io, vresult, ctext, csize,
   11.94                  netpgp.secring, netpgp.pubring,
   11.95                  _armoured(ctext, csize, ARMOR_HEAD),
   11.96 -                0 /* sshkeys */,
   11.97 -                NULL, -1, NULL  /* pass fp,attempts,cb */);
   11.98 +                 &recipients_key_ids, &recipients_count);
   11.99 +
  11.100      if (mem == NULL) {
  11.101          result = PEP_OUT_OF_MEMORY;
  11.102          goto unlock_netpgp;
  11.103 @@ -405,9 +423,12 @@
  11.104  
  11.105      if (result == PEP_DECRYPTED) {
  11.106          result = _validation_results(&netpgp, vresult, &_keylist);
  11.107 -        if (result == PEP_DECRYPTED) {
  11.108 -            //no change
  11.109 -        } else if (result == PEP_VERIFY_NO_KEY) {
  11.110 +        if (result == PEP_DECRYPTED ||
  11.111 +            result == PEP_VERIFY_NO_KEY) {
  11.112 +            if((_keylist = new_stringlist("")) == NULL) {
  11.113 +                result = PEP_OUT_OF_MEMORY;
  11.114 +                goto free_ptext;
  11.115 +            }
  11.116              result = PEP_DECRYPTED;
  11.117          }else if (result != PEP_STATUS_OK) {
  11.118              goto free_ptext;
  11.119 @@ -416,14 +437,47 @@
  11.120          }
  11.121      }
  11.122  
  11.123 +    stringlist_t *k = _keylist;
  11.124 +    for (unsigned n = 0; n < recipients_count; ++n) {
  11.125 +        unsigned from = 0;
  11.126 +        const pgp_key_t	 *rcpt;
  11.127 +        char *fprstr = NULL;
  11.128 +        key_id_t *keyid = &recipients_key_ids[n];
  11.129 +
  11.130 +        rcpt = pgp_getkeybyid(netpgp.io, netpgp.pubring,
  11.131 +                                *keyid, &from, NULL, NULL,
  11.132 +                                0, 0); /* check neither revocation nor expiry*/
  11.133 +        if(rcpt)
  11.134 +            fpr_to_str(&fprstr,
  11.135 +                       rcpt->pubkeyfpr.fingerprint,
  11.136 +                       rcpt->pubkeyfpr.length);
  11.137 +        else
  11.138 +            // if no key found put ID instead of fpr
  11.139 +            fpr_to_str(&fprstr,
  11.140 +                       *keyid,
  11.141 +                       sizeof(key_id_t));
  11.142 +
  11.143 +        if (fprstr == NULL){
  11.144 +            result = PEP_OUT_OF_MEMORY;
  11.145 +            goto free_keylist;
  11.146 +        }
  11.147 +
  11.148 +        k = stringlist_add_unique(k, fprstr);
  11.149 +
  11.150 +        free(fprstr);
  11.151 +
  11.152 +        if(!k){
  11.153 +            result = PEP_OUT_OF_MEMORY;
  11.154 +            goto free_keylist;
  11.155 +        }
  11.156 +    }
  11.157 +
  11.158      if (result == PEP_DECRYPTED_AND_VERIFIED
  11.159          || result == PEP_DECRYPTED) {
  11.160          *ptext = _ptext;
  11.161          *psize = _psize;
  11.162          (*ptext)[*psize] = 0; // safeguard for naive users
  11.163 -        if (result == PEP_DECRYPTED_AND_VERIFIED) {
  11.164 -            *keylist = _keylist;
  11.165 -        }
  11.166 +        *keylist = _keylist;
  11.167  
  11.168          /* _ptext and _keylist ownership transfer, don't free */
  11.169          goto free_pgp;
  11.170 @@ -521,7 +575,6 @@
  11.171          goto free_pgp;
  11.172      }
  11.173  
  11.174 -free_keylist:
  11.175      free_stringlist(_keylist);
  11.176  
  11.177  free_pgp:
  11.178 @@ -536,14 +589,14 @@
  11.179      return result;
  11.180  }
  11.181  
  11.182 -PEP_STATUS pgp_encrypt_and_sign(
  11.183 +static PEP_STATUS _encrypt_and_sign(
  11.184      PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  11.185 -    size_t psize, char **ctext, size_t *csize
  11.186 +    size_t psize, char **ctext, size_t *csize, bool do_sign
  11.187      )
  11.188  {
  11.189      pgp_key_t *signer = NULL;
  11.190      pgp_seckey_t *seckey = NULL;
  11.191 -    pgp_memory_t *signedmem;
  11.192 +    pgp_memory_t *signedmem = NULL;
  11.193      pgp_memory_t *cmem;
  11.194      const char *hashalg;
  11.195      pgp_keyring_t *rcpts;
  11.196 @@ -631,25 +684,38 @@
  11.197  
  11.198      hashalg = netpgp_getvar(&netpgp, "hash");
  11.199  
  11.200 -    // Sign data
  11.201 -    signedmem = pgp_sign_buf(netpgp.io, ptext, psize, seckey,
  11.202 -                time(NULL), /* birthtime */
  11.203 -                0 /* duration */,
  11.204 -                hashalg,
  11.205 -                0 /* armored */,
  11.206 -                0 /* cleartext */);
  11.207 +    const char *stext;
  11.208 +    size_t ssize;
  11.209 +    unsigned encrypt_raw_packet;
  11.210 +   
  11.211 +    if (do_sign) {  
  11.212 +        // Sign data
  11.213 +        signedmem = pgp_sign_buf(netpgp.io, ptext, psize, seckey,
  11.214 +                    time(NULL), /* birthtime */
  11.215 +                    0 /* duration */,
  11.216 +                    hashalg,
  11.217 +                    0 /* armored */,
  11.218 +                    0 /* cleartext */);
  11.219  
  11.220 -    if (!signedmem) {
  11.221 -        result = PEP_UNENCRYPTED;
  11.222 -        goto free_rcpts;
  11.223 +        if (!signedmem) {
  11.224 +            result = PEP_UNENCRYPTED;
  11.225 +            goto free_rcpts;
  11.226 +        }
  11.227 +        stext = (char*) pgp_mem_data(signedmem);
  11.228 +        ssize = pgp_mem_len(signedmem);
  11.229 +        encrypt_raw_packet = 1 /* takes raw OpenPGP message */;
  11.230 +    } else {
  11.231 +        stext = ptext;
  11.232 +        ssize = psize;
  11.233 +        encrypt_raw_packet = 0 /* not a raw OpenPGP message */;
  11.234      }
  11.235  
  11.236 -    // Encrypt signed data
  11.237 +    // Encrypt (maybe) signed data
  11.238  
  11.239 -    cmem = pgp_encrypt_buf(netpgp.io, pgp_mem_data(signedmem),
  11.240 -            pgp_mem_len(signedmem), rcpts, 1 /* armored */,
  11.241 +    cmem = pgp_encrypt_buf(netpgp.io, stext,
  11.242 +            ssize, rcpts, 1 /* armored */,
  11.243              netpgp_getvar(&netpgp, "cipher"),
  11.244 -            1 /* takes raw OpenPGP message */);
  11.245 +            encrypt_raw_packet);
  11.246  
  11.247      if (cmem == NULL) {
  11.248          result = PEP_OUT_OF_MEMORY;
  11.249 @@ -678,7 +744,9 @@
  11.250  free_cmem :
  11.251      pgp_memory_free(cmem);
  11.252  free_signedmem :
  11.253 -    pgp_memory_free(signedmem);
  11.254 +    if (do_sign) {
  11.255 +        pgp_memory_free(signedmem);
  11.256 +    }
  11.257  free_rcpts :
  11.258      pgp_keyring_free(rcpts);
  11.259  unlock_netpgp:
  11.260 @@ -687,6 +755,29 @@
  11.261      return result;
  11.262  }
  11.263  
  11.264 +PEP_STATUS pgp_encrypt_and_sign(
  11.265 +    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  11.266 +    size_t psize, char **ctext, size_t *csize
  11.267 +    )
  11.268 +{
  11.269 +    PEP_STATUS result;
  11.270 +    result = _encrypt_and_sign(session, keylist, ptext, psize, ctext, csize,
  11.271 +                               true);
  11.272 +    return result;
  11.273 +}
  11.274 +
  11.275 +PEP_STATUS pgp_encrypt_only(
  11.276 +        PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  11.277 +        size_t psize, char **ctext, size_t *csize
  11.278 +    )
  11.279 +{
  11.280 +    PEP_STATUS result;
  11.281 +    result = _encrypt_and_sign(session, keylist, ptext, psize, ctext, csize,
  11.282 +                               false);
  11.283 +    return result;
  11.284 +}
  11.285 +
  11.286 +
  11.287  PEP_STATUS pgp_generate_keypair(
  11.288      PEP_SESSION session, pEp_identity *identity
  11.289      )
  11.290 @@ -857,7 +948,8 @@
  11.291  PEP_STATUS pgp_import_keydata(
  11.292          PEP_SESSION session,
  11.293          const char *key_data,
  11.294 -        size_t size
  11.295 +        size_t size,
  11.296 +        identity_list **private_idents
  11.297      )
  11.298  {
  11.299      pgp_memory_t *mem;
  11.300 @@ -867,6 +959,11 @@
  11.301      assert(session);
  11.302      assert(key_data);
  11.303  
  11.304 +    // reporting imported private keys not supported
  11.305 +    // stub code to be reomoved
  11.306 +    if(private_idents)
  11.307 +        *private_idents = NULL;
  11.308 +
  11.309      if(!session || !key_data)
  11.310          return PEP_ILLEGAL_VALUE;
  11.311  
  11.312 @@ -947,7 +1044,8 @@
  11.313  }
  11.314  
  11.315  PEP_STATUS pgp_export_keydata(
  11.316 -    PEP_SESSION session, const char *fprstr, char **key_data, size_t *size
  11.317 +    PEP_SESSION session, const char *fprstr, char **key_data, size_t *size,
  11.318 +    bool secret
  11.319      )
  11.320  {
  11.321      pgp_key_t *key;
  11.322 @@ -963,6 +1061,12 @@
  11.323      assert(key_data);
  11.324      assert(size);
  11.325  
  11.326 +    // TODO : support export secret key
  11.327 +    // crashing stub until export secret supported
  11.328 +    assert(!secret);
  11.329 +    if (secret)
  11.330 +        return PEP_ILLEGAL_VALUE;
  11.331 +
  11.332      if (!session || !fprstr || !key_data || !size)
  11.333          return PEP_ILLEGAL_VALUE;
  11.334  
  11.335 @@ -1091,9 +1195,9 @@
  11.336  
  11.337      result = pgp_import_keydata(session,
  11.338                                  answer.memory,
  11.339 -                                answer.size);
  11.340 +                                answer.size,
  11.341 +                                NULL);
  11.342  
  11.343 -free_answer:
  11.344      free(answer.memory);
  11.345  free_request:
  11.346      free(request);
  11.347 @@ -1109,7 +1213,7 @@
  11.348  
  11.349  typedef PEP_STATUS (*find_key_cb_t)(void*, pgp_key_t *);
  11.350  
  11.351 -static PEP_STATUS find_keys_do(
  11.352 +static PEP_STATUS find_keys_do(pgp_keyring_t* keyring,
  11.353          const char *pattern, find_key_cb_t cb, void* cb_arg)
  11.354  {
  11.355      uint8_t fpr[PGP_FINGERPRINT_SIZE];
  11.356 @@ -1126,7 +1230,7 @@
  11.357          // Only one fingerprint can match
  11.358          if ((key = (pgp_key_t *)pgp_getkeybyfpr(
  11.359                          netpgp.io,
  11.360 -                        (pgp_keyring_t *)netpgp.pubring,
  11.361 +                        keyring,
  11.362                          (const uint8_t *)fpr, length,
  11.363                          &from,
  11.364                          NULL, 0, 0)) == NULL) {
  11.365 @@ -1142,7 +1246,7 @@
  11.366          result = PEP_KEY_NOT_FOUND;
  11.367          while((key = (pgp_key_t *)pgp_getnextkeybyname(
  11.368                          netpgp.io,
  11.369 -                        (pgp_keyring_t *)netpgp.pubring,
  11.370 +                        keyring,
  11.371  			            (const char *)pattern,
  11.372                          &from)) != NULL) {
  11.373  
  11.374 @@ -1261,7 +1365,8 @@
  11.375      }
  11.376      _k = _keylist;
  11.377  
  11.378 -    result = find_keys_do(pattern, &add_key_fpr_to_stringlist, &_k);
  11.379 +    result = find_keys_do((pgp_keyring_t *)netpgp.pubring,
  11.380 +                          pattern, &add_key_fpr_to_stringlist, &_k);
  11.381  
  11.382      if (result == PEP_STATUS_OK) {
  11.383          *keylist = _keylist;
  11.384 @@ -1269,7 +1374,6 @@
  11.385          goto unlock_netpgp;
  11.386      }
  11.387  
  11.388 -free_keylist:
  11.389      free_stringlist(_keylist);
  11.390  
  11.391  unlock_netpgp:
  11.392 @@ -1350,7 +1454,8 @@
  11.393          goto free_encoded_keys;
  11.394      }
  11.395  
  11.396 -    result = find_keys_do(pattern, &send_key_cb, (void*)encoded_keys);
  11.397 +    result = find_keys_do((pgp_keyring_t *)netpgp.pubring,
  11.398 +                          pattern, &send_key_cb, (void*)encoded_keys);
  11.399  
  11.400      pthread_mutex_unlock(&netpgp_mutex);
  11.401  
  11.402 @@ -1770,12 +1875,12 @@
  11.403  
  11.404      PEP_STATUS result;
  11.405  
  11.406 -    result = find_keys_do(pattern, &add_keyinfo_to_stringpair_list, (void*)keyinfo_list);
  11.407 +    result = find_keys_do((pgp_keyring_t *)netpgp.pubring,
  11.408 +                          pattern, &add_keyinfo_to_stringpair_list, (void*)keyinfo_list);
  11.409  
  11.410      if (!keyinfo_list)
  11.411          result = PEP_KEY_NOT_FOUND;
  11.412  
  11.413 -unlock_netpgp:
  11.414      pthread_mutex_unlock(&netpgp_mutex);
  11.415  
  11.416      return result;
  11.417 @@ -1811,7 +1916,8 @@
  11.418      }
  11.419      _k = _keylist;
  11.420  
  11.421 -    result = find_keys_do(pattern, &add_secret_key_fpr_to_stringlist, &_k);
  11.422 +    result = find_keys_do((pgp_keyring_t *)netpgp.secring,
  11.423 +                          pattern, &add_secret_key_fpr_to_stringlist, &_k);
  11.424  
  11.425      if (result == PEP_STATUS_OK) {
  11.426          *keylist = _keylist;
  11.427 @@ -1819,7 +1925,6 @@
  11.428          goto unlock_netpgp;
  11.429      }
  11.430  
  11.431 -free_keylist:
  11.432      free_stringlist(_keylist);
  11.433  
  11.434  unlock_netpgp:
    12.1 --- a/src/pgp_netpgp.h	Tue Mar 21 15:26:12 2017 +0100
    12.2 +++ b/src/pgp_netpgp.h	Thu May 04 15:16:47 2017 +0200
    12.3 @@ -1,5 +1,4 @@
    12.4  // This file is under GNU General Public License 3.0
    12.5 -// see LICENSE.txt
    12.6  
    12.7  #pragma once
    12.8  
    12.9 @@ -19,6 +18,13 @@
   12.10          size_t psize, char **ctext, size_t *csize
   12.11      );
   12.12  
   12.13 +
   12.14 +PEP_STATUS pgp_encrypt_only(
   12.15 +        PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
   12.16 +        size_t psize, char **ctext, size_t *csize
   12.17 +    );
   12.18 +
   12.19 +
   12.20  PEP_STATUS pgp_verify_text(
   12.21          PEP_SESSION session, const char *text, size_t size,
   12.22          const char *signature, size_t sig_size, stringlist_t **keylist
   12.23 @@ -27,7 +33,8 @@
   12.24  PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fpr);
   12.25  
   12.26  PEP_STATUS pgp_export_keydata(
   12.27 -        PEP_SESSION session, const char *fpr, char **key_data, size_t *size
   12.28 +        PEP_SESSION session, const char *fpr, char **key_data, size_t *size,
   12.29 +        bool secret
   12.30      );
   12.31  
   12.32  PEP_STATUS pgp_find_keys(
   12.33 @@ -49,7 +56,7 @@
   12.34      );
   12.35  
   12.36  PEP_STATUS pgp_import_keydata(PEP_SESSION session, const char *key_data,
   12.37 -        size_t size);
   12.38 +        size_t size, identity_list **private_idents);
   12.39  
   12.40  PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern);
   12.41  PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern);
    13.1 --- a/src/stringlist.c	Tue Mar 21 15:26:12 2017 +0100
    13.2 +++ b/src/stringlist.c	Thu May 04 15:16:47 2017 +0200
    13.3 @@ -53,6 +53,39 @@
    13.4      return dst;
    13.5  }
    13.6  
    13.7 +static bool _stringlist_add_first(
    13.8 +        stringlist_t *stringlist,
    13.9 +        stringlist_t **result,
   13.10 +        const char *value
   13.11 +    )
   13.12 +{  
   13.13 +    // empty list (no nodes)
   13.14 +    if (stringlist == NULL) {
   13.15 +        *result = new_stringlist(value);
   13.16 +        return true;
   13.17 +    }
   13.18 +
   13.19 +    // empty list (one node, no value)
   13.20 +    if (stringlist->value == NULL) {
   13.21 +        if (stringlist->next) {
   13.22 +            *result = NULL; // invalid list
   13.23 +            return true;
   13.24 +        } 
   13.25 +            
   13.26 +        stringlist->value = strdup(value);
   13.27 +        assert(stringlist->value);
   13.28 +        
   13.29 +        if (stringlist->value == NULL) {
   13.30 +            *result = NULL;
   13.31 +            return true;
   13.32 +        }
   13.33 +        
   13.34 +        *result = stringlist;
   13.35 +        return true;
   13.36 +    }
   13.37 +    return false;
   13.38 +}
   13.39 +
   13.40  DYNAMIC_API stringlist_t *stringlist_add(
   13.41          stringlist_t *stringlist,
   13.42          const char *value
   13.43 @@ -62,23 +95,9 @@
   13.44      if (value == NULL)
   13.45          return NULL;
   13.46  
   13.47 -    // empty list (no nodes)
   13.48 -    if (stringlist == NULL)
   13.49 -        return new_stringlist(value);
   13.50 -
   13.51 -    // empty list (one node, no value)
   13.52 -    if (stringlist->value == NULL) {
   13.53 -        if (stringlist->next) 
   13.54 -            return NULL; // invalid list
   13.55 -            
   13.56 -        stringlist->value = strdup(value);
   13.57 -        assert(stringlist->value);
   13.58 -        
   13.59 -        if (stringlist->value == NULL)
   13.60 -            return NULL;
   13.61 -        
   13.62 -        return stringlist;
   13.63 -    }
   13.64 +    stringlist_t *result = NULL;
   13.65 +    if(_stringlist_add_first(stringlist, &result, value))
   13.66 +        return result;
   13.67      
   13.68      stringlist_t* list_curr = stringlist;
   13.69  
   13.70 @@ -94,6 +113,42 @@
   13.71      return list_curr->next;
   13.72  }
   13.73  
   13.74 +DYNAMIC_API stringlist_t *stringlist_add_unique(
   13.75 +        stringlist_t *stringlist,
   13.76 +        const char *value
   13.77 +    )
   13.78 +{  
   13.79 +    assert(value);
   13.80 +    if (value == NULL)
   13.81 +        return NULL;
   13.82 +
   13.83 +    stringlist_t *result = NULL;
   13.84 +    if(_stringlist_add_first(stringlist, &result, value))
   13.85 +        return result;
   13.86 +    
   13.87 +    stringlist_t* list_curr = stringlist;
   13.88 +
   13.89 +    bool found = false;
   13.90 +    while (list_curr->next) {
   13.91 +        if(strcmp(list_curr->value,value)==0)
   13.92 +            found = true;
   13.93 +        list_curr = list_curr->next;
   13.94 +    }
   13.95 +     
   13.96 +    if (!found) {
   13.97 +        list_curr->next = new_stringlist(value);
   13.98 +
   13.99 +        assert(list_curr->next);
  13.100 +        if (list_curr->next == NULL)
  13.101 +            return NULL;
  13.102 +
  13.103 +        return list_curr->next;
  13.104 +    } else {
  13.105 +        return list_curr;
  13.106 +    }
  13.107 +}
  13.108 +
  13.109 +
  13.110  DYNAMIC_API stringlist_t *stringlist_append(
  13.111          stringlist_t *stringlist,
  13.112          stringlist_t *second
    14.1 --- a/src/stringlist.h	Tue Mar 21 15:26:12 2017 +0100
    14.2 +++ b/src/stringlist.h	Thu May 04 15:16:47 2017 +0200
    14.3 @@ -61,6 +61,24 @@
    14.4          const char *value
    14.5      );
    14.6  
    14.7 +// stringlist_add_unique() - add string to stringlist, if not already there
    14.8 +//
    14.9 +//  parameters:
   14.10 +//      stringlist (in)     stringlist struct or NULL to create a new one
   14.11 +//      value (in)          value as C string
   14.12 +//
   14.13 +//  return value:
   14.14 +//      pointer to last element in stringlist or NULL if out of memory
   14.15 +//
   14.16 +//  caveat:
   14.17 +//      the value is being copied before being added to the list
   14.18 +//      the original string is still being owned by the caller
   14.19 +
   14.20 +DYNAMIC_API stringlist_t *stringlist_add_unique(
   14.21 +        stringlist_t *stringlist,
   14.22 +        const char *value
   14.23 +    );
   14.24 +
   14.25  
   14.26  // stringlist_append() - append stringlist to stringlist
   14.27  //
    15.1 --- a/src/sync.h	Tue Mar 21 15:26:12 2017 +0100
    15.2 +++ b/src/sync.h	Thu May 04 15:16:47 2017 +0200
    15.3 @@ -309,11 +309,12 @@
    15.4  //  parameters:
    15.5  //      management (in)     application defined
    15.6  //      timeout (in,out)    do not wait longer than timeout for message
    15.7 +//                          timeout == NULL or *timeout == 0 is blocking
    15.8  //
    15.9  //  return value:
   15.10 -//      next message or :
   15.11 -//      NULL and timeout == 0 for termination
   15.12 -//      NULL and timeout != 0 for timeout occurence
   15.13 +//      next message, then timeout[out] == remaining time
   15.14 +//      NULL and timeout[out] != 0 for timeout occurence
   15.15 +//      NULL and timeout[out] == 0 for termination
   15.16  
   15.17  typedef void *(*retrieve_next_sync_msg_t)(void *management, time_t *timeout);
   15.18  
    16.1 --- a/src/sync_actions.c	Tue Mar 21 15:26:12 2017 +0100
    16.2 +++ b/src/sync_actions.c	Thu May 04 15:16:47 2017 +0200
    16.3 @@ -105,6 +105,23 @@
    16.4      return 1;
    16.5  }
    16.6  
    16.7 +int sameKeyAndAddress(PEP_SESSION session, Identity a, Identity b)
    16.8 +{
    16.9 +    assert(session);
   16.10 +    assert(a);
   16.11 +    assert(b);
   16.12 +
   16.13 +    if (!(session && a && b))
   16.14 +        return invalid_condition; // error
   16.15 +
   16.16 +    if (a->fpr == NULL || b->fpr == NULL ||
   16.17 +        (!_same_fpr(a->fpr, strlen(a->fpr), b->fpr, strlen(b->fpr))) ||
   16.18 +        a->address == NULL || b->address == NULL ||
   16.19 +        strcmp(a->address, b->address) != 0)
   16.20 +            return 0;
   16.21 +    return 1;
   16.22 +}
   16.23 +
   16.24  // actions
   16.25  
   16.26  PEP_STATUS _notifyHandshake(
    17.1 --- a/sync/Makefile	Tue Mar 21 15:26:12 2017 +0100
    17.2 +++ b/sync/Makefile	Thu May 04 15:16:47 2017 +0200
    17.3 @@ -13,10 +13,10 @@
    17.4  	touch .codegen
    17.5  
    17.6  .actions: devicegroup.fsm gen_actions.ysl2 fsm.yml2 functions.ysl2
    17.7 -	$(YML2PROC) -y gen_actions.ysl2 $< -o $@
    17.8 +	$(YML2PROC) $(YML_OPTS) -y gen_actions.ysl2 $< -o $@
    17.9  
   17.10  .statemachines: devicegroup.fsm gen_statemachine.ysl2 fsm.yml2 functions.ysl2
   17.11 -	$(YML2PROC) -y gen_statemachine.ysl2 $< -o $@
   17.12 +	$(YML2PROC) $(YML_OPTS) -y gen_statemachine.ysl2 $< -o $@
   17.13  
   17.14  .PHONY: clean
   17.15  
   17.16 @@ -29,7 +29,7 @@
   17.17  	yml2c $< -o $@
   17.18  
   17.19  %.dot: devicegroup.fsm gen_dot.ysl2
   17.20 -	yml2proc -y gen_dot.ysl2 $<
   17.21 +	$(YML2PROC) $(YML_OPTS) -y gen_dot.ysl2 $<
   17.22  
   17.23  %.svg: %.dot
   17.24  	dot -Tsvg -o $@ $<
    18.1 --- a/sync/devicegroup.fsm	Tue Mar 21 15:26:12 2017 +0100
    18.2 +++ b/sync/devicegroup.fsm	Thu May 04 15:16:47 2017 +0200
    18.3 @@ -21,6 +21,7 @@
    18.4          condition deviceGrouped();
    18.5          condition keyElectionWon(Identity partner);
    18.6          condition sameIdentities(Identity a, Identity b);
    18.7 +        condition sameKeyAndAddress(Identity a, Identity b);
    18.8  
    18.9          state InitState {
   18.10              on Init {
   18.11 @@ -31,10 +32,14 @@
   18.12          }
   18.13  
   18.14          state Sole end=1 {
   18.15 -            on KeyGen
   18.16 +            on KeyGen {
   18.17                  do sendBeacon;
   18.18 -            on CannotDecrypt
   18.19 +                go SoleWaiting;
   18.20 +            }
   18.21 +            on CannotDecrypt {
   18.22                  do sendBeacon;
   18.23 +                go SoleWaiting;
   18.24 +            }
   18.25              on Beacon(Identity partner){
   18.26                  do sendHandshakeRequest(partner);
   18.27                  go SoleBeaconed(partner);
   18.28 @@ -45,6 +50,26 @@
   18.29              }
   18.30          }
   18.31  
   18.32 +        // copy of sole state with a timeout to enable fast polling for a second
   18.33 +        // TODO use more YSLT power here (substates ?) 
   18.34 +        state SoleWaiting timeout=60 {
   18.35 +            on KeyGen {
   18.36 +                do sendBeacon;
   18.37 +            }
   18.38 +            on CannotDecrypt {
   18.39 +                do sendBeacon;
   18.40 +            }
   18.41 +            on Beacon(Identity partner){
   18.42 +                do sendHandshakeRequest(partner);
   18.43 +                go SoleBeaconed(partner);
   18.44 +            }
   18.45 +            on HandshakeRequest(Identity partner) {
   18.46 +                do sendHandshakeRequest(partner);
   18.47 +                go HandshakingSole(partner);
   18.48 +            }
   18.49 +            on Timeout go Sole;
   18.50 +        }
   18.51 +
   18.52          state SoleBeaconed timeout=600 (Identity expected) {
   18.53              on KeyGen{
   18.54                  do sendBeacon;
   18.55 @@ -71,10 +96,10 @@
   18.56  
   18.57          state HandshakingSole timeout=600 (Identity expected) {
   18.58              on Init{
   18.59 -                if keyElectionWon(partner) {
   18.60 -                    do notifyInitFormGroup(partner);
   18.61 +                if keyElectionWon(expected) {
   18.62 +                    do notifyInitFormGroup(expected);
   18.63                  } else {
   18.64 -                    do notifyInitAddOurDevice(partner);
   18.65 +                    do notifyInitAddOurDevice(expected);
   18.66                  }
   18.67              }
   18.68              on HandshakeRejected(Identity partner) {
   18.69 @@ -97,10 +122,11 @@
   18.70              }
   18.71              on Cancel go Sole;
   18.72              on GroupKeys(Identity partner, GroupKeys groupkeys) {
   18.73 -                if keyElectionWon(partner) {
   18.74 -                    // not suppose to receive groupkeys - ignore
   18.75 +                if keyElectionWon(expected) {
   18.76 +                    // not supposed to receive groupkeys - ignore
   18.77                  } else {
   18.78 -                    if sameIdentities(partner, expected) {
   18.79 +                    // UUID changes in between, so we can only check for same address and fpr
   18.80 +                    if sameKeyAndAddress(partner, expected) {
   18.81                          go WaitForAcceptSole(partner, groupkeys);
   18.82                      }
   18.83                  }
   18.84 @@ -114,7 +140,8 @@
   18.85      
   18.86          state WaitForGroupKeysSole timeout=600 (Identity expected) {
   18.87              on GroupKeys(Identity partner, GroupKeys groupkeys) {
   18.88 -                if sameIdentities(partner, expected) {
   18.89 +                // UUID changes in between, so we can only check for same address and fpr
   18.90 +                if sameKeyAndAddress(partner, expected) {
   18.91                      do storeGroupKeys(partner, groupkeys);
   18.92                      do sendGroupUpdate;
   18.93                      do renewUUID;
   18.94 @@ -134,7 +161,8 @@
   18.95                  go Sole;
   18.96              }
   18.97              on HandshakeAccepted(Identity partner) {
   18.98 -                if sameIdentities(partner, expected) {
   18.99 +                // UUID changes in between, so we can only check for same address and fpr
  18.100 +                if sameKeyAndAddress(partner, expected) {
  18.101                      do acceptHandshake(partner); 
  18.102                      do storeGroupKeys(partner, groupkeys);
  18.103                      do sendGroupUpdate;
  18.104 @@ -156,13 +184,182 @@
  18.105                  do sendGroupUpdate;
  18.106              on CannotDecrypt {
  18.107                  do sendUpdateRequest;
  18.108 +
  18.109 +                ///// de-activate 3+ de group in test_diphoton
  18.110 +                // do sendBeacon;
  18.111 +
  18.112 +                go GroupWaiting;
  18.113              }
  18.114              on UpdateRequest
  18.115                  do sendGroupUpdate;
  18.116 +
  18.117 +            ///// de-activate 3+ de group in test_diphoton
  18.118 +            // on Beacon(Identity partner){
  18.119 +            //     do sendHandshakeRequest(partner);
  18.120 +            //     go GroupedBeaconed(partner);
  18.121 +            // }
  18.122 +            // on HandshakeRequest(Identity partner) {
  18.123 +            //     do sendHandshakeRequest(partner);
  18.124 +            //     go HandshakingGrouped(partner);
  18.125 +            // }
  18.126 +
  18.127              on GroupUpdate(Identity partner, IdentityList keys)
  18.128                  do storeGroupUpdate(partner, keys);
  18.129          }
  18.130  
  18.131 +        // copy of grouped state, with a timeout to enable fast poling for a minut
  18.132 +        state GroupWaiting timeout=60 {
  18.133 +            on KeyGen
  18.134 +                do sendGroupUpdate;
  18.135 +            on CannotDecrypt {
  18.136 +                do sendUpdateRequest;
  18.137 +
  18.138 +                ///// de-activate 3+ de group in test_diphoton
  18.139 +                // do sendBeacon;
  18.140 +            }
  18.141 +            on UpdateRequest
  18.142 +                do sendGroupUpdate;
  18.143 +
  18.144 +            ///// de-activate 3+ de group in test_diphoton
  18.145 +            // on Beacon(Identity partner){
  18.146 +            //     do sendHandshakeRequest(partner);
  18.147 +            //     go GroupedBeaconed(partner);
  18.148 +            // }
  18.149 +            // on HandshakeRequest(Identity partner) {
  18.150 +            //     do sendHandshakeRequest(partner);
  18.151 +            //     go HandshakingGrouped(partner);
  18.152 +            // }
  18.153 +
  18.154 +            on GroupUpdate(Identity partner, IdentityList keys)
  18.155 +                do storeGroupUpdate(partner, keys);
  18.156 +            on Timeout go Grouped;
  18.157 +        }
  18.158 +
  18.159 +        ///// de-activate 3+ de group in test_diphoton
  18.160 +        // state GroupedBeaconed timeout=600 (Identity expected){
  18.161 +        //     on KeyGen
  18.162 +        //         do sendGroupUpdate;
  18.163 +        //     on CannotDecrypt {
  18.164 +        //         do sendUpdateRequest;
  18.165 +        //         do sendBeacon;
  18.166 +        //     }
  18.167 +        //     on UpdateRequest
  18.168 +        //         do sendGroupUpdate;
  18.169 +        //     on Beacon(Identity partner){
  18.170 +        //         do sendHandshakeRequest(partner);
  18.171 +        //         go GroupedBeaconed(partner);
  18.172 +        //     }
  18.173 +        //     on HandshakeRequest(Identity partner) {
  18.174 +        //         if sameIdentities(partner, expected) {
  18.175 +        //             // do nothing, to avoid sending handshake request twice 
  18.176 +        //         } else {
  18.177 +        //             do sendHandshakeRequest(partner);
  18.178 +        //         }
  18.179 +        //         go HandshakingGrouped(partner);
  18.180 +        //     }
  18.181 +        //     on GroupUpdate(Identity partner, IdentityList keys)
  18.182 +        //         do storeGroupUpdate(partner, keys);
  18.183 +        //     on Timeout go Grouped;
  18.184 +        // }
  18.185 +
  18.186 +        ///// de-activate 3+ de group in test_diphoton
  18.187 +        // state HandshakingGrouped timeout=600 (Identity expected) {
  18.188 +        //     // HandshakeRequest from same group are filtered in receive_sync_msg
  18.189 +        //     on Init{
  18.190 +        //         if keyElectionWon(expected) {
  18.191 +        //             do notifyInitAddOtherDevice(partner);
  18.192 +        //         } else {
  18.193 +        //             do notifyInitMoveOurDevice(partner);
  18.194 +        //         }
  18.195 +        //     }
  18.196 +        //     on HandshakeRejected(Identity partner) {
  18.197 +        //         do rejectHandshake(partner);             // stores rejection of partner
  18.198 +        //         do sendGroupUpdate;
  18.199 +        //         go Grouped;
  18.200 +        //     }
  18.201 +        //     on HandshakeAccepted(Identity partner) {
  18.202 +        //         do acceptHandshake(partner); 
  18.203 +        //         do sendGroupUpdate;
  18.204 +        //         if keyElectionWon(partner) {
  18.205 +        //             do sendGroupKeys(partner);
  18.206 +        //             do notifyAcceptedDeviceAdded(partner);
  18.207 +        //             go Grouped;
  18.208 +        //         }
  18.209 +        //         go WaitForGroupKeysGrouped(partner);
  18.210 +        //     }
  18.211 +        //     on Cancel go Grouped;
  18.212 +        //     on GroupKeys(Identity partner, GroupKeys groupkeys) {
  18.213 +        //         if keyElectionWon(expected) {
  18.214 +        //             // not supposed to receive groupkeys - ignore
  18.215 +        //         } else {
  18.216 +        //             // UUID changes in between, so we can only check for same address and fpr
  18.217 +        //             if sameKeyAndAddress(partner, expected) {
  18.218 +        //                 go WaitForAcceptGrouped(partner, groupkeys);
  18.219 +        //             }
  18.220 +        //         }
  18.221 +        //     }
  18.222 +        //     on GroupUpdate(Identity partner, IdentityList keys) {
  18.223 +        //         do notifyOvertaken(partner);
  18.224 +        //         do storeGroupUpdate(partner, keys);
  18.225 +        //         go Grouped;
  18.226 +        //     }
  18.227 +        //     on Timeout {
  18.228 +        //         do notifyTimeout(expected);
  18.229 +        //         go Grouped;
  18.230 +        //     }
  18.231 +        // }
  18.232 +
  18.233 +        ///// de-activate 3+ de group in test_diphoton
  18.234 +        // state WaitForGroupKeysGrouped timeout=600 (Identity expected) {
  18.235 +        //     on GroupKeys(Identity partner, GroupKeys groupkeys) {
  18.236 +        //         if sameIdentities(partner, expected) {
  18.237 +        //             do storeGroupKeys(partner, groupkeys);
  18.238 +        //             do sendGroupUpdate;
  18.239 +        //             do renewUUID;
  18.240 +        //             do notifyAcceptedDeviceMoved(partner);
  18.241 +        //             go Grouped;
  18.242 +        //         }
  18.243 +        //     }
  18.244 +        //     on GroupUpdate(Identity partner, IdentityList keys) {
  18.245 +        //         do notifyOvertaken(partner);
  18.246 +        //         do storeGroupUpdate(partner, keys);
  18.247 +        //         go Grouped;
  18.248 +        //     }
  18.249 +        //     on Timeout {
  18.250 +        //         do notifyTimeout(expected);
  18.251 +        //         go Grouped;
  18.252 +        //     }
  18.253 +        // }
  18.254 +
  18.255 +        ///// de-activate 3+ de group in test_diphoton
  18.256 +        // state WaitForAcceptGrouped timeout=600 (Identity expected, GroupKeys groupkeys) {
  18.257 +        //     on HandshakeRejected(Identity partner) {
  18.258 +        //         do rejectHandshake(partner);
  18.259 +        //         do sendGroupUpdate;
  18.260 +        //         go Grouped;
  18.261 +        //     }
  18.262 +        //     on HandshakeAccepted(Identity partner) {
  18.263 +        //         if sameIdentities(partner, expected) {
  18.264 +        //             do acceptHandshake(partner); 
  18.265 +        //             do storeGroupKeys(partner, groupkeys);
  18.266 +        //             do sendGroupUpdate;
  18.267 +        //             do renewUUID;
  18.268 +        //             do notifyAcceptedDeviceMoved(partner);
  18.269 +        //         }
  18.270 +        //         go Grouped;
  18.271 +        //     }
  18.272 +        //     on Cancel go Grouped;
  18.273 +        //     on GroupUpdate(Identity partner, IdentityList keys) {
  18.274 +        //         do notifyOvertaken(partner);
  18.275 +        //         do storeGroupUpdate(partner, keys);
  18.276 +        //         go Grouped;
  18.277 +        //     }
  18.278 +        //     on Timeout {
  18.279 +        //         do notifyTimeout(expected);
  18.280 +        //         go Grouped;
  18.281 +        //     }
  18.282 +        // }
  18.283 +
  18.284          tag Init 1;
  18.285          tag Beacon 2;
  18.286          tag HandshakeRequest 3;
    19.1 --- a/sync/fsm.yml2	Tue Mar 21 15:26:12 2017 +0100
    19.2 +++ b/sync/fsm.yml2	Thu May 04 15:16:47 2017 +0200
    19.3 @@ -14,5 +14,6 @@
    19.4  decl transition @target, go is transition;
    19.5  decl action @name, do is action;
    19.6  decl condition @name, if is condition;
    19.7 +decl alternative, else is alternative;
    19.8  decl interface @name;
    19.9  decl tag @name (id);
    20.1 --- a/sync/gen_dot.ysl2	Tue Mar 21 15:26:12 2017 +0100
    20.2 +++ b/sync/gen_dot.ysl2	Thu May 04 15:16:47 2017 +0200
    20.3 @@ -21,9 +21,10 @@
    20.4  
    20.5      template "event" {
    20.6          param "state";
    20.7 +        const "transitions", "transition|descendant::condition/transition|descendant::alternative/transition";
    20.8          choose {
    20.9 -            when "count(transition) > 0"
   20.10 -                apply "transition|condition/transition", 0
   20.11 +            when "count($transitions) > 0"
   20.12 +                apply "$transitions", 0
   20.13                      with "state", "$state", with "event", "@name";
   20.14              otherwise
   20.15                  if "@name != 'Init'"
    21.1 --- a/sync/gen_statemachine.ysl2	Tue Mar 21 15:26:12 2017 +0100
    21.2 +++ b/sync/gen_statemachine.ysl2	Thu May 04 15:16:47 2017 +0200
    21.3 @@ -231,7 +231,6 @@
    21.4          ||
    21.5  
    21.6          ||
    21.7 -            *timeout = «@timeout»;
    21.8              switch (event) {
    21.9          ||
   21.10  
   21.11 @@ -239,6 +238,7 @@
   21.12          ||
   21.13                  case Init: 
   21.14                      DEBUG_LOG("FSM event", "«../@filename»_fsm.c, state=«@name»", "event=Init") 
   21.15 +                    *timeout = «@timeout»;
   21.16                      break;
   21.17          ||
   21.18  
   21.19 @@ -300,13 +300,16 @@
   21.20          case «@name»:
   21.21          {
   21.22              DEBUG_LOG("FSM event", "«../../@filename»_fsm.c, state=«../@name»", "event=«@name»")
   21.23 +        `` if "@name='Init'" |> *timeout = «../@timeout»;
   21.24          ||
   21.25 +
   21.26          if "count(parm) > 1" {
   21.27              // TODO get ride of void *extra, pass per-event struct incl all params.
   21.28              const "extrapEpType" call "pEp_type" with "type","name(parm[2]/*[1])"; 
   21.29              const "extraArgName","name(parm[2]/*[2])"; 
   21.30              |> «$extrapEpType» «$extraArgName» = («$extrapEpType»)extra;
   21.31          }
   21.32 +
   21.33          ||
   21.34          `` apply "action|transition|condition";
   21.35          `` if "name(*[position()=last()]) != 'transition'" |> break;
   21.36 @@ -346,10 +349,10 @@
   21.37          |> if (cond_result) {
   21.38          apply "action|transition|condition";
   21.39          |> }
   21.40 -        const "else", "./following-sibling::*[position()=1][name(.)='else']";
   21.41 -        if "$else" {
   21.42 +        const "alternative", "./following-sibling::*[position()=1][name(.)='alternative']";
   21.43 +        if "$alternative" {
   21.44          |> else {
   21.45 -        apply "$else/action|$else/transition|$else/condition";
   21.46 +        apply "$alternative/action|$alternative/transition|$alternative/condition";
   21.47          |> }
   21.48          }
   21.49          | }
    22.1 --- a/sync/generated/sync_fsm.c	Tue Mar 21 15:26:12 2017 +0100
    22.2 +++ b/sync/generated/sync_fsm.c	Thu May 04 15:16:47 2017 +0200
    22.3 @@ -39,11 +39,11 @@
    22.4          case InitState:
    22.5          {
    22.6              DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=InitState")
    22.7 -            *timeout = 0;
    22.8              switch (event) {
    22.9                  case Init:
   22.10                  {
   22.11                      DEBUG_LOG("FSM event", "sync_fsm.c, state=InitState", "event=Init")
   22.12 +                    *timeout = 0;
   22.13                      {
   22.14                          int cond_result = deviceGrouped(session);
   22.15                          #ifndef NDEBUG
   22.16 @@ -69,10 +69,10 @@
   22.17          case Sole:
   22.18          {
   22.19              DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=Sole")
   22.20 -            *timeout = 0;
   22.21              switch (event) {
   22.22                  case Init: 
   22.23                      DEBUG_LOG("FSM event", "sync_fsm.c, state=Sole", "event=Init") 
   22.24 +                    *timeout = 0;
   22.25                      break;
   22.26                  case KeyGen:
   22.27                  {
   22.28 @@ -83,7 +83,8 @@
   22.29                          return (int) invalid_out_of_memory;
   22.30                      if (status != PEP_STATUS_OK)
   22.31                          return (int) invalid_action;
   22.32 -                    break;
   22.33 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=Sole, event=KeyGen", "target=SoleWaiting")
   22.34 +                    return SoleWaiting;
   22.35                  }
   22.36                  case CannotDecrypt:
   22.37                  {
   22.38 @@ -94,7 +95,8 @@
   22.39                          return (int) invalid_out_of_memory;
   22.40                      if (status != PEP_STATUS_OK)
   22.41                          return (int) invalid_action;
   22.42 -                    break;
   22.43 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=Sole, event=CannotDecrypt", "target=SoleWaiting")
   22.44 +                    return SoleWaiting;
   22.45                  }
   22.46                  case Beacon:
   22.47                  {
   22.48 @@ -135,16 +137,91 @@
   22.49              }
   22.50              break;
   22.51          }
   22.52 +        case SoleWaiting:
   22.53 +        {
   22.54 +            DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=SoleWaiting")
   22.55 +            switch (event) {
   22.56 +                case Init: 
   22.57 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleWaiting", "event=Init") 
   22.58 +                    *timeout = 60;
   22.59 +                    break;
   22.60 +                case KeyGen:
   22.61 +                {
   22.62 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleWaiting", "event=KeyGen")
   22.63 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=SoleWaiting, event=KeyGen", "action=sendBeacon")
   22.64 +                    status = sendBeacon(session, state, NULL, NULL);
   22.65 +                    if (status == PEP_OUT_OF_MEMORY)
   22.66 +                        return (int) invalid_out_of_memory;
   22.67 +                    if (status != PEP_STATUS_OK)
   22.68 +                        return (int) invalid_action;
   22.69 +                    break;
   22.70 +                }
   22.71 +                case CannotDecrypt:
   22.72 +                {
   22.73 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleWaiting", "event=CannotDecrypt")
   22.74 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=SoleWaiting, event=CannotDecrypt", "action=sendBeacon")
   22.75 +                    status = sendBeacon(session, state, NULL, NULL);
   22.76 +                    if (status == PEP_OUT_OF_MEMORY)
   22.77 +                        return (int) invalid_out_of_memory;
   22.78 +                    if (status != PEP_STATUS_OK)
   22.79 +                        return (int) invalid_action;
   22.80 +                    break;
   22.81 +                }
   22.82 +                case Beacon:
   22.83 +                {
   22.84 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleWaiting", "event=Beacon")
   22.85 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=SoleWaiting, event=Beacon", "action=sendHandshakeRequest")
   22.86 +                    status = sendHandshakeRequest(session, state, partner, NULL);
   22.87 +                    if (status == PEP_OUT_OF_MEMORY)
   22.88 +                        return (int) invalid_out_of_memory;
   22.89 +                    if (status != PEP_STATUS_OK)
   22.90 +                        return (int) invalid_action;
   22.91 +                    session->sync_state_payload = malloc(sizeof(SoleBeaconed_state_payload_t));
   22.92 +                    assert(session->sync_state_payload);
   22.93 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory;
   22.94 +                    ((SoleBeaconed_state_payload_t*)session->sync_state_payload)->expected =
   22.95 +                        identity_dup(partner);
   22.96 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=SoleWaiting, event=Beacon", "target=SoleBeaconed")
   22.97 +                    return SoleBeaconed;
   22.98 +                }
   22.99 +                case HandshakeRequest:
  22.100 +                {
  22.101 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleWaiting", "event=HandshakeRequest")
  22.102 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=SoleWaiting, event=HandshakeRequest", "action=sendHandshakeRequest")
  22.103 +                    status = sendHandshakeRequest(session, state, partner, NULL);
  22.104 +                    if (status == PEP_OUT_OF_MEMORY)
  22.105 +                        return (int) invalid_out_of_memory;
  22.106 +                    if (status != PEP_STATUS_OK)
  22.107 +                        return (int) invalid_action;
  22.108 +                    session->sync_state_payload = malloc(sizeof(HandshakingSole_state_payload_t));
  22.109 +                    assert(session->sync_state_payload);
  22.110 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory;
  22.111 +                    ((HandshakingSole_state_payload_t*)session->sync_state_payload)->expected =
  22.112 +                        identity_dup(partner);
  22.113 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=SoleWaiting, event=HandshakeRequest", "target=HandshakingSole")
  22.114 +                    return HandshakingSole;
  22.115 +                }
  22.116 +                case Timeout:
  22.117 +                {
  22.118 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleWaiting", "event=Timeout")
  22.119 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=SoleWaiting, event=Timeout", "target=Sole")
  22.120 +                    return Sole;
  22.121 +                }
  22.122 +                default:
  22.123 +                    return (DeviceState_state) invalid_event;
  22.124 +            }
  22.125 +            break;
  22.126 +        }
  22.127          case SoleBeaconed:
  22.128          {
  22.129              DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=SoleBeaconed")
  22.130              assert(session->sync_state_payload);
  22.131              if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  22.132              Identity expected = ((SoleBeaconed_state_payload_t*)session->sync_state_payload)->expected;
  22.133 -            *timeout = 600;
  22.134              switch (event) {
  22.135                  case Init: 
  22.136                      DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleBeaconed", "event=Init") 
  22.137 +                    *timeout = 600;
  22.138                      break;
  22.139                  case KeyGen:
  22.140                  {
  22.141 @@ -260,13 +337,13 @@
  22.142              assert(session->sync_state_payload);
  22.143              if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  22.144              Identity expected = ((HandshakingSole_state_payload_t*)session->sync_state_payload)->expected;
  22.145 -            *timeout = 600;
  22.146              switch (event) {
  22.147                  case Init:
  22.148                  {
  22.149                      DEBUG_LOG("FSM event", "sync_fsm.c, state=HandshakingSole", "event=Init")
  22.150 +                    *timeout = 600;
  22.151                      {
  22.152 -                        int cond_result = keyElectionWon(session, partner);
  22.153 +                        int cond_result = keyElectionWon(session, expected);
  22.154                          #ifndef NDEBUG
  22.155                          char resstr[11] = {0,};
  22.156                          snprintf(resstr,10,"result=%d",cond_result);
  22.157 @@ -276,7 +353,7 @@
  22.158                              return cond_result;
  22.159                          if (cond_result) {
  22.160                          DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingSole, event=Init", "action=notifyInitFormGroup")
  22.161 -                        status = notifyInitFormGroup(session, state, partner, NULL);
  22.162 +                        status = notifyInitFormGroup(session, state, expected, NULL);
  22.163                          if (status == PEP_OUT_OF_MEMORY)
  22.164                              return (int) invalid_out_of_memory;
  22.165                          if (status != PEP_STATUS_OK)
  22.166 @@ -284,7 +361,7 @@
  22.167                          }
  22.168                          else {
  22.169                          DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingSole, event=Init", "action=notifyInitAddOurDevice")
  22.170 -                        status = notifyInitAddOurDevice(session, state, partner, NULL);
  22.171 +                        status = notifyInitAddOurDevice(session, state, expected, NULL);
  22.172                          if (status == PEP_OUT_OF_MEMORY)
  22.173                              return (int) invalid_out_of_memory;
  22.174                          if (status != PEP_STATUS_OK)
  22.175 @@ -410,7 +487,7 @@
  22.176                      DEBUG_LOG("FSM event", "sync_fsm.c, state=HandshakingSole", "event=GroupKeys")
  22.177                      group_keys_extra_t* groupkeys = (group_keys_extra_t*)extra;
  22.178                      {
  22.179 -                        int cond_result = keyElectionWon(session, partner);
  22.180 +                        int cond_result = keyElectionWon(session, expected);
  22.181                          #ifndef NDEBUG
  22.182                          char resstr[11] = {0,};
  22.183                          snprintf(resstr,10,"result=%d",cond_result);
  22.184 @@ -422,12 +499,12 @@
  22.185                          }
  22.186                          else {
  22.187                          {
  22.188 -                            int cond_result = sameIdentities(session, partner, expected);
  22.189 +                            int cond_result = sameKeyAndAddress(session, partner, expected);
  22.190                              #ifndef NDEBUG
  22.191                              char resstr[11] = {0,};
  22.192                              snprintf(resstr,10,"result=%d",cond_result);
  22.193                              #endif
  22.194 -                            DEBUG_LOG("FSM condition", "sync_fsm.c, state=HandshakingSole, event=GroupKeys, condition=sameIdentities", resstr)
  22.195 +                            DEBUG_LOG("FSM condition", "sync_fsm.c, state=HandshakingSole, event=GroupKeys, condition=sameKeyAndAddress", resstr)
  22.196                              if (cond_result < 0)
  22.197                                  return cond_result;
  22.198                              if (cond_result) {
  22.199 @@ -485,22 +562,22 @@
  22.200              assert(session->sync_state_payload);
  22.201              if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  22.202              Identity expected = ((WaitForGroupKeysSole_state_payload_t*)session->sync_state_payload)->expected;
  22.203 -            *timeout = 600;
  22.204              switch (event) {
  22.205                  case Init: 
  22.206                      DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForGroupKeysSole", "event=Init") 
  22.207 +                    *timeout = 600;
  22.208                      break;
  22.209                  case GroupKeys:
  22.210                  {
  22.211                      DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForGroupKeysSole", "event=GroupKeys")
  22.212                      group_keys_extra_t* groupkeys = (group_keys_extra_t*)extra;
  22.213                      {
  22.214 -                        int cond_result = sameIdentities(session, partner, expected);
  22.215 +                        int cond_result = sameKeyAndAddress(session, partner, expected);
  22.216                          #ifndef NDEBUG
  22.217                          char resstr[11] = {0,};
  22.218                          snprintf(resstr,10,"result=%d",cond_result);
  22.219                          #endif
  22.220 -                        DEBUG_LOG("FSM condition", "sync_fsm.c, state=WaitForGroupKeysSole, event=GroupKeys, condition=sameIdentities", resstr)
  22.221 +                        DEBUG_LOG("FSM condition", "sync_fsm.c, state=WaitForGroupKeysSole, event=GroupKeys, condition=sameKeyAndAddress", resstr)
  22.222                          if (cond_result < 0)
  22.223                              return cond_result;
  22.224                          if (cond_result) {
  22.225 @@ -568,10 +645,10 @@
  22.226              if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  22.227              Identity expected = ((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->expected;
  22.228              group_keys_extra_t* groupkeys = ((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->groupkeys;
  22.229 -            *timeout = 600;
  22.230              switch (event) {
  22.231                  case Init: 
  22.232                      DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForAcceptSole", "event=Init") 
  22.233 +                    *timeout = 600;
  22.234                      break;
  22.235                  case HandshakeRejected:
  22.236                  {
  22.237 @@ -595,12 +672,12 @@
  22.238                  {
  22.239                      DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForAcceptSole", "event=HandshakeAccepted")
  22.240                      {
  22.241 -                        int cond_result = sameIdentities(session, partner, expected);
  22.242 +                        int cond_result = sameKeyAndAddress(session, partner, expected);
  22.243                          #ifndef NDEBUG
  22.244                          char resstr[11] = {0,};
  22.245                          snprintf(resstr,10,"result=%d",cond_result);
  22.246                          #endif
  22.247 -                        DEBUG_LOG("FSM condition", "sync_fsm.c, state=WaitForAcceptSole, event=HandshakeAccepted, condition=sameIdentities", resstr)
  22.248 +                        DEBUG_LOG("FSM condition", "sync_fsm.c, state=WaitForAcceptSole, event=HandshakeAccepted, condition=sameKeyAndAddress", resstr)
  22.249                          if (cond_result < 0)
  22.250                              return cond_result;
  22.251                          if (cond_result) {
  22.252 @@ -691,10 +768,10 @@
  22.253          case Grouped:
  22.254          {
  22.255              DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=Grouped")
  22.256 -            *timeout = 0;
  22.257              switch (event) {
  22.258                  case Init: 
  22.259                      DEBUG_LOG("FSM event", "sync_fsm.c, state=Grouped", "event=Init") 
  22.260 +                    *timeout = 0;
  22.261                      break;
  22.262                  case KeyGen:
  22.263                  {
  22.264 @@ -716,7 +793,8 @@
  22.265                          return (int) invalid_out_of_memory;
  22.266                      if (status != PEP_STATUS_OK)
  22.267                          return (int) invalid_action;
  22.268 -                    break;
  22.269 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=Grouped, event=CannotDecrypt", "target=GroupWaiting")
  22.270 +                    return GroupWaiting;
  22.271                  }
  22.272                  case UpdateRequest:
  22.273                  {
  22.274 @@ -746,6 +824,70 @@
  22.275              }
  22.276              break;
  22.277          }
  22.278 +        case GroupWaiting:
  22.279 +        {
  22.280 +            DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=GroupWaiting")
  22.281 +            switch (event) {
  22.282 +                case Init: 
  22.283 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupWaiting", "event=Init") 
  22.284 +                    *timeout = 60;
  22.285 +                    break;
  22.286 +                case KeyGen:
  22.287 +                {
  22.288 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupWaiting", "event=KeyGen")
  22.289 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupWaiting, event=KeyGen", "action=sendGroupUpdate")
  22.290 +                    status = sendGroupUpdate(session, state, NULL, NULL);
  22.291 +                    if (status == PEP_OUT_OF_MEMORY)
  22.292 +                        return (int) invalid_out_of_memory;
  22.293 +                    if (status != PEP_STATUS_OK)
  22.294 +                        return (int) invalid_action;
  22.295 +                    break;
  22.296 +                }
  22.297 +                case CannotDecrypt:
  22.298 +                {
  22.299 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupWaiting", "event=CannotDecrypt")
  22.300 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupWaiting, event=CannotDecrypt", "action=sendUpdateRequest")
  22.301 +                    status = sendUpdateRequest(session, state, NULL, NULL);
  22.302 +                    if (status == PEP_OUT_OF_MEMORY)
  22.303 +                        return (int) invalid_out_of_memory;
  22.304 +                    if (status != PEP_STATUS_OK)
  22.305 +                        return (int) invalid_action;
  22.306 +                    break;
  22.307 +                }
  22.308 +                case UpdateRequest:
  22.309 +                {
  22.310 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupWaiting", "event=UpdateRequest")
  22.311 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupWaiting, event=UpdateRequest", "action=sendGroupUpdate")
  22.312 +                    status = sendGroupUpdate(session, state, NULL, NULL);
  22.313 +                    if (status == PEP_OUT_OF_MEMORY)
  22.314 +                        return (int) invalid_out_of_memory;
  22.315 +                    if (status != PEP_STATUS_OK)
  22.316 +                        return (int) invalid_action;
  22.317 +                    break;
  22.318 +                }
  22.319 +                case GroupUpdate:
  22.320 +                {
  22.321 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupWaiting", "event=GroupUpdate")
  22.322 +                    identity_list* keys = (identity_list*)extra;
  22.323 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupWaiting, event=GroupUpdate", "action=storeGroupUpdate")
  22.324 +                    status = storeGroupUpdate(session, state, partner, keys);
  22.325 +                    if (status == PEP_OUT_OF_MEMORY)
  22.326 +                        return (int) invalid_out_of_memory;
  22.327 +                    if (status != PEP_STATUS_OK)
  22.328 +                        return (int) invalid_action;
  22.329 +                    break;
  22.330 +                }
  22.331 +                case Timeout:
  22.332 +                {
  22.333 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupWaiting", "event=Timeout")
  22.334 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=GroupWaiting, event=Timeout", "target=Grouped")
  22.335 +                    return Grouped;
  22.336 +                }
  22.337 +                default:
  22.338 +                    return (DeviceState_state) invalid_event;
  22.339 +            }
  22.340 +            break;
  22.341 +        }
  22.342          default:
  22.343              return (DeviceState_state) invalid_state;
  22.344      }
    23.1 --- a/sync/generated/sync_fsm.h	Tue Mar 21 15:26:12 2017 +0100
    23.2 +++ b/sync/generated/sync_fsm.h	Thu May 04 15:16:47 2017 +0200
    23.3 @@ -32,6 +32,7 @@
    23.4  int deviceGrouped(PEP_SESSION session);
    23.5  int keyElectionWon(PEP_SESSION session, Identity partner);
    23.6  int sameIdentities(PEP_SESSION session, Identity a, Identity b);
    23.7 +int sameKeyAndAddress(PEP_SESSION session, Identity a, Identity b);
    23.8  
    23.9  // states
   23.10  
   23.11 @@ -46,11 +47,13 @@
   23.12      DeviceState_state_NONE = 0,
   23.13      InitState, 
   23.14      Sole, 
   23.15 +    SoleWaiting, 
   23.16      SoleBeaconed, 
   23.17      HandshakingSole, 
   23.18      WaitForGroupKeysSole, 
   23.19      WaitForAcceptSole, 
   23.20 -    Grouped
   23.21 +    Grouped, 
   23.22 +    GroupWaiting
   23.23  } DeviceState_state;
   23.24  
   23.25  // events
    24.1 --- a/sync/skeletons/sync_actions.c	Tue Mar 21 15:26:12 2017 +0100
    24.2 +++ b/sync/skeletons/sync_actions.c	Thu May 04 15:16:47 2017 +0200
    24.3 @@ -28,8 +28,8 @@
    24.4      PEP_STATUS status = PEP_STATUS_OK;
    24.5  
    24.6      assert(session);
    24.7 -    assert(partner);
    24.8 -    if (!(session && partner))
    24.9 +    assert(!partner);
   24.10 +    if (!(session && !partner))
   24.11          return PEP_ILLEGAL_VALUE;
   24.12  
   24.13      // working code
   24.14 @@ -65,8 +65,8 @@
   24.15      PEP_STATUS status = PEP_STATUS_OK;
   24.16  
   24.17      assert(session);
   24.18 -    assert(partner);
   24.19 -    if (!(session && partner))
   24.20 +    assert(!partner);
   24.21 +    if (!(session && !partner))
   24.22          return PEP_ILLEGAL_VALUE;
   24.23  
   24.24      // working code
    25.1 --- a/test/Makefile	Tue Mar 21 15:26:12 2017 +0100
    25.2 +++ b/test/Makefile	Thu May 04 15:16:47 2017 +0200
    25.3 @@ -48,14 +48,17 @@
    25.4  %_test : %_test.o test_util.o
    25.5  	 $(LD) $(LDFLAGS) -o $@ $^ $(LDLIBS)
    25.6  
    25.7 -%_test_run : %_test
    25.8 +%_run : %
    25.9  	LD_LIBRARY_PATH=~/lib:../src ./$<
   25.10  
   25.11  
   25.12 -%_test_lldb : %_test
   25.13 +%_lldb : %
   25.14  	LD_LIBRARY_PATH=~/lib:../src lldb ./$<
   25.15  
   25.16 -%_test_gdb : %_test
   25.17 +%_valgrind : %
   25.18 +	LD_LIBRARY_PATH=~/lib:../src valgrind --leak-check=yes ./$<
   25.19 +
   25.20 +%_gdb : %
   25.21  	LD_LIBRARY_PATH=~/lib:../src gdb ./$<
   25.22  
   25.23  unit_tests: $(UNIT_TESTS) $(UNIT_TESTS_RUN)
    26.1 --- a/test/encrypt_for_identity_test.cc	Tue Mar 21 15:26:12 2017 +0100
    26.2 +++ b/test/encrypt_for_identity_test.cc	Thu May 04 15:16:47 2017 +0200
    26.3 @@ -26,6 +26,14 @@
    26.4  
    26.5      // message_api test code
    26.6  
    26.7 +    const string alice_pub_key = slurp("test_keys/pub/pep-test-alice-0x6FF00E97_pub.asc");
    26.8 +    const string alice_priv_key = slurp("test_keys/priv/pep-test-alice-0x6FF00E97_priv.asc");
    26.9 +
   26.10 +    PEP_STATUS statuspub = import_key(session, alice_pub_key.c_str(), alice_pub_key.length(), NULL);
   26.11 +    PEP_STATUS statuspriv = import_key(session, alice_priv_key.c_str(), alice_priv_key.length(), NULL);
   26.12 +    assert(statuspub == PEP_STATUS_OK);
   26.13 +    assert(statuspriv == PEP_STATUS_OK);
   26.14 +
   26.15      cout << "creating message…\n";
   26.16      pEp_identity* alice = new_identity("pep.test.alice@pep-project.org", NULL, PEP_OWN_USERID, "Alice Test");
   26.17      pEp_identity* bob = new_identity("pep.test.bob@pep-project.org", NULL, "42", "Bob Test");
    27.1 --- a/test/pEpEngineTest.cc	Tue Mar 21 15:26:12 2017 +0100
    27.2 +++ b/test/pEpEngineTest.cc	Thu May 04 15:16:47 2017 +0200
    27.3 @@ -26,7 +26,25 @@
    27.4          snprintf(buf,31, "%lu", u);
    27.5          return buf;
    27.6      }
    27.7 -}
    27.8 +    
    27.9 +    std::string status(PEP_STATUS status)
   27.10 +    {
   27.11 +        char buf[32] = {0};
   27.12 +        if(status==0)
   27.13 +        {
   27.14 +            return "PEP_STATUS_OK";
   27.15 +        }else{
   27.16 +            if(status>0)
   27.17 +            {
   27.18 +                snprintf(buf,31, "%u (0x%x)", status, status);
   27.19 +            }else{
   27.20 +                snprintf(buf,31, "%d", status);
   27.21 +            }
   27.22 +        }
   27.23 +        return buf;
   27.24 +    }
   27.25 +
   27.26 +} // end of anonymous namespace
   27.27  
   27.28  
   27.29  Buffer ReadFileIntoMem(const char *fname){
   27.30 @@ -66,13 +84,13 @@
   27.31      cout << "calling init()\n";
   27.32      PEP_STATUS init_result = init(&session);
   27.33      
   27.34 -    cout << "returning from init() with result == " << init_result << "\n";
   27.35 +    cout << "returning from init() with result == " << status(init_result) << endl;
   27.36      assert(init_result == PEP_STATUS_OK);
   27.37  
   27.38      PEP_SESSION second_session;
   27.39      cout << "second session test\n";
   27.40      PEP_STATUS second_init_result = init(&second_session);
   27.41 -    cout << "returning from second init() with result == " << second_init_result << "\n";
   27.42 +    cout << "returning from second init() with result == " << status(second_init_result) << endl;
   27.43      assert(second_init_result == PEP_STATUS_OK);
   27.44      assert(second_session);
   27.45      cout << "dropping second session\n";
   27.46 @@ -125,14 +143,14 @@
   27.47      cout << "calling decrypt_and_verify()\n";
   27.48      PEP_STATUS decrypt_result = decrypt_and_verify(session, cipher_buffer.data(), cipher_buffer.size(), NULL, 0, &buf_text, &buf_size, &keylist);
   27.49  
   27.50 -    cout << "returning from decrypt_and_verify() with result == 0x" << std::hex << decrypt_result << "\n";
   27.51 +    cout << "returning from decrypt_and_verify() with result == " << status(decrypt_result) << endl;
   27.52      assert(decrypt_result == PEP_DECRYPTED_AND_VERIFIED);
   27.53      assert(buf_text);
   27.54      assert(keylist);
   27.55  
   27.56      for (stringlist_t *_keylist=keylist; _keylist!=NULL; _keylist=_keylist->next) {
   27.57          assert(_keylist->value);
   27.58 -        cout << "signed with " << _keylist->value << "\n";
   27.59 +        cout << "signed with " << _keylist->value << endl;
   27.60      }
   27.61  
   27.62      free_stringlist(keylist);
   27.63 @@ -146,10 +164,10 @@
   27.64  
   27.65      cout << "\ncalling verify_text()\n";
   27.66      PEP_STATUS verify_result = verify_text(session, t1_buffer.data(), t1_buffer.size(), sig_buffer.data(), sig_buffer.size(), &keylist);
   27.67 -    cout << "returning from verify_text() with result == " << verify_result << "\n";
   27.68 +    cout << "returning from verify_text() with result == " << status(verify_result) << endl;
   27.69      assert(verify_result == PEP_VERIFIED || verify_result == PEP_VERIFIED_AND_TRUSTED);
   27.70      assert(keylist->value);
   27.71 -    cout << "signed with " << keylist->value << "\n";
   27.72 +    cout << "signed with " << keylist->value << endl;
   27.73      free_stringlist(keylist);
   27.74  
   27.75      const Buffer t2_buffer = ReadFileIntoMem("t2.txt");
   27.76 @@ -168,7 +186,7 @@
   27.77  
   27.78      cout << "\ncalling encrypt_and_sign()\n";
   27.79      PEP_STATUS encrypt_result = encrypt_and_sign(session, keylist, plain.c_str(), plain.length(), &buf_text, &buf_size);
   27.80 -    cout << "returning from encrypt_and_sign() with result == " << encrypt_result << "\n";
   27.81 +    cout << "returning from encrypt_and_sign() with result == " << status(encrypt_result) << endl;
   27.82      assert(encrypt_result == PEP_STATUS_OK);
   27.83      free_stringlist(keylist);
   27.84  
   27.85 @@ -182,12 +200,12 @@
   27.86      size_t wsize;
   27.87      trustword(session, 2342, "en", &word, &wsize);
   27.88      assert(word);
   27.89 -    cout << "the English trustword for 2342 is " << word << "\n";
   27.90 +    cout << "the English trustword for 2342 is " << word << endl;
   27.91      pEp_free(word);
   27.92      cout << "\nfinding French trustword for 2342...\n";
   27.93      trustword(session, 2342, "fr", &word, &wsize);
   27.94      assert(word);
   27.95 -    cout << "the French trustword for 2342 is " << word << "\n";
   27.96 +    cout << "the French trustword for 2342 is " << word << endl;
   27.97      pEp_free(word);
   27.98  
   27.99      const string fingerprint = "4942 2235 FC99 585B 891C  6653 0C7B 109B FA72 61F7";
  27.100 @@ -196,7 +214,7 @@
  27.101      cout << "\nfinding German trustwords for " << fingerprint << "...\n";
  27.102      trustwords(session, fingerprint.c_str(), "de", &words, &wsize, 5);
  27.103      assert(words);
  27.104 -    cout << words << "\n";
  27.105 +    cout << words << endl;
  27.106      pEp_free(words);
  27.107  
  27.108      pEp_identity* identity  = new_identity(
  27.109 @@ -213,11 +231,11 @@
  27.110      free_identity(identity);
  27.111      get_identity(session, "leon.schumacher@digitalekho.com", "23", &identity);
  27.112      assert(identity);
  27.113 -    cout << "set: " << identity->address << ", " << identity->fpr << ", " << identity->user_id << ", " << identity->username << "\n";
  27.114 +    cout << "set: " << identity->address << ", " << identity->fpr << ", " << identity->user_id << ", " << identity->username << endl;
  27.115  
  27.116      PEP_STATUS get_trust_result = get_trust(session, identity);
  27.117      assert(get_trust_result == PEP_STATUS_OK);
  27.118 -    cout << "trust of " << identity->user_id << " is " << identity->comm_type << "\n";
  27.119 +    cout << "trust of " << identity->user_id << " is " << identity->comm_type << endl;
  27.120  
  27.121      free_identity(identity);
  27.122  
  27.123 @@ -231,9 +249,9 @@
  27.124  
  27.125      assert(identity);
  27.126      PEP_STATUS generate_status = generate_keypair(session, identity);
  27.127 -    cout << "generate_keypair() exits with " << generate_status << "\n";
  27.128 +    cout << "generate_keypair() exits with " << status(generate_status) << endl;
  27.129      assert(generate_status == PEP_STATUS_OK);
  27.130 -    cout << "generated key is " << identity->fpr << "\n";
  27.131 +    cout << "generated key is " << identity->fpr << endl;
  27.132  
  27.133      const string key(identity->fpr);
  27.134      free_identity(identity);
  27.135 @@ -243,13 +261,13 @@
  27.136  
  27.137      cout << "export_key()\n\n";
  27.138      PEP_STATUS export_status = export_key(session, key.c_str(), &key_data, &size);
  27.139 -    cout << "export_key() exits with " << export_status << "\n";
  27.140 +    cout << "export_key() exits with " << status(export_status) << endl;
  27.141      assert(export_status == PEP_STATUS_OK);
  27.142      cout << key_data << "\n\n";
  27.143  
  27.144 -    cout << "deleting key pair " << key.c_str() << "\n";
  27.145 +    cout << "deleting key pair " << key.c_str() << endl;
  27.146      PEP_STATUS delete_status = delete_keypair(session, key.c_str());
  27.147 -    cout << "delete_keypair() exits with " << delete_status << "\n";
  27.148 +    cout << "delete_keypair() exits with " << status(delete_status) << endl;
  27.149      assert(delete_status == PEP_STATUS_OK);
  27.150      
  27.151      cout << "import_key()\n";
  27.152 @@ -262,31 +280,31 @@
  27.153  
  27.154      cout << "deleting key " << key.c_str() << " again\n";
  27.155      delete_status = delete_keypair(session, key.c_str());
  27.156 -    cout << "delete_keypair() exits with " << delete_status << "\n";
  27.157 +    cout << "delete_keypair() exits with " << status(delete_status) << endl;
  27.158      assert(delete_status == PEP_STATUS_OK);
  27.159  
  27.160      cout << "finding key for pep.test.john@pep-project.org\n";
  27.161      PEP_STATUS find_keys_status = find_keys(session, "pep.test.john@pep-project.org", &keylist);
  27.162 -    cout << "find_keys() exits with " << find_keys_status << "\n";
  27.163 +    cout << "find_keys() exits with " << status(find_keys_status) << endl;
  27.164      assert(find_keys_status == PEP_STATUS_OK);
  27.165      assert(keylist);
  27.166 -    cout << "found: " << keylist->value << "\n";
  27.167 +    cout << "found: " << keylist->value << endl;
  27.168      assert(keylist->next == NULL);
  27.169      free_stringlist(keylist);
  27.170  
  27.171      cout << "searching for vb@ulm.ccc.de on keyserver\n";
  27.172      PEP_STATUS recv_key_status = recv_key(session, "vb@ulm.ccc.de");
  27.173 -    cout << "recv_key() exits with " << recv_key_status << "\n";
  27.174 +    cout << "recv_key() exits with " << status(recv_key_status) << endl;
  27.175      assert(recv_key_status == PEP_STATUS_OK);
  27.176  
  27.177      cout << "sending vb@ulm.ccc.de to keyserver\n";
  27.178      PEP_STATUS send_key_status = send_key(session, "vb@ulm.ccc.de");
  27.179 -    cout << "send_key() exits with " << send_key_status << "\n";
  27.180 +    cout << "send_key() exits with " << status(send_key_status) << endl;
  27.181      assert(send_key_status == PEP_STATUS_OK);
  27.182  
  27.183      PEP_comm_type tcomm_type;
  27.184      PEP_STATUS tstatus = get_key_rating(session, "BFCDB7F301DEEEBBF947F29659BFF488C9C2EE39", &tcomm_type);
  27.185 -    cout << "get_key_rating() exits with " << tstatus << "\n";
  27.186 +    cout << "get_key_rating() exits with " << status(tstatus) << endl;
  27.187      assert(tstatus == PEP_STATUS_OK);
  27.188      assert(tcomm_type == PEP_ct_OpenPGP_unconfirmed);
  27.189      
    28.1 --- a/test/trustwords_test.cc	Tue Mar 21 15:26:12 2017 +0100
    28.2 +++ b/test/trustwords_test.cc	Thu May 04 15:16:47 2017 +0200
    28.3 @@ -33,6 +33,12 @@
    28.4          "blargh",
    28.5          "Krista Grothoff");
    28.6      
    28.7 +    pEp_identity* identity2_with_spaces = new_identity(
    28.8 +        "krista@kgrothoff.org",
    28.9 +        " 62D4932086185C159 17B72D30571A FBCA    5493553   ",
   28.10 +        "blargh",
   28.11 +        "Krista Grothoff");
   28.12 +    
   28.13      string fingerprint1 = identity1->fpr;
   28.14      string fingerprint2 = identity2->fpr;
   28.15      char* words1 = nullptr;
   28.16 @@ -58,6 +64,11 @@
   28.17      get_trustwords(session, identity1, identity2, "de", &full_wordlist, &wsize_full, false);
   28.18      assert(full_wordlist);
   28.19      cout << full_wordlist << "\n";
   28.20 +
   28.21 +    cout << "\nfinding Englis trustwords for " << identity1->address << " and " << identity2->address << "... with spaces\n";
   28.22 +    get_trustwords(session, identity1, identity2_with_spaces, "en", &full_wordlist, &wsize_full, false);
   28.23 +    assert(full_wordlist);
   28.24 +    cout << full_wordlist << "\n";
   28.25      
   28.26      
   28.27      pEp_free(words1);
   28.28 @@ -79,6 +90,11 @@
   28.29      assert(full_wordlist);
   28.30      cout << full_wordlist << "\n";
   28.31  
   28.32 +    cout << "\nfinding English trustwords for " << identity2->address << " and " << identity2->address << "... with spaces\n";
   28.33 +    get_trustwords(session, identity2, identity2_with_spaces, "en", &full_wordlist, &wsize_full, false);
   28.34 +    assert(full_wordlist);
   28.35 +    cout << full_wordlist << "\n";
   28.36 +
   28.37      pEp_free(words1);
   28.38      words1 = nullptr;
   28.39      pEp_free(full_wordlist);
   28.40 @@ -101,6 +117,11 @@
   28.41      assert(full_wordlist);
   28.42      cout << full_wordlist << "\n";
   28.43      
   28.44 +    cout << "\nfinding English trustwords for " << identity2->address << " and " << identity2->address << "... with spaces\n";
   28.45 +    get_trustwords(session, identity2_with_spaces, identity1, "en", &full_wordlist, &wsize_full, false);
   28.46 +    assert(full_wordlist);
   28.47 +    cout << full_wordlist << "\n";
   28.48 +    
   28.49      pEp_free(words1);
   28.50      words1 = nullptr;
   28.51      pEp_free(words2);