merged in default message-2.0
authorKrista Bennett <krista@pep-project.org>
Tue, 13 Jun 2017 13:00:37 +0200
branchmessage-2.0
changeset 185518dce9e2977a
parent 1609 cc8da50d624b
parent 1852 8b786dad8b60
child 1890 2f85b57d9964
merged in default
     1.1 --- a/.hgignore	Tue Jan 31 08:42:25 2017 +0100
     1.2 +++ b/.hgignore	Tue Jun 13 13:00:37 2017 +0200
     1.3 @@ -47,10 +47,10 @@
     1.4  *.xml
     1.5  *.dot
     1.6  *.svg
     1.7 -.imported
     1.8  gpg-agent.conf
     1.9  gpg.conf
    1.10  pubring.gpg
    1.11  random_seed
    1.12  secring.gpg
    1.13  trustdb.gpg
    1.14 +.pEp_management.db
     2.1 --- a/Makefile.conf	Tue Jan 31 08:42:25 2017 +0100
     2.2 +++ b/Makefile.conf	Tue Jun 13 13:00:37 2017 +0200
     2.3 @@ -2,7 +2,7 @@
     2.4  
     2.5  BUILD_ON=$(shell uname)
     2.6  BUILD_FOR=$(BUILD_ON)
     2.7 -OPTIMIZE=-g -Wall -O0 -fPIC
     2.8 +OPTIMIZE=-g -Wall -O0 -fPIC -DDEBUG_ERRORSTACK
     2.9  #OPTIMIZE=-O3 -Wall -DNDEBUG -std=c99
    2.10  LD=$(CC)
    2.11  #CC=gcc-mp-4.9 -std=c99 -fstrict-aliasing -Wstrict-aliasing=3
    2.12 @@ -10,10 +10,11 @@
    2.13  SYSTEM_DB=/usr/local/share/pEp/system.db
    2.14  PREFIX=$(HOME)
    2.15  YML2PROC=$(HOME)/yml2/yml2proc
    2.16 +YML_OPTS=--encoding=utf8
    2.17  YML_PATH=$(HOME)/yml2
    2.18  ASN1C=asn1c
    2.19  ASN1C_INCLUDE=/opt/local/share/asn1c
    2.20 -#LIBGPGME=/opt/local/lib/libgpgme-pthread.11.dylib
    2.21 +#LIBGPGME=/opt/local/lib/libgpgme.11.dylib
    2.22  
    2.23  # C makros (not environment variables) to overwrite:
    2.24  #
     3.1 --- a/README-OSX.md	Tue Jan 31 08:42:25 2017 +0100
     3.2 +++ b/README-OSX.md	Tue Jun 13 13:00:37 2017 +0200
     3.3 @@ -1,38 +1,30 @@
     3.4 -# this file is under Creative Commons License 3.0 cc-by-sa
     3.5 +This file is under Creative Commons License 3.0 cc-by-sa
     3.6  
     3.7  # Building for OS X/macOS
     3.8 -
     3.9  See also README.txt for general information.
    3.10  
    3.11 -## Environment
    3.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.
    3.13  
    3.14 -`export LANG=en_US.UTF-8` is recommended on OS X.
    3.15 -
    3.16 -`export DYLD_FALLBACK_LIBRARY_PATH=$HOME/lib:/opt/local/lib` will help if you
    3.17 -build in your home and with MacPorts.
    3.18 +```
    3.19 +export LANG=en_US.UTF-8
    3.20 +```
    3.21  
    3.22  ## Dependencies
    3.23  
    3.24  ### MacPorts
    3.25 +[Install MacPorts](https://www.macports.org/install.php) for your version of OS X/macOS.
    3.26  
    3.27 -Install [MacPorts](https://www.macports.org/) for your
    3.28 -[version of OS X/macOS](https://www.macports.org/install.php).
    3.29 -
    3.30 -Note that you need [Xcode installed](https://www.macports.org/install.php)
    3.31 -for MacPorts, and for building the engine. You also need to accept Xcode's EULA.
    3.32 -
    3.33 -#### MacPorts dependencies
    3.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`:
    3.35  
    3.36  ```
    3.37 -sudo port install mercurial
    3.38 -sudo port install py27-lxml
    3.39 -sudo port install gpgme
    3.40 -sudo port install automake
    3.41 -sudo port install asn1c
    3.42 -sudo port install zlib
    3.43 +export PATH="/opt/local/bin:/opt/local/sbin:$PATH"
    3.44  ```
    3.45  
    3.46 -There are others, please refer to the engine README.txt.
    3.47 +Install dependencies packaged with MacPorts as follows.
    3.48 +
    3.49 +```
    3.50 +sudo port install mercurial py27-lxml gpgme autoconf automake libtool asn1c zlib openssl libiconv cyrus-sasl2
    3.51 +```
    3.52  
    3.53  Make sure that `python` is a version 2 one:
    3.54  
    3.55 @@ -40,10 +32,46 @@
    3.56  sudo port select python python27
    3.57  ```
    3.58  
    3.59 -### Other dependecies
    3.60 +### NetPGP (if not GPGME)
    3.61 +
    3.62 +#### Prepare :
    3.63 +
    3.64 +Get OpenSSL and build/install it as shared library.
    3.65 +
    3.66 +```
    3.67 +wget https://www.openssl.org/source/old/1.0.1/openssl-1.0.1u.tar.gz
    3.68 +tar xvfz openssl-1.0.1u.tar.gz
    3.69 +cd openssl-1.0.1u
    3.70 +./Configure darwin64-x86_64-cc --prefix=$HOME shared
    3.71 +make install
    3.72 +```
    3.73 +
    3.74 +Get and autoconf NetPGP
    3.75 +
    3.76 +```
    3.77 +cd $SRC
    3.78 +hg clone https://cacert.pep.foundation/dev/repos/netpgp-et/
    3.79 +cd netpgp-et
    3.80 +autoreconf -i
    3.81 +```
    3.82 +
    3.83 +#### Build
    3.84 +
    3.85 +Important : LDFLAGS is set to help finding OpenSSL shared lib. If not set,
    3.86 +system's default libcrypto may silently be used instead, causing memory
    3.87 +corruption or crash at runtime.
    3.88 +
    3.89 +```
    3.90 +mkdir netpgp_debug
    3.91 +cd netpgp_debug
    3.92 +$SRC/netpgp-et/configure --with-openssl=$HOME --prefix=$HOME CPPFLAGS=-DDEBUG CXXFLAGS="-g -O0" LDFLAGS="-L${HOME}/lib"
    3.93 +make
    3.94 +make install
    3.95 +```
    3.96 +
    3.97 +### Other Dependecies
    3.98  
    3.99  #### [yml2](https://fdik.org/yml/toolchain)
   3.100 -
   3.101  Install into your home directory:
   3.102  
   3.103  ```
   3.104 @@ -58,16 +86,21 @@
   3.105  functions seem to have been renamed there. Therefore the dynlib from OS X is used.
   3.106  
   3.107  ```
   3.108 -git clone https://github.com/fdik/libetpan libetpan-osx
   3.109 -cd libetpan-osx/
   3.110 -./autogen.sh
   3.111 +git clone https://github.com/fdik/libetpan
   3.112 +cd libetpan
   3.113 +./autogen.sh --prefix "$HOME"
   3.114  make
   3.115 -cp ./src/.libs/libetpan.a ~/lib/
   3.116 +make install
   3.117  ```
   3.118  
   3.119 +## Building pEp Engine
   3.120 +
   3.121  ### Configuration
   3.122 +You can change some defaults by editing `Makefile.conf`. The following variable needs to be set appropriately:
   3.123  
   3.124 -You can change some defaults by editing `Makefile.conf`. But this readme assumes you don't.
   3.125 +```
   3.126 +LIBGPGME=/opt/local/lib/libgpgme.11.dylib
   3.127 +```
   3.128  
   3.129  ### Build
   3.130  
   3.131 @@ -77,30 +110,21 @@
   3.132  make db
   3.133  ```
   3.134  
   3.135 -Done! The result should be (among others):
   3.136 -
   3.137 -```
   3.138 -./src/libpEpEngine.a
   3.139 -./src/libpEpEngine.dylib
   3.140 -```
   3.141 -
   3.142 -### Install
   3.143 -
   3.144 -Install (you might need sudo for some commands, depending on how your system is set up):
   3.145 +### Installation
   3.146  
   3.147  ```
   3.148  make install
   3.149 -make -C db install
   3.150 +sudo make -C db install
   3.151  ```
   3.152  
   3.153 -Since the `system.db` rarely changes, `make -C db install` is not needed for every build.
   3.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.
   3.155  
   3.156  ### Run tests
   3.157  
   3.158 -If you installed the test keys in your keyring (README.txt),
   3.159 -this should just work:
   3.160 +If you installed the test keys in your keyring (see: README.txt), this should just work:
   3.161  
   3.162  ```
   3.163 +cd test
   3.164  make test
   3.165  ```
   3.166  
     4.1 --- a/README.txt	Tue Jan 31 08:42:25 2017 +0100
     4.2 +++ b/README.txt	Tue Jun 13 13:00:37 2017 +0200
     4.3 @@ -56,7 +56,7 @@
     4.4  
     4.5  * Cyrus SASL, see http://cyrusimap.org/
     4.6  
     4.7 -* GnuPG via GPGME, see https://gnupg.org/
     4.8 +* GnuPG via GPGME, version 1.6.0 or newer, see https://gnupg.org/
     4.9  
    4.10  * NetPGP/p≡p, see https://cacert.pep.foundation/dev/repos/netpgp-et/
    4.11  
     5.1 --- a/asn.1/devicegroup.asn1	Tue Jan 31 08:42:25 2017 +0100
     5.2 +++ b/asn.1/devicegroup.asn1	Tue Jun 13 13:00:37 2017 +0200
     5.3 @@ -14,11 +14,17 @@
     5.4  Beacon ::= NULL
     5.5  
     5.6  HandshakeRequest ::= SEQUENCE {
     5.7 -    partner Identity /* identity of the receiver */
     5.8 +    /* UUID of receiver, group UUID if grouped */
     5.9 +    partner-id     UTF8String  (SIZE(1..1024)) OPTIONAL,
    5.10 +    /* Group UUID of sender, if grouped */
    5.11 +    group-id       UTF8String  (SIZE(1..1024)) OPTIONAL
    5.12  }
    5.13  
    5.14  GroupKeys ::= SEQUENCE {
    5.15 -    partner Identity, /* identity of the receiver */
    5.16 +    /* UUID of receiver */
    5.17 +    partner-id     UTF8String  (SIZE(1..1024)) OPTIONAL,
    5.18 +    /* Group UUID of sender */
    5.19 +    group-id       UTF8String  (SIZE(1..1024)) OPTIONAL,
    5.20      ownIdentities IdentityList
    5.21  }
    5.22  
     6.1 --- a/build-mac/pEpEngine.xcodeproj/project.pbxproj	Tue Jan 31 08:42:25 2017 +0100
     6.2 +++ b/build-mac/pEpEngine.xcodeproj/project.pbxproj	Tue Jun 13 13:00:37 2017 +0200
     6.3 @@ -190,6 +190,7 @@
     6.4  
     6.5  /* Begin PBXFileReference section */
     6.6  		430D258A1C9ED75A00B94535 /* blacklist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = blacklist.c; path = ../src/blacklist.c; sourceTree = "<group>"; };
     6.7 +		4346F86A1ECB38E700381CBE /* sync_app.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = sync_app.h; path = ../src/sync_app.h; sourceTree = "<group>"; };
     6.8  		4354FF641D6EDF300033069C /* sync_impl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sync_impl.c; path = ../src/sync_impl.c; sourceTree = "<group>"; };
     6.9  		4354FF681D6EE1A70033069C /* NULL.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = NULL.c; path = ../asn.1/NULL.c; sourceTree = "<group>"; };
    6.10  		43BA0F451D7964750059172F /* asn1_helper.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = asn1_helper.c; path = ../src/asn1_helper.c; sourceTree = "<group>"; };
    6.11 @@ -292,7 +293,7 @@
    6.12  		646C414C1D510D8800C63EFF /* baseprotocol.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = baseprotocol.c; path = ../src/baseprotocol.c; sourceTree = "<group>"; };
    6.13  		646C414D1D510D8800C63EFF /* baseprotocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = baseprotocol.h; path = ../src/baseprotocol.h; sourceTree = "<group>"; };
    6.14  		64796A3F1B455AA5004B1C24 /* libpEpEngine.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libpEpEngine.a; sourceTree = BUILT_PRODUCTS_DIR; };
    6.15 -		64951A1B1BE0FCD800B10E71 /* system.db */ = {isa = PBXFileReference; lastKnownFileType = file; name = system.db; path = ../db/system.db; sourceTree = "<group>"; };
    6.16 +		64951A1B1BE0FCD800B10E71 /* system.db */ = {isa = PBXFileReference; lastKnownFileType = text; name = system.db; path = ../db/system.db; sourceTree = "<group>"; };
    6.17  		649DE08A1B45C19100912F72 /* libcurl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libcurl.a; sourceTree = "<group>"; };
    6.18  		64A8264C1B455D0800EECAF0 /* bloblist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bloblist.c; path = ../src/bloblist.c; sourceTree = "<group>"; };
    6.19  		64A8264D1B455D0800EECAF0 /* bloblist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bloblist.h; path = ../src/bloblist.h; sourceTree = "<group>"; };
    6.20 @@ -517,6 +518,7 @@
    6.21  				646C41421D510D2C00C63EFF /* sync_send_actions.c */,
    6.22  				646C41431D510D2C00C63EFF /* sync.c */,
    6.23  				646C41441D510D2C00C63EFF /* sync.h */,
    6.24 +				4346F86A1ECB38E700381CBE /* sync_app.h */,
    6.25  				646788871CEB3D120001F54C /* map_asn1.c */,
    6.26  				646788881CEB3D120001F54C /* map_asn1.h */,
    6.27  				430D258A1C9ED75A00B94535 /* blacklist.c */,
    6.28 @@ -779,7 +781,7 @@
    6.29  			);
    6.30  			runOnlyForDeploymentPostprocessing = 0;
    6.31  			shellPath = /bin/sh;
    6.32 -			shellScript = "mkdir -p \"$BUILT_PRODUCTS_DIR/include\"\n\ncp \"$SRCROOT/../src/\"{\\\npEpEngine.h,\\\ncryptotech.h,\\\nkeymanagement.h,\\\nmessage_api.h,\\\ndynamic_api.h,\\\nstringlist.h,\\\ntimestamp.h,\\\nidentity_list.h,\\\nbloblist.h,\\\nstringpair.h,\\\nmessage.h,\\\nmime.h} \"$BUILT_PRODUCTS_DIR/include\"\n\nbash -l -c \"make -C ../asn.1 generate\"\nbash -l -c \"make -C ../asn.1\"\nbash -l -c \"LC_ALL=en_US.UTF-8 YML_PATH=$HOME/yml2 make -C ../sync\"\n";
    6.33 +			shellScript = "mkdir -p \"$BUILT_PRODUCTS_DIR/include\"\n\ncp \"$SRCROOT/../src/\"{\\\npEpEngine.h,\\\ncryptotech.h,\\\nkeymanagement.h,\\\nmessage_api.h,\\\ndynamic_api.h,\\\nstringlist.h,\\\ntimestamp.h,\\\nidentity_list.h,\\\nbloblist.h,\\\nstringpair.h,\\\nmessage.h,\\\nmime.h,\\\nsync_fsm.h,\\\nsync.h,\\\nsync_app.h} \"$BUILT_PRODUCTS_DIR/include\"\n\nbash -l -c \"make -C ../asn.1 generate\"\nbash -l -c \"make -C ../asn.1\"\nbash -l -c \"LC_ALL=en_US.UTF-8 YML_PATH=$HOME/yml2 make -C ../sync\"\n";
    6.34  		};
    6.35  /* End PBXShellScriptBuildPhase section */
    6.36  
    6.37 @@ -947,7 +949,7 @@
    6.38  					"$(SRCROOT)",
    6.39  					"$(SRCROOT)/../../netpgp-et/include/",
    6.40  					"$(SRCROOT)/../../netpgp-et/src/",
    6.41 -					"$(SRCROOT)/../../netpgp-et/netpgp-xcode/openssl/include/",
    6.42 +					"$(SRCROOT)/../../OpenSSL-for-iPhone/include",
    6.43  					"$(SRCROOT)/../asn.1/",
    6.44  				);
    6.45  				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
    6.46 @@ -994,7 +996,7 @@
    6.47  					"$(SRCROOT)",
    6.48  					"$(SRCROOT)/../../netpgp-et/include/",
    6.49  					"$(SRCROOT)/../../netpgp-et/src/",
    6.50 -					"$(SRCROOT)/../../netpgp-et/netpgp-xcode/openssl/include/",
    6.51 +					"$(SRCROOT)/../../OpenSSL-for-iPhone/include",
    6.52  					"$(SRCROOT)/../asn.1/",
    6.53  				);
    6.54  				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
     7.1 --- a/db/create_system_db.sql	Tue Jan 31 08:42:25 2017 +0100
     7.2 +++ b/db/create_system_db.sql	Tue Jun 13 13:00:37 2017 +0200
     7.3 @@ -46,5 +46,8 @@
     7.4  
     7.5  INSERT INTO i18n_language VALUES ('tr', 'Türkçe');
     7.6  INSERT INTO i18n_token VALUES ('tr', 1000, 'Güvenlik kelimelerini Türkçe görüntülemek istiyorum');
     7.7 +
     7.8 +INSERT INTO i18n_language VALUES ('nl', 'Nederlands');
     7.9 +INSERT INTO i18n_token VALUES ('nl', 1000, 'Ik wil de trustwords in de nederlandse taal laten zien');
    7.10  -- add more languages here
    7.11  
     8.1 --- a/src/Makefile	Tue Jan 31 08:42:25 2017 +0100
     8.2 +++ b/src/Makefile	Tue Jun 13 13:00:37 2017 +0200
     8.3 @@ -1,20 +1,19 @@
     8.4  include ../Makefile.conf
     8.5  
     8.6 -OPENPGP?=GPG
     8.7 +ETPAN_IN?=$(HOME)
     8.8  
     8.9  ifeq ($(BUILD_ON),Darwin)
    8.10  ifeq ($(BUILD_FOR),Darwin)
    8.11  
    8.12  TARGET?=libpEpEngine.dylib
    8.13  MACOSX_VERSION_MIN=10.6
    8.14 -GPGME_IN=$(HOME)
    8.15  LIBGPGME?=libgpgme.dylib
    8.16  CC?=clang -std=c99 -pthread
    8.17  LD?=clang
    8.18 -CFLAGS?=-I$(GPGME_IN)/include -I$(HOME)/include -I/opt/local/include $(OPTIMIZE) -pedantic \
    8.19 -	-DSYSTEM_DB=\"$(SYSTEM_DB)\" -DLIBGPGME=\"$(LIBGPGME)\" -I../asn.1 $(EXTRAMACROS)
    8.20 -LDFLAGS?=-lc -shared -arch x86_64 \
    8.21 -	-L$(HOME)/lib -L/usr/lib -L/opt/local/lib -letpan -lsqlite3 -L../asn.1 -lasn1 -lz -liconv
    8.22 +CFLAGS?= -I$(ETPAN_IN)/include -I/opt/local/include $(OPTIMIZE) -pedantic \
    8.23 +	-DSYSTEM_DB=\"$(SYSTEM_DB)\" -I../asn.1 $(EXTRAMACROS)
    8.24 +LDFLAGS?= -lc -shared -arch x86_64 \
    8.25 +	-L$(ETPAN_IN)/lib -L/usr/lib -L/opt/local/lib -letpan -lsqlite3 -L../asn.1 -lasn1 -lz -liconv
    8.26  
    8.27  else
    8.28  $(error don't know how to make for $(BUILD_FOR) on $(BUILD_ON))
    8.29 @@ -24,13 +23,11 @@
    8.30  ifeq ($(BUILD_FOR),Linux)
    8.31  
    8.32  TARGET=libpEpEngine.so
    8.33 -GPGME_IN=$(HOME)
    8.34 -LIBGPGME=libgpgme.so.11
    8.35 +LIBGPGME?=libgpgme.so.11
    8.36  CC=gcc -std=c99
    8.37 -CFLAGS?=-I$(GPGME_IN)/include $(OPTIMIZE) -fPIC -pedantic \
    8.38 -	-DSYSTEM_DB=\"$(SYSTEM_DB)\" -DLIBGPGME=\"$(LIBGPGME)\" \
    8.39 +CFLAGS?= $(OPTIMIZE) -fPIC -pedantic -DSYSTEM_DB=\"$(SYSTEM_DB)\" \
    8.40  	-DSQLITE_THREADSAFE=1 -D_GNU_SOURCE -I../asn.1 $(EXTRAMACROS)
    8.41 -LDFLAGS?=-L$(GPGME_IN)/lib -shared -lc -ldl -letpan -lpthread -L../asn.1 -lasn1
    8.42 +LDFLAGS?= -L$(ETPAN_IN)/lib -shared -lc -ldl -letpan -lpthread -L../asn.1 -lasn1 -luuid
    8.43  
    8.44  else
    8.45  $(error don't know how to make for $(BUILD_FOR) on $(BUILD_ON))
    8.46 @@ -40,14 +37,22 @@
    8.47  $(error don't know how to make for $(BUILD_FOR) on $(BUILD_ON))
    8.48  endif
    8.49  
    8.50 +DEBUG?=NO
    8.51 +ifeq ("$(DEBUG)","NO")
    8.52 +    CFLAGS+= -DNDEBUG
    8.53 +endif
    8.54 +
    8.55 +OPENPGP?=GPG
    8.56  ifeq ("$(OPENPGP)","GPG")
    8.57 -	NO_SOURCE=pgp_netpgp.c
    8.58 -	CFLAGS+= -DUSE_GPG
    8.59 -	LDFLAGS+= -lgpgme
    8.60 +    NO_SOURCE=pgp_netpgp.c
    8.61 +    GPGME_IN?=$(HOME)
    8.62 +    CFLAGS+= -DUSE_GPG -I$(GPGME_IN)/include -DLIBGPGME=\"$(LIBGPGME)\"
    8.63 +    #LDFLAGS+= -L$(GPGME_IN)/lib -lgpgme
    8.64  else ifeq ("$(OPENPGP)","NETPGP")
    8.65 -	NO_SOURCE=pgp_gpg.c
    8.66 -	CFLAGS+= -DUSE_NETPGP
    8.67 -	LDFLAGS+= -lnetpgp -lcurl
    8.68 +    NO_SOURCE=pgp_gpg.c
    8.69 +    NETPGP_IN?=$(HOME)
    8.70 +    CFLAGS+= -DUSE_NETPGP -I$(NETPGP_IN)/include
    8.71 +    LDFLAGS+= -L$(NETPGP_IN)/lib -lnetpgp -lcurl
    8.72  else
    8.73  	$(error Unknown OpenPGP library : $(OPENPGP))
    8.74  endif
    8.75 @@ -88,7 +93,7 @@
    8.76  install: $(TARGET)
    8.77  	cp $< $(PREFIX)/lib/
    8.78  	mkdir -p $(PREFIX)/include/pEp
    8.79 -	cp pEpEngine.h keymanagement.h message_api.h dynamic_api.h stringlist.h timestamp.h identity_list.h bloblist.h stringpair.h message.h mime.h cryptotech.h sync.h sync_fsm.h blacklist.h openpgp_compat.h $(PREFIX)/include/pEp/
    8.80 +	cp pEpEngine.h keymanagement.h message_api.h dynamic_api.h stringlist.h timestamp.h identity_list.h bloblist.h stringpair.h message.h mime.h cryptotech.h sync.h sync_fsm.h sync_app.h blacklist.h openpgp_compat.h $(PREFIX)/include/pEp/
    8.81  
    8.82  uninstall:
    8.83  	rm -f $(PREFIX)/lib/$(TARGET)
     9.1 --- a/src/cryptotech.c	Tue Jan 31 08:42:25 2017 +0100
     9.2 +++ b/src/cryptotech.c	Tue Jun 13 13:00:37 2017 +0200
     9.3 @@ -36,6 +36,7 @@
     9.4          cryptotech[PEP_crypt_OpenPGP].confirmed_comm_type = PEP_ct_OpenPGP;
     9.5          cryptotech[PEP_crypt_OpenPGP].decrypt_and_verify = pgp_decrypt_and_verify;
     9.6          cryptotech[PEP_crypt_OpenPGP].encrypt_and_sign = pgp_encrypt_and_sign;
     9.7 +        cryptotech[PEP_crypt_OpenPGP].encrypt_only = pgp_encrypt_only;
     9.8          cryptotech[PEP_crypt_OpenPGP].verify_text = pgp_verify_text;
     9.9          cryptotech[PEP_crypt_OpenPGP].delete_keypair = pgp_delete_keypair;
    9.10          cryptotech[PEP_crypt_OpenPGP].export_key = pgp_export_keydata;
    10.1 --- a/src/cryptotech.h	Tue Jan 31 08:42:25 2017 +0100
    10.2 +++ b/src/cryptotech.h	Tue Jun 13 13:00:37 2017 +0200
    10.3 @@ -32,6 +32,11 @@
    10.4          size_t psize, char **ctext, size_t *csize
    10.5      );
    10.6  
    10.7 +typedef PEP_STATUS (*encrypt_only_t)(
    10.8 +        PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
    10.9 +        size_t psize, char **ctext, size_t *csize
   10.10 +    );
   10.11 +
   10.12  typedef PEP_STATUS (*delete_keypair_t)(PEP_SESSION session, const char *fpr);
   10.13  
   10.14  typedef PEP_STATUS (*export_key_t)(
   10.15 @@ -92,6 +97,7 @@
   10.16      decrypt_and_verify_t decrypt_and_verify;
   10.17      verify_text_t verify_text;
   10.18      encrypt_and_sign_t encrypt_and_sign;
   10.19 +    encrypt_only_t encrypt_only;
   10.20      delete_keypair_t delete_keypair;
   10.21      export_key_t export_key;
   10.22      find_keys_t find_keys;
    11.1 --- a/src/keymanagement.c	Tue Jan 31 08:42:25 2017 +0100
    11.2 +++ b/src/keymanagement.c	Tue Jun 13 13:00:37 2017 +0200
    11.3 @@ -91,7 +91,7 @@
    11.4      assert(!EMPTYSTR(identity->address));
    11.5  
    11.6      if (!(session && identity && !EMPTYSTR(identity->address)))
    11.7 -        return PEP_ILLEGAL_VALUE;
    11.8 +        return ERROR(PEP_ILLEGAL_VALUE);
    11.9  
   11.10      if (identity->me || (identity->user_id && strcmp(identity->user_id, PEP_OWN_USERID) == 0)) {
   11.11          identity->me = true;
   11.12 @@ -144,9 +144,23 @@
   11.13  
   11.14          /* if we have a stored_identity fpr */
   11.15          if (!EMPTYSTR(stored_identity->fpr)) {
   11.16 -            status = blacklist_is_listed(session, stored_identity->fpr, &dont_use_stored_fpr);
   11.17 -            if (status != PEP_STATUS_OK)
   11.18 -                dont_use_stored_fpr = true; 
   11.19 +            bool revoked = false;
   11.20 +            status = key_revoked(session, stored_identity->fpr, &revoked);
   11.21 +            
   11.22 +            if (status != PEP_STATUS_OK || revoked)
   11.23 +                dont_use_stored_fpr = true;
   11.24 +                
   11.25 +            if (revoked) {
   11.26 +                // Do stuff
   11.27 +                status = update_trust_for_fpr(session, stored_identity->fpr, PEP_ct_key_revoked);
   11.28 +                // What to do on failure? FIXME
   11.29 +                status = replace_identities_fpr(session, stored_identity->fpr, "");
   11.30 +            }
   11.31 +            else {    
   11.32 +                status = blacklist_is_listed(session, stored_identity->fpr, &dont_use_stored_fpr);
   11.33 +                if (status != PEP_STATUS_OK)
   11.34 +                    dont_use_stored_fpr = true; 
   11.35 +            }
   11.36          }
   11.37              
   11.38  
   11.39 @@ -179,10 +193,11 @@
   11.40                         downgrade eventually trusted comm_type */
   11.41                      temp_id->comm_type = _comm_type_key;
   11.42                  } else {
   11.43 -                    /* otherwise take stored comm_type as-is */
   11.44 +                    /* otherwise take stored comm_type as-is except if 
   11.45 +                       is unknown or is expired (but key not expired anymore) */
   11.46                      temp_id->comm_type = stored_identity->comm_type;
   11.47 -                    if (temp_id->comm_type == PEP_ct_unknown) {
   11.48 -                        /* except if unknown */
   11.49 +                    if (temp_id->comm_type == PEP_ct_unknown ||
   11.50 +                        temp_id->comm_type == PEP_ct_key_expired) {
   11.51                          temp_id->comm_type = _comm_type_key;
   11.52                      }
   11.53                  }
   11.54 @@ -311,7 +326,7 @@
   11.55      free_identity(stored_identity);
   11.56      free_identity(temp_id);
   11.57      
   11.58 -    return status;
   11.59 +    return ERROR(status);
   11.60  }
   11.61  
   11.62  PEP_STATUS elect_ownkey(
   11.63 @@ -338,19 +353,14 @@
   11.64          for (_keylist = keylist; _keylist && _keylist->value; _keylist = _keylist->next) {
   11.65              bool is_own = false;
   11.66              
   11.67 -            if (session->use_only_own_private_keys)
   11.68 -            {
   11.69 -                status = own_key_is_listed(session, _keylist->value, &is_own);
   11.70 -                assert(status == PEP_STATUS_OK);
   11.71 -                if (status != PEP_STATUS_OK) {
   11.72 -                    free_stringlist(keylist);
   11.73 -                    return status;
   11.74 -                }
   11.75 +            status = own_key_is_listed(session, _keylist->value, &is_own);
   11.76 +            assert(status == PEP_STATUS_OK);
   11.77 +            if (status != PEP_STATUS_OK) {
   11.78 +                free_stringlist(keylist);
   11.79 +                return status;
   11.80              }
   11.81 -
   11.82 -            // TODO : also accept synchronized device group keys ?
   11.83              
   11.84 -            if (!session->use_only_own_private_keys || is_own)
   11.85 +            if (is_own)
   11.86              {
   11.87                  PEP_comm_type _comm_type_key;
   11.88                  
   11.89 @@ -406,7 +416,7 @@
   11.90      
   11.91      *is_usable = !dont_use_fpr;
   11.92      
   11.93 -    return status;
   11.94 +    return ERROR(status);
   11.95  }
   11.96  
   11.97  PEP_STATUS _myself(PEP_SESSION session, pEp_identity * identity, bool do_keygen, bool ignore_flags)
   11.98 @@ -424,7 +434,7 @@
   11.99      if (!(session && identity && !EMPTYSTR(identity->address) &&
  11.100              (EMPTYSTR(identity->user_id) ||
  11.101              strcmp(identity->user_id, PEP_OWN_USERID) == 0)))
  11.102 -        return PEP_ILLEGAL_VALUE;
  11.103 +        return ERROR(PEP_ILLEGAL_VALUE);
  11.104  
  11.105      identity->comm_type = PEP_ct_pEp;
  11.106      identity->me = true;
  11.107 @@ -512,7 +522,7 @@
  11.108          status = elect_ownkey(session, identity);
  11.109          assert(status == PEP_STATUS_OK);
  11.110          if (status != PEP_STATUS_OK) {
  11.111 -            return status;
  11.112 +            return ERROR(status);
  11.113          }
  11.114  
  11.115          bool has_private = false;
  11.116 @@ -542,27 +552,18 @@
  11.117      {
  11.118          status = key_revoked(session, identity->fpr, &revoked);
  11.119  
  11.120 -        // Forces re-election if key is missing and own-key-only not forced
  11.121 -        if (!session->use_only_own_private_keys && status == PEP_KEY_NOT_FOUND) 
  11.122 +        if (status != PEP_STATUS_OK) 
  11.123          {
  11.124 -            status = elect_ownkey(session, identity);
  11.125 -            assert(status == PEP_STATUS_OK);
  11.126 -            if (status != PEP_STATUS_OK) {
  11.127 -                return status;
  11.128 -            }
  11.129 -        } 
  11.130 -        else if (status != PEP_STATUS_OK) 
  11.131 -        {
  11.132 -            return status;
  11.133 +            return ERROR(status);
  11.134          }
  11.135      }
  11.136     
  11.137      bool new_key_generated = false;
  11.138  
  11.139      if (EMPTYSTR(identity->fpr) || revoked)
  11.140 -    {        
  11.141 +    {
  11.142          if(!do_keygen){
  11.143 -            return PEP_GET_KEY_FAILED;
  11.144 +            return ERROR(PEP_GET_KEY_FAILED);
  11.145          }
  11.146  
  11.147          if(revoked)
  11.148 @@ -580,7 +581,7 @@
  11.149              DEBUG_LOG("generating key pair failed", "debug", buf);
  11.150              if(revoked && r_fpr)
  11.151                  free(r_fpr);
  11.152 -            return status;
  11.153 +            return ERROR(status);
  11.154          }
  11.155  
  11.156          new_key_generated = true;
  11.157 @@ -591,7 +592,7 @@
  11.158                                   identity->fpr, time(NULL));
  11.159              free(r_fpr);
  11.160              if (status != PEP_STATUS_OK) {
  11.161 -                return status;
  11.162 +                return ERROR(status);
  11.163              }
  11.164          }
  11.165      }
  11.166 @@ -604,7 +605,7 @@
  11.167  
  11.168          assert(status == PEP_STATUS_OK);
  11.169          if (status != PEP_STATUS_OK) {
  11.170 -            return status;
  11.171 +            return ERROR(status);
  11.172          }
  11.173  
  11.174          if (status == PEP_STATUS_OK && expired) {
  11.175 @@ -632,12 +633,12 @@
  11.176          }
  11.177      }
  11.178  
  11.179 -    return PEP_STATUS_OK;
  11.180 +    return ERROR(PEP_STATUS_OK);
  11.181  }
  11.182  
  11.183  DYNAMIC_API PEP_STATUS myself(PEP_SESSION session, pEp_identity * identity)
  11.184  {
  11.185 -    return _myself(session, identity, true, false);
  11.186 +    return ERROR(_myself(session, identity, true, false));
  11.187  }
  11.188  
  11.189  DYNAMIC_API PEP_STATUS register_examine_function(
  11.190 @@ -779,10 +780,10 @@
  11.191      assert(!EMPTYSTR(ident->address));
  11.192      assert(!EMPTYSTR(ident->user_id));
  11.193      assert(!EMPTYSTR(ident->fpr));
  11.194 -    assert(!ident->me);
  11.195 +//    assert(!ident->me);
  11.196  
  11.197      if (!ident || EMPTYSTR(ident->address) || EMPTYSTR(ident->user_id) ||
  11.198 -            EMPTYSTR(ident->fpr) || ident->me)
  11.199 +            EMPTYSTR(ident->fpr)) // || ident->me)
  11.200          return PEP_ILLEGAL_VALUE;
  11.201  
  11.202      status = update_identity(session, ident);
  11.203 @@ -1009,7 +1010,7 @@
  11.204      return _own_keys_retrieve(session, keylist, 0);
  11.205  }
  11.206  
  11.207 -// TODO: Unused for now, but should be used when sync receive old keys (ENGINE-145)
  11.208 +// FIXME: should it be be used when sync receive old keys ? (ENGINE-145)
  11.209  DYNAMIC_API PEP_STATUS set_own_key(
  11.210         PEP_SESSION session,
  11.211         const char *address,
  11.212 @@ -1019,12 +1020,12 @@
  11.213      PEP_STATUS status = PEP_STATUS_OK;
  11.214      
  11.215      assert(session &&
  11.216 -           address && address[0] &&
  11.217 +           address &&
  11.218             fpr && fpr[0]
  11.219            );
  11.220      
  11.221      if (!(session &&
  11.222 -          address && address[0] &&
  11.223 +          address &&
  11.224            fpr && fpr[0]
  11.225           ))
  11.226          return PEP_ILLEGAL_VALUE;
    12.1 --- a/src/keymanagement.h	Tue Jan 31 08:42:25 2017 +0100
    12.2 +++ b/src/keymanagement.h	Tue Jun 13 13:00:37 2017 +0200
    12.3 @@ -15,6 +15,11 @@
    12.4  //      session (in)        session to use
    12.5  //      identity (inout)    identity information of communication partner
    12.6  //                          (identity->fpr is OUT ONLY)
    12.7 +//  return value:
    12.8 +//      PEP_STATUS_OK if identity could be updated,
    12.9 +//      PEP_GET_KEY_FAILED for own identity that must be completed (myself())
   12.10 +//      any other value on error
   12.11 +//
   12.12  //  caveat:
   12.13  //      if this function returns PEP_ct_unknown or PEP_ct_key_expired in
   12.14  //      identity->comm_type, the caller must insert the identity into the
   12.15 @@ -159,7 +164,6 @@
   12.16          pEp_identity *ident
   12.17      );
   12.18  
   12.19 -
   12.20  // own_key_is_listed() - returns true id key is listed as own key
   12.21  //
   12.22  //  parameters:
   12.23 @@ -235,7 +239,12 @@
   12.24          stringlist_t **keylist
   12.25        );
   12.26  
   12.27 +DYNAMIC_API PEP_STATUS set_own_key(
   12.28 +       PEP_SESSION session,
   12.29 +       const char *address,
   12.30 +       const char *fpr
   12.31 +    );
   12.32 +
   12.33  #ifdef __cplusplus
   12.34  }
   12.35  #endif
   12.36 -
    13.1 --- a/src/map_asn1.c	Tue Jan 31 08:42:25 2017 +0100
    13.2 +++ b/src/map_asn1.c	Tue Jun 13 13:00:37 2017 +0200
    13.3 @@ -9,12 +9,15 @@
    13.4          Identity_t *result
    13.5      )
    13.6  {
    13.7 +    bool allocated = !result;
    13.8 +
    13.9      assert(ident);
   13.10      if (!ident)
   13.11          return NULL;
   13.12  
   13.13 -    if (!result)
   13.14 +    if (allocated){
   13.15          result = (Identity_t *) calloc(1, sizeof(Identity_t));
   13.16 +    }
   13.17      assert(result);
   13.18      if (!result)
   13.19          return NULL;
   13.20 @@ -56,26 +59,34 @@
   13.21      if (ident->lang[0]) {
   13.22          int r = OCTET_STRING_fromBuf(&result->lang, ident->lang, 2);
   13.23          assert(r == 0);
   13.24 +        if(r != 0)
   13.25 +            goto enomem;
   13.26      }
   13.27      else {
   13.28          int r = OCTET_STRING_fromBuf(&result->lang, "en", 2);
   13.29          assert(r == 0);
   13.30 +        if(r != 0)
   13.31 +            goto enomem;
   13.32      }
   13.33  
   13.34      return result;
   13.35  
   13.36  enomem:
   13.37 -    ASN_STRUCT_FREE(asn_DEF_Identity, result);
   13.38 +    if (allocated){
   13.39 +        ASN_STRUCT_FREE(asn_DEF_Identity, result);
   13.40 +    }
   13.41      return NULL;
   13.42  }
   13.43  
   13.44  pEp_identity *Identity_to_Struct(Identity_t *ident, pEp_identity *result)
   13.45  {
   13.46 +    bool allocated = !result;
   13.47 +
   13.48      assert(ident);
   13.49      if (!ident)
   13.50          return NULL;
   13.51      
   13.52 -    if (!result)
   13.53 +    if (allocated)
   13.54          result = new_identity(NULL, NULL, NULL, NULL);
   13.55      if (!result)
   13.56          return NULL;
   13.57 @@ -121,7 +132,8 @@
   13.58      return result;
   13.59  
   13.60  enomem:
   13.61 -    free_identity(result);
   13.62 +    if (allocated)
   13.63 +        free_identity(result);
   13.64      return NULL;
   13.65  }
   13.66  
   13.67 @@ -130,11 +142,13 @@
   13.68          IdentityList_t *result
   13.69      )
   13.70  {
   13.71 +    bool allocated = !result;
   13.72 +
   13.73      assert(list);
   13.74      if (!list)
   13.75          return NULL;
   13.76  
   13.77 -    if (!result)
   13.78 +    if (allocated)
   13.79          result = (IdentityList_t *) calloc(1, sizeof(IdentityList_t));
   13.80      assert(result);
   13.81      if (!result)
   13.82 @@ -151,17 +165,20 @@
   13.83      return result;
   13.84  
   13.85  enomem:
   13.86 -    ASN_STRUCT_FREE(asn_DEF_IdentityList, result);
   13.87 +    if (allocated)
   13.88 +        ASN_STRUCT_FREE(asn_DEF_IdentityList, result);
   13.89      return NULL;
   13.90  }
   13.91  
   13.92  identity_list *IdentityList_to_identity_list(IdentityList_t *list, identity_list *result)
   13.93  {
   13.94 +    bool allocated = !result;
   13.95 +
   13.96      assert(list);
   13.97      if (!list)
   13.98          return NULL;
   13.99  
  13.100 -    if (!result)
  13.101 +    if (allocated)
  13.102          result = new_identity_list(NULL);
  13.103      if (!result)
  13.104          return NULL;
  13.105 @@ -177,7 +194,8 @@
  13.106      return result;
  13.107  
  13.108  enomem:
  13.109 -    free_identity_list(result);
  13.110 +    if (allocated)
  13.111 +        free_identity_list(result);
  13.112      return NULL;
  13.113  }
  13.114  
    14.1 --- a/src/message_api.c	Tue Jan 31 08:42:25 2017 +0100
    14.2 +++ b/src/message_api.c	Tue Jun 13 13:00:37 2017 +0200
    14.3 @@ -169,19 +169,22 @@
    14.4                      goto enomem;
    14.5              }
    14.6          }
    14.7 +        *shortmsg = _shortmsg;
    14.8      }
    14.9      else {
   14.10 -        _shortmsg = strdup("");
   14.11 -        assert(_shortmsg);
   14.12 -        if (_shortmsg == NULL)
   14.13 -            goto enomem;
   14.14 +        // If there's no "Subject: " and the shortmsg is
   14.15 +        // pEp (or anything else), then we shouldn't be replacing it.
   14.16 +        // Chances are that the message wasn't encrypted
   14.17 +        // using pEp and that the actually subject IS pEp. In any event,
   14.18 +        // erasing the subject line when we don't have one in the plaintext
   14.19 +        // isn't the right behaviour.
   14.20 +        // _shortmsg = strdup("");
   14.21          _longmsg = strdup(src);
   14.22          assert(_longmsg);
   14.23          if (_longmsg == NULL)
   14.24              goto enomem;
   14.25      }
   14.26 -
   14.27 -    *shortmsg = _shortmsg;
   14.28 +    
   14.29      *longmsg = _longmsg;
   14.30  
   14.31      return 0;
   14.32 @@ -340,7 +343,8 @@
   14.33      PEP_SESSION session,
   14.34      const message *src,
   14.35      stringlist_t *keys,
   14.36 -    message *dst
   14.37 +    message *dst,
   14.38 +    PEP_encrypt_flags_t flags
   14.39      )
   14.40  {
   14.41      PEP_STATUS status = PEP_STATUS_OK;
   14.42 @@ -396,8 +400,12 @@
   14.43      if (mimetext == NULL)
   14.44          goto pep_error;
   14.45  
   14.46 -    status = encrypt_and_sign(session, keys, mimetext, strlen(mimetext),
   14.47 -        &ctext, &csize);
   14.48 +    if (flags & PEP_encrypt_flag_force_unsigned)
   14.49 +        status = encrypt_only(session, keys, mimetext, strlen(mimetext),
   14.50 +            &ctext, &csize);
   14.51 +    else
   14.52 +        status = encrypt_and_sign(session, keys, mimetext, strlen(mimetext),
   14.53 +            &ctext, &csize);
   14.54      free(mimetext);
   14.55      if (ctext == NULL)
   14.56          goto pep_error;
   14.57 @@ -439,7 +447,8 @@
   14.58      PEP_SESSION session,
   14.59      const message *src,
   14.60      stringlist_t *keys,
   14.61 -    message *dst
   14.62 +    message *dst,
   14.63 +    PEP_encrypt_flags_t flags
   14.64      )
   14.65  {
   14.66      PEP_STATUS status = PEP_STATUS_OK;
   14.67 @@ -453,6 +462,8 @@
   14.68  
   14.69      dst->enc_format = PEP_enc_pieces;
   14.70  
   14.71 +    bool nosign = (flags & PEP_encrypt_flag_force_unsigned);
   14.72 +
   14.73      if (src->shortmsg && src->shortmsg[0] && strcmp(src->shortmsg, "pEp") != 0) {
   14.74          if (session->unencrypted_subject) {
   14.75              dst->shortmsg = strdup(src->shortmsg);
   14.76 @@ -468,8 +479,12 @@
   14.77              free_ptext = true;
   14.78          }
   14.79  
   14.80 -        status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
   14.81 -            &csize);
   14.82 +        if (nosign)
   14.83 +            status = encrypt_only(session, keys, ptext, strlen(ptext), &ctext,
   14.84 +                &csize);
   14.85 +        else 
   14.86 +            status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
   14.87 +                &csize);
   14.88          if (free_ptext)
   14.89              free(ptext);
   14.90          free_ptext = false;
   14.91 @@ -482,8 +497,12 @@
   14.92      }
   14.93      else if (src->longmsg && src->longmsg[0]) {
   14.94          ptext = src->longmsg;
   14.95 -        status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
   14.96 -            &csize);
   14.97 +        if (nosign)
   14.98 +            status = encrypt_only(session, keys, ptext, strlen(ptext), &ctext,
   14.99 +                &csize);
  14.100 +        else 
  14.101 +            status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
  14.102 +                &csize);
  14.103          if (ctext) {
  14.104              dst->longmsg = ctext;
  14.105          }
  14.106 @@ -500,8 +519,12 @@
  14.107  
  14.108      if (src->longmsg_formatted && src->longmsg_formatted[0]) {
  14.109          ptext = src->longmsg_formatted;
  14.110 -        status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
  14.111 -            &csize);
  14.112 +        if (nosign)
  14.113 +            status = encrypt_only(session, keys, ptext, strlen(ptext), &ctext,
  14.114 +                &csize);
  14.115 +        else 
  14.116 +            status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
  14.117 +                &csize);
  14.118          if (ctext) {
  14.119  
  14.120              bloblist_t *_a = bloblist_add(dst->attachments, ctext, csize,
  14.121 @@ -535,8 +558,12 @@
  14.122              else {
  14.123                  size_t psize = _s->size;
  14.124                  ptext = _s->value;
  14.125 -                status = encrypt_and_sign(session, keys, ptext, psize, &ctext,
  14.126 -                    &csize);
  14.127 +                if (nosign)
  14.128 +                    status = encrypt_only(session, keys, ptext, psize, &ctext,
  14.129 +                        &csize);
  14.130 +                else 
  14.131 +                    status = encrypt_and_sign(session, keys, ptext, psize, &ctext,
  14.132 +                        &csize);
  14.133                  if (ctext) {
  14.134                      char *filename = NULL;
  14.135  
  14.136 @@ -770,6 +797,7 @@
  14.137          return PEP_rating_unencrypted;
  14.138  
  14.139      case PEP_DECRYPTED:
  14.140 +    case PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH:
  14.141          return PEP_rating_unreliable;
  14.142  
  14.143      case PEP_DECRYPTED_AND_VERIFIED:
  14.144 @@ -789,7 +817,6 @@
  14.145  
  14.146  static PEP_rating key_rating(PEP_SESSION session, const char *fpr)
  14.147  {
  14.148 -    PEP_comm_type comm_type = PEP_ct_unknown;
  14.149  
  14.150      assert(session);
  14.151      assert(fpr);
  14.152 @@ -797,49 +824,70 @@
  14.153      if (session == NULL || fpr == NULL)
  14.154          return PEP_rating_undefined;
  14.155  
  14.156 -    PEP_STATUS status = get_key_rating(session, fpr, &comm_type);
  14.157 +
  14.158 +    PEP_comm_type bare_comm_type = PEP_ct_unknown;
  14.159 +    PEP_STATUS status = get_key_rating(session, fpr, &bare_comm_type);
  14.160      if (status != PEP_STATUS_OK)
  14.161          return PEP_rating_undefined;
  14.162  
  14.163 -    return _rating(comm_type, PEP_rating_undefined);
  14.164 +    PEP_comm_type least_trust_type = PEP_ct_unknown;
  14.165 +    least_trust(session, fpr, &least_trust_type);
  14.166 +
  14.167 +    if (least_trust_type == PEP_ct_unknown) {
  14.168 +        return _rating(bare_comm_type, PEP_rating_undefined);
  14.169 +    } else {
  14.170 +        return _rating(least_trust_type, PEP_rating_undefined);
  14.171 +    }
  14.172 +}
  14.173 +
  14.174 +static PEP_rating worst_rating(PEP_rating rating1, PEP_rating rating2) {
  14.175 +    return ((rating1 < rating2) ? rating1 : rating2);
  14.176  }
  14.177  
  14.178  static PEP_rating keylist_rating(PEP_SESSION session, stringlist_t *keylist)
  14.179  {
  14.180 -    PEP_rating rating = PEP_rating_reliable;
  14.181 +    PEP_rating rating = PEP_rating_undefined;
  14.182  
  14.183      assert(keylist && keylist->value);
  14.184      if (keylist == NULL || keylist->value == NULL)
  14.185          return PEP_rating_undefined;
  14.186  
  14.187      stringlist_t *_kl;
  14.188 +    bool first = true;
  14.189      for (_kl = keylist; _kl && _kl->value; _kl = _kl->next) {
  14.190          PEP_comm_type ct;
  14.191          PEP_STATUS status;
  14.192  
  14.193          PEP_rating _rating_ = key_rating(session, _kl->value);
  14.194 +         
  14.195          if (_rating_ <= PEP_rating_mistrust)
  14.196              return _rating_;
  14.197 -
  14.198 -        if (rating == PEP_rating_undefined)
  14.199 +            
  14.200 +        if (first) {
  14.201              rating = _rating_;
  14.202 +            first = false;
  14.203 +        }
  14.204 +        else if (rating == PEP_rating_undefined)
  14.205 +            rating = worst_rating(rating, _rating_);
  14.206  
  14.207          if (_rating_ >= PEP_rating_reliable) {
  14.208              status = least_trust(session, _kl->value, &ct);
  14.209              if (status != PEP_STATUS_OK)
  14.210                  return PEP_rating_undefined;
  14.211              if (ct == PEP_ct_unknown){
  14.212 +                /* per edouard, we reduce reliable+ ratings to reliable because
  14.213 +                   ct unknown */
  14.214                  if (rating >= PEP_rating_reliable){
  14.215 -                    rating = PEP_rating_reliable;
  14.216 +                    rating = PEP_rating_reliable; 
  14.217                  }
  14.218              }
  14.219              else{
  14.220 -                rating = _rating(ct, rating);
  14.221 +                rating = worst_rating(rating, _rating(ct, rating));
  14.222              }
  14.223          }
  14.224          else if (_rating_ == PEP_rating_unencrypted) {
  14.225              if (rating > PEP_rating_unencrypted_for_some)
  14.226 -                rating = PEP_rating_unencrypted_for_some;
  14.227 +                rating = worst_rating(rating, PEP_rating_unencrypted_for_some);
  14.228          }
  14.229      }
  14.230  
  14.231 @@ -1056,20 +1104,20 @@
  14.232      assert(enc_format != PEP_enc_none);
  14.233  
  14.234      if (!(session && src && dst && enc_format != PEP_enc_none))
  14.235 -        return PEP_ILLEGAL_VALUE;
  14.236 +        return ERROR(PEP_ILLEGAL_VALUE);
  14.237  
  14.238      if (src->dir == PEP_dir_incoming)
  14.239 -        return PEP_ILLEGAL_VALUE;
  14.240 +        return ERROR(PEP_ILLEGAL_VALUE);
  14.241  
  14.242      determine_encryption_format(src);
  14.243      if (src->enc_format != PEP_enc_none)
  14.244 -        return PEP_ILLEGAL_VALUE;
  14.245 +        return ERROR(PEP_ILLEGAL_VALUE);
  14.246  
  14.247      *dst = NULL;
  14.248  
  14.249      status = myself(session, src->from);
  14.250      if (status != PEP_STATUS_OK)
  14.251 -        goto pep_error;
  14.252 +        GOTO(pep_error);
  14.253  
  14.254      keys = new_stringlist(src->from->fpr);
  14.255      if (keys == NULL)
  14.256 @@ -1103,7 +1151,7 @@
  14.257          PEP_STATUS _status = update_identity(session, _il->ident);
  14.258          if (_status != PEP_STATUS_OK) {
  14.259              status = _status;
  14.260 -            goto pep_error;
  14.261 +            GOTO(pep_error);
  14.262          }
  14.263  
  14.264          if (_il->ident->fpr && _il->ident->fpr[0]) {
  14.265 @@ -1124,7 +1172,7 @@
  14.266              PEP_STATUS _status = update_identity(session, _il->ident);
  14.267              if (_status != PEP_STATUS_OK) {
  14.268                  status = _status;
  14.269 -                goto pep_error;
  14.270 +                GOTO(pep_error);
  14.271              }
  14.272  
  14.273              if (_il->ident->fpr && _il->ident->fpr[0]) {
  14.274 @@ -1145,7 +1193,7 @@
  14.275              if (_status != PEP_STATUS_OK)
  14.276              {
  14.277                  status = _status;
  14.278 -                goto pep_error;
  14.279 +                GOTO(pep_error);
  14.280              }
  14.281  
  14.282              if (_il->ident->fpr && _il->ident->fpr[0]) {
  14.283 @@ -1163,30 +1211,31 @@
  14.284      }
  14.285  
  14.286      if (!dest_keys_found ||
  14.287 -        stringlist_length(keys) == 0 ||
  14.288 +        stringlist_length(keys)  == 0 ||
  14.289          _rating(max_comm_type,
  14.290                  PEP_rating_undefined) < PEP_rating_reliable)
  14.291      {
  14.292          free_stringlist(keys);
  14.293 -        if (!session->passive_mode)
  14.294 +        if (!session->passive_mode && !(flags & PEP_encrypt_flag_force_no_attached_key))
  14.295              attach_own_key(session, src);
  14.296 -        return PEP_UNENCRYPTED;
  14.297 +        return ERROR(PEP_UNENCRYPTED);
  14.298      }
  14.299      else {
  14.300          msg = clone_to_empty_message(src);
  14.301          if (msg == NULL)
  14.302              goto enomem;
  14.303  
  14.304 -        attach_own_key(session, src);
  14.305 +        if (!(flags & PEP_encrypt_flag_force_no_attached_key))
  14.306 +            attach_own_key(session, src);
  14.307  
  14.308          switch (enc_format) {
  14.309          case PEP_enc_PGP_MIME:
  14.310          case PEP_enc_PEP: // BUG: should be implemented extra
  14.311 -            status = encrypt_PGP_MIME(session, src, keys, msg);
  14.312 +            status = encrypt_PGP_MIME(session, src, keys, msg, flags);
  14.313              break;
  14.314  
  14.315          case PEP_enc_pieces:
  14.316 -            status = encrypt_PGP_in_pieces(session, src, keys, msg);
  14.317 +            status = encrypt_PGP_in_pieces(session, src, keys, msg, flags);
  14.318              break;
  14.319  
  14.320          /* case PEP_enc_PEP:
  14.321 @@ -1196,14 +1245,14 @@
  14.322          default:
  14.323              assert(0);
  14.324              status = PEP_ILLEGAL_VALUE;
  14.325 -            goto pep_error;
  14.326 +            GOTO(pep_error);
  14.327          }
  14.328  
  14.329          if (status == PEP_OUT_OF_MEMORY)
  14.330              goto enomem;
  14.331  
  14.332          if (status != PEP_STATUS_OK)
  14.333 -            goto pep_error;
  14.334 +            GOTO(pep_error);
  14.335      }
  14.336  
  14.337      free_stringlist(keys);
  14.338 @@ -1226,7 +1275,7 @@
  14.339      }
  14.340  
  14.341      *dst = msg;
  14.342 -    return status;
  14.343 +    return ERROR(status);
  14.344  
  14.345  enomem:
  14.346      status = PEP_OUT_OF_MEMORY;
  14.347 @@ -1235,7 +1284,7 @@
  14.348      free_stringlist(keys);
  14.349      free_message(msg);
  14.350  
  14.351 -    return status;
  14.352 +    return ERROR(status);
  14.353  }
  14.354  
  14.355  DYNAMIC_API PEP_STATUS encrypt_message_for_self(
  14.356 @@ -1243,7 +1292,8 @@
  14.357          pEp_identity* target_id,
  14.358          message *src,
  14.359          message **dst,
  14.360 -        PEP_enc_format enc_format
  14.361 +        PEP_enc_format enc_format,
  14.362 +        PEP_encrypt_flags_t flags
  14.363      )
  14.364  {
  14.365      PEP_STATUS status = PEP_STATUS_OK;
  14.366 @@ -1256,18 +1306,18 @@
  14.367      assert(enc_format != PEP_enc_none);
  14.368  
  14.369      if (!(session && src && dst && enc_format != PEP_enc_none))
  14.370 -        return PEP_ILLEGAL_VALUE;
  14.371 +        return ERROR(PEP_ILLEGAL_VALUE);
  14.372  
  14.373      if (src->dir == PEP_dir_incoming)
  14.374 -        return PEP_ILLEGAL_VALUE;
  14.375 +        return ERROR(PEP_ILLEGAL_VALUE);
  14.376  
  14.377      determine_encryption_format(src);
  14.378      if (src->enc_format != PEP_enc_none)
  14.379 -        return PEP_ILLEGAL_VALUE;
  14.380 +        return ERROR(PEP_ILLEGAL_VALUE);
  14.381  
  14.382      status = myself(session, target_id);
  14.383      if (status != PEP_STATUS_OK)
  14.384 -        goto pep_error;
  14.385 +        GOTO(pep_error);
  14.386  
  14.387      *dst = NULL;
  14.388  
  14.389 @@ -1281,9 +1331,12 @@
  14.390      char* target_fpr = target_id->fpr;
  14.391      if (!target_fpr)
  14.392          return PEP_KEY_NOT_FOUND; // FIXME: Error condition
  14.393 -
  14.394 + 
  14.395      keys = new_stringlist(target_fpr);
  14.396 -
  14.397 +    
  14.398 +    /* KG: did we ever do this??? */
  14.399 +    if (!(flags & PEP_encrypt_flag_force_no_attached_key))
  14.400 +        _attach_key(session, target_fpr, src);
  14.401  
  14.402      msg = clone_to_empty_message(src);
  14.403      if (msg == NULL)
  14.404 @@ -1292,16 +1345,16 @@
  14.405      switch (enc_format) {
  14.406          case PEP_enc_PGP_MIME:
  14.407          case PEP_enc_PEP: // BUG: should be implemented extra
  14.408 -            status = encrypt_PGP_MIME(session, src, keys, msg);
  14.409 +            status = encrypt_PGP_MIME(session, src, keys, msg, flags);
  14.410              break;
  14.411  
  14.412          case PEP_enc_pieces:
  14.413 -            status = encrypt_PGP_in_pieces(session, src, keys, msg);
  14.414 +            status = encrypt_PGP_in_pieces(session, src, keys, msg, flags);
  14.415              break;
  14.416  
  14.417          /* case PEP_enc_PEP:
  14.418 +            NOT_IMPLEMENTED */
  14.419              // TODO: implement
  14.420 -            NOT_IMPLEMENTED */
  14.421  
  14.422          default:
  14.423              assert(0);
  14.424 @@ -1341,7 +1394,7 @@
  14.425      free_stringlist(keys);
  14.426      free_message(msg);
  14.427  
  14.428 -    return status;
  14.429 +    return ERROR(status);
  14.430  }
  14.431  
  14.432  static bool is_a_pEpmessage(const message *msg)
  14.433 @@ -1370,7 +1423,7 @@
  14.434                  && src->from->comm_type != PEP_ct_pEp)
  14.435          {
  14.436              src->from->comm_type |= PEP_ct_pEp_unconfirmed;
  14.437 -            status = update_identity(session, src->from);
  14.438 +            status = set_identity(session, src->from);
  14.439          }
  14.440          return status;
  14.441      }
  14.442 @@ -1408,8 +1461,8 @@
  14.443  
  14.444      char* curr_line = signpost;
  14.445  //    const char* end_text = ptext + psize;
  14.446 -    const char* boundary_key = "boundary=\"";
  14.447 -    const size_t BOUNDARY_KEY_SIZE = 10;
  14.448 +    const char* boundary_key = "boundary=";
  14.449 +    const size_t BOUNDARY_KEY_SIZE = 9;
  14.450  
  14.451      char* start_boundary = strstr(curr_line, boundary_key);
  14.452      if (!start_boundary)
  14.453 @@ -1417,11 +1470,17 @@
  14.454  
  14.455      start_boundary += BOUNDARY_KEY_SIZE;
  14.456  
  14.457 -    char* end_boundary = strstr(start_boundary, "\"");
  14.458 +    bool quoted = (*start_boundary == '"');
  14.459 +
  14.460 +    if (quoted)
  14.461 +        start_boundary++;
  14.462 +        
  14.463 +    char* end_boundary = (quoted ? strstr(start_boundary, "\"") : strstr(start_boundary, ";")); // FIXME: third possiblity is CRLF, or?
  14.464  
  14.465      if (!end_boundary)
  14.466          return PEP_UNKNOWN_ERROR;
  14.467  
  14.468 +    // Add space for the "--"
  14.469      size_t boundary_strlen = (end_boundary - start_boundary) + 2;
  14.470  
  14.471      signed_boundary = calloc(1, boundary_strlen + 1);
  14.472 @@ -1435,7 +1494,11 @@
  14.473  
  14.474      start_boundary += boundary_strlen;
  14.475  
  14.476 -    while (*start_boundary == '\n')
  14.477 +    if (*start_boundary == '\r') {
  14.478 +        if (*(start_boundary + 1) == '\n')
  14.479 +            start_boundary += 2;
  14.480 +    }
  14.481 +    else if (*start_boundary == '\n')
  14.482          start_boundary++;
  14.483  
  14.484      end_boundary = strstr(start_boundary + boundary_strlen, signed_boundary);
  14.485 @@ -1443,7 +1506,10 @@
  14.486      if (!end_boundary)
  14.487          return PEP_UNKNOWN_ERROR;
  14.488  
  14.489 -    end_boundary--; // See RFC3156 section 5...
  14.490 +    // See RFC3156 section 5...
  14.491 +    end_boundary--; 
  14.492 +    if (*(end_boundary - 1) == '\r')
  14.493 +        end_boundary--; 
  14.494  
  14.495      *ssize = end_boundary - start_boundary;
  14.496      *stext = start_boundary;
  14.497 @@ -1473,7 +1539,8 @@
  14.498      for (from_curr = from_keys; from_curr; from_curr = from_curr->next) {
  14.499          for (verify_curr = orig_verify; verify_curr; verify_curr = verify_curr->next) {
  14.500              if (from_curr->value && verify_curr->value &&
  14.501 -                strcasecmp(from_curr->value, verify_curr->value) == 0) {
  14.502 +                _same_fpr(from_curr->value, strlen(from_curr->value),
  14.503 +                          verify_curr->value, strlen(verify_curr->value))) {
  14.504                  from_fpr_node = from_curr;
  14.505                  break;
  14.506              }
  14.507 @@ -1488,7 +1555,8 @@
  14.508      verify_curr = orig_verify;
  14.509      
  14.510      /* put "from" signer at the beginning of the list */
  14.511 -    if (strcasecmp(orig_verify->value, from_fpr_node->value) != 0) {
  14.512 +    if (!_same_fpr(orig_verify->value, strlen(orig_verify->value),
  14.513 +                   from_fpr_node->value, strlen(from_fpr_node->value))) {
  14.514          orig_verify = stringlist_delete(orig_verify, from_fpr_node->value);
  14.515          verify_curr = new_stringlist(from_fpr_node->value);
  14.516          verify_curr->next = orig_verify;
  14.517 @@ -1501,6 +1569,20 @@
  14.518          while (*tail_pp) {
  14.519              tail_pp = &((*tail_pp)->next);
  14.520          }
  14.521 +        stringlist_t* second_list = *keylist_in_out;
  14.522 +        if (second_list) {
  14.523 +            char* listhead_val = second_list->value;
  14.524 +            if (!listhead_val || listhead_val[0] == '\0') {
  14.525 +                /* remove head, basically. This can happen when,
  14.526 +                   for example, the signature is detached and
  14.527 +                   verification is not seen directly after
  14.528 +                   decryption, so no signer is presumed in
  14.529 +                   the first construction of the keylist */
  14.530 +                *keylist_in_out = (*keylist_in_out)->next;
  14.531 +                second_list->next = NULL;
  14.532 +                free_stringlist(second_list);
  14.533 +            }
  14.534 +        }
  14.535          *tail_pp = *keylist_in_out;
  14.536      }
  14.537      
  14.538 @@ -1513,6 +1595,52 @@
  14.539      return status;
  14.540  }
  14.541  
  14.542 +PEP_STATUS amend_rating_according_to_sender_and_recipients(
  14.543 +    PEP_SESSION session,
  14.544 +    PEP_rating *rating,
  14.545 +    pEp_identity *sender,
  14.546 +    stringlist_t *recipients) {
  14.547 +    
  14.548 +    PEP_STATUS status = PEP_STATUS_OK;
  14.549 +
  14.550 +    if (*rating > PEP_rating_mistrust) {
  14.551 +        PEP_rating kl_rating = PEP_rating_undefined;
  14.552 +
  14.553 +        if (recipients)
  14.554 +            kl_rating = keylist_rating(session, recipients);
  14.555 +
  14.556 +        if (kl_rating <= PEP_rating_mistrust) {
  14.557 +            *rating = kl_rating;
  14.558 +        }
  14.559 +        else if (*rating >= PEP_rating_reliable &&
  14.560 +                 kl_rating < PEP_rating_reliable) {
  14.561 +            *rating = PEP_rating_unreliable;
  14.562 +        }
  14.563 +        else if (*rating >= PEP_rating_reliable &&
  14.564 +                 kl_rating >= PEP_rating_reliable) {
  14.565 +            if (!(sender && sender->user_id && sender->user_id[0])) {
  14.566 +                *rating = PEP_rating_unreliable;
  14.567 +            }
  14.568 +            else {
  14.569 +                char *fpr = recipients->value;
  14.570 +                pEp_identity *_sender = new_identity(sender->address, fpr,
  14.571 +                                                   sender->user_id, sender->username);
  14.572 +                if (_sender == NULL)
  14.573 +                    return PEP_OUT_OF_MEMORY;
  14.574 +                status = get_trust(session, _sender);
  14.575 +                if (_sender->comm_type != PEP_ct_unknown) {
  14.576 +                    *rating = worst_rating(_rating(_sender->comm_type, PEP_rating_undefined),
  14.577 +                              kl_rating);
  14.578 +                }
  14.579 +                free_identity(_sender);
  14.580 +                if (status == PEP_CANNOT_FIND_IDENTITY)
  14.581 +                   status = PEP_STATUS_OK;
  14.582 +            }
  14.583 +        }
  14.584 +    }
  14.585 +    return status;
  14.586 +}
  14.587 +
  14.588  
  14.589  DYNAMIC_API PEP_STATUS _decrypt_message(
  14.590          PEP_SESSION session,
  14.591 @@ -1541,7 +1669,7 @@
  14.592      assert(flags);
  14.593  
  14.594      if (!(session && src && dst && keylist && rating && flags))
  14.595 -        return PEP_ILLEGAL_VALUE;
  14.596 +        return ERROR(PEP_ILLEGAL_VALUE);
  14.597  
  14.598      *flags = 0;
  14.599  
  14.600 @@ -1552,7 +1680,7 @@
  14.601      // we would need to check signature
  14.602      status = _update_identity_for_incoming_message(session, src);
  14.603      if(status != PEP_STATUS_OK)
  14.604 -        return status;
  14.605 +        return ERROR(status);
  14.606  
  14.607      // Get detached signature, if any
  14.608      bloblist_t* detached_sig = NULL;
  14.609 @@ -1575,7 +1703,7 @@
  14.610              *rating = PEP_rating_unencrypted;
  14.611              if (imported_keys)
  14.612                  remove_attached_keys(src);
  14.613 -            if(session->inject_sync_msg){
  14.614 +            if(session->sync_session->inject_sync_msg){
  14.615                  status = receive_DeviceState_msg(session, src, *rating, *keylist);
  14.616                  if (status == PEP_MESSAGE_CONSUME ||
  14.617                      status == PEP_MESSAGE_IGNORE) {
  14.618 @@ -1586,7 +1714,7 @@
  14.619                                  PEP_decrypt_flag_consume;
  14.620                  }
  14.621                  else if (status != PEP_STATUS_OK) {
  14.622 -                    return status;
  14.623 +                    return ERROR(status);
  14.624                  }
  14.625              }
  14.626              
  14.627 @@ -1618,7 +1746,7 @@
  14.628                  }
  14.629              }
  14.630              
  14.631 -            return PEP_UNENCRYPTED;
  14.632 +            return ERROR(PEP_UNENCRYPTED);
  14.633  
  14.634          case PEP_enc_PGP_MIME:
  14.635              ctext = src->attachments->next->value;
  14.636 @@ -1642,7 +1770,7 @@
  14.637                                                     csize, dsig_text, dsig_size,
  14.638                                                     &ptext, &psize, &_keylist);
  14.639      if (status > PEP_CANNOT_DECRYPT_UNKNOWN){
  14.640 -        goto pep_error;
  14.641 +        GOTO(pep_error);
  14.642      }
  14.643  
  14.644      decrypt_status = status;
  14.645 @@ -1818,7 +1946,9 @@
  14.646              case PEP_enc_PGP_MIME_Outlook1:
  14.647                  status = copy_fields(msg, src);
  14.648                  if (status != PEP_STATUS_OK)
  14.649 -                    goto pep_error;
  14.650 +                {
  14.651 +                    GOTO(pep_error);
  14.652 +                }
  14.653  
  14.654                  if (src->shortmsg == NULL || strcmp(src->shortmsg, "pEp") == 0)
  14.655                  {
  14.656 @@ -1827,9 +1957,24 @@
  14.657  
  14.658                      int r = separate_short_and_long(msg->longmsg, &shortmsg,
  14.659                              &longmsg);
  14.660 +                    
  14.661                      if (r == -1)
  14.662                          goto enomem;
  14.663  
  14.664 +                    if (shortmsg == NULL) {
  14.665 +                        if (src->shortmsg == NULL)
  14.666 +                            shortmsg = strdup("");
  14.667 +                        else {
  14.668 +                            // FIXME: is msg->shortmsg always a copy of
  14.669 +                            // src->shortmsg already?
  14.670 +                            // if so, we need to change the logic so
  14.671 +                            // that in this case, we don't free msg->shortmsg
  14.672 +                            // and do this strdup, etc.
  14.673 +                            shortmsg = strdup(src->shortmsg);
  14.674 +                        }
  14.675 +                    }
  14.676 +
  14.677 +
  14.678                      free(msg->shortmsg);
  14.679                      free(msg->longmsg);
  14.680  
  14.681 @@ -1876,7 +2021,9 @@
  14.682  
  14.683              status = _update_identity_for_incoming_message(session, src);
  14.684              if(status != PEP_STATUS_OK)
  14.685 -                goto pep_error;
  14.686 +            {
  14.687 +                GOTO(pep_error);
  14.688 +            }
  14.689  
  14.690              char *re_ptext = NULL;
  14.691              size_t re_psize;
  14.692 @@ -1890,48 +2037,22 @@
  14.693              free(re_ptext);
  14.694  
  14.695              if (status > PEP_CANNOT_DECRYPT_UNKNOWN)
  14.696 -                goto pep_error;
  14.697 +            {
  14.698 +                GOTO(pep_error);
  14.699 +            }
  14.700  
  14.701              decrypt_status = status;
  14.702          }
  14.703  
  14.704          *rating = decrypt_rating(decrypt_status);
  14.705  
  14.706 -        if (*rating > PEP_rating_mistrust) {
  14.707 -            PEP_rating kl_rating = PEP_rating_undefined;
  14.708 -
  14.709 -            if (_keylist)
  14.710 -                kl_rating = keylist_rating(session, _keylist);
  14.711 -
  14.712 -            if (kl_rating <= PEP_rating_mistrust) {
  14.713 -                *rating = kl_rating;
  14.714 -            }
  14.715 -            else if (*rating >= PEP_rating_reliable &&
  14.716 -                     kl_rating < PEP_rating_reliable) {
  14.717 -                *rating = PEP_rating_unreliable;
  14.718 -            }
  14.719 -            else if (*rating >= PEP_rating_reliable &&
  14.720 -                     kl_rating >= PEP_rating_reliable) {
  14.721 -                if (!(src->from && src->from->user_id && src->from->user_id[0])) {
  14.722 -                    *rating = PEP_rating_unreliable;
  14.723 -                }
  14.724 -                else {
  14.725 -                    char *fpr = _keylist->value;
  14.726 -                    pEp_identity *_from = new_identity(src->from->address, fpr,
  14.727 -                                                       src->from->user_id, src->from->username);
  14.728 -                    if (_from == NULL)
  14.729 -                        goto enomem;
  14.730 -                    status = get_trust(session, _from);
  14.731 -                    if (_from->comm_type != PEP_ct_unknown)
  14.732 -                        *rating = _rating(_from->comm_type, PEP_rating_undefined);
  14.733 -                    free_identity(_from);
  14.734 -                    if (status == PEP_CANNOT_FIND_IDENTITY)
  14.735 -                       status = PEP_STATUS_OK;
  14.736 -                    if (status != PEP_STATUS_OK)
  14.737 -                        goto pep_error;
  14.738 -                }
  14.739 -            }
  14.740 -        }
  14.741 +        status = amend_rating_according_to_sender_and_recipients(session,
  14.742 +                                                                 rating,
  14.743 +                                                                 src->from,
  14.744 +                                                                 _keylist);
  14.745 +
  14.746 +        if (status != PEP_STATUS_OK)
  14.747 +            GOTO(pep_error);
  14.748      }
  14.749      else
  14.750      {
  14.751 @@ -1956,7 +2077,8 @@
  14.752          decorate_message(msg, *rating, _keylist);
  14.753          if (imported_keys)
  14.754              remove_attached_keys(msg);
  14.755 -        if (*rating >= PEP_rating_reliable && session->inject_sync_msg) {
  14.756 +        if (*rating >= PEP_rating_reliable &&
  14.757 +            session->sync_session->inject_sync_msg) {
  14.758              status = receive_DeviceState_msg(session, msg, *rating, _keylist);
  14.759              if (status == PEP_MESSAGE_CONSUME ||
  14.760                  status == PEP_MESSAGE_IGNORE) {
  14.761 @@ -1985,7 +2107,7 @@
  14.762      *dst = msg;
  14.763      *keylist = _keylist;
  14.764  
  14.765 -    return status;
  14.766 +    return PEP_STATUS_OK;
  14.767  
  14.768  enomem:
  14.769      status = PEP_OUT_OF_MEMORY;
  14.770 @@ -1995,7 +2117,7 @@
  14.771      free_message(msg);
  14.772      free_stringlist(_keylist);
  14.773  
  14.774 -    return status;
  14.775 +    return ERROR(status);
  14.776  }
  14.777  
  14.778  DYNAMIC_API PEP_STATUS decrypt_message(
  14.779 @@ -2044,8 +2166,7 @@
  14.780  
  14.781      free_identity_list(private_il);
  14.782  
  14.783 -    return status;
  14.784 -
  14.785 +    return ERROR(status);
  14.786  }
  14.787  
  14.788  static void _max_comm_type_from_identity_list(
  14.789 @@ -2086,10 +2207,10 @@
  14.790      assert(rating);
  14.791  
  14.792      if (!(session && msg && rating))
  14.793 -        return PEP_ILLEGAL_VALUE;
  14.794 +        return ERROR(PEP_ILLEGAL_VALUE);
  14.795  
  14.796      if (msg->dir != PEP_dir_outgoing)
  14.797 -        return PEP_ILLEGAL_VALUE;
  14.798 +        return ERROR(PEP_ILLEGAL_VALUE);
  14.799  
  14.800      *rating = PEP_rating_undefined;
  14.801  
  14.802 @@ -2173,89 +2294,7 @@
  14.803  
  14.804      // this should never happen
  14.805      assert(false);
  14.806 -	return PEP_color_no_color;
  14.807 -}
  14.808 -
  14.809 -static bool _is_valid_hex(const char* hexstr) {
  14.810 -    if (!hexstr)
  14.811 -        return false;
  14.812 -
  14.813 -    const char* curr = hexstr;
  14.814 -    char currchar;
  14.815 -
  14.816 -    for (currchar = *curr; currchar != '\0'; currchar = *(++curr)) {
  14.817 -        if ((currchar >= '0' && currchar <= '9') ||
  14.818 -            (currchar >= 'a' && currchar <= 'f') ||
  14.819 -            (currchar >= 'A' && currchar <= 'F'))
  14.820 -        {
  14.821 -            continue;
  14.822 -        }
  14.823 -        return false;
  14.824 -    }
  14.825 -    return true;
  14.826 -}
  14.827 -
  14.828 -// Returns, in comparison: 1 if fpr1 > fpr2, 0 if equal, -1 if fpr1 < fpr2
  14.829 -static PEP_STATUS _compare_fprs(const char* fpr1, const char* fpr2, int* comparison) {
  14.830 -
  14.831 -    const int _FULL_FINGERPRINT_LENGTH = 40;
  14.832 -    const int _ASCII_LOWERCASE_OFFSET = 32;
  14.833 -
  14.834 -    size_t fpr1_len = strlen(fpr1);
  14.835 -    size_t fpr2_len = strlen(fpr2);
  14.836 -
  14.837 -    if (fpr1_len != _FULL_FINGERPRINT_LENGTH || fpr2_len != _FULL_FINGERPRINT_LENGTH)
  14.838 -        return PEP_TRUSTWORDS_FPR_WRONG_LENGTH;
  14.839 -
  14.840 -    if (!_is_valid_hex(fpr1) || !_is_valid_hex(fpr2))
  14.841 -        return PEP_ILLEGAL_VALUE;
  14.842 -
  14.843 -    const char* fpr1_curr = fpr1;
  14.844 -    const char* fpr2_curr = fpr2;
  14.845 -
  14.846 -    char current;
  14.847 -
  14.848 -    // Advance past leading zeros.
  14.849 -    for (current = *fpr1_curr; current != '0' && current != '\0'; current = *(++fpr1_curr), fpr1_len--);
  14.850 -    for (current = *fpr2_curr; current != '0' && current != '\0'; current = *(++fpr2_curr), fpr2_len--);
  14.851 -
  14.852 -    if (fpr1_len == fpr2_len) {
  14.853 -        char digit1;
  14.854 -        char digit2;
  14.855 -
  14.856 -        while (fpr1_curr && *fpr1_curr != '\0') {
  14.857 -            digit1 = *fpr1_curr++;
  14.858 -            digit2 = *fpr2_curr++;
  14.859 -
  14.860 -            // Adjust for case-insensitive compare
  14.861 -            if (digit1 >= 'a' && digit1 <= 'f')
  14.862 -                digit1 -= _ASCII_LOWERCASE_OFFSET;
  14.863 -            if (digit2 >= 'a' && digit2 <= 'f')
  14.864 -                digit2 -= _ASCII_LOWERCASE_OFFSET;
  14.865 -
  14.866 -            // We take advantage of the fact that 'a'-'f' are larger
  14.867 -            // integer values in the ASCII table than '0'-'9'.
  14.868 -            // This allows us to compare digits directly.
  14.869 -            if (digit1 > digit2) {
  14.870 -                *comparison = 1;
  14.871 -                return PEP_STATUS_OK;
  14.872 -            } else if (digit1 < digit2) {
  14.873 -                *comparison = -1;
  14.874 -                return PEP_STATUS_OK;
  14.875 -            }
  14.876 -
  14.877 -            // pointers already advanced above. Keep going.
  14.878 -        }
  14.879 -        *comparison = 0;
  14.880 -        return PEP_STATUS_OK;
  14.881 -    }
  14.882 -    else if (fpr1_len > fpr2_len) {
  14.883 -        *comparison = 1;
  14.884 -        return PEP_STATUS_OK;
  14.885 -    }
  14.886 -    // Otherwise, fpr1_len < fpr2_len
  14.887 -    *comparison = -1;
  14.888 -    return PEP_STATUS_OK;
  14.889 +    return PEP_color_no_color;
  14.890  }
  14.891  
  14.892  DYNAMIC_API PEP_STATUS get_trustwords(
  14.893 @@ -2293,7 +2332,7 @@
  14.894      size_t second_wsize = 0;
  14.895  
  14.896      int fpr_comparison = -255;
  14.897 -    PEP_STATUS status = _compare_fprs(source1, source2, &fpr_comparison);
  14.898 +    PEP_STATUS status = _compare_fprs(source1, strlen(source1), source2, strlen(source2), &fpr_comparison);
  14.899      if (status != PEP_STATUS_OK)
  14.900          return status;
  14.901  
  14.902 @@ -2318,7 +2357,7 @@
  14.903                  goto error_release;
  14.904              break;
  14.905          default:
  14.906 -            return PEP_UNKNOWN_ERROR; // shouldn't be possible
  14.907 +            return ERROR(PEP_UNKNOWN_ERROR); // shouldn't be possible
  14.908      }
  14.909  
  14.910      size_t _wsize = first_wsize + second_wsize;
  14.911 @@ -2360,7 +2399,7 @@
  14.912      the_end:
  14.913      free(first_set);
  14.914      free(second_set);
  14.915 -    return status;
  14.916 +    return ERROR(status);
  14.917  }
  14.918  
  14.919  DYNAMIC_API PEP_STATUS get_message_trustwords(
  14.920 @@ -2446,7 +2485,7 @@
  14.921  
  14.922      if (status != PEP_STATUS_OK) {
  14.923          free_identity(partner);
  14.924 -        return status;
  14.925 +        return ERROR(status);
  14.926      }
  14.927     
  14.928      // Find own identity corresponding to given account address.
  14.929 @@ -2459,7 +2498,7 @@
  14.930  
  14.931      if (status != PEP_STATUS_OK) {
  14.932          free_identity(stored_identity);
  14.933 -        return status;
  14.934 +        return ERROR(status);
  14.935      }
  14.936  
  14.937      // get the trustwords
  14.938 @@ -2468,7 +2507,7 @@
  14.939                              partner, received_by, 
  14.940                              lang, words, &wsize, full);
  14.941  
  14.942 -    return status;
  14.943 +    return ERROR(status);
  14.944  }
  14.945  
  14.946  DYNAMIC_API PEP_STATUS MIME_decrypt_message(
  14.947 @@ -2481,32 +2520,55 @@
  14.948      PEP_decrypt_flags_t *flags
  14.949  )
  14.950  {
  14.951 +    assert(mimetext);
  14.952 +    assert(mime_plaintext);
  14.953 +    assert(keylist);
  14.954 +    assert(rating);
  14.955 +    assert(flags);
  14.956 +
  14.957      PEP_STATUS status = PEP_STATUS_OK;
  14.958      message* tmp_msg = NULL;
  14.959      message* dec_msg = NULL;
  14.960 +    *mime_plaintext = NULL;
  14.961  
  14.962      status = mime_decode_message(mimetext, size, &tmp_msg);
  14.963      if (status != PEP_STATUS_OK)
  14.964 -        goto pep_error;
  14.965 -
  14.966 -    status = decrypt_message(session,
  14.967 -                             tmp_msg,
  14.968 -                             &dec_msg,
  14.969 -                             keylist,
  14.970 -                             rating,
  14.971 -                             flags);
  14.972 -    if (status != PEP_STATUS_OK)
  14.973 -        goto pep_error;
  14.974 +        GOTO(pep_error);
  14.975 +
  14.976 +    PEP_STATUS decrypt_status = decrypt_message(session,
  14.977 +                                                tmp_msg,
  14.978 +                                                &dec_msg,
  14.979 +                                                keylist,
  14.980 +                                                rating,
  14.981 +                                                flags);
  14.982 +                                                
  14.983 +    if (!dec_msg && (decrypt_status == PEP_UNENCRYPTED || decrypt_status == PEP_VERIFIED)) {
  14.984 +        dec_msg = message_dup(tmp_msg);
  14.985 +    }
  14.986 +        
  14.987 +    if (decrypt_status > PEP_CANNOT_DECRYPT_UNKNOWN || !dec_msg)
  14.988 +    {
  14.989 +        status = decrypt_status;
  14.990 +        GOTO(pep_error);
  14.991 +    }
  14.992  
  14.993      status = mime_encode_message(dec_msg, false, mime_plaintext);
  14.994  
  14.995 +    if (status == PEP_STATUS_OK)
  14.996 +    {
  14.997 +        free(tmp_msg);
  14.998 +        free(dec_msg);
  14.999 +        return ERROR(decrypt_status);
 14.1000 +    }
 14.1001 +    
 14.1002  pep_error:
 14.1003      free_message(tmp_msg);
 14.1004      free_message(dec_msg);
 14.1005  
 14.1006 -    return status;
 14.1007 +    return ERROR(status);
 14.1008  }
 14.1009  
 14.1010 +
 14.1011  DYNAMIC_API PEP_STATUS MIME_encrypt_message(
 14.1012      PEP_SESSION session,
 14.1013      const char *mimetext,
 14.1014 @@ -2523,7 +2585,7 @@
 14.1015  
 14.1016      status = mime_decode_message(mimetext, size, &tmp_msg);
 14.1017      if (status != PEP_STATUS_OK)
 14.1018 -        goto pep_error;
 14.1019 +        GOTO(pep_error);
 14.1020  
 14.1021      // This isn't incoming, though... so we need to reverse the direction
 14.1022      tmp_msg->dir = PEP_dir_outgoing;
 14.1023 @@ -2534,7 +2596,13 @@
 14.1024                               enc_format,
 14.1025                               flags);
 14.1026      if (status != PEP_STATUS_OK)
 14.1027 -        goto pep_error;
 14.1028 +        GOTO(pep_error);
 14.1029 +
 14.1030 +
 14.1031 +    if (!enc_msg) {
 14.1032 +        status = PEP_UNKNOWN_ERROR;
 14.1033 +        GOTO(pep_error);
 14.1034 +    }
 14.1035  
 14.1036      status = mime_encode_message(enc_msg, false, mime_ciphertext);
 14.1037  
 14.1038 @@ -2542,6 +2610,189 @@
 14.1039      free_message(tmp_msg);
 14.1040      free_message(enc_msg);
 14.1041  
 14.1042 -    return status;
 14.1043 +    return ERROR(status);
 14.1044  
 14.1045  }
 14.1046 +
 14.1047 +DYNAMIC_API PEP_STATUS MIME_encrypt_message_for_self(
 14.1048 +    PEP_SESSION session,
 14.1049 +    pEp_identity* target_id,
 14.1050 +    const char *mimetext,
 14.1051 +    size_t size,
 14.1052 +    char** mime_ciphertext,
 14.1053 +    PEP_enc_format enc_format,
 14.1054 +    PEP_encrypt_flags_t flags
 14.1055 +)
 14.1056 +{
 14.1057 +    PEP_STATUS status = PEP_STATUS_OK;
 14.1058 +    message* tmp_msg = NULL;
 14.1059 +    message* enc_msg = NULL;
 14.1060 +
 14.1061 +    status = mime_decode_message(mimetext, size, &tmp_msg);
 14.1062 +    if (status != PEP_STATUS_OK)
 14.1063 +        goto pep_error;
 14.1064 +
 14.1065 +    // This isn't incoming, though... so we need to reverse the direction
 14.1066 +    tmp_msg->dir = PEP_dir_outgoing;
 14.1067 +    status = encrypt_message_for_self(session,
 14.1068 +                                      target_id,
 14.1069 +                                      tmp_msg,
 14.1070 +                                      &enc_msg,
 14.1071 +                                      enc_format,
 14.1072 +                                      flags);
 14.1073 +    if (status != PEP_STATUS_OK)
 14.1074 +        goto pep_error;
 14.1075 + 
 14.1076 +    if (!enc_msg) {
 14.1077 +        status = PEP_UNKNOWN_ERROR;
 14.1078 +        goto pep_error;
 14.1079 +    }
 14.1080 +
 14.1081 +    status = mime_encode_message(enc_msg, false, mime_ciphertext);
 14.1082 +
 14.1083 +pep_error:
 14.1084 +    free_message(tmp_msg);
 14.1085 +    free_message(enc_msg);
 14.1086 +
 14.1087 +    return ERROR(status);
 14.1088 +}
 14.1089 +
 14.1090 +static PEP_rating string_to_rating(const char * rating)
 14.1091 +{
 14.1092 +    if (rating == NULL)
 14.1093 +        return PEP_rating_undefined;
 14.1094 +    if (strcmp(rating, "cannot_decrypt") == 0)
 14.1095 +        return PEP_rating_cannot_decrypt;
 14.1096 +    if (strcmp(rating, "have_no_key") == 0)
 14.1097 +        return PEP_rating_have_no_key;
 14.1098 +    if (strcmp(rating, "unencrypted") == 0)
 14.1099 +        return PEP_rating_unencrypted;
 14.1100 +    if (strcmp(rating, "unencrypted_for_some") == 0)
 14.1101 +        return PEP_rating_unencrypted_for_some;
 14.1102 +    if (strcmp(rating, "unreliable") == 0)
 14.1103 +        return PEP_rating_unreliable;
 14.1104 +    if (strcmp(rating, "reliable") == 0)
 14.1105 +        return PEP_rating_reliable;
 14.1106 +    if (strcmp(rating, "trusted") == 0)
 14.1107 +        return PEP_rating_trusted;
 14.1108 +    if (strcmp(rating, "trusted_and_anonymized") == 0)
 14.1109 +        return PEP_rating_trusted_and_anonymized;
 14.1110 +    if (strcmp(rating, "fully_anonymous") == 0)
 14.1111 +        return PEP_rating_fully_anonymous;
 14.1112 +    if (strcmp(rating, "mistrust") == 0)
 14.1113 +        return PEP_rating_mistrust;
 14.1114 +    if (strcmp(rating, "b0rken") == 0)
 14.1115 +        return PEP_rating_b0rken;
 14.1116 +    if (strcmp(rating, "under_attack") == 0)
 14.1117 +        return PEP_rating_under_attack;
 14.1118 +    return PEP_rating_undefined;
 14.1119 +}
 14.1120 +
 14.1121 +static PEP_STATUS string_to_keylist(const char * skeylist, stringlist_t **keylist)
 14.1122 +{
 14.1123 +    if (skeylist == NULL || keylist == NULL)
 14.1124 +        return PEP_ILLEGAL_VALUE;
 14.1125 +
 14.1126 +    stringlist_t *rkeylist = NULL;
 14.1127 +    stringlist_t *_kcurr = NULL;
 14.1128 +    const char * fpr_begin = skeylist;
 14.1129 +    const char * fpr_end = NULL;
 14.1130 +
 14.1131 +    do {
 14.1132 +        fpr_end = strstr(fpr_begin, ",");
 14.1133 +        
 14.1134 +        char * fpr = strndup(
 14.1135 +            fpr_begin,
 14.1136 +            (fpr_end == NULL) ? strlen(fpr_begin) : fpr_end - fpr_begin);
 14.1137 +        
 14.1138 +        if (fpr == NULL)
 14.1139 +            goto enomem;
 14.1140 +        
 14.1141 +        _kcurr = stringlist_add(_kcurr, fpr);
 14.1142 +        if (_kcurr == NULL) {
 14.1143 +            free(fpr);
 14.1144 +            goto enomem;
 14.1145 +        }
 14.1146 +        
 14.1147 +        if (rkeylist == NULL)
 14.1148 +            rkeylist = _kcurr;
 14.1149 +        
 14.1150 +        fpr_begin = fpr_end ? fpr_end + 1 : NULL;
 14.1151 +        
 14.1152 +    } while (fpr_begin);
 14.1153 +    
 14.1154 +    *keylist = rkeylist;
 14.1155 +    return PEP_STATUS_OK;
 14.1156 +    
 14.1157 +enomem:
 14.1158 +    free_stringlist(rkeylist);
 14.1159 +    return PEP_OUT_OF_MEMORY;
 14.1160 +}
 14.1161 +
 14.1162 +DYNAMIC_API PEP_STATUS re_evaluate_message_rating(
 14.1163 +    PEP_SESSION session,
 14.1164 +    message *msg,
 14.1165 +    stringlist_t *x_keylist,
 14.1166 +    PEP_rating x_enc_status,
 14.1167 +    PEP_rating *rating
 14.1168 +)
 14.1169 +{
 14.1170 +    PEP_STATUS status = PEP_STATUS_OK;
 14.1171 +    stringlist_t *_keylist = x_keylist;
 14.1172 +    bool must_free_keylist = false;
 14.1173 +    PEP_rating _rating;
 14.1174 +
 14.1175 +    assert(session);
 14.1176 +    assert(msg);
 14.1177 +    assert(rating);
 14.1178 +
 14.1179 +    if (!(session && msg && rating))
 14.1180 +        return ERROR(PEP_ILLEGAL_VALUE);
 14.1181 +
 14.1182 +    *rating = PEP_rating_undefined;
 14.1183 +
 14.1184 +    if (x_enc_status == PEP_rating_undefined){
 14.1185 +        for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
 14.1186 +            if (strcasecmp(i->value->key, "X-EncStatus") == 0){
 14.1187 +                x_enc_status = string_to_rating(i->value->value);
 14.1188 +                goto got_rating;
 14.1189 +            }
 14.1190 +        }
 14.1191 +        return ERROR(PEP_ILLEGAL_VALUE);
 14.1192 +    }
 14.1193 +
 14.1194 +got_rating:
 14.1195 +
 14.1196 +    _rating = x_enc_status;
 14.1197 +
 14.1198 +    if (_keylist == NULL){
 14.1199 +        for (stringpair_list_t *i = msg->opt_fields; i && i->value ; i=i->next) {
 14.1200 +            if (strcasecmp(i->value->key, "X-KeyList") == 0){
 14.1201 +                status = string_to_keylist(i->value->value, &_keylist);
 14.1202 +                if (status != PEP_STATUS_OK)
 14.1203 +                    GOTO(pep_error);
 14.1204 +                must_free_keylist = true;
 14.1205 +                goto got_keylist;
 14.1206 +            }
 14.1207 +        }
 14.1208 +        return ERROR(PEP_ILLEGAL_VALUE);
 14.1209 +    }
 14.1210 +got_keylist:
 14.1211 +
 14.1212 +    status = update_identity(session, msg->from);
 14.1213 +    if (status != PEP_STATUS_OK)
 14.1214 +        GOTO(pep_error);
 14.1215 +
 14.1216 +    status = amend_rating_according_to_sender_and_recipients(session,
 14.1217 +                                                             &_rating,
 14.1218 +                                                             msg->from,
 14.1219 +                                                             _keylist);
 14.1220 +    if (status == PEP_STATUS_OK)
 14.1221 +        *rating = _rating;
 14.1222 +    
 14.1223 +pep_error:
 14.1224 +    if (must_free_keylist)
 14.1225 +        free_stringlist(_keylist);
 14.1226 +
 14.1227 +    return ERROR(status);
 14.1228 +}
    15.1 --- a/src/message_api.h	Tue Jan 31 08:42:25 2017 +0100
    15.2 +++ b/src/message_api.h	Tue Jun 13 13:00:37 2017 +0200
    15.3 @@ -23,7 +23,14 @@
    15.4  void add_opt_field(message *msg, const char *name, const char *value);
    15.5  
    15.6  typedef enum _PEP_encrypt_flags {
    15.7 -    PEP_encrypt_flag_force_encryption = 0x1
    15.8 +    // "default" means whatever the default behaviour for the function is.
    15.9 +    PEP_encrypt_flag_default = 0x0,
   15.10 +    PEP_encrypt_flag_force_encryption = 0x1,
   15.11 +
   15.12 +    // This flag is for special use cases and should not be used
   15.13 +    // by normal pEp clients!
   15.14 +    PEP_encrypt_flag_force_unsigned = 0x2,
   15.15 +    PEP_encrypt_flag_force_no_attached_key = 0x4
   15.16  } PEP_encrypt_flags; 
   15.17  
   15.18  typedef unsigned int PEP_encrypt_flags_t;
   15.19 @@ -68,6 +75,7 @@
   15.20  //      src (in)            message to encrypt
   15.21  //      dst (out)           pointer to new encrypted message or NULL on failure
   15.22  //      enc_format (in)     encrypted format
   15.23 +//      flags (in)          flags to set special encryption features
   15.24  //
   15.25  //  return value:       (FIXME: This may not be correct or complete)
   15.26  //      PEP_STATUS_OK                   on success
   15.27 @@ -89,7 +97,8 @@
   15.28          pEp_identity* target_id,
   15.29          message *src,
   15.30          message **dst,
   15.31 -        PEP_enc_format enc_format
   15.32 +        PEP_enc_format enc_format,
   15.33 +        PEP_encrypt_flags_t flags
   15.34      );
   15.35  
   15.36  // MIME_encrypt_message() - encrypt a MIME message, with MIME output
   15.37 @@ -126,6 +135,43 @@
   15.38      PEP_encrypt_flags_t flags
   15.39  );
   15.40  
   15.41 +// MIME_encrypt_message_for_self() - encrypt MIME message for user's identity only,
   15.42 +//                              ignoring recipients and other identities from
   15.43 +//                              the message, with MIME output
   15.44 +//  parameters:
   15.45 +//      session (in)            session handle
   15.46 +//      target_id (in)      self identity this message should be encrypted for
   15.47 +//      mimetext (in)           MIME encoded text to encrypt
   15.48 +//      size (in)               size of input mime text
   15.49 +//      mime_ciphertext (out)   encrypted, encoded message
   15.50 +//      enc_format (in)         encrypted format
   15.51 +//      flags (in)              flags to set special encryption features
   15.52 +//
   15.53 +//  return value:
   15.54 +//      PEP_STATUS_OK           if everything worked
   15.55 +//      PEP_BUFFER_TOO_SMALL    if encoded message size is too big to handle
   15.56 +//      PEP_CANNOT_CREATE_TEMP_FILE
   15.57 +//                              if there are issues with temp files; in
   15.58 +//                              this case errno will contain the underlying
   15.59 +//                              error
   15.60 +//      PEP_OUT_OF_MEMORY       if not enough memory could be allocated
   15.61 +//
   15.62 +//  caveat:
   15.63 +//      the encrypted, encoded mime text will go to the ownership of the caller; mimetext
   15.64 +//      will remain in the ownership of the caller
   15.65 +
   15.66 +DYNAMIC_API PEP_STATUS MIME_encrypt_message_for_self(
   15.67 +    PEP_SESSION session,
   15.68 +    pEp_identity* target_id,
   15.69 +    const char *mimetext,
   15.70 +    size_t size,
   15.71 +    char** mime_ciphertext,
   15.72 +    PEP_enc_format enc_format,
   15.73 +    PEP_encrypt_flags_t flags
   15.74 +);
   15.75 +
   15.76 +
   15.77 +
   15.78  typedef enum _PEP_rating {
   15.79      PEP_rating_undefined = 0,
   15.80      PEP_rating_cannot_decrypt,
   15.81 @@ -208,7 +254,9 @@
   15.82  //      flags (out)             flags to signal special decryption features
   15.83  //
   15.84  //  return value:
   15.85 -//      PEP_STATUS_OK           if everything worked
   15.86 +//      decrypt status          if everything worked with MIME encode/decode, 
   15.87 +//                              the status of the decryption is returned 
   15.88 +//                              (PEP_STATUS_OK or decryption error status)
   15.89  //      PEP_BUFFER_TOO_SMALL    if encoded message size is too big to handle
   15.90  //      PEP_CANNOT_CREATE_TEMP_FILE
   15.91  //                              if there are issues with temp files; in
   15.92 @@ -374,7 +422,35 @@
   15.93      const char* lang, char **words, bool full
   15.94  );
   15.95  
   15.96 +// re_evaluate_message_rating() - re-evaluate already decrypted message rating
   15.97 +//
   15.98 +//  parameters:
   15.99 +//      session (in)            session handle
  15.100 +//      msg (in)                message to get the rating for
  15.101 +//      x_keylist (in)          decrypted message recipients keys fpr
  15.102 +//      x_enc_status (in)       original rating for the decrypted message
  15.103 +//      rating (out)            rating for the message
  15.104 +//
  15.105 +//  return value:
  15.106 +//      PEP_ILLEGAL_VALUE       if decrypted message doesn't contain 
  15.107 +//                              X-EncStatus optional field and x_enc_status is 
  15.108 +//                              pEp_rating_udefined
  15.109 +//                              or if decrypted message doesn't contain 
  15.110 +//                              X-Keylist optional field and x_keylist is NULL
  15.111 +//      PEP_OUT_OF_MEMORY       if not enough memory could be allocated
  15.112 +//
  15.113 +//  caveat:
  15.114 +//      msg->from must point to a valid pEp_identity
  15.115 +//      the ownership of msg remains with the caller
  15.116 +//	    the ownership of x_keylist remains with to the caller
  15.117 +
  15.118 +DYNAMIC_API PEP_STATUS re_evaluate_message_rating(
  15.119 +    PEP_SESSION session,
  15.120 +    message *msg,
  15.121 +    stringlist_t *x_keylist,
  15.122 +    PEP_rating x_enc_status,
  15.123 +    PEP_rating *rating
  15.124 +);
  15.125  #ifdef __cplusplus
  15.126  }
  15.127  #endif
  15.128 -
    16.1 --- a/src/pEpEngine.c	Tue Jan 31 08:42:25 2017 +0100
    16.2 +++ b/src/pEpEngine.c	Tue Jun 13 13:00:37 2017 +0200
    16.3 @@ -29,6 +29,11 @@
    16.4      "       and pgp_keypair_fpr = identity.main_key_id"
    16.5      "   where address = ?1 and identity.user_id = ?2;";
    16.6  
    16.7 +static const char *sql_replace_identities_fpr =  
    16.8 +    "update identity"
    16.9 +    "   set main_key_id = ?1 "
   16.10 +    "   where main_key_id = ?2 ;";
   16.11 +
   16.12  // Set person, but if already exist, only update.
   16.13  // if main_key_id already set, don't touch.
   16.14  static const char *sql_set_person = 
   16.15 @@ -42,8 +47,6 @@
   16.16      "update person set device_group = ?1 "
   16.17      "where id = '" PEP_OWN_USERID "';";
   16.18  
   16.19 -// TODO leave group
   16.20 -
   16.21  static const char *sql_get_device_group = 
   16.22      "select device_group from person "
   16.23      "where id = '" PEP_OWN_USERID "';";
   16.24 @@ -87,12 +90,20 @@
   16.25      "insert or replace into trust (user_id, pgp_keypair_fpr, comm_type) "
   16.26      "values (?1, upper(replace(?2,' ','')), ?3) ;";
   16.27  
   16.28 +static const char *sql_update_trust_for_fpr =
   16.29 +    "update trust "
   16.30 +    "set comm_type = ?1 "
   16.31 +    "where pgp_keypair_fpr = upper(replace(?2,' ','')) ;";
   16.32 +
   16.33  static const char *sql_get_trust = 
   16.34      "select comm_type from trust where user_id = ?1 "
   16.35      "and pgp_keypair_fpr = upper(replace(?2,' ','')) ;";
   16.36  
   16.37  static const char *sql_least_trust = 
   16.38 -    "select min(comm_type) from trust where pgp_keypair_fpr = upper(replace(?1,' ','')) ;";
   16.39 +    "select min(comm_type) from trust where"
   16.40 +    " pgp_keypair_fpr = upper(replace(?1,' ',''))"
   16.41 +    " and comm_type != 0;"; // ignores PEP_ct_unknown
   16.42 +    // returns PEP_ct_unknown only when no known trust is recorded
   16.43  
   16.44  static const char *sql_mark_as_compromized = 
   16.45      "update trust not indexed set comm_type = 15"
   16.46 @@ -135,7 +146,11 @@
   16.47      " union "
   16.48      "  select main_key_id from identity "
   16.49      "   where main_key_id = upper(replace(?1,' ',''))"
   16.50 -    "    and user_id = '" PEP_OWN_USERID "' );";
   16.51 +    "    and user_id = '" PEP_OWN_USERID "' "
   16.52 +    " union "
   16.53 +    "  select fpr from own_keys "
   16.54 +    "   where fpr = upper(replace(?1,' ',''))"
   16.55 +    " );";
   16.56  
   16.57  static const char *sql_own_identities_retrieve =  
   16.58      "select address, fpr, username, "
   16.59 @@ -162,14 +177,20 @@
   16.60  static const char *sql_sequence_value1 = 
   16.61      "insert or replace into sequences (name, value, own) "
   16.62      "values (?1, "
   16.63 -    "(select coalesce((select value + 1 from sequences "
   16.64 -    "where name = ?1), 1 )), ?2) ; ";
   16.65 +    "       (select coalesce((select value + 1 from sequences "
   16.66 +    "           where name = ?1), 1 )), "
   16.67 +    "       (select coalesce((select own or ?2 from sequences "
   16.68 +    "           where name = ?1), ?2))) ; ";
   16.69  
   16.70  static const char *sql_sequence_value2 = 
   16.71      "select value, own from sequences where name = ?1 ;";
   16.72  
   16.73  static const char *sql_sequence_value3 = 
   16.74 -    "update sequences set value = ?2, own = ?3 where name = ?1 ;";
   16.75 +    "insert or replace into sequences (name, value, own) "
   16.76 +    "values (?1, "
   16.77 +    "        ?2, "
   16.78 +    "       (select coalesce((select own or ?3 from sequences "
   16.79 +    "           where name = ?1), ?3))) ; ";
   16.80          
   16.81  // Revocation tracking
   16.82  static const char *sql_set_revoked =
   16.83 @@ -202,6 +223,7 @@
   16.84      int int_result;
   16.85      
   16.86      bool in_first = false;
   16.87 +    bool very_first = false;
   16.88  
   16.89      assert(sqlite3_threadsafe());
   16.90      if (!sqlite3_threadsafe())
   16.91 @@ -227,6 +249,10 @@
   16.92  
   16.93      _session->version = PEP_ENGINE_VERSION;
   16.94  
   16.95 +#ifdef DEBUG_ERRORSTACK
   16.96 +    _session->errorstack = new_stringlist("init()");
   16.97 +#endif
   16.98 +
   16.99      assert(LOCAL_DB);
  16.100      if (LOCAL_DB == NULL) {
  16.101          status = PEP_INIT_CANNOT_OPEN_DB;
  16.102 @@ -390,56 +416,75 @@
  16.103          );
  16.104          assert(int_result == SQLITE_OK);
  16.105  
  16.106 -        if (version < 1) {
  16.107 -            int_result = sqlite3_exec(
  16.108 -                _session->db,
  16.109 -                "alter table identity\n"
  16.110 -                "   add column flags integer default 0;\n",
  16.111 -                NULL,
  16.112 -                NULL,
  16.113 -                NULL
  16.114 -            );
  16.115 +        if(version != 0) { 
  16.116 +            // Version has been already set
  16.117 +
  16.118 +            // Early mistake : version 0 shouldn't have existed.
  16.119 +            // Numbering should have started at 1 to detect newly created DB.
  16.120 +            // Version 0 DBs are not anymore compatible.
  16.121 +
  16.122 +            // // Was version 0 compat code.
  16.123 +            // if (version < 1) {
  16.124 +            //     int_result = sqlite3_exec(
  16.125 +            //         _session->db,
  16.126 +            //         "alter table identity\n"
  16.127 +            //         "   add column flags integer default 0;\n",
  16.128 +            //         NULL,
  16.129 +            //         NULL,
  16.130 +            //         NULL
  16.131 +            //     );
  16.132 +            //     assert(int_result == SQLITE_OK);
  16.133 +            // }
  16.134 +
  16.135 +            if (version < 2) {
  16.136 +                int_result = sqlite3_exec(
  16.137 +                    _session->db,
  16.138 +                    "alter table pgp_keypair\n"
  16.139 +                    "   add column flags integer default 0;\n"
  16.140 +                    "alter table person\n"
  16.141 +                    "   add column device_group text;\n",
  16.142 +                    NULL,
  16.143 +                    NULL,
  16.144 +                    NULL
  16.145 +                );
  16.146 +                assert(int_result == SQLITE_OK);
  16.147 +            }
  16.148 +
  16.149 +            if (version < 3) {
  16.150 +                int_result = sqlite3_exec(
  16.151 +                    _session->db,
  16.152 +                    "alter table sequences\n"
  16.153 +                    "   add column own integer default 0;\n",
  16.154 +                    NULL,
  16.155 +                    NULL,
  16.156 +                    NULL
  16.157 +                );
  16.158 +                assert(int_result == SQLITE_OK);
  16.159 +            }
  16.160 +
  16.161 +            if (version < 5) {
  16.162 +                int_result = sqlite3_exec(
  16.163 +                    _session->db,
  16.164 +                    "delete from pgp_keypair where fpr = '';",
  16.165 +                    NULL,
  16.166 +                    NULL,
  16.167 +                    NULL
  16.168 +                );
  16.169 +                assert(int_result == SQLITE_OK);
  16.170 +                int_result = sqlite3_exec(
  16.171 +                    _session->db,
  16.172 +                    "delete from trust where pgp_keypair_fpr = '';",
  16.173 +                    NULL,
  16.174 +                    NULL,
  16.175 +                    NULL
  16.176 +                );
  16.177 +                assert(int_result == SQLITE_OK);
  16.178 +            }
  16.179          }
  16.180 -
  16.181 -        if (version < 2) {
  16.182 -            int_result = sqlite3_exec(
  16.183 -                _session->db,
  16.184 -                "alter table pgp_keypair\n"
  16.185 -                "   add column flags integer default 0;\n"
  16.186 -                "alter table person\n"
  16.187 -                "   add column device_group text;\n",
  16.188 -                NULL,
  16.189 -                NULL,
  16.190 -                NULL
  16.191 -            );
  16.192 -        }
  16.193 -
  16.194 -        if (version < 3) {
  16.195 -            int_result = sqlite3_exec(
  16.196 -                _session->db,
  16.197 -                "alter table sequences\n"
  16.198 -                "   add column own integer default 0;\n",
  16.199 -                NULL,
  16.200 -                NULL,
  16.201 -                NULL
  16.202 -            );
  16.203 -        }
  16.204 -
  16.205 -        if (version < 5) {
  16.206 -            int_result = sqlite3_exec(
  16.207 -                _session->db,
  16.208 -                "delete from pgp_keypair where fpr = '';",
  16.209 -                NULL,
  16.210 -                NULL,
  16.211 -                NULL
  16.212 -            );
  16.213 -            int_result = sqlite3_exec(
  16.214 -                _session->db,
  16.215 -                "delete from trust where pgp_keypair_fpr = '';",
  16.216 -                NULL,
  16.217 -                NULL,
  16.218 -                NULL
  16.219 -            );
  16.220 +        else { 
  16.221 +            // Version from DB was 0, it means this is initial setup.
  16.222 +            // DB has just been created, and all tables are empty.
  16.223 +            very_first = true;
  16.224          }
  16.225  
  16.226          if (version < atoi(_DDL_USER_VERSION)) {
  16.227 @@ -454,7 +499,6 @@
  16.228              );
  16.229              assert(int_result == SQLITE_OK);
  16.230          }
  16.231 -
  16.232      }
  16.233  
  16.234      int_result = sqlite3_prepare_v2(_session->db, sql_log,
  16.235 @@ -469,6 +513,11 @@
  16.236              (int)strlen(sql_get_identity), &_session->get_identity, NULL);
  16.237      assert(int_result == SQLITE_OK);
  16.238  
  16.239 +    int_result = sqlite3_prepare_v2(_session->db, sql_replace_identities_fpr,
  16.240 +            (int)strlen(sql_replace_identities_fpr), 
  16.241 +            &_session->replace_identities_fpr, NULL);
  16.242 +    assert(int_result == SQLITE_OK);
  16.243 +
  16.244      int_result = sqlite3_prepare_v2(_session->db, sql_set_person,
  16.245              (int)strlen(sql_set_person), &_session->set_person, NULL);
  16.246      assert(int_result == SQLITE_OK);
  16.247 @@ -504,6 +553,10 @@
  16.248              (int)strlen(sql_set_trust), &_session->set_trust, NULL);
  16.249      assert(int_result == SQLITE_OK);
  16.250  
  16.251 +    int_result = sqlite3_prepare_v2(_session->db, sql_update_trust_for_fpr,
  16.252 +            (int)strlen(sql_update_trust_for_fpr), &_session->update_trust_for_fpr, NULL);
  16.253 +    assert(int_result == SQLITE_OK);
  16.254 +
  16.255      int_result = sqlite3_prepare_v2(_session->db, sql_get_trust,
  16.256              (int)strlen(sql_get_trust), &_session->get_trust, NULL);
  16.257      assert(int_result == SQLITE_OK);
  16.258 @@ -614,13 +667,50 @@
  16.259      // runtime config
  16.260  
  16.261  #ifdef ANDROID
  16.262 -    _session->use_only_own_private_keys = true;
  16.263  #elif TARGET_OS_IPHONE
  16.264 -    _session->use_only_own_private_keys = true;
  16.265 -#else
  16.266 -    _session->use_only_own_private_keys = false;
  16.267 +#else /* Desktop */
  16.268 +    if (very_first)
  16.269 +    {
  16.270 +        // On first run, all private keys already present in PGP keyring 
  16.271 +        // are taken as own in order to seamlessly integrate with
  16.272 +        // pre-existing GPG setup.
  16.273 +
  16.274 +        ////////////////////////////// WARNING: ///////////////////////////
  16.275 +        // Considering all PGP priv keys as own is dangerous in case of 
  16.276 +        // re-initialization of pEp DB, while keeping PGP keyring as-is!
  16.277 +        //
  16.278 +        // Indeed, if pEpEngine did import spoofed private keys in previous
  16.279 +        // install, then those keys become automatically trusted in case 
  16.280 +        // pEp_management.db is deleted.
  16.281 +        //
  16.282 +        // A solution to distinguish bare GPG keyring from pEp keyring is
  16.283 +        // needed here. Then keys managed by pEpEngine wouldn't be
  16.284 +        // confused with GPG keys managed by the user through GPA.
  16.285 +        ///////////////////////////////////////////////////////////////////
  16.286 +        
  16.287 +        stringlist_t *keylist = NULL;
  16.288 +
  16.289 +        status = find_private_keys(_session, NULL, &keylist);
  16.290 +        assert(status != PEP_OUT_OF_MEMORY);
  16.291 +        if (status == PEP_OUT_OF_MEMORY)
  16.292 +            return PEP_OUT_OF_MEMORY;
  16.293 +        
  16.294 +        if (keylist != NULL && keylist->value != NULL)
  16.295 +        {
  16.296 +            stringlist_t *_keylist;
  16.297 +            for (_keylist = keylist; _keylist && _keylist->value; _keylist = _keylist->next) {
  16.298 +                status = set_own_key(_session, 
  16.299 +                                     "" /* address is unused in own_keys */,
  16.300 +                                     _keylist->value);
  16.301 +            }
  16.302 +        }
  16.303 +    }
  16.304  #endif
  16.305  
  16.306 +    // sync_session set to own session by default
  16.307 +    // sync_session is then never null on a valid session
  16.308 +    _session->sync_session = _session;
  16.309 +
  16.310      *session = _session;
  16.311      return PEP_STATUS_OK;
  16.312  
  16.313 @@ -660,6 +750,8 @@
  16.314                  sqlite3_finalize(session->trustword);
  16.315              if (session->get_identity)
  16.316                  sqlite3_finalize(session->get_identity);
  16.317 +            if (session->replace_identities_fpr)
  16.318 +                sqlite3_finalize(session->replace_identities_fpr);        
  16.319              if (session->set_person)
  16.320                  sqlite3_finalize(session->set_person);
  16.321              if (session->set_device_group)
  16.322 @@ -676,6 +768,8 @@
  16.323                  sqlite3_finalize(session->unset_identity_flags);
  16.324              if (session->set_trust)
  16.325                  sqlite3_finalize(session->set_trust);
  16.326 +            if (session->update_trust_for_fpr)
  16.327 +                sqlite3_finalize(session->update_trust_for_fpr);
  16.328              if (session->get_trust)
  16.329                  sqlite3_finalize(session->get_trust);
  16.330              if (session->least_trust)
  16.331 @@ -724,6 +818,9 @@
  16.332          release_transport_system(session, out_last);
  16.333          release_cryptotech(session, out_last);
  16.334  
  16.335 +#ifdef DEBUG_ERRORSTACK
  16.336 +        free_stringlist(session->errorstack);
  16.337 +#endif
  16.338          free(session);
  16.339      }
  16.340  }
  16.341 @@ -740,19 +837,18 @@
  16.342      session->unencrypted_subject = enable;
  16.343  }
  16.344  
  16.345 -DYNAMIC_API void config_use_only_own_private_keys(PEP_SESSION session,
  16.346 -        bool enable)
  16.347 -{
  16.348 -    assert(session);
  16.349 -    session->use_only_own_private_keys = enable;
  16.350 -}
  16.351 -
  16.352  DYNAMIC_API void config_keep_sync_msg(PEP_SESSION session, bool enable)
  16.353  {
  16.354      assert(session);
  16.355      session->keep_sync_msg = enable;
  16.356  }
  16.357  
  16.358 +DYNAMIC_API void config_service_log(PEP_SESSION session, bool enable)
  16.359 +{
  16.360 +    assert(session);
  16.361 +    session->service_log = enable;
  16.362 +}
  16.363 +
  16.364  DYNAMIC_API PEP_STATUS log_event(
  16.365          PEP_SESSION session,
  16.366          const char *title,
  16.367 @@ -790,7 +886,25 @@
  16.368      } while (result == SQLITE_BUSY);
  16.369      sqlite3_reset(session->log);
  16.370  
  16.371 -    return status;
  16.372 +    return ERROR(status);
  16.373 +}
  16.374 +
  16.375 +DYNAMIC_API PEP_STATUS log_service(
  16.376 +        PEP_SESSION session,
  16.377 +        const char *title,
  16.378 +        const char *entity,
  16.379 +        const char *description,
  16.380 +        const char *comment
  16.381 +    )
  16.382 +{
  16.383 +    assert(session);
  16.384 +    if (!session)
  16.385 +        return PEP_ILLEGAL_VALUE;
  16.386 +
  16.387 +    if (session->service_log)
  16.388 +        return log_event(session, title, entity, description, comment);
  16.389 +    else
  16.390 +        return PEP_STATUS_OK;
  16.391  }
  16.392  
  16.393  DYNAMIC_API PEP_STATUS trustword(
  16.394 @@ -1080,13 +1194,15 @@
  16.395                  identity->user_id && identity->username))
  16.396          return PEP_ILLEGAL_VALUE;
  16.397  
  16.398 +    PEP_STATUS status = PEP_STATUS_OK;
  16.399 +    
  16.400      bool listed;
  16.401  
  16.402      bool has_fpr = (identity->fpr && identity->fpr[0] != '\0');
  16.403      
  16.404      if (has_fpr) {    
  16.405          // blacklist check
  16.406 -        PEP_STATUS status = blacklist_is_listed(session, identity->fpr, &listed);
  16.407 +        status = blacklist_is_listed(session, identity->fpr, &listed);
  16.408          assert(status == PEP_STATUS_OK);
  16.409          if (status != PEP_STATUS_OK)
  16.410              return status;
  16.411 @@ -1164,6 +1280,8 @@
  16.412              }
  16.413          }
  16.414  
  16.415 +        // status = set_trust(session, identity->user_id, identity->fpr,
  16.416 +        //                    identity->comm_type)
  16.417          sqlite3_reset(session->set_trust);
  16.418          sqlite3_bind_text(session->set_trust, 1, identity->user_id, -1,
  16.419                  SQLITE_STATIC);
  16.420 @@ -1185,6 +1303,52 @@
  16.421          return PEP_COMMIT_FAILED;
  16.422  }
  16.423  
  16.424 +PEP_STATUS replace_identities_fpr(PEP_SESSION session, 
  16.425 +                                 const char* old_fpr, 
  16.426 +                                 const char* new_fpr) 
  16.427 +{
  16.428 +    assert(old_fpr);
  16.429 +    assert(new_fpr);
  16.430 +    
  16.431 +    if (!old_fpr || !new_fpr)
  16.432 +        return PEP_ILLEGAL_VALUE;
  16.433 +            
  16.434 +    sqlite3_reset(session->replace_identities_fpr);
  16.435 +    sqlite3_bind_text(session->replace_identities_fpr, 1, new_fpr, -1,
  16.436 +                      SQLITE_STATIC);
  16.437 +    sqlite3_bind_text(session->replace_identities_fpr, 2, old_fpr, -1,
  16.438 +                      SQLITE_STATIC);
  16.439 +
  16.440 +    int result = sqlite3_step(session->replace_identities_fpr);
  16.441 +    sqlite3_reset(session->replace_identities_fpr);
  16.442 +    
  16.443 +    if (result != SQLITE_DONE)
  16.444 +        return PEP_CANNOT_SET_IDENTITY;
  16.445 +
  16.446 +    return PEP_STATUS_OK;
  16.447 +}
  16.448 +
  16.449 +
  16.450 +PEP_STATUS update_trust_for_fpr(PEP_SESSION session, 
  16.451 +                                const char* fpr, 
  16.452 +                                PEP_comm_type comm_type)
  16.453 +{
  16.454 +    if (!fpr)
  16.455 +        return PEP_ILLEGAL_VALUE;
  16.456 +        
  16.457 +    sqlite3_reset(session->update_trust_for_fpr);
  16.458 +    sqlite3_bind_int(session->update_trust_for_fpr, 1, comm_type);
  16.459 +    sqlite3_bind_text(session->update_trust_for_fpr, 2, fpr, -1,
  16.460 +            SQLITE_STATIC);
  16.461 +    int result = sqlite3_step(session->update_trust_for_fpr);
  16.462 +    sqlite3_reset(session->update_trust_for_fpr);
  16.463 +    if (result != SQLITE_DONE) {
  16.464 +        return PEP_CANNOT_SET_TRUST;
  16.465 +    }
  16.466 +    
  16.467 +    return PEP_STATUS_OK;
  16.468 +}
  16.469 +
  16.470  DYNAMIC_API PEP_STATUS set_device_group(
  16.471          PEP_SESSION session,
  16.472          const char *group_name
  16.473 @@ -1193,14 +1357,18 @@
  16.474      int result;
  16.475  
  16.476      assert(session);
  16.477 -    assert(group_name);
  16.478  
  16.479      if (!(session && group_name))
  16.480          return PEP_ILLEGAL_VALUE;
  16.481  
  16.482      sqlite3_reset(session->set_device_group);
  16.483 -    sqlite3_bind_text(session->set_device_group, 1, group_name, -1,
  16.484 -            SQLITE_STATIC);
  16.485 +    if(group_name){
  16.486 +        sqlite3_bind_text(session->set_device_group, 1, group_name, -1,
  16.487 +                SQLITE_STATIC);
  16.488 +    } else {
  16.489 +        sqlite3_bind_null(session->set_device_group, 1);
  16.490 +    }
  16.491 +
  16.492      result = sqlite3_step(session->set_device_group);
  16.493      sqlite3_reset(session->set_device_group);
  16.494      if (result != SQLITE_DONE)
  16.495 @@ -1225,10 +1393,12 @@
  16.496      result = sqlite3_step(session->get_device_group);
  16.497      switch (result) {
  16.498      case SQLITE_ROW: {
  16.499 -        *group_name = strdup(
  16.500 -            (const char *) sqlite3_column_text(session->get_device_group, 0));
  16.501 -            if(*group_name == NULL)
  16.502 -                status = PEP_OUT_OF_MEMORY;
  16.503 +        const char *_group_name = (const char *)sqlite3_column_text(session->get_device_group, 0);
  16.504 +        if(_group_name){
  16.505 +            *group_name = strdup(_group_name);
  16.506 +                if(*group_name == NULL)
  16.507 +                    status = PEP_OUT_OF_MEMORY;
  16.508 +        }
  16.509          break;
  16.510      }
  16.511   
  16.512 @@ -1401,6 +1571,7 @@
  16.513              break;
  16.514          }
  16.515          default:
  16.516 +            // never reached because of sql min()
  16.517              status = PEP_CANNOT_FIND_IDENTITY;
  16.518      }
  16.519  
  16.520 @@ -1447,6 +1618,26 @@
  16.521              keylist, ptext, psize, ctext, csize);
  16.522  }
  16.523  
  16.524 +PEP_STATUS encrypt_only(
  16.525 +    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  16.526 +    size_t psize, char **ctext, size_t *csize
  16.527 +    )
  16.528 +{
  16.529 +    assert(session);
  16.530 +    assert(keylist);
  16.531 +    assert(ptext);
  16.532 +    assert(psize);
  16.533 +    assert(ctext);
  16.534 +    assert(csize);
  16.535 +
  16.536 +    if (!(session && keylist && ptext && psize && ctext && csize))
  16.537 +        return PEP_ILLEGAL_VALUE;
  16.538 +
  16.539 +    return session->cryptotech[PEP_crypt_OpenPGP].encrypt_only(session,
  16.540 +            keylist, ptext, psize, ctext, csize);
  16.541 +}
  16.542 +
  16.543 +
  16.544  DYNAMIC_API PEP_STATUS verify_text(
  16.545      PEP_SESSION session, const char *text, size_t size,
  16.546      const char *signature, size_t sig_size, stringlist_t **keylist
  16.547 @@ -1797,7 +1988,7 @@
  16.548      status = PEP_OUT_OF_MEMORY;
  16.549  
  16.550  the_end:
  16.551 -    return status;
  16.552 +    return ERROR(status);
  16.553  }
  16.554  
  16.555  DYNAMIC_API PEP_STATUS get_languagelist(
  16.556 @@ -2004,6 +2195,7 @@
  16.557      )
  16.558  {
  16.559      PEP_STATUS status = PEP_STATUS_OK;
  16.560 +    int result;
  16.561  
  16.562      assert(session);
  16.563      assert(name && value && *value >= 0);
  16.564 @@ -2019,32 +2211,60 @@
  16.565          own = 1;
  16.566      }
  16.567      else {
  16.568 -        if (name == session->sync_uuid || strcmp(name, session->sync_uuid) == 0)
  16.569 +        if (name == session->sync_session->sync_uuid || 
  16.570 +            strcmp(name, session->sync_session->sync_uuid) == 0)
  16.571              own = 1;
  16.572      }
  16.573  
  16.574      if (*value) {
  16.575 +        sqlite3_exec(session->db, "BEGIN ;", NULL, NULL, NULL);
  16.576          int32_t old_value = 0;
  16.577          status = _get_sequence_value(session, name, &old_value);
  16.578          if (status != PEP_STATUS_OK && status != PEP_RECORD_NOT_FOUND)
  16.579 +        {
  16.580 +            sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
  16.581              return status;
  16.582 +        }
  16.583  
  16.584          if (old_value >= *value) {
  16.585 +            sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
  16.586              return PEP_SEQUENCE_VIOLATED;
  16.587          }
  16.588          else {
  16.589              status = _set_sequence_value(session, name, *value, own);
  16.590 -            return status;
  16.591 +            if (status == PEP_STATUS_OK) {
  16.592 +                result = sqlite3_exec(session->db, "COMMIT ;", NULL, NULL, NULL);
  16.593 +                if (result == SQLITE_OK)
  16.594 +                    return PEP_STATUS_OK;
  16.595 +                else
  16.596 +                    return PEP_COMMIT_FAILED;
  16.597 +            } else {
  16.598 +                sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
  16.599 +                return status;
  16.600 +            }
  16.601          }
  16.602      }
  16.603  
  16.604      assert(*value == 0);
  16.605 +    sqlite3_exec(session->db, "BEGIN ;", NULL, NULL, NULL);
  16.606      status = _increment_sequence_value(session, name, own);
  16.607      if (status == PEP_STATUS_OK) {
  16.608          status = _get_sequence_value(session, name, value);
  16.609 -        assert(*value < INT32_MAX);
  16.610 -        if (*value == INT32_MAX)
  16.611 -            return PEP_CANNOT_INCREASE_SEQUENCE;
  16.612 +    }
  16.613 +    if (status == PEP_STATUS_OK || status == PEP_OWN_SEQUENCE) {
  16.614 +        result = sqlite3_exec(session->db, "COMMIT ;", NULL, NULL, NULL);
  16.615 +        if (result == SQLITE_OK){
  16.616 +            assert(*value < INT32_MAX);
  16.617 +            if (*value == INT32_MAX){
  16.618 +                return PEP_CANNOT_INCREASE_SEQUENCE;
  16.619 +            }
  16.620 +            return status;
  16.621 +        } else {
  16.622 +            return PEP_COMMIT_FAILED;
  16.623 +        }
  16.624 +    } else {
  16.625 +        sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
  16.626 +        return status;
  16.627      }
  16.628      return status;
  16.629  }
  16.630 @@ -2157,8 +2377,8 @@
  16.631  
  16.632  PEP_STATUS find_private_keys(PEP_SESSION session, const char* pattern,
  16.633                               stringlist_t **keylist) {
  16.634 -    assert(session && pattern && keylist);
  16.635 -    if (!(session && pattern && keylist))
  16.636 +    assert(session && keylist);
  16.637 +    if (!(session && keylist))
  16.638          return PEP_ILLEGAL_VALUE;
  16.639      
  16.640      return session->cryptotech[PEP_crypt_OpenPGP].find_private_keys(session, pattern,
  16.641 @@ -2186,5 +2406,57 @@
  16.642      );
  16.643      assert(int_result == SQLITE_OK);
  16.644  
  16.645 +    if (int_result != SQLITE_OK)
  16.646 +        return PEP_UNKNOWN_ERROR;
  16.647 +
  16.648      return PEP_STATUS_OK;
  16.649  }
  16.650 +
  16.651 +#ifdef DEBUG_ERRORSTACK
  16.652 +PEP_STATUS session_add_error(PEP_SESSION session, const char* file, unsigned line, PEP_STATUS status)
  16.653 +{
  16.654 +    char logline[48];
  16.655 +    if(status>0)
  16.656 +    {
  16.657 +        snprintf(logline,47, "%.24s:%u status=%u (0x%x)", file, line, status, status);
  16.658 +    }else{
  16.659 +        snprintf(logline,47, "%.24s:%u status=%i.", file, line, status);
  16.660 +    }
  16.661 +    stringlist_add(session->errorstack, logline); // logline is copied! :-)
  16.662 +    return status;
  16.663 +}
  16.664 +
  16.665 +DYNAMIC_API const stringlist_t* get_errorstack(PEP_SESSION session)
  16.666 +{
  16.667 +    return session->errorstack;
  16.668 +}
  16.669 +
  16.670 +DYNAMIC_API void clear_errorstack(PEP_SESSION session)
  16.671 +{
  16.672 +    const int old_len = stringlist_length(session->errorstack);
  16.673 +    char buf[48];
  16.674 +    free_stringlist(session->errorstack);
  16.675 +    snprintf(buf, 47, "(%i elements cleared)", old_len);
  16.676 +    session->errorstack = new_stringlist(buf);
  16.677 +}
  16.678 +
  16.679 +#else
  16.680 +
  16.681 +static stringlist_t* dummy_errorstack = NULL;
  16.682 +
  16.683 +DYNAMIC_API const stringlist_t* get_errorstack(PEP_SESSION session)
  16.684 +{
  16.685 +    if(dummy_errorstack == NULL)
  16.686 +    {
  16.687 +        dummy_errorstack = new_stringlist("( Please recompile pEpEngine with -DDEBUG_ERRORSTACK )");
  16.688 +    }
  16.689 +
  16.690 +    return dummy_errorstack;
  16.691 +}
  16.692 +
  16.693 +DYNAMIC_API void clear_errorstack(PEP_SESSION session)
  16.694 +{
  16.695 +    // nothing to do here
  16.696 +}
  16.697 +
  16.698 +#endif
    17.1 --- a/src/pEpEngine.h	Tue Jan 31 08:42:25 2017 +0100
    17.2 +++ b/src/pEpEngine.h	Tue Jun 13 13:00:37 2017 +0200
    17.3 @@ -46,6 +46,7 @@
    17.4      PEP_KEY_HAS_AMBIG_NAME                          = 0x0202,
    17.5      PEP_GET_KEY_FAILED                              = 0x0203,
    17.6      PEP_CANNOT_EXPORT_KEY                           = 0x0204,
    17.7 +    PEP_CANNOT_EDIT_KEY                             = 0x0205,
    17.8      
    17.9      PEP_CANNOT_FIND_IDENTITY                        = 0x0301,
   17.10      PEP_CANNOT_SET_PERSON                           = 0x0381,
   17.11 @@ -147,6 +148,25 @@
   17.12  DYNAMIC_API void release(PEP_SESSION session);
   17.13  
   17.14  
   17.15 +// const stringlist_t* get_errorstack(PEP_SESSION) - get the error stack for that session, if any
   17.16 +//
   17.17 +//  parameters:
   17.18 +//        session (in)    session handle
   17.19 +//
   17.20 +//    caveat:
   17.21 +//        To get a useful error stack you have to compile with -DDEBUG_ERRORSTACK
   17.22 +//        The error stack belongs to the session. Do no not change it!
   17.23 +DYNAMIC_API const stringlist_t* get_errorstack(PEP_SESSION session);
   17.24 +
   17.25 +
   17.26 +// void clear_errorstack(PEP_SESSION) - clear the error stack for that session, if any
   17.27 +//
   17.28 +//  parameters:
   17.29 +//        session (in)    session handle
   17.30 +//
   17.31 +DYNAMIC_API void clear_errorstack(PEP_SESSION session);
   17.32 +
   17.33 +
   17.34  // config_passive_mode() - enable passive mode
   17.35  //
   17.36  //  parameters:
   17.37 @@ -182,6 +202,14 @@
   17.38  DYNAMIC_API void config_keep_sync_msg(PEP_SESSION session, bool enable);
   17.39  
   17.40  
   17.41 +// config_service_log() - log more for service purposes
   17.42 +//
   17.43 +//      session (in)    session handle
   17.44 +//      enable (in)     flag if enabled or disabled
   17.45 +
   17.46 +DYNAMIC_API void config_service_log(PEP_SESSION session, bool enable);
   17.47 +
   17.48 +
   17.49  // decrypt_and_verify() - decrypt and/or verify a message
   17.50  //
   17.51  //    parameters:
   17.52 @@ -296,6 +324,17 @@
   17.53      );
   17.54  
   17.55  
   17.56 +DYNAMIC_API PEP_STATUS log_service(PEP_SESSION session, const char *title,
   17.57 +        const char *entity, const char *description, const char *comment);
   17.58 +
   17.59 +#define _STR_(x) #x
   17.60 +#define _D_STR_(x) _STR_(x)
   17.61 +#define S_LINE _D_STR_(__LINE__)
   17.62 +
   17.63 +#define SERVICE_LOG(session, title, entity, desc) \
   17.64 +    log_service((session), (title), (entity), (desc), "service " __FILE__ ":" S_LINE)
   17.65 +
   17.66 +
   17.67  // trustword() - get the corresponding trustword for a 16 bit value
   17.68  //
   17.69  //    parameters:
   17.70 @@ -402,7 +441,7 @@
   17.71      // range 0x90 to 0xbf: confirmed encryption
   17.72  
   17.73      PEP_ct_confirmed_encryption = 0x90,         // generic
   17.74 -    PEP_ct_OpenPGP_weak = 0x91,                 // RSA 1024 is weak
   17.75 +    PEP_ct_OpenPGP_weak = 0x91,                 // RSA 1024 is weak (unused)
   17.76  
   17.77      PEP_ct_to_be_checked_confirmed = 0xa0,      //generic
   17.78      PEP_ct_SMIME = 0xa1,
   17.79 @@ -524,6 +563,11 @@
   17.80          pEp_identity **identity
   17.81      );
   17.82  
   17.83 +PEP_STATUS replace_identities_fpr(PEP_SESSION session, 
   17.84 +                                 const char* old_fpr, 
   17.85 +                                 const char* new_fpr); 
   17.86 +
   17.87 +
   17.88  // set_identity() - set identity information
   17.89  //
   17.90  //    parameters:
   17.91 @@ -807,6 +851,14 @@
   17.92  
   17.93  DYNAMIC_API PEP_STATUS get_trust(PEP_SESSION session, pEp_identity *identity);
   17.94  
   17.95 +PEP_STATUS set_trust(PEP_SESSION session, 
   17.96 +                            const char* user_id,
   17.97 +                            const char* fpr, 
   17.98 +                            PEP_comm_type comm_type);
   17.99 +                            
  17.100 +PEP_STATUS update_trust_for_fpr(PEP_SESSION session, 
  17.101 +                                const char* fpr, 
  17.102 +                                PEP_comm_type comm_type);
  17.103  
  17.104  // least_trust() - get the least known trust level for a key in the database
  17.105  //
  17.106 @@ -905,6 +957,12 @@
  17.107          bool *revoked
  17.108      );
  17.109  
  17.110 +PEP_STATUS get_key_userids(
  17.111 +        PEP_SESSION session,
  17.112 +        const char* fpr,
  17.113 +        stringlist_t** keylist
  17.114 +    );
  17.115 +
  17.116  
  17.117  // get_crashdump_log() - get the last log messages out
  17.118  //
    18.1 --- a/src/pEp_internal.h	Tue Jan 31 08:42:25 2017 +0100
    18.2 +++ b/src/pEp_internal.h	Tue Jun 13 13:00:37 2017 +0200
    18.3 @@ -81,7 +81,9 @@
    18.4  
    18.5  #define NOT_IMPLEMENTED assert(0); return PEP_UNKNOWN_ERROR;
    18.6  
    18.7 -typedef struct _pEpSession {
    18.8 +struct _pEpSession;
    18.9 +typedef struct _pEpSession pEpSession;
   18.10 +struct _pEpSession {
   18.11      const char *version;
   18.12  #ifdef USE_GPG
   18.13      gpgme_ctx_t ctx;
   18.14 @@ -98,6 +100,7 @@
   18.15      sqlite3_stmt *log;
   18.16      sqlite3_stmt *trustword;
   18.17      sqlite3_stmt *get_identity;
   18.18 +    sqlite3_stmt *replace_identities_fpr;
   18.19      sqlite3_stmt *set_person;
   18.20      sqlite3_stmt *set_device_group;
   18.21      sqlite3_stmt *get_device_group;
   18.22 @@ -106,6 +109,7 @@
   18.23      sqlite3_stmt *set_identity_flags;
   18.24      sqlite3_stmt *unset_identity_flags;
   18.25      sqlite3_stmt *set_trust;
   18.26 +    sqlite3_stmt *update_trust_for_fpr;
   18.27      sqlite3_stmt *get_trust;
   18.28      sqlite3_stmt *least_trust;
   18.29      sqlite3_stmt *mark_compromized;
   18.30 @@ -146,6 +150,7 @@
   18.31      retrieve_next_sync_msg_t retrieve_next_sync_msg;
   18.32  
   18.33      // key sync
   18.34 +    pEpSession* sync_session;
   18.35      DeviceState_state sync_state;
   18.36      void* sync_state_payload;
   18.37      char sync_uuid[37];
   18.38 @@ -156,22 +161,143 @@
   18.39  
   18.40      bool passive_mode;
   18.41      bool unencrypted_subject;
   18.42 -    bool use_only_own_private_keys;
   18.43      bool keep_sync_msg;
   18.44 +    bool service_log;
   18.45      
   18.46 -} pEpSession;
   18.47 +#ifdef DEBUG_ERRORSTACK
   18.48 +    stringlist_t* errorstack;
   18.49 +#endif
   18.50 +};
   18.51 +
   18.52  
   18.53  PEP_STATUS init_transport_system(PEP_SESSION session, bool in_first);
   18.54  void release_transport_system(PEP_SESSION session, bool out_last);
   18.55  
   18.56 +/* NOT to be exposed to the outside!!! */
   18.57 +PEP_STATUS encrypt_only(
   18.58 +        PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
   18.59 +        size_t psize, char **ctext, size_t *csize
   18.60 +);
   18.61 +
   18.62  #ifdef NDEBUG
   18.63  #define DEBUG_LOG(TITLE, ENTITY, DESC)
   18.64  #else
   18.65 -#define DEBUG_LOG(TITLE, ENTITY, DESC) \
   18.66 -    log_event(session, (TITLE), (ENTITY), (DESC), "debug");
   18.67 +#ifdef ANDROID
   18.68 +#include <android/log.h>
   18.69 +#define  LOG_MORE(...)  __android_log_print(ANDROID_LOG_DEBUG, "pEpEngine", " %s :: %s :: %s :: %s ", __VA_ARGS__);
   18.70 +#else
   18.71 +#include <stdio.h>
   18.72 +#define  LOG_MORE(...)  fprintf(stderr, "pEpEngine DEBUG_LOG('%s','%s','%s','%s')\n", __VA_ARGS__);
   18.73 +#endif
   18.74 +#define DEBUG_LOG(TITLE, ENTITY, DESC) {\
   18.75 +    log_event(session, (TITLE), (ENTITY), (DESC), "debug " __FILE__ ":" S_LINE);\
   18.76 +    LOG_MORE((TITLE), (ENTITY), (DESC), __FILE__ ":" S_LINE)\
   18.77 +}
   18.78  #endif
   18.79  
   18.80 +typedef enum _normalize_hex_rest_t {
   18.81 +    accept_hex,
   18.82 +    ignore_hex,
   18.83 +    reject_hex
   18.84 +} normalize_hex_res_t;
   18.85 +
   18.86 +static inline normalize_hex_res_t _normalize_hex(char *hex) 
   18.87 +{
   18.88 +    if (*hex >= '0' && *hex <= '9')
   18.89 +        return accept_hex;
   18.90 +
   18.91 +    if (*hex >= 'A' && *hex <= 'F') {
   18.92 +        *hex += 'a' - 'A';
   18.93 +        return accept_hex;
   18.94 +    }
   18.95 +
   18.96 +    if (*hex >= 'a' && *hex <= 'f') 
   18.97 +        return accept_hex;
   18.98 +
   18.99 +    if (*hex == ' ') 
  18.100 +        return ignore_hex;
  18.101 +
  18.102 +    return reject_hex;
  18.103 +}
  18.104 +
  18.105  // Space tolerant and case insensitive fingerprint string compare
  18.106 +static inline PEP_STATUS _compare_fprs(
  18.107 +        const char* fpra,
  18.108 +        size_t fpras,
  18.109 +        const char* fprb,
  18.110 +        size_t fprbs,
  18.111 +        int* comparison)
  18.112 +{
  18.113 +
  18.114 +    size_t ai = 0;
  18.115 +    size_t bi = 0;
  18.116 +    size_t significant = 0;
  18.117 +    int _comparison = 0;
  18.118 +    const int _FULL_FINGERPRINT_LENGTH = 40;
  18.119 +   
  18.120 +    // First compare every non-ignored chars until an end is reached
  18.121 +    while(ai < fpras && bi < fprbs)
  18.122 +    {
  18.123 +        char fprac = fpra[ai];
  18.124 +        char fprbc = fprb[bi];
  18.125 +        normalize_hex_res_t fprah = _normalize_hex(&fprac);
  18.126 +        normalize_hex_res_t fprbh = _normalize_hex(&fprbc);
  18.127 +
  18.128 +        if(fprah == reject_hex || fprbh == reject_hex)
  18.129 +            return PEP_ILLEGAL_VALUE;
  18.130 +
  18.131 +        if ( fprah == ignore_hex )
  18.132 +        {
  18.133 +            ai++;
  18.134 +        }
  18.135 +        else if ( fprbh == ignore_hex )
  18.136 +        {
  18.137 +            bi++;
  18.138 +        }
  18.139 +        else
  18.140 +        {
  18.141 +            if(fprac != fprbc && _comparison == 0 )
  18.142 +            {
  18.143 +                _comparison = fprac > fprbc ? 1 : -1;
  18.144 +            }
  18.145 +
  18.146 +            significant++;
  18.147 +            ai++;
  18.148 +            bi++;
  18.149 +
  18.150 +        } 
  18.151 +    }
  18.152 +
  18.153 +    // Bail out if we didn't got enough significnt chars
  18.154 +    if (significant != _FULL_FINGERPRINT_LENGTH )
  18.155 +        return PEP_TRUSTWORDS_FPR_WRONG_LENGTH;
  18.156 +
  18.157 +    // Then purge remaining chars, all must be ignored chars
  18.158 +    while ( ai < fpras )
  18.159 +    {
  18.160 +        char fprac = fpra[ai];
  18.161 +        normalize_hex_res_t fprah = _normalize_hex(&fprac);
  18.162 +        if( fprah == reject_hex )
  18.163 +            return PEP_ILLEGAL_VALUE;
  18.164 +        if ( fprah != ignore_hex )
  18.165 +            return PEP_TRUSTWORDS_FPR_WRONG_LENGTH;
  18.166 +        ai++;
  18.167 +    }
  18.168 +    while ( bi < fprbs )
  18.169 +    {
  18.170 +        char fprbc = fprb[bi];
  18.171 +        normalize_hex_res_t fprbh = _normalize_hex(&fprbc);
  18.172 +        if( fprbh == reject_hex )
  18.173 +            return PEP_ILLEGAL_VALUE;
  18.174 +        if ( fprbh != ignore_hex )
  18.175 +            return PEP_TRUSTWORDS_FPR_WRONG_LENGTH;
  18.176 +        bi++;
  18.177 +    }
  18.178 +
  18.179 +    *comparison = _comparison;
  18.180 +    return PEP_STATUS_OK;
  18.181 +}
  18.182 +
  18.183  static inline int _same_fpr(
  18.184          const char* fpra,
  18.185          size_t fpras,
  18.186 @@ -179,35 +305,20 @@
  18.187          size_t fprbs
  18.188      )
  18.189  {
  18.190 -    size_t ai = 0;
  18.191 -    size_t bi = 0;
  18.192 -    
  18.193 -    do
  18.194 -    {
  18.195 -        if(fpra[ai] == 0 || fprb[bi] == 0)
  18.196 -        {
  18.197 -            return 0;
  18.198 -        }
  18.199 -        else if(fpra[ai] == ' ')
  18.200 -        {
  18.201 -            ai++;
  18.202 -        }
  18.203 -        else if(fprb[bi] == ' ')
  18.204 -        {
  18.205 -            bi++;
  18.206 -        }
  18.207 -        else if(toupper(fpra[ai]) == toupper(fprb[bi]))
  18.208 -        {
  18.209 -            ai++;
  18.210 -            bi++;
  18.211 -        }
  18.212 -        else
  18.213 -        {
  18.214 -            return 0;
  18.215 -        }
  18.216 -        
  18.217 -    }
  18.218 -    while(ai < fpras && bi < fprbs);
  18.219 -    
  18.220 -    return ai == fpras && bi == fprbs;
  18.221 +    // illegal values are ignored, and considered not same.
  18.222 +    int comparison = 1;
  18.223 +
  18.224 +    _compare_fprs(fpra, fpras, fprb, fprbs, &comparison);
  18.225 +
  18.226 +    return comparison == 0;
  18.227  }
  18.228 +
  18.229 +
  18.230 +#ifdef DEBUG_ERRORSTACK
  18.231 +    PEP_STATUS session_add_error(PEP_SESSION session, const char* file, unsigned line, PEP_STATUS status);
  18.232 +    #define ERROR(status)   session_add_error(session, __FILE__, __LINE__, (status))
  18.233 +    #define GOTO(label)     do{ (void)session_add_error(session, __FILE__, __LINE__, status); goto label; }while(0)
  18.234 +#else
  18.235 +    #define ERROR(status)   (status)
  18.236 +    #define GOTO(label)     goto label
  18.237 +#endif
    19.1 --- a/src/pgp_gpg.c	Tue Jan 31 08:42:25 2017 +0100
    19.2 +++ b/src/pgp_gpg.c	Tue Jun 13 13:00:37 2017 +0200
    19.3 @@ -39,8 +39,7 @@
    19.4          assert(length == stringlist_length(values));
    19.5          if (!(length == stringlist_length(values) &&
    19.6                length <= sizeof(unsigned int) * CHAR_BIT)) {
    19.7 -            r = Fclose(f);
    19.8 -            assert(r == 0);
    19.9 +            Fclose(f);
   19.10  
   19.11              return false;
   19.12          }
   19.13 @@ -62,6 +61,8 @@
   19.14  
   19.15                          if (i == n) {
   19.16                              r = Fclose(f);
   19.17 +                            if (r != 0)
   19.18 +                                return false;
   19.19                              return true;
   19.20                          }
   19.21                      }
   19.22 @@ -83,11 +84,15 @@
   19.23          if ((found & i) == 0) {
   19.24              r = Fprintf(f, "%s %s\n", _k->value, _v->value);
   19.25              assert(r >= 0);
   19.26 +            if(r<0)
   19.27 +                return false;
   19.28          }
   19.29      }
   19.30  
   19.31      r = Fclose(f);
   19.32      assert(r == 0);
   19.33 +    if (r != 0)
   19.34 +        return false;
   19.35  
   19.36      return true;
   19.37  }
   19.38 @@ -118,6 +123,9 @@
   19.39          stringlist_add(conf_keys, "personal-digest-preferences");
   19.40          stringlist_add(conf_values, "SHA256 SHA512 SHA384 SHA224");
   19.41  
   19.42 +        stringlist_add(conf_keys, "ignore-time-conflict");
   19.43 +        stringlist_add(conf_values, "");
   19.44 +
   19.45          bResult = ensure_config_values(conf_keys, conf_values, gpg_conf());
   19.46  
   19.47          free_stringlist(conf_keys);
   19.48 @@ -247,6 +255,11 @@
   19.49              "gpgme_op_encrypt_sign");
   19.50          assert(gpg.gpgme_op_encrypt_sign);
   19.51  
   19.52 +        gpg.gpgme_op_encrypt
   19.53 +            = (gpgme_op_encrypt_t) (intptr_t) dlsym(gpgme,
   19.54 +            "gpgme_op_encrypt");
   19.55 +        assert(gpg.gpgme_op_encrypt);
   19.56 +
   19.57          gpg.gpgme_op_verify_result
   19.58              = (gpgme_op_verify_result_t) (intptr_t) dlsym(gpgme,
   19.59              "gpgme_op_verify_result");
   19.60 @@ -393,6 +406,7 @@
   19.61      gpgme_error_t gpgme_error;
   19.62      gpgme_data_t cipher, plain;
   19.63      gpgme_data_type_t dt;
   19.64 +    gpgme_decrypt_result_t gpgme_decrypt_result = NULL;
   19.65  
   19.66      stringlist_t *_keylist = NULL;
   19.67      //int i_key = 0;
   19.68 @@ -429,6 +443,7 @@
   19.69              return PEP_UNKNOWN_ERROR;
   19.70      }
   19.71  
   19.72 +
   19.73      dt = gpg.gpgme_data_identify(cipher);
   19.74      switch (dt) {
   19.75  #if GPGME_VERSION_NUMBER > 0x010600
   19.76 @@ -450,6 +465,57 @@
   19.77          switch (gpgme_error) {
   19.78              case GPG_ERR_NO_ERROR:
   19.79              {
   19.80 +                gpgme_decrypt_result = gpg.gpgme_op_decrypt_result(session->ctx);
   19.81 +                /* NOW is when we have to process the decrypt_result, period.
   19.82 +                   it is only valid until the next call on the context. */
   19.83 +                   
   19.84 +                gpgme_key_t key;
   19.85 +                memset(&key,0,sizeof(key));
   19.86 +                stringlist_t* recipient_keylist = new_stringlist(NULL);
   19.87 +                if (!recipient_keylist) {
   19.88 +                    gpg.gpgme_data_release(plain);
   19.89 +                    gpg.gpgme_data_release(cipher);
   19.90 +                    if (recipient_keylist)
   19.91 +                        free_stringlist(recipient_keylist);
   19.92 +                    return PEP_OUT_OF_MEMORY;
   19.93 +                }
   19.94 +               
   19.95 +                if (gpgme_decrypt_result != NULL) {
   19.96 +                    stringlist_t* _keylist = recipient_keylist;
   19.97 +                    for (gpgme_recipient_t r = gpgme_decrypt_result->recipients; r != NULL; r = r->next) {
   19.98 +                        // GPGME may give subkey's fpr instead of primary key's fpr.
   19.99 +                        // Therefore we ask for the primary fingerprint instead
  19.100 +                        // we assume that gpgme_get_key can find key by subkey's fpr
  19.101 +                        gpgme_error = gpg.gpgme_get_key(session->ctx,
  19.102 +                            r->keyid, &key, 0);
  19.103 +                        gpgme_error = _GPGERR(gpgme_error);
  19.104 +                        assert(gpgme_error != GPG_ERR_ENOMEM);
  19.105 +                        if (gpgme_error == GPG_ERR_ENOMEM) {
  19.106 +                            free_stringlist(_keylist);
  19.107 +                            result = PEP_OUT_OF_MEMORY;
  19.108 +                        }
  19.109 +                        // Primary key is given as the first subkey
  19.110 +                        if (gpgme_error == GPG_ERR_NO_ERROR &&
  19.111 +                            key && key->subkeys && key->subkeys->fpr
  19.112 +                            && key->subkeys->fpr[0]) {
  19.113 +                            _keylist = stringlist_add(_keylist, key->subkeys->fpr);
  19.114 + 
  19.115 +                            gpg.gpgme_key_unref(key);
  19.116 + 
  19.117 +                        }
  19.118 +                    }
  19.119 +                    assert(_keylist);
  19.120 +                    if (_keylist == NULL) {
  19.121 +                        free_stringlist(recipient_keylist);
  19.122 +                        if (*keylist)
  19.123 +                            free_stringlist(*keylist);
  19.124 +                        *keylist = NULL;
  19.125 +                        result = PEP_OUT_OF_MEMORY;
  19.126 +                    }
  19.127 +                } /* Ok, so now we have any recipients it was encrypted for
  19.128 +                     in recipient_keylist */
  19.129 +            
  19.130 +                   
  19.131                  gpgme_verify_result_t gpgme_verify_result;
  19.132                  char *_buffer = NULL;
  19.133                  size_t reading;
  19.134 @@ -468,6 +534,8 @@
  19.135                  if (_buffer == NULL) {
  19.136                      gpg.gpgme_data_release(plain);
  19.137                      gpg.gpgme_data_release(cipher);
  19.138 +                    if (recipient_keylist)
  19.139 +                        free_stringlist(recipient_keylist);
  19.140                      return PEP_OUT_OF_MEMORY;
  19.141                  }
  19.142  
  19.143 @@ -486,16 +554,15 @@
  19.144                      gpg.gpgme_op_verify_result(session->ctx);
  19.145                  assert(gpgme_verify_result);
  19.146                  gpgme_signature = gpgme_verify_result->signatures;
  19.147 -/*
  19.148 +
  19.149                  if (!gpgme_signature) {
  19.150                      // try cleartext sig verification
  19.151                      gpg.gpgme_op_verify(session->ctx, plain, NULL, plain);
  19.152                      gpgme_verify_result =
  19.153                          gpg.gpgme_op_verify_result(session->ctx);
  19.154 -                    assert(gpgme_verify_result);
  19.155 +                            assert(gpgme_verify_result);
  19.156                      gpgme_signature = gpgme_verify_result->signatures;                    
  19.157                  }
  19.158 -*/
  19.159  
  19.160                  if (gpgme_signature) {
  19.161                      stringlist_t *k;
  19.162 @@ -511,7 +578,8 @@
  19.163  
  19.164                      result = PEP_DECRYPTED_AND_VERIFIED;
  19.165                      gpg.gpgme_check(NULL);
  19.166 -                    do {
  19.167 +                    do { /* get all signers and put them at the front off
  19.168 +                            the keylist (likely only one) */
  19.169                          switch (_GPGERR(gpgme_signature->status)) {
  19.170                          case GPG_ERR_NO_ERROR:
  19.171                          {
  19.172 @@ -545,6 +613,8 @@
  19.173  
  19.174                                  if (k == NULL) {
  19.175                                      free_stringlist(_keylist);
  19.176 +                                    if (recipient_keylist)
  19.177 +                                        free (recipient_keylist);
  19.178                                      gpg.gpgme_data_release(plain);
  19.179                                      gpg.gpgme_data_release(cipher);
  19.180                                      free(_buffer);
  19.181 @@ -568,6 +638,8 @@
  19.182                              k = stringlist_add(k, gpgme_signature->fpr);
  19.183                              if (k == NULL) {
  19.184                                  free_stringlist(_keylist);
  19.185 +                                if (recipient_keylist)
  19.186 +                                    free_stringlist(recipient_keylist);
  19.187                                  gpg.gpgme_data_release(plain);
  19.188                                  gpg.gpgme_data_release(cipher);
  19.189                                  free(_buffer);
  19.190 @@ -595,9 +667,24 @@
  19.191                      *psize = reading;
  19.192                      (*ptext)[*psize] = 0; // safeguard for naive users
  19.193                      *keylist = _keylist;
  19.194 +                    if (recipient_keylist)
  19.195 +                        if (!_keylist)
  19.196 +                            *keylist = new_stringlist(""); // no sig 
  19.197 +                        if (!(*keylist)) {
  19.198 +                            free_stringlist(_keylist);
  19.199 +                            if (recipient_keylist)
  19.200 +                                free_stringlist(recipient_keylist);
  19.201 +                            gpg.gpgme_data_release(plain);
  19.202 +                            gpg.gpgme_data_release(cipher);
  19.203 +                            free(_buffer);
  19.204 +                            return PEP_OUT_OF_MEMORY;
  19.205 +                        }    
  19.206 +                        stringlist_append(*keylist, recipient_keylist);
  19.207                  }
  19.208                  else {
  19.209                      free_stringlist(_keylist);
  19.210 +                    if (recipient_keylist)
  19.211 +                        free_stringlist(recipient_keylist);
  19.212                      free(_buffer);
  19.213                  }
  19.214                  break;
  19.215 @@ -608,7 +695,7 @@
  19.216              case GPG_ERR_DECRYPT_FAILED:
  19.217              default:
  19.218              {
  19.219 -                gpgme_decrypt_result_t gpgme_decrypt_result = gpg.gpgme_op_decrypt_result(session->ctx);
  19.220 +                gpgme_decrypt_result = gpg.gpgme_op_decrypt_result(session->ctx);
  19.221                  result = PEP_DECRYPT_NO_KEY;
  19.222  
  19.223                  if (gpgme_decrypt_result != NULL) {
  19.224 @@ -621,19 +708,6 @@
  19.225                          result = PEP_OUT_OF_MEMORY;
  19.226                          break;
  19.227                      }
  19.228 -                    stringlist_t *_keylist = *keylist;
  19.229 -                    for (gpgme_recipient_t r = gpgme_decrypt_result->recipients; r != NULL; r = r->next) {
  19.230 -                        _keylist = stringlist_add(_keylist, r->keyid);
  19.231 -                        assert(_keylist);
  19.232 -                        if (_keylist == NULL) {
  19.233 -                            free_stringlist(*keylist);
  19.234 -                            *keylist = NULL;
  19.235 -                            result = PEP_OUT_OF_MEMORY;
  19.236 -                            break;
  19.237 -                        }
  19.238 -                    }
  19.239 -                    if (result == PEP_OUT_OF_MEMORY)
  19.240 -                        break;
  19.241                  }
  19.242              }
  19.243          }
  19.244 @@ -809,11 +883,12 @@
  19.245      return result;
  19.246  }
  19.247  
  19.248 -PEP_STATUS pgp_encrypt_and_sign(
  19.249 +
  19.250 +static PEP_STATUS pgp_encrypt_sign_optional(    
  19.251      PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  19.252 -    size_t psize, char **ctext, size_t *csize
  19.253 -    )
  19.254 -{
  19.255 +    size_t psize, char **ctext, size_t *csize, bool sign
  19.256 +)
  19.257 +{    
  19.258      PEP_STATUS result;
  19.259      gpgme_error_t gpgme_error;
  19.260      gpgme_data_t plain, cipher;
  19.261 @@ -879,7 +954,7 @@
  19.262              gpg.gpgme_data_release(cipher);
  19.263              return PEP_OUT_OF_MEMORY;
  19.264          case GPG_ERR_NO_ERROR:
  19.265 -            if (i == 0) {
  19.266 +            if (i == 0 && sign) {
  19.267                  gpgme_error_t _gpgme_error = gpg.gpgme_signers_add(session->ctx, rcpt[0]);
  19.268                  _gpgme_error = _GPGERR(_gpgme_error);
  19.269                  assert(_gpgme_error == GPG_ERR_NO_ERROR);
  19.270 @@ -912,9 +987,16 @@
  19.271  
  19.272      // TODO: remove that and replace with proper key management
  19.273      flags = GPGME_ENCRYPT_ALWAYS_TRUST;
  19.274 -
  19.275 -    gpgme_error = gpg.gpgme_op_encrypt_sign(session->ctx, rcpt, flags,
  19.276 -        plain, cipher);
  19.277 +    
  19.278 +    if (sign) {
  19.279 +        gpgme_error = gpg.gpgme_op_encrypt_sign(session->ctx, rcpt, flags,
  19.280 +            plain, cipher);
  19.281 +    }
  19.282 +    else {
  19.283 +        gpgme_error = gpg.gpgme_op_encrypt(session->ctx, rcpt, flags,
  19.284 +            plain, cipher);
  19.285 +    }
  19.286 +    
  19.287      gpgme_error = _GPGERR(gpgme_error);
  19.288      switch (gpgme_error) {
  19.289      case GPG_ERR_NO_ERROR:
  19.290 @@ -960,6 +1042,24 @@
  19.291      return result;
  19.292  }
  19.293  
  19.294 +PEP_STATUS pgp_encrypt_only(
  19.295 +    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  19.296 +    size_t psize, char **ctext, size_t *csize
  19.297 +    )
  19.298 +{
  19.299 +    return pgp_encrypt_sign_optional(session, keylist, ptext,
  19.300 +        psize, ctext, csize, false);
  19.301 +}
  19.302 +
  19.303 +PEP_STATUS pgp_encrypt_and_sign(
  19.304 +    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  19.305 +    size_t psize, char **ctext, size_t *csize
  19.306 +    )
  19.307 +{
  19.308 +    return pgp_encrypt_sign_optional(session, keylist, ptext,
  19.309 +        psize, ctext, csize, true);
  19.310 +}
  19.311 +
  19.312  PEP_STATUS pgp_generate_keypair(
  19.313      PEP_SESSION session, pEp_identity *identity
  19.314      )
  19.315 @@ -1257,6 +1357,8 @@
  19.316  
  19.317      reading = gpg.gpgme_data_read(dh, buffer, _size);
  19.318      assert(_size == reading);
  19.319 +    if(_size != reading)
  19.320 +        return PEP_CANNOT_EXPORT_KEY;
  19.321  
  19.322      // safeguard for the naive user
  19.323      buffer[_size] = 0;
  19.324 @@ -1452,7 +1554,6 @@
  19.325      gpgme_key_t key;
  19.326  
  19.327      assert(session);
  19.328 -    assert(pattern);
  19.329      assert(keylist);
  19.330  
  19.331      *keylist = NULL;
  19.332 @@ -1489,7 +1590,9 @@
  19.333                  gpgme_user_id_t kuid = key->uids;
  19.334                  // check that at least one uid's email matches pattern exactly
  19.335                  while(kuid) {
  19.336 -                    if(kuid->email && strcmp(kuid->email, pattern) == 0){
  19.337 +                    if((pattern && kuid->email && strcmp(kuid->email, pattern) == 0) ||
  19.338 +                       pattern == NULL /* match all */ )
  19.339 +                    { 
  19.340                          char *fpr = key->subkeys->fpr;
  19.341                          assert(fpr);
  19.342                          _k = stringlist_add(_k, fpr);
  19.343 @@ -1844,11 +1947,14 @@
  19.344      gpgme_error = gpg.gpgme_op_edit(session->ctx, key, renew_fsm, &handle,
  19.345              output);
  19.346      assert(gpgme_error == GPG_ERR_NO_ERROR);
  19.347 +    if(gpgme_error != GPG_ERR_NO_ERROR) {
  19.348 +        status = PEP_CANNOT_EDIT_KEY;
  19.349 +    }
  19.350  
  19.351      gpg.gpgme_data_release(output);
  19.352      gpg.gpgme_key_unref(key);
  19.353  
  19.354 -    return PEP_STATUS_OK;
  19.355 +    return status;
  19.356  }
  19.357  
  19.358  typedef struct _revoke_state {
  19.359 @@ -2031,11 +2137,14 @@
  19.360      gpgme_error = gpg.gpgme_op_edit(session->ctx, key, revoke_fsm, &handle,
  19.361              output);
  19.362      assert(gpgme_error == GPG_ERR_NO_ERROR);
  19.363 +    if(gpgme_error != GPG_ERR_NO_ERROR) {
  19.364 +        status = PEP_CANNOT_EDIT_KEY;
  19.365 +    }
  19.366  
  19.367      gpg.gpgme_data_release(output);
  19.368      gpg.gpgme_key_unref(key);
  19.369  
  19.370 -    return PEP_STATUS_OK;
  19.371 +    return status;
  19.372  }
  19.373  
  19.374  PEP_STATUS pgp_key_expired(
    20.1 --- a/src/pgp_gpg.h	Tue Jan 31 08:42:25 2017 +0100
    20.2 +++ b/src/pgp_gpg.h	Tue Jun 13 13:00:37 2017 +0200
    20.3 @@ -19,6 +19,12 @@
    20.4          size_t psize, char **ctext, size_t *csize
    20.5      );
    20.6  
    20.7 +PEP_STATUS pgp_encrypt_only(
    20.8 +        PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
    20.9 +        size_t psize, char **ctext, size_t *csize
   20.10 +    );
   20.11 +
   20.12 +
   20.13  PEP_STATUS pgp_verify_text(
   20.14          PEP_SESSION session, const char *text, size_t size,
   20.15          const char *signature, size_t sig_size, stringlist_t **keylist
   20.16 @@ -100,4 +106,3 @@
   20.17  
   20.18  PEP_STATUS pgp_binary(const char **path);
   20.19  #define PGP_BINARY_PATH pgp_binary
   20.20 -
    21.1 --- a/src/pgp_gpg_internal.h	Tue Jan 31 08:42:25 2017 +0100
    21.2 +++ b/src/pgp_gpg_internal.h	Tue Jun 13 13:00:37 2017 +0200
    21.3 @@ -43,6 +43,9 @@
    21.4  typedef gpgme_error_t(*gpgme_op_encrypt_sign_t)(gpgme_ctx_t CTX,
    21.5      gpgme_key_t RECP[], gpgme_encrypt_flags_t FLAGS, gpgme_data_t PLAIN,
    21.6      gpgme_data_t CIPHER);
    21.7 +typedef gpgme_error_t(*gpgme_op_encrypt_t)(gpgme_ctx_t CTX,
    21.8 +        gpgme_key_t RECP[], gpgme_encrypt_flags_t FLAGS, gpgme_data_t PLAIN,
    21.9 +        gpgme_data_t CIPHER);
   21.10  typedef gpgme_verify_result_t(*gpgme_op_verify_result_t)(gpgme_ctx_t CTX);
   21.11  typedef void(*gpgme_signers_clear_t)(gpgme_ctx_t CTX);
   21.12  typedef gpgme_error_t(*gpgme_signers_add_t)(gpgme_ctx_t CTX, const gpgme_key_t KEY);
   21.13 @@ -102,6 +105,7 @@
   21.14      gpgme_op_decrypt_verify_t gpgme_op_decrypt_verify;
   21.15      gpgme_op_decrypt_result_t gpgme_op_decrypt_result;
   21.16      gpgme_op_encrypt_sign_t gpgme_op_encrypt_sign;
   21.17 +    gpgme_op_encrypt_t gpgme_op_encrypt;
   21.18      gpgme_op_verify_result_t gpgme_op_verify_result;
   21.19      gpgme_signers_clear_t gpgme_signers_clear;
   21.20      gpgme_signers_add_t gpgme_signers_add;
   21.21 @@ -125,4 +129,3 @@
   21.22      gpgme_op_edit_t gpgme_op_edit;
   21.23      gpgme_io_write_t gpgme_io_write;
   21.24  };
   21.25 -
    22.1 --- a/src/pgp_netpgp.c	Tue Jan 31 08:42:25 2017 +0100
    22.2 +++ b/src/pgp_netpgp.c	Tue Jun 13 13:00:37 2017 +0200
    22.3 @@ -227,7 +227,7 @@
    22.4          return 0;
    22.5  
    22.6      for (n = 0, i = 0 ; i < length; i += 2) {
    22.7 -        n += snprintf(&((*str)[n]), 5, "%02x%02x", fpr[i], fpr[i+1]);
    22.8 +        n += snprintf(&((*str)[n]), 5, "%02X%02X", fpr[i], fpr[i+1]);
    22.9      }
   22.10  
   22.11      return 1;
   22.12 @@ -241,6 +241,9 @@
   22.13      unsigned i,j;
   22.14  
   22.15      *length = 0;
   22.16 +    
   22.17 +    if (str == NULL)
   22.18 +        return 0;
   22.19  
   22.20      while(*str && *length < PGP_FINGERPRINT_SIZE){
   22.21          while (*str == ' ') str++;
   22.22 @@ -273,12 +276,14 @@
   22.23  static PEP_STATUS _validation_results(
   22.24          netpgp_t *netpgp,
   22.25          pgp_validation_t *vresult,
   22.26 -        stringlist_t **_keylist
   22.27 +        stringlist_t **keylist
   22.28      )
   22.29  {
   22.30      time_t    now;
   22.31      time_t    t;
   22.32  
   22.33 +    *keylist = NULL;
   22.34 +
   22.35      now = time(NULL);
   22.36      if (now < vresult->birthtime) {
   22.37          // signature is not valid yet
   22.38 @@ -292,14 +297,17 @@
   22.39      if (vresult->validc && vresult->valid_sigs &&
   22.40          !vresult->invalidc && !vresult->unknownc ) {
   22.41          
   22.42 +        stringlist_t *_keylist;
   22.43 +
   22.44          // caller responsible to free
   22.45 -        *_keylist = new_stringlist(NULL);
   22.46 -        assert(*_keylist);
   22.47 -        if (*_keylist == NULL) {
   22.48 +        _keylist = new_stringlist(NULL);
   22.49 +        assert(_keylist);
   22.50 +        if (_keylist == NULL) {
   22.51              return PEP_OUT_OF_MEMORY;
   22.52          }
   22.53          
   22.54 -        stringlist_t *k = *_keylist;
   22.55 +        stringlist_t *k = _keylist;
   22.56 +        unsigned c = 0;
   22.57          for (unsigned n = 0; n < vresult->validc; ++n) {
   22.58              unsigned from = 0;
   22.59              const pgp_key_t	 *signer;
   22.60 @@ -315,21 +323,31 @@
   22.61                             signer->pubkeyfpr.fingerprint,
   22.62                             signer->pubkeyfpr.length);
   22.63              else
   22.64 -                return PEP_VERIFY_NO_KEY;
   22.65 +                continue;
   22.66  
   22.67 -            if (fprstr == NULL)
   22.68 +            if (fprstr == NULL){
   22.69 +                free_stringlist(_keylist);
   22.70                  return PEP_OUT_OF_MEMORY;
   22.71 +            }
   22.72  
   22.73              k = stringlist_add(k, fprstr);
   22.74  
   22.75              free(fprstr);
   22.76  
   22.77              if(!k){
   22.78 -                free_stringlist(*_keylist);
   22.79 +                free_stringlist(_keylist);
   22.80                  return PEP_OUT_OF_MEMORY;
   22.81              }
   22.82 +
   22.83 +            c++;
   22.84          }
   22.85 -        return PEP_STATUS_OK;
   22.86 +        if(c > 0) {
   22.87 +            *keylist = _keylist;
   22.88 +            return PEP_STATUS_OK;
   22.89 +        }
   22.90 +
   22.91 +        free_stringlist(_keylist);
   22.92 +        return PEP_VERIFY_NO_KEY;
   22.93      }
   22.94      if (vresult->validc + vresult->invalidc + vresult->unknownc == 0) {
   22.95          // No signatures found - is this memory signed?
   22.96 @@ -379,11 +397,14 @@
   22.97      pgp_validation_t *vresult = malloc(sizeof(pgp_validation_t));
   22.98      memset(vresult, 0x0, sizeof(pgp_validation_t));
   22.99  
  22.100 +    key_id_t *recipients_key_ids = NULL;
  22.101 +    unsigned recipients_count = 0;
  22.102 +
  22.103      pgp_memory_t *mem = pgp_decrypt_and_validate_buf(netpgp.io, vresult, ctext, csize,
  22.104                  netpgp.secring, netpgp.pubring,
  22.105                  _armoured(ctext, csize, ARMOR_HEAD),
  22.106 -                0 /* sshkeys */,
  22.107 -                NULL, -1, NULL  /* pass fp,attempts,cb */);
  22.108 +                 &recipients_key_ids, &recipients_count);
  22.109 +
  22.110      if (mem == NULL) {
  22.111          result = PEP_OUT_OF_MEMORY;
  22.112          goto unlock_netpgp;
  22.113 @@ -405,9 +426,12 @@
  22.114  
  22.115      if (result == PEP_DECRYPTED) {
  22.116          result = _validation_results(&netpgp, vresult, &_keylist);
  22.117 -        if (result == PEP_DECRYPTED) {
  22.118 -            //no change
  22.119 -        } else if (result == PEP_VERIFY_NO_KEY) {
  22.120 +        if (result == PEP_DECRYPTED ||
  22.121 +            result == PEP_VERIFY_NO_KEY) {
  22.122 +            if((_keylist = new_stringlist("")) == NULL) {
  22.123 +                result = PEP_OUT_OF_MEMORY;
  22.124 +                goto free_ptext;
  22.125 +            }
  22.126              result = PEP_DECRYPTED;
  22.127          }else if (result != PEP_STATUS_OK) {
  22.128              goto free_ptext;
  22.129 @@ -416,14 +440,47 @@
  22.130          }
  22.131      }
  22.132  
  22.133 +    stringlist_t *k = _keylist;
  22.134 +    for (unsigned n = 0; n < recipients_count; ++n) {
  22.135 +        unsigned from = 0;
  22.136 +        const pgp_key_t	 *rcpt;
  22.137 +        char *fprstr = NULL;
  22.138 +        key_id_t *keyid = &recipients_key_ids[n];
  22.139 +
  22.140 +        rcpt = pgp_getkeybyid(netpgp.io, netpgp.pubring,
  22.141 +                                *keyid, &from, NULL, NULL,
  22.142 +                                0, 0); /* check neither revocation nor expiry*/
  22.143 +        if(rcpt)
  22.144 +            fpr_to_str(&fprstr,
  22.145 +                       rcpt->pubkeyfpr.fingerprint,
  22.146 +                       rcpt->pubkeyfpr.length);
  22.147 +        else
  22.148 +            // if no key found put ID instead of fpr
  22.149 +            fpr_to_str(&fprstr,
  22.150 +                       *keyid,
  22.151 +                       sizeof(key_id_t));
  22.152 +
  22.153 +        if (fprstr == NULL){
  22.154 +            result = PEP_OUT_OF_MEMORY;
  22.155 +            goto free_keylist;
  22.156 +        }
  22.157 +
  22.158 +        k = stringlist_add_unique(k, fprstr);
  22.159 +
  22.160 +        free(fprstr);
  22.161 +
  22.162 +        if(!k){
  22.163 +            result = PEP_OUT_OF_MEMORY;
  22.164 +            goto free_keylist;
  22.165 +        }
  22.166 +    }
  22.167 +
  22.168      if (result == PEP_DECRYPTED_AND_VERIFIED
  22.169          || result == PEP_DECRYPTED) {
  22.170          *ptext = _ptext;
  22.171          *psize = _psize;
  22.172          (*ptext)[*psize] = 0; // safeguard for naive users
  22.173 -        if (result == PEP_DECRYPTED_AND_VERIFIED) {
  22.174 -            *keylist = _keylist;
  22.175 -        }
  22.176 +        *keylist = _keylist;
  22.177  
  22.178          /* _ptext and _keylist ownership transfer, don't free */
  22.179          goto free_pgp;
  22.180 @@ -521,7 +578,6 @@
  22.181          goto free_pgp;
  22.182      }
  22.183  
  22.184 -free_keylist:
  22.185      free_stringlist(_keylist);
  22.186  
  22.187  free_pgp:
  22.188 @@ -536,14 +592,14 @@
  22.189      return result;
  22.190  }
  22.191  
  22.192 -PEP_STATUS pgp_encrypt_and_sign(
  22.193 +static PEP_STATUS _encrypt_and_sign(
  22.194      PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  22.195 -    size_t psize, char **ctext, size_t *csize
  22.196 +    size_t psize, char **ctext, size_t *csize, bool do_sign
  22.197      )
  22.198  {
  22.199      pgp_key_t *signer = NULL;
  22.200      pgp_seckey_t *seckey = NULL;
  22.201 -    pgp_memory_t *signedmem;
  22.202 +    pgp_memory_t *signedmem = NULL;
  22.203      pgp_memory_t *cmem;
  22.204      const char *hashalg;
  22.205      pgp_keyring_t *rcpts;
  22.206 @@ -631,25 +687,38 @@
  22.207  
  22.208      hashalg = netpgp_getvar(&netpgp, "hash");
  22.209  
  22.210 -    // Sign data
  22.211 -    signedmem = pgp_sign_buf(netpgp.io, ptext, psize, seckey,
  22.212 -                time(NULL), /* birthtime */
  22.213 -                0 /* duration */,
  22.214 -                hashalg,
  22.215 -                0 /* armored */,
  22.216 -                0 /* cleartext */);
  22.217 +    const char *stext;
  22.218 +    size_t ssize;
  22.219 +    unsigned encrypt_raw_packet;
  22.220 +   
  22.221 +    if (do_sign) {  
  22.222 +        // Sign data
  22.223 +        signedmem = pgp_sign_buf(netpgp.io, ptext, psize, seckey,
  22.224 +                    time(NULL), /* birthtime */
  22.225 +                    0 /* duration */,
  22.226 +                    hashalg,
  22.227 +                    0 /* armored */,
  22.228 +                    0 /* cleartext */);
  22.229  
  22.230 -    if (!signedmem) {
  22.231 -        result = PEP_UNENCRYPTED;
  22.232 -        goto free_rcpts;
  22.233 +        if (!signedmem) {
  22.234 +            result = PEP_UNENCRYPTED;
  22.235 +            goto free_rcpts;
  22.236 +        }
  22.237 +        stext = (char*) pgp_mem_data(signedmem);
  22.238 +        ssize = pgp_mem_len(signedmem);
  22.239 +        encrypt_raw_packet = 1 /* takes raw OpenPGP message */;
  22.240 +    } else {
  22.241 +        stext = ptext;
  22.242 +        ssize = psize;
  22.243 +        encrypt_raw_packet = 0 /* not a raw OpenPGP message */;
  22.244      }
  22.245  
  22.246 -    // Encrypt signed data
  22.247 +    // Encrypt (maybe) signed data
  22.248  
  22.249 -    cmem = pgp_encrypt_buf(netpgp.io, pgp_mem_data(signedmem),
  22.250 -            pgp_mem_len(signedmem), rcpts, 1 /* armored */,
  22.251 +    cmem = pgp_encrypt_buf(netpgp.io, stext,
  22.252 +            ssize, rcpts, 1 /* armored */,
  22.253              netpgp_getvar(&netpgp, "cipher"),
  22.254 -            1 /* takes raw OpenPGP message */);
  22.255 +            encrypt_raw_packet);
  22.256  
  22.257      if (cmem == NULL) {
  22.258          result = PEP_OUT_OF_MEMORY;
  22.259 @@ -678,7 +747,9 @@
  22.260  free_cmem :
  22.261      pgp_memory_free(cmem);
  22.262  free_signedmem :
  22.263 -    pgp_memory_free(signedmem);
  22.264 +    if (do_sign) {
  22.265 +        pgp_memory_free(signedmem);
  22.266 +    }
  22.267  free_rcpts :
  22.268      pgp_keyring_free(rcpts);
  22.269  unlock_netpgp:
  22.270 @@ -687,6 +758,29 @@
  22.271      return result;
  22.272  }
  22.273  
  22.274 +PEP_STATUS pgp_encrypt_and_sign(
  22.275 +    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  22.276 +    size_t psize, char **ctext, size_t *csize
  22.277 +    )
  22.278 +{
  22.279 +    PEP_STATUS result;
  22.280 +    result = _encrypt_and_sign(session, keylist, ptext, psize, ctext, csize,
  22.281 +                               true);
  22.282 +    return result;
  22.283 +}
  22.284 +
  22.285 +PEP_STATUS pgp_encrypt_only(
  22.286 +        PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  22.287 +        size_t psize, char **ctext, size_t *csize
  22.288 +    )
  22.289 +{
  22.290 +    PEP_STATUS result;
  22.291 +    result = _encrypt_and_sign(session, keylist, ptext, psize, ctext, csize,
  22.292 +                               false);
  22.293 +    return result;
  22.294 +}
  22.295 +
  22.296 +
  22.297  PEP_STATUS pgp_generate_keypair(
  22.298      PEP_SESSION session, pEp_identity *identity
  22.299      )
  22.300 @@ -857,7 +951,8 @@
  22.301  PEP_STATUS pgp_import_keydata(
  22.302          PEP_SESSION session,
  22.303          const char *key_data,
  22.304 -        size_t size
  22.305 +        size_t size,
  22.306 +        identity_list **private_idents
  22.307      )
  22.308  {
  22.309      pgp_memory_t *mem;
  22.310 @@ -867,6 +962,11 @@
  22.311      assert(session);
  22.312      assert(key_data);
  22.313  
  22.314 +    // reporting imported private keys not supported
  22.315 +    // stub code to be reomoved
  22.316 +    if(private_idents)
  22.317 +        *private_idents = NULL;
  22.318 +
  22.319      if(!session || !key_data)
  22.320          return PEP_ILLEGAL_VALUE;
  22.321  
  22.322 @@ -947,7 +1047,8 @@
  22.323  }
  22.324  
  22.325  PEP_STATUS pgp_export_keydata(
  22.326 -    PEP_SESSION session, const char *fprstr, char **key_data, size_t *size
  22.327 +    PEP_SESSION session, const char *fprstr, char **key_data, size_t *size,
  22.328 +    bool secret
  22.329      )
  22.330  {
  22.331      pgp_key_t *key;
  22.332 @@ -957,12 +1058,18 @@
  22.333      PEP_STATUS result;
  22.334      char *buffer;
  22.335      size_t buflen;
  22.336 +    const pgp_keyring_t *srcring;
  22.337  
  22.338      assert(session);
  22.339      assert(fprstr);
  22.340      assert(key_data);
  22.341      assert(size);
  22.342  
  22.343 +    if (secret)
  22.344 +        srcring = netpgp.secring;
  22.345 +    else
  22.346 +        srcring = netpgp.pubring;
  22.347 +    
  22.348      if (!session || !fprstr || !key_data || !size)
  22.349          return PEP_ILLEGAL_VALUE;
  22.350  
  22.351 @@ -973,7 +1080,7 @@
  22.352      if (str_to_fpr(fprstr, fpr, &fprlen)) {
  22.353          unsigned from = 0;
  22.354  
  22.355 -        if ((key = (pgp_key_t *)pgp_getkeybyfpr(netpgp.io, netpgp.pubring,
  22.356 +        if ((key = (pgp_key_t *)pgp_getkeybyfpr(netpgp.io, srcring,
  22.357                                                  fpr, fprlen, &from,
  22.358                                                  NULL,0,0)) == NULL) {
  22.359              result = PEP_KEY_NOT_FOUND;
  22.360 @@ -1091,9 +1198,9 @@
  22.361  
  22.362      result = pgp_import_keydata(session,
  22.363                                  answer.memory,
  22.364 -                                answer.size);
  22.365 +                                answer.size,
  22.366 +                                NULL);
  22.367  
  22.368 -free_answer:
  22.369      free(answer.memory);
  22.370  free_request:
  22.371      free(request);
  22.372 @@ -1109,7 +1216,7 @@
  22.373  
  22.374  typedef PEP_STATUS (*find_key_cb_t)(void*, pgp_key_t *);
  22.375  
  22.376 -static PEP_STATUS find_keys_do(
  22.377 +static PEP_STATUS find_keys_do(pgp_keyring_t* keyring,
  22.378          const char *pattern, find_key_cb_t cb, void* cb_arg)
  22.379  {
  22.380      uint8_t fpr[PGP_FINGERPRINT_SIZE];
  22.381 @@ -1126,7 +1233,7 @@
  22.382          // Only one fingerprint can match
  22.383          if ((key = (pgp_key_t *)pgp_getkeybyfpr(
  22.384                          netpgp.io,
  22.385 -                        (pgp_keyring_t *)netpgp.pubring,
  22.386 +                        keyring,
  22.387                          (const uint8_t *)fpr, length,
  22.388                          &from,
  22.389                          NULL, 0, 0)) == NULL) {
  22.390 @@ -1142,7 +1249,7 @@
  22.391          result = PEP_KEY_NOT_FOUND;
  22.392          while((key = (pgp_key_t *)pgp_getnextkeybyname(
  22.393                          netpgp.io,
  22.394 -                        (pgp_keyring_t *)netpgp.pubring,
  22.395 +                        keyring,
  22.396  			            (const char *)pattern,
  22.397                          &from)) != NULL) {
  22.398  
  22.399 @@ -1261,7 +1368,8 @@
  22.400      }
  22.401      _k = _keylist;
  22.402  
  22.403 -    result = find_keys_do(pattern, &add_key_fpr_to_stringlist, &_k);
  22.404 +    result = find_keys_do((pgp_keyring_t *)netpgp.pubring,
  22.405 +                          pattern, &add_key_fpr_to_stringlist, &_k);
  22.406  
  22.407      if (result == PEP_STATUS_OK) {
  22.408          *keylist = _keylist;
  22.409 @@ -1269,7 +1377,6 @@
  22.410          goto unlock_netpgp;
  22.411      }
  22.412  
  22.413 -free_keylist:
  22.414      free_stringlist(_keylist);
  22.415  
  22.416  unlock_netpgp:
  22.417 @@ -1350,7 +1457,8 @@
  22.418          goto free_encoded_keys;
  22.419      }
  22.420  
  22.421 -    result = find_keys_do(pattern, &send_key_cb, (void*)encoded_keys);
  22.422 +    result = find_keys_do((pgp_keyring_t *)netpgp.pubring,
  22.423 +                          pattern, &send_key_cb, (void*)encoded_keys);
  22.424  
  22.425      pthread_mutex_unlock(&netpgp_mutex);
  22.426  
  22.427 @@ -1770,12 +1878,12 @@
  22.428  
  22.429      PEP_STATUS result;
  22.430  
  22.431 -    result = find_keys_do(pattern, &add_keyinfo_to_stringpair_list, (void*)keyinfo_list);
  22.432 +    result = find_keys_do((pgp_keyring_t *)netpgp.pubring,
  22.433 +                          pattern, &add_keyinfo_to_stringpair_list, (void*)keyinfo_list);
  22.434  
  22.435      if (!keyinfo_list)
  22.436          result = PEP_KEY_NOT_FOUND;
  22.437  
  22.438 -unlock_netpgp:
  22.439      pthread_mutex_unlock(&netpgp_mutex);
  22.440  
  22.441      return result;
  22.442 @@ -1790,10 +1898,9 @@
  22.443      PEP_STATUS result;
  22.444  
  22.445      assert(session);
  22.446 -    assert(pattern);
  22.447      assert(keylist);
  22.448  
  22.449 -    if (!session || !pattern || !keylist )
  22.450 +    if (!session || !keylist )
  22.451      {
  22.452          return PEP_ILLEGAL_VALUE;
  22.453      }
  22.454 @@ -1811,7 +1918,8 @@
  22.455      }
  22.456      _k = _keylist;
  22.457  
  22.458 -    result = find_keys_do(pattern, &add_secret_key_fpr_to_stringlist, &_k);
  22.459 +    result = find_keys_do((pgp_keyring_t *)netpgp.secring,
  22.460 +                          pattern, &add_secret_key_fpr_to_stringlist, &_k);
  22.461  
  22.462      if (result == PEP_STATUS_OK) {
  22.463          *keylist = _keylist;
  22.464 @@ -1819,7 +1927,6 @@
  22.465          goto unlock_netpgp;
  22.466      }
  22.467  
  22.468 -free_keylist:
  22.469      free_stringlist(_keylist);
  22.470  
  22.471  unlock_netpgp:
    23.1 --- a/src/pgp_netpgp.h	Tue Jan 31 08:42:25 2017 +0100
    23.2 +++ b/src/pgp_netpgp.h	Tue Jun 13 13:00:37 2017 +0200
    23.3 @@ -1,5 +1,4 @@
    23.4  // This file is under GNU General Public License 3.0
    23.5 -// see LICENSE.txt
    23.6  
    23.7  #pragma once
    23.8  
    23.9 @@ -19,6 +18,13 @@
   23.10          size_t psize, char **ctext, size_t *csize
   23.11      );
   23.12  
   23.13 +
   23.14 +PEP_STATUS pgp_encrypt_only(
   23.15 +        PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
   23.16 +        size_t psize, char **ctext, size_t *csize
   23.17 +    );
   23.18 +
   23.19 +
   23.20  PEP_STATUS pgp_verify_text(
   23.21          PEP_SESSION session, const char *text, size_t size,
   23.22          const char *signature, size_t sig_size, stringlist_t **keylist
   23.23 @@ -27,7 +33,8 @@
   23.24  PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fpr);
   23.25  
   23.26  PEP_STATUS pgp_export_keydata(
   23.27 -        PEP_SESSION session, const char *fpr, char **key_data, size_t *size
   23.28 +        PEP_SESSION session, const char *fpr, char **key_data, size_t *size,
   23.29 +        bool secret
   23.30      );
   23.31  
   23.32  PEP_STATUS pgp_find_keys(
   23.33 @@ -49,7 +56,7 @@
   23.34      );
   23.35  
   23.36  PEP_STATUS pgp_import_keydata(PEP_SESSION session, const char *key_data,
   23.37 -        size_t size);
   23.38 +        size_t size, identity_list **private_idents);
   23.39  
   23.40  PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern);
   23.41  PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern);
    24.1 --- a/src/platform_windows.cpp	Tue Jan 31 08:42:25 2017 +0100
    24.2 +++ b/src/platform_windows.cpp	Tue Jun 13 13:00:37 2017 +0200
    24.3 @@ -139,9 +139,15 @@
    24.4      assert(filename);
    24.5  	assert(flag == RTLD_LAZY); // only lazy binding is implemented
    24.6  
    24.7 -    bool result = readRegistryString(HKEY_LOCAL_MACHINE,
    24.8 -            TEXT("SOFTWARE\\GNU\\GnuPG"), TEXT("Install Directory"), path,
    24.9 -            PATH_BUF_SIZE, NULL);
   24.10 +	// Look up GnuPG installation in current user scope
   24.11 +	bool result = readRegistryString(HKEY_CURRENT_USER,
   24.12 +		TEXT("SOFTWARE\\GNU\\GnuPG"), TEXT("Install Directory"), path,
   24.13 +		PATH_BUF_SIZE, NULL);
   24.14 +	// If not found in current user, look up in local machine
   24.15 +	if (!result)
   24.16 +		result = readRegistryString(HKEY_LOCAL_MACHINE,
   24.17 +			TEXT("SOFTWARE\\GNU\\GnuPG"), TEXT("Install Directory"), path,
   24.18 +			PATH_BUF_SIZE, NULL);
   24.19  	assert(result);
   24.20  	if (!result)
   24.21  		return NULL;
    25.1 --- a/src/stringlist.c	Tue Jan 31 08:42:25 2017 +0100
    25.2 +++ b/src/stringlist.c	Tue Jun 13 13:00:37 2017 +0200
    25.3 @@ -53,6 +53,39 @@
    25.4      return dst;
    25.5  }
    25.6  
    25.7 +static bool _stringlist_add_first(
    25.8 +        stringlist_t *stringlist,
    25.9 +        stringlist_t **result,
   25.10 +        const char *value
   25.11 +    )
   25.12 +{  
   25.13 +    // empty list (no nodes)
   25.14 +    if (stringlist == NULL) {
   25.15 +        *result = new_stringlist(value);
   25.16 +        return true;
   25.17 +    }
   25.18 +
   25.19 +    // empty list (one node, no value)
   25.20 +    if (stringlist->value == NULL) {
   25.21 +        if (stringlist->next) {
   25.22 +            *result = NULL; // invalid list
   25.23 +            return true;
   25.24 +        } 
   25.25 +            
   25.26 +        stringlist->value = strdup(value);
   25.27 +        assert(stringlist->value);
   25.28 +        
   25.29 +        if (stringlist->value == NULL) {
   25.30 +            *result = NULL;
   25.31 +            return true;
   25.32 +        }
   25.33 +        
   25.34 +        *result = stringlist;
   25.35 +        return true;
   25.36 +    }
   25.37 +    return false;
   25.38 +}
   25.39 +
   25.40  DYNAMIC_API stringlist_t *stringlist_add(
   25.41          stringlist_t *stringlist,
   25.42          const char *value
   25.43 @@ -62,23 +95,9 @@
   25.44      if (value == NULL)
   25.45          return NULL;
   25.46  
   25.47 -    // empty list (no nodes)
   25.48 -    if (stringlist == NULL)
   25.49 -        return new_stringlist(value);
   25.50 -
   25.51 -    // empty list (one node, no value)
   25.52 -    if (stringlist->value == NULL) {
   25.53 -        if (stringlist->next) 
   25.54 -            return NULL; // invalid list
   25.55 -            
   25.56 -        stringlist->value = strdup(value);
   25.57 -        assert(stringlist->value);
   25.58 -        
   25.59 -        if (stringlist->value == NULL)
   25.60 -            return NULL;
   25.61 -        
   25.62 -        return stringlist;
   25.63 -    }
   25.64 +    stringlist_t *result = NULL;
   25.65 +    if(_stringlist_add_first(stringlist, &result, value))
   25.66 +        return result;
   25.67      
   25.68      stringlist_t* list_curr = stringlist;
   25.69  
   25.70 @@ -94,6 +113,42 @@
   25.71      return list_curr->next;
   25.72  }
   25.73  
   25.74 +DYNAMIC_API stringlist_t *stringlist_add_unique(
   25.75 +        stringlist_t *stringlist,
   25.76 +        const char *value
   25.77 +    )
   25.78 +{  
   25.79 +    assert(value);
   25.80 +    if (value == NULL)
   25.81 +        return NULL;
   25.82 +
   25.83 +    stringlist_t *result = NULL;
   25.84 +    if(_stringlist_add_first(stringlist, &result, value))
   25.85 +        return result;
   25.86 +    
   25.87 +    stringlist_t* list_curr = stringlist;
   25.88 +
   25.89 +    bool found = false;
   25.90 +    while (list_curr->next) {
   25.91 +        if(strcmp(list_curr->value,value)==0)
   25.92 +            found = true;
   25.93 +        list_curr = list_curr->next;
   25.94 +    }
   25.95 +     
   25.96 +    if (!found) {
   25.97 +        list_curr->next = new_stringlist(value);
   25.98 +
   25.99 +        assert(list_curr->next);
  25.100 +        if (list_curr->next == NULL)
  25.101 +            return NULL;
  25.102 +
  25.103 +        return list_curr->next;
  25.104 +    } else {
  25.105 +        return list_curr;
  25.106 +    }
  25.107 +}
  25.108 +
  25.109 +
  25.110  DYNAMIC_API stringlist_t *stringlist_append(
  25.111          stringlist_t *stringlist,
  25.112          stringlist_t *second
  25.113 @@ -163,13 +218,13 @@
  25.114  
  25.115  DYNAMIC_API void free_stringlist(stringlist_t *stringlist)
  25.116  {
  25.117 -    stringlist_t *curr = stringlist;;
  25.118 +    stringlist_t *curr = stringlist;
  25.119      
  25.120      while (curr) {
  25.121          stringlist_t *next = curr->next;
  25.122          free(curr->value);
  25.123 +        curr->value = NULL;
  25.124          free(curr);
  25.125          curr = next;
  25.126      }
  25.127  }
  25.128 -
    26.1 --- a/src/stringlist.h	Tue Jan 31 08:42:25 2017 +0100
    26.2 +++ b/src/stringlist.h	Tue Jun 13 13:00:37 2017 +0200
    26.3 @@ -61,6 +61,24 @@
    26.4          const char *value
    26.5      );
    26.6  
    26.7 +// stringlist_add_unique() - add string to stringlist, if not already there
    26.8 +//
    26.9 +//  parameters:
   26.10 +//      stringlist (in)     stringlist struct or NULL to create a new one
   26.11 +//      value (in)          value as C string
   26.12 +//
   26.13 +//  return value:
   26.14 +//      pointer to last element in stringlist or NULL if out of memory
   26.15 +//
   26.16 +//  caveat:
   26.17 +//      the value is being copied before being added to the list
   26.18 +//      the original string is still being owned by the caller
   26.19 +
   26.20 +DYNAMIC_API stringlist_t *stringlist_add_unique(
   26.21 +        stringlist_t *stringlist,
   26.22 +        const char *value
   26.23 +    );
   26.24 +
   26.25  
   26.26  // stringlist_append() - append stringlist to stringlist
   26.27  //
    27.1 --- a/src/sync.c	Tue Jan 31 08:42:25 2017 +0100
    27.2 +++ b/src/sync.c	Tue Jun 13 13:00:37 2017 +0200
    27.3 @@ -59,32 +59,36 @@
    27.4      if (!(session && sync_session && sync_session->sync_management && sync_session->inject_sync_msg ))
    27.5          return PEP_ILLEGAL_VALUE;
    27.6  
    27.7 -    memcpy(session->sync_uuid, sync_session->sync_uuid, 37);
    27.8 +    session->sync_session = sync_session;
    27.9 +    // memcpy(session->sync_uuid, sync_session->sync_uuid, 37);
   27.10  
   27.11 -    session->sync_management = sync_session->sync_management;
   27.12 -    session->inject_sync_msg = sync_session->inject_sync_msg;
   27.13 +    // session->sync_management = sync_session->sync_management;
   27.14 +    // session->inject_sync_msg = sync_session->inject_sync_msg;
   27.15  
   27.16      return PEP_STATUS_OK;
   27.17  }
   27.18  
   27.19  DYNAMIC_API PEP_STATUS detach_sync_session(PEP_SESSION session)
   27.20  {
   27.21 -    assert(session && session->sync_management && session->inject_sync_msg );
   27.22 -    if (!(session && session->sync_management && session->inject_sync_msg ))
   27.23 +    assert(session);
   27.24 +    if (!(session))
   27.25          return PEP_ILLEGAL_VALUE;
   27.26  
   27.27 -    memset(session->sync_uuid, 0, 37);
   27.28 +    session->sync_session = session;
   27.29 +    // memset(session->sync_uuid, 0, 37);
   27.30  
   27.31 -    session->sync_management = NULL;
   27.32 -    session->inject_sync_msg = NULL;
   27.33 +    // session->sync_management = NULL;
   27.34 +    // session->inject_sync_msg = NULL;
   27.35  
   27.36      return PEP_STATUS_OK;
   27.37  }
   27.38  
   27.39  int call_inject_sync_msg(PEP_SESSION session, void *msg)
   27.40  {
   27.41 -    if(session->inject_sync_msg && session->sync_management)
   27.42 -        return session->inject_sync_msg(msg, session->sync_management);
   27.43 +    if(session->sync_session->inject_sync_msg &&
   27.44 +       session->sync_session->sync_management)
   27.45 +        return session->sync_session->inject_sync_msg(msg, 
   27.46 +            session->sync_session->sync_management);
   27.47      else
   27.48         return PEP_SYNC_NO_INJECT_CALLBACK;
   27.49  }
   27.50 @@ -181,13 +185,16 @@
   27.51              continue;
   27.52  #endif
   27.53          }
   27.54 -        else if ((status = receive_sync_msg(session, msg, &timeout) != PEP_STATUS_OK)) {
   27.55 +        else {
   27.56 +            status = receive_sync_msg(session, msg, &timeout);
   27.57 +            if (status != PEP_STATUS_OK && status != PEP_MESSAGE_IGNORE) {
   27.58  #ifndef NDEBUG
   27.59 -            char buffer[MAX_LINELENGTH];
   27.60 -            memset(buffer, 0, MAX_LINELENGTH);
   27.61 -            snprintf(buffer, MAX_LINELENGTH, "problem with msg received: %d\n", (int) status);
   27.62 -            log_event(session, buffer, "pEp sync protocol", NULL, NULL);
   27.63 +                char buffer[MAX_LINELENGTH];
   27.64 +                memset(buffer, 0, MAX_LINELENGTH);
   27.65 +                snprintf(buffer, MAX_LINELENGTH, "problem with msg received: %d\n", (int) status);
   27.66 +                log_event(session, buffer, "pEp sync protocol", NULL, NULL);
   27.67  #endif
   27.68 +            }
   27.69          }
   27.70      }
   27.71  
    28.1 --- a/src/sync.h	Tue Jan 31 08:42:25 2017 +0100
    28.2 +++ b/src/sync.h	Tue Jun 13 13:00:37 2017 +0200
    28.3 @@ -160,6 +160,13 @@
    28.4          App displays trustwords, and requests user accept or reject
    28.5          App calls deliverHandshakeResult with user's answer
    28.6  
    28.7 +    SYNC_NOTIFY_INIT_MOVE_OUR_DEVICE
    28.8 +        Device (me) is grouped and will leave current group to join another
    28.9 +        device's (partner) group.
   28.10 +        App displays trustwords, and requests user accept or reject
   28.11 +        App calls deliverHandshakeResult with user's answer
   28.12 +
   28.13 +
   28.14      SYNC_NOTIFY_TIMEOUT :
   28.15          KeySync operation timed out.
   28.16          Identities are set reflecting peers involved in aborted operation.
   28.17 @@ -173,6 +180,10 @@
   28.18          New group created.
   28.19          App displays message. No feedback to engine.
   28.20  
   28.21 +    SYNC_NOTIFY_ACCEPTED_DEVICE_MOVED
   28.22 +        New device was moved from one group to another.
   28.23 +        App displays message. No feedback to engine.
   28.24 +
   28.25     To deliver handshake result back to engine once user reacted,
   28.26     deliver_handshake_result is used. Result can be :
   28.27  
   28.28 @@ -192,7 +203,7 @@
   28.29  
   28.30  #include "message.h"
   28.31  #include "sync_fsm.h"
   28.32 -
   28.33 +#include "sync_app.h"
   28.34  
   28.35  // this module is for being used WITHOUT the Transport API in transport.h
   28.36  // DO NOT USE IT WHEN USING Transport API!
   28.37 @@ -216,24 +227,6 @@
   28.38  
   28.39  typedef PEP_STATUS (*messageToSend_t)(void *obj, message *msg);
   28.40  
   28.41 -// TODO add this to generated code.
   28.42 -typedef enum _sync_handshake_signal {
   28.43 -    SYNC_NOTIFY_UNDEFINED = 0,
   28.44 -
   28.45 -    // request show handshake dialog
   28.46 -    SYNC_NOTIFY_INIT_ADD_OUR_DEVICE,
   28.47 -    SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE,
   28.48 -    SYNC_NOTIFY_INIT_FORM_GROUP,
   28.49 -
   28.50 -    // handshake process timed out
   28.51 -    SYNC_NOTIFY_TIMEOUT,
   28.52 -
   28.53 -    // handshake accepted by user
   28.54 -    SYNC_NOTIFY_ACCEPTED_DEVICE_ADDED,
   28.55 -    SYNC_NOTIFY_ACCEPTED_GROUP_CREATED
   28.56 -
   28.57 -} sync_handshake_signal;
   28.58 -
   28.59  // notifyHandshake() - notify UI about sync handshaking process
   28.60  //
   28.61  //  parameters:
   28.62 @@ -294,11 +287,12 @@
   28.63  //  parameters:
   28.64  //      management (in)     application defined
   28.65  //      timeout (in,out)    do not wait longer than timeout for message
   28.66 +//                          timeout == NULL or *timeout == 0 is blocking
   28.67  //
   28.68  //  return value:
   28.69 -//      next message or :
   28.70 -//      NULL and timeout == 0 for termination
   28.71 -//      NULL and timeout != 0 for timeout occurence
   28.72 +//      next message, then timeout[out] == remaining time
   28.73 +//      NULL and timeout[out] != 0 for timeout occurence
   28.74 +//      NULL and timeout[out] == 0 for termination
   28.75  
   28.76  typedef void *(*retrieve_next_sync_msg_t)(void *management, time_t *timeout);
   28.77  
    29.1 --- a/src/sync_actions.c	Tue Jan 31 08:42:25 2017 +0100
    29.2 +++ b/src/sync_actions.c	Tue Jun 13 13:00:37 2017 +0200
    29.3 @@ -7,51 +7,30 @@
    29.4  #include "pEp_internal.h"
    29.5  #include "message.h"
    29.6  #include "sync_fsm.h"
    29.7 +#include "sync_impl.h"
    29.8  #include "map_asn1.h"
    29.9  #include "baseprotocol.h"
   29.10  
   29.11  // conditions
   29.12  
   29.13 -// TODO : move that SQL statement with other prepared SQL statements in pEpEngine.c
   29.14 -static const char *sql_stored_group_keys =
   29.15 -        "select count(device_group) from person where id = '" PEP_OWN_USERID "';"; 
   29.16 -
   29.17 -// TODO  is that necessary ?
   29.18 -static int _stored_group_keys(void *_gc, int count, char **text, char **name)
   29.19 -{
   29.20 -    assert(_gc);
   29.21 -    assert(count == 1);
   29.22 -    assert(text && text[0]);
   29.23 -    if (!(_gc && count == 1 && text && text[0]))
   29.24 -        return -1;
   29.25 -
   29.26 -    bool *gc = (bool *) _gc;
   29.27 -    *gc = atoi(text[0]) != 0;
   29.28 -    return 0;
   29.29 -}
   29.30 -
   29.31 -int storedGroupKeys(PEP_SESSION session)
   29.32 +int deviceGrouped(PEP_SESSION session)
   29.33  {
   29.34      assert(session);
   29.35      if (!session)
   29.36          return invalid_condition; // error
   29.37  
   29.38 -    bool gc = false;
   29.39 -    int int_result = sqlite3_exec(
   29.40 -        session->db,
   29.41 -        sql_stored_group_keys,
   29.42 -        _stored_group_keys,
   29.43 -        &gc,
   29.44 -        NULL
   29.45 -    );
   29.46 -    assert(int_result == SQLITE_OK);
   29.47 -    if (int_result != SQLITE_OK)
   29.48 -        return invalid_condition; // error
   29.49 +    char *devgrp = NULL;
   29.50 +    int res = 0;
   29.51 +    PEP_STATUS status;
   29.52  
   29.53 -    if (gc)
   29.54 -        return 1;
   29.55 -    else
   29.56 -        return 0;
   29.57 +    status = get_device_group(session, &devgrp);
   29.58 +
   29.59 +    if (status == PEP_STATUS_OK && devgrp && devgrp[0])
   29.60 +        res = 1;
   29.61 +
   29.62 +    free(devgrp);
   29.63 +
   29.64 +    return res;
   29.65  }
   29.66  
   29.67  int keyElectionWon(PEP_SESSION session, Identity partner)
   29.68 @@ -61,15 +40,20 @@
   29.69      if (!(session && partner))
   29.70          return invalid_condition; // error
   29.71  
   29.72 -    // an already existing group always wins
   29.73 +    int partner_is_group = partner->flags & PEP_idf_devicegroup;
   29.74  
   29.75 -    if (storedGroupKeys(session)) {
   29.76 -        assert(!(partner->flags & PEP_idf_devicegroup));
   29.77 -        return 1;
   29.78 +    if (deviceGrouped(session)){
   29.79 +        // existing group always wins against sole device
   29.80 +        if(!partner_is_group)
   29.81 +            return 1;
   29.82 +    } else {
   29.83 +        // sole device always loses against group
   29.84 +        if(partner_is_group)
   29.85 +            return 0;
   29.86      }
   29.87  
   29.88 -    if (partner->flags & PEP_idf_devicegroup)
   29.89 -        return 0;
   29.90 +    // two groups or two sole are elected based on key age
   29.91 +    // key created first wins
   29.92  
   29.93      Identity me = NULL;
   29.94      PEP_STATUS status = get_identity(session, partner->address, PEP_OWN_USERID,
   29.95 @@ -121,6 +105,23 @@
   29.96      return 1;
   29.97  }
   29.98  
   29.99 +int sameKeyAndAddress(PEP_SESSION session, Identity a, Identity b)
  29.100 +{
  29.101 +    assert(session);
  29.102 +    assert(a);
  29.103 +    assert(b);
  29.104 +
  29.105 +    if (!(session && a && b))
  29.106 +        return invalid_condition; // error
  29.107 +
  29.108 +    if (a->fpr == NULL || b->fpr == NULL ||
  29.109 +        (!_same_fpr(a->fpr, strlen(a->fpr), b->fpr, strlen(b->fpr))) ||
  29.110 +        a->address == NULL || b->address == NULL ||
  29.111 +        strcmp(a->address, b->address) != 0)
  29.112 +            return 0;
  29.113 +    return 1;
  29.114 +}
  29.115 +
  29.116  // actions
  29.117  
  29.118  PEP_STATUS _notifyHandshake(
  29.119 @@ -221,12 +222,46 @@
  29.120      if (!(session && partner))
  29.121          return PEP_ILLEGAL_VALUE;
  29.122  
  29.123 +    // TODO : disable sync globally if not in a group
  29.124      status = set_identity_flags(session, partner,
  29.125              partner->flags | PEP_idf_not_for_sync);
  29.126  
  29.127      return status;
  29.128  }
  29.129  
  29.130 +PEP_STATUS _storeGroupKeys(
  29.131 +        PEP_SESSION session,
  29.132 +        identity_list *group_keys
  29.133 +    )
  29.134 +{
  29.135 +    PEP_STATUS status = PEP_STATUS_OK;
  29.136 +
  29.137 +    for (identity_list *il = group_keys; il && il->ident; il = il->next) {
  29.138 +
  29.139 +        if (strcmp(il->ident->user_id, PEP_OWN_USERID)!=0) {
  29.140 +            assert(0);
  29.141 +            continue;
  29.142 +        }
  29.143 +        // Check that identity isn't excluded from sync.
  29.144 +        pEp_identity *stored_identity = NULL;
  29.145 +        status = get_identity(session, il->ident->address, PEP_OWN_USERID,
  29.146 +                &stored_identity);
  29.147 +        if (status == PEP_STATUS_OK) {
  29.148 +            if(stored_identity->flags & PEP_idf_not_for_sync){
  29.149 +                free_identity(stored_identity);
  29.150 +                continue;
  29.151 +            }
  29.152 +            free_identity(stored_identity);
  29.153 +        }
  29.154 +
  29.155 +        status = set_identity(session, il->ident);
  29.156 +        if (status != PEP_STATUS_OK)
  29.157 +            break;
  29.158 +    }
  29.159 +
  29.160 +    return status;
  29.161 +}
  29.162 +    
  29.163  
  29.164  // storeGroupKeys() - 
  29.165  //
  29.166 @@ -243,54 +278,69 @@
  29.167          PEP_SESSION session,
  29.168          DeviceState_state state,
  29.169          Identity partner,
  29.170 -        void *_group_keys
  29.171 +        void *group_keys_extra_
  29.172      )
  29.173  {
  29.174      PEP_STATUS status = PEP_STATUS_OK;
  29.175  
  29.176      assert(session);
  29.177      assert(partner);
  29.178 -    assert(_group_keys);
  29.179 -    if (!(session && partner && _group_keys))
  29.180 +    assert(group_keys_extra_);
  29.181 +    if (!(session && partner && group_keys_extra_))
  29.182          return PEP_ILLEGAL_VALUE;
  29.183  
  29.184 -    identity_list *group_keys = (identity_list *) _group_keys;
  29.185 +    group_keys_extra_t *group_keys_extra = 
  29.186 +        (group_keys_extra_t*) group_keys_extra_;
  29.187 +    identity_list *group_keys = group_keys_extra->group_keys;
  29.188 +    char *group_id = group_keys_extra->group_id;
  29.189  
  29.190 -    for (identity_list *il = group_keys; il && il->ident; il = il->next) {
  29.191 +    status = _storeGroupKeys(session, group_keys);
  29.192 +    if (status != PEP_STATUS_OK)
  29.193 +        return status;
  29.194  
  29.195 -        // Check that identity isn't excluded from sync.
  29.196 -        pEp_identity *stored_identity = NULL;
  29.197 -        status = get_identity(session, il->ident->address, PEP_OWN_USERID,
  29.198 -                &stored_identity);
  29.199 -        if (status == PEP_STATUS_OK) {
  29.200 -            if(stored_identity->flags & PEP_idf_not_for_sync){
  29.201 -                free_identity(stored_identity);
  29.202 -                continue;
  29.203 -            }
  29.204 -            free_identity(stored_identity);
  29.205 -        }
  29.206 -
  29.207 -        free(il->ident->user_id);
  29.208 -        il->ident->user_id = strdup(PEP_OWN_USERID);
  29.209 -        assert(il->ident->user_id);
  29.210 -        if (!il->ident->user_id)
  29.211 -            goto enomem;
  29.212 -        status = set_identity(session, il->ident);
  29.213 -        if (status != PEP_STATUS_OK)
  29.214 -            break;
  29.215 -    }
  29.216 -
  29.217 -    free_identity_list(group_keys);
  29.218 +    // set group id according to given group-id
  29.219 +    status = set_device_group(session, group_id);
  29.220 +    if (status != PEP_STATUS_OK)
  29.221 +        return status;
  29.222      
  29.223      return status;
  29.224 -
  29.225 -enomem:
  29.226 -    status = PEP_OUT_OF_MEMORY;
  29.227 -    free_identity_list(group_keys);
  29.228 -    return status;
  29.229  }
  29.230  
  29.231 -// enterGroup() - 
  29.232 +// storeGroupUpdate() - 
  29.233 +//
  29.234 +//  params:
  29.235 +//      session (in)        session handle
  29.236 +//      state (in)          state the state machine is in
  29.237 +//      partner (in)        partner to communicate with
  29.238 +//      _group_keys (in)    group keys received from partner
  29.239 +//
  29.240 +//  returns:
  29.241 +//      PEP_STATUS_OK or any other value on error
  29.242 +
  29.243 +PEP_STATUS storeGroupUpdate(
  29.244 +        PEP_SESSION session,
  29.245 +        DeviceState_state state,
  29.246 +        Identity partner,
  29.247 +        void *group_keys_
  29.248 +    )
  29.249 +{
  29.250 +    PEP_STATUS status = PEP_STATUS_OK;
  29.251 +
  29.252 +    assert(session);
  29.253 +    assert(partner);
  29.254 +    assert(group_keys_);
  29.255 +    if (!(session && partner && group_keys_))
  29.256 +        return PEP_ILLEGAL_VALUE;
  29.257 +
  29.258 +    identity_list *group_keys = (identity_list*) group_keys_;
  29.259 +
  29.260 +    status = _storeGroupKeys(session, group_keys);
  29.261 +
  29.262 +
  29.263 +    return status;
  29.264 +}
  29.265 +
  29.266 +// makeGroup() - 
  29.267  //
  29.268  //  params:
  29.269  //      session (in)        session handle
  29.270 @@ -301,7 +351,41 @@
  29.271  //  returns:
  29.272  //      PEP_STATUS_OK or any other value on error
  29.273  
  29.274 -PEP_STATUS enterGroup(
  29.275 +PEP_STATUS makeGroup(
  29.276 +        PEP_SESSION session,
  29.277 +        DeviceState_state state,
  29.278 +        Identity partner,
  29.279 +        void *extra
  29.280 +    )
  29.281 +{
  29.282 +    PEP_STATUS status = PEP_STATUS_OK;
  29.283 +
  29.284 +    assert(session);
  29.285 +   
  29.286 +    // make a new uuid 
  29.287 +    char new_uuid[37];
  29.288 +    pEpUUID uuid;
  29.289 +    uuid_generate_random(uuid);
  29.290 +    uuid_unparse_upper(uuid, new_uuid);
  29.291 +
  29.292 +    // take that new uuid as group-id
  29.293 +    status = set_device_group(session, new_uuid);
  29.294 +
  29.295 +    return status;
  29.296 +}
  29.297 +
  29.298 +// renewUUID() - 
  29.299 +//
  29.300 +//  params:
  29.301 +//      session (in)        session handle
  29.302 +//      state (in)          state the state machine is in
  29.303 +//      partner (in)        ignored
  29.304 +//      extra (in)          ignored
  29.305 +//
  29.306 +//  returns:
  29.307 +//      PEP_STATUS_OK or any other value on error
  29.308 +
  29.309 +PEP_STATUS renewUUID(
  29.310          PEP_SESSION session,
  29.311          DeviceState_state state,
  29.312          Identity partner,
  29.313 @@ -312,8 +396,39 @@
  29.314  
  29.315      assert(session);
  29.316  
  29.317 -    // groups have no uuid for now
  29.318 -    status = set_device_group(session, "1");
  29.319 +    // change sync_uuid when entering group 
  29.320 +    // thus ignoring unprocessed handshakes
  29.321 +    // addressed to previous self (sole) once in.
  29.322 +    pEpUUID uuid;
  29.323 +    uuid_generate_random(uuid);
  29.324 +    uuid_unparse_upper(uuid, session->sync_uuid);
  29.325      
  29.326      return status;
  29.327  }
  29.328 +
  29.329 +// leaveGroup() - 
  29.330 +//
  29.331 +//  params:
  29.332 +//      session (in)        session handle
  29.333 +//      state (in)          state the state machine is in
  29.334 +//      partner (in)        ignored
  29.335 +//      extra (in)          ignored
  29.336 +//
  29.337 +//  returns:
  29.338 +//      PEP_STATUS_OK or any other value on error
  29.339 +
  29.340 +PEP_STATUS leaveGroup(
  29.341 +        PEP_SESSION session,
  29.342 +        DeviceState_state state,
  29.343 +        Identity partner,
  29.344 +        void *extra
  29.345 +    )
  29.346 +{
  29.347 +    PEP_STATUS status = PEP_STATUS_OK;
  29.348 +
  29.349 +    assert(session);
  29.350 +
  29.351 +    status = set_device_group(session, NULL);
  29.352 +    
  29.353 +    return status;
  29.354 +}
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/src/sync_app.h	Tue Jun 13 13:00:37 2017 +0200
    30.3 @@ -0,0 +1,34 @@
    30.4 +//
    30.5 +//  sync_app.h
    30.6 +//  pEpEngine
    30.7 +//
    30.8 +//  Created by Dirk Zimmermann on 16.05.17.
    30.9 +//  Copyright © 2017 Edouard Tisserant. All rights reserved.
   30.10 +//
   30.11 +
   30.12 +#ifndef sync_app_h
   30.13 +#define sync_app_h
   30.14 +
   30.15 +// TODO add this to generated code.
   30.16 +typedef enum _sync_handshake_signal {
   30.17 +    SYNC_NOTIFY_UNDEFINED = 0,
   30.18 +
   30.19 +    // request show handshake dialog
   30.20 +    SYNC_NOTIFY_INIT_ADD_OUR_DEVICE,
   30.21 +    SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE,
   30.22 +    SYNC_NOTIFY_INIT_FORM_GROUP,
   30.23 +    SYNC_NOTIFY_INIT_MOVE_OUR_DEVICE,
   30.24 +
   30.25 +    // handshake process timed out
   30.26 +    SYNC_NOTIFY_TIMEOUT,
   30.27 +
   30.28 +    // handshake accepted by user
   30.29 +    SYNC_NOTIFY_ACCEPTED_DEVICE_ADDED,
   30.30 +    SYNC_NOTIFY_ACCEPTED_GROUP_CREATED,
   30.31 +    SYNC_NOTIFY_ACCEPTED_DEVICE_MOVED,
   30.32 +
   30.33 +    // handshake dialog must be closed
   30.34 +    SYNC_NOTIFY_OVERTAKEN
   30.35 +} sync_handshake_signal;
   30.36 +
   30.37 +#endif /* sync_app_h */
    31.1 --- a/src/sync_impl.c	Tue Jan 31 08:42:25 2017 +0100
    31.2 +++ b/src/sync_impl.c	Tue Jun 13 13:00:37 2017 +0200
    31.3 @@ -7,7 +7,6 @@
    31.4  // #define for the dllimport / dllexport DYNAMIC_API stuff.
    31.5  #include "pEp_internal.h"
    31.6  
    31.7 -#include "../asn.1/DeviceGroup-Protocol.h"
    31.8  #include "sync_impl.h"
    31.9  #include "keymanagement.h"
   31.10  #include "message_api.h"
   31.11 @@ -32,6 +31,33 @@
   31.12      } u;
   31.13  };
   31.14  
   31.15 +static bool _is_own_uuid( PEP_SESSION session, UTF8String_t *uuid)
   31.16 +{
   31.17 +    return strncmp(session->sync_session->sync_uuid,
   31.18 +                   (const char*)uuid->buf, uuid->size) == 0;
   31.19 +}
   31.20 +
   31.21 +static bool _is_own_group_uuid( PEP_SESSION session, UTF8String_t *uuid, char** our_group)
   31.22 +{
   31.23 +    PEP_STATUS status = PEP_STATUS_OK;
   31.24 +    char *devgrp = NULL;
   31.25 +
   31.26 +    if(our_group == NULL || *our_group == NULL)
   31.27 +        status = get_device_group(session, &devgrp);
   31.28 +    else
   31.29 +        devgrp = *our_group;
   31.30 +
   31.31 +    bool res = (status == PEP_STATUS_OK && devgrp && devgrp[0] &&
   31.32 +        strncmp(devgrp,(const char*)uuid->buf, uuid->size) == 0);
   31.33 +
   31.34 +    if(our_group == NULL)
   31.35 +        free(devgrp);
   31.36 +    else if(*our_group == NULL)
   31.37 +        *our_group = devgrp;
   31.38 +
   31.39 +    return res;
   31.40 +}
   31.41 +
   31.42  PEP_STATUS receive_sync_msg(
   31.43          PEP_SESSION session,
   31.44          sync_msg_t *sync_msg,
   31.45 @@ -55,6 +81,13 @@
   31.46              goto error;
   31.47          }
   31.48  
   31.49 +        partner = Identity_to_Struct(&msg->header.me, NULL);
   31.50 +        if (!partner){
   31.51 +            status = PEP_OUT_OF_MEMORY;
   31.52 +            ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   31.53 +            goto error;
   31.54 +        }
   31.55 +
   31.56          msgIsFromGroup = msg->header.devicegroup;
   31.57  
   31.58          switch (msg->payload.present) {
   31.59 @@ -63,31 +96,142 @@
   31.60                  break;
   31.61  
   31.62              case DeviceGroup_Protocol__payload_PR_handshakeRequest:
   31.63 +            {
   31.64 +                // re-check uuid in case sync_uuid or group changed while in the queue
   31.65 +                char *own_group_id = NULL;
   31.66 +                bool is_for_me = _is_own_uuid(session, 
   31.67 +                    msg->payload.choice.handshakeRequest.partner_id);
   31.68 +                bool is_for_group = !is_for_me && _is_own_group_uuid(session, 
   31.69 +                    msg->payload.choice.handshakeRequest.partner_id, &own_group_id);
   31.70 +                if (!(is_for_me || is_for_group)){
   31.71 +                    status = PEP_MESSAGE_IGNORE;
   31.72 +                    goto error;
   31.73 +                }
   31.74 +
   31.75 +                UTF8String_t *guuid = msg->payload.choice.handshakeRequest.group_id;
   31.76 +                if(msgIsFromGroup && guuid && guuid->buf && guuid->size) {
   31.77 +                    bool is_from_own_group = _is_own_group_uuid(session, 
   31.78 +                                                                guuid, &own_group_id);
   31.79 +
   31.80 +                    // Filter handshake requests from own group
   31.81 +                    if(is_from_own_group) {
   31.82 +                        status = PEP_MESSAGE_IGNORE;
   31.83 +                        goto error;
   31.84 +                    }
   31.85 +
   31.86 +                    // if it comes from another group, 
   31.87 +                    // we want to communicate with that group
   31.88 +                    // insert group_id given in handshake request 
   31.89 +                    // into partner's id
   31.90 +
   31.91 +                    free(partner->user_id);
   31.92 +                    partner->user_id = strndup((const char*)guuid->buf, guuid->size);
   31.93 +                    if(partner->user_id == NULL){
   31.94 +                        status = PEP_OUT_OF_MEMORY;
   31.95 +                        goto error;
   31.96 +                    }
   31.97 +
   31.98 +                    // if it comes from another group, and we are grouped,
   31.99 +                    // then this is groupmerge
  31.100 +                }
  31.101 +
  31.102                  event = HandshakeRequest;
  31.103                  break;
  31.104  
  31.105 +            }
  31.106              case DeviceGroup_Protocol__payload_PR_updateRequest:
  31.107                  event = UpdateRequest;
  31.108                  break;
  31.109  
  31.110              case DeviceGroup_Protocol__payload_PR_groupKeys:
  31.111 +            {
  31.112 +                // re-check uuid in case sync_uuid or group_uuid changed while in the queue
  31.113 +                char *own_group_id = NULL;
  31.114 +                UTF8String_t *puuid = msg->payload.choice.groupKeys.partner_id;
  31.115 +                bool is_for_me = _is_own_uuid(session, puuid);
  31.116 +                bool is_for_group = !is_for_me &&
  31.117 +                                    _is_own_group_uuid(session, 
  31.118 +                                        puuid, &own_group_id);
  31.119 +                if (!(is_for_me || is_for_group)){
  31.120 +                    status = PEP_MESSAGE_IGNORE;
  31.121 +                    goto error;
  31.122 +                }
  31.123 +
  31.124 +                UTF8String_t *guuid = msg->payload.choice.groupKeys.group_id;
  31.125 +
  31.126 +                // GroupKeys come from groups, no choice
  31.127 +                if(!(msgIsFromGroup && guuid && guuid->buf && guuid->size)) {
  31.128 +                    status = PEP_SYNC_ILLEGAL_MESSAGE;
  31.129 +                    goto error;
  31.130 +                }
  31.131 +
  31.132 +                // Filter groupKeys from own group
  31.133 +                bool is_from_own_group = _is_own_group_uuid(session, 
  31.134 +                                                            guuid, 
  31.135 +                                                            &own_group_id);
  31.136 +                if(is_from_own_group) {
  31.137 +                    // FixMe : protocol shouldn't allow this
  31.138 +                    status = PEP_SYNC_ILLEGAL_MESSAGE;
  31.139 +                    goto error;
  31.140 +                }
  31.141 +
  31.142 +                // insert group_id given in groupKeys into partner's id
  31.143 +                free(partner->user_id);
  31.144 +                partner->user_id = strndup((const char*)guuid->buf, guuid->size);
  31.145 +                if(partner->user_id == NULL){
  31.146 +                    status = PEP_OUT_OF_MEMORY;
  31.147 +                    goto error;
  31.148 +                }
  31.149 +
  31.150 +                // if it comes from another group, and we are grouped,
  31.151 +                // then this is groupmerge's groupKeys
  31.152 +
  31.153 +                group_keys_extra_t *group_keys_extra;
  31.154 +                group_keys_extra = malloc(sizeof(group_keys_extra_t));
  31.155 +                if(group_keys_extra == NULL){
  31.156 +                    status = PEP_OUT_OF_MEMORY;
  31.157 +                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
  31.158 +                    goto error;
  31.159 +                }
  31.160 +
  31.161 +                char *group_id = strndup((char*)guuid->buf, guuid->size);
  31.162 +
  31.163 +                if (!group_id){
  31.164 +                    status = PEP_OUT_OF_MEMORY;
  31.165 +                    free(group_keys_extra);
  31.166 +                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
  31.167 +                    goto error;
  31.168 +                }
  31.169 +                group_keys_extra->group_id = group_id;
  31.170 +
  31.171 +                identity_list *group_keys = IdentityList_to_identity_list(
  31.172 +                        &msg->payload.choice.groupKeys.ownIdentities,
  31.173 +                        NULL);
  31.174 +                if (!group_keys) {
  31.175 +                    status = PEP_OUT_OF_MEMORY;
  31.176 +                    free(group_id);
  31.177 +                    free(group_keys_extra);
  31.178 +                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
  31.179 +                    goto error;
  31.180 +                }
  31.181 +                group_keys_extra->group_keys = group_keys;
  31.182 +
  31.183 +                extra = (void *) group_keys_extra;
  31.184 +                event = GroupKeys;
  31.185 +
  31.186 +                break;
  31.187 +            }
  31.188              case DeviceGroup_Protocol__payload_PR_groupUpdate:
  31.189              {
  31.190                  identity_list *group_keys = IdentityList_to_identity_list(
  31.191 -                        msg->payload.present == 
  31.192 -                          DeviceGroup_Protocol__payload_PR_groupKeys ?
  31.193 -                            &msg->payload.choice.groupKeys.ownIdentities :
  31.194 -                            &msg->payload.choice.groupUpdate.ownIdentities,
  31.195 -                        NULL);
  31.196 +                        &msg->payload.choice.groupUpdate.ownIdentities, NULL);
  31.197                  if (!group_keys) {
  31.198                      status = PEP_OUT_OF_MEMORY;
  31.199                      ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
  31.200                      goto error;
  31.201                  }
  31.202                  extra = (void *) group_keys;
  31.203 -                event = msg->payload.present == 
  31.204 -                          DeviceGroup_Protocol__payload_PR_groupKeys ?
  31.205 -                            GroupKeys : GroupUpdate;
  31.206 +                event = GroupUpdate;
  31.207                  break;
  31.208              }
  31.209  
  31.210 @@ -97,12 +241,6 @@
  31.211                  goto error;
  31.212          }
  31.213  
  31.214 -        partner = Identity_to_Struct(&msg->header.me, NULL);
  31.215 -        if (!partner){
  31.216 -            status = PEP_OUT_OF_MEMORY;
  31.217 -            ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
  31.218 -            goto error;
  31.219 -        }
  31.220      }
  31.221      else{
  31.222          partner = sync_msg->u.event.partner;
  31.223 @@ -124,10 +262,10 @@
  31.224          default:
  31.225              break;
  31.226      }
  31.227 -    time_t now = time(NULL);
  31.228 +
  31.229      if(last != NULL){
  31.230 +        time_t now = time(NULL);
  31.231          if(*last != 0 && (*last + SYNC_INHIBIT_TIME) > now ){
  31.232 -            free_identity(partner);
  31.233              status = PEP_STATEMACHINE_INHIBITED_EVENT;
  31.234              goto error;
  31.235          }
  31.236 @@ -189,9 +327,27 @@
  31.237  
  31.238      status = fsm_DeviceState_inject(session, event, partner, extra, timeout);
  31.239  
  31.240 +error:
  31.241 +
  31.242      free_identity(partner);
  31.243  
  31.244 -error:
  31.245 +    switch(event){
  31.246 +        case GroupKeys:
  31.247 +        {
  31.248 +            free_group_keys_extra((group_keys_extra_t*)extra);
  31.249 +            break;
  31.250 +        }
  31.251 +        case GroupUpdate:
  31.252 +        {
  31.253 +            identity_list *group_keys = (identity_list*) extra;
  31.254 +            free_identity_list(group_keys);
  31.255 +            break;
  31.256 +        }
  31.257 +        default:
  31.258 +            assert(extra==NULL);
  31.259 +            break;
  31.260 +    }
  31.261 +
  31.262      free(sync_msg);
  31.263  
  31.264      return status;
  31.265 @@ -345,53 +501,97 @@
  31.266                  }
  31.267  
  31.268                  int32_t value = (int32_t) msg->header.sequence;
  31.269 -                status = sequence_value(session, (char *) user_id,
  31.270 -                        &value);
  31.271 +                if (value < 1) {
  31.272 +                    status = PEP_SEQUENCE_VIOLATED;
  31.273 +                } else {
  31.274 +                    status = sequence_value(session, (char *) user_id,
  31.275 +                            &value);
  31.276 +                }
  31.277  
  31.278                  if (status == PEP_STATUS_OK) {
  31.279                      switch (msg->payload.present) {
  31.280                          // HandshakeRequest needs encryption
  31.281                          case DeviceGroup_Protocol__payload_PR_handshakeRequest:
  31.282 +                        {
  31.283 +                            UTF8String_t *puuid = 
  31.284 +                              msg->payload.choice.handshakeRequest.partner_id;
  31.285 +                            bool is_for_me = _is_own_uuid(session, puuid);
  31.286 +                            bool is_for_group = !is_for_me && 
  31.287 +                                                _is_own_group_uuid(
  31.288 +                                                    session, puuid, NULL);
  31.289 +
  31.290 +                            // Reject handshake requests not addressed to us
  31.291                              if (rating < PEP_rating_reliable ||
  31.292 -                                strncmp(session->sync_uuid,
  31.293 -                                        (const char *)msg->payload.choice.handshakeRequest.partner.user_id->buf,
  31.294 -                                        msg->payload.choice.handshakeRequest.partner.user_id->size) != 0){
  31.295 -                                discard = true;
  31.296 -                                goto free_all;
  31.297 -                            }
  31.298 -                            
  31.299 -                            break;
  31.300 -                        // accepting GroupKeys needs encryption and trust of peer device
  31.301 -                        case DeviceGroup_Protocol__payload_PR_groupKeys:
  31.302 -                        {
  31.303 -                            if (!keylist || rating < PEP_rating_reliable ||
  31.304 -                                // message is only consumed by instance it is addressed to
  31.305 -                                (strncmp(session->sync_uuid,
  31.306 -                                        (const char *)msg->payload.choice.groupKeys.partner.user_id->buf,
  31.307 -                                        msg->payload.choice.groupKeys.partner.user_id->size) != 0)){
  31.308 +                                !(is_for_me || is_for_group)){
  31.309                                  discard = true;
  31.310                                  goto free_all;
  31.311                              }
  31.312  
  31.313 -                            // check trust of identity using user_id given in msg.header.me
  31.314 -                            // to exacly match identity of device, the one trusted in
  31.315 -                            // case of accepted handshake
  31.316 -                            pEp_identity *_from = new_identity(NULL, 
  31.317 -                                                               keylist->value,
  31.318 -                                                               user_id,
  31.319 -                                                               NULL);
  31.320 -                            if (_from == NULL){
  31.321 -                                status = PEP_OUT_OF_MEMORY;
  31.322 -                                goto free_all;
  31.323 +                            // do not consume handshake request for group
  31.324 +                            if(is_for_group){ 
  31.325 +                                force_keep_msg = true;
  31.326                              }
  31.327 -                            status = get_trust(session, _from);
  31.328 -                            if (status != PEP_STATUS_OK || _from->comm_type < PEP_ct_strong_encryption) {
  31.329 -                                status = PEP_STATUS_OK;
  31.330 -                                free_identity(_from);
  31.331 +                            break;
  31.332 +                        }
  31.333 +                        // accepting GroupKeys needs encryption and trust of peer device
  31.334 +                        case DeviceGroup_Protocol__payload_PR_groupKeys:
  31.335 +                        {
  31.336 +                            UTF8String_t *puuid = msg->payload.choice.groupKeys.partner_id;
  31.337 +                            bool is_for_me = _is_own_uuid(session, puuid);
  31.338 +                            bool is_for_group = !is_for_me &&
  31.339 +                                                _is_own_group_uuid(session, 
  31.340 +                                                    puuid, NULL);
  31.341 +                            if (!keylist || rating < PEP_rating_reliable ||
  31.342 +                                // message is only consumed by instance it is addressed to
  31.343 +                                !(is_for_me || is_for_group)){
  31.344                                  discard = true;
  31.345                                  goto free_all;
  31.346                              }
  31.347 -                            free_identity(_from);
  31.348 +
  31.349 +                            // do not consume groupKeys for group
  31.350 +                            if(is_for_group){ 
  31.351 +                                // This happens in case case of groupmerge
  31.352 +                                force_keep_msg = true;
  31.353 +                            }
  31.354 +
  31.355 +                            // Trust check disabled here but it still it should be safe.
  31.356 +                            // SameIdentity checks in state machine ensures that we only
  31.357 +                            // store groupkeys signed by device or group that have been 
  31.358 +                            // previously accepted in handshake.
  31.359 +                            //
  31.360 +                            // // check trust of identity using user_id given in msg.header.me
  31.361 +                            // // to exacly match identity of device, the one trusted in
  31.362 +                            // // case of accepted handshake from a sole device
  31.363 +                            // pEp_identity *_from = new_identity(NULL, 
  31.364 +                            //                                    keylist->value,
  31.365 +                            //                                    user_id,
  31.366 +                            //                                    NULL);
  31.367 +                            // if (_from == NULL){
  31.368 +                            //     status = PEP_OUT_OF_MEMORY;
  31.369 +                            //     goto free_all;
  31.370 +                            // }
  31.371 +                            // status = get_trust(session, _from);
  31.372 +                            // if (status != PEP_STATUS_OK || _from->comm_type < PEP_ct_strong_encryption) {
  31.373 +
  31.374 +                            //     // re-try with group_id instead, in case of handshake with pre-existing group
  31.375 +                            //     UTF8String_t *guuid = msg->payload.choice.groupKeys.group_id;
  31.376 +                            //     free(_from->user_id);
  31.377 +                            //     if ((_from->user_id = strndup((const char*)guuid->buf, guuid->size)) == NULL){
  31.378 +                            //         free_identity(_from);
  31.379 +                            //         status = PEP_OUT_OF_MEMORY;
  31.380 +                            //         goto free_all;
  31.381 +                            //     }
  31.382 +                            //     _from->comm_type = PEP_ct_unknown;
  31.383 +
  31.384 +                            //     status = get_trust(session, _from);
  31.385 +                            //     if (status != PEP_STATUS_OK || _from->comm_type < PEP_ct_strong_encryption) {
  31.386 +                            //         status = PEP_STATUS_OK;
  31.387 +                            //         free_identity(_from);
  31.388 +                            //         discard = true;
  31.389 +                            //         goto free_all;
  31.390 +                            //     }
  31.391 +                            // }
  31.392 +                            // free_identity(_from);
  31.393                              break;
  31.394                          }
  31.395                          case DeviceGroup_Protocol__payload_PR_groupUpdate:
  31.396 @@ -448,7 +648,7 @@
  31.397                      // don't free message now that it is in the queue
  31.398                      goto free_userid;
  31.399                  }
  31.400 -                else if (status == PEP_OWN_SEQUENCE) {
  31.401 +                else if (status == PEP_OWN_SEQUENCE || status == PEP_SEQUENCE_VIOLATED) {
  31.402                      status = PEP_STATUS_OK;
  31.403                      discard = true;
  31.404                      goto free_all;
  31.405 @@ -574,7 +774,7 @@
  31.406      
  31.407      int32_t seq = 0;
  31.408  
  31.409 -    status = sequence_value(session, session->sync_uuid, &seq);
  31.410 +    status = sequence_value(session, session->sync_session->sync_uuid, &seq);
  31.411      if (status != PEP_OWN_SEQUENCE && status != PEP_STATUS_OK)
  31.412          goto error;
  31.413  
  31.414 @@ -585,7 +785,7 @@
  31.415          goto enomem;
  31.416  
  31.417      free(_me->user_id);
  31.418 -    _me->user_id = strndup(session->sync_uuid, 36);
  31.419 +    _me->user_id = strndup(session->sync_session->sync_uuid, 36);
  31.420      assert(_me->user_id);
  31.421      if (!_me->user_id)
  31.422          goto enomem;
  31.423 @@ -598,7 +798,7 @@
  31.424  
  31.425      msg->header.state = (long) state;
  31.426  
  31.427 -    bool devicegroup = storedGroupKeys(session);
  31.428 +    bool devicegroup = deviceGrouped(session);
  31.429      if (devicegroup)
  31.430          msg->header.devicegroup = 1;
  31.431      else
  31.432 @@ -734,3 +934,39 @@
  31.433  //     return status;
  31.434  }
  31.435  
  31.436 +void free_group_keys_extra(group_keys_extra_t* group_keys_extra)
  31.437 +{
  31.438 +    identity_list *group_keys = group_keys_extra->group_keys;
  31.439 +    char *group_id = group_keys_extra->group_id;
  31.440 +    free_identity_list(group_keys);
  31.441 +    free(group_id);
  31.442 +    free(group_keys_extra);
  31.443 +}
  31.444 +
  31.445 +group_keys_extra_t* group_keys_extra_dup(group_keys_extra_t* group_key_extra_src)
  31.446 +{
  31.447 +    group_keys_extra_t *group_key_extra_dst;
  31.448 +    group_key_extra_dst = calloc(1,sizeof(group_keys_extra_t));
  31.449 +    if(group_key_extra_dst == NULL){
  31.450 +        return NULL;
  31.451 +    }
  31.452 +
  31.453 +    char *group_id = strdup(group_key_extra_src->group_id);
  31.454 +
  31.455 +    if (group_key_extra_dst->group_id && !group_id){
  31.456 +        free(group_key_extra_dst);
  31.457 +        return NULL;
  31.458 +    }
  31.459 +    group_key_extra_dst->group_id = group_id;
  31.460 +
  31.461 +    identity_list *group_keys = identity_list_dup(group_key_extra_src->group_keys);;
  31.462 +    if (!group_keys) {
  31.463 +        free(group_id);
  31.464 +        free(group_key_extra_dst);
  31.465 +        return NULL;
  31.466 +    }
  31.467 +    group_key_extra_dst->group_keys = group_keys;
  31.468 +
  31.469 +    return group_key_extra_dst;
  31.470 +}
  31.471 +
    32.1 --- a/src/sync_impl.h	Tue Jan 31 08:42:25 2017 +0100
    32.2 +++ b/src/sync_impl.h	Tue Jun 13 13:00:37 2017 +0200
    32.3 @@ -3,6 +3,7 @@
    32.4  
    32.5  #pragma once
    32.6  
    32.7 +#include "../asn.1/DeviceGroup-Protocol.h"
    32.8  #include "message.h"
    32.9  #include "sync.h"
   32.10  #include "sync_fsm.h"
   32.11 @@ -11,6 +12,14 @@
   32.12  extern "C" {
   32.13  #endif
   32.14  
   32.15 +typedef struct _group_keys_extra {
   32.16 +    identity_list *group_keys;
   32.17 +    char *group_id;
   32.18 +} group_keys_extra_t;
   32.19 +
   32.20 +void free_group_keys_extra(group_keys_extra_t* groupkeys);
   32.21 +group_keys_extra_t* group_keys_extra_dup(group_keys_extra_t* groupkeys);
   32.22 +
   32.23  PEP_STATUS receive_sync_msg(
   32.24          PEP_SESSION session,
   32.25          sync_msg_t *sync_msg,
    33.1 --- a/sync/Makefile	Tue Jan 31 08:42:25 2017 +0100
    33.2 +++ b/sync/Makefile	Tue Jun 13 13:00:37 2017 +0200
    33.3 @@ -13,10 +13,10 @@
    33.4  	touch .codegen
    33.5  
    33.6  .actions: devicegroup.fsm gen_actions.ysl2 fsm.yml2 functions.ysl2
    33.7 -	$(YML2PROC) -y gen_actions.ysl2 $< -o $@
    33.8 +	$(YML2PROC) $(YML_OPTS) -y gen_actions.ysl2 $< -o $@
    33.9  
   33.10  .statemachines: devicegroup.fsm gen_statemachine.ysl2 fsm.yml2 functions.ysl2
   33.11 -	$(YML2PROC) -y gen_statemachine.ysl2 $< -o $@
   33.12 +	$(YML2PROC) $(YML_OPTS) -y gen_statemachine.ysl2 $< -o $@
   33.13  
   33.14  .PHONY: clean
   33.15  
   33.16 @@ -29,7 +29,7 @@
   33.17  	yml2c $< -o $@
   33.18  
   33.19  %.dot: devicegroup.fsm gen_dot.ysl2
   33.20 -	yml2proc -y gen_dot.ysl2 $<
   33.21 +	$(YML2PROC) $(YML_OPTS) -y gen_dot.ysl2 $<
   33.22  
   33.23  %.svg: %.dot
   33.24  	dot -Tsvg -o $@ $<
    34.1 --- a/sync/devicegroup.fsm	Tue Jan 31 08:42:25 2017 +0100
    34.2 +++ b/sync/devicegroup.fsm	Tue Jun 13 13:00:37 2017 +0200
    34.3 @@ -18,23 +18,28 @@
    34.4      unencrypted sendBeacon;
    34.5  
    34.6      fsm DeviceState filename=sync {
    34.7 -        condition storedGroupKeys();
    34.8 +        condition deviceGrouped();
    34.9          condition keyElectionWon(Identity partner);
   34.10          condition sameIdentities(Identity a, Identity b);
   34.11 +        condition sameKeyAndAddress(Identity a, Identity b);
   34.12  
   34.13          state InitState {
   34.14              on Init {
   34.15 -                if storedGroupKeys()
   34.16 +                if deviceGrouped()
   34.17                      go Grouped;
   34.18                  go Sole;
   34.19              }
   34.20          }
   34.21  
   34.22          state Sole end=1 {
   34.23 -            on KeyGen
   34.24 +            on KeyGen {
   34.25                  do sendBeacon;
   34.26 -            on CannotDecrypt
   34.27 +                go SoleWaiting;
   34.28 +            }
   34.29 +            on CannotDecrypt {
   34.30                  do sendBeacon;
   34.31 +                go SoleWaiting;
   34.32 +            }
   34.33              on Beacon(Identity partner){
   34.34                  do sendHandshakeRequest(partner);
   34.35                  go SoleBeaconed(partner);
   34.36 @@ -45,6 +50,26 @@
   34.37              }
   34.38          }
   34.39  
   34.40 +        // copy of sole state with a timeout to enable fast polling for a second
   34.41 +        // TODO use more YSLT power here (substates ?) 
   34.42 +        state SoleWaiting timeout=60 {
   34.43 +            on KeyGen {
   34.44 +                do sendBeacon;
   34.45 +            }
   34.46 +            on CannotDecrypt {
   34.47 +                do sendBeacon;
   34.48 +            }
   34.49 +            on Beacon(Identity partner){
   34.50 +                do sendHandshakeRequest(partner);
   34.51 +                go SoleBeaconed(partner);
   34.52 +            }
   34.53 +            on HandshakeRequest(Identity partner) {
   34.54 +                do sendHandshakeRequest(partner);
   34.55 +                go HandshakingSole(partner);
   34.56 +            }
   34.57 +            on Timeout go Sole;
   34.58 +        }
   34.59 +
   34.60          state SoleBeaconed timeout=600 (Identity expected) {
   34.61              on KeyGen{
   34.62                  do sendBeacon;
   34.63 @@ -71,27 +96,41 @@
   34.64  
   34.65          state HandshakingSole timeout=600 (Identity expected) {
   34.66              on Init{
   34.67 -                if keyElectionWon(partner) {
   34.68 -                    do notifyInitFormGroup(partner);
   34.69 +                if keyElectionWon(expected) {
   34.70 +                    do notifyInitFormGroup(expected);
   34.71                  } else {
   34.72 -                    do notifyInitAddOurDevice(partner);
   34.73 +                    do notifyInitAddOurDevice(expected);
   34.74                  }
   34.75              }
   34.76 -
   34.77              on HandshakeRejected(Identity partner) {
   34.78                  do rejectHandshake(partner);
   34.79                  go Sole;
   34.80              }
   34.81              on HandshakeAccepted(Identity partner) {
   34.82 -                do acceptHandshake(partner); 
   34.83 -                if keyElectionWon(partner) {
   34.84 -                    do sendGroupKeys(partner);
   34.85 -                    do notifyAcceptedGroupCreated(partner);
   34.86 -                    go Grouped;
   34.87 +                if sameIdentities(partner, expected) {
   34.88 +                    do acceptHandshake(partner); 
   34.89 +                    if keyElectionWon(partner) {
   34.90 +                        do makeGroup;
   34.91 +                        do sendGroupKeys(partner);
   34.92 +                        do renewUUID;
   34.93 +                        do notifyAcceptedGroupCreated(partner);
   34.94 +                        go Grouped;
   34.95 +                    }
   34.96 +                    go WaitForGroupKeysSole(partner);
   34.97                  }
   34.98 -                go WaitForGroupKeysSole(partner);
   34.99 +                go Sole;
  34.100              }
  34.101              on Cancel go Sole;
  34.102 +            on GroupKeys(Identity partner, GroupKeys groupkeys) {
  34.103 +                if keyElectionWon(expected) {
  34.104 +                    // not supposed to receive groupkeys - ignore
  34.105 +                } else {
  34.106 +                    // UUID changes in between, so we can only check for same address and fpr
  34.107 +                    if sameKeyAndAddress(partner, expected) {
  34.108 +                        go WaitForAcceptSole(partner, groupkeys);
  34.109 +                    }
  34.110 +                }
  34.111 +            }
  34.112              on Timeout {
  34.113                  do notifyTimeout(expected);
  34.114                  do sendBeacon;
  34.115 @@ -100,9 +139,12 @@
  34.116          }
  34.117      
  34.118          state WaitForGroupKeysSole timeout=600 (Identity expected) {
  34.119 -            on GroupKeys(Identity partner, Stringlist keys) {
  34.120 -                if sameIdentities(partner, expected) {
  34.121 -                    do storeGroupKeys(partner, keys);
  34.122 +            on GroupKeys(Identity partner, GroupKeys groupkeys) {
  34.123 +                // UUID changes in between, so we can only check for same address and fpr
  34.124 +                if sameKeyAndAddress(partner, expected) {
  34.125 +                    do storeGroupKeys(partner, groupkeys);
  34.126 +                    do sendGroupUpdate;
  34.127 +                    do renewUUID;
  34.128                      do notifyAcceptedDeviceAdded(partner);
  34.129                      go Grouped;
  34.130                  }
  34.131 @@ -113,13 +155,38 @@
  34.132              }
  34.133          }
  34.134  
  34.135 +        state WaitForAcceptSole timeout=600 (Identity expected, GroupKeys groupkeys) {
  34.136 +            on HandshakeRejected(Identity partner) {
  34.137 +                do rejectHandshake(partner);
  34.138 +                go Sole;
  34.139 +            }
  34.140 +            on HandshakeAccepted(Identity partner) {
  34.141 +                // UUID changes in between, so we can only check for same address and fpr
  34.142 +                if sameKeyAndAddress(partner, expected) {
  34.143 +                    do acceptHandshake(partner); 
  34.144 +                    do storeGroupKeys(partner, groupkeys);
  34.145 +                    do sendGroupUpdate;
  34.146 +                    do renewUUID;
  34.147 +                    do notifyAcceptedDeviceAdded(partner);
  34.148 +                    go Grouped;
  34.149 +                }
  34.150 +                go Sole;
  34.151 +            }
  34.152 +            on Cancel go Sole;
  34.153 +            on Timeout {
  34.154 +                do notifyTimeout(expected);
  34.155 +                go Sole;
  34.156 +            }
  34.157 +        }
  34.158 +
  34.159          state Grouped end=1 {
  34.160 -            on Init 
  34.161 -                do enterGroup;
  34.162              on KeyGen
  34.163                  do sendGroupUpdate;
  34.164 -            on CannotDecrypt
  34.165 +            on CannotDecrypt {
  34.166                  do sendUpdateRequest;
  34.167 +                do sendBeacon;
  34.168 +                go GroupWaiting;
  34.169 +            }
  34.170              on UpdateRequest
  34.171                  do sendGroupUpdate;
  34.172              on Beacon(Identity partner){
  34.173 @@ -130,15 +197,40 @@
  34.174                  do sendHandshakeRequest(partner);
  34.175                  go HandshakingGrouped(partner);
  34.176              }
  34.177 -            on GroupUpdate(Identity partner, Stringlist keys)
  34.178 -                do storeGroupKeys(partner, keys);
  34.179 +            on GroupUpdate(Identity partner, IdentityList keys)
  34.180 +                do storeGroupUpdate(partner, keys);
  34.181 +        }
  34.182 +
  34.183 +        // copy of grouped state, with a timeout to enable fast poling for a minut
  34.184 +        state GroupWaiting timeout=60 {
  34.185 +            on KeyGen
  34.186 +                do sendGroupUpdate;
  34.187 +            on CannotDecrypt {
  34.188 +                do sendUpdateRequest;
  34.189 +                do sendBeacon;
  34.190 +            }
  34.191 +            on UpdateRequest
  34.192 +                do sendGroupUpdate;
  34.193 +            on Beacon(Identity partner){
  34.194 +                do sendHandshakeRequest(partner);
  34.195 +                go GroupedBeaconed(partner);
  34.196 +            }
  34.197 +            on HandshakeRequest(Identity partner) {
  34.198 +                do sendHandshakeRequest(partner);
  34.199 +                go HandshakingGrouped(partner);
  34.200 +            }
  34.201 +            on GroupUpdate(Identity partner, IdentityList keys)
  34.202 +                do storeGroupUpdate(partner, keys);
  34.203 +            on Timeout go Grouped;
  34.204          }
  34.205  
  34.206          state GroupedBeaconed timeout=600 (Identity expected){
  34.207              on KeyGen
  34.208                  do sendGroupUpdate;
  34.209 -            on CannotDecrypt
  34.210 +            on CannotDecrypt {
  34.211                  do sendUpdateRequest;
  34.212 +                do sendBeacon;
  34.213 +            }
  34.214              on UpdateRequest
  34.215                  do sendGroupUpdate;
  34.216              on Beacon(Identity partner){
  34.217 @@ -153,24 +245,98 @@
  34.218                  }
  34.219                  go HandshakingGrouped(partner);
  34.220              }
  34.221 -            on GroupUpdate(Identity partner, Stringlist keys)
  34.222 -                do storeGroupKeys(partner, keys);
  34.223 +            on GroupUpdate(Identity partner, IdentityList keys)
  34.224 +                do storeGroupUpdate(partner, keys);
  34.225              on Timeout go Grouped;
  34.226          }
  34.227  
  34.228          state HandshakingGrouped timeout=600 (Identity expected) {
  34.229 -            on Init
  34.230 -                do notifyInitAddOurDevice(partner);
  34.231 +            // HandshakeRequest from same group are filtered in receive_sync_msg
  34.232 +            on Init{
  34.233 +                if keyElectionWon(expected) {
  34.234 +                    do notifyInitAddOtherDevice(partner);
  34.235 +                } else {
  34.236 +                    do notifyInitMoveOurDevice(partner);
  34.237 +                }
  34.238 +            }
  34.239              on HandshakeRejected(Identity partner) {
  34.240                  do rejectHandshake(partner);             // stores rejection of partner
  34.241 +                do sendGroupUpdate;
  34.242                  go Grouped;
  34.243              }
  34.244              on HandshakeAccepted(Identity partner) {
  34.245                  do acceptHandshake(partner); 
  34.246 +                do sendGroupUpdate;
  34.247 +                if keyElectionWon(partner) {
  34.248 +                    do sendGroupKeys(partner);
  34.249 +                    do notifyAcceptedDeviceAdded(partner);
  34.250 +                    go Grouped;
  34.251 +                }
  34.252 +                go WaitForGroupKeysGrouped(partner);
  34.253 +            }
  34.254 +            on Cancel go Grouped;
  34.255 +            on GroupKeys(Identity partner, GroupKeys groupkeys) {
  34.256 +                if keyElectionWon(expected) {
  34.257 +                    // not supposed to receive groupkeys - ignore
  34.258 +                } else {
  34.259 +                    // UUID changes in between, so we can only check for same address and fpr
  34.260 +                    if sameKeyAndAddress(partner, expected) {
  34.261 +                        go WaitForAcceptGrouped(partner, groupkeys);
  34.262 +                    }
  34.263 +                }
  34.264 +            }
  34.265 +            on GroupUpdate(Identity partner, IdentityList keys) {
  34.266 +                do notifyOvertaken(partner);
  34.267 +                do storeGroupUpdate(partner, keys);
  34.268 +                go Grouped;
  34.269 +            }
  34.270 +            on Timeout {
  34.271 +                do notifyTimeout(expected);
  34.272 +                go Grouped;
  34.273 +            }
  34.274 +        }
  34.275  
  34.276 -                // an already existing group always wins
  34.277 -                do sendGroupKeys(partner);
  34.278 +        state WaitForGroupKeysGrouped timeout=600 (Identity expected) {
  34.279 +            on GroupKeys(Identity partner, GroupKeys groupkeys) {
  34.280 +                if sameIdentities(partner, expected) {
  34.281 +                    do storeGroupKeys(partner, groupkeys);
  34.282 +                    do sendGroupUpdate;
  34.283 +                    do renewUUID;
  34.284 +                    do notifyAcceptedDeviceMoved(partner);
  34.285 +                    go Grouped;
  34.286 +                }
  34.287 +            }
  34.288 +            on GroupUpdate(Identity partner, IdentityList keys) {
  34.289 +                do notifyOvertaken(partner);
  34.290 +                do storeGroupUpdate(partner, keys);
  34.291 +                go Grouped;
  34.292 +            }
  34.293 +            on Timeout {
  34.294 +                do notifyTimeout(expected);
  34.295 +                go Grouped;
  34.296 +            }
  34.297 +        }
  34.298  
  34.299 +        state WaitForAcceptGrouped timeout=600 (Identity expected, GroupKeys groupkeys) {
  34.300 +            on HandshakeRejected(Identity partner) {
  34.301 +                do rejectHandshake(partner);
  34.302 +                do sendGroupUpdate;
  34.303 +                go Grouped;
  34.304 +            }
  34.305 +            on HandshakeAccepted(Identity partner) {
  34.306 +                if sameIdentities(partner, expected) {
  34.307 +                    do acceptHandshake(partner); 
  34.308 +                    do storeGroupKeys(partner, groupkeys);
  34.309 +                    do sendGroupUpdate;
  34.310 +                    do renewUUID;
  34.311 +                    do notifyAcceptedDeviceMoved(partner);
  34.312 +                }
  34.313 +                go Grouped;
  34.314 +            }
  34.315 +            on Cancel go Grouped;
  34.316 +            on GroupUpdate(Identity partner, IdentityList keys) {
  34.317 +                do notifyOvertaken(partner);
  34.318 +                do storeGroupUpdate(partner, keys);
  34.319                  go Grouped;
  34.320              }
  34.321              on Timeout {
    35.1 --- a/sync/fsm.yml2	Tue Jan 31 08:42:25 2017 +0100
    35.2 +++ b/sync/fsm.yml2	Tue Jun 13 13:00:37 2017 +0200
    35.3 @@ -14,5 +14,6 @@
    35.4  decl transition @target, go is transition;
    35.5  decl action @name, do is action;
    35.6  decl condition @name, if is condition;
    35.7 +decl alternative, else is alternative;
    35.8  decl interface @name;
    35.9  decl tag @name (id);
    36.1 --- a/sync/gen_actions.ysl2	Tue Jan 31 08:42:25 2017 +0100
    36.2 +++ b/sync/gen_actions.ysl2	Tue Jun 13 13:00:37 2017 +0200
    36.3 @@ -198,9 +198,21 @@
    36.4          choose {
    36.5              when "$name='GroupKeys' or $name='HandshakeRequest'" {
    36.6                  |
    36.7 -                |> if (Identity_from_Struct(partner,
    36.8 -                |>                          &msg->payload.choice.«$lname».partner) == NULL)
    36.9 -                |>> goto enomem;
   36.10 +                |> msg->payload.choice.«$lname».partner_id = 
   36.11 +                |>     OCTET_STRING_new_fromBuf(&asn_DEF_UTF8String,
   36.12 +                |>                              partner->user_id, -1);
   36.13 +                |> if (partner->user_id && !msg->payload.choice.«$lname».partner_id)
   36.14 +                |>    goto enomem;
   36.15 +                |
   36.16 +                |> char *devgrp = NULL;
   36.17 +                |> status = get_device_group(session, &devgrp);
   36.18 +                |> if (status == PEP_STATUS_OK && devgrp && devgrp[0])
   36.19 +                |> msg->payload.choice.«$lname».group_id = 
   36.20 +                |>     OCTET_STRING_new_fromBuf(&asn_DEF_UTF8String,
   36.21 +                |>                              devgrp, -1);
   36.22 +                |> free(devgrp);
   36.23 +                |> if (devgrp && !msg->payload.choice.«$lname».partner_id)
   36.24 +                |>    goto enomem;
   36.25              }
   36.26          }
   36.27          ||
    37.1 --- a/sync/gen_dot.ysl2	Tue Jan 31 08:42:25 2017 +0100
    37.2 +++ b/sync/gen_dot.ysl2	Tue Jun 13 13:00:37 2017 +0200
    37.3 @@ -21,9 +21,10 @@
    37.4  
    37.5      template "event" {
    37.6          param "state";
    37.7 +        const "transitions", "transition|descendant::condition/transition|descendant::alternative/transition";
    37.8          choose {
    37.9 -            when "count(transition) > 0"
   37.10 -                apply "transition|condition/transition", 0
   37.11 +            when "count($transitions) > 0"
   37.12 +                apply "$transitions", 0
   37.13                      with "state", "$state", with "event", "@name";
   37.14              otherwise
   37.15                  if "@name != 'Init'"
    38.1 --- a/sync/gen_statemachine.ysl2	Tue Jan 31 08:42:25 2017 +0100
    38.2 +++ b/sync/gen_statemachine.ysl2	Tue Jun 13 13:00:37 2017 +0200
    38.3 @@ -42,7 +42,6 @@
    38.4  
    38.5          typedef pEp_identity * Identity;
    38.6          typedef stringlist_t * Stringlist;
    38.7 -        typedef union _param { Identity partner; stringlist_t *keylist; } param_t;
    38.8  
    38.9          // error values
   38.10  
   38.11 @@ -186,6 +185,11 @@
   38.12          ||
   38.13          #include "pEp_internal.h"
   38.14          #include "«@filename»_fsm.h"
   38.15 +        #include "«@filename»_impl.h"
   38.16 +
   38.17 +        // local definitions for «@name»'s state machine 
   38.18 +
   38.19 +        `` apply "state", 0 mode="declStatePayload"
   38.20  
   38.21          // state machine for «@name»
   38.22  
   38.23 @@ -198,7 +202,6 @@
   38.24                  time_t *timeout
   38.25              )
   38.26          {
   38.27 -            int cond_result;
   38.28              PEP_STATUS status = PEP_STATUS_OK;
   38.29  
   38.30              switch (state) {
   38.31 @@ -213,38 +216,106 @@
   38.32          ||
   38.33      }
   38.34  
   38.35 -    template "state"
   38.36 +    template "state" {
   38.37 +        ||
   38.38 +        case «@name»:
   38.39 +        {
   38.40 +            DEBUG_LOG("Entering FSM state", "«../@filename»_fsm.c", "state=«@name»")
   38.41 +        ||
   38.42 +
   38.43 +        if "count(parm) > 0" 
   38.44 +        || 
   38.45 +            assert(session->sync_state_payload);
   38.46 +            if(!session->sync_state_payload) return («../@name»_state) invalid_state;
   38.47 +            `` apply "parm", 1 mode="unpackStatePayloadParm" with "stateName", "@name"
   38.48 +        ||
   38.49 +
   38.50 +        ||
   38.51 +            switch (event) {
   38.52 +        ||
   38.53 +
   38.54 +        if "not(event[@name='Init'])" 
   38.55 +        ||
   38.56 +                case Init: 
   38.57 +                    DEBUG_LOG("FSM event", "«../@filename»_fsm.c, state=«@name»", "event=Init") 
   38.58 +                    *timeout = «@timeout»;
   38.59 +                    break;
   38.60 +        ||
   38.61 +
   38.62 +        apply "event", 2;
   38.63 +
   38.64 +        ||
   38.65 +                default:
   38.66 +                    return («../@name»_state) invalid_event;
   38.67 +            }
   38.68 +            break;
   38.69 +        }
   38.70 +        ||
   38.71 +    }
   38.72 +
   38.73 +    function "pEp_type" {
   38.74 +        param "type";
   38.75 +
   38.76 +        choose {
   38.77 +            when "$type = 'Identity'" > Identity
   38.78 +            when "$type = 'IdentityList'" > identity_list*
   38.79 +            when "$type = 'GroupKeys'" > group_keys_extra_t*
   38.80 +            otherwise value "$type";
   38.81 +        }
   38.82 +    }
   38.83 +
   38.84 +    function "pEp_type_op_radix" {
   38.85 +        param "type";
   38.86 +
   38.87 +        choose {
   38.88 +            when "$type = 'Identity'" > identity
   38.89 +            when "$type = 'IdentityList'" > identity_list
   38.90 +            when "$type = 'GroupKeys'" > group_keys_extra
   38.91 +            otherwise call "pEp_type" with "type", "$type";
   38.92 +        }
   38.93 +    }
   38.94 +
   38.95 +    template "parm" mode="unpackStatePayloadParm" 
   38.96 +    {
   38.97 +        param "stateName";
   38.98 +        const "pEpType" call "pEp_type" with "type","name(*[1])"; 
   38.99 +        | «$pEpType» «name(*[2])» = ((«$stateName»_state_payload_t*)session->sync_state_payload)->«name(*[2])»;
  38.100 +    }
  38.101 +
  38.102 +    template "state" mode="declStatePayload" if "count(parm) > 0"
  38.103      ||
  38.104 -    case «@name»:
  38.105 -    {
  38.106 -        `` if "count(parm) > 1" error | # TODO composite state payload 
  38.107 -        `` apply "parm", 1 mode="stateParm"
  38.108 -        *timeout = «@timeout»;
  38.109 -        DEBUG_LOG("Entering FSM state", "«../@filename»_fsm.c", "state=«@name»")
  38.110 -        switch (event) {
  38.111 -        `` if "not(event[@name='Init'])" |>> case Init: DEBUG_LOG("FSM event", "«../@filename»_fsm.c, state=«@name»", "event=Init") break;
  38.112 -        `` apply "event", 2
  38.113 -            default:
  38.114 -                return («../@name»_state) invalid_event;
  38.115 -        }
  38.116 -        break;
  38.117 -    }
  38.118 +    typedef struct _«@name»_state_payload {
  38.119 +        `` apply "parm", 1 mode="declStatePayloadParm"
  38.120 +    } «@name»_state_payload_t;
  38.121 +
  38.122      ||
  38.123  
  38.124 -    template "parm" mode="stateParm" 
  38.125 -    {
  38.126 -        | «name(*[1])» «name(*[2])» = («name(*[1])»)session->sync_state_payload;
  38.127 +    template "parm" mode="declStatePayloadParm" {
  38.128 +        const "pEpType" call "pEp_type" with "type","name(*[1])"; 
  38.129 +        | «$pEpType» «name(*[2])»;
  38.130      }
  38.131  
  38.132 -    template "event"
  38.133 -    ||
  38.134 -    case «@name»:
  38.135 -    {
  38.136 -        DEBUG_LOG("FSM event", "«../../@filename»_fsm.c, state=«../@name»", "event=«@name»")
  38.137 -    `` apply "action|transition|condition";
  38.138 -    `` if "name(*[position()=last()]) != 'transition'" |> break;
  38.139 +    template "event" {
  38.140 +        ||
  38.141 +        case «@name»:
  38.142 +        {
  38.143 +            DEBUG_LOG("FSM event", "«../../@filename»_fsm.c, state=«../@name»", "event=«@name»")
  38.144 +        `` if "@name='Init'" |> *timeout = «../@timeout»;
  38.145 +        ||
  38.146 +
  38.147 +        if "count(parm) > 1" {
  38.148 +            // TODO get ride of void *extra, pass per-event struct incl all params.
  38.149 +            const "extrapEpType" call "pEp_type" with "type","name(parm[2]/*[1])"; 
  38.150 +            const "extraArgName","name(parm[2]/*[2])"; 
  38.151 +            |> «$extrapEpType» «$extraArgName» = («$extrapEpType»)extra;
  38.152 +        }
  38.153 +
  38.154 +        ||
  38.155 +        `` apply "action|transition|condition";
  38.156 +        `` if "name(*[position()=last()]) != 'transition'" |> break;
  38.157 +        }
  38.158 +        ||
  38.159      }
  38.160 -    ||
  38.161  
  38.162      template "action" {
  38.163          | DEBUG_LOG("FSM action", "«ancestor::fsm/@filename»_fsm.c, state=«ancestor::state/@name», event=«ancestor::event/@name»", "action=«@name»")
  38.164 @@ -255,7 +326,7 @@
  38.165              otherwise > NULL
  38.166          }
  38.167          choose {
  38.168 -            when "parm[2]" > , extra /*«name(parm[2]/*)»*/
  38.169 +            when "count(parm) > 1" > , «name(parm[2]/*)»
  38.170              otherwise > , NULL
  38.171          }
  38.172          > );\n
  38.173 @@ -266,23 +337,25 @@
  38.174      }
  38.175  
  38.176      template "condition" {
  38.177 -        | cond_result = «@name»(session`apply "parm", 0`);
  38.178 -        | #ifndef NDEBUG
  38.179 -        | char resstr[11] = {0,};
  38.180 -        | snprintf(resstr,10,"result=%d",cond_result);
  38.181 -        | #endif
  38.182 -        | DEBUG_LOG("FSM condition", "«ancestor::fsm/@filename»_fsm.c, state=«ancestor::state/@name», event=«ancestor::event/@name», condition=«@name»", resstr)
  38.183 -        | if (cond_result < 0)
  38.184 -        |> return cond_result;
  38.185 -        | if (cond_result) {
  38.186 +        | {
  38.187 +        |> int cond_result = «@name»(session`apply "parm", 0`);
  38.188 +        |> #ifndef NDEBUG
  38.189 +        |> char resstr[11] = {0,};
  38.190 +        |> snprintf(resstr,10,"result=%d",cond_result);
  38.191 +        |> #endif
  38.192 +        |> DEBUG_LOG("FSM condition", "«ancestor::fsm/@filename»_fsm.c, state=«ancestor::state/@name», event=«ancestor::event/@name», condition=«@name»", resstr)
  38.193 +        |> if (cond_result < 0)
  38.194 +        |>> return cond_result;
  38.195 +        |> if (cond_result) {
  38.196          apply "action|transition|condition";
  38.197 +        |> }
  38.198 +        const "alternative", "./following-sibling::*[position()=1][name(.)='alternative']";
  38.199 +        if "$alternative" {
  38.200 +        |> else {
  38.201 +        apply "$alternative/action|$alternative/transition|$alternative/condition";
  38.202 +        |> }
  38.203 +        }
  38.204          | }
  38.205 -        const "else", "./following-sibling::*[position()=1][name(.)='else']";
  38.206 -        if "$else" {
  38.207 -        | else {
  38.208 -        apply "$else/action|transition|condition";
  38.209 -        | }
  38.210 -        }
  38.211      }
  38.212  
  38.213      template "parm" choose {
  38.214 @@ -294,19 +367,49 @@
  38.215  
  38.216      template "transition"{
  38.217          const "stateparm", "ancestor::state/child::parm";
  38.218 -        if "$stateparm" {
  38.219 -            | if(session->sync_state_payload){
  38.220 -            |     free_«yml:lcase(name($stateparm[1]/*))»((«name($stateparm[1]/*)»)session->sync_state_payload);
  38.221 -            |     session->sync_state_payload = NULL;
  38.222 -            | }
  38.223 +        if "count($stateparm) > 0" {
  38.224 +            ||
  38.225 +            assert(session->sync_state_payload);
  38.226 +            if(!session->sync_state_payload) return («ancestor::fsm/@name»_state) invalid_state;
  38.227 +            `` apply "$stateparm", 0 mode="freeStatePayloadParm" with "stateName", "ancestor::state/@name"
  38.228 +            free(session->sync_state_payload);
  38.229 +            session->sync_state_payload = NULL;
  38.230 +            ||
  38.231          }
  38.232 -        if "parm" {
  38.233 +        if "count(parm) > 0" {
  38.234              const "nextstatename", "@target";
  38.235              const "nextstateparm", "ancestor::fsm/child::state[@name = $nextstatename]/child::parm";
  38.236 -            | session->sync_state_payload = «yml:lcase(name($nextstateparm/*))»_dup(«name(parm/*)»);
  38.237 +            if "count(parm) != count($nextstateparm)" 
  38.238 +                error > different state parameters and transition parameters count state=«ancestor::state/@name», event=«ancestor::event/@name» target=«@target»
  38.239 +            ||
  38.240 +            session->sync_state_payload = malloc(sizeof(«$nextstatename»_state_payload_t));
  38.241 +            assert(session->sync_state_payload);
  38.242 +            if(!session->sync_state_payload) return («ancestor::fsm/@name»_state) invalid_out_of_memory;
  38.243 +            ||
  38.244 +            apply "$nextstateparm", 0 mode="dupStatePayloadParm" {
  38.245 +                with "stateName", "$nextstatename";
  38.246 +                with "transitionParms", "parm";
  38.247 +            }
  38.248          }
  38.249          | DEBUG_LOG("FSM transition", "«ancestor::fsm/@filename»_fsm.c, state=«ancestor::state/@name», event=«ancestor::event/@name»", "target=«@target»")
  38.250          | return «@target»;
  38.251      }
  38.252 +
  38.253 +    template "parm" mode="freeStatePayloadParm" 
  38.254 +    {
  38.255 +        param "stateName";
  38.256 +        const "pEpTypeOpRadix" call "pEp_type_op_radix" with "type","name(*[1])"; 
  38.257 +        | free_«$pEpTypeOpRadix»(((«$stateName»_state_payload_t*)session->sync_state_payload)->«name(*[2])»);
  38.258 +    }
  38.259 +
  38.260 +    template "parm" mode="dupStatePayloadParm" 
  38.261 +    {
  38.262 +        param "stateName";
  38.263 +        param "transitionParms";
  38.264 +        const "pEpTypeOpRadix" call "pEp_type_op_radix" with "type","name(*[1])"; 
  38.265 +        const "pos", "position()";
  38.266 +        | ((«$stateName»_state_payload_t*)session->sync_state_payload)->«name(*[2])» =
  38.267 +        |     «$pEpTypeOpRadix»_dup(«name($transitionParms[$pos]/*)»);
  38.268 +    }
  38.269  }
  38.270  
    39.1 --- a/sync/generated/sync_fsm.c	Tue Jan 31 08:42:25 2017 +0100
    39.2 +++ b/sync/generated/sync_fsm.c	Tue Jun 13 13:00:37 2017 +0200
    39.3 @@ -1,5 +1,43 @@
    39.4  #include "pEp_internal.h"
    39.5  #include "sync_fsm.h"
    39.6 +#include "sync_impl.h"
    39.7 +
    39.8 +// local definitions for DeviceState's state machine 
    39.9 +
   39.10 +typedef struct _SoleBeaconed_state_payload {
   39.11 +    Identity expected;
   39.12 +} SoleBeaconed_state_payload_t;
   39.13 +
   39.14 +typedef struct _HandshakingSole_state_payload {
   39.15 +    Identity expected;
   39.16 +} HandshakingSole_state_payload_t;
   39.17 +
   39.18 +typedef struct _WaitForGroupKeysSole_state_payload {
   39.19 +    Identity expected;
   39.20 +} WaitForGroupKeysSole_state_payload_t;
   39.21 +
   39.22 +typedef struct _WaitForAcceptSole_state_payload {
   39.23 +    Identity expected;
   39.24 +    group_keys_extra_t* groupkeys;
   39.25 +} WaitForAcceptSole_state_payload_t;
   39.26 +
   39.27 +typedef struct _GroupedBeaconed_state_payload {
   39.28 +    Identity expected;
   39.29 +} GroupedBeaconed_state_payload_t;
   39.30 +
   39.31 +typedef struct _HandshakingGrouped_state_payload {
   39.32 +    Identity expected;
   39.33 +} HandshakingGrouped_state_payload_t;
   39.34 +
   39.35 +typedef struct _WaitForGroupKeysGrouped_state_payload {
   39.36 +    Identity expected;
   39.37 +} WaitForGroupKeysGrouped_state_payload_t;
   39.38 +
   39.39 +typedef struct _WaitForAcceptGrouped_state_payload {
   39.40 +    Identity expected;
   39.41 +    group_keys_extra_t* groupkeys;
   39.42 +} WaitForAcceptGrouped_state_payload_t;
   39.43 +
   39.44  
   39.45  // state machine for DeviceState
   39.46  
   39.47 @@ -12,29 +50,30 @@
   39.48          time_t *timeout
   39.49      )
   39.50  {
   39.51 -    int cond_result;
   39.52      PEP_STATUS status = PEP_STATUS_OK;
   39.53  
   39.54      switch (state) {
   39.55          case InitState:
   39.56          {
   39.57 -            *timeout = 0;
   39.58              DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=InitState")
   39.59              switch (event) {
   39.60                  case Init:
   39.61                  {
   39.62                      DEBUG_LOG("FSM event", "sync_fsm.c, state=InitState", "event=Init")
   39.63 -                    cond_result = storedGroupKeys(session);
   39.64 -                    #ifndef NDEBUG
   39.65 -                    char resstr[11] = {0,};
   39.66 -                    snprintf(resstr,10,"result=%d",cond_result);
   39.67 -                    #endif
   39.68 -                    DEBUG_LOG("FSM condition", "sync_fsm.c, state=InitState, event=Init, condition=storedGroupKeys", resstr)
   39.69 -                    if (cond_result < 0)
   39.70 -                        return cond_result;
   39.71 -                    if (cond_result) {
   39.72 +                    *timeout = 0;
   39.73 +                    {
   39.74 +                        int cond_result = deviceGrouped(session);
   39.75 +                        #ifndef NDEBUG
   39.76 +                        char resstr[11] = {0,};
   39.77 +                        snprintf(resstr,10,"result=%d",cond_result);
   39.78 +                        #endif
   39.79 +                        DEBUG_LOG("FSM condition", "sync_fsm.c, state=InitState, event=Init, condition=deviceGrouped", resstr)
   39.80 +                        if (cond_result < 0)
   39.81 +                            return cond_result;
   39.82 +                        if (cond_result) {
   39.83                          DEBUG_LOG("FSM transition", "sync_fsm.c, state=InitState, event=Init", "target=Grouped")
   39.84                          return Grouped;
   39.85 +                        }
   39.86                      }
   39.87                      DEBUG_LOG("FSM transition", "sync_fsm.c, state=InitState, event=Init", "target=Sole")
   39.88                      return Sole;
   39.89 @@ -46,10 +85,12 @@
   39.90          }
   39.91          case Sole:
   39.92          {
   39.93 -            *timeout = 0;
   39.94              DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=Sole")
   39.95              switch (event) {
   39.96 -                case Init: DEBUG_LOG("FSM event", "sync_fsm.c, state=Sole", "event=Init") break;
   39.97 +                case Init: 
   39.98 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=Sole", "event=Init") 
   39.99 +                    *timeout = 0;
  39.100 +                    break;
  39.101                  case KeyGen:
  39.102                  {
  39.103                      DEBUG_LOG("FSM event", "sync_fsm.c, state=Sole", "event=KeyGen")
  39.104 @@ -59,7 +100,8 @@
  39.105                          return (int) invalid_out_of_memory;
  39.106                      if (status != PEP_STATUS_OK)
  39.107                          return (int) invalid_action;
  39.108 -                    break;
  39.109 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=Sole, event=KeyGen", "target=SoleWaiting")
  39.110 +                    return SoleWaiting;
  39.111                  }
  39.112                  case CannotDecrypt:
  39.113                  {
  39.114 @@ -70,7 +112,8 @@
  39.115                          return (int) invalid_out_of_memory;
  39.116                      if (status != PEP_STATUS_OK)
  39.117                          return (int) invalid_action;
  39.118 -                    break;
  39.119 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=Sole, event=CannotDecrypt", "target=SoleWaiting")
  39.120 +                    return SoleWaiting;
  39.121                  }
  39.122                  case Beacon:
  39.123                  {
  39.124 @@ -81,7 +124,11 @@
  39.125                          return (int) invalid_out_of_memory;
  39.126                      if (status != PEP_STATUS_OK)
  39.127                          return (int) invalid_action;
  39.128 -                    session->sync_state_payload = identity_dup(partner);
  39.129 +                    session->sync_state_payload = malloc(sizeof(SoleBeaconed_state_payload_t));
  39.130 +                    assert(session->sync_state_payload);
  39.131 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory;
  39.132 +                    ((SoleBeaconed_state_payload_t*)session->sync_state_payload)->expected =
  39.133 +                        identity_dup(partner);
  39.134                      DEBUG_LOG("FSM transition", "sync_fsm.c, state=Sole, event=Beacon", "target=SoleBeaconed")
  39.135                      return SoleBeaconed;
  39.136                  }
  39.137 @@ -94,7 +141,11 @@
  39.138                          return (int) invalid_out_of_memory;
  39.139                      if (status != PEP_STATUS_OK)
  39.140                          return (int) invalid_action;
  39.141 -                    session->sync_state_payload = identity_dup(partner);
  39.142 +                    session->sync_state_payload = malloc(sizeof(HandshakingSole_state_payload_t));
  39.143 +                    assert(session->sync_state_payload);
  39.144 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory;
  39.145 +                    ((HandshakingSole_state_payload_t*)session->sync_state_payload)->expected =
  39.146 +                        identity_dup(partner);
  39.147                      DEBUG_LOG("FSM transition", "sync_fsm.c, state=Sole, event=HandshakeRequest", "target=HandshakingSole")
  39.148                      return HandshakingSole;
  39.149                  }
  39.150 @@ -103,13 +154,92 @@
  39.151              }
  39.152              break;
  39.153          }
  39.154 +        case SoleWaiting:
  39.155 +        {
  39.156 +            DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=SoleWaiting")
  39.157 +            switch (event) {
  39.158 +                case Init: 
  39.159 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleWaiting", "event=Init") 
  39.160 +                    *timeout = 60;
  39.161 +                    break;
  39.162 +                case KeyGen:
  39.163 +                {
  39.164 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleWaiting", "event=KeyGen")
  39.165 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=SoleWaiting, event=KeyGen", "action=sendBeacon")
  39.166 +                    status = sendBeacon(session, state, NULL, NULL);
  39.167 +                    if (status == PEP_OUT_OF_MEMORY)
  39.168 +                        return (int) invalid_out_of_memory;
  39.169 +                    if (status != PEP_STATUS_OK)
  39.170 +                        return (int) invalid_action;
  39.171 +                    break;
  39.172 +                }
  39.173 +                case CannotDecrypt:
  39.174 +                {
  39.175 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleWaiting", "event=CannotDecrypt")
  39.176 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=SoleWaiting, event=CannotDecrypt", "action=sendBeacon")
  39.177 +                    status = sendBeacon(session, state, NULL, NULL);
  39.178 +                    if (status == PEP_OUT_OF_MEMORY)
  39.179 +                        return (int) invalid_out_of_memory;
  39.180 +                    if (status != PEP_STATUS_OK)
  39.181 +                        return (int) invalid_action;
  39.182 +                    break;
  39.183 +                }
  39.184 +                case Beacon:
  39.185 +                {
  39.186 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleWaiting", "event=Beacon")
  39.187 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=SoleWaiting, event=Beacon", "action=sendHandshakeRequest")
  39.188 +                    status = sendHandshakeRequest(session, state, partner, NULL);
  39.189 +                    if (status == PEP_OUT_OF_MEMORY)
  39.190 +                        return (int) invalid_out_of_memory;
  39.191 +                    if (status != PEP_STATUS_OK)
  39.192 +                        return (int) invalid_action;
  39.193 +                    session->sync_state_payload = malloc(sizeof(SoleBeaconed_state_payload_t));
  39.194 +                    assert(session->sync_state_payload);
  39.195 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory;
  39.196 +                    ((SoleBeaconed_state_payload_t*)session->sync_state_payload)->expected =
  39.197 +                        identity_dup(partner);
  39.198 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=SoleWaiting, event=Beacon", "target=SoleBeaconed")
  39.199 +                    return SoleBeaconed;
  39.200 +                }
  39.201 +                case HandshakeRequest:
  39.202 +                {
  39.203 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleWaiting", "event=HandshakeRequest")
  39.204 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=SoleWaiting, event=HandshakeRequest", "action=sendHandshakeRequest")
  39.205 +                    status = sendHandshakeRequest(session, state, partner, NULL);
  39.206 +                    if (status == PEP_OUT_OF_MEMORY)
  39.207 +                        return (int) invalid_out_of_memory;
  39.208 +                    if (status != PEP_STATUS_OK)
  39.209 +                        return (int) invalid_action;
  39.210 +                    session->sync_state_payload = malloc(sizeof(HandshakingSole_state_payload_t));
  39.211 +                    assert(session->sync_state_payload);
  39.212 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory;
  39.213 +                    ((HandshakingSole_state_payload_t*)session->sync_state_payload)->expected =
  39.214 +                        identity_dup(partner);
  39.215 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=SoleWaiting, event=HandshakeRequest", "target=HandshakingSole")
  39.216 +                    return HandshakingSole;
  39.217 +                }
  39.218 +                case Timeout:
  39.219 +                {
  39.220 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleWaiting", "event=Timeout")
  39.221 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=SoleWaiting, event=Timeout", "target=Sole")
  39.222 +                    return Sole;
  39.223 +                }
  39.224 +                default:
  39.225 +                    return (DeviceState_state) invalid_event;
  39.226 +            }
  39.227 +            break;
  39.228 +        }
  39.229          case SoleBeaconed:
  39.230          {
  39.231 -            Identity expected = (Identity)session->sync_state_payload;
  39.232 -            *timeout = 600;
  39.233              DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=SoleBeaconed")
  39.234 +            assert(session->sync_state_payload);
  39.235 +            if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  39.236 +            Identity expected = ((SoleBeaconed_state_payload_t*)session->sync_state_payload)->expected;
  39.237              switch (event) {
  39.238 -                case Init: DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleBeaconed", "event=Init") break;
  39.239 +                case Init: 
  39.240 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleBeaconed", "event=Init") 
  39.241 +                    *timeout = 600;
  39.242 +                    break;
  39.243                  case KeyGen:
  39.244                  {
  39.245                      DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleBeaconed", "event=KeyGen")
  39.246 @@ -119,10 +249,11 @@
  39.247                          return (int) invalid_out_of_memory;
  39.248                      if (status != PEP_STATUS_OK)
  39.249                          return (int) invalid_action;
  39.250 -                    if(session->sync_state_payload){
  39.251 -                        free_identity((Identity)session->sync_state_payload);
  39.252 -                        session->sync_state_payload = NULL;
  39.253 -                    }
  39.254 +                    assert(session->sync_state_payload);
  39.255 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  39.256 +                    free_identity(((SoleBeaconed_state_payload_t*)session->sync_state_payload)->expected);
  39.257 +                    free(session->sync_state_payload);
  39.258 +                    session->sync_state_payload = NULL;
  39.259                      DEBUG_LOG("FSM transition", "sync_fsm.c, state=SoleBeaconed, event=KeyGen", "target=Sole")
  39.260                      return Sole;
  39.261                  }
  39.262 @@ -135,10 +266,11 @@
  39.263                          return (int) invalid_out_of_memory;
  39.264                      if (status != PEP_STATUS_OK)
  39.265                          return (int) invalid_action;
  39.266 -                    if(session->sync_state_payload){
  39.267 -                        free_identity((Identity)session->sync_state_payload);
  39.268 -                        session->sync_state_payload = NULL;
  39.269 -                    }
  39.270 +                    assert(session->sync_state_payload);
  39.271 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  39.272 +                    free_identity(((SoleBeaconed_state_payload_t*)session->sync_state_payload)->expected);
  39.273 +                    free(session->sync_state_payload);
  39.274 +                    session->sync_state_payload = NULL;
  39.275                      DEBUG_LOG("FSM transition", "sync_fsm.c, state=SoleBeaconed, event=CannotDecrypt", "target=Sole")
  39.276                      return Sole;
  39.277                  }
  39.278 @@ -151,50 +283,63 @@
  39.279                          return (int) invalid_out_of_memory;
  39.280                      if (status != PEP_STATUS_OK)
  39.281                          return (int) invalid_action;
  39.282 -                    if(session->sync_state_payload){
  39.283 -                        free_identity((Identity)session->sync_state_payload);
  39.284 -                        session->sync_state_payload = NULL;
  39.285 -                    }
  39.286 -                    session->sync_state_payload = identity_dup(partner);
  39.287 +                    assert(session->sync_state_payload);
  39.288 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  39.289 +                    free_identity(((SoleBeaconed_state_payload_t*)session->sync_state_payload)->expected);
  39.290 +                    free(session->sync_state_payload);
  39.291 +                    session->sync_state_payload = NULL;
  39.292 +                    session->sync_state_payload = malloc(sizeof(SoleBeaconed_state_payload_t));
  39.293 +                    assert(session->sync_state_payload);
  39.294 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory;
  39.295 +                    ((SoleBeaconed_state_payload_t*)session->sync_state_payload)->expected =
  39.296 +                        identity_dup(partner);
  39.297                      DEBUG_LOG("FSM transition", "sync_fsm.c, state=SoleBeaconed, event=Beacon", "target=SoleBeaconed")
  39.298                      return SoleBeaconed;
  39.299                  }
  39.300                  case HandshakeRequest:
  39.301                  {
  39.302                      DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleBeaconed", "event=HandshakeRequest")
  39.303 -                    cond_result = sameIdentities(session, partner, expected);
  39.304 -                    #ifndef NDEBUG
  39.305 -                    char resstr[11] = {0,};
  39.306 -                    snprintf(resstr,10,"result=%d",cond_result);
  39.307 -                    #endif
  39.308 -                    DEBUG_LOG("FSM condition", "sync_fsm.c, state=SoleBeaconed, event=HandshakeRequest, condition=sameIdentities", resstr)
  39.309 -                    if (cond_result < 0)
  39.310 -                        return cond_result;
  39.311 -                    if (cond_result) {
  39.312 -                    }
  39.313 -                    else {
  39.314 +                    {
  39.315 +                        int cond_result = sameIdentities(session, partner, expected);
  39.316 +                        #ifndef NDEBUG
  39.317 +                        char resstr[11] = {0,};
  39.318 +                        snprintf(resstr,10,"result=%d",cond_result);
  39.319 +                        #endif
  39.320 +                        DEBUG_LOG("FSM condition", "sync_fsm.c, state=SoleBeaconed, event=HandshakeRequest, condition=sameIdentities", resstr)
  39.321 +                        if (cond_result < 0)
  39.322 +                            return cond_result;
  39.323 +                        if (cond_result) {
  39.324 +                        }
  39.325 +                        else {
  39.326                          DEBUG_LOG("FSM action", "sync_fsm.c, state=SoleBeaconed, event=HandshakeRequest", "action=sendHandshakeRequest")
  39.327                          status = sendHandshakeRequest(session, state, partner, NULL);
  39.328                          if (status == PEP_OUT_OF_MEMORY)
  39.329                              return (int) invalid_out_of_memory;
  39.330                          if (status != PEP_STATUS_OK)
  39.331                              return (int) invalid_action;
  39.332 +                        }
  39.333                      }
  39.334 -                    if(session->sync_state_payload){
  39.335 -                        free_identity((Identity)session->sync_state_payload);
  39.336 -                        session->sync_state_payload = NULL;
  39.337 -                    }
  39.338 -                    session->sync_state_payload = identity_dup(partner);
  39.339 +                    assert(session->sync_state_payload);
  39.340 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  39.341 +                    free_identity(((SoleBeaconed_state_payload_t*)session->sync_state_payload)->expected);
  39.342 +                    free(session->sync_state_payload);
  39.343 +                    session->sync_state_payload = NULL;
  39.344 +                    session->sync_state_payload = malloc(sizeof(HandshakingSole_state_payload_t));
  39.345 +                    assert(session->sync_state_payload);
  39.346 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory;
  39.347 +                    ((HandshakingSole_state_payload_t*)session->sync_state_payload)->expected =
  39.348 +                        identity_dup(partner);
  39.349                      DEBUG_LOG("FSM transition", "sync_fsm.c, state=SoleBeaconed, event=HandshakeRequest", "target=HandshakingSole")
  39.350                      return HandshakingSole;
  39.351                  }
  39.352                  case Timeout:
  39.353                  {
  39.354                      DEBUG_LOG("FSM event", "sync_fsm.c, state=SoleBeaconed", "event=Timeout")
  39.355 -                    if(session->sync_state_payload){
  39.356 -                        free_identity((Identity)session->sync_state_payload);
  39.357 -                        session->sync_state_payload = NULL;
  39.358 -                    }
  39.359 +                    assert(session->sync_state_payload);
  39.360 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  39.361 +                    free_identity(((SoleBeaconed_state_payload_t*)session->sync_state_payload)->expected);
  39.362 +                    free(session->sync_state_payload);
  39.363 +                    session->sync_state_payload = NULL;
  39.364                      DEBUG_LOG("FSM transition", "sync_fsm.c, state=SoleBeaconed, event=Timeout", "target=Sole")
  39.365                      return Sole;
  39.366                  }
  39.367 @@ -205,36 +350,40 @@
  39.368          }
  39.369          case HandshakingSole:
  39.370          {
  39.371 -            Identity expected = (Identity)session->sync_state_payload;
  39.372 -            *timeout = 600;
  39.373              DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=HandshakingSole")
  39.374 +            assert(session->sync_state_payload);
  39.375 +            if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  39.376 +            Identity expected = ((HandshakingSole_state_payload_t*)session->sync_state_payload)->expected;
  39.377              switch (event) {
  39.378                  case Init:
  39.379                  {
  39.380                      DEBUG_LOG("FSM event", "sync_fsm.c, state=HandshakingSole", "event=Init")
  39.381 -                    cond_result = keyElectionWon(session, partner);
  39.382 -                    #ifndef NDEBUG
  39.383 -                    char resstr[11] = {0,};
  39.384 -                    snprintf(resstr,10,"result=%d",cond_result);
  39.385 -                    #endif
  39.386 -                    DEBUG_LOG("FSM condition", "sync_fsm.c, state=HandshakingSole, event=Init, condition=keyElectionWon", resstr)
  39.387 -                    if (cond_result < 0)
  39.388 -                        return cond_result;
  39.389 -                    if (cond_result) {
  39.390 +                    *timeout = 600;
  39.391 +                    {
  39.392 +                        int cond_result = keyElectionWon(session, expected);
  39.393 +                        #ifndef NDEBUG
  39.394 +                        char resstr[11] = {0,};
  39.395 +                        snprintf(resstr,10,"result=%d",cond_result);
  39.396 +                        #endif
  39.397 +                        DEBUG_LOG("FSM condition", "sync_fsm.c, state=HandshakingSole, event=Init, condition=keyElectionWon", resstr)
  39.398 +                        if (cond_result < 0)
  39.399 +                            return cond_result;
  39.400 +                        if (cond_result) {
  39.401                          DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingSole, event=Init", "action=notifyInitFormGroup")
  39.402 -                        status = notifyInitFormGroup(session, state, partner, NULL);
  39.403 +                        status = notifyInitFormGroup(session, state, expected, NULL);
  39.404                          if (status == PEP_OUT_OF_MEMORY)
  39.405                              return (int) invalid_out_of_memory;
  39.406                          if (status != PEP_STATUS_OK)
  39.407                              return (int) invalid_action;
  39.408 -                    }
  39.409 -                    else {
  39.410 +                        }
  39.411 +                        else {
  39.412                          DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingSole, event=Init", "action=notifyInitAddOurDevice")
  39.413 -                        status = notifyInitAddOurDevice(session, state, partner, NULL);
  39.414 +                        status = notifyInitAddOurDevice(session, state, expected, NULL);
  39.415                          if (status == PEP_OUT_OF_MEMORY)
  39.416                              return (int) invalid_out_of_memory;
  39.417                          if (status != PEP_STATUS_OK)
  39.418                              return (int) invalid_action;
  39.419 +                        }
  39.420                      }
  39.421                      break;
  39.422                  }
  39.423 @@ -247,68 +396,155 @@
  39.424                          return (int) invalid_out_of_memory;
  39.425                      if (status != PEP_STATUS_OK)
  39.426                          return (int) invalid_action;
  39.427 -                    if(session->sync_state_payload){
  39.428 -                        free_identity((Identity)session->sync_state_payload);
  39.429 -                        session->sync_state_payload = NULL;
  39.430 -                    }
  39.431 +                    assert(session->sync_state_payload);
  39.432 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  39.433 +                    free_identity(((HandshakingSole_state_payload_t*)session->sync_state_payload)->expected);
  39.434 +                    free(session->sync_state_payload);
  39.435 +                    session->sync_state_payload = NULL;
  39.436                      DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingSole, event=HandshakeRejected", "target=Sole")
  39.437                      return Sole;
  39.438                  }
  39.439                  case HandshakeAccepted:
  39.440                  {
  39.441                      DEBUG_LOG("FSM event", "sync_fsm.c, state=HandshakingSole", "event=HandshakeAccepted")
  39.442 -                    DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted", "action=acceptHandshake")
  39.443 -                    status = acceptHandshake(session, state, partner, NULL);
  39.444 -                    if (status == PEP_OUT_OF_MEMORY)
  39.445 -                        return (int) invalid_out_of_memory;
  39.446 -                    if (status != PEP_STATUS_OK)
  39.447 -                        return (int) invalid_action;
  39.448 -                    cond_result = keyElectionWon(session, partner);
  39.449 -                    #ifndef NDEBUG
  39.450 -                    char resstr[11] = {0,};
  39.451 -                    snprintf(resstr,10,"result=%d",cond_result);
  39.452 -                    #endif
  39.453 -                    DEBUG_LOG("FSM condition", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted, condition=keyElectionWon", resstr)
  39.454 -                    if (cond_result < 0)
  39.455 -                        return cond_result;
  39.456 -                    if (cond_result) {
  39.457 -                        DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted", "action=sendGroupKeys")
  39.458 -                        status = sendGroupKeys(session, state, partner, NULL);
  39.459 +                    {
  39.460 +                        int cond_result = sameIdentities(session, partner, expected);
  39.461 +                        #ifndef NDEBUG
  39.462 +                        char resstr[11] = {0,};
  39.463 +                        snprintf(resstr,10,"result=%d",cond_result);
  39.464 +                        #endif
  39.465 +                        DEBUG_LOG("FSM condition", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted, condition=sameIdentities", resstr)
  39.466 +                        if (cond_result < 0)
  39.467 +                            return cond_result;
  39.468 +                        if (cond_result) {
  39.469 +                        DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted", "action=acceptHandshake")
  39.470 +                        status = acceptHandshake(session, state, partner, NULL);
  39.471                          if (status == PEP_OUT_OF_MEMORY)
  39.472                              return (int) invalid_out_of_memory;
  39.473                          if (status != PEP_STATUS_OK)
  39.474                              return (int) invalid_action;
  39.475 -                        DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted", "action=notifyAcceptedGroupCreated")
  39.476 -                        status = notifyAcceptedGroupCreated(session, state, partner, NULL);
  39.477 -                        if (status == PEP_OUT_OF_MEMORY)
  39.478 -                            return (int) invalid_out_of_memory;
  39.479 -                        if (status != PEP_STATUS_OK)
  39.480 -                            return (int) invalid_action;
  39.481 -                        if(session->sync_state_payload){
  39.482 -                            free_identity((Identity)session->sync_state_payload);
  39.483 +                        {
  39.484 +                            int cond_result = keyElectionWon(session, partner);
  39.485 +                            #ifndef NDEBUG
  39.486 +                            char resstr[11] = {0,};
  39.487 +                            snprintf(resstr,10,"result=%d",cond_result);
  39.488 +                            #endif
  39.489 +                            DEBUG_LOG("FSM condition", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted, condition=keyElectionWon", resstr)
  39.490 +                            if (cond_result < 0)
  39.491 +                                return cond_result;
  39.492 +                            if (cond_result) {
  39.493 +                            DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted", "action=makeGroup")
  39.494 +                            status = makeGroup(session, state, NULL, NULL);
  39.495 +                            if (status == PEP_OUT_OF_MEMORY)
  39.496 +                                return (int) invalid_out_of_memory;
  39.497 +                            if (status != PEP_STATUS_OK)
  39.498 +                                return (int) invalid_action;
  39.499 +                            DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted", "action=sendGroupKeys")
  39.500 +                            status = sendGroupKeys(session, state, partner, NULL);
  39.501 +                            if (status == PEP_OUT_OF_MEMORY)
  39.502 +                                return (int) invalid_out_of_memory;
  39.503 +                            if (status != PEP_STATUS_OK)
  39.504 +                                return (int) invalid_action;
  39.505 +                            DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted", "action=renewUUID")
  39.506 +                            status = renewUUID(session, state, NULL, NULL);
  39.507 +                            if (status == PEP_OUT_OF_MEMORY)
  39.508 +                                return (int) invalid_out_of_memory;
  39.509 +                            if (status != PEP_STATUS_OK)
  39.510 +                                return (int) invalid_action;
  39.511 +                            DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted", "action=notifyAcceptedGroupCreated")
  39.512 +                            status = notifyAcceptedGroupCreated(session, state, partner, NULL);
  39.513 +                            if (status == PEP_OUT_OF_MEMORY)
  39.514 +                                return (int) invalid_out_of_memory;
  39.515 +                            if (status != PEP_STATUS_OK)
  39.516 +                                return (int) invalid_action;
  39.517 +                            assert(session->sync_state_payload);
  39.518 +                            if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  39.519 +                            free_identity(((HandshakingSole_state_payload_t*)session->sync_state_payload)->expected);
  39.520 +                            free(session->sync_state_payload);
  39.521                              session->sync_state_payload = NULL;
  39.522 +                            DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted", "target=Grouped")
  39.523 +                            return Grouped;
  39.524 +                            }
  39.525                          }
  39.526 -                        DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted", "target=Grouped")
  39.527 -                        return Grouped;
  39.528 +                        assert(session->sync_state_payload);
  39.529 +                        if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  39.530 +                        free_identity(((HandshakingSole_state_payload_t*)session->sync_state_payload)->expected);
  39.531 +                        free(session->sync_state_payload);
  39.532 +                        session->sync_state_payload = NULL;
  39.533 +                        session->sync_state_payload = malloc(sizeof(WaitForGroupKeysSole_state_payload_t));
  39.534 +                        assert(session->sync_state_payload);
  39.535 +                        if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory;
  39.536 +                        ((WaitForGroupKeysSole_state_payload_t*)session->sync_state_payload)->expected =
  39.537 +                            identity_dup(partner);
  39.538 +                        DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted", "target=WaitForGroupKeysSole")
  39.539 +                        return WaitForGroupKeysSole;
  39.540 +                        }
  39.541                      }
  39.542 -                    if(session->sync_state_payload){
  39.543 -                        free_identity((Identity)session->sync_state_payload);
  39.544 -                        session->sync_state_payload = NULL;
  39.545 -                    }
  39.546 -                    session->sync_state_payload = identity_dup(partner);
  39.547 -                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted", "target=WaitForGroupKeysSole")
  39.548 -                    return WaitForGroupKeysSole;
  39.549 +                    assert(session->sync_state_payload);
  39.550 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  39.551 +                    free_identity(((HandshakingSole_state_payload_t*)session->sync_state_payload)->expected);
  39.552 +                    free(session->sync_state_payload);
  39.553 +                    session->sync_state_payload = NULL;
  39.554 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingSole, event=HandshakeAccepted", "target=Sole")
  39.555 +                    return Sole;
  39.556                  }
  39.557                  case Cancel:
  39.558                  {
  39.559                      DEBUG_LOG("FSM event", "sync_fsm.c, state=HandshakingSole", "event=Cancel")
  39.560 -                    if(session->sync_state_payload){
  39.561 -                        free_identity((Identity)session->sync_state_payload);
  39.562 -                        session->sync_state_payload = NULL;
  39.563 -                    }
  39.564 +                    assert(session->sync_state_payload);
  39.565 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  39.566 +                    free_identity(((HandshakingSole_state_payload_t*)session->sync_state_payload)->expected);
  39.567 +                    free(session->sync_state_payload);
  39.568 +                    session->sync_state_payload = NULL;
  39.569                      DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingSole, event=Cancel", "target=Sole")
  39.570                      return Sole;
  39.571                  }
  39.572 +                case GroupKeys:
  39.573 +                {
  39.574 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=HandshakingSole", "event=GroupKeys")
  39.575 +                    group_keys_extra_t* groupkeys = (group_keys_extra_t*)extra;
  39.576 +                    {
  39.577 +                        int cond_result = keyElectionWon(session, expected);
  39.578 +                        #ifndef NDEBUG
  39.579 +                        char resstr[11] = {0,};
  39.580 +                        snprintf(resstr,10,"result=%d",cond_result);
  39.581 +                        #endif
  39.582 +                        DEBUG_LOG("FSM condition", "sync_fsm.c, state=HandshakingSole, event=GroupKeys, condition=keyElectionWon", resstr)
  39.583 +                        if (cond_result < 0)
  39.584 +                            return cond_result;
  39.585 +                        if (cond_result) {
  39.586 +                        }
  39.587 +                        else {
  39.588 +                        {
  39.589 +                            int cond_result = sameKeyAndAddress(session, partner, expected);
  39.590 +                            #ifndef NDEBUG
  39.591 +                            char resstr[11] = {0,};
  39.592 +                            snprintf(resstr,10,"result=%d",cond_result);
  39.593 +                            #endif
  39.594 +                            DEBUG_LOG("FSM condition", "sync_fsm.c, state=HandshakingSole, event=GroupKeys, condition=sameKeyAndAddress", resstr)
  39.595 +                            if (cond_result < 0)
  39.596 +                                return cond_result;
  39.597 +                            if (cond_result) {
  39.598 +                            assert(session->sync_state_payload);
  39.599 +                            if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  39.600 +                            free_identity(((HandshakingSole_state_payload_t*)session->sync_state_payload)->expected);
  39.601 +                            free(session->sync_state_payload);
  39.602 +                            session->sync_state_payload = NULL;
  39.603 +                            session->sync_state_payload = malloc(sizeof(WaitForAcceptSole_state_payload_t));
  39.604 +                            assert(session->sync_state_payload);
  39.605 +                            if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory;
  39.606 +                            ((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->expected =
  39.607 +                                identity_dup(partner);
  39.608 +                            ((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->groupkeys =
  39.609 +                                group_keys_extra_dup(groupkeys);
  39.610 +                            DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingSole, event=GroupKeys", "target=WaitForAcceptSole")
  39.611 +                            return WaitForAcceptSole;
  39.612 +                            }
  39.613 +                        }
  39.614 +                        }
  39.615 +                    }
  39.616 +                    break;
  39.617 +                }
  39.618                  case Timeout:
  39.619                  {
  39.620                      DEBUG_LOG("FSM event", "sync_fsm.c, state=HandshakingSole", "event=Timeout")
  39.621 @@ -324,10 +560,11 @@
  39.622                          return (int) invalid_out_of_memory;
  39.623                      if (status != PEP_STATUS_OK)
  39.624                          return (int) invalid_action;
  39.625 -                    if(session->sync_state_payload){
  39.626 -                        free_identity((Identity)session->sync_state_payload);
  39.627 -                        session->sync_state_payload = NULL;
  39.628 -                    }
  39.629 +                    assert(session->sync_state_payload);
  39.630 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  39.631 +                    free_identity(((HandshakingSole_state_payload_t*)session->sync_state_payload)->expected);
  39.632 +                    free(session->sync_state_payload);
  39.633 +                    session->sync_state_payload = NULL;
  39.634                      DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingSole, event=Timeout", "target=Sole")
  39.635                      return Sole;
  39.636                  }
  39.637 @@ -338,25 +575,43 @@
  39.638          }
  39.639          case WaitForGroupKeysSole:
  39.640          {
  39.641 -            Identity expected = (Identity)session->sync_state_payload;
  39.642 -            *timeout = 600;
  39.643              DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=WaitForGroupKeysSole")
  39.644 +            assert(session->sync_state_payload);
  39.645 +            if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  39.646 +            Identity expected = ((WaitForGroupKeysSole_state_payload_t*)session->sync_state_payload)->expected;
  39.647              switch (event) {
  39.648 -                case Init: DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForGroupKeysSole", "event=Init") break;
  39.649 +                case Init: 
  39.650 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForGroupKeysSole", "event=Init") 
  39.651 +                    *timeout = 600;
  39.652 +                    break;
  39.653                  case GroupKeys:
  39.654                  {
  39.655                      DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForGroupKeysSole", "event=GroupKeys")
  39.656 -                    cond_result = sameIdentities(session, partner, expected);
  39.657 -                    #ifndef NDEBUG
  39.658 -                    char resstr[11] = {0,};
  39.659 -                    snprintf(resstr,10,"result=%d",cond_result);
  39.660 -                    #endif
  39.661 -                    DEBUG_LOG("FSM condition", "sync_fsm.c, state=WaitForGroupKeysSole, event=GroupKeys, condition=sameIdentities", resstr)
  39.662 -                    if (cond_result < 0)
  39.663 -                        return cond_result;
  39.664 -                    if (cond_result) {
  39.665 +                    group_keys_extra_t* groupkeys = (group_keys_extra_t*)extra;
  39.666 +                    {
  39.667 +                        int cond_result = sameKeyAndAddress(session, partner, expected);
  39.668 +                        #ifndef NDEBUG
  39.669 +                        char resstr[11] = {0,};
  39.670 +                        snprintf(resstr,10,"result=%d",cond_result);
  39.671 +                        #endif
  39.672 +                        DEBUG_LOG("FSM condition", "sync_fsm.c, state=WaitForGroupKeysSole, event=GroupKeys, condition=sameKeyAndAddress", resstr)
  39.673 +                        if (cond_result < 0)
  39.674 +                            return cond_result;
  39.675 +                        if (cond_result) {
  39.676                          DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForGroupKeysSole, event=GroupKeys", "action=storeGroupKeys")
  39.677 -                        status = storeGroupKeys(session, state, partner, extra /*keys*/);
  39.678 +                        status = storeGroupKeys(session, state, partner, groupkeys);
  39.679 +                        if (status == PEP_OUT_OF_MEMORY)
  39.680 +                            return (int) invalid_out_of_memory;
  39.681 +                        if (status != PEP_STATUS_OK)
  39.682 +                            return (int) invalid_action;
  39.683 +                        DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForGroupKeysSole, event=GroupKeys", "action=sendGroupUpdate")
  39.684 +                        status = sendGroupUpdate(session, state, NULL, NULL);
  39.685 +                        if (status == PEP_OUT_OF_MEMORY)
  39.686 +                            return (int) invalid_out_of_memory;
  39.687 +                        if (status != PEP_STATUS_OK)
  39.688 +                            return (int) invalid_action;
  39.689 +                        DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForGroupKeysSole, event=GroupKeys", "action=renewUUID")
  39.690 +                        status = renewUUID(session, state, NULL, NULL);
  39.691                          if (status == PEP_OUT_OF_MEMORY)
  39.692                              return (int) invalid_out_of_memory;
  39.693                          if (status != PEP_STATUS_OK)
  39.694 @@ -367,12 +622,14 @@
  39.695                              return (int) invalid_out_of_memory;
  39.696                          if (status != PEP_STATUS_OK)
  39.697                              return (int) invalid_action;
  39.698 -                        if(session->sync_state_payload){
  39.699 -                            free_identity((Identity)session->sync_state_payload);
  39.700 -                            session->sync_state_payload = NULL;
  39.701 -                        }
  39.702 +                        assert(session->sync_state_payload);
  39.703 +                        if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  39.704 +                        free_identity(((WaitForGroupKeysSole_state_payload_t*)session->sync_state_payload)->expected);
  39.705 +                        free(session->sync_state_payload);
  39.706 +                        session->sync_state_payload = NULL;
  39.707                          DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForGroupKeysSole, event=GroupKeys", "target=Grouped")
  39.708                          return Grouped;
  39.709 +                        }
  39.710                      }
  39.711                      break;
  39.712                  }
  39.713 @@ -385,11 +642,139 @@
  39.714                          return (int) invalid_out_of_memory;
  39.715                      if (status != PEP_STATUS_OK)
  39.716                          return (int) invalid_action;
  39.717 -                    if(session->sync_state_payload){
  39.718 -                        free_identity((Identity)session->sync_state_payload);
  39.719 +                    assert(session->sync_state_payload);
  39.720 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  39.721 +                    free_identity(((WaitForGroupKeysSole_state_payload_t*)session->sync_state_payload)->expected);
  39.722 +                    free(session->sync_state_payload);
  39.723 +                    session->sync_state_payload = NULL;
  39.724 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForGroupKeysSole, event=Timeout", "target=Sole")
  39.725 +                    return Sole;
  39.726 +                }
  39.727 +                default:
  39.728 +                    return (DeviceState_state) invalid_event;
  39.729 +            }
  39.730 +            break;
  39.731 +        }
  39.732 +        case WaitForAcceptSole:
  39.733 +        {
  39.734 +            DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=WaitForAcceptSole")
  39.735 +            assert(session->sync_state_payload);
  39.736 +            if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  39.737 +            Identity expected = ((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->expected;
  39.738 +            group_keys_extra_t* groupkeys = ((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->groupkeys;
  39.739 +            switch (event) {
  39.740 +                case Init: 
  39.741 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForAcceptSole", "event=Init") 
  39.742 +                    *timeout = 600;
  39.743 +                    break;
  39.744 +                case HandshakeRejected:
  39.745 +                {
  39.746 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForAcceptSole", "event=HandshakeRejected")
  39.747 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptSole, event=HandshakeRejected", "action=rejectHandshake")
  39.748 +                    status = rejectHandshake(session, state, partner, NULL);
  39.749 +                    if (status == PEP_OUT_OF_MEMORY)
  39.750 +                        return (int) invalid_out_of_memory;
  39.751 +                    if (status != PEP_STATUS_OK)
  39.752 +                        return (int) invalid_action;
  39.753 +                    assert(session->sync_state_payload);
  39.754 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  39.755 +                    free_identity(((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->expected);
  39.756 +                    free_group_keys_extra(((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->groupkeys);
  39.757 +                    free(session->sync_state_payload);
  39.758 +                    session->sync_state_payload = NULL;
  39.759 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForAcceptSole, event=HandshakeRejected", "target=Sole")
  39.760 +                    return Sole;
  39.761 +                }
  39.762 +                case HandshakeAccepted:
  39.763 +                {
  39.764 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForAcceptSole", "event=HandshakeAccepted")
  39.765 +                    {
  39.766 +                        int cond_result = sameKeyAndAddress(session, partner, expected);
  39.767 +                        #ifndef NDEBUG
  39.768 +                        char resstr[11] = {0,};
  39.769 +                        snprintf(resstr,10,"result=%d",cond_result);
  39.770 +                        #endif
  39.771 +                        DEBUG_LOG("FSM condition", "sync_fsm.c, state=WaitForAcceptSole, event=HandshakeAccepted, condition=sameKeyAndAddress", resstr)
  39.772 +                        if (cond_result < 0)
  39.773 +                            return cond_result;
  39.774 +                        if (cond_result) {
  39.775 +                        DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptSole, event=HandshakeAccepted", "action=acceptHandshake")
  39.776 +                        status = acceptHandshake(session, state, partner, NULL);
  39.777 +                        if (status == PEP_OUT_OF_MEMORY)
  39.778 +                            return (int) invalid_out_of_memory;
  39.779 +                        if (status != PEP_STATUS_OK)
  39.780 +                            return (int) invalid_action;
  39.781 +                        DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptSole, event=HandshakeAccepted", "action=storeGroupKeys")
  39.782 +                        status = storeGroupKeys(session, state, partner, groupkeys);
  39.783 +                        if (status == PEP_OUT_OF_MEMORY)
  39.784 +                            return (int) invalid_out_of_memory;
  39.785 +                        if (status != PEP_STATUS_OK)
  39.786 +                            return (int) invalid_action;
  39.787 +                        DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptSole, event=HandshakeAccepted", "action=sendGroupUpdate")
  39.788 +                        status = sendGroupUpdate(session, state, NULL, NULL);
  39.789 +                        if (status == PEP_OUT_OF_MEMORY)
  39.790 +                            return (int) invalid_out_of_memory;
  39.791 +                        if (status != PEP_STATUS_OK)
  39.792 +                            return (int) invalid_action;
  39.793 +                        DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptSole, event=HandshakeAccepted", "action=renewUUID")
  39.794 +                        status = renewUUID(session, state, NULL, NULL);
  39.795 +                        if (status == PEP_OUT_OF_MEMORY)
  39.796 +                            return (int) invalid_out_of_memory;
  39.797 +                        if (status != PEP_STATUS_OK)
  39.798 +                            return (int) invalid_action;
  39.799 +                        DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptSole, event=HandshakeAccepted", "action=notifyAcceptedDeviceAdded")
  39.800 +                        status = notifyAcceptedDeviceAdded(session, state, partner, NULL);
  39.801 +                        if (status == PEP_OUT_OF_MEMORY)
  39.802 +                            return (int) invalid_out_of_memory;
  39.803 +                        if (status != PEP_STATUS_OK)
  39.804 +                            return (int) invalid_action;
  39.805 +                        assert(session->sync_state_payload);
  39.806 +                        if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  39.807 +                        free_identity(((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->expected);
  39.808 +                        free_group_keys_extra(((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->groupkeys);
  39.809 +                        free(session->sync_state_payload);
  39.810                          session->sync_state_payload = NULL;
  39.811 +                        DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForAcceptSole, event=HandshakeAccepted", "target=Grouped")
  39.812 +                        return Grouped;
  39.813 +                        }
  39.814                      }
  39.815 -                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForGroupKeysSole, event=Timeout", "target=Sole")
  39.816 +                    assert(session->sync_state_payload);
  39.817 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  39.818 +                    free_identity(((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->expected);
  39.819 +                    free_group_keys_extra(((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->groupkeys);
  39.820 +                    free(session->sync_state_payload);
  39.821 +                    session->sync_state_payload = NULL;
  39.822 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForAcceptSole, event=HandshakeAccepted", "target=Sole")
  39.823 +                    return Sole;
  39.824 +                }
  39.825 +                case Cancel:
  39.826 +                {
  39.827 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForAcceptSole", "event=Cancel")
  39.828 +                    assert(session->sync_state_payload);
  39.829 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  39.830 +                    free_identity(((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->expected);
  39.831 +                    free_group_keys_extra(((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->groupkeys);
  39.832 +                    free(session->sync_state_payload);
  39.833 +                    session->sync_state_payload = NULL;
  39.834 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForAcceptSole, event=Cancel", "target=Sole")
  39.835 +                    return Sole;
  39.836 +                }
  39.837 +                case Timeout:
  39.838 +                {
  39.839 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForAcceptSole", "event=Timeout")
  39.840 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptSole, event=Timeout", "action=notifyTimeout")
  39.841 +                    status = notifyTimeout(session, state, expected, NULL);
  39.842 +                    if (status == PEP_OUT_OF_MEMORY)
  39.843 +                        return (int) invalid_out_of_memory;
  39.844 +                    if (status != PEP_STATUS_OK)
  39.845 +                        return (int) invalid_action;
  39.846 +                    assert(session->sync_state_payload);
  39.847 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
  39.848 +                    free_identity(((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->expected);
  39.849 +                    free_group_keys_extra(((WaitForAcceptSole_state_payload_t*)session->sync_state_payload)->groupkeys);
  39.850 +                    free(session->sync_state_payload);
  39.851 +                    session->sync_state_payload = NULL;
  39.852 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForAcceptSole, event=Timeout", "target=Sole")
  39.853                      return Sole;
  39.854                  }
  39.855                  default:
  39.856 @@ -399,20 +784,12 @@
  39.857          }
  39.858          case Grouped:
  39.859          {
  39.860 -            *timeout = 0;
  39.861              DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=Grouped")
  39.862              switch (event) {
  39.863 -                case Init:
  39.864 -                {
  39.865 -                    DEBUG_LOG("FSM event", "sync_fsm.c, state=Grouped", "event=Init")
  39.866 -                    DEBUG_LOG("FSM action", "sync_fsm.c, state=Grouped, event=Init", "action=enterGroup")
  39.867 -                    status = enterGroup(session, state, NULL, NULL);
  39.868 -                    if (status == PEP_OUT_OF_MEMORY)
  39.869 -                        return (int) invalid_out_of_memory;
  39.870 -                    if (status != PEP_STATUS_OK)
  39.871 -                        return (int) invalid_action;
  39.872 +                case Init: 
  39.873 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=Grouped", "event=Init") 
  39.874 +                    *timeout = 0;
  39.875                      break;
  39.876 -                }
  39.877                  case KeyGen:
  39.878                  {
  39.879                      DEBUG_LOG("FSM event", "sync_fsm.c, state=Grouped", "event=KeyGen")
  39.880 @@ -433,7 +810,14 @@
  39.881                          return (int) invalid_out_of_memory;
  39.882                      if (status != PEP_STATUS_OK)
  39.883                          return (int) invalid_action;
  39.884 -                    break;
  39.885 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=Grouped, event=CannotDecrypt", "action=sendBeacon")
  39.886 +                    status = sendBeacon(session, state, NULL, NULL);
  39.887 +                    if (status == PEP_OUT_OF_MEMORY)
  39.888 +                        return (int) invalid_out_of_memory;
  39.889 +                    if (status != PEP_STATUS_OK)
  39.890 +                        return (int) invalid_action;
  39.891 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=Grouped, event=CannotDecrypt", "target=GroupWaiting")
  39.892 +                    return GroupWaiting;
  39.893                  }
  39.894                  case UpdateRequest:
  39.895                  {
  39.896 @@ -455,7 +839,11 @@
  39.897                          return (int) invalid_out_of_memory;
  39.898                      if (status != PEP_STATUS_OK)
  39.899                          return (int) invalid_action;
  39.900 -                    session->sync_state_payload = identity_dup(partner);
  39.901 +                    session->sync_state_payload = malloc(sizeof(GroupedBeaconed_state_payload_t));
  39.902 +                    assert(session->sync_state_payload);
  39.903 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory;
  39.904 +                    ((GroupedBeaconed_state_payload_t*)session->sync_state_payload)->expected =
  39.905 +                        identity_dup(partner);
  39.906                      DEBUG_LOG("FSM transition", "sync_fsm.c, state=Grouped, event=Beacon", "target=GroupedBeaconed")
  39.907                      return GroupedBeaconed;
  39.908                  }
  39.909 @@ -468,15 +856,20 @@
  39.910                          return (int) invalid_out_of_memory;
  39.911                      if (status != PEP_STATUS_OK)
  39.912                          return (int) invalid_action;
  39.913 -                    session->sync_state_payload = identity_dup(partner);
  39.914 +                    session->sync_state_payload = malloc(sizeof(HandshakingGrouped_state_payload_t));
  39.915 +                    assert(session->sync_state_payload);
  39.916 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory;
  39.917 +                    ((HandshakingGrouped_state_payload_t*)session->sync_state_payload)->expected =
  39.918 +                        identity_dup(partner);
  39.919                      DEBUG_LOG("FSM transition", "sync_fsm.c, state=Grouped, event=HandshakeRequest", "target=HandshakingGrouped")
  39.920                      return HandshakingGrouped;
  39.921                  }
  39.922                  case GroupUpdate:
  39.923                  {
  39.924                      DEBUG_LOG("FSM event", "sync_fsm.c, state=Grouped", "event=GroupUpdate")
  39.925 -                    DEBUG_LOG("FSM action", "sync_fsm.c, state=Grouped, event=GroupUpdate", "action=storeGroupKeys")
  39.926 -                    status = storeGroupKeys(session, state, partner, extra /*keys*/);
  39.927 +                    identity_list* keys = (identity_list*)extra;
  39.928 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=Grouped, event=GroupUpdate", "action=storeGroupUpdate")
  39.929 +                    status = storeGroupUpdate(session, state, partner, keys);
  39.930                      if (status == PEP_OUT_OF_MEMORY)
  39.931                          return (int) invalid_out_of_memory;
  39.932                      if (status != PEP_STATUS_OK)
  39.933 @@ -488,13 +881,121 @@
  39.934              }
  39.935              break;
  39.936          }
  39.937 +        case GroupWaiting:
  39.938 +        {
  39.939 +            DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=GroupWaiting")
  39.940 +            switch (event) {
  39.941 +                case Init: 
  39.942 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupWaiting", "event=Init") 
  39.943 +                    *timeout = 60;
  39.944 +                    break;
  39.945 +                case KeyGen:
  39.946 +                {
  39.947 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupWaiting", "event=KeyGen")
  39.948 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupWaiting, event=KeyGen", "action=sendGroupUpdate")
  39.949 +                    status = sendGroupUpdate(session, state, NULL, NULL);
  39.950 +                    if (status == PEP_OUT_OF_MEMORY)
  39.951 +                        return (int) invalid_out_of_memory;
  39.952 +                    if (status != PEP_STATUS_OK)
  39.953 +                        return (int) invalid_action;
  39.954 +                    break;
  39.955 +                }
  39.956 +                case CannotDecrypt:
  39.957 +                {
  39.958 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupWaiting", "event=CannotDecrypt")
  39.959 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupWaiting, event=CannotDecrypt", "action=sendUpdateRequest")
  39.960 +                    status = sendUpdateRequest(session, state, NULL, NULL);
  39.961 +                    if (status == PEP_OUT_OF_MEMORY)
  39.962 +                        return (int) invalid_out_of_memory;
  39.963 +                    if (status != PEP_STATUS_OK)
  39.964 +                        return (int) invalid_action;
  39.965 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupWaiting, event=CannotDecrypt", "action=sendBeacon")
  39.966 +                    status = sendBeacon(session, state, NULL, NULL);
  39.967 +                    if (status == PEP_OUT_OF_MEMORY)
  39.968 +                        return (int) invalid_out_of_memory;
  39.969 +                    if (status != PEP_STATUS_OK)
  39.970 +                        return (int) invalid_action;
  39.971 +                    break;
  39.972 +                }
  39.973 +                case UpdateRequest:
  39.974 +                {
  39.975 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupWaiting", "event=UpdateRequest")
  39.976 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupWaiting, event=UpdateRequest", "action=sendGroupUpdate")
  39.977 +                    status = sendGroupUpdate(session, state, NULL, NULL);
  39.978 +                    if (status == PEP_OUT_OF_MEMORY)
  39.979 +                        return (int) invalid_out_of_memory;
  39.980 +                    if (status != PEP_STATUS_OK)
  39.981 +                        return (int) invalid_action;
  39.982 +                    break;
  39.983 +                }
  39.984 +                case Beacon:
  39.985 +                {
  39.986 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupWaiting", "event=Beacon")
  39.987 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupWaiting, event=Beacon", "action=sendHandshakeRequest")
  39.988 +                    status = sendHandshakeRequest(session, state, partner, NULL);
  39.989 +                    if (status == PEP_OUT_OF_MEMORY)
  39.990 +                        return (int) invalid_out_of_memory;
  39.991 +                    if (status != PEP_STATUS_OK)
  39.992 +                        return (int) invalid_action;
  39.993 +                    session->sync_state_payload = malloc(sizeof(GroupedBeaconed_state_payload_t));
  39.994 +                    assert(session->sync_state_payload);
  39.995 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory;
  39.996 +                    ((GroupedBeaconed_state_payload_t*)session->sync_state_payload)->expected =
  39.997 +                        identity_dup(partner);
  39.998 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=GroupWaiting, event=Beacon", "target=GroupedBeaconed")
  39.999 +                    return GroupedBeaconed;
 39.1000 +                }
 39.1001 +                case HandshakeRequest:
 39.1002 +                {
 39.1003 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupWaiting", "event=HandshakeRequest")
 39.1004 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupWaiting, event=HandshakeRequest", "action=sendHandshakeRequest")
 39.1005 +                    status = sendHandshakeRequest(session, state, partner, NULL);
 39.1006 +                    if (status == PEP_OUT_OF_MEMORY)
 39.1007 +                        return (int) invalid_out_of_memory;
 39.1008 +                    if (status != PEP_STATUS_OK)
 39.1009 +                        return (int) invalid_action;
 39.1010 +                    session->sync_state_payload = malloc(sizeof(HandshakingGrouped_state_payload_t));
 39.1011 +                    assert(session->sync_state_payload);
 39.1012 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory;
 39.1013 +                    ((HandshakingGrouped_state_payload_t*)session->sync_state_payload)->expected =
 39.1014 +                        identity_dup(partner);
 39.1015 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=GroupWaiting, event=HandshakeRequest", "target=HandshakingGrouped")
 39.1016 +                    return HandshakingGrouped;
 39.1017 +                }
 39.1018 +                case GroupUpdate:
 39.1019 +                {
 39.1020 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupWaiting", "event=GroupUpdate")
 39.1021 +                    identity_list* keys = (identity_list*)extra;
 39.1022 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupWaiting, event=GroupUpdate", "action=storeGroupUpdate")
 39.1023 +                    status = storeGroupUpdate(session, state, partner, keys);
 39.1024 +                    if (status == PEP_OUT_OF_MEMORY)
 39.1025 +                        return (int) invalid_out_of_memory;
 39.1026 +                    if (status != PEP_STATUS_OK)
 39.1027 +                        return (int) invalid_action;
 39.1028 +                    break;
 39.1029 +                }
 39.1030 +                case Timeout:
 39.1031 +                {
 39.1032 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupWaiting", "event=Timeout")
 39.1033 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=GroupWaiting, event=Timeout", "target=Grouped")
 39.1034 +                    return Grouped;
 39.1035 +                }
 39.1036 +                default:
 39.1037 +                    return (DeviceState_state) invalid_event;
 39.1038 +            }
 39.1039 +            break;
 39.1040 +        }
 39.1041          case GroupedBeaconed:
 39.1042          {
 39.1043 -            Identity expected = (Identity)session->sync_state_payload;
 39.1044 -            *timeout = 600;
 39.1045              DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=GroupedBeaconed")
 39.1046 +            assert(session->sync_state_payload);
 39.1047 +            if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
 39.1048 +            Identity expected = ((GroupedBeaconed_state_payload_t*)session->sync_state_payload)->expected;
 39.1049              switch (event) {
 39.1050 -                case Init: DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupedBeaconed", "event=Init") break;
 39.1051 +                case Init: 
 39.1052 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupedBeaconed", "event=Init") 
 39.1053 +                    *timeout = 600;
 39.1054 +                    break;
 39.1055                  case KeyGen:
 39.1056                  {
 39.1057                      DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupedBeaconed", "event=KeyGen")
 39.1058 @@ -515,6 +1016,12 @@
 39.1059                          return (int) invalid_out_of_memory;
 39.1060                      if (status != PEP_STATUS_OK)
 39.1061                          return (int) invalid_action;
 39.1062 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupedBeaconed, event=CannotDecrypt", "action=sendBeacon")
 39.1063 +                    status = sendBeacon(session, state, NULL, NULL);
 39.1064 +                    if (status == PEP_OUT_OF_MEMORY)
 39.1065 +                        return (int) invalid_out_of_memory;
 39.1066 +                    if (status != PEP_STATUS_OK)
 39.1067 +                        return (int) invalid_action;
 39.1068                      break;
 39.1069                  }
 39.1070                  case UpdateRequest:
 39.1071 @@ -537,48 +1044,61 @@
 39.1072                          return (int) invalid_out_of_memory;
 39.1073                      if (status != PEP_STATUS_OK)
 39.1074                          return (int) invalid_action;
 39.1075 -                    if(session->sync_state_payload){
 39.1076 -                        free_identity((Identity)session->sync_state_payload);
 39.1077 -                        session->sync_state_payload = NULL;
 39.1078 -                    }
 39.1079 -                    session->sync_state_payload = identity_dup(partner);
 39.1080 +                    assert(session->sync_state_payload);
 39.1081 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
 39.1082 +                    free_identity(((GroupedBeaconed_state_payload_t*)session->sync_state_payload)->expected);
 39.1083 +                    free(session->sync_state_payload);
 39.1084 +                    session->sync_state_payload = NULL;
 39.1085 +                    session->sync_state_payload = malloc(sizeof(GroupedBeaconed_state_payload_t));
 39.1086 +                    assert(session->sync_state_payload);
 39.1087 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory;
 39.1088 +                    ((GroupedBeaconed_state_payload_t*)session->sync_state_payload)->expected =
 39.1089 +                        identity_dup(partner);
 39.1090                      DEBUG_LOG("FSM transition", "sync_fsm.c, state=GroupedBeaconed, event=Beacon", "target=GroupedBeaconed")
 39.1091                      return GroupedBeaconed;
 39.1092                  }
 39.1093                  case HandshakeRequest:
 39.1094                  {
 39.1095                      DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupedBeaconed", "event=HandshakeRequest")
 39.1096 -                    cond_result = sameIdentities(session, partner, expected);
 39.1097 -                    #ifndef NDEBUG
 39.1098 -                    char resstr[11] = {0,};
 39.1099 -                    snprintf(resstr,10,"result=%d",cond_result);
 39.1100 -                    #endif
 39.1101 -                    DEBUG_LOG("FSM condition", "sync_fsm.c, state=GroupedBeaconed, event=HandshakeRequest, condition=sameIdentities", resstr)
 39.1102 -                    if (cond_result < 0)
 39.1103 -                        return cond_result;
 39.1104 -                    if (cond_result) {
 39.1105 -                    }
 39.1106 -                    else {
 39.1107 +                    {
 39.1108 +                        int cond_result = sameIdentities(session, partner, expected);
 39.1109 +                        #ifndef NDEBUG
 39.1110 +                        char resstr[11] = {0,};
 39.1111 +                        snprintf(resstr,10,"result=%d",cond_result);
 39.1112 +                        #endif
 39.1113 +                        DEBUG_LOG("FSM condition", "sync_fsm.c, state=GroupedBeaconed, event=HandshakeRequest, condition=sameIdentities", resstr)
 39.1114 +                        if (cond_result < 0)
 39.1115 +                            return cond_result;
 39.1116 +                        if (cond_result) {
 39.1117 +                        }
 39.1118 +                        else {
 39.1119                          DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupedBeaconed, event=HandshakeRequest", "action=sendHandshakeRequest")
 39.1120                          status = sendHandshakeRequest(session, state, partner, NULL);
 39.1121                          if (status == PEP_OUT_OF_MEMORY)
 39.1122                              return (int) invalid_out_of_memory;
 39.1123                          if (status != PEP_STATUS_OK)
 39.1124                              return (int) invalid_action;
 39.1125 +                        }
 39.1126                      }
 39.1127 -                    if(session->sync_state_payload){
 39.1128 -                        free_identity((Identity)session->sync_state_payload);
 39.1129 -                        session->sync_state_payload = NULL;
 39.1130 -                    }
 39.1131 -                    session->sync_state_payload = identity_dup(partner);
 39.1132 +                    assert(session->sync_state_payload);
 39.1133 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
 39.1134 +                    free_identity(((GroupedBeaconed_state_payload_t*)session->sync_state_payload)->expected);
 39.1135 +                    free(session->sync_state_payload);
 39.1136 +                    session->sync_state_payload = NULL;
 39.1137 +                    session->sync_state_payload = malloc(sizeof(HandshakingGrouped_state_payload_t));
 39.1138 +                    assert(session->sync_state_payload);
 39.1139 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory;
 39.1140 +                    ((HandshakingGrouped_state_payload_t*)session->sync_state_payload)->expected =
 39.1141 +                        identity_dup(partner);
 39.1142                      DEBUG_LOG("FSM transition", "sync_fsm.c, state=GroupedBeaconed, event=HandshakeRequest", "target=HandshakingGrouped")
 39.1143                      return HandshakingGrouped;
 39.1144                  }
 39.1145                  case GroupUpdate:
 39.1146                  {
 39.1147                      DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupedBeaconed", "event=GroupUpdate")
 39.1148 -                    DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupedBeaconed, event=GroupUpdate", "action=storeGroupKeys")
 39.1149 -                    status = storeGroupKeys(session, state, partner, extra /*keys*/);
 39.1150 +                    identity_list* keys = (identity_list*)extra;
 39.1151 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=GroupedBeaconed, event=GroupUpdate", "action=storeGroupUpdate")
 39.1152 +                    status = storeGroupUpdate(session, state, partner, keys);
 39.1153                      if (status == PEP_OUT_OF_MEMORY)
 39.1154                          return (int) invalid_out_of_memory;
 39.1155                      if (status != PEP_STATUS_OK)
 39.1156 @@ -588,10 +1108,11 @@
 39.1157                  case Timeout:
 39.1158                  {
 39.1159                      DEBUG_LOG("FSM event", "sync_fsm.c, state=GroupedBeaconed", "event=Timeout")
 39.1160 -                    if(session->sync_state_payload){
 39.1161 -                        free_identity((Identity)session->sync_state_payload);
 39.1162 -                        session->sync_state_payload = NULL;
 39.1163 -                    }
 39.1164 +                    assert(session->sync_state_payload);
 39.1165 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
 39.1166 +                    free_identity(((GroupedBeaconed_state_payload_t*)session->sync_state_payload)->expected);
 39.1167 +                    free(session->sync_state_payload);
 39.1168 +                    session->sync_state_payload = NULL;
 39.1169                      DEBUG_LOG("FSM transition", "sync_fsm.c, state=GroupedBeaconed, event=Timeout", "target=Grouped")
 39.1170                      return Grouped;
 39.1171                  }
 39.1172 @@ -602,19 +1123,41 @@
 39.1173          }
 39.1174          case HandshakingGrouped:
 39.1175          {
 39.1176 -            Identity expected = (Identity)session->sync_state_payload;
 39.1177 -            *timeout = 600;
 39.1178              DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=HandshakingGrouped")
 39.1179 +            assert(session->sync_state_payload);
 39.1180 +            if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
 39.1181 +            Identity expected = ((HandshakingGrouped_state_payload_t*)session->sync_state_payload)->expected;
 39.1182              switch (event) {
 39.1183                  case Init:
 39.1184                  {
 39.1185                      DEBUG_LOG("FSM event", "sync_fsm.c, state=HandshakingGrouped", "event=Init")
 39.1186 -                    DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingGrouped, event=Init", "action=notifyInitAddOurDevice")
 39.1187 -                    status = notifyInitAddOurDevice(session, state, partner, NULL);
 39.1188 -                    if (status == PEP_OUT_OF_MEMORY)
 39.1189 -                        return (int) invalid_out_of_memory;
 39.1190 -                    if (status != PEP_STATUS_OK)
 39.1191 -                        return (int) invalid_action;
 39.1192 +                    *timeout = 600;
 39.1193 +                    {
 39.1194 +                        int cond_result = keyElectionWon(session, expected);
 39.1195 +                        #ifndef NDEBUG
 39.1196 +                        char resstr[11] = {0,};
 39.1197 +                        snprintf(resstr,10,"result=%d",cond_result);
 39.1198 +                        #endif
 39.1199 +                        DEBUG_LOG("FSM condition", "sync_fsm.c, state=HandshakingGrouped, event=Init, condition=keyElectionWon", resstr)
 39.1200 +                        if (cond_result < 0)
 39.1201 +                            return cond_result;
 39.1202 +                        if (cond_result) {
 39.1203 +                        DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingGrouped, event=Init", "action=notifyInitAddOtherDevice")
 39.1204 +                        status = notifyInitAddOtherDevice(session, state, partner, NULL);
 39.1205 +                        if (status == PEP_OUT_OF_MEMORY)
 39.1206 +                            return (int) invalid_out_of_memory;
 39.1207 +                        if (status != PEP_STATUS_OK)
 39.1208 +                            return (int) invalid_action;
 39.1209 +                        }
 39.1210 +                        else {
 39.1211 +                        DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingGrouped, event=Init", "action=notifyInitMoveOurDevice")
 39.1212 +                        status = notifyInitMoveOurDevice(session, state, partner, NULL);
 39.1213 +                        if (status == PEP_OUT_OF_MEMORY)
 39.1214 +                            return (int) invalid_out_of_memory;
 39.1215 +                        if (status != PEP_STATUS_OK)
 39.1216 +                            return (int) invalid_action;
 39.1217 +                        }
 39.1218 +                    }
 39.1219                      break;
 39.1220                  }
 39.1221                  case HandshakeRejected:
 39.1222 @@ -626,10 +1169,17 @@
 39.1223                          return (int) invalid_out_of_memory;
 39.1224                      if (status != PEP_STATUS_OK)
 39.1225                          return (int) invalid_action;
 39.1226 -                    if(session->sync_state_payload){
 39.1227 -                        free_identity((Identity)session->sync_state_payload);
 39.1228 -                        session->sync_state_payload = NULL;
 39.1229 -                    }
 39.1230 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingGrouped, event=HandshakeRejected", "action=sendGroupUpdate")
 39.1231 +                    status = sendGroupUpdate(session, state, NULL, NULL);
 39.1232 +                    if (status == PEP_OUT_OF_MEMORY)
 39.1233 +                        return (int) invalid_out_of_memory;
 39.1234 +                    if (status != PEP_STATUS_OK)
 39.1235 +                        return (int) invalid_action;
 39.1236 +                    assert(session->sync_state_payload);
 39.1237 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
 39.1238 +                    free_identity(((HandshakingGrouped_state_payload_t*)session->sync_state_payload)->expected);
 39.1239 +                    free(session->sync_state_payload);
 39.1240 +                    session->sync_state_payload = NULL;
 39.1241                      DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingGrouped, event=HandshakeRejected", "target=Grouped")
 39.1242                      return Grouped;
 39.1243                  }
 39.1244 @@ -642,17 +1192,135 @@
 39.1245                          return (int) invalid_out_of_memory;
 39.1246                      if (status != PEP_STATUS_OK)
 39.1247                          return (int) invalid_action;
 39.1248 -                    DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingGrouped, event=HandshakeAccepted", "action=sendGroupKeys")
 39.1249 -                    status = sendGroupKeys(session, state, partner, NULL);
 39.1250 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingGrouped, event=HandshakeAccepted", "action=sendGroupUpdate")
 39.1251 +                    status = sendGroupUpdate(session, state, NULL, NULL);
 39.1252                      if (status == PEP_OUT_OF_MEMORY)
 39.1253                          return (int) invalid_out_of_memory;
 39.1254                      if (status != PEP_STATUS_OK)
 39.1255                          return (int) invalid_action;
 39.1256 -                    if(session->sync_state_payload){
 39.1257 -                        free_identity((Identity)session->sync_state_payload);
 39.1258 +                    {
 39.1259 +                        int cond_result = keyElectionWon(session, partner);
 39.1260 +                        #ifndef NDEBUG
 39.1261 +                        char resstr[11] = {0,};
 39.1262 +                        snprintf(resstr,10,"result=%d",cond_result);
 39.1263 +                        #endif
 39.1264 +                        DEBUG_LOG("FSM condition", "sync_fsm.c, state=HandshakingGrouped, event=HandshakeAccepted, condition=keyElectionWon", resstr)
 39.1265 +                        if (cond_result < 0)
 39.1266 +                            return cond_result;
 39.1267 +                        if (cond_result) {
 39.1268 +                        DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingGrouped, event=HandshakeAccepted", "action=sendGroupKeys")
 39.1269 +                        status = sendGroupKeys(session, state, partner, NULL);
 39.1270 +                        if (status == PEP_OUT_OF_MEMORY)
 39.1271 +                            return (int) invalid_out_of_memory;
 39.1272 +                        if (status != PEP_STATUS_OK)
 39.1273 +                            return (int) invalid_action;
 39.1274 +                        DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingGrouped, event=HandshakeAccepted", "action=notifyAcceptedDeviceAdded")
 39.1275 +                        status = notifyAcceptedDeviceAdded(session, state, partner, NULL);
 39.1276 +                        if (status == PEP_OUT_OF_MEMORY)
 39.1277 +                            return (int) invalid_out_of_memory;
 39.1278 +                        if (status != PEP_STATUS_OK)
 39.1279 +                            return (int) invalid_action;
 39.1280 +                        assert(session->sync_state_payload);
 39.1281 +                        if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
 39.1282 +                        free_identity(((HandshakingGrouped_state_payload_t*)session->sync_state_payload)->expected);
 39.1283 +                        free(session->sync_state_payload);
 39.1284                          session->sync_state_payload = NULL;
 39.1285 +                        DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingGrouped, event=HandshakeAccepted", "target=Grouped")
 39.1286 +                        return Grouped;
 39.1287 +                        }
 39.1288                      }
 39.1289 -                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingGrouped, event=HandshakeAccepted", "target=Grouped")
 39.1290 +                    assert(session->sync_state_payload);
 39.1291 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
 39.1292 +                    free_identity(((HandshakingGrouped_state_payload_t*)session->sync_state_payload)->expected);
 39.1293 +                    free(session->sync_state_payload);
 39.1294 +                    session->sync_state_payload = NULL;
 39.1295 +                    session->sync_state_payload = malloc(sizeof(WaitForGroupKeysGrouped_state_payload_t));
 39.1296 +                    assert(session->sync_state_payload);
 39.1297 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory;
 39.1298 +                    ((WaitForGroupKeysGrouped_state_payload_t*)session->sync_state_payload)->expected =
 39.1299 +                        identity_dup(partner);
 39.1300 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingGrouped, event=HandshakeAccepted", "target=WaitForGroupKeysGrouped")
 39.1301 +                    return WaitForGroupKeysGrouped;
 39.1302 +                }
 39.1303 +                case Cancel:
 39.1304 +                {
 39.1305 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=HandshakingGrouped", "event=Cancel")
 39.1306 +                    assert(session->sync_state_payload);
 39.1307 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
 39.1308 +                    free_identity(((HandshakingGrouped_state_payload_t*)session->sync_state_payload)->expected);
 39.1309 +                    free(session->sync_state_payload);
 39.1310 +                    session->sync_state_payload = NULL;
 39.1311 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingGrouped, event=Cancel", "target=Grouped")
 39.1312 +                    return Grouped;
 39.1313 +                }
 39.1314 +                case GroupKeys:
 39.1315 +                {
 39.1316 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=HandshakingGrouped", "event=GroupKeys")
 39.1317 +                    group_keys_extra_t* groupkeys = (group_keys_extra_t*)extra;
 39.1318 +                    {
 39.1319 +                        int cond_result = keyElectionWon(session, expected);
 39.1320 +                        #ifndef NDEBUG
 39.1321 +                        char resstr[11] = {0,};
 39.1322 +                        snprintf(resstr,10,"result=%d",cond_result);
 39.1323 +                        #endif
 39.1324 +                        DEBUG_LOG("FSM condition", "sync_fsm.c, state=HandshakingGrouped, event=GroupKeys, condition=keyElectionWon", resstr)
 39.1325 +                        if (cond_result < 0)
 39.1326 +                            return cond_result;
 39.1327 +                        if (cond_result) {
 39.1328 +                        }
 39.1329 +                        else {
 39.1330 +                        {
 39.1331 +                            int cond_result = sameKeyAndAddress(session, partner, expected);
 39.1332 +                            #ifndef NDEBUG
 39.1333 +                            char resstr[11] = {0,};
 39.1334 +                            snprintf(resstr,10,"result=%d",cond_result);
 39.1335 +                            #endif
 39.1336 +                            DEBUG_LOG("FSM condition", "sync_fsm.c, state=HandshakingGrouped, event=GroupKeys, condition=sameKeyAndAddress", resstr)
 39.1337 +                            if (cond_result < 0)
 39.1338 +                                return cond_result;
 39.1339 +                            if (cond_result) {
 39.1340 +                            assert(session->sync_state_payload);
 39.1341 +                            if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
 39.1342 +                            free_identity(((HandshakingGrouped_state_payload_t*)session->sync_state_payload)->expected);
 39.1343 +                            free(session->sync_state_payload);
 39.1344 +                            session->sync_state_payload = NULL;
 39.1345 +                            session->sync_state_payload = malloc(sizeof(WaitForAcceptGrouped_state_payload_t));
 39.1346 +                            assert(session->sync_state_payload);
 39.1347 +                            if(!session->sync_state_payload) return (DeviceState_state) invalid_out_of_memory;
 39.1348 +                            ((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->expected =
 39.1349 +                                identity_dup(partner);
 39.1350 +                            ((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->groupkeys =
 39.1351 +                                group_keys_extra_dup(groupkeys);
 39.1352 +                            DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingGrouped, event=GroupKeys", "target=WaitForAcceptGrouped")
 39.1353 +                            return WaitForAcceptGrouped;
 39.1354 +                            }
 39.1355 +                        }
 39.1356 +                        }
 39.1357 +                    }
 39.1358 +                    break;
 39.1359 +                }
 39.1360 +                case GroupUpdate:
 39.1361 +                {
 39.1362 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=HandshakingGrouped", "event=GroupUpdate")
 39.1363 +                    identity_list* keys = (identity_list*)extra;
 39.1364 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingGrouped, event=GroupUpdate", "action=notifyOvertaken")
 39.1365 +                    status = notifyOvertaken(session, state, partner, NULL);
 39.1366 +                    if (status == PEP_OUT_OF_MEMORY)
 39.1367 +                        return (int) invalid_out_of_memory;
 39.1368 +                    if (status != PEP_STATUS_OK)
 39.1369 +                        return (int) invalid_action;
 39.1370 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=HandshakingGrouped, event=GroupUpdate", "action=storeGroupUpdate")
 39.1371 +                    status = storeGroupUpdate(session, state, partner, keys);
 39.1372 +                    if (status == PEP_OUT_OF_MEMORY)
 39.1373 +                        return (int) invalid_out_of_memory;
 39.1374 +                    if (status != PEP_STATUS_OK)
 39.1375 +                        return (int) invalid_action;
 39.1376 +                    assert(session->sync_state_payload);
 39.1377 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
 39.1378 +                    free_identity(((HandshakingGrouped_state_payload_t*)session->sync_state_payload)->expected);
 39.1379 +                    free(session->sync_state_payload);
 39.1380 +                    session->sync_state_payload = NULL;
 39.1381 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingGrouped, event=GroupUpdate", "target=Grouped")
 39.1382                      return Grouped;
 39.1383                  }
 39.1384                  case Timeout:
 39.1385 @@ -664,11 +1332,268 @@
 39.1386                          return (int) invalid_out_of_memory;
 39.1387                      if (status != PEP_STATUS_OK)
 39.1388                          return (int) invalid_action;
 39.1389 -                    if(session->sync_state_payload){
 39.1390 -                        free_identity((Identity)session->sync_state_payload);
 39.1391 +                    assert(session->sync_state_payload);
 39.1392 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
 39.1393 +                    free_identity(((HandshakingGrouped_state_payload_t*)session->sync_state_payload)->expected);
 39.1394 +                    free(session->sync_state_payload);
 39.1395 +                    session->sync_state_payload = NULL;
 39.1396 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingGrouped, event=Timeout", "target=Grouped")
 39.1397 +                    return Grouped;
 39.1398 +                }
 39.1399 +                default:
 39.1400 +                    return (DeviceState_state) invalid_event;
 39.1401 +            }
 39.1402 +            break;
 39.1403 +        }
 39.1404 +        case WaitForGroupKeysGrouped:
 39.1405 +        {
 39.1406 +            DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=WaitForGroupKeysGrouped")
 39.1407 +            assert(session->sync_state_payload);
 39.1408 +            if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
 39.1409 +            Identity expected = ((WaitForGroupKeysGrouped_state_payload_t*)session->sync_state_payload)->expected;
 39.1410 +            switch (event) {
 39.1411 +                case Init: 
 39.1412 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForGroupKeysGrouped", "event=Init") 
 39.1413 +                    *timeout = 600;
 39.1414 +                    break;
 39.1415 +                case GroupKeys:
 39.1416 +                {
 39.1417 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForGroupKeysGrouped", "event=GroupKeys")
 39.1418 +                    group_keys_extra_t* groupkeys = (group_keys_extra_t*)extra;
 39.1419 +                    {
 39.1420 +                        int cond_result = sameIdentities(session, partner, expected);
 39.1421 +                        #ifndef NDEBUG
 39.1422 +                        char resstr[11] = {0,};
 39.1423 +                        snprintf(resstr,10,"result=%d",cond_result);
 39.1424 +                        #endif
 39.1425 +                        DEBUG_LOG("FSM condition", "sync_fsm.c, state=WaitForGroupKeysGrouped, event=GroupKeys, condition=sameIdentities", resstr)
 39.1426 +                        if (cond_result < 0)
 39.1427 +                            return cond_result;
 39.1428 +                        if (cond_result) {
 39.1429 +                        DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForGroupKeysGrouped, event=GroupKeys", "action=storeGroupKeys")
 39.1430 +                        status = storeGroupKeys(session, state, partner, groupkeys);
 39.1431 +                        if (status == PEP_OUT_OF_MEMORY)
 39.1432 +                            return (int) invalid_out_of_memory;
 39.1433 +                        if (status != PEP_STATUS_OK)
 39.1434 +                            return (int) invalid_action;
 39.1435 +                        DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForGroupKeysGrouped, event=GroupKeys", "action=sendGroupUpdate")
 39.1436 +                        status = sendGroupUpdate(session, state, NULL, NULL);
 39.1437 +                        if (status == PEP_OUT_OF_MEMORY)
 39.1438 +                            return (int) invalid_out_of_memory;
 39.1439 +                        if (status != PEP_STATUS_OK)
 39.1440 +                            return (int) invalid_action;
 39.1441 +                        DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForGroupKeysGrouped, event=GroupKeys", "action=renewUUID")
 39.1442 +                        status = renewUUID(session, state, NULL, NULL);
 39.1443 +                        if (status == PEP_OUT_OF_MEMORY)
 39.1444 +                            return (int) invalid_out_of_memory;
 39.1445 +                        if (status != PEP_STATUS_OK)
 39.1446 +                            return (int) invalid_action;
 39.1447 +                        DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForGroupKeysGrouped, event=GroupKeys", "action=notifyAcceptedDeviceMoved")
 39.1448 +                        status = notifyAcceptedDeviceMoved(session, state, partner, NULL);
 39.1449 +                        if (status == PEP_OUT_OF_MEMORY)
 39.1450 +                            return (int) invalid_out_of_memory;
 39.1451 +                        if (status != PEP_STATUS_OK)
 39.1452 +                            return (int) invalid_action;
 39.1453 +                        assert(session->sync_state_payload);
 39.1454 +                        if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
 39.1455 +                        free_identity(((WaitForGroupKeysGrouped_state_payload_t*)session->sync_state_payload)->expected);
 39.1456 +                        free(session->sync_state_payload);
 39.1457                          session->sync_state_payload = NULL;
 39.1458 +                        DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForGroupKeysGrouped, event=GroupKeys", "target=Grouped")
 39.1459 +                        return Grouped;
 39.1460 +                        }
 39.1461                      }
 39.1462 -                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=HandshakingGrouped, event=Timeout", "target=Grouped")
 39.1463 +                    break;
 39.1464 +                }
 39.1465 +                case GroupUpdate:
 39.1466 +                {
 39.1467 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForGroupKeysGrouped", "event=GroupUpdate")
 39.1468 +                    identity_list* keys = (identity_list*)extra;
 39.1469 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForGroupKeysGrouped, event=GroupUpdate", "action=notifyOvertaken")
 39.1470 +                    status = notifyOvertaken(session, state, partner, NULL);
 39.1471 +                    if (status == PEP_OUT_OF_MEMORY)
 39.1472 +                        return (int) invalid_out_of_memory;
 39.1473 +                    if (status != PEP_STATUS_OK)
 39.1474 +                        return (int) invalid_action;
 39.1475 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForGroupKeysGrouped, event=GroupUpdate", "action=storeGroupUpdate")
 39.1476 +                    status = storeGroupUpdate(session, state, partner, keys);
 39.1477 +                    if (status == PEP_OUT_OF_MEMORY)
 39.1478 +                        return (int) invalid_out_of_memory;
 39.1479 +                    if (status != PEP_STATUS_OK)
 39.1480 +                        return (int) invalid_action;
 39.1481 +                    assert(session->sync_state_payload);
 39.1482 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
 39.1483 +                    free_identity(((WaitForGroupKeysGrouped_state_payload_t*)session->sync_state_payload)->expected);
 39.1484 +                    free(session->sync_state_payload);
 39.1485 +                    session->sync_state_payload = NULL;
 39.1486 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForGroupKeysGrouped, event=GroupUpdate", "target=Grouped")
 39.1487 +                    return Grouped;
 39.1488 +                }
 39.1489 +                case Timeout:
 39.1490 +                {
 39.1491 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForGroupKeysGrouped", "event=Timeout")
 39.1492 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForGroupKeysGrouped, event=Timeout", "action=notifyTimeout")
 39.1493 +                    status = notifyTimeout(session, state, expected, NULL);
 39.1494 +                    if (status == PEP_OUT_OF_MEMORY)
 39.1495 +                        return (int) invalid_out_of_memory;
 39.1496 +                    if (status != PEP_STATUS_OK)
 39.1497 +                        return (int) invalid_action;
 39.1498 +                    assert(session->sync_state_payload);
 39.1499 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
 39.1500 +                    free_identity(((WaitForGroupKeysGrouped_state_payload_t*)session->sync_state_payload)->expected);
 39.1501 +                    free(session->sync_state_payload);
 39.1502 +                    session->sync_state_payload = NULL;
 39.1503 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForGroupKeysGrouped, event=Timeout", "target=Grouped")
 39.1504 +                    return Grouped;
 39.1505 +                }
 39.1506 +                default:
 39.1507 +                    return (DeviceState_state) invalid_event;
 39.1508 +            }
 39.1509 +            break;
 39.1510 +        }
 39.1511 +        case WaitForAcceptGrouped:
 39.1512 +        {
 39.1513 +            DEBUG_LOG("Entering FSM state", "sync_fsm.c", "state=WaitForAcceptGrouped")
 39.1514 +            assert(session->sync_state_payload);
 39.1515 +            if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
 39.1516 +            Identity expected = ((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->expected;
 39.1517 +            group_keys_extra_t* groupkeys = ((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->groupkeys;
 39.1518 +            switch (event) {
 39.1519 +                case Init: 
 39.1520 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForAcceptGrouped", "event=Init") 
 39.1521 +                    *timeout = 600;
 39.1522 +                    break;
 39.1523 +                case HandshakeRejected:
 39.1524 +                {
 39.1525 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForAcceptGrouped", "event=HandshakeRejected")
 39.1526 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptGrouped, event=HandshakeRejected", "action=rejectHandshake")
 39.1527 +                    status = rejectHandshake(session, state, partner, NULL);
 39.1528 +                    if (status == PEP_OUT_OF_MEMORY)
 39.1529 +                        return (int) invalid_out_of_memory;
 39.1530 +                    if (status != PEP_STATUS_OK)
 39.1531 +                        return (int) invalid_action;
 39.1532 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptGrouped, event=HandshakeRejected", "action=sendGroupUpdate")
 39.1533 +                    status = sendGroupUpdate(session, state, NULL, NULL);
 39.1534 +                    if (status == PEP_OUT_OF_MEMORY)
 39.1535 +                        return (int) invalid_out_of_memory;
 39.1536 +                    if (status != PEP_STATUS_OK)
 39.1537 +                        return (int) invalid_action;
 39.1538 +                    assert(session->sync_state_payload);
 39.1539 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
 39.1540 +                    free_identity(((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->expected);
 39.1541 +                    free_group_keys_extra(((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->groupkeys);
 39.1542 +                    free(session->sync_state_payload);
 39.1543 +                    session->sync_state_payload = NULL;
 39.1544 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForAcceptGrouped, event=HandshakeRejected", "target=Grouped")
 39.1545 +                    return Grouped;
 39.1546 +                }
 39.1547 +                case HandshakeAccepted:
 39.1548 +                {
 39.1549 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForAcceptGrouped", "event=HandshakeAccepted")
 39.1550 +                    {
 39.1551 +                        int cond_result = sameIdentities(session, partner, expected);
 39.1552 +                        #ifndef NDEBUG
 39.1553 +                        char resstr[11] = {0,};
 39.1554 +                        snprintf(resstr,10,"result=%d",cond_result);
 39.1555 +                        #endif
 39.1556 +                        DEBUG_LOG("FSM condition", "sync_fsm.c, state=WaitForAcceptGrouped, event=HandshakeAccepted, condition=sameIdentities", resstr)
 39.1557 +                        if (cond_result < 0)
 39.1558 +                            return cond_result;
 39.1559 +                        if (cond_result) {
 39.1560 +                        DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptGrouped, event=HandshakeAccepted", "action=acceptHandshake")
 39.1561 +                        status = acceptHandshake(session, state, partner, NULL);
 39.1562 +                        if (status == PEP_OUT_OF_MEMORY)
 39.1563 +                            return (int) invalid_out_of_memory;
 39.1564 +                        if (status != PEP_STATUS_OK)
 39.1565 +                            return (int) invalid_action;
 39.1566 +                        DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptGrouped, event=HandshakeAccepted", "action=storeGroupKeys")
 39.1567 +                        status = storeGroupKeys(session, state, partner, groupkeys);
 39.1568 +                        if (status == PEP_OUT_OF_MEMORY)
 39.1569 +                            return (int) invalid_out_of_memory;
 39.1570 +                        if (status != PEP_STATUS_OK)
 39.1571 +                            return (int) invalid_action;
 39.1572 +                        DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptGrouped, event=HandshakeAccepted", "action=sendGroupUpdate")
 39.1573 +                        status = sendGroupUpdate(session, state, NULL, NULL);
 39.1574 +                        if (status == PEP_OUT_OF_MEMORY)
 39.1575 +                            return (int) invalid_out_of_memory;
 39.1576 +                        if (status != PEP_STATUS_OK)
 39.1577 +                            return (int) invalid_action;
 39.1578 +                        DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptGrouped, event=HandshakeAccepted", "action=renewUUID")
 39.1579 +                        status = renewUUID(session, state, NULL, NULL);
 39.1580 +                        if (status == PEP_OUT_OF_MEMORY)
 39.1581 +                            return (int) invalid_out_of_memory;
 39.1582 +                        if (status != PEP_STATUS_OK)
 39.1583 +                            return (int) invalid_action;
 39.1584 +                        DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptGrouped, event=HandshakeAccepted", "action=notifyAcceptedDeviceMoved")
 39.1585 +                        status = notifyAcceptedDeviceMoved(session, state, partner, NULL);
 39.1586 +                        if (status == PEP_OUT_OF_MEMORY)
 39.1587 +                            return (int) invalid_out_of_memory;
 39.1588 +                        if (status != PEP_STATUS_OK)
 39.1589 +                            return (int) invalid_action;
 39.1590 +                        }
 39.1591 +                    }
 39.1592 +                    assert(session->sync_state_payload);
 39.1593 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
 39.1594 +                    free_identity(((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->expected);
 39.1595 +                    free_group_keys_extra(((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->groupkeys);
 39.1596 +                    free(session->sync_state_payload);
 39.1597 +                    session->sync_state_payload = NULL;
 39.1598 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForAcceptGrouped, event=HandshakeAccepted", "target=Grouped")
 39.1599 +                    return Grouped;
 39.1600 +                }
 39.1601 +                case Cancel:
 39.1602 +                {
 39.1603 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForAcceptGrouped", "event=Cancel")
 39.1604 +                    assert(session->sync_state_payload);
 39.1605 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
 39.1606 +                    free_identity(((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->expected);
 39.1607 +                    free_group_keys_extra(((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->groupkeys);
 39.1608 +                    free(session->sync_state_payload);
 39.1609 +                    session->sync_state_payload = NULL;
 39.1610 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForAcceptGrouped, event=Cancel", "target=Grouped")
 39.1611 +                    return Grouped;
 39.1612 +                }
 39.1613 +                case GroupUpdate:
 39.1614 +                {
 39.1615 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForAcceptGrouped", "event=GroupUpdate")
 39.1616 +                    identity_list* keys = (identity_list*)extra;
 39.1617 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptGrouped, event=GroupUpdate", "action=notifyOvertaken")
 39.1618 +                    status = notifyOvertaken(session, state, partner, NULL);
 39.1619 +                    if (status == PEP_OUT_OF_MEMORY)
 39.1620 +                        return (int) invalid_out_of_memory;
 39.1621 +                    if (status != PEP_STATUS_OK)
 39.1622 +                        return (int) invalid_action;
 39.1623 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptGrouped, event=GroupUpdate", "action=storeGroupUpdate")
 39.1624 +                    status = storeGroupUpdate(session, state, partner, keys);
 39.1625 +                    if (status == PEP_OUT_OF_MEMORY)
 39.1626 +                        return (int) invalid_out_of_memory;
 39.1627 +                    if (status != PEP_STATUS_OK)
 39.1628 +                        return (int) invalid_action;
 39.1629 +                    assert(session->sync_state_payload);
 39.1630 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
 39.1631 +                    free_identity(((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->expected);
 39.1632 +                    free_group_keys_extra(((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->groupkeys);
 39.1633 +                    free(session->sync_state_payload);
 39.1634 +                    session->sync_state_payload = NULL;
 39.1635 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForAcceptGrouped, event=GroupUpdate", "target=Grouped")
 39.1636 +                    return Grouped;
 39.1637 +                }
 39.1638 +                case Timeout:
 39.1639 +                {
 39.1640 +                    DEBUG_LOG("FSM event", "sync_fsm.c, state=WaitForAcceptGrouped", "event=Timeout")
 39.1641 +                    DEBUG_LOG("FSM action", "sync_fsm.c, state=WaitForAcceptGrouped, event=Timeout", "action=notifyTimeout")
 39.1642 +                    status = notifyTimeout(session, state, expected, NULL);
 39.1643 +                    if (status == PEP_OUT_OF_MEMORY)
 39.1644 +                        return (int) invalid_out_of_memory;
 39.1645 +                    if (status != PEP_STATUS_OK)
 39.1646 +                        return (int) invalid_action;
 39.1647 +                    assert(session->sync_state_payload);
 39.1648 +                    if(!session->sync_state_payload) return (DeviceState_state) invalid_state;
 39.1649 +                    free_identity(((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->expected);
 39.1650 +                    free_group_keys_extra(((WaitForAcceptGrouped_state_payload_t*)session->sync_state_payload)->groupkeys);
 39.1651 +                    free(session->sync_state_payload);
 39.1652 +                    session->sync_state_payload = NULL;
 39.1653 +                    DEBUG_LOG("FSM transition", "sync_fsm.c, state=WaitForAcceptGrouped, event=Timeout", "target=Grouped")
 39.1654                      return Grouped;
 39.1655                  }
 39.1656                  default:
    40.1 --- a/sync/generated/sync_fsm.h	Tue Jan 31 08:42:25 2017 +0100
    40.2 +++ b/sync/generated/sync_fsm.h	Tue Jun 13 13:00:37 2017 +0200
    40.3 @@ -12,7 +12,6 @@
    40.4  
    40.5  typedef pEp_identity * Identity;
    40.6  typedef stringlist_t * Stringlist;
    40.7 -typedef union _param { Identity partner; stringlist_t *keylist; } param_t;
    40.8  
    40.9  // error values
   40.10  
   40.11 @@ -30,9 +29,10 @@
   40.12  
   40.13  // conditions
   40.14  
   40.15 -int storedGroupKeys(PEP_SESSION session);
   40.16 +int deviceGrouped(PEP_SESSION session);
   40.17  int keyElectionWon(PEP_SESSION session, Identity partner);
   40.18  int sameIdentities(PEP_SESSION session, Identity a, Identity b);
   40.19 +int sameKeyAndAddress(PEP_SESSION session, Identity a, Identity b);
   40.20  
   40.21  // states
   40.22  
   40.23 @@ -47,12 +47,17 @@
   40.24      DeviceState_state_NONE = 0,
   40.25      InitState, 
   40.26      Sole, 
   40.27 +    SoleWaiting, 
   40.28      SoleBeaconed, 
   40.29      HandshakingSole, 
   40.30      WaitForGroupKeysSole, 
   40.31 +    WaitForAcceptSole, 
   40.32      Grouped, 
   40.33 +    GroupWaiting, 
   40.34      GroupedBeaconed, 
   40.35 -    HandshakingGrouped
   40.36 +    HandshakingGrouped, 
   40.37 +    WaitForGroupKeysGrouped, 
   40.38 +    WaitForAcceptGrouped
   40.39  } DeviceState_state;
   40.40  
   40.41  // events
   40.42 @@ -81,14 +86,20 @@
   40.43  PEP_STATUS notifyInitAddOurDevice(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra);
   40.44  PEP_STATUS rejectHandshake(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra);
   40.45  PEP_STATUS acceptHandshake(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra);
   40.46 +PEP_STATUS makeGroup(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra);
   40.47  PEP_STATUS sendGroupKeys(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra);
   40.48 +PEP_STATUS renewUUID(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra);
   40.49  PEP_STATUS notifyAcceptedGroupCreated(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra);
   40.50  PEP_STATUS notifyTimeout(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra);
   40.51  PEP_STATUS storeGroupKeys(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra);
   40.52 +PEP_STATUS sendGroupUpdate(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra);
   40.53  PEP_STATUS notifyAcceptedDeviceAdded(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra);
   40.54 -PEP_STATUS enterGroup(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra);
   40.55 -PEP_STATUS sendGroupUpdate(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra);
   40.56  PEP_STATUS sendUpdateRequest(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra);
   40.57 +PEP_STATUS storeGroupUpdate(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra);
   40.58 +PEP_STATUS notifyInitAddOtherDevice(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra);
   40.59 +PEP_STATUS notifyInitMoveOurDevice(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra);
   40.60 +PEP_STATUS notifyOvertaken(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra);
   40.61 +PEP_STATUS notifyAcceptedDeviceMoved(PEP_SESSION session, DeviceState_state state, Identity partner, void *extra);
   40.62  
   40.63  // event injector
   40.64  
    41.1 --- a/sync/generated/sync_send_actions.c	Tue Jan 31 08:42:25 2017 +0100
    41.2 +++ b/sync/generated/sync_send_actions.c	Tue Jun 13 13:00:37 2017 +0200
    41.3 @@ -86,9 +86,21 @@
    41.4      if (!msg)
    41.5          goto enomem;
    41.6  
    41.7 -    if (Identity_from_Struct(partner,
    41.8 -                             &msg->payload.choice.handshakeRequest.partner) == NULL)
    41.9 -        goto enomem;
   41.10 +    msg->payload.choice.handshakeRequest.partner_id = 
   41.11 +        OCTET_STRING_new_fromBuf(&asn_DEF_UTF8String,
   41.12 +                                 partner->user_id, -1);
   41.13 +    if (partner->user_id && !msg->payload.choice.handshakeRequest.partner_id)
   41.14 +       goto enomem;
   41.15 +
   41.16 +    char *devgrp = NULL;
   41.17 +    status = get_device_group(session, &devgrp);
   41.18 +    if (status == PEP_STATUS_OK && devgrp && devgrp[0])
   41.19 +    msg->payload.choice.handshakeRequest.group_id = 
   41.20 +        OCTET_STRING_new_fromBuf(&asn_DEF_UTF8String,
   41.21 +                                 devgrp, -1);
   41.22 +    free(devgrp);
   41.23 +    if (devgrp && !msg->payload.choice.handshakeRequest.partner_id)
   41.24 +       goto enomem;
   41.25  
   41.26      bool encrypted = true;
   41.27      status = unicast_msg(session, partner, state, msg, encrypted);
   41.28 @@ -140,9 +152,21 @@
   41.29      if (IdentityList_from_identity_list(kl, &msg->payload.choice.groupKeys.ownIdentities) == NULL)
   41.30          goto enomem;
   41.31  
   41.32 -    if (Identity_from_Struct(partner,
   41.33 -                             &msg->payload.choice.groupKeys.partner) == NULL)
   41.34 -        goto enomem;
   41.35 +    msg->payload.choice.groupKeys.partner_id = 
   41.36 +        OCTET_STRING_new_fromBuf(&asn_DEF_UTF8String,
   41.37 +                                 partner->user_id, -1);
   41.38 +    if (partner->user_id && !msg->payload.choice.groupKeys.partner_id)
   41.39 +       goto enomem;
   41.40 +
   41.41 +    char *devgrp = NULL;
   41.42 +    status = get_device_group(session, &devgrp);
   41.43 +    if (status == PEP_STATUS_OK && devgrp && devgrp[0])
   41.44 +    msg->payload.choice.groupKeys.group_id = 
   41.45 +        OCTET_STRING_new_fromBuf(&asn_DEF_UTF8String,
   41.46 +                                 devgrp, -1);
   41.47 +    free(devgrp);
   41.48 +    if (devgrp && !msg->payload.choice.groupKeys.partner_id)
   41.49 +       goto enomem;
   41.50  
   41.51      bool encrypted = true;
   41.52      status = unicast_msg(session, partner, state, msg, encrypted);
   41.53 @@ -391,3 +415,107 @@
   41.54      return _notifyHandshake(session, partner, SYNC_NOTIFY_ACCEPTED_DEVICE_ADDED);
   41.55  }
   41.56  
   41.57 +
   41.58 +// notifyInitAddOtherDevice() - notify InitAddOtherDevice to app
   41.59 +//
   41.60 +//  params:
   41.61 +//      session (in)        session handle
   41.62 +//      state (in)          state the state machine is in
   41.63 +//      partner (in)        partner to communicate with
   41.64 +//
   41.65 +//  returns:
   41.66 +//      PEP_STATUS_OK or any other value on error
   41.67 +
   41.68 +PEP_STATUS notifyInitAddOtherDevice(
   41.69 +        PEP_SESSION session,
   41.70 +        DeviceState_state state,
   41.71 +        Identity partner,
   41.72 +        void *extra
   41.73 +    )
   41.74 +{
   41.75 +    assert(session && state);
   41.76 +    assert(extra == NULL);
   41.77 +    if (!(session && state && extra == NULL))
   41.78 +        return PEP_ILLEGAL_VALUE;
   41.79 +
   41.80 +    return _notifyHandshake(session, partner, SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE);
   41.81 +}
   41.82 +
   41.83 +
   41.84 +// notifyInitMoveOurDevice() - notify InitMoveOurDevice to app
   41.85 +//
   41.86 +//  params:
   41.87 +//      session (in)        session handle
   41.88 +//      state (in)          state the state machine is in
   41.89 +//      partner (in)        partner to communicate with
   41.90 +//
   41.91 +//  returns:
   41.92 +//      PEP_STATUS_OK or any other value on error
   41.93 +
   41.94 +PEP_STATUS notifyInitMoveOurDevice(
   41.95 +        PEP_SESSION session,
   41.96 +        DeviceState_state state,
   41.97 +        Identity partner,
   41.98 +        void *extra
   41.99 +    )
  41.100 +{
  41.101 +    assert(session && state);
  41.102 +    assert(extra == NULL);
  41.103 +    if (!(session && state && extra == NULL))
  41.104 +        return PEP_ILLEGAL_VALUE;
  41.105 +
  41.106 +    return _notifyHandshake(session, partner, SYNC_NOTIFY_INIT_MOVE_OUR_DEVICE);
  41.107 +}
  41.108 +
  41.109 +
  41.110 +// notifyOvertaken() - notify Overtaken to app
  41.111 +//
  41.112 +//  params:
  41.113 +//      session (in)        session handle
  41.114 +//      state (in)          state the state machine is in
  41.115 +//      partner (in)        partner to communicate with
  41.116 +//
  41.117 +//  returns:
  41.118 +//      PEP_STATUS_OK or any other value on error
  41.119 +
  41.120 +PEP_STATUS notifyOvertaken(
  41.121 +        PEP_SESSION session,
  41.122 +        DeviceState_state state,
  41.123 +        Identity partner,
  41.124 +        void *extra
  41.125 +    )
  41.126 +{
  41.127 +    assert(session && state);
  41.128 +    assert(extra == NULL);
  41.129 +    if (!(session && state && extra == NULL))
  41.130 +        return PEP_ILLEGAL_VALUE;
  41.131 +
  41.132 +    return _notifyHandshake(session, partner, SYNC_NOTIFY_OVERTAKEN);
  41.133 +}
  41.134 +
  41.135 +
  41.136 +// notifyAcceptedDeviceMoved() - notify AcceptedDeviceMoved to app
  41.137 +//
  41.138 +//  params:
  41.139 +//      session (in)        session handle
  41.140 +//      state (in)          state the state machine is in
  41.141 +//      partner (in)        partner to communicate with
  41.142 +//
  41.143 +//  returns:
  41.144 +//      PEP_STATUS_OK or any other value on error
  41.145 +
  41.146 +PEP_STATUS notifyAcceptedDeviceMoved(
  41.147 +        PEP_SESSION session,
  41.148 +        DeviceState_state state,
  41.149 +        Identity partner,
  41.150 +        void *extra
  41.151 +    )
  41.152 +{
  41.153 +    assert(session && state);
  41.154 +    assert(extra == NULL);
  41.155 +    if (!(session && state && extra == NULL))
  41.156 +        return PEP_ILLEGAL_VALUE;
  41.157 +
  41.158 +    return _notifyHandshake(session, partner, SYNC_NOTIFY_ACCEPTED_DEVICE_MOVED);
  41.159 +}
  41.160 +
    42.1 --- a/sync/skeletons/sync_actions.c	Tue Jan 31 08:42:25 2017 +0100
    42.2 +++ b/sync/skeletons/sync_actions.c	Tue Jun 13 13:00:37 2017 +0200
    42.3 @@ -28,8 +28,8 @@
    42.4      PEP_STATUS status = PEP_STATUS_OK;
    42.5  
    42.6      assert(session);
    42.7 -    assert(partner);
    42.8 -    if (!(session && partner))
    42.9 +    assert(!partner);
   42.10 +    if (!(session && !partner))
   42.11          return PEP_ILLEGAL_VALUE;
   42.12  
   42.13      // working code
   42.14 @@ -65,8 +65,8 @@
   42.15      PEP_STATUS status = PEP_STATUS_OK;
   42.16  
   42.17      assert(session);
   42.18 -    assert(partner);
   42.19 -    if (!(session && partner))
   42.20 +    assert(!partner);
   42.21 +    if (!(session && !partner))
   42.22          return PEP_ILLEGAL_VALUE;
   42.23  
   42.24      // working code
   42.25 @@ -156,6 +156,80 @@
   42.26  }
   42.27  
   42.28  
   42.29 +// makeGroup() - 
   42.30 +//
   42.31 +//  params:
   42.32 +//      session (in)        session handle
   42.33 +//      state (in)          state the state machine is in
   42.34 +//      partner (in)        (must be NULL)
   42.35 +//
   42.36 +//  returns:
   42.37 +//      PEP_STATUS_OK or any other value on error
   42.38 +
   42.39 +PEP_STATUS makeGroup(
   42.40 +        PEP_SESSION session,
   42.41 +        DeviceState_state state,
   42.42 +        Identity partner,
   42.43 +        void *extra
   42.44 +    )
   42.45 +{
   42.46 +    PEP_STATUS status = PEP_STATUS_OK;
   42.47 +
   42.48 +    assert(session);
   42.49 +    assert(!partner);
   42.50 +    if (!(session && !partner))
   42.51 +        return PEP_ILLEGAL_VALUE;
   42.52 +
   42.53 +    // working code
   42.54 +
   42.55 +    // free extra
   42.56 +    return status;
   42.57 +
   42.58 +enomem:
   42.59 +    status = PEP_OUT_OF_MEMORY;
   42.60 +error:
   42.61 +    // free extra
   42.62 +    return status;
   42.63 +}
   42.64 +
   42.65 +
   42.66 +// renewUUID() - 
   42.67 +//
   42.68 +//  params:
   42.69 +//      session (in)        session handle
   42.70 +//      state (in)          state the state machine is in
   42.71 +//      partner (in)        (must be NULL)
   42.72 +//
   42.73 +//  returns:
   42.74 +//      PEP_STATUS_OK or any other value on error
   42.75 +
   42.76 +PEP_STATUS renewUUID(
   42.77 +        PEP_SESSION session,
   42.78 +        DeviceState_state state,
   42.79 +        Identity partner,
   42.80 +        void *extra
   42.81 +    )
   42.82 +{
   42.83 +    PEP_STATUS status = PEP_STATUS_OK;
   42.84 +
   42.85 +    assert(session);
   42.86 +    assert(!partner);
   42.87 +    if (!(session && !partner))
   42.88 +        return PEP_ILLEGAL_VALUE;
   42.89 +
   42.90 +    // working code
   42.91 +
   42.92 +    // free extra
   42.93 +    return status;
   42.94 +
   42.95 +enomem:
   42.96 +    status = PEP_OUT_OF_MEMORY;
   42.97 +error:
   42.98 +    // free extra
   42.99 +    return status;
  42.100 +}
  42.101 +
  42.102 +
  42.103  // notifyAcceptedGroupCreated() - 
  42.104  //
  42.105  //  params:
  42.106 @@ -304,17 +378,17 @@
  42.107  }
  42.108  
  42.109  
  42.110 -// enterGroup() - 
  42.111 +// storeGroupUpdate() - 
  42.112  //
  42.113  //  params:
  42.114  //      session (in)        session handle
  42.115  //      state (in)          state the state machine is in
  42.116 -//      partner (in)        (must be NULL)
  42.117 +//      partner (in)        partner to communicate with
  42.118  //
  42.119  //  returns:
  42.120  //      PEP_STATUS_OK or any other value on error
  42.121  
  42.122 -PEP_STATUS enterGroup(
  42.123 +PEP_STATUS storeGroupUpdate(
  42.124          PEP_SESSION session,
  42.125          DeviceState_state state,
  42.126          Identity partner,
  42.127 @@ -324,8 +398,8 @@
  42.128      PEP_STATUS status = PEP_STATUS_OK;
  42.129  
  42.130      assert(session);
  42.131 -    assert(!partner);
  42.132 -    if (!(session && !partner))
  42.133 +    assert(partner);
  42.134 +    if (!(session && partner))
  42.135          return PEP_ILLEGAL_VALUE;
  42.136  
  42.137      // working code
  42.138 @@ -340,3 +414,151 @@
  42.139      return status;
  42.140  }
  42.141  
  42.142 +
  42.143 +// notifyInitAddOtherDevice() - 
  42.144 +//
  42.145 +//  params:
  42.146 +//      session (in)        session handle
  42.147 +//      state (in)          state the state machine is in
  42.148 +//      partner (in)        partner to communicate with
  42.149 +//
  42.150 +//  returns:
  42.151 +//      PEP_STATUS_OK or any other value on error
  42.152 +
  42.153 +PEP_STATUS notifyInitAddOtherDevice(
  42.154 +        PEP_SESSION session,
  42.155 +        DeviceState_state state,
  42.156 +        Identity partner,
  42.157 +        void *extra
  42.158 +    )
  42.159 +{
  42.160 +    PEP_STATUS status = PEP_STATUS_OK;
  42.161 +
  42.162 +    assert(session);
  42.163 +    assert(partner);
  42.164 +    if (!(session && partner))
  42.165 +        return PEP_ILLEGAL_VALUE;
  42.166 +
  42.167 +    // working code
  42.168 +
  42.169 +    // free extra
  42.170 +    return status;
  42.171 +
  42.172 +enomem:
  42.173 +    status = PEP_OUT_OF_MEMORY;
  42.174 +error:
  42.175 +    // free extra
  42.176 +    return status;
  42.177 +}
  42.178 +
  42.179 +
  42.180 +// notifyInitMoveOurDevice() - 
  42.181 +//
  42.182 +//  params:
  42.183 +//      session (in)        session handle
  42.184 +//      state (in)          state the state machine is in
  42.185 +//      partner (in)        partner to communicate with
  42.186 +//
  42.187 +//  returns:
  42.188 +//      PEP_STATUS_OK or any other value on error
  42.189 +
  42.190 +PEP_STATUS notifyInitMoveOurDevice(
  42.191 +        PEP_SESSION session,
  42.192 +        DeviceState_state state,
  42.193 +        Identity partner,
  42.194 +        void *extra
  42.195 +    )
  42.196 +{
  42.197 +    PEP_STATUS status = PEP_STATUS_OK;
  42.198 +
  42.199 +    assert(session);
  42.200 +    assert(partner);
  42.201 +    if (!(session && partner))
  42.202 +        return PEP_ILLEGAL_VALUE;
  42.203 +
  42.204 +    // working code
  42.205 +
  42.206 +    // free extra
  42.207 +    return status;
  42.208 +
  42.209 +enomem:
  42.210 +    status = PEP_OUT_OF_MEMORY;
  42.211 +error:
  42.212 +    // free extra
  42.213 +    return status;
  42.214 +}
  42.215 +
  42.216 +
  42.217 +// notifyOvertaken() - 
  42.218 +//
  42.219 +//  params:
  42.220 +//      session (in)        session handle
  42.221 +//      state (in)          state the state machine is in
  42.222 +//      partner (in)        partner to communicate with