merge "default" into "rok-mac" branch rok-mac
authorRoker <roker@pep-project.org>
Wed, 13 Jul 2016 18:05:35 +0200
branchrok-mac
changeset 8601f469b5b459a
parent 804 5d14d44817b0
parent 858 043a39b5e301
child 874 c88b2d6f23cd
merge "default" into "rok-mac" branch
Makefile.conf
src/Makefile
sync/sync.fsm
     1.1 --- a/.hgignore	Fri Jul 08 21:29:55 2016 +0200
     1.2 +++ b/.hgignore	Wed Jul 13 18:05:35 2016 +0200
     1.3 @@ -33,4 +33,7 @@
     1.4  msg4.asc
     1.5  pep_Dokument_Titel.pdf
     1.6  pEpEngine.vcxproj.user
     1.7 -
     1.8 +*.skeleton
     1.9 +.skeletons
    1.10 +.statemachines
    1.11 +Makefile.protocols
     2.1 --- a/Makefile	Fri Jul 08 21:29:55 2016 +0200
     2.2 +++ b/Makefile	Wed Jul 13 18:05:35 2016 +0200
     2.3 @@ -18,6 +18,7 @@
     2.4  	$(MAKE) -C src clean
     2.5  	$(MAKE) -C test clean
     2.6  	$(MAKE) -C db clean
     2.7 +	$(MAKE) -C sync clean
     2.8  	$(MAKE) -C asn.1 clean
     2.9  
    2.10  test: all
     3.1 --- a/Makefile.conf	Fri Jul 08 21:29:55 2016 +0200
     3.2 +++ b/Makefile.conf	Wed Jul 13 18:05:35 2016 +0200
     3.3 @@ -1,7 +1,7 @@
     3.4  BUILD_ON=$(shell uname)
     3.5  BUILD_FOR=$(BUILD_ON)
     3.6  OPTIMIZE=-g -Wall -O0 -fPIC
     3.7 -#OPTIMIZE=-O3 -DNDEBUG -std=c99
     3.8 +#OPTIMIZE=-O3 -Wall -DNDEBUG -std=c99
     3.9  LD=$(CC)
    3.10  #CC=gcc-mp-4.9 -std=c99 -fstrict-aliasing -Wstrict-aliasing=3
    3.11  #LD=gcc-mp-4.9
    3.12 @@ -14,6 +14,9 @@
    3.13  # TODO: For brew this is /usr/local/share/asn1c
    3.14  # On BSDs, it might be that as well. How to check?
    3.15  # For now, it just works, even when it doesn't exist.
    3.16 +# TODO: For brew this is /usr/local/share/asn1c
    3.17 +# On BSDs, it might be that as well. How to check?
    3.18 +# For now, it just works, even when it doesn't exist.
    3.19  ASN1C_INCLUDE=/Users/lars/local/share/asn1c
    3.20  
    3.21  # C makros (not environment variables) to overwrite:
     4.1 --- a/README-OSX.md	Fri Jul 08 21:29:55 2016 +0200
     4.2 +++ b/README-OSX.md	Wed Jul 13 18:05:35 2016 +0200
     4.3 @@ -1,21 +1,119 @@
     4.4 -# Dependencies
     4.5 +# Building for OS X/macOS
     4.6  
     4.7 -You need a working [asn1c](https://lionet.info/asn1c/blog/).
     4.8 +See also README.txt for general information.
     4.9 +
    4.10 +## Dependencies
    4.11 +
    4.12 +### MacPorts
    4.13 +
    4.14 +Install [MacPorts](https://www.macports.org/) for your
    4.15 +[version of OS X/macOS](https://www.macports.org/install.php).
    4.16 +
    4.17 +Note that you need [Xcode installed](https://www.macports.org/install.php)
    4.18 +for MacPorts, and for building the engine. You also need to accept Xcode's EULA.
    4.19 +
    4.20 +*Note*: Use the script `macports_env.sh` (or a similar one) to set up a clean build environment
    4.21 +before building the engine:
    4.22  
    4.23  ```
    4.24 -brew install asn1c
    4.25 +. macports_env.sh
    4.26  ```
    4.27  
    4.28 -# Building for OS X
    4.29 +If you don't use that environment, please make sure you've set up all search paths correctly.
    4.30  
    4.31 -## Build libetpan
    4.32 +#### MacPorts dependencies
    4.33  
    4.34  ```
    4.35 -cd pEpEngine
    4.36 -autoreconf -vfi
    4.37 -./configure
    4.38 +sudo port install mercurial
    4.39 +sudo port install py27-lxml
    4.40 +sudo port install gpgme
    4.41 +sudo port install autoconf
    4.42 +sudo port install asn1c
    4.43 +sudo port install zlib
    4.44 +```
    4.45 +
    4.46 +### Other dependecies
    4.47 +
    4.48 +#### [yml2](https://fdik.org/yml/toolchain)
    4.49 +
    4.50 +Install into your home directory:
    4.51 +
    4.52 +```
    4.53 +pushd ~
    4.54 +curl -LO http://fdik.org/yml2.tar.bz2
    4.55 +tar xf yml2.tar.bz2
    4.56 +rm yml2.tar.bz2*
    4.57 +popd
    4.58 +```
    4.59 +
    4.60 +#### libetpan
    4.61 +
    4.62 +Note: libetpan needs libz and libiconv, but the libiconv from MacPorts is not compatible, some
    4.63 +functions seem to have been renamed there. Therefore the dynlib from OS X is used.
    4.64 +
    4.65 +```
    4.66 +git clone https://github.com/fdik/libetpan libetpan-osx
    4.67 +cd libetpan-osx/
    4.68 +./autogen.sh
    4.69  make
    4.70 +cp ./src/.libs/libetpan.a ~/lib/
    4.71 +```
    4.72 +
    4.73 +##### libetpan with xcodebuild
    4.74 +
    4.75 +The build with autoconf (see previous section) is preferred. This is just for completeness.
    4.76 +*Don't actually build libetpan with xcodebuild.*
    4.77 +
    4.78 +```
    4.79 +git clone https://github.com/fdik/libetpan libetpan-osx
    4.80 +cd libetpan-osx/build-mac
    4.81 +xcodebuild -project libetpan.xcodeproj/ -target "static libetpan"
    4.82 +mkdir ~/lib
    4.83 +cp build/Release/libetpan.a ~/lib/
    4.84 +```
    4.85 +
    4.86 +### Configuration
    4.87 +
    4.88 +You can change some defaults by editing `Makefile.conf`. But this readme assumes you don't.
    4.89 +
    4.90 +### Build
    4.91 +
    4.92 +```
    4.93 +make clean
    4.94 +make all
    4.95 +make db
    4.96 +```
    4.97 +
    4.98 +Done! The result should be (among others):
    4.99 +
   4.100 +```
   4.101 +./src/libpEpEngine.a
   4.102 +./src/libpEpEngine.dylib
   4.103 +```
   4.104 +
   4.105 +### Install
   4.106 +
   4.107 +Install (you might need sudo for some commands, depending on how your system is set up):
   4.108 +
   4.109 +```
   4.110  make install
   4.111 +make -C db install
   4.112 +```
   4.113 +
   4.114 +Since the `system.db` rarely changes, `make -C db install` is not needed for every build.
   4.115 +
   4.116 +### Run tests
   4.117 +
   4.118 +Make sure that you add `/opt/local/lib` to each definition of `LD_LIBRARY_PATH`
   4.119 +in `test/Makefile`. This ensures that libgpgme will be found:
   4.120 +
   4.121 +```
   4.122 +test: pEpEngineTest
   4.123 +        LD_LIBRARY_PATH=/opt/local/lib:~/lib:../src ./pEpEngineTest
   4.124 +```
   4.125 +
   4.126 +```
   4.127 +make test
   4.128  ```
   4.129  
   4.130  # Building for iOS
     5.1 --- a/README.txt	Fri Jul 08 21:29:55 2016 +0200
     5.2 +++ b/README.txt	Wed Jul 13 18:05:35 2016 +0200
     5.3 @@ -61,6 +61,7 @@
     5.4  * Asn1c, download from https://lionet.info/soft/asn1c-0.9.27.tar.gz
     5.5         (Debian's version 0.9.24 does not work)
     5.6  
     5.7 +* yml2, which needs lxml (where to get?)
     5.8  
     5.9  2. Building p≡p engine
    5.10  ----------------------
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/db/mkpass	Wed Jul 13 18:05:35 2016 +0200
     6.3 @@ -0,0 +1,13 @@
     6.4 +#!/bin/sh
     6.5 +
     6.6 +if [ $1/ == / ] ; then
     6.7 +    lang=en
     6.8 +else
     6.9 +    if [ $1/ == -h/ -o $2/ != / ] ; then
    6.10 +        echo usage: $0 [ISO 639 language code]
    6.11 +        exit 0
    6.12 +    fi
    6.13 +    lang=$1
    6.14 +fi
    6.15 +
    6.16 +trustwords.py -l $lang ` hexdump -vxn 10 /dev/random | sed -E 's/^[0-9a-z]+//'`
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/macports_env.sh	Wed Jul 13 18:05:35 2016 +0200
     7.3 @@ -0,0 +1,14 @@
     7.4 +# Typical pure MacPorts environment
     7.5 +
     7.6 +# Restrict to MacPorts
     7.7 +export PATH=/opt/local/bin:/opt/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin
     7.8 +
     7.9 +# Make sure the Apple python (which will be triggered by the makefile)
    7.10 +# has access to the Python libs installed for MacPorts
    7.11 +export PYTHONPATH=/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/
    7.12 +
    7.13 +# YML processing might complain about that. Make sure the locale exists (locale -a)
    7.14 +export LC_ALL=en_US.UTF-8
    7.15 +
    7.16 +# Search paths for includes used when doing YML processing
    7.17 +export YML_PATH=~/yml2/
     8.1 --- a/src/Makefile	Fri Jul 08 21:29:55 2016 +0200
     8.2 +++ b/src/Makefile	Wed Jul 13 18:05:35 2016 +0200
     8.3 @@ -14,7 +14,7 @@
     8.4  CFLAGS?=-I$(GPGME_IN)/include -I$(HOME)/include -I/opt/local/include $(OPTIMIZE) -pedantic \
     8.5  	-DSYSTEM_DB=\"$(SYSTEM_DB)\" -DLIBGPGME=\"$(LIBGPGME)\" -I../asn.1
     8.6  LDFLAGS?=-lc -shared -arch x86_64 \
     8.7 -	-L$(HOME)/lib -L/opt/local/lib -letpan -lsqlite3 -L../asn.1 -lasn1
     8.8 +	-L$(HOME)/lib -L/usr/lib -L/opt/local/lib -letpan -lsqlite3 -L../asn.1 -lasn1 -lz -liconv
     8.9  
    8.10  else
    8.11  $(error don't know how to make for $(BUILD_FOR) on $(BUILD_ON))
    8.12 @@ -59,8 +59,7 @@
    8.13  
    8.14  all: $(TARGET)
    8.15  
    8.16 -sync_fsm.c: ../sync/sync.fsm
    8.17 -	make -C ../sync
    8.18 +include Makefile.protocols
    8.19  
    8.20  %.d: %.c
    8.21  	@set -e; rm -f $@; \
     9.1 --- a/src/etpan_mime.c	Fri Jul 08 21:29:55 2016 +0200
     9.2 +++ b/src/etpan_mime.c	Wed Jul 13 18:05:35 2016 +0200
     9.3 @@ -136,7 +136,8 @@
     9.4      if (content->ct_parameters == NULL)
     9.5          if (parameters)
     9.6              clist_free(parameters);
     9.7 -
     9.8 +    if (param)
     9.9 +        mailmime_parameter_free(param);
    9.10  	return NULL;
    9.11  }
    9.12  
    10.1 --- a/src/identity_list.c	Fri Jul 08 21:29:55 2016 +0200
    10.2 +++ b/src/identity_list.c	Wed Jul 13 18:05:35 2016 +0200
    10.3 @@ -21,6 +21,8 @@
    10.4  DYNAMIC_API identity_list *identity_list_dup(const identity_list *src)
    10.5  {
    10.6      assert(src);
    10.7 +    if (src == NULL)
    10.8 +        return NULL;
    10.9  
   10.10      pEp_identity *_ident = identity_dup(src->ident);
   10.11      if (_ident == NULL)
   10.12 @@ -53,7 +55,9 @@
   10.13  DYNAMIC_API identity_list *identity_list_add(identity_list *id_list, pEp_identity *ident)
   10.14  {
   10.15      assert(ident);
   10.16 -
   10.17 +    if (ident == NULL)
   10.18 +        return NULL;
   10.19 +    
   10.20      if (id_list == NULL)
   10.21          return new_identity_list(ident);
   10.22  
    11.1 --- a/src/keymanagement.c	Fri Jul 08 21:29:55 2016 +0200
    11.2 +++ b/src/keymanagement.c	Wed Jul 13 18:05:35 2016 +0200
    11.3 @@ -142,21 +142,23 @@
    11.4      
    11.5      assert(status != PEP_OUT_OF_MEMORY);
    11.6      if (status == PEP_OUT_OF_MEMORY)
    11.7 -        return PEP_OUT_OF_MEMORY;
    11.8 +        goto exit_free;
    11.9  
   11.10      if (stored_identity) {
   11.11          PEP_comm_type _comm_type_key;
   11.12          status = get_key_rating(session, stored_identity->fpr, &_comm_type_key);
   11.13          assert(status != PEP_OUT_OF_MEMORY);
   11.14          if (status == PEP_OUT_OF_MEMORY)
   11.15 -            return PEP_OUT_OF_MEMORY;
   11.16 +            goto exit_free;
   11.17  
   11.18          if (EMPTYSTR(identity->username)) {
   11.19              free(identity->username);
   11.20              identity->username = strdup(stored_identity->username);
   11.21              assert(identity->username);
   11.22 -            if (identity->username == NULL)
   11.23 -                return PEP_OUT_OF_MEMORY;
   11.24 +            if (identity->username == NULL){
   11.25 +                status = PEP_OUT_OF_MEMORY;
   11.26 +                goto exit_free;
   11.27 +            }
   11.28          }
   11.29  
   11.30          if (EMPTYSTR(identity->fpr)) {
   11.31 @@ -167,7 +169,7 @@
   11.32              if (_comm_type_key < PEP_ct_unconfirmed_encryption) {
   11.33                  PEP_STATUS status = elect_pubkey(session, identity);
   11.34                  if (status != PEP_STATUS_OK)
   11.35 -                    return status;
   11.36 +                    goto exit_free;
   11.37              }
   11.38              else {
   11.39                  identity->comm_type = stored_identity->comm_type;
   11.40 @@ -190,7 +192,7 @@
   11.41                  status = get_trust(session, identity);
   11.42                  assert(status != PEP_OUT_OF_MEMORY);
   11.43                  if (status == PEP_OUT_OF_MEMORY)
   11.44 -                    return PEP_OUT_OF_MEMORY;
   11.45 +                    goto exit_free;
   11.46                  if (identity->comm_type < stored_identity->comm_type)
   11.47                      identity->comm_type = PEP_ct_unknown;
   11.48              }
   11.49 @@ -209,14 +211,14 @@
   11.50              status = get_key_rating(session, identity->fpr, &_comm_type_key);
   11.51              assert(status != PEP_OUT_OF_MEMORY);
   11.52              if (status == PEP_OUT_OF_MEMORY)
   11.53 -                return PEP_OUT_OF_MEMORY;
   11.54 +                goto exit_free;
   11.55  
   11.56              identity->comm_type = _comm_type_key;
   11.57          }
   11.58          else /* EMPTYSTR(identity->fpr) */ {
   11.59              PEP_STATUS status = elect_pubkey(session, identity);
   11.60              if (status != PEP_STATUS_OK)
   11.61 -                return status;
   11.62 +                goto exit_free;
   11.63          }
   11.64      }
   11.65  
   11.66 @@ -228,8 +230,10 @@
   11.67          if (EMPTYSTR(identity->username)) { // mitigate
   11.68              free(identity->username);
   11.69              identity->username = strdup("anonymous");
   11.70 -            if (identity->username == NULL)
   11.71 -                return PEP_OUT_OF_MEMORY;
   11.72 +            if (identity->username == NULL){
   11.73 +                status = PEP_OUT_OF_MEMORY;
   11.74 +                goto exit_free;
   11.75 +            }
   11.76          }
   11.77  
   11.78          // Identity doesn't get stored if call was just about checking existing
   11.79 @@ -239,7 +243,7 @@
   11.80              status = set_identity(session, identity);
   11.81              assert(status == PEP_STATUS_OK);
   11.82              if (status != PEP_STATUS_OK) {
   11.83 -                return status;
   11.84 +                goto exit_free;
   11.85              }
   11.86          }
   11.87      }
   11.88 @@ -249,6 +253,12 @@
   11.89          if (session->examine_identity)
   11.90              session->examine_identity(identity, session->examine_management);
   11.91  
   11.92 +exit_free :
   11.93 +    
   11.94 +    if (stored_identity){
   11.95 +        free_identity(stored_identity);
   11.96 +    }
   11.97 +
   11.98      return status;
   11.99  }
  11.100  
    12.1 --- a/src/message_api.c	Fri Jul 08 21:29:55 2016 +0200
    12.2 +++ b/src/message_api.c	Wed Jul 13 18:05:35 2016 +0200
    12.3 @@ -33,11 +33,17 @@
    12.4      return bl && string_equality(bl->mime_type, mt);
    12.5  }
    12.6  
    12.7 +//
    12.8 +// This function presumes the file ending is a proper substring of the
    12.9 +// filename (i.e. if bl->filename is "a.pgp" and fe is ".pgp", it will
   12.10 +// return true, but if bl->filename is ".pgp" and fe is ".pgp", it will
   12.11 +// return false. This is desired behaviour.
   12.12 +//
   12.13  static bool is_fileending(const bloblist_t *bl, const char *fe)
   12.14  {
   12.15      assert(fe);
   12.16 -
   12.17 -    if (bl == NULL || bl->filename == NULL)
   12.18 +    
   12.19 +    if (bl == NULL || bl->filename == NULL || fe == NULL)
   12.20          return false;
   12.21  
   12.22      assert(bl && bl->filename);
   12.23 @@ -64,7 +70,10 @@
   12.24  
   12.25          stringpair_list_t *field = stringpair_list_add(msg->opt_fields, pair);
   12.26          if (field == NULL)
   12.27 +        {
   12.28 +            free_stringpair(pair);
   12.29              return;
   12.30 +        }
   12.31  
   12.32          if (msg->opt_fields == NULL)
   12.33              msg->opt_fields = field;
   12.34 @@ -78,6 +87,17 @@
   12.35      assert(shortmsg);
   12.36      assert(strcmp(shortmsg, "pEp") != 0);
   12.37  
   12.38 +    if (!shortmsg || strcmp(shortmsg, "pEp") == 0) {
   12.39 +        if (!longmsg) {
   12.40 +            return NULL;
   12.41 +        }
   12.42 +        else {
   12.43 +            char *result = strdup(longmsg);
   12.44 +            assert(result);
   12.45 +            return result;
   12.46 +        }
   12.47 +    }
   12.48 +        
   12.49      if (longmsg == NULL)
   12.50          longmsg = "";
   12.51  
   12.52 @@ -94,7 +114,7 @@
   12.53      return ptext;
   12.54  }
   12.55  
   12.56 -static int seperate_short_and_long(const char *src, char **shortmsg, char **longmsg)
   12.57 +static int separate_short_and_long(const char *src, char **shortmsg, char **longmsg)
   12.58  {
   12.59      char *_shortmsg = NULL;
   12.60      char *_longmsg = NULL;
   12.61 @@ -102,6 +122,9 @@
   12.62      assert(src);
   12.63      assert(shortmsg);
   12.64      assert(longmsg);
   12.65 +    
   12.66 +    if (src == NULL || shortmsg == NULL || longmsg == NULL)
   12.67 +        return -1;
   12.68  
   12.69      *shortmsg = NULL;
   12.70      *longmsg = NULL;
   12.71 @@ -166,6 +189,9 @@
   12.72      assert(dst);
   12.73      assert(src);
   12.74  
   12.75 +    if(!(dst && src))
   12.76 +        return PEP_ILLEGAL_VALUE;
   12.77 +
   12.78      free_timestamp(dst->sent);
   12.79      dst->sent = NULL;
   12.80      if (src->sent) {
   12.81 @@ -272,6 +298,8 @@
   12.82      message * msg = NULL;
   12.83  
   12.84      assert(src);
   12.85 +    if (src == NULL)
   12.86 +        return NULL;
   12.87  
   12.88      msg = calloc(1, sizeof(message));
   12.89      assert(msg);
   12.90 @@ -340,6 +368,9 @@
   12.91      _src->enc_format = PEP_enc_none;
   12.92      status = mime_encode_message(_src, true, &mimetext);
   12.93      assert(status == PEP_STATUS_OK);
   12.94 +    if (status != PEP_STATUS_OK)
   12.95 +        goto pep_error;
   12.96 +    
   12.97      if (free_ptext){
   12.98          free(ptext);
   12.99          free_ptext=0;
  12.100 @@ -682,9 +713,9 @@
  12.101  
  12.102      assert(blob);
  12.103  
  12.104 -    if (blob->filename == NULL)
  12.105 +    if (blob == NULL || blob->filename == NULL)
  12.106          return false;
  12.107 -
  12.108 +    
  12.109      ext = strrchr(blob->filename, '.');
  12.110      if (ext == NULL)
  12.111          return false;
  12.112 @@ -706,6 +737,8 @@
  12.113  {
  12.114      assert(blob);
  12.115      assert(blob->filename);
  12.116 +    if (blob == NULL || blob->filename == NULL)
  12.117 +        return false;
  12.118  
  12.119      if (strncmp(blob->filename, "PGPexch.htm.", 12) == 0) {
  12.120          if (strcmp(blob->filename + 11, ".pgp") == 0 ||
  12.121 @@ -721,7 +754,9 @@
  12.122      char *ext;
  12.123  
  12.124      assert(filename);
  12.125 -
  12.126 +    if (filename == NULL)
  12.127 +        return NULL;
  12.128 +    
  12.129      ext = strrchr(filename, '.');
  12.130      if (ext == NULL)
  12.131          return NULL;
  12.132 @@ -764,6 +799,9 @@
  12.133  
  12.134      assert(session);
  12.135      assert(fpr);
  12.136 +    
  12.137 +    if (session == NULL || fpr == NULL)
  12.138 +        return PEP_rating_undefined;
  12.139  
  12.140      PEP_STATUS status = get_key_rating(session, fpr, &comm_type);
  12.141      if (status != PEP_STATUS_OK)
  12.142 @@ -898,6 +936,9 @@
  12.143  {
  12.144      assert(session);
  12.145      assert(msg);
  12.146 +    
  12.147 +    if (session == NULL || msg == NULL)
  12.148 +        return false;
  12.149  
  12.150      bool remove = false;
  12.151  
  12.152 @@ -941,7 +982,7 @@
  12.153  {
  12.154      assert(session);
  12.155      assert(msg);
  12.156 -
  12.157 +    
  12.158      if (msg->dir == PEP_dir_incoming)
  12.159          return;
  12.160  
  12.161 @@ -972,7 +1013,7 @@
  12.162  PEP_cryptotech determine_encryption_format(message *msg)
  12.163  {
  12.164      assert(msg);
  12.165 -
  12.166 +    
  12.167      if (is_PGP_message_text(msg->longmsg)) {
  12.168          msg->enc_format = PEP_enc_pieces;
  12.169          return PEP_crypt_OpenPGP;
  12.170 @@ -1163,6 +1204,8 @@
  12.171      if (msg && msg->shortmsg == NULL) {
  12.172          msg->shortmsg = strdup("pEp");
  12.173          assert(msg->shortmsg);
  12.174 +        if (msg->shortmsg == NULL)
  12.175 +            goto enomem;
  12.176      }
  12.177  
  12.178      if (msg)
  12.179 @@ -1192,22 +1235,26 @@
  12.180  
  12.181  // update comm_type to pEp_ct_pEp if needed
  12.182  
  12.183 -static void _update_identity_for_incoming_message(
  12.184 +static PEP_STATUS _update_identity_for_incoming_message(
  12.185          PEP_SESSION session,
  12.186          const message *src
  12.187      )
  12.188  {
  12.189 -    if (src->from && src->from->user_id && src->from->address) {
  12.190 -        update_identity(session, src->from);
  12.191 -        if (is_a_pEpmessage(src)
  12.192 +    PEP_STATUS status;
  12.193 +    if (src->from && src->from->address) {
  12.194 +        status = update_identity(session, src->from);
  12.195 +        if (status == PEP_STATUS_OK
  12.196 +                && is_a_pEpmessage(src)
  12.197                  && src->from->comm_type >= PEP_ct_OpenPGP_unconfirmed
  12.198                  && src->from->comm_type != PEP_ct_pEp_unconfirmed
  12.199                  && src->from->comm_type != PEP_ct_pEp)
  12.200          {
  12.201              src->from->comm_type |= PEP_ct_pEp_unconfirmed;
  12.202 -            update_identity(session, src->from);
  12.203 +            status = update_identity(session, src->from);
  12.204          }
  12.205 +        return status;
  12.206      }
  12.207 +    return PEP_ILLEGAL_VALUE;
  12.208  }
  12.209  
  12.210  DYNAMIC_API PEP_STATUS _decrypt_message(
  12.211 @@ -1246,7 +1293,10 @@
  12.212  
  12.213      // Update src->from in case we just imported a key
  12.214      // we would need to check signature
  12.215 -    _update_identity_for_incoming_message(session, src);
  12.216 +    status = _update_identity_for_incoming_message(session, src);
  12.217 +    if(status != PEP_STATUS_OK)
  12.218 +        return status;
  12.219 +
  12.220      PEP_cryptotech crypto = determine_encryption_format(src);
  12.221  
  12.222      *dst = NULL;
  12.223 @@ -1322,6 +1372,9 @@
  12.224                          attctext = _s->value;
  12.225                          attcsize = _s->size;
  12.226  
  12.227 +                        free(ptext);
  12.228 +                        ptext = NULL;
  12.229 +
  12.230                          status = decrypt_and_verify(session, attctext, attcsize,
  12.231                                  &ptext, &psize, &_keylist);
  12.232                          free_stringlist(_keylist);
  12.233 @@ -1397,7 +1450,7 @@
  12.234                      char * shortmsg;
  12.235                      char * longmsg;
  12.236  
  12.237 -                    int r = seperate_short_and_long(msg->longmsg, &shortmsg,
  12.238 +                    int r = separate_short_and_long(msg->longmsg, &shortmsg,
  12.239                              &longmsg);
  12.240                      if (r == -1)
  12.241                          goto enomem;
  12.242 @@ -1448,6 +1501,8 @@
  12.243              // we would need to check signature
  12.244  
  12.245              _update_identity_for_incoming_message(session, src);
  12.246 +            if(status != PEP_STATUS_OK)
  12.247 +                goto pep_error;
  12.248              
  12.249              char *re_ptext = NULL;
  12.250              size_t re_psize;
  12.251 @@ -1591,6 +1646,29 @@
  12.252  
  12.253  }
  12.254  
  12.255 +static void _max_comm_type_from_identity_list(
  12.256 +        identity_list *identities, 
  12.257 +        PEP_SESSION session,
  12.258 +        PEP_comm_type *max_comm_type,
  12.259 +        bool *comm_type_determined
  12.260 +    )
  12.261 +{
  12.262 +    identity_list * il;
  12.263 +    for (il = identities; il != NULL; il = il->next)
  12.264 +    {
  12.265 +        if (il->ident)
  12.266 +        {
  12.267 +            PEP_STATUS status = update_identity(session, il->ident);
  12.268 +            if (status == PEP_STATUS_OK)
  12.269 +            {
  12.270 +                *max_comm_type = _get_comm_type(session, *max_comm_type,
  12.271 +                        il->ident);
  12.272 +                *comm_type_determined = true;
  12.273 +            }
  12.274 +        }
  12.275 +    }
  12.276 +}
  12.277 +
  12.278  DYNAMIC_API PEP_STATUS outgoing_message_color(
  12.279          PEP_SESSION session,
  12.280          message *msg,
  12.281 @@ -1600,7 +1678,6 @@
  12.282      PEP_STATUS status = PEP_STATUS_OK;
  12.283      PEP_comm_type max_comm_type = PEP_ct_pEp;
  12.284      bool comm_type_determined = false;
  12.285 -    identity_list * il;
  12.286  
  12.287      assert(session);
  12.288      assert(msg);
  12.289 @@ -1620,38 +1697,14 @@
  12.290      if (status != PEP_STATUS_OK)
  12.291          return status;
  12.292  
  12.293 -    for (il = msg->to; il != NULL; il = il->next)
  12.294 -    {
  12.295 -        if (il->ident)
  12.296 -        {
  12.297 -            update_identity(session, il->ident);
  12.298 -            max_comm_type = _get_comm_type(session, max_comm_type,
  12.299 -                    il->ident);
  12.300 -            comm_type_determined = true;
  12.301 -        }
  12.302 -    }
  12.303 +    _max_comm_type_from_identity_list(msg->to, session,
  12.304 +                                      &max_comm_type, &comm_type_determined);
  12.305  
  12.306 -    for (il = msg->cc; il != NULL; il = il->next)
  12.307 -    {
  12.308 -        if (il->ident)
  12.309 -        {
  12.310 -            update_identity(session, il->ident);
  12.311 -            max_comm_type = _get_comm_type(session, max_comm_type,
  12.312 -                    il->ident);
  12.313 -            comm_type_determined = true;
  12.314 -        }
  12.315 -    }
  12.316 +    _max_comm_type_from_identity_list(msg->cc, session,
  12.317 +                                      &max_comm_type, &comm_type_determined);
  12.318          
  12.319 -    for (il = msg->bcc; il != NULL; il = il->next)
  12.320 -    {
  12.321 -        if (il->ident)
  12.322 -        {
  12.323 -            update_identity(session, il->ident);
  12.324 -            max_comm_type = _get_comm_type(session, max_comm_type,
  12.325 -                                           il->ident);
  12.326 -            comm_type_determined = true;
  12.327 -        }
  12.328 -    }
  12.329 +    _max_comm_type_from_identity_list(msg->bcc, session,
  12.330 +                                      &max_comm_type, &comm_type_determined);
  12.331  
  12.332      if (comm_type_determined == false)
  12.333          *color = PEP_rating_undefined;
    13.1 --- a/src/pgp_gpg.c	Fri Jul 08 21:29:55 2016 +0200
    13.2 +++ b/src/pgp_gpg.c	Wed Jul 13 18:05:35 2016 +0200
    13.3 @@ -29,9 +29,17 @@
    13.4          int length = stringlist_length(keys);
    13.5          unsigned int n = (1 << length) - 1;
    13.6  
    13.7 +        // make sure we 1) have the same number of keys and values
    13.8 +        // and 2) we don't have more key/value pairs than
    13.9 +        // the size of the bitfield used to hold the indices
   13.10 +        // of key/value pairs matching keys in the config file.
   13.11          assert(length <= sizeof(unsigned int) * CHAR_BIT);
   13.12          assert(length == stringlist_length(values));
   13.13 -
   13.14 +        if (!(length == stringlist_length(values) &&
   13.15 +              length <= sizeof(unsigned int) * CHAR_BIT)) {
   13.16 +            return false;
   13.17 +        }
   13.18 +        
   13.19          do {
   13.20              char * s;
   13.21  
    14.1 --- a/src/platform_unix.c	Fri Jul 08 21:29:55 2016 +0200
    14.2 +++ b/src/platform_unix.c	Wed Jul 13 18:05:35 2016 +0200
    14.3 @@ -52,7 +52,17 @@
    14.4  
    14.5  long int random(void)
    14.6  {
    14.7 -    static unsigned short xsubi[3] = {'p', 'E', 'p'};
    14.8 +    static bool seeded = false;
    14.9 +    static unsigned short xsubi[3];
   14.10 +    if(!seeded)
   14.11 +    {
   14.12 +        const long long t = (long long)time(NULL);
   14.13 +        xsubi[0] = (unsigned short)t;
   14.14 +        xsubi[1] = (unsigned short)(t>>16);
   14.15 +        xsubi[2] = (unsigned short)(t>>32);
   14.16 +        seeded = true;
   14.17 +    }
   14.18 +
   14.19      return nrand48(xsubi);
   14.20  }
   14.21  
   14.22 @@ -65,7 +75,7 @@
   14.23          char *tw_env;
   14.24          if(tw_env = getenv("TRUSTWORDS")){
   14.25              char *p = stpncpy(buffer, tw_env, MAX_PATH);
   14.26 -            size_t len = MAX_PATH - (p - buffer) - 2;
   14.27 +            ssize_t len = MAX_PATH - (p - buffer) - 2;
   14.28  
   14.29              if (len < strlen(SYSTEM_DB_FILENAME)) {
   14.30                  assert(0);
   14.31 @@ -93,7 +103,7 @@
   14.32          char *home_env;
   14.33          if((home_env = getenv("HOME"))){
   14.34              char *p = stpncpy(buffer, home_env, MAX_PATH);
   14.35 -            size_t len = MAX_PATH - (p - buffer) - 2;
   14.36 +            ssize_t len = MAX_PATH - (p - buffer) - 2;
   14.37  
   14.38              if (len < strlen(LOCAL_DB_FILENAME)) {
   14.39                  assert(0);
   14.40 @@ -123,7 +133,7 @@
   14.41  
   14.42      if (!done) {
   14.43          char *p;
   14.44 -        size_t len;
   14.45 +        ssize_t len;
   14.46          char *gpg_home_env = getenv("GNUPGHOME");
   14.47          char *home_env = getenv("HOME");
   14.48  
   14.49 @@ -200,7 +210,7 @@
   14.50          char *p;
   14.51          p = stpncpy(agent_path, dirname, MAX_PATH);
   14.52          
   14.53 -        size_t len = MAX_PATH - (p - agent_path) - 2;
   14.54 +        ssize_t len = MAX_PATH - (p - agent_path) - 2;
   14.55  
   14.56          if (len < strlen(gpg_agent_conf_name))
   14.57          {
    15.1 --- a/src/stringlist.c	Fri Jul 08 21:29:55 2016 +0200
    15.2 +++ b/src/stringlist.c	Wed Jul 13 18:05:35 2016 +0200
    15.3 @@ -20,6 +20,8 @@
    15.4              return NULL;
    15.5          }
    15.6      }
    15.7 +    
    15.8 +    result->next = NULL; // needed for one-element lists
    15.9  
   15.10      return result;
   15.11  }
   15.12 @@ -34,12 +36,13 @@
   15.13      if (dst == NULL)
   15.14          return NULL;
   15.15  
   15.16 -    if (src->next) {
   15.17 -        dst->next = stringlist_dup(src->next);
   15.18 -        if (dst->next == NULL) {
   15.19 -            free_stringlist(dst);
   15.20 -            return NULL;
   15.21 -        }
   15.22 +    stringlist_t* src_curr = src->next;
   15.23 +    stringlist_t** dst_curr_ptr = &dst->next;
   15.24 +    
   15.25 +    while (src_curr) {
   15.26 +        *dst_curr_ptr = new_stringlist(src_curr->value);
   15.27 +        src_curr = src_curr->next;
   15.28 +        dst_curr_ptr = &((*dst_curr_ptr)->next);
   15.29      }
   15.30  
   15.31      return dst;
   15.32 @@ -49,28 +52,41 @@
   15.33          stringlist_t *stringlist,
   15.34          const char *value
   15.35      )
   15.36 -{
   15.37 +{  
   15.38      assert(value);
   15.39 +    if (value == NULL)
   15.40 +        return NULL;
   15.41  
   15.42 +    // empty list (no nodes)
   15.43      if (stringlist == NULL)
   15.44          return new_stringlist(value);
   15.45  
   15.46 -    if (stringlist->next != NULL)
   15.47 -        return stringlist_add(stringlist->next, value);
   15.48 +    // empty list (one node, no value)
   15.49      if (stringlist->value == NULL) {
   15.50 +        if (stringlist->next) 
   15.51 +            return NULL; // invalid list
   15.52 +            
   15.53          stringlist->value = strdup(value);
   15.54          assert(stringlist->value);
   15.55 +        
   15.56          if (stringlist->value == NULL)
   15.57              return NULL;
   15.58 +        
   15.59          return stringlist;
   15.60      }
   15.61 +    
   15.62 +    stringlist_t* list_curr = stringlist;
   15.63  
   15.64 -    stringlist->next = new_stringlist(value);
   15.65 -    assert(stringlist->next);
   15.66 -    if (stringlist->next == NULL)
   15.67 +    while (list_curr->next)
   15.68 +        list_curr = list_curr->next;
   15.69 +     
   15.70 +    list_curr->next = new_stringlist(value);
   15.71 +
   15.72 +    assert(list_curr->next);
   15.73 +    if (list_curr->next == NULL)
   15.74          return NULL;
   15.75  
   15.76 -    return stringlist->next;
   15.77 +    return list_curr->next;
   15.78  }
   15.79  
   15.80  DYNAMIC_API stringlist_t *stringlist_append(
   15.81 @@ -79,7 +95,10 @@
   15.82      )
   15.83  {
   15.84      assert(stringlist);
   15.85 +    if (stringlist == NULL)
   15.86 +        return NULL;
   15.87  
   15.88 +    // Second list is empty
   15.89      if (second == NULL || second->value == NULL)
   15.90          return stringlist;
   15.91  
   15.92 @@ -139,10 +158,16 @@
   15.93  
   15.94  DYNAMIC_API void free_stringlist(stringlist_t *stringlist)
   15.95  {
   15.96 -    if (stringlist) {
   15.97 -        free_stringlist(stringlist->next);
   15.98 -        free(stringlist->value);
   15.99 -        free(stringlist);
  15.100 +    stringlist_t *curr;
  15.101 +    stringlist_t *next;
  15.102 +    
  15.103 +    curr = stringlist;
  15.104 +    
  15.105 +    while (curr) {
  15.106 +        next = curr->next;
  15.107 +        free(curr->value);
  15.108 +        free(curr);
  15.109 +        curr = next;
  15.110      }
  15.111  }
  15.112  
    16.1 --- a/src/stringlist.h	Fri Jul 08 21:29:55 2016 +0200
    16.2 +++ b/src/stringlist.h	Wed Jul 13 18:05:35 2016 +0200
    16.3 @@ -24,6 +24,7 @@
    16.4  //  caveat:
    16.5  //      the value is being copied before being added to the list
    16.6  //      the original string is still being owned by the caller
    16.7 +//      the "next" pointer of the returned object is explicitly set to NULL
    16.8  
    16.9  DYNAMIC_API stringlist_t *new_stringlist(const char *value);
   16.10  
   16.11 @@ -66,6 +67,7 @@
   16.12  //
   16.13  //  return value:
   16.14  //      pointer to last element in stringlist or NULL if out of memory
   16.15 +//      or stringpair_list is NULL
   16.16  //
   16.17  //  caveat:
   16.18  //      all values are being copied before being added to the list
    17.1 --- a/src/stringpair.c	Fri Jul 08 21:29:55 2016 +0200
    17.2 +++ b/src/stringpair.c	Wed Jul 13 18:05:35 2016 +0200
    17.3 @@ -47,6 +47,9 @@
    17.4  DYNAMIC_API stringpair_t * stringpair_dup(const stringpair_t *src)
    17.5  {
    17.6      assert(src);
    17.7 +    if (src == NULL)
    17.8 +        return NULL;
    17.9 +    
   17.10      return new_stringpair(src->key, src->value);
   17.11  }
   17.12  
   17.13 @@ -58,6 +61,8 @@
   17.14      if (result && value)
   17.15          result->value = value;
   17.16  
   17.17 +    result->next = NULL;
   17.18 +    
   17.19      return result;
   17.20  }
   17.21  
   17.22 @@ -69,19 +74,24 @@
   17.23      if (src == NULL)
   17.24          return NULL;
   17.25  
   17.26 -    stringpair_list_t *dst = new_stringpair_list(src->value);
   17.27 +    stringpair_t* copy_pair = stringpair_dup(src->value);
   17.28 +    
   17.29 +    stringpair_list_t *dst = new_stringpair_list(copy_pair);
   17.30      if (dst == NULL)
   17.31          return NULL;
   17.32  
   17.33 -    if (src->next) {
   17.34 -        dst->next = stringpair_list_dup(src->next);
   17.35 -        if (dst->next == NULL) {
   17.36 -            free_stringpair_list(dst);
   17.37 -            return NULL;
   17.38 -        }
   17.39 +    stringpair_list_t* src_curr = src->next;
   17.40 +    stringpair_list_t** dst_curr_ptr = &dst->next;
   17.41 +
   17.42 +    while (src_curr) {
   17.43 +        copy_pair = stringpair_dup(src_curr->value);
   17.44 +        *dst_curr_ptr = new_stringpair_list(copy_pair);
   17.45 +        src_curr = src_curr->next;
   17.46 +        dst_curr_ptr = &((*dst_curr_ptr)->next);
   17.47      }
   17.48  
   17.49      return dst;
   17.50 +    
   17.51  }
   17.52  
   17.53  DYNAMIC_API stringpair_list_t *stringpair_list_add(
   17.54 @@ -91,23 +101,37 @@
   17.55  {
   17.56      assert(value);
   17.57  
   17.58 +    // empty list (no nodes)
   17.59      if (stringpair_list == NULL)
   17.60          return new_stringpair_list(value);
   17.61  
   17.62 -    if (stringpair_list->next)
   17.63 -        return stringpair_list_add(stringpair_list->next, value);
   17.64 -
   17.65 +    // empty list (one node, no value)
   17.66      if (stringpair_list->value == NULL) {
   17.67 -        assert(stringpair_list->next == NULL);
   17.68 +        if (stringpair_list->next)
   17.69 +            return NULL; // invalid list
   17.70 +            
   17.71          stringpair_list->value = value;
   17.72 +        assert(stringpair_list->value);
   17.73 +        
   17.74 +        if (stringpair_list->value == NULL)
   17.75 +            return NULL;
   17.76 +        
   17.77          return stringpair_list;
   17.78      }
   17.79 +    
   17.80 +    stringpair_list_t* list_curr = stringpair_list;
   17.81 +    
   17.82 +    while (list_curr->next)
   17.83 +        list_curr = list_curr->next;
   17.84 +     
   17.85 +    list_curr->next = new_stringpair_list(value);
   17.86  
   17.87 -    stringpair_list->next = new_stringpair_list(value);
   17.88 -    if (stringpair_list->next == NULL)
   17.89 +    assert(list_curr->next);
   17.90 +    if (list_curr->next == NULL)
   17.91          return NULL;
   17.92  
   17.93 -    return stringpair_list->next;
   17.94 +    return list_curr->next;
   17.95 +    
   17.96  }
   17.97  
   17.98  DYNAMIC_API stringpair_list_t *stringpair_list_append(
   17.99 @@ -116,16 +140,24 @@
  17.100      )
  17.101  {
  17.102      assert(stringpair_list);
  17.103 +    if (stringpair_list == NULL)
  17.104 +        return NULL;
  17.105  
  17.106 +    // second list is empty
  17.107      if (second == NULL || second->value == NULL)
  17.108          return stringpair_list;
  17.109  
  17.110      stringpair_list_t *_s = stringpair_list;
  17.111      stringpair_list_t *_s2;
  17.112      for (_s2 = second; _s2 != NULL; _s2 = _s2->next) {
  17.113 -        _s = stringpair_list_add(_s, _s2->value);
  17.114 -        if (_s == NULL)
  17.115 +        stringpair_t *_sp = stringpair_dup(_s2->value);
  17.116 +        if (_sp == NULL)
  17.117              return NULL;
  17.118 +        _s = stringpair_list_add(_s, _sp);
  17.119 +        if (_s == NULL){
  17.120 +            free_stringpair(_sp);
  17.121 +            return NULL;
  17.122 +        }
  17.123      }
  17.124      return _s;
  17.125  }
    18.1 --- a/src/stringpair.h	Fri Jul 08 21:29:55 2016 +0200
    18.2 +++ b/src/stringpair.h	Wed Jul 13 18:05:35 2016 +0200
    18.3 @@ -63,17 +63,19 @@
    18.4  //
    18.5  //  caveat:
    18.6  //      the ownership of the value goes to the stringpair_list
    18.7 +//      next pointer explicitly set to NULL
    18.8  
    18.9  DYNAMIC_API stringpair_list_t *new_stringpair_list(stringpair_t *value);
   18.10  
   18.11  
   18.12 -// stringpair_list_dup() - duplicate a stringpair_list
   18.13 +// stringpair_list_dup() - duplicate a stringpair_list (deep copy)
   18.14  //
   18.15  //  parameters:
   18.16  //      src (in)                stringpair_list to copy
   18.17  //
   18.18  //  return value:
   18.19  //      pointer to stringpair_list_t object or NULL if out of memory
   18.20 +//      stringpair value copies created by this function belong to the returned list
   18.21  
   18.22  DYNAMIC_API stringpair_list_t *stringpair_list_dup(
   18.23          const stringpair_list_t *src
   18.24 @@ -107,6 +109,7 @@
   18.25  //
   18.26  //  return value:
   18.27  //      pointer to last element in stringpair_list or NULL if out of memory
   18.28 +//      or stringpair_list is NULL
   18.29  //
   18.30  //  caveat:
   18.31  //      all values are being copied before being added to the list
    19.1 --- a/src/sync_actions.c	Fri Jul 08 21:29:55 2016 +0200
    19.2 +++ b/src/sync_actions.c	Wed Jul 13 18:05:35 2016 +0200
    19.3 @@ -108,7 +108,7 @@
    19.4  //  params:
    19.5  //      session (in)        session handle
    19.6  //      state (in)          state the state machine is in
    19.7 -//      partner (in)        partner in sync
    19.8 +//      partner (in)        partner to communicate with
    19.9  //
   19.10  //  returns:
   19.11  //      PEP_STATUS_OK or any other value on error
   19.12 @@ -202,7 +202,7 @@
   19.13  //  params:
   19.14  //      session (in)        session handle
   19.15  //      state (in)          state the state machine is in
   19.16 -//      partner (in)        partner in sync
   19.17 +//      partner (in)        partner to communicate with
   19.18  //
   19.19  //  returns:
   19.20  //      PEP_STATUS_OK or any other value on error
   19.21 @@ -238,7 +238,7 @@
   19.22  //  params:
   19.23  //      session (in)        session handle
   19.24  //      state (in)          state the state machine is in
   19.25 -//      partner (in)        partner in sync
   19.26 +//      partner (in)        partner to communicate with
   19.27  //
   19.28  //  returns:
   19.29  //      PEP_STATUS_OK or any other value on error
   19.30 @@ -274,7 +274,7 @@
   19.31  //  params:
   19.32  //      session (in)        session handle
   19.33  //      state (in)          state the state machine is in
   19.34 -//      partner (in)        partner in sync
   19.35 +//      partner (in)        partner to communicate with
   19.36  //
   19.37  //  returns:
   19.38  //      PEP_STATUS_OK or any other value on error
   19.39 @@ -395,3 +395,4 @@
   19.40      return status;
   19.41  }
   19.42  
   19.43 +
    20.1 --- a/src/sync_fsm.c	Fri Jul 08 21:29:55 2016 +0200
    20.2 +++ b/src/sync_fsm.c	Wed Jul 13 18:05:35 2016 +0200
    20.3 @@ -98,3 +98,4 @@
    20.4  
    20.5      return state;
    20.6  }
    20.7 +
    21.1 --- a/sync/Makefile	Fri Jul 08 21:29:55 2016 +0200
    21.2 +++ b/sync/Makefile	Wed Jul 13 18:05:35 2016 +0200
    21.3 @@ -1,16 +1,16 @@
    21.4  include ../Makefile.conf
    21.5  
    21.6 -all: ../src/sync_fsm.c
    21.7 +all: .statemachines
    21.8  
    21.9 -skeleton: ../src/sync_actions.c.skeleton
   21.10 +skeleton: .skeletons
   21.11  
   21.12 -../src/sync_actions.c.skeleton: sync.fsm gen_actions_skeleton.ysl2 fsm.yml2 functions.ysl2
   21.13 +.skeletons: devicegroup.fsm gen_actions_skeleton.ysl2 fsm.yml2 functions.ysl2
   21.14  	$(YML2PROC) -y gen_actions_skeleton.ysl2 $< -o $@
   21.15  
   21.16 -../src/sync_fsm.c: sync.fsm gen_statemachine.ysl2 fsm.yml2 functions.ysl2
   21.17 +.statemachines: devicegroup.fsm gen_statemachine.ysl2 fsm.yml2 functions.ysl2
   21.18  	$(YML2PROC) -y gen_statemachine.ysl2 $< -o $@
   21.19  
   21.20  .PHONY: clean
   21.21  
   21.22  clean:
   21.23 -	rm -f *.xml *.xsl ../src/sync_fsm.* ../src/*.skeleton
   21.24 +	rm -f *.xml *.xsl ../src/sync_fsm.* ../src/*.skeleton .statemachines .skeletons
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/sync/devicegroup.fsm	Wed Jul 13 18:05:35 2016 +0200
    22.3 @@ -0,0 +1,87 @@
    22.4 +// DeviceGroup protocol for p≡p
    22.5 +
    22.6 +// Copyleft (c) 2016, p≡p foundation
    22.7 +
    22.8 +// Written by Volker Birk
    22.9 +
   22.10 +include ./fsm.yml2
   22.11 +
   22.12 +protocol DeviceGroup {
   22.13 +    // all messages have a timestamp, time out and are removed after timeout
   22.14 +
   22.15 +    fsm DeviceState filename=sync {
   22.16 +        state InitState {
   22.17 +            on Init {
   22.18 +                if (storedGroupKeys)
   22.19 +                    go Grouped;
   22.20 +                go Sole;
   22.21 +            }
   22.22 +        }
   22.23 +
   22.24 +        state Sole {
   22.25 +            on KeyGen
   22.26 +                do sendBeacon;
   22.27 +            on CannotDecrypt
   22.28 +                do sendBeacon;  // cry, baby
   22.29 +            on Beacon(Identity partner) // this event will not happen for already
   22.30 +                                        // rejected partners
   22.31 +                do sendHandshakeRequest(partner);
   22.32 +            on HandshakeRequest(Identity partner) {
   22.33 +                do sendHandshakeRequest(partner);
   22.34 +                go HandshakingSole(partner);
   22.35 +            }
   22.36 +        }
   22.37 +
   22.38 +        state HandshakingSole(Identity partner) {
   22.39 +            on Init
   22.40 +                do showHandshake(partner);
   22.41 +            on HandshakeRejected(Identity partner) {
   22.42 +                do reject(partner);             // sends Reject to partner and
   22.43 +                                                // stores rejection of partner
   22.44 +                go Sole;
   22.45 +            }
   22.46 +            on HandshakeAccepted(Identity partner) {
   22.47 +                if keyElectionWon(partner) {    // an already existing group
   22.48 +                                                // always wins
   22.49 +                    ownGroupKeys;
   22.50 +                    sendGroupKeys(partner);
   22.51 +                    go Grouped;
   22.52 +                }
   22.53 +                go WaitForGroupKeys(Identity partner);
   22.54 +            }
   22.55 +        }
   22.56 +    
   22.57 +        state WaitForGroupKeys(Identity partner) {
   22.58 +            on GroupKeys(Identity partner, Stringlist keys) {
   22.59 +                do storeGroupKeys(partner, keys);
   22.60 +                go Grouped;
   22.61 +            }
   22.62 +            on Cancel go Sole;
   22.63 +            on Reject(Identity partner) {
   22.64 +                do reject(partner);
   22.65 +                go Sole;
   22.66 +            }
   22.67 +        }
   22.68 +
   22.69 +        state Grouped {
   22.70 +            on KeyGen
   22.71 +                do sendGroupKeys; // always send all keys
   22.72 +            on HandshakeRequest(Identity partner) {
   22.73 +                do sendHandshakeRequest(partner);
   22.74 +                do showHandshake(partner);
   22.75 +            }
   22.76 +            on HandshakeRejected(Identity partner)
   22.77 +                do reject(partner);
   22.78 +            on HandshakeAccepted(Identity partner)
   22.79 +                do sendGroupKeys(partner);
   22.80 +            on Reject(Identity partner)
   22.81 +                do reject partner;
   22.82 +        }
   22.83 +
   22.84 +        tag InitState 0;
   22.85 +        tag Beacon 1;
   22.86 +        tag HandshakeRequest 2;
   22.87 +        tag GroupKeys 3;
   22.88 +    }
   22.89 +}
   22.90 +
    23.1 --- a/sync/gen_actions_skeleton.ysl2	Fri Jul 08 21:29:55 2016 +0200
    23.2 +++ b/sync/gen_actions_skeleton.ysl2	Wed Jul 13 18:05:35 2016 +0200
    23.3 @@ -9,35 +9,47 @@
    23.4  tstylesheet {
    23.5      include ./functions.ysl2
    23.6  
    23.7 -    template "/protocol/fsm" {
    23.8 -    ||
    23.9 -    `` const "name", "@name"
   23.10 -    // Actions for «@name» state machine
   23.11 +    template "/protocol/fsm" document "../src/{@filename}_actions.c.skeleton", "text" {
   23.12 +        const "name", "@name";
   23.13 +        const "filename", "@filename";
   23.14 +        ||
   23.15 +        // Actions for «@name» state machine
   23.16  
   23.17 -    #include <assert.h>
   23.18 -    #include "pEp_internal.h"
   23.19 -    #include "keymanagement.h"
   23.20 -    #include "message.h"
   23.21 -    #include "sync_fsm.h"
   23.22 -    #include "baseprotocol.h"
   23.23 -    #include "map_asn1.h"
   23.24 -    `` for "func:distinctName(//action)" if "substring(@name, 1, 4) = 'send'" | #include "../asn.1/«substring(@name, 5, 255)».h"
   23.25 -
   23.26 -    `` for "func:distinctName(//action)" call "action" with "action", ".", with "fsm", "$name";
   23.27 -
   23.28 -    ||
   23.29 +        #include <assert.h>
   23.30 +        #include "pEp_internal.h"
   23.31 +        #include "keymanagement.h"
   23.32 +        #include "message.h"
   23.33 +        #include "«@filename»_fsm.h"
   23.34 +        #include "baseprotocol.h"
   23.35 +        #include "map_asn1.h"
   23.36 +        ||
   23.37 +        for "func:distinctName(//action)"
   23.38 +            if "substring(@name, 1, 4) = 'send'"
   23.39 +                | #include "../asn.1/«substring(@name, 5, 255)».h"
   23.40 +        |
   23.41 +        for "func:distinctName(//action)"
   23.42 +            call "action"
   23.43 +                with "action", ".",
   23.44 +                with "fsm", "$name",
   23.45 +                with "filename", "$filename";
   23.46 +        |
   23.47      }
   23.48  
   23.49      function "action" {
   23.50          param "action";
   23.51          param "fsm";
   23.52 +        param "filename", "'###'";
   23.53          choose {
   23.54              when "substring($action/@name, 1, 4) = 'send'"
   23.55 -                call "send_action" with "action", "$action",
   23.56 -                     with "fsm", "$fsm";
   23.57 +                call "send_action"
   23.58 +                    with "action", "$action",
   23.59 +                    with "fsm", "$fsm",
   23.60 +                    with "filename", "$filename";
   23.61              otherwise
   23.62 -                call "other_action" with "action", "$action",
   23.63 -                     with "fsm", "$fsm";
   23.64 +                call "other_action"
   23.65 +                    with "action", "$action",
   23.66 +                    with "fsm", "$fsm",
   23.67 +                    with "filename", "$filename";
   23.68          }
   23.69      }
   23.70  
   23.71 @@ -63,6 +75,7 @@
   23.72      function "other_action" {
   23.73          param "action";
   23.74          param "fsm";
   23.75 +        param "filename", "'###'";
   23.76  
   23.77          ||
   23.78  
   23.79 @@ -71,7 +84,7 @@
   23.80          //  params:
   23.81          //      session (in)        session handle
   23.82          //      state (in)          state the state machine is in
   23.83 -        `` if "parm"        | //      partner (in)        partner in sync
   23.84 +        `` if "parm"        | //      partner (in)        partner to communicate with
   23.85          `` if "not(parm)"   | //      partner (in)        (must be NULL)
   23.86          //
   23.87          //  returns:
   23.88 @@ -105,6 +118,7 @@
   23.89      function "send_action" {
   23.90          param "action";
   23.91          param "fsm";
   23.92 +        param "filename", "'###'";
   23.93          const "name", "substring($action/@name, 5, 255)";
   23.94  
   23.95          ||
   23.96 @@ -114,7 +128,7 @@
   23.97          //  params:
   23.98          //      session (in)        session handle
   23.99          //      state (in)          state the state machine is in
  23.100 -        `` if "parm"        | //      partner (in)        partner in sync
  23.101 +        `` if "parm"        | //      partner (in)        partner to communicate with
  23.102          `` if "not(parm)"   | //      partner (in)        (must be NULL)
  23.103          //
  23.104          //  returns:
  23.105 @@ -159,15 +173,17 @@
  23.106                  goto error;
  23.107              if (Identity_from_Struct(me, &msg->me) == NULL)
  23.108                  goto enomem;
  23.109 -         `` if "parm or $name='OwnKeys'" |
  23.110 -         `` if "parm/partner"   |> if (Identity_from_Struct(partner, &msg->partner) == NULL)
  23.111 -         `` if "parm/partner"   |>> goto enomem;
  23.112 -         `` if "$name='OwnKeys'"|> stringlist_t *sl;
  23.113 -         `` if "$name='OwnKeys'"|> status = own_key_retrieve(session, &sl);
  23.114 -         `` if "$name='OwnKeys'"|> if (status != PEP_STATUS_OK)
  23.115 -         `` if "$name='OwnKeys'"|>> goto error;
  23.116 -         `` if "$name='OwnKeys'"|> if (KeyList_from_stringlist(sl, &msg->keylist) == NULL)
  23.117 -         `` if "$name='OwnKeys'"|>> goto enomem;
  23.118 +        ||
  23.119 +        if "parm or $name='OwnKeys'" |
  23.120 +        if "parm/partner"   |> if (Identity_from_Struct(partner, &msg->partner) == NULL)
  23.121 +        if "parm/partner"   |>> goto enomem;
  23.122 +        if "$name='OwnKeys'"|> stringlist_t *sl;
  23.123 +        if "$name='OwnKeys'"|> status = own_key_retrieve(session, &sl);
  23.124 +        if "$name='OwnKeys'"|> if (status != PEP_STATUS_OK)
  23.125 +        if "$name='OwnKeys'"|>> goto error;
  23.126 +        if "$name='OwnKeys'"|> if (KeyList_from_stringlist(sl, &msg->keylist) == NULL)
  23.127 +        if "$name='OwnKeys'"|>> goto enomem;
  23.128 +        ||
  23.129  
  23.130              if (asn_check_constraints(&asn_DEF_«$name», msg, NULL, NULL)) {
  23.131                  status = PEP_CONTRAINTS_VIOLATED;
  23.132 @@ -189,7 +205,7 @@
  23.133              free_identity(me);
  23.134              me = NULL;
  23.135  
  23.136 -            status = session->messageToSend(session->sync_obj, _message);
  23.137 +            status = session->messageToSend(session->«$filename»_obj, _message);
  23.138  
  23.139              free_message(_message);
  23.140              ASN_STRUCT_FREE(asn_DEF_«$name», msg);
    24.1 --- a/sync/gen_statemachine.ysl2	Fri Jul 08 21:29:55 2016 +0200
    24.2 +++ b/sync/gen_statemachine.ysl2	Wed Jul 13 18:05:35 2016 +0200
    24.3 @@ -9,8 +9,20 @@
    24.4  tstylesheet {
    24.5      include ./functions.ysl2
    24.6  
    24.7 -    template "/protocol/fsm" {
    24.8 -        document "../src/sync_fsm.h", "text" {
    24.9 +    template "/protocol" {
   24.10 +        document "../src/Makefile.protocols", "text"
   24.11 +            apply "fsm", 0, mode="make";
   24.12 +        apply "fsm", 0, mode=gen;
   24.13 +    }
   24.14 +
   24.15 +    template "fsm", mode=make
   24.16 +    ||
   24.17 +    «@filename»_fsm.c: ../sync/devicegroup.fsm
   24.18 +    \tmake -C ../«@filename»
   24.19 +    ||
   24.20 +
   24.21 +    template "fsm", mode=gen {
   24.22 +        document "../src/{@filename}_fsm.h", "text" {
   24.23          ||
   24.24          #pragma once
   24.25  
   24.26 @@ -85,7 +97,7 @@
   24.27  
   24.28          ||
   24.29          }
   24.30 -        document "../src/sync_driver.c", "text"
   24.31 +        document "../src/{@filename}_driver.c", "text"
   24.32          ||
   24.33          // Driver for «@name» state machine
   24.34  
   24.35 @@ -102,15 +114,16 @@
   24.36          {
   24.37              PEP_STATUS status = PEP_STATUS_OK;
   24.38  
   24.39 -            session->sync_state = fsm_«@name»(session, session->sync_state,
   24.40 +            session->«@filename»_state = fsm_«@name»(session, session->«@filename»_state,
   24.41                      event, partner, state_partner);
   24.42  
   24.43              return status;
   24.44          }
   24.45  
   24.46          ||
   24.47 +        document "../src/{@filename}_fsm.c", "text"
   24.48          ||
   24.49 -        #include "sync_fsm.h"
   24.50 +        #include "«@filename»_fsm.h"
   24.51  
   24.52          // state machine for «@name»
   24.53  
    25.1 --- a/sync/sync.fsm	Fri Jul 08 21:29:55 2016 +0200
    25.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.3 @@ -1,87 +0,0 @@
    25.4 -// DeviceGroup protocol for p≡p
    25.5 -
    25.6 -// Copyleft (c) 2016, p≡p foundation
    25.7 -
    25.8 -// Written by Volker Birk
    25.9 -
   25.10 -include ./fsm.yml2
   25.11 -
   25.12 -protocol DeviceGroup {
   25.13 -    // all messages have a timestamp, time out and are removed after timeout
   25.14 -
   25.15 -    fsm DeviceState {
   25.16 -        state InitState {
   25.17 -            on Init {
   25.18 -                if (storedGroupKeys)
   25.19 -                    go Grouped;
   25.20 -                go Sole;
   25.21 -            }
   25.22 -        }
   25.23 -
   25.24 -        state Sole {
   25.25 -            on KeyGen
   25.26 -                do sendBeacon;
   25.27 -            on CannotDecrypt
   25.28 -                do sendBeacon;  // cry, baby
   25.29 -            on Beacon(Identity partner) // this event will not happen for already
   25.30 -                                        // rejected partners
   25.31 -                do sendHandshakeRequest(partner);
   25.32 -            on HandshakeRequest(Identity partner) {
   25.33 -                do sendHandshakeRequest(partner);
   25.34 -                go HandshakingSole(partner);
   25.35 -            }
   25.36 -        }
   25.37 -
   25.38 -        state HandshakingSole(Identity partner) {
   25.39 -            on Init
   25.40 -                do showHandshake(partner);
   25.41 -            on HandshakeRejected(Identity partner) {
   25.42 -                do reject(partner);             // sends Reject to partner and
   25.43 -                                                // stores rejection of partner
   25.44 -                go Sole;
   25.45 -            }
   25.46 -            on HandshakeAccepted(Identity partner) {
   25.47 -                if keyElectionWon(partner) {    // an already existing group
   25.48 -                                                // always wins
   25.49 -                    ownGroupKeys;
   25.50 -                    sendGroupKeys(partner);
   25.51 -                    go Grouped;
   25.52 -                }
   25.53 -                go WaitForGroupKeys(Identity partner);
   25.54 -            }
   25.55 -        }
   25.56 -    
   25.57 -        state WaitForGroupKeys(Identity partner) {
   25.58 -            on GroupKeys(Identity partner, Stringlist keys) {
   25.59 -                do storeGroupKeys(partner, keys);
   25.60 -                go Grouped;
   25.61 -            }
   25.62 -            on Cancel go Sole;
   25.63 -            on Reject(Identity partner) {
   25.64 -                do reject(partner);
   25.65 -                go Sole;
   25.66 -            }
   25.67 -        }
   25.68 -
   25.69 -        state Grouped {
   25.70 -            on KeyGen
   25.71 -                do sendGroupKeys; // always send all keys
   25.72 -            on HandshakeRequest(Identity partner) {
   25.73 -                do sendHandshakeRequest(partner);
   25.74 -                do showHandshake(partner);
   25.75 -            }
   25.76 -            on HandshakeRejected(Identity partner)
   25.77 -                do reject(partner);
   25.78 -            on HandshakeAccepted(Identity partner)
   25.79 -                do sendGroupKeys(partner);
   25.80 -            on Reject(Identity partner)
   25.81 -                do reject partner;
   25.82 -        }
   25.83 -
   25.84 -        tag InitState 0;
   25.85 -        tag Beacon 1;
   25.86 -        tag HandshakeRequest 2;
   25.87 -        tag GroupKeys 3;
   25.88 -    }
   25.89 -}
   25.90 -
    26.1 --- a/test/message_api_test.cc	Fri Jul 08 21:29:55 2016 +0200
    26.2 +++ b/test/message_api_test.cc	Wed Jul 13 18:05:35 2016 +0200
    26.3 @@ -23,10 +23,10 @@
    26.4      // message_api test code
    26.5  
    26.6      cout << "creating message…\n";
    26.7 -    pEp_identity * me2 = new_identity("outlooktest@dingens.org", NULL, PEP_OWN_USERID, "Outlook Test");
    26.8 +    pEp_identity * me2 = new_identity("pep.test.alice@pep-project.org", NULL, PEP_OWN_USERID, "Alice Test");
    26.9      // pEp_identity * me2 = new_identity("test@nokey.plop", NULL, PEP_OWN_USERID, "Test no key");
   26.10      me2->me = true;
   26.11 -    identity_list *to2 = new_identity_list(new_identity("vb@dingens.org", NULL, "42", "Volker Birk"));
   26.12 +    identity_list *to2 = new_identity_list(new_identity("pep.test.bob@pep-project.org", NULL, "42", "Bob Test"));
   26.13      // identity_list *to2 = new_identity_list(new_identity("still@nokey.blup", NULL, "42", "Still no key"));
   26.14      message *msg2 = new_message(PEP_dir_outgoing);
   26.15      assert(msg2);
   26.16 @@ -84,7 +84,7 @@
   26.17      assert(keylist4);
   26.18      assert(color);
   26.19      PEP_comm_type ct = enc_msg2->from->comm_type;
   26.20 -    assert(ct == PEP_ct_pEp || ct == PEP_ct_pEp_unconfirmed);
   26.21 +    assert(ct == PEP_ct_pEp || ct == PEP_ct_pEp_unconfirmed || ct == PEP_ct_OpenPGP || ct == PEP_ct_OpenPGP_unconfirmed );
   26.22  
   26.23      free_stringpair_list(enc_msg2->opt_fields);
   26.24      enc_msg2->opt_fields = NULL;
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/test/stringlist_test.cc	Wed Jul 13 18:05:35 2016 +0200
    27.3 @@ -0,0 +1,112 @@
    27.4 +#include <stdlib.h>
    27.5 +#include <string.h>
    27.6 +#include "platform.h"
    27.7 +#include <iostream>
    27.8 +#include <fstream>
    27.9 +#include <assert.h>
   27.10 +
   27.11 +#include "stringlist.h"
   27.12 +
   27.13 +using namespace std;
   27.14 +
   27.15 +int main() {
   27.16 +    cout << "\n*** data structures: stringlist_test ***\n\n";
   27.17 +
   27.18 +    const char* str0 = "I am your father, Luke\n";
   27.19 +    
   27.20 +    // new_stringlist test code
   27.21 +    cout << "creating one-element stringlist…\n";
   27.22 +    
   27.23 +    stringlist_t* src = new_stringlist(str0);
   27.24 +    assert(src);
   27.25 +    assert(strcmp(src->value,str0) == 0);
   27.26 +    cout << "Value: " << src->value;
   27.27 +    assert(src->next == NULL);
   27.28 +    cout << "one-element stringlist created, next element is NULL\n";
   27.29 +    
   27.30 +    cout << "freeing stringlist…\n\n";
   27.31 +    free_stringlist(src);
   27.32 +    src = NULL;
   27.33 +    
   27.34 +    // test stringlist_add with four-element list
   27.35 +    cout << "creating four-element stringlist…\n";
   27.36 +    const char* str1 = "String 1";
   27.37 +    const char* str2 = "\tString 2";
   27.38 +    const char* str3 = "\tString 3";
   27.39 +    const char* str4 = "\tString 4\n";
   27.40 +    const char* strarr[4] = {str1, str2, str3, str4};
   27.41 +    cout << "stringlist_add on empty list…\n";
   27.42 +    src = stringlist_add(src, str1); // src is NULL
   27.43 +    assert(src);
   27.44 +    assert(stringlist_add(src, str2)); // returns ptr to new elt
   27.45 +    assert(stringlist_add(src, str3));
   27.46 +    assert(stringlist_add(src, str4));
   27.47 +    
   27.48 +    cout << "checking contents\n";
   27.49 +    stringlist_t* p = src;
   27.50 +    int i = 0;
   27.51 +    while (p) {
   27.52 +        assert(p->value);
   27.53 +        assert(strcmp(p->value, strarr[i++]) == 0);
   27.54 +        assert(p->value != *(strarr + i)); // ensure this is a copy
   27.55 +        cout << p->value;
   27.56 +        p = p->next;
   27.57 +    }
   27.58 +    assert(p == NULL); // list ends properly
   27.59 +    
   27.60 +    cout << "\nduplicating four-element stringlist…\n";
   27.61 +    stringlist_t* dst = stringlist_dup(src);
   27.62 +    assert(dst);
   27.63 +    
   27.64 +    stringlist_t* p_dst = dst;
   27.65 +    p = src;
   27.66 +
   27.67 +    cout << "checking contents\n";    
   27.68 +    while (p_dst) {
   27.69 +        assert(p_dst->value);
   27.70 +        assert(strcmp(p->value, p_dst->value) == 0);
   27.71 +        assert(p->value != p_dst->value); // ensure this is a copy
   27.72 +        cout << p_dst->value;
   27.73 +        p = p->next;
   27.74 +        p_dst = p_dst->next;
   27.75 +        assert((p == NULL) == (p_dst == NULL));
   27.76 +    }
   27.77 +    assert(p_dst == NULL);
   27.78 +        
   27.79 +    cout << "freeing stringlists…\n\n";
   27.80 +    free_stringlist(src);
   27.81 +    free_stringlist(dst);
   27.82 +    src = NULL;
   27.83 +    dst = NULL;
   27.84 +
   27.85 +    cout << "duplicating one-element stringlist…\n";    
   27.86 +    src = new_stringlist(str0);
   27.87 +    assert(src);
   27.88 +    dst = stringlist_dup(src);
   27.89 +    assert(strcmp(dst->value, str0) == 0);
   27.90 +    cout << "Value: " << src->value;
   27.91 +    assert(dst->next == NULL);
   27.92 +    cout << "one-element stringlist duped, next element is NULL\n";
   27.93 +    
   27.94 +    cout << "\nAdd to empty stringlist (node exists, but no value…)\n";
   27.95 +    if (src->value)
   27.96 +        free(src->value);
   27.97 +    src->value = NULL;
   27.98 +    stringlist_add(src, str2);
   27.99 +    assert(src->value);
  27.100 +    assert(strcmp(src->value, str2) == 0);
  27.101 +    assert(src->value != str2); // ensure this is a copy
  27.102 +    cout << src->value;
  27.103 +
  27.104 +    cout << "\nfreeing stringlists…\n\n";
  27.105 +    free_stringlist(src);
  27.106 +    free_stringlist(dst);
  27.107 +    
  27.108 +    src = NULL;
  27.109 +    dst = NULL;
  27.110 +    
  27.111 +    cout << "done.\n";
  27.112 +
  27.113 +    return 0;
  27.114 +}
  27.115 +
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/test/stringpair_list_test.cc	Wed Jul 13 18:05:35 2016 +0200
    28.3 @@ -0,0 +1,138 @@
    28.4 +#include <stdlib.h>
    28.5 +#include <string.h>
    28.6 +#include "platform.h"
    28.7 +#include <iostream>
    28.8 +#include <fstream>
    28.9 +#include <assert.h>
   28.10 +
   28.11 +#include "stringpair.h"
   28.12 +
   28.13 +using namespace std;
   28.14 +
   28.15 +int test_stringpair_equals(stringpair_t* val1, stringpair_t* val2) {
   28.16 +    assert(val1);
   28.17 +    assert(val2);
   28.18 +    assert(val1->key);
   28.19 +    assert(val2->key);
   28.20 +    assert(val1->value);
   28.21 +    assert(val2->value);
   28.22 +    return((strcmp(val1->key, val2->key) == 0) && (strcmp(val1->value, val2->value) == 0));
   28.23 +}
   28.24 +
   28.25 +int main() {
   28.26 +    cout << "\n*** data structures: stringpair_list_test ***\n\n";
   28.27 +
   28.28 +    const char* val_1_arr[4] = {"I am your father, Luke",
   28.29 +                                "These are not the droids you're looking for",
   28.30 +                                "Swooping is bad",
   28.31 +                                "I should go."};
   28.32 +    const char* val_2_arr[4] = {"Had to be me.",
   28.33 +                                "Someone else might have gotten it wrong",
   28.34 +                                "Na via lerno victoria",
   28.35 +                                "I was told that there would be cake."};
   28.36 +                                
   28.37 +//    const stringpair_t* stringpair_arr[4];
   28.38 +    
   28.39 +    int i;
   28.40 +    
   28.41 +//    for (i = 0; i < 4; i++) {
   28.42 +//        stringpair_arr[i] = new stringpair(val_1_arr[i], val_2_arr[i]);
   28.43 +//    }
   28.44 +    
   28.45 +    cout << "creating one-element stringpair_list...\n";
   28.46 +    
   28.47 +    stringpair_t* strpair = new_stringpair(val_1_arr[0], val_2_arr[0]);
   28.48 +    assert(strpair);
   28.49 +    stringpair_list_t* pairlist = new_stringpair_list(strpair);
   28.50 +    assert(pairlist->value);
   28.51 +    assert(test_stringpair_equals(strpair, pairlist->value));
   28.52 +    assert(pairlist->next == NULL);
   28.53 +    cout << "one-element stringpair_list created, next element is NULL\n\n";
   28.54 +    
   28.55 +    cout << "duplicating one-element list...\n";
   28.56 +    stringpair_list_t* duplist = stringpair_list_dup(pairlist);
   28.57 +    stringpair_t* srcpair = pairlist->value;
   28.58 +    stringpair_t* dstpair = duplist->value;
   28.59 +    assert(dstpair);
   28.60 +    assert(dstpair->value);
   28.61 +    assert(test_stringpair_equals(srcpair, dstpair));
   28.62 +    assert(srcpair->key != dstpair->key);   // test deep copies (to be fixed in next 2 commits)
   28.63 +    assert(srcpair->value != dstpair->value);
   28.64 +    assert(duplist->next == NULL);
   28.65 +    cout << "one-element stringpair_list duplicated.\n\n";
   28.66 +    
   28.67 +    cout << "freeing stringpair_lists...\n";
   28.68 +    free_stringpair_list(pairlist); // will free strpair
   28.69 +    free_stringpair_list(duplist);
   28.70 +    pairlist = NULL;
   28.71 +    duplist = NULL;
   28.72 +    strpair = NULL;
   28.73 +    
   28.74 +    stringpair_list_t* p;
   28.75 +    cout << "\ncreating four-element list...\n";
   28.76 +    pairlist = stringpair_list_add(pairlist, new_stringpair(val_1_arr[0], val_2_arr[0]));
   28.77 +    for (i = 1; i < 4; i++) {
   28.78 +        p = stringpair_list_add(pairlist, new_stringpair(val_1_arr[i], val_2_arr[i]));
   28.79 +        assert(p);
   28.80 +    }
   28.81 +    
   28.82 +    p = pairlist;
   28.83 +    
   28.84 +    for (i = 0; i < 4; i++) {
   28.85 +        assert(p);
   28.86 +        
   28.87 +        strpair = p->value;
   28.88 +        assert(strpair);
   28.89 +        
   28.90 +        assert(strpair->key);
   28.91 +        assert(strcmp(val_1_arr[i], strpair->key) == 0);
   28.92 +        
   28.93 +        assert(strpair->value);
   28.94 +        assert(strcmp(val_2_arr[i], strpair->value) == 0);
   28.95 +        
   28.96 +        assert(val_1_arr[i] != strpair->key);
   28.97 +        assert(val_2_arr[i] != strpair->value);
   28.98 +        
   28.99 +        p = p->next;
  28.100 +    }
  28.101 +    assert(p == NULL);
  28.102 +    
  28.103 +    cout << "\nduplicating four-element list...\n\n";
  28.104 +    duplist = stringpair_list_dup(pairlist);
  28.105 +    
  28.106 +    p = pairlist;
  28.107 +    stringpair_list_t* dup_p = duplist;
  28.108 +    
  28.109 +    while (dup_p) {
  28.110 +        srcpair = p->value;
  28.111 +        dstpair = dup_p->value;
  28.112 +
  28.113 +        assert(dstpair);
  28.114 +        assert(dstpair->value);
  28.115 +        
  28.116 +        cout << srcpair->key << ":" << srcpair->value << " / " << dstpair->key << ":" << dstpair->value << "\n";
  28.117 +        assert(test_stringpair_equals(srcpair, dstpair));
  28.118 +
  28.119 +        assert(srcpair->key != dstpair->key);   // test deep copies (to be fixed in next 2 commits)
  28.120 +        assert(srcpair->value != dstpair->value);
  28.121 +
  28.122 +        i++;
  28.123 +        p = p->next;
  28.124 +
  28.125 +        dup_p = dup_p->next;
  28.126 +        assert((p == NULL) == (dup_p == NULL));
  28.127 +    }
  28.128 +    cout << "\nfour-element stringpair_list successfully duplicated.\n\n";
  28.129 +
  28.130 +    cout << "freeing stringpair_lists...\n";
  28.131 +    free_stringpair_list(pairlist); // will free strpair
  28.132 +    free_stringpair_list(duplist);
  28.133 +    pairlist = NULL;
  28.134 +    duplist = NULL;
  28.135 +    
  28.136 +    cout << "done.\n";
  28.137 +        
  28.138 +    
  28.139 +    return 0;
  28.140 +}
  28.141 +