cut things in sync
authorVolker Birk <vb@pep.foundation>
Tue, 07 Aug 2018 17:16:03 +0200
branchsync
changeset 2829e444c3c960bb
parent 2803 fadf1e8e22ff
child 2830 d6f044e43e1a
cut things in
.hgignore
Makefile
asn.1/Makefile
asn.1/pEp.asn1
asn.1/pEpEngineASN1/pEpEngineASN1.vcxproj
default.conf
src/sync_actions.c
src/sync_impl.c
src/sync_impl.h
sync/Makefile
sync/fsm.yml2
sync/functions.ysl2
sync/gen_actions.ysl2
sync/gen_dot.ysl2
sync/gen_statemachine.ysl2
     1.1 --- a/.hgignore	Tue Aug 07 14:24:15 2018 +0200
     1.2 +++ b/.hgignore	Tue Aug 07 17:16:03 2018 +0200
     1.3 @@ -9,6 +9,7 @@
     1.4  
     1.5  syntax: glob
     1.6  *.orig
     1.7 +*.old
     1.8  *.d
     1.9  *.d.*
    1.10  *.o
     2.1 --- a/Makefile	Tue Aug 07 14:24:15 2018 +0200
     2.2 +++ b/Makefile	Tue Aug 07 17:16:03 2018 +0200
     2.3 @@ -21,9 +21,9 @@
     2.4  
     2.5  .PHONY: all
     2.6  all:
     2.7 +	$(MAKE) -C sync
     2.8  	$(MAKE) -C asn.1 generate
     2.9  	$(MAKE) -C asn.1
    2.10 -	$(MAKE) -C sync
    2.11  	$(MAKE) -C src all
    2.12  
    2.13  .PHONY: install
     3.1 --- a/asn.1/Makefile	Tue Aug 07 14:24:15 2018 +0200
     3.2 +++ b/asn.1/Makefile	Tue Aug 07 17:16:03 2018 +0200
     3.3 @@ -1,35 +1,30 @@
     3.4 -# Copyright 2017, pEp Foundation
     3.5 -# This file is part of pEpEngine
     3.6 -# This file may be used under the terms of the GNU General Public License version 3
     3.7 +# This file is under GNU General Public License 3.0
     3.8  # see LICENSE.txt
     3.9  
    3.10  include ../default.conf
    3.11  
    3.12 -ALL_SOURCE=$(wildcard *.c)
    3.13 +ALL_SOURCE=$(subst $(NO_SOURCE),,$(wildcard *.c))
    3.14  ALL_OBJECTS=$(subst .c,.o,$(ALL_SOURCE))
    3.15  
    3.16 +all: generate
    3.17 +	make libasn1.a
    3.18 +
    3.19  libasn1.a: $(ALL_OBJECTS)
    3.20 -	ar -rc $@ $^
    3.21 +	ar -rc $@ $(ALL_OBJECTS)
    3.22  
    3.23 -# "converter-sample.c" is the example file containing a "main()" function generated by ans1c.
    3.24 -.PHONY: generate
    3.25 -generate: Sync-Protocols.c
    3.26 +generate: Sync.c
    3.27  	rm -f converter-sample.c
    3.28  
    3.29  %.o: %.c %.h
    3.30 -	$(CC) $(CFLAGS) $(CFLAGS_GENERATED) -I. $(ASN1C_INC) -c $< -o $@
    3.31 +	$(CC) $(CFLAGS) $(OPTIMIZE) -I. -I$(ASN1C_INC) -c $< -o $@
    3.32  
    3.33 -Sync-Protocols.c: pEp.asn1 devicegroup.asn1 protocols.asn1
    3.34 -	$(ASN1C) -gen-PER -fincludes-quoted -fcompound-names -pdu=PEP.Message $^
    3.35 +Sync.c: sync.asn1 keysync.asn1 pEp.asn1
    3.36 +	$(ASN1C) -gen-PER -fincludes-quoted -fcompound-names -pdu=PEP.Message pEp.asn1 keysync.asn1 $<
    3.37 +
    3.38 +sync.asn1 keysync.asn1 pEp.asn1:
    3.39 +	cp -f ../sync/generated/*.asn1 ../asn.1
    3.40  
    3.41  .PHONY: clean
    3.42 +
    3.43  clean:
    3.44 -	rm -f *.a *.o *.c *.h *.sample
    3.45 -
    3.46 -.PHONY: install
    3.47 -install: libasn1.a
    3.48 -	cp $< $(PREFIX)/lib/
    3.49 -
    3.50 -.PHONY: uninstall
    3.51 -uninstall:
    3.52 -	rm -f $(PREFIX)/lib/libasn1.a
    3.53 +	rm -f *.a *.o *.c *.h *.sample sync.asn1 keysync.asn1
     4.1 --- a/asn.1/pEp.asn1	Tue Aug 07 14:24:15 2018 +0200
     4.2 +++ b/asn.1/pEp.asn1	Tue Aug 07 17:16:03 2018 +0200
     4.3 @@ -1,5 +1,9 @@
     4.4 -/* This file is under GNU General Public License 3.0 */
     4.5 -/* see LICENSE.txt */
     4.6 +-- This file is under BSD License 2.0
     4.7 +
     4.8 +-- Sync protocol for p≡p
     4.9 +-- Copyright (c) 2016, 2017 p≡p foundation
    4.10 +
    4.11 +-- Written by Volker Birk
    4.12  
    4.13  PEP
    4.14      { iso(1) org(3) dod(6) internet(1) private(4) enterprise(1) pEp(47878) basic(0) }
    4.15 @@ -8,27 +12,24 @@
    4.16  
    4.17  BEGIN
    4.18  
    4.19 -EXPORTS Version, Identity, IdentityList;
    4.20 +EXPORTS Identity, IdentityList, TID, Hash;
    4.21  
    4.22  ISO639-1 ::= PrintableString(FROM ("a".."z")) (SIZE(2))
    4.23  Hex ::= PrintableString(FROM ("A".."F") | FROM ("0".."9"))
    4.24 -Hash ::= Hex(SIZE(1..128)) -- SHA1 to SHA512 in hex
    4.25 +Hash ::= Hex(SIZE(16..128)) -- 32bit Key ID to SHA512 in hex
    4.26 +PString ::= UTF8String  (SIZE(1..1024))
    4.27 +TID ::= OCTET STRING (SIZE(16)) -- UUID version 4 variant 1
    4.28  
    4.29  Identity ::= SEQUENCE {
    4.30 -    address     UTF8String  (SIZE(1..1024)) OPTIONAL,
    4.31 +    address     PString,
    4.32      fpr         Hash,
    4.33 -    user-id     UTF8String  (SIZE(1..1024)) OPTIONAL,
    4.34 -    username    UTF8String  (SIZE(1..1024)) OPTIONAL,
    4.35 -    comm-type   INTEGER     (0..255) OPTIONAL,
    4.36 +    user-id     PString,
    4.37 +    username    PString,
    4.38 +    comm-type   INTEGER (0..255),
    4.39      lang        ISO639-1
    4.40  }
    4.41  
    4.42  IdentityList ::= SEQUENCE OF Identity
    4.43  
    4.44 -Version ::= SEQUENCE {
    4.45 -    major       INTEGER (0..255),
    4.46 -    minor       INTEGER (0..255)
    4.47 -}
    4.48 -
    4.49  END
    4.50  
     5.1 --- a/asn.1/pEpEngineASN1/pEpEngineASN1.vcxproj	Tue Aug 07 14:24:15 2018 +0200
     5.2 +++ b/asn.1/pEpEngineASN1/pEpEngineASN1.vcxproj	Tue Aug 07 17:16:03 2018 +0200
     5.3 @@ -62,7 +62,7 @@
     5.4        <GenerateDebugInformation>true</GenerateDebugInformation>
     5.5      </Link>
     5.6      <PreBuildEvent>
     5.7 -      <Command>cd "$(ProjectDir).." &amp;&amp; "$(SolutionDir)Tools\asn1c\bin\asn1c" -S "$(SolutionDir)Tools\asn1c\share\asn1c" -gen-PER -fincludes-quoted -fcompound-names -pdu=PEP.Message pEp.asn1 devicegroup.asn1 protocols.asn1
     5.8 +      <Command>cd "$(ProjectDir).." &amp;&amp; "$(SolutionDir)Tools\asn1c\bin\asn1c" -S "$(SolutionDir)Tools\asn1c\share\asn1c" -gen-PER -fincludes-quoted -fcompound-names -pdu=PEP.Message pEp.asn1 keysync.asn1 sync.asn.1
     5.9  cd "$(ProjectDir).." &amp;&amp; del converter-sample.c
    5.10  </Command>
    5.11      </PreBuildEvent>
    5.12 @@ -99,7 +99,7 @@
    5.13        <OptimizeReferences>true</OptimizeReferences>
    5.14      </Link>
    5.15      <PreBuildEvent>
    5.16 -      <Command>cd "$(ProjectDir).." &amp;&amp; "$(SolutionDir)Tools\asn1c\bin\asn1c" -S "$(SolutionDir)Tools\asn1c\share\asn1c" -gen-PER -fincludes-quoted -fcompound-names -pdu=PEP.Message pEp.asn1 devicegroup.asn1 protocols.asn1
    5.17 +      <Command>cd "$(ProjectDir).." &amp;&amp; "$(SolutionDir)Tools\asn1c\bin\asn1c" -S "$(SolutionDir)Tools\asn1c\share\asn1c" -gen-PER -fincludes-quoted -fcompound-names -pdu=PEP.Message pEp.asn1 keysync.asn1 sync.asn.1
    5.18  cd "$(ProjectDir).." &amp;&amp; del converter-sample.c
    5.19  </Command>
    5.20        <Message>compiling ASN.1 description</Message>
    5.21 @@ -215,4 +215,4 @@
    5.22    <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
    5.23    <ImportGroup Label="ExtensionTargets">
    5.24    </ImportGroup>
    5.25 -</Project>
    5.26 \ No newline at end of file
    5.27 +</Project>
     6.1 --- a/default.conf	Tue Aug 07 14:24:15 2018 +0200
     6.2 +++ b/default.conf	Tue Aug 07 17:16:03 2018 +0200
     6.3 @@ -182,8 +182,7 @@
     6.4  ASN1C=asn1c
     6.5  
     6.6  # asn1c include search flag
     6.7 -ASN1C_INC=
     6.8 -#ASN1C_INC=-I$(HOME)/include
     6.9 +ASN1C_INC=-I$(PREFIX)/include
    6.10  
    6.11  
    6.12  ######### libetpan #########
     7.1 --- a/src/sync_actions.c	Tue Aug 07 14:24:15 2018 +0200
     7.2 +++ b/src/sync_actions.c	Tue Aug 07 17:16:03 2018 +0200
     7.3 @@ -1,454 +1,409 @@
     7.4  // This file is under GNU General Public License 3.0
     7.5  // see LICENSE.txt
     7.6  
     7.7 -// Actions for DeviceState state machine
     7.8 +#include "Sync_impl.h"
     7.9 +#include "KeySync_fsm.h"
    7.10  
    7.11 -#include <assert.h>
    7.12 -#include "pEp_internal.h"
    7.13 -#include "message.h"
    7.14 -#include "sync_fsm.h"
    7.15 -#include "sync_impl.h"
    7.16 -#include "map_asn1.h"
    7.17 -#include "baseprotocol.h"
    7.18 +PEP_STATUS deviceGrouped(PEP_SESSION session, bool *result)
    7.19 +{
    7.20 +    assert(session && result);
    7.21 +    if (!(session && result))
    7.22 +        return PEP_ILLEGAL_VALUE;
    7.23  
    7.24 -// conditions
    7.25 +    static const char *sql = "select count(*) from identity where user_id = '"PEP_OWN_USERID"' and (flags & 4) = 4;";
    7.26 +    static const size_t len = strlen(sql);
    7.27 +    sqlite3_stmt *_sql;
    7.28 +    int int_result = sqlite3_prepare_v2(session->db, sql, (int) len, &_sql, NULL);
    7.29 +    assert(int_result == SQLITE_OK);
    7.30 +    if (!(int_result == SQLITE_OK))
    7.31 +        return PEP_UNKNOWN_ERROR;
    7.32  
    7.33 -int deviceGrouped(PEP_SESSION session)
    7.34 +    int _result = 0;
    7.35 +    int_result = sqlite3_step(_sql);
    7.36 +    assert(int_result == SQLITE_ROW);
    7.37 +    if (int_result == SQLITE_ROW)
    7.38 +        _result = sqlite3_column_int(_sql, 0);
    7.39 +    sqlite3_finalize(_sql);
    7.40 +    if (int_result != SQLITE_ROW)
    7.41 +        return PEP_UNKNOWN_ERROR;
    7.42 +
    7.43 +    *result = _result > 0;
    7.44 +
    7.45 +    return PEP_STATUS_OK;
    7.46 +}
    7.47 +
    7.48 +PEP_STATUS challengeAccepted(PEP_SESSION session, bool *result)
    7.49 +{
    7.50 +    assert(session && result);
    7.51 +    if (!(session && result))
    7.52 +        return PEP_ILLEGAL_VALUE;
    7.53 +
    7.54 +    TID_t *t1 = &session->sync_state.keysync.challenge;
    7.55 +    TID_t *t2 = &session->own_sync_state.challenge;
    7.56 +
    7.57 +    *result = t1->size == t2->size && memcmp(t1->buf, t2->buf, t1->size) == 0;
    7.58 +
    7.59 +    return PEP_STATUS_OK;
    7.60 +}
    7.61 +
    7.62 +PEP_STATUS partnerIsGrouped(PEP_SESSION session, bool *result)
    7.63 +{
    7.64 +    assert(session && result);
    7.65 +    if (!(session && result))
    7.66 +        return PEP_ILLEGAL_VALUE;
    7.67 +
    7.68 +    *result = session->sync_state.keysync.is_group;
    7.69 +
    7.70 +    return PEP_STATUS_OK;
    7.71 +}
    7.72 +
    7.73 +PEP_STATUS keyElectionWon(PEP_SESSION session, bool *result)
    7.74 +{
    7.75 +    assert(session && result);
    7.76 +    if (!(session && result))
    7.77 +        return PEP_ILLEGAL_VALUE;
    7.78 +
    7.79 +    pEp_identity *from = session->sync_state.basic.from;
    7.80 +
    7.81 +    assert(from && from->fpr && from->fpr[0] && from->address && from->address[0]);
    7.82 +    if (!(from && from->fpr && from->fpr[0] && from->address && from->address[0]))
    7.83 +        return PEP_ILLEGAL_VALUE;
    7.84 +
    7.85 +    pEp_identity *me = NULL;
    7.86 +    PEP_STATUS status = get_identity(session, from->address, PEP_OWN_USERID, &me);
    7.87 +    assert(status == PEP_STATUS_OK);
    7.88 +    if (status)
    7.89 +        return status;
    7.90 +
    7.91 +    assert(me->fpr && me->fpr[0]);
    7.92 +    if (!(me->fpr && me->fpr[0])) {
    7.93 +        free_identity(me);
    7.94 +        return PEP_ILLEGAL_VALUE;
    7.95 +    }
    7.96 +
    7.97 +    size_t len = MIN(strlen(from->fpr), strlen(me->fpr));
    7.98 +    *result = strncasecmp(from->fpr, me->fpr, len) > 0;
    7.99 +    free_identity(me);
   7.100 +
   7.101 +    return PEP_STATUS_OK;
   7.102 +}
   7.103 +
   7.104 +PEP_STATUS closeHandshakeDialog(PEP_SESSION session)
   7.105  {
   7.106      assert(session);
   7.107      if (!session)
   7.108 -        return invalid_condition; // error
   7.109 -
   7.110 -    char *devgrp = NULL;
   7.111 -    int res = 0;
   7.112 -    PEP_STATUS status;
   7.113 -
   7.114 -    status = get_device_group(session, &devgrp);
   7.115 -
   7.116 -    if (status == PEP_STATUS_OK && devgrp && devgrp[0])
   7.117 -        res = 1;
   7.118 -
   7.119 -    free(devgrp);
   7.120 -
   7.121 -    return res;
   7.122 -}
   7.123 -
   7.124 -int keyElectionWon(PEP_SESSION session, Identity partner)
   7.125 -{
   7.126 -    assert(session);
   7.127 -    assert(partner);
   7.128 -    if (!(session && partner))
   7.129 -        return invalid_condition; // error
   7.130 -
   7.131 -    int partner_is_group = partner->flags & PEP_idf_devicegroup;
   7.132 -
   7.133 -    if (deviceGrouped(session)){
   7.134 -        // existing group always wins against sole device
   7.135 -        if(!partner_is_group)
   7.136 -            return 1;
   7.137 -    } else {
   7.138 -        // sole device always loses against group
   7.139 -        if(partner_is_group)
   7.140 -            return 0;
   7.141 -    }
   7.142 -
   7.143 -    // two groups or two sole are elected based on key age
   7.144 -    // key created first wins
   7.145 -
   7.146 -    Identity me = NULL;
   7.147 -    
   7.148 -    char* own_id = NULL;
   7.149 -    PEP_STATUS status = get_default_own_userid(session, &own_id);
   7.150 -    if (own_id) {
   7.151 -        status = get_identity(session, partner->address, own_id,
   7.152 -                              &me);
   7.153 -        free(own_id);
   7.154 -    }
   7.155 -    if (status == PEP_OUT_OF_MEMORY)
   7.156 -        return invalid_out_of_memory;
   7.157 -    if (status != PEP_STATUS_OK)
   7.158 -        return invalid_condition; // error
   7.159 -
   7.160 -    int result = invalid_condition; // error state has to be overwritten
   7.161 -
   7.162 -    time_t own_created;
   7.163 -    time_t partners_created;
   7.164 -
   7.165 -    status = key_created(session, me->fpr, &own_created);
   7.166 -    if (status != PEP_STATUS_OK)
   7.167 -        goto the_end;
   7.168 -
   7.169 -    status = key_created(session, partner->fpr, &partners_created);
   7.170 -    if (status != PEP_STATUS_OK)
   7.171 -        goto the_end;
   7.172 -
   7.173 -    if (own_created > partners_created)
   7.174 -        result = 0;
   7.175 -    else
   7.176 -        result = 1;
   7.177 -
   7.178 -the_end:
   7.179 -    free_identity(me);
   7.180 -    return result;
   7.181 -}
   7.182 -
   7.183 -int sameIdentities(PEP_SESSION session, Identity a, Identity b)
   7.184 -{
   7.185 -    assert(session);
   7.186 -    assert(a);
   7.187 -    assert(b);
   7.188 -
   7.189 -    if (!(session && a && b))
   7.190 -        return invalid_condition; // error
   7.191 -
   7.192 -    if (a->fpr == NULL || b->fpr == NULL ||
   7.193 -        (!_same_fpr(a->fpr, strlen(a->fpr), b->fpr, strlen(b->fpr))) ||
   7.194 -        a->address == NULL || b->address == NULL ||
   7.195 -        strcmp(a->address, b->address) != 0 ||
   7.196 -        a->user_id == NULL || b->user_id == NULL ||
   7.197 -        strcmp(a->user_id, b->user_id) != 0)
   7.198 -            return 0;
   7.199 -    return 1;
   7.200 -}
   7.201 -
   7.202 -int sameKeyAndAddress(PEP_SESSION session, Identity a, Identity b)
   7.203 -{
   7.204 -    assert(session);
   7.205 -    assert(a);
   7.206 -    assert(b);
   7.207 -
   7.208 -    if (!(session && a && b))
   7.209 -        return invalid_condition; // error
   7.210 -
   7.211 -    if (a->fpr == NULL || b->fpr == NULL ||
   7.212 -        (!_same_fpr(a->fpr, strlen(a->fpr), b->fpr, strlen(b->fpr))) ||
   7.213 -        a->address == NULL || b->address == NULL ||
   7.214 -        strcmp(a->address, b->address) != 0)
   7.215 -            return 0;
   7.216 -    return 1;
   7.217 -}
   7.218 -
   7.219 -// actions
   7.220 -
   7.221 -PEP_STATUS _notifyHandshake(
   7.222 -        PEP_SESSION session,
   7.223 -        Identity partner,
   7.224 -        sync_handshake_signal signal
   7.225 -    )
   7.226 -{
   7.227 -    PEP_STATUS status = PEP_STATUS_OK;
   7.228 -
   7.229 -    assert(session);
   7.230 -    assert(partner);
   7.231 -
   7.232 -    if (!(session && partner))
   7.233          return PEP_ILLEGAL_VALUE;
   7.234  
   7.235      assert(session->notifyHandshake);
   7.236      if (!session->notifyHandshake)
   7.237          return PEP_SYNC_NO_NOTIFY_CALLBACK;
   7.238  
   7.239 -    char* own_id = NULL;
   7.240 -    status = get_default_own_userid(session, &own_id);
   7.241 -        
   7.242 -    // notifyHandshake take ownership of given identities
   7.243 +    PEP_STATUS status = session->notifyHandshake(
   7.244 +            session->sync_management, NULL, NULL, SYNC_NOTIFY_OVERTAKEN);
   7.245 +    if (status)
   7.246 +        return status;
   7.247 +
   7.248 +    return PEP_STATUS_OK;
   7.249 +}
   7.250 +
   7.251 +PEP_STATUS openChallenge(PEP_SESSION session)
   7.252 +{
   7.253 +    assert(session);
   7.254 +    if (!session)
   7.255 +        return PEP_ILLEGAL_VALUE;
   7.256 +
   7.257 +    pEpUUID c;
   7.258 +    uuid_generate_random(c);
   7.259 +
   7.260 +    OCTET_STRING_fromBuf(&session->own_sync_state.challenge, c, 16);
   7.261 +
   7.262 +    return PEP_STATUS_OK;
   7.263 +}
   7.264 +
   7.265 +PEP_STATUS storeChallenge(PEP_SESSION session)
   7.266 +{
   7.267 +    assert(session);
   7.268 +    if (!session)
   7.269 +        return PEP_ILLEGAL_VALUE;
   7.270 +
   7.271 +    TID_t *src = &session->sync_state.keysync.challenge;
   7.272 +    TID_t *dst = &session->own_sync_state.challenge;
   7.273 +
   7.274 +    assert(src->size == 16);
   7.275 +    if (!(src->size == 16))
   7.276 +        return PEP_UNKNOWN_ERROR;
   7.277 +
   7.278 +    OCTET_STRING_fromBuf(dst, (char *) src->buf, src->size);
   7.279 +
   7.280 +    return PEP_STATUS_OK;
   7.281 +}
   7.282 +
   7.283 +PEP_STATUS openTransaction(PEP_SESSION session)
   7.284 +{
   7.285 +    assert(session);
   7.286 +    if (!session)
   7.287 +        return PEP_ILLEGAL_VALUE;
   7.288 +
   7.289 +    pEpUUID c;
   7.290 +    uuid_generate_random(c);
   7.291 +
   7.292 +    OCTET_STRING_fromBuf(&session->own_sync_state.transaction, c, 16);
   7.293 +
   7.294 +    return PEP_STATUS_OK;
   7.295 +}
   7.296 +
   7.297 +PEP_STATUS storeTransaction(PEP_SESSION session)
   7.298 +{
   7.299 +    assert(session);
   7.300 +    if (!session)
   7.301 +        return PEP_ILLEGAL_VALUE;
   7.302 +
   7.303 +    TID_t *src = &session->sync_state.keysync.transaction;
   7.304 +    TID_t *dst =  &session->own_sync_state.transaction;
   7.305 +
   7.306 +    assert(src->size == 16);
   7.307 +    if (!(src->size == 16))
   7.308 +        return PEP_UNKNOWN_ERROR;
   7.309 +
   7.310 +    OCTET_STRING_fromBuf(dst, (char *) src->buf, src->size);
   7.311 +
   7.312 +    return PEP_STATUS_OK;
   7.313 +}
   7.314 +
   7.315 +PEP_STATUS showSoleHandshake(PEP_SESSION session)
   7.316 +{
   7.317 +    assert(session);
   7.318 +    if (!session)
   7.319 +        return PEP_ILLEGAL_VALUE;
   7.320 +
   7.321 +    assert(session->notifyHandshake);
   7.322 +    if (!session->notifyHandshake)
   7.323 +        return PEP_SYNC_NO_NOTIFY_CALLBACK;
   7.324 + 
   7.325 +    assert(session->sync_state.basic.from);
   7.326 +    if (!session->sync_state.basic.from)
   7.327 +        return PEP_ILLEGAL_VALUE;
   7.328 +
   7.329      pEp_identity *me = NULL;
   7.330 -    if (own_id) {
   7.331 -        status = get_identity(session, partner->address, own_id, &me);
   7.332 -        free(own_id);
   7.333 -    }
   7.334 -    if (status != PEP_STATUS_OK)
   7.335 -        goto error;
   7.336 -    
   7.337 -    pEp_identity *_partner = NULL;
   7.338 -    _partner = identity_dup(partner);
   7.339 -    if (_partner == NULL){
   7.340 -        status = PEP_OUT_OF_MEMORY;
   7.341 -        goto error;
   7.342 +    PEP_STATUS status = get_identity(session, from->address, PEP_OWN_USERID, &me);
   7.343 +    assert(status == PEP_STATUS_OK);
   7.344 +    if (status)
   7.345 +        return status;
   7.346 +
   7.347 +    assert(me->fpr && me->fpr[0]);
   7.348 +    if (!(me->fpr && me->fpr[0])) {
   7.349 +        free_identity(me);
   7.350 +        return PEP_ILLEGAL_VALUE;
   7.351      }
   7.352  
   7.353 -    status = session->notifyHandshake(session->sync_obj, me, _partner, signal);
   7.354 -    if (status != PEP_STATUS_OK)
   7.355 -        goto error;
   7.356 +    pEp_identity *partner = identity_dup(session->sync_state.basic.from);
   7.357 +    if (!partner) {
   7.358 +        free_identity(me);
   7.359 +        return PEP_OUT_OF_MEMORY;
   7.360 +    }
   7.361  
   7.362 -    return status;
   7.363 +    PEP_STATUS status = session->notifyHandshake(
   7.364 +            session->sync_management, me, partner, SYNC_NOTIFY_INIT_FORM_GROUP);
   7.365 +    if (status)
   7.366 +        return status;
   7.367  
   7.368 -error:
   7.369 -    free_identity(me);
   7.370 -    return status;
   7.371 +    return PEP_STATUS_OK;
   7.372  }
   7.373  
   7.374 -// acceptHandshake() - stores acception of partner
   7.375 -//
   7.376 -//  params:
   7.377 -//      session (in)        session handle
   7.378 -//      state (in)          state the state machine is in
   7.379 -//      partner (in)        partner to communicate with
   7.380 -//
   7.381 -//  returns:
   7.382 -//      PEP_STATUS_OK or any other value on error
   7.383 -
   7.384 -PEP_STATUS acceptHandshake(
   7.385 -        PEP_SESSION session,
   7.386 -        DeviceState_state state,
   7.387 -        Identity partner,
   7.388 -        void *extra
   7.389 -    )
   7.390 +PEP_STATUS disable(PEP_SESSION session)
   7.391  {
   7.392 -    PEP_STATUS status = PEP_STATUS_OK;
   7.393 -
   7.394      assert(session);
   7.395 -    assert(partner);
   7.396 -    assert(extra == NULL);
   7.397 -    if (!(session && partner))
   7.398 +    if (!session)
   7.399          return PEP_ILLEGAL_VALUE;
   7.400  
   7.401 -    status = trust_personal_key(session, partner);
   7.402  
   7.403 -    return status;
   7.404 +    return PEP_STATUS_OK;
   7.405  }
   7.406  
   7.407 -
   7.408 -// rejectHandshake() - stores rejection of partner
   7.409 -//
   7.410 -//  params:
   7.411 -//      session (in)        session handle
   7.412 -//      state (in)          state the state machine is in
   7.413 -//      partner (in)        partner to communicate with
   7.414 -//
   7.415 -//  returns:
   7.416 -//      PEP_STATUS_OK or any other value on error
   7.417 -
   7.418 -PEP_STATUS rejectHandshake(
   7.419 -        PEP_SESSION session,
   7.420 -        DeviceState_state state,
   7.421 -        Identity partner,
   7.422 -        void *extra
   7.423 -    )
   7.424 +PEP_STATUS saveGroupKeys(PEP_SESSION session)
   7.425  {
   7.426 -    PEP_STATUS status = PEP_STATUS_OK;
   7.427 -
   7.428      assert(session);
   7.429 -    assert(partner);
   7.430 -    assert(extra == NULL);
   7.431 -    if (!(session && partner))
   7.432 +    if (!session)
   7.433          return PEP_ILLEGAL_VALUE;
   7.434  
   7.435 -    // TODO : disable sync globally if not in a group
   7.436 -    status = set_identity_flags(session, partner,
   7.437 -            partner->flags | PEP_idf_not_for_sync);
   7.438 +    identity_list *il = IdentityList_to_identity_list(&session->sync_state.keysync.identities, NULL);
   7.439 +    if (!il)
   7.440 +        return PEP_OUT_OF_MEMORY;
   7.441 +    
   7.442 +    // BUG: this should be a transaction and been rolled back completely on error
   7.443 +    for (identity_list *_il = il; _il && _il->ident; _il = _il->next) {
   7.444 +        PEP_STATUS status = set_identity(session, _il->ident);
   7.445 +        if (status) {
   7.446 +            free_identity_list(il);
   7.447 +            return status;
   7.448 +        }
   7.449 +    }
   7.450  
   7.451 -    return status;
   7.452 +    free_identity_list(il);
   7.453 +
   7.454 +    return PEP_STATUS_OK;
   7.455  }
   7.456  
   7.457 -PEP_STATUS _storeGroupKeys(
   7.458 -        PEP_SESSION session,
   7.459 -        identity_list *group_keys
   7.460 -    )
   7.461 +PEP_STATUS ownKeysAreGroupKeys(PEP_SESSION session)
   7.462  {
   7.463 -    PEP_STATUS status = PEP_STATUS_OK;
   7.464 -    
   7.465 -    char* own_id = NULL;
   7.466 -    status = get_default_own_userid(session, &own_id);
   7.467 -    
   7.468 -    // FIXME: Is this where and what we wanna do with this?
   7.469 -    if (status != PEP_STATUS_OK)
   7.470 -        return status;
   7.471 -        
   7.472 -    for (identity_list *il = group_keys; il && il->ident; il = il->next) {
   7.473 -
   7.474 -        if (strcmp(il->ident->user_id, own_id)!=0) {
   7.475 -            assert(0);
   7.476 -            continue;
   7.477 -        }
   7.478 -        // Check that identity isn't excluded from sync.
   7.479 -        pEp_identity *stored_identity = NULL;
   7.480 -        status = get_identity(session, il->ident->address, own_id,
   7.481 -                &stored_identity);
   7.482 -        if (status == PEP_STATUS_OK) {
   7.483 -            if(stored_identity->flags & PEP_idf_not_for_sync){
   7.484 -                free_identity(stored_identity);
   7.485 -                continue;
   7.486 -            }
   7.487 -            free_identity(stored_identity);
   7.488 -        }
   7.489 -
   7.490 -        status = set_identity(session, il->ident);
   7.491 -        if (status != PEP_STATUS_OK)
   7.492 -            break;
   7.493 -    }
   7.494 -    
   7.495 -    free(own_id);
   7.496 -    return status;
   7.497 -}
   7.498 -    
   7.499 -
   7.500 -// storeGroupKeys() - 
   7.501 -//
   7.502 -//  params:
   7.503 -//      session (in)        session handle
   7.504 -//      state (in)          state the state machine is in
   7.505 -//      partner (in)        partner to communicate with
   7.506 -//      _group_keys (in)    group keys received from partner
   7.507 -//
   7.508 -//  returns:
   7.509 -//      PEP_STATUS_OK or any other value on error
   7.510 -
   7.511 -PEP_STATUS storeGroupKeys(
   7.512 -        PEP_SESSION session,
   7.513 -        DeviceState_state state,
   7.514 -        Identity partner,
   7.515 -        void *group_keys_extra_
   7.516 -    )
   7.517 -{
   7.518 -    PEP_STATUS status = PEP_STATUS_OK;
   7.519 -
   7.520      assert(session);
   7.521 -    assert(partner);
   7.522 -    assert(group_keys_extra_);
   7.523 -    if (!(session && partner && group_keys_extra_))
   7.524 +    if (!session)
   7.525          return PEP_ILLEGAL_VALUE;
   7.526  
   7.527 -    group_keys_extra_t *group_keys_extra = 
   7.528 -        (group_keys_extra_t*) group_keys_extra_;
   7.529 -    identity_list *group_keys = group_keys_extra->group_keys;
   7.530 -    char *group_id = group_keys_extra->group_id;
   7.531 +    static const char *sql = "select fpr, username, comm_type, lang,"
   7.532 +        "   identity.flags | pgp_keypair.flags"
   7.533 +        "   from identity"
   7.534 +        "   join person on id = identity.user_id"
   7.535 +        "   join pgp_keypair on fpr = identity.main_key_id"
   7.536 +        "   join trust on id = trust.user_id"
   7.537 +        "       and pgp_keypair_fpr = identity.main_key_id"
   7.538 +        "   where identity.user_id = '" PEP_OWN_USERID "';";
   7.539 +    static const size_t len = strlen(sql);
   7.540 +    sqlite3_stmt *_sql;
   7.541 +    int int_result = sqlite3_prepare_v2(session->db, sql, (int) len, &_sql, NULL);
   7.542 +    assert(int_result == SQLITE_OK);
   7.543 +    if (!(int_result == SQLITE_OK))
   7.544 +        return PEP_UNKNOWN_ERROR;
   7.545  
   7.546 -    status = _storeGroupKeys(session, group_keys);
   7.547 -    if (status != PEP_STATUS_OK)
   7.548 +    identity_list *il = new_identity_list(NULL);
   7.549 +    if (!il)
   7.550 +        return PEP_OUT_OF_MEMORY;
   7.551 +
   7.552 +    identity_list *_il = il;
   7.553 +
   7.554 +    int result;
   7.555 +    do {
   7.556 +        result = sqlite3_step(_sql);
   7.557 +        pEp_identity *_identity = NULL;
   7.558 +        switch (result) {
   7.559 +        case SQLITE_ROW:
   7.560 +            _identity = new_identity(
   7.561 +                    address,
   7.562 +                    (const char *) sqlite3_column_text(_sql, 0),
   7.563 +                    user_id,
   7.564 +                    (const char *) sqlite3_column_text(_sql, 1)
   7.565 +                    );
   7.566 +            assert(_identity);
   7.567 +            if (_identity == NULL)
   7.568 +                return PEP_OUT_OF_MEMORY;
   7.569 +
   7.570 +            _identity->comm_type = (PEP_comm_type)
   7.571 +                sqlite3_column_int(_sql, 2);
   7.572 +            const char* const _lang = (const char *)
   7.573 +                sqlite3_column_text(_sql, 3);
   7.574 +            if (_lang && _lang[0]) {
   7.575 +                assert(_lang[0] >= 'a' && _lang[0] <= 'z');
   7.576 +                assert(_lang[1] >= 'a' && _lang[1] <= 'z');
   7.577 +                assert(_lang[2] == 0);
   7.578 +                _identity->lang[0] = _lang[0];
   7.579 +                _identity->lang[1] = _lang[1];
   7.580 +                _identity->lang[2] = 0;
   7.581 +            }
   7.582 +            _identity->flags = (unsigned int)
   7.583 +                sqlite3_column_int(_sql, 4);
   7.584 +
   7.585 +            _il = identity_list_add(_il, _identity);
   7.586 +            if (!_il) {
   7.587 +                free_identity_list(il);
   7.588 +                free_identity(_identity);
   7.589 +                return PEP_OUT_OF_MEMORY;
   7.590 +            }
   7.591 +            break;
   7.592 +
   7.593 +        case SQLITE_DONE:
   7.594 +            break;
   7.595 +
   7.596 +        default:
   7.597 +            free_identity_list(il);
   7.598 +            return PEP_UNKOWN_ERROR;
   7.599 +        }
   7.600 +    } while (result != SQLITE_DONE);
   7.601 +
   7.602 +    IdentityList_t *r = IdentityList_from_identity_list(il, &session->sync_state.keysync.identities);
   7.603 +    free_identity_list(il);
   7.604 +    if (!r)
   7.605 +        return PEP_OUT_OF_MEMORY;
   7.606 +
   7.607 +    return PEP_STATUS_OK;
   7.608 +}
   7.609 +
   7.610 +PEP_STATUS showJoinGroupHandshake(PEP_SESSION session)
   7.611 +{
   7.612 +    assert(session);
   7.613 +    if (!session)
   7.614 +        return PEP_ILLEGAL_VALUE;
   7.615 +
   7.616 +    assert(session->notifyHandshake);
   7.617 +    if (!session->notifyHandshake)
   7.618 +        return PEP_SYNC_NO_NOTIFY_CALLBACK;
   7.619 + 
   7.620 +    assert(session->sync_state.basic.from);
   7.621 +    if (!session->sync_state.basic.from)
   7.622 +        return PEP_ILLEGAL_VALUE;
   7.623 +
   7.624 +    pEp_identity *me = NULL;
   7.625 +    PEP_STATUS status = get_identity(session, from->address, PEP_OWN_USERID, &me);
   7.626 +    assert(status == PEP_STATUS_OK);
   7.627 +    if (status)
   7.628          return status;
   7.629  
   7.630 -    // set group id according to given group-id
   7.631 -    status = set_device_group(session, group_id);
   7.632 -    if (status != PEP_STATUS_OK)
   7.633 +    assert(me->fpr && me->fpr[0]);
   7.634 +    if (!(me->fpr && me->fpr[0])) {
   7.635 +        free_identity(me);
   7.636 +        return PEP_ILLEGAL_VALUE;
   7.637 +    }
   7.638 +
   7.639 +    pEp_identity *partner = identity_dup(session->sync_state.basic.from);
   7.640 +    if (!partner) {
   7.641 +        free_identity(me);
   7.642 +        return PEP_OUT_OF_MEMORY;
   7.643 +    }
   7.644 +
   7.645 +    PEP_STATUS status = session->notifyHandshake(
   7.646 +            session->sync_management, me, partner, SYNC_NOTIFY_INIT_ADD_OUR_DEVICE);
   7.647 +    if (status)
   7.648          return status;
   7.649 -    
   7.650 -    return status;
   7.651 +
   7.652 +    return PEP_STATUS_OK;
   7.653  }
   7.654  
   7.655 -// storeGroupUpdate() - 
   7.656 -//
   7.657 -//  params:
   7.658 -//      session (in)        session handle
   7.659 -//      state (in)          state the state machine is in
   7.660 -//      partner (in)        partner to communicate with
   7.661 -//      _group_keys (in)    group keys received from partner
   7.662 -//
   7.663 -//  returns:
   7.664 -//      PEP_STATUS_OK or any other value on error
   7.665 -
   7.666 -PEP_STATUS storeGroupUpdate(
   7.667 -        PEP_SESSION session,
   7.668 -        DeviceState_state state,
   7.669 -        Identity partner,
   7.670 -        void *group_keys_
   7.671 -    )
   7.672 +PEP_STATUS showGroupedHandshake(PEP_SESSION session)
   7.673  {
   7.674 -    PEP_STATUS status = PEP_STATUS_OK;
   7.675 -
   7.676      assert(session);
   7.677 -    assert(partner);
   7.678 -    assert(group_keys_);
   7.679 -    if (!(session && partner && group_keys_))
   7.680 +    if (!session)
   7.681          return PEP_ILLEGAL_VALUE;
   7.682  
   7.683 -    identity_list *group_keys = (identity_list*) group_keys_;
   7.684 +    assert(session->notifyHandshake);
   7.685 +    if (!session->notifyHandshake)
   7.686 +        return PEP_SYNC_NO_NOTIFY_CALLBACK;
   7.687 + 
   7.688 +    assert(session->sync_state.basic.from);
   7.689 +    if (!session->sync_state.basic.from)
   7.690 +        return PEP_ILLEGAL_VALUE;
   7.691  
   7.692 -    status = _storeGroupKeys(session, group_keys);
   7.693 +    pEp_identity *me = NULL;
   7.694 +    PEP_STATUS status = get_identity(session, from->address, PEP_OWN_USERID, &me);
   7.695 +    assert(status == PEP_STATUS_OK);
   7.696 +    if (status)
   7.697 +        return status;
   7.698  
   7.699 +    assert(me->fpr && me->fpr[0]);
   7.700 +    if (!(me->fpr && me->fpr[0])) {
   7.701 +        free_identity(me);
   7.702 +        return PEP_ILLEGAL_VALUE;
   7.703 +    }
   7.704  
   7.705 -    return status;
   7.706 +    pEp_identity *partner = identity_dup(session->sync_state.basic.from);
   7.707 +    if (!partner) {
   7.708 +        free_identity(me);
   7.709 +        return PEP_OUT_OF_MEMORY;
   7.710 +    }
   7.711 +
   7.712 +    PEP_STATUS status = session->notifyHandshake(
   7.713 +            session->sync_management, me, partner, SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE);
   7.714 +    if (status)
   7.715 +        return status;
   7.716 +
   7.717 +    return PEP_STATUS_OK;
   7.718  }
   7.719  
   7.720 -// makeGroup() - 
   7.721 -//
   7.722 -//  params:
   7.723 -//      session (in)        session handle
   7.724 -//      state (in)          state the state machine is in
   7.725 -//      partner (in)        ignored
   7.726 -//      extra (in)          ignored
   7.727 -//
   7.728 -//  returns:
   7.729 -//      PEP_STATUS_OK or any other value on error
   7.730 -
   7.731 -PEP_STATUS makeGroup(
   7.732 -        PEP_SESSION session,
   7.733 -        DeviceState_state state,
   7.734 -        Identity partner,
   7.735 -        void *extra
   7.736 -    )
   7.737 -{
   7.738 -    PEP_STATUS status = PEP_STATUS_OK;
   7.739 -
   7.740 -    assert(session);
   7.741 -   
   7.742 -    // make a new uuid 
   7.743 -    char new_uuid[37];
   7.744 -    pEpUUID uuid;
   7.745 -    uuid_generate_random(uuid);
   7.746 -    uuid_unparse_upper(uuid, new_uuid);
   7.747 -
   7.748 -    // take that new uuid as group-id
   7.749 -    status = set_device_group(session, new_uuid);
   7.750 -
   7.751 -    return status;
   7.752 -}
   7.753 -
   7.754 -// renewUUID() - 
   7.755 -//
   7.756 -//  params:
   7.757 -//      session (in)        session handle
   7.758 -//      state (in)          state the state machine is in
   7.759 -//      partner (in)        ignored
   7.760 -//      extra (in)          ignored
   7.761 -//
   7.762 -//  returns:
   7.763 -//      PEP_STATUS_OK or any other value on error
   7.764 -
   7.765 -PEP_STATUS renewUUID(
   7.766 -        PEP_SESSION session,
   7.767 -        DeviceState_state state,
   7.768 -        Identity partner,
   7.769 -        void *extra
   7.770 -    )
   7.771 -{
   7.772 -    PEP_STATUS status = PEP_STATUS_OK;
   7.773 -
   7.774 -    assert(session);
   7.775 -
   7.776 -    // change sync_uuid when entering group 
   7.777 -    // thus ignoring unprocessed handshakes
   7.778 -    // addressed to previous self (sole) once in.
   7.779 -    pEpUUID uuid;
   7.780 -    uuid_generate_random(uuid);
   7.781 -    uuid_unparse_upper(uuid, session->sync_uuid);
   7.782 -    
   7.783 -    return status;
   7.784 -}
   7.785 -
   7.786 -// leaveGroup() - 
   7.787 -//
   7.788 -//  params:
   7.789 -//      session (in)        session handle
   7.790 -//      state (in)          state the state machine is in
   7.791 -//      partner (in)        ignored
   7.792 -//      extra (in)          ignored
   7.793 -//
   7.794 -//  returns:
   7.795 -//      PEP_STATUS_OK or any other value on error
   7.796 -
   7.797 -PEP_STATUS leaveGroup(
   7.798 -        PEP_SESSION session,
   7.799 -        DeviceState_state state,
   7.800 -        Identity partner,
   7.801 -        void *extra
   7.802 -    )
   7.803 -{
   7.804 -    PEP_STATUS status = PEP_STATUS_OK;
   7.805 -
   7.806 -    assert(session);
   7.807 -
   7.808 -    status = set_device_group(session, NULL);
   7.809 -    
   7.810 -    return status;
   7.811 -}
     8.1 --- a/src/sync_impl.c	Tue Aug 07 14:24:15 2018 +0200
     8.2 +++ b/src/sync_impl.c	Tue Aug 07 17:16:03 2018 +0200
     8.3 @@ -1,1010 +1,178 @@
     8.4  // This file is under GNU General Public License 3.0
     8.5  // see LICENSE.txt
     8.6  
     8.7 -#include "platform.h"
     8.8 +#include "Sync_impl.h"
     8.9 +#include "pEp_internal.h"
    8.10 +#include "KeySync_fsm.h"
    8.11  
    8.12 -// it seems pEp_internal.h needs to be the first pEp include due to the 
    8.13 -// #define for the dllimport / dllexport DYNAMIC_API stuff.
    8.14 -#include "pEp_internal.h"
    8.15 -
    8.16 -#include "sync_impl.h"
    8.17 -#include "keymanagement.h"
    8.18 -#include "message_api.h"
    8.19 -#include "map_asn1.h"
    8.20 -#include "baseprotocol.h"
    8.21 -
    8.22 -#define SYNC_VERSION_MAJOR 1
    8.23 -#define SYNC_VERSION_MINOR 0
    8.24 -
    8.25 -#define SYNC_INHIBIT_TIME (60*10)
    8.26 -#define SYNC_MSG_EXPIRE_TIME (60 * 10)
    8.27 -
    8.28 -struct _sync_msg_t {
    8.29 -    bool is_a_message;
    8.30 -    union {
    8.31 -        DeviceGroup_Protocol_t *message;
    8.32 -        struct {
    8.33 -            DeviceState_event event;
    8.34 -            Identity partner;
    8.35 -            void *extra;
    8.36 -        } event;
    8.37 -    } u;
    8.38 -};
    8.39 -
    8.40 -static bool _is_own_uuid( PEP_SESSION session, UTF8String_t *uuid)
    8.41 -{
    8.42 -    return strncmp(session->sync_session->sync_uuid,
    8.43 -                   (const char*)uuid->buf, uuid->size) == 0;
    8.44 -}
    8.45 -
    8.46 -static bool _is_own_group_uuid( PEP_SESSION session, UTF8String_t *uuid, char** our_group)
    8.47 -{
    8.48 -    PEP_STATUS status = PEP_STATUS_OK;
    8.49 -    char *devgrp = NULL;
    8.50 -
    8.51 -    if(our_group == NULL || *our_group == NULL)
    8.52 -        status = get_device_group(session, &devgrp);
    8.53 -    else
    8.54 -        devgrp = *our_group;
    8.55 -
    8.56 -    bool res = (status == PEP_STATUS_OK && devgrp && devgrp[0] &&
    8.57 -        strncmp(devgrp,(const char*)uuid->buf, uuid->size) == 0);
    8.58 -
    8.59 -    if(our_group == NULL)
    8.60 -        free(devgrp);
    8.61 -    else if(*our_group == NULL)
    8.62 -        *our_group = devgrp;
    8.63 -
    8.64 -    return res;
    8.65 -}
    8.66 -
    8.67 -PEP_STATUS receive_sync_msg(
    8.68 +PEP_STATUS Sync_driver(
    8.69          PEP_SESSION session,
    8.70 -        sync_msg_t *sync_msg,
    8.71 -        time_t *timeout
    8.72 +        Sync_PR fsm,
    8.73 +        int event
    8.74      )
    8.75  {
    8.76 -    PEP_STATUS status;
    8.77 -    void *extra = NULL;
    8.78 -    Identity partner = NULL;
    8.79 -    DeviceState_event event = DeviceState_event_NONE;
    8.80 -    assert(session && sync_msg);
    8.81 -    if (!(session && sync_msg))
    8.82 +    assert(session && fsm);
    8.83 +    if (!(session && fsm))
    8.84          return PEP_ILLEGAL_VALUE;
    8.85 -    char* own_id = NULL;
    8.86  
    8.87 -    bool msgIsFromGroup = false;
    8.88 -    if(sync_msg->is_a_message){
    8.89 -        DeviceGroup_Protocol_t *msg = sync_msg->u.message;
    8.90 -        assert(msg && msg->payload.present != DeviceGroup_Protocol__payload_PR_NOTHING);
    8.91 -        if (!(msg && msg->payload.present != DeviceGroup_Protocol__payload_PR_NOTHING)){
    8.92 -            status = PEP_OUT_OF_MEMORY;
    8.93 -            goto error;
    8.94 -        }
    8.95 -
    8.96 -        partner = Identity_to_Struct(&msg->header.me, NULL);
    8.97 -        if (!partner){
    8.98 -            status = PEP_OUT_OF_MEMORY;
    8.99 -            ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   8.100 -            goto error;
   8.101 -        }
   8.102 -
   8.103 -        msgIsFromGroup = msg->header.devicegroup;
   8.104 -
   8.105 -        switch (msg->payload.present) {
   8.106 -            case DeviceGroup_Protocol__payload_PR_beacon:
   8.107 -                event = Beacon;
   8.108 -                break;
   8.109 -
   8.110 -            case DeviceGroup_Protocol__payload_PR_handshakeRequest:
   8.111 -            {
   8.112 -                // re-check uuid in case sync_uuid or group changed while in the queue
   8.113 -                char *own_group_id = NULL;
   8.114 -                bool is_for_me = _is_own_uuid(session, 
   8.115 -                    msg->payload.choice.handshakeRequest.partner_id);
   8.116 -                bool is_for_group = !is_for_me && _is_own_group_uuid(session, 
   8.117 -                    msg->payload.choice.handshakeRequest.partner_id, &own_group_id);
   8.118 -                if (!(is_for_me || is_for_group)){
   8.119 -                    status = PEP_MESSAGE_IGNORE;
   8.120 -                    goto error;
   8.121 -                }
   8.122 -
   8.123 -                UTF8String_t *guuid = msg->payload.choice.handshakeRequest.group_id;
   8.124 -                if(msgIsFromGroup && guuid && guuid->buf && guuid->size) {
   8.125 -                    bool is_from_own_group = _is_own_group_uuid(session, 
   8.126 -                                                                guuid, &own_group_id);
   8.127 -
   8.128 -                    // Filter handshake requests from own group
   8.129 -                    if(is_from_own_group) {
   8.130 -                        status = PEP_MESSAGE_IGNORE;
   8.131 -                        goto error;
   8.132 -                    }
   8.133 -
   8.134 -                    // if it comes from another group, 
   8.135 -                    // we want to communicate with that group
   8.136 -                    // insert group_id given in handshake request 
   8.137 -                    // into partner's id
   8.138 -
   8.139 -                    free(partner->user_id);
   8.140 -                    partner->user_id = strndup((const char*)guuid->buf, guuid->size);
   8.141 -                    if(partner->user_id == NULL){
   8.142 -                        status = PEP_OUT_OF_MEMORY;
   8.143 -                        goto error;
   8.144 -                    }
   8.145 -
   8.146 -                    // if it comes from another group, and we are grouped,
   8.147 -                    // then this is groupmerge
   8.148 -                }
   8.149 -
   8.150 -                event = HandshakeRequest;
   8.151 -                break;
   8.152 -
   8.153 -            }
   8.154 -            case DeviceGroup_Protocol__payload_PR_updateRequest:
   8.155 -                event = UpdateRequest;
   8.156 -                break;
   8.157 -
   8.158 -            case DeviceGroup_Protocol__payload_PR_groupKeys:
   8.159 -            {
   8.160 -                // re-check uuid in case sync_uuid or group_uuid changed while in the queue
   8.161 -                char *own_group_id = NULL;
   8.162 -                UTF8String_t *puuid = msg->payload.choice.groupKeys.partner_id;
   8.163 -                bool is_for_me = _is_own_uuid(session, puuid);
   8.164 -                bool is_for_group = !is_for_me &&
   8.165 -                                    _is_own_group_uuid(session, 
   8.166 -                                        puuid, &own_group_id);
   8.167 -                if (!(is_for_me || is_for_group)){
   8.168 -                    status = PEP_MESSAGE_IGNORE;
   8.169 -                    goto error;
   8.170 -                }
   8.171 -
   8.172 -                UTF8String_t *guuid = msg->payload.choice.groupKeys.group_id;
   8.173 -
   8.174 -                // GroupKeys come from groups, no choice
   8.175 -                if(!(msgIsFromGroup && guuid && guuid->buf && guuid->size)) {
   8.176 -                    status = PEP_SYNC_ILLEGAL_MESSAGE;
   8.177 -                    goto error;
   8.178 -                }
   8.179 -
   8.180 -                // Filter groupKeys from own group
   8.181 -                bool is_from_own_group = _is_own_group_uuid(session, 
   8.182 -                                                            guuid, 
   8.183 -                                                            &own_group_id);
   8.184 -                if(is_from_own_group) {
   8.185 -                    // FixMe : protocol shouldn't allow this
   8.186 -                    status = PEP_SYNC_ILLEGAL_MESSAGE;
   8.187 -                    goto error;
   8.188 -                }
   8.189 -
   8.190 -                // insert group_id given in groupKeys into partner's id
   8.191 -                free(partner->user_id);
   8.192 -                partner->user_id = strndup((const char*)guuid->buf, guuid->size);
   8.193 -                if(partner->user_id == NULL){
   8.194 -                    status = PEP_OUT_OF_MEMORY;
   8.195 -                    goto error;
   8.196 -                }
   8.197 -
   8.198 -                // if it comes from another group, and we are grouped,
   8.199 -                // then this is groupmerge's groupKeys
   8.200 -
   8.201 -                group_keys_extra_t *group_keys_extra;
   8.202 -                group_keys_extra = malloc(sizeof(group_keys_extra_t));
   8.203 -                if(group_keys_extra == NULL){
   8.204 -                    status = PEP_OUT_OF_MEMORY;
   8.205 -                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   8.206 -                    goto error;
   8.207 -                }
   8.208 -
   8.209 -                char *group_id = strndup((char*)guuid->buf, guuid->size);
   8.210 -
   8.211 -                if (!group_id){
   8.212 -                    status = PEP_OUT_OF_MEMORY;
   8.213 -                    free(group_keys_extra);
   8.214 -                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   8.215 -                    goto error;
   8.216 -                }
   8.217 -                group_keys_extra->group_id = group_id;
   8.218 -
   8.219 -                identity_list *group_keys = IdentityList_to_identity_list(
   8.220 -                        &msg->payload.choice.groupKeys.ownIdentities,
   8.221 -                        NULL);
   8.222 -                if (!group_keys) {
   8.223 -                    status = PEP_OUT_OF_MEMORY;
   8.224 -                    free(group_id);
   8.225 -                    free(group_keys_extra);
   8.226 -                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   8.227 -                    goto error;
   8.228 -                }
   8.229 -                group_keys_extra->group_keys = group_keys;
   8.230 -
   8.231 -                extra = (void *) group_keys_extra;
   8.232 -                event = GroupKeys;
   8.233 -
   8.234 -                break;
   8.235 -            }
   8.236 -            case DeviceGroup_Protocol__payload_PR_groupUpdate:
   8.237 -            {
   8.238 -                identity_list *group_keys = IdentityList_to_identity_list(
   8.239 -                        &msg->payload.choice.groupUpdate.ownIdentities, NULL);
   8.240 -                if (!group_keys) {
   8.241 -                    status = PEP_OUT_OF_MEMORY;
   8.242 -                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   8.243 -                    goto error;
   8.244 -                }
   8.245 -                extra = (void *) group_keys;
   8.246 -                event = GroupUpdate;
   8.247 -                break;
   8.248 -            }
   8.249 -
   8.250 -            default:
   8.251 -                status = PEP_SYNC_ILLEGAL_MESSAGE;
   8.252 -                ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   8.253 -                goto error;
   8.254 -        }
   8.255 -
   8.256 -    }
   8.257 -    else{
   8.258 -        partner = sync_msg->u.event.partner;
   8.259 -        extra = sync_msg->u.event.extra;
   8.260 -        event = sync_msg->u.event.event;
   8.261 -    }
   8.262 -
   8.263 -    // Event inhibition, to limit mailbox and prevent cycles
   8.264 -    time_t *last = NULL;
   8.265 -    switch(event){
   8.266 -        case CannotDecrypt:
   8.267 -            last = &session->LastCannotDecrypt;
   8.268 -            break;
   8.269 -
   8.270 -        case UpdateRequest:
   8.271 -            last = &session->LastUpdateRequest;
   8.272 -            break;
   8.273 -
   8.274 -        default:
   8.275 -            break;
   8.276 -    }
   8.277 -
   8.278 -    if(last != NULL){
   8.279 -        time_t now = time(NULL);
   8.280 -        if(*last != 0 && (*last + SYNC_INHIBIT_TIME) > now ){
   8.281 -            status = PEP_STATEMACHINE_INHIBITED_EVENT;
   8.282 -            goto error;
   8.283 -        }
   8.284 -        *last = now;
   8.285 -    }
   8.286 -
   8.287 -    // partner identity must be explicitely added DB to later
   8.288 -    // be able to communicate securely with it.
   8.289 -    if(partner){
   8.290 -        
   8.291 -        status = get_default_own_userid(session, &own_id);
   8.292 -        
   8.293 -        if (!own_id)
   8.294 -            own_id = strdup(PEP_OWN_USERID);
   8.295 -            
   8.296 -        // protect virtual user IDs 
   8.297 -        if((strncmp("TOFU_", partner->user_id, 6) == 0 &&
   8.298 -           strlen(partner->user_id) == strlen(partner->address) + 6 &&
   8.299 -           strcmp(partner->user_id + 6, partner->address)) ||
   8.300 -        // protect own ID 
   8.301 -           (strcmp(own_id, partner->user_id) == 0)){
   8.302 -            status = PEP_SYNC_ILLEGAL_MESSAGE;
   8.303 -            free(own_id);
   8.304 -            goto error;
   8.305 -        }
   8.306 -
   8.307 -        free(own_id);
   8.308 -        // partner IDs are UUIDs bound to session lifespan
   8.309 -        // and therefore partner identities are not supposed
   8.310 -        // to mutate over time, but just not be used anymore.
   8.311 -        // It should then be safe to accept given identity if not 
   8.312 -        // already pre-existing
   8.313 -        pEp_identity *stored_identity = NULL;
   8.314 -        status = get_identity(session,
   8.315 -                              partner->address,
   8.316 -                              partner->user_id,
   8.317 -                              &stored_identity);
   8.318 -
   8.319 -        if (!stored_identity) {
   8.320 -            // make a safe copy of partner, with no flags or comm_type
   8.321 -            pEp_identity *tmpident = new_identity(partner->address,
   8.322 -                                                  partner->fpr,
   8.323 -                                                  partner->user_id,
   8.324 -                                                  partner->username);
   8.325 -            if (tmpident == NULL){
   8.326 -                status = PEP_OUT_OF_MEMORY;
   8.327 -                goto error;
   8.328 -            }
   8.329 -
   8.330 -            // finaly add partner to DB
   8.331 -            status = set_identity(session, tmpident);
   8.332 -            assert(status == PEP_STATUS_OK);
   8.333 -            if(status == PEP_STATUS_OK && msgIsFromGroup)
   8.334 -                status = set_identity_flags(session, tmpident, PEP_idf_devicegroup);
   8.335 -            free_identity(tmpident);
   8.336 -            assert(status == PEP_STATUS_OK);
   8.337 -            if (status != PEP_STATUS_OK) {
   8.338 -                goto error;
   8.339 -            }
   8.340 -        }
   8.341 -        else if (status == PEP_STATUS_OK) {
   8.342 -            free_identity(stored_identity);
   8.343 -        } 
   8.344 -        else
   8.345 -            goto error;
   8.346 -    }
   8.347 -
   8.348 -    status = fsm_DeviceState_inject(session, event, partner, extra, timeout);
   8.349 -
   8.350 -error:
   8.351 -
   8.352 -    free_identity(partner);
   8.353 -
   8.354 -    switch(event){
   8.355 -        case GroupKeys:
   8.356 -        {
   8.357 -            free_group_keys_extra((group_keys_extra_t*)extra);
   8.358 +    switch (fsm) {
   8.359 +        case Sync_PR_keysync: {
   8.360 +            int state = session->sync_state.keysync.state;
   8.361 +            state = fsm_KeySync(session, state, event);
   8.362 +            if (state > 0)
   8.363 +                session->sync_state.keysync.state = state;
   8.364 +            else if (state < 0)
   8.365 +                return PEP_STATEMACHINE_ERROR - state;
   8.366              break;
   8.367          }
   8.368 -        case GroupUpdate:
   8.369 -        {
   8.370 -            identity_list *group_keys = (identity_list*) extra;
   8.371 -            free_identity_list(group_keys);
   8.372 -            break;
   8.373 -        }
   8.374 +        
   8.375          default:
   8.376 -            assert(extra==NULL);
   8.377 -            break;
   8.378 -    }
   8.379 -
   8.380 -    free(sync_msg);
   8.381 -    free(own_id);
   8.382 -    
   8.383 -    return status;
   8.384 -}
   8.385 -
   8.386 -// TODO: DYNAMIC_API was here, but broke the windows build. 
   8.387 -// We need to check whether it belongs here or it's a bug.
   8.388 -/* DYNAMIC_API */ void free_sync_msg(sync_msg_t *sync_msg)
   8.389 -{
   8.390 -    if (!sync_msg)
   8.391 -        return;
   8.392 -
   8.393 -    if(sync_msg->is_a_message){
   8.394 -        DeviceGroup_Protocol_t *msg = sync_msg->u.message;
   8.395 -        assert(msg);
   8.396 -        if (!(msg))
   8.397 -            return;
   8.398 -
   8.399 -        ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   8.400 -    }
   8.401 -    else{
   8.402 -        Identity partner = NULL;
   8.403 -        partner = sync_msg->u.event.partner;
   8.404 -        if(partner != NULL)
   8.405 -            free_identity(partner);
   8.406 -    }
   8.407 -
   8.408 -    free(sync_msg);
   8.409 -
   8.410 -    return;
   8.411 -}
   8.412 -
   8.413 -// from sync.c
   8.414 -int call_inject_sync_msg(PEP_SESSION session, void *msg);
   8.415 -
   8.416 -PEP_STATUS inject_DeviceState_event(
   8.417 -    PEP_SESSION session, 
   8.418 -    DeviceState_event event,
   8.419 -    Identity partner,
   8.420 -    void *extra)
   8.421 -{
   8.422 -    PEP_STATUS status;
   8.423 -
   8.424 -    assert(session);
   8.425 -    if (!(session))
   8.426 -        return PEP_ILLEGAL_VALUE;
   8.427 -
   8.428 -    sync_msg_t *sync_msg = malloc(sizeof(sync_msg_t));
   8.429 -    if(sync_msg == NULL)
   8.430 -        return PEP_OUT_OF_MEMORY;
   8.431 -
   8.432 -    sync_msg->is_a_message = false;
   8.433 -    sync_msg->u.event.partner = partner;
   8.434 -    sync_msg->u.event.extra = extra;
   8.435 -    sync_msg->u.event.event = event;
   8.436 -
   8.437 -    status = call_inject_sync_msg(session, sync_msg);
   8.438 -    if (status == PEP_SYNC_NO_INJECT_CALLBACK){
   8.439 -        free(sync_msg);
   8.440 -    }
   8.441 -
   8.442 -    return status;
   8.443 -}
   8.444 -
   8.445 -PEP_STATUS receive_DeviceState_msg(
   8.446 -    PEP_SESSION session, 
   8.447 -    message *src, 
   8.448 -    PEP_rating rating, 
   8.449 -    stringlist_t *keylist)
   8.450 -{
   8.451 -    assert(session && src);
   8.452 -    if (!(session && src))
   8.453 -        return PEP_ILLEGAL_VALUE;
   8.454 -
   8.455 -    bool consume = false;
   8.456 -    bool discard = false;
   8.457 -    bool force_keep_msg = false;
   8.458 -
   8.459 -    char* own_id = NULL;
   8.460 -    PEP_STATUS own_id_status = get_default_own_userid(session, &own_id);
   8.461 -
   8.462 -    for (bloblist_t *bl = src->attachments; bl && bl->value; bl = bl->next) {
   8.463 -        if (bl->mime_type && strcasecmp(bl->mime_type, "application/pEp.sync") == 0
   8.464 -                && bl->size) {
   8.465 -            DeviceGroup_Protocol_t *msg = NULL;
   8.466 -            uper_decode_complete(NULL, &asn_DEF_DeviceGroup_Protocol, (void **)
   8.467 -                    &msg, bl->value, bl->size);
   8.468 -
   8.469 -            if (msg) {
   8.470 -                PEP_STATUS status = PEP_STATUS_OK;
   8.471 -
   8.472 -                char *user_id = strndup((char *) msg->header.me.user_id->buf,
   8.473 -                        msg->header.me.user_id->size);
   8.474 -                assert(user_id);
   8.475 -                if (!user_id) {
   8.476 -                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   8.477 -                    return PEP_OUT_OF_MEMORY;
   8.478 -                }
   8.479 -
   8.480 -                // detect and mitigate address spoofing
   8.481 -                Identity check_me = NULL;
   8.482 -                char* null_terminated_address = 
   8.483 -                    strndup((char *) msg->header.me.address->buf,
   8.484 -                            msg->header.me.address->size);
   8.485 -
   8.486 -                if(null_terminated_address){
   8.487 -                    
   8.488 -                    if (own_id) {                        
   8.489 -                        status = get_identity(session, 
   8.490 -                                              null_terminated_address, 
   8.491 -                                              own_id, 
   8.492 -                                              &check_me);
   8.493 -                        free(null_terminated_address);
   8.494 -
   8.495 -                    }
   8.496 -                    else {
   8.497 -                        status = own_id_status;
   8.498 -                    }
   8.499 -                } 
   8.500 -                else
   8.501 -                    status = PEP_OUT_OF_MEMORY;
   8.502 -
   8.503 -                if (status == PEP_OUT_OF_MEMORY)
   8.504 -                    goto free_all;
   8.505 -
   8.506 -                free_identity(check_me);
   8.507 -
   8.508 -                bool not_own_address = status != PEP_STATUS_OK;
   8.509 -                status = PEP_STATUS_OK;
   8.510 -
   8.511 -                if (not_own_address || 
   8.512 -                    strncmp(src->from->address,
   8.513 -                            (char *) msg->header.me.address->buf,
   8.514 -                            msg->header.me.address->size) != 0 ||
   8.515 -                    strncmp(src->to->ident->address,
   8.516 -                            (char *) msg->header.me.address->buf,
   8.517 -                            msg->header.me.address->size) != 0) {
   8.518 -                    consume = true;
   8.519 -                    goto free_all;
   8.520 -                }
   8.521 -
   8.522 -                // if encrypted, ensure that header.me.fpr match signer's fpr
   8.523 -                if (rating >= PEP_rating_reliable && (
   8.524 -                        !keylist ||
   8.525 -                        !_same_fpr((char *) msg->header.me.fpr.buf,
   8.526 -                                   msg->header.me.fpr.size,
   8.527 -                                   keylist->value,
   8.528 -                                   strlen(keylist->value)))) {
   8.529 -                    consume = true;
   8.530 -                    goto free_all;
   8.531 -                }
   8.532 -
   8.533 -                // check message expiry 
   8.534 -                if(src->recv) {
   8.535 -                    time_t expiry = timegm(src->recv) + SYNC_MSG_EXPIRE_TIME;
   8.536 -                    time_t now = time(NULL);
   8.537 -                    if(expiry != 0 && now != 0 && expiry < now){
   8.538 -                        consume = true;
   8.539 -                        goto free_all;
   8.540 -                    }
   8.541 -                }
   8.542 -
   8.543 -                int32_t value = (int32_t) msg->header.sequence;
   8.544 -                if (value < 1) {
   8.545 -                    status = PEP_SEQUENCE_VIOLATED;
   8.546 -                } else {
   8.547 -                    status = sequence_value(session, (char *) user_id,
   8.548 -                            &value);
   8.549 -                }
   8.550 -
   8.551 -                if (status == PEP_STATUS_OK) {
   8.552 -                    switch (msg->payload.present) {
   8.553 -                        // HandshakeRequest needs encryption
   8.554 -                        case DeviceGroup_Protocol__payload_PR_handshakeRequest:
   8.555 -                        {
   8.556 -                            UTF8String_t *puuid = 
   8.557 -                              msg->payload.choice.handshakeRequest.partner_id;
   8.558 -                            bool is_for_me = _is_own_uuid(session, puuid);
   8.559 -                            bool is_for_group = !is_for_me && 
   8.560 -                                                _is_own_group_uuid(
   8.561 -                                                    session, puuid, NULL);
   8.562 -
   8.563 -                            // Reject handshake requests not addressed to us
   8.564 -                            if (rating < PEP_rating_reliable ||
   8.565 -                                !(is_for_me || is_for_group)){
   8.566 -                                discard = true;
   8.567 -                                goto free_all;
   8.568 -                            }
   8.569 -
   8.570 -                            // do not consume handshake request for group
   8.571 -                            if(is_for_group){ 
   8.572 -                                force_keep_msg = true;
   8.573 -                            }
   8.574 -                            break;
   8.575 -                        }
   8.576 -                        // accepting GroupKeys needs encryption and trust of peer device
   8.577 -                        case DeviceGroup_Protocol__payload_PR_groupKeys:
   8.578 -                        {
   8.579 -                            UTF8String_t *puuid = msg->payload.choice.groupKeys.partner_id;
   8.580 -                            bool is_for_me = _is_own_uuid(session, puuid);
   8.581 -                            bool is_for_group = !is_for_me &&
   8.582 -                                                _is_own_group_uuid(session, 
   8.583 -                                                    puuid, NULL);
   8.584 -                            if (!keylist || rating < PEP_rating_reliable ||
   8.585 -                                // message is only consumed by instance it is addressed to
   8.586 -                                !(is_for_me || is_for_group)){
   8.587 -                                discard = true;
   8.588 -                                goto free_all;
   8.589 -                            }
   8.590 -
   8.591 -                            // do not consume groupKeys for group
   8.592 -                            if(is_for_group){ 
   8.593 -                                // This happens in case case of groupmerge
   8.594 -                                force_keep_msg = true;
   8.595 -                            }
   8.596 -
   8.597 -                            // Trust check disabled here but it still it should be safe.
   8.598 -                            // SameIdentity checks in state machine ensures that we only
   8.599 -                            // store groupkeys signed by device or group that have been 
   8.600 -                            // previously accepted in handshake.
   8.601 -                            //
   8.602 -                            // // check trust of identity using user_id given in msg.header.me
   8.603 -                            // // to exacly match identity of device, the one trusted in
   8.604 -                            // // case of accepted handshake from a sole device
   8.605 -                            // pEp_identity *_from = new_identity(NULL, 
   8.606 -                            //                                    keylist->value,
   8.607 -                            //                                    user_id,
   8.608 -                            //                                    NULL);
   8.609 -                            // if (_from == NULL){
   8.610 -                            //     status = PEP_OUT_OF_MEMORY;
   8.611 -                            //     goto free_all;
   8.612 -                            // }
   8.613 -                            // status = get_trust(session, _from);
   8.614 -                            // if (status != PEP_STATUS_OK || _from->comm_type < PEP_ct_strong_encryption) {
   8.615 -
   8.616 -                            //     // re-try with group_id instead, in case of handshake with pre-existing group
   8.617 -                            //     UTF8String_t *guuid = msg->payload.choice.groupKeys.group_id;
   8.618 -                            //     free(_from->user_id);
   8.619 -                            //     if ((_from->user_id = strndup((const char*)guuid->buf, guuid->size)) == NULL){
   8.620 -                            //         free_identity(_from);
   8.621 -                            //         status = PEP_OUT_OF_MEMORY;
   8.622 -                            //         goto free_all;
   8.623 -                            //     }
   8.624 -                            //     _from->comm_type = PEP_ct_unknown;
   8.625 -
   8.626 -                            //     status = get_trust(session, _from);
   8.627 -                            //     if (status != PEP_STATUS_OK || _from->comm_type < PEP_ct_strong_encryption) {
   8.628 -                            //         status = PEP_STATUS_OK;
   8.629 -                            //         free_identity(_from);
   8.630 -                            //         discard = true;
   8.631 -                            //         goto free_all;
   8.632 -                            //     }
   8.633 -                            // }
   8.634 -                            // free_identity(_from);
   8.635 -                            break;
   8.636 -                        }
   8.637 -                        case DeviceGroup_Protocol__payload_PR_groupUpdate:
   8.638 -                        case DeviceGroup_Protocol__payload_PR_updateRequest:
   8.639 -                        {
   8.640 -                            // inject message but don't consume it, so 
   8.641 -                            // that other group members can also be updated
   8.642 -                            force_keep_msg = true;
   8.643 -                            
   8.644 -                            if (!keylist || rating < PEP_rating_reliable){
   8.645 -                                discard = true;
   8.646 -                                goto free_all;
   8.647 -                            }
   8.648 -                            // GroupUpdate and UpdateRequests come from group.
   8.649 -                            // check trust relation in between signer key and 
   8.650 -                            // own id to be sure.
   8.651 -                            
   8.652 -                            if (status != PEP_STATUS_OK)
   8.653 -                                goto free_all;
   8.654 -                            
   8.655 -                            pEp_identity* _from = NULL;
   8.656 -                            
   8.657 -                            if (own_id) {    
   8.658 -                                _from = new_identity(NULL, 
   8.659 -                                                     keylist->value,
   8.660 -                                                     own_id,
   8.661 -                                                     NULL);
   8.662 -                            }
   8.663 -                            else {
   8.664 -                                status = own_id_status;
   8.665 -                                goto free_all;
   8.666 -                            }
   8.667 -                            
   8.668 -                            if (_from == NULL){
   8.669 -                                status = PEP_OUT_OF_MEMORY;
   8.670 -                                goto free_all;
   8.671 -                            }
   8.672 -                            status = get_trust(session, _from);
   8.673 -                            if (status != PEP_STATUS_OK || _from->comm_type < PEP_ct_pEp) {
   8.674 -                                status = PEP_STATUS_OK;
   8.675 -                                free_identity(_from);
   8.676 -                                discard = true;
   8.677 -                                goto free_all;
   8.678 -                            }
   8.679 -                            free_identity(_from);
   8.680 -                        }
   8.681 -                        default:
   8.682 -                            break;
   8.683 -                    }
   8.684 -
   8.685 -
   8.686 -                    consume = true;
   8.687 -                    sync_msg_t *sync_msg = malloc(sizeof(sync_msg_t));
   8.688 -                    if(sync_msg == NULL){
   8.689 -                        status = PEP_OUT_OF_MEMORY;
   8.690 -                        goto free_all;
   8.691 -                    }
   8.692 -                    sync_msg->is_a_message = true;
   8.693 -                    sync_msg->u.message = msg;
   8.694 -                    status = call_inject_sync_msg(session, sync_msg);
   8.695 -                    if (status != PEP_STATUS_OK){
   8.696 -                        if (status == PEP_SYNC_NO_INJECT_CALLBACK){
   8.697 -                            free(sync_msg);
   8.698 -                        }
   8.699 -                        goto free_all;
   8.700 -                    }
   8.701 -                    // don't free message now that it is in the queue
   8.702 -                    goto free_userid;
   8.703 -                }
   8.704 -                else if (status == PEP_OWN_SEQUENCE || status == PEP_SEQUENCE_VIOLATED) {
   8.705 -                    status = PEP_STATUS_OK;
   8.706 -                    discard = true;
   8.707 -                    goto free_all;
   8.708 -                }
   8.709 -
   8.710 -            free_all:
   8.711 -                ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   8.712 -            free_userid:
   8.713 -                free(user_id);
   8.714 -                free(own_id);
   8.715 -                if (status != PEP_STATUS_OK)
   8.716 -                    return status;
   8.717 -            }
   8.718 -        }
   8.719 -    }
   8.720 -
   8.721 -    if (force_keep_msg) {
   8.722 -        return PEP_MESSAGE_IGNORE;
   8.723 -    }
   8.724 -
   8.725 -    if (consume && !session->keep_sync_msg) {
   8.726 -        for (stringpair_list_t *spl = src->opt_fields ; spl && spl->value ;
   8.727 -                spl = spl->next) {
   8.728 -            if (spl->value->key &&
   8.729 -                    strcasecmp(spl->value->key, "pEp-auto-consume") == 0) {
   8.730 -                if (spl->value->value &&
   8.731 -                        strcasecmp(spl->value->value, "yes") == 0)
   8.732 -                    return PEP_MESSAGE_CONSUME;
   8.733 -            }
   8.734 -        }
   8.735 -        return PEP_MESSAGE_IGNORE;
   8.736 -    }
   8.737 -
   8.738 -    if(discard)
   8.739 -        return PEP_MESSAGE_IGNORE;
   8.740 -
   8.741 -    if (!session->keep_sync_msg) {
   8.742 -        bloblist_t *last = NULL;
   8.743 -        for (bloblist_t *bl = src->attachments; bl && bl->value; ) {
   8.744 -            if (bl->mime_type && strcasecmp(bl->mime_type, "application/pEp.sync") == 0) {
   8.745 -                bloblist_t *b = bl;
   8.746 -                bl = bl->next;
   8.747 -                if (!last)
   8.748 -                    src->attachments = bl;
   8.749 -                else
   8.750 -                    last->next = bl;
   8.751 -                free(b->mime_type);
   8.752 -                free(b->filename);
   8.753 -                free(b->value);
   8.754 -                free(b);
   8.755 -            }
   8.756 -            else {
   8.757 -                last = bl;
   8.758 -                bl = bl->next;
   8.759 -            }
   8.760 -        }
   8.761 +            return PEP_ILLEGAL_VALUE;
   8.762      }
   8.763  
   8.764      return PEP_STATUS_OK;
   8.765  }
   8.766  
   8.767 -DeviceGroup_Protocol_t *new_DeviceGroup_Protocol_msg(DeviceGroup_Protocol__payload_PR type)
   8.768 -{
   8.769 -    DeviceGroup_Protocol_t *msg = (DeviceGroup_Protocol_t *)
   8.770 -            calloc(1, sizeof(DeviceGroup_Protocol_t));
   8.771 -    assert(msg);
   8.772 -    if (!msg)
   8.773 -        return NULL;
   8.774 -    msg->payload.present = type;
   8.775 -    return msg;
   8.776 -}
   8.777 -
   8.778 -void free_DeviceGroup_Protocol_msg(DeviceGroup_Protocol_t *msg)
   8.779 -{
   8.780 -    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   8.781 -}
   8.782 -
   8.783 -
   8.784 -#ifndef NDEBUG
   8.785 -static int _append(const void *buffer, size_t size, void *appkey)
   8.786 -{
   8.787 -    char **dest_ptr = (char **)appkey;
   8.788 -    size_t osize = strlen(*dest_ptr);
   8.789 -    size_t nsize = size + osize;
   8.790 -    *dest_ptr = realloc(*dest_ptr, nsize + 1);
   8.791 -    if(*dest_ptr == NULL) return -1;
   8.792 -    memcpy(*dest_ptr + osize, buffer, size);
   8.793 -    (*dest_ptr)[nsize] = '\0';
   8.794 -    return 0;
   8.795 -}
   8.796 -#endif
   8.797 -
   8.798 -PEP_STATUS unicast_msg(
   8.799 -        PEP_SESSION session,
   8.800 -        const Identity partner,
   8.801 -        DeviceState_state state,
   8.802 -        DeviceGroup_Protocol_t *msg,
   8.803 -        bool encrypted
   8.804 +PEP_STATUS inject_Sync_event(
   8.805 +        PEP_SESSION session, 
   8.806 +        Sync_PR fsm,
   8.807 +        int event
   8.808      )
   8.809  {
   8.810 -    PEP_STATUS status = PEP_STATUS_OK;
   8.811 -    char *payload = NULL;
   8.812 -    message *_message = NULL;
   8.813 -    pEp_identity *me = NULL;
   8.814 -    pEp_identity *_me = NULL;
   8.815 -    char* own_id = NULL;
   8.816 +    Sync_t *msg = NULL;
   8.817 +    Sync_event_t *ev = NULL;
   8.818  
   8.819 -    assert(session && partner && state && msg);
   8.820 -    if (!(session && partner && state && msg))
   8.821 +    assert(session && fsm > 0 && event > None);
   8.822 +    if (!(session && fsm > 0 && event > None))
   8.823          return PEP_ILLEGAL_VALUE;
   8.824  
   8.825 -    assert(session->messageToSend);
   8.826 -    if (!session->messageToSend) {
   8.827 -        status = PEP_SEND_FUNCTION_NOT_REGISTERED;
   8.828 +    PEP_STATUS status = PEP_STATUS_OK;
   8.829 +
   8.830 +    if (!session->inject_sync_msg) {
   8.831 +       status = PEP_SYNC_NO_INJECT_CALLBACK;
   8.832 +       goto error;
   8.833 +    }
   8.834 +
   8.835 +    if (event < Extra) {
   8.836 +        msg = new_Sync_message(fsm, event);
   8.837 +        assert(msg);
   8.838 +        if (!msg) {
   8.839 +            status = PEP_OUT_OF_MEMORY;
   8.840 +            goto error;
   8.841 +        }
   8.842 +
   8.843 +        status = update_Sync_message(session, fsm, event, msg);
   8.844 +        if (status)
   8.845 +            goto error;
   8.846 +    }
   8.847 +
   8.848 +    ev = (Sync_event_t *) calloc(1, sizeof(Sync_event_t));
   8.849 +    assert(ev);
   8.850 +    if (!ev) {
   8.851 +        status = PEP_OUT_OF_MEMORY;
   8.852 +        goto error;
   8.853 +    }
   8.854 +    
   8.855 +    ev->fsm = fsm;
   8.856 +    ev->event = event;
   8.857 +    ev->msg = msg;
   8.858 +
   8.859 +    int result = session->inject_sync_msg(ev,
   8.860 +            session->sync_management);
   8.861 +    if (result) {
   8.862 +        status = PEP_STATEMACHINE_ERROR;
   8.863          goto error;
   8.864      }
   8.865  
   8.866 -    status = get_default_own_userid(session, &own_id);
   8.867 -    if (status != PEP_STATUS_OK)
   8.868 -        goto error;
   8.869 +    goto the_end;
   8.870  
   8.871 -    msg->header.version.major = SYNC_VERSION_MAJOR;
   8.872 -    msg->header.version.minor = SYNC_VERSION_MINOR;
   8.873 +error:
   8.874 +    free(ev);
   8.875 +    free_Sync_message(msg);
   8.876  
   8.877 -    status = get_identity(session, partner->address, own_id, &me);
   8.878 -    if (status != PEP_STATUS_OK)
   8.879 -        goto error;
   8.880 -    
   8.881 -    int32_t seq = 0;
   8.882 +the_end:
   8.883 +    return status;
   8.884 +}
   8.885  
   8.886 -    status = sequence_value(session, session->sync_session->sync_uuid, &seq);
   8.887 -    if (status != PEP_OWN_SEQUENCE && status != PEP_STATUS_OK)
   8.888 -        goto error;
   8.889 +PEP_STATUS Sync_send(
   8.890 +        PEP_SESSION session, 
   8.891 +        Sync_PR fsm,
   8.892 +        int message_type
   8.893 +    )
   8.894 +{
   8.895 +    assert(session && fsm > 0 && message_type > 1 && message_type < Extra);
   8.896 +    if (!(session && fsm > 0 && message_type > 1 && message_type < Extra))
   8.897 +        return PEP_ILLEGAL_VALUE;
   8.898  
   8.899 -    msg->header.sequence = (long) seq;
   8.900 +    PEP_STATUS status = PEP_STATUS_OK;
   8.901  
   8.902 -    _me = identity_dup(me);
   8.903 -    if (!_me)
   8.904 -        goto enomem;
   8.905 -
   8.906 -    free(_me->user_id);
   8.907 -    _me->user_id = strndup(session->sync_session->sync_uuid, 36);
   8.908 -    assert(_me->user_id);
   8.909 -    if (!_me->user_id)
   8.910 -        goto enomem;
   8.911 -
   8.912 -    if (Identity_from_Struct(_me, &msg->header.me) == NULL)
   8.913 -        goto enomem;
   8.914 -
   8.915 -    free_identity(_me);
   8.916 -    _me = NULL;
   8.917 -
   8.918 -    msg->header.state = (long) state;
   8.919 -
   8.920 -    bool devicegroup = deviceGrouped(session);
   8.921 -    if (devicegroup)
   8.922 -        msg->header.devicegroup = 1;
   8.923 -    else
   8.924 -        msg->header.devicegroup = 0;
   8.925 -
   8.926 -    if (asn_check_constraints(&asn_DEF_DeviceGroup_Protocol, msg, NULL, NULL)) {
   8.927 -        status = PEP_CONTRAINTS_VIOLATED;
   8.928 +    Sync_t *msg = new_Sync_message(fsm, message_type);
   8.929 +    assert(msg);
   8.930 +    if (!msg) {
   8.931 +        status = PEP_OUT_OF_MEMORY;
   8.932          goto error;
   8.933      }
   8.934  
   8.935 -    ssize_t size = uper_encode_to_new_buffer(&asn_DEF_DeviceGroup_Protocol,
   8.936 -            NULL, msg, (void **) &payload);
   8.937 -    if (size == -1) {
   8.938 -        status = PEP_CANNOT_ENCODE;
   8.939 +    status = update_Sync_message(session, fsm, message_type, msg);
   8.940 +    if (status)
   8.941          goto error;
   8.942 -    }
   8.943  
   8.944 -    status = prepare_message(me, partner, payload, size, &_message);
   8.945 -    if (status != PEP_STATUS_OK)
   8.946 -        goto error;
   8.947 -    payload = NULL;
   8.948 -    free_identity(me);
   8.949 -    me = NULL;
   8.950 +    goto the_end;
   8.951  
   8.952 -#ifndef NDEBUG
   8.953 -    asn_enc_rval_t er;
   8.954 -    er = xer_encode(&asn_DEF_DeviceGroup_Protocol, msg, 
   8.955 -                    XER_F_BASIC, _append, &_message->longmsg);
   8.956 -    if(er.encoded == -1)
   8.957 -        goto error;
   8.958 -#endif
   8.959 +error:
   8.960 +    free_Sync_message(msg);
   8.961  
   8.962 -    if (encrypted) {
   8.963 -        if (msg->payload.present == DeviceGroup_Protocol__payload_PR_groupKeys || 
   8.964 -            msg->payload.present == DeviceGroup_Protocol__payload_PR_groupUpdate) {
   8.965 -            PEP_rating rating = PEP_rating_undefined;
   8.966 -            status = outgoing_message_rating(session, _message, &rating);
   8.967 -            if (status != PEP_STATUS_OK)
   8.968 -                goto error;
   8.969 -            if (rating < PEP_rating_trusted) {
   8.970 -                status = PEP_SYNC_NO_TRUST;
   8.971 -                goto error;
   8.972 -            }
   8.973 -            
   8.974 -            stringlist_t *keylist = NULL;
   8.975 -            status = _own_keys_retrieve(session, &keylist, PEP_idf_not_for_sync);
   8.976 -            if (status != PEP_STATUS_OK)
   8.977 -                goto error;
   8.978 -
   8.979 -            for (stringlist_t *_keylist=keylist; _keylist!=NULL; _keylist=_keylist->next) {
   8.980 -                char *fpr = _keylist->value;
   8.981 -                static char filename[MAX_LINELENGTH];
   8.982 -                int result = snprintf(filename, MAX_LINELENGTH, "file://%s-sec.asc", fpr);
   8.983 -                if (result < 0)
   8.984 -                    goto enomem;
   8.985 -                char *key = NULL;
   8.986 -                size_t size = 0;
   8.987 -                status = export_secret_key(session, fpr, &key, &size);
   8.988 -                if (status != PEP_STATUS_OK)
   8.989 -                    goto error;
   8.990 -                bloblist_t *bl = bloblist_add(_message->attachments,
   8.991 -                        (char *) key, size, "application/pgp-keys", filename);
   8.992 -                if (!bl)
   8.993 -                    goto enomem;
   8.994 -                if (!_message->attachments)
   8.995 -                    _message->attachments = bl;
   8.996 -            }
   8.997 -        }
   8.998 -
   8.999 -        message *_encrypted = NULL;
  8.1000 -        status = encrypt_message(session, _message, NULL, &_encrypted, PEP_enc_PEP, 0);
  8.1001 -        if (status != PEP_STATUS_OK)
  8.1002 -            goto error;
  8.1003 -        free_message(_message);
  8.1004 -        _message = _encrypted;
  8.1005 -    }
  8.1006 -    else {
  8.1007 -        attach_own_key(session, _message);
  8.1008 -    }
  8.1009 -
  8.1010 -    status = session->messageToSend(session->sync_obj, _message);
  8.1011 -    return status;
  8.1012 -
  8.1013 -enomem:
  8.1014 -    status = PEP_OUT_OF_MEMORY;
  8.1015 -error:
  8.1016 -    free_identity(_me);
  8.1017 -    free(payload);
  8.1018 -    free_message(_message);
  8.1019 -    free_identity(me);
  8.1020 -    free(own_id);
  8.1021 +the_end:
  8.1022      return status;
  8.1023  }
  8.1024  
  8.1025 -PEP_STATUS multicast_self_msg(
  8.1026 -        PEP_SESSION session,
  8.1027 -        DeviceState_state state,
  8.1028 -        DeviceGroup_Protocol_t *msg,
  8.1029 -        bool encrypted
  8.1030 +PEP_STATUS recv_Sync_event(
  8.1031 +        PEP_SESSION session, 
  8.1032 +        Sync_event_t *ev
  8.1033      )
  8.1034  {
  8.1035 +    assert(session && ev);
  8.1036 +    if (!(session && ev))
  8.1037 +        return PEP_ILLEGAL_VALUE;
  8.1038 +
  8.1039 +    assert(ev->fsm >= None && ev->event >= None);
  8.1040 +    if (!(ev->fsm >= None && ev->event >= None))
  8.1041 +        return PEP_ILLEGAL_VALUE;
  8.1042 +
  8.1043      PEP_STATUS status = PEP_STATUS_OK;
  8.1044  
  8.1045 -    assert(session && state && msg);
  8.1046 -    if (!(session && state && msg))
  8.1047 -        return PEP_ILLEGAL_VALUE;
  8.1048 +    if (ev->event < Extra) {
  8.1049 +        Sync_PR fsm = (int) None;
  8.1050 +        int event = None;
  8.1051  
  8.1052 -    identity_list *own_identities = NULL;
  8.1053 -    status = _own_identities_retrieve(session, &own_identities, PEP_idf_not_for_sync);
  8.1054 -    if (status != PEP_STATUS_OK)
  8.1055 -        return status;
  8.1056 +        status = update_Sync_state(session, ev->msg, &fsm, &event);
  8.1057 +        if (status)
  8.1058 +            goto error;
  8.1059  
  8.1060 -    for (identity_list *_i = own_identities; _i && _i->ident; _i = _i->next) {
  8.1061 -        pEp_identity *me = _i->ident;
  8.1062 -
  8.1063 -        // FIXME: no deep copy for multicast supported yet
  8.1064 -        // DeviceGroup_Protocol_t *_msg = malloc(sizeof(DeviceGroup_Protocol_t));
  8.1065 -        // assert(_msg);
  8.1066 -        // if (_msg == NULL){
  8.1067 -        //     status = PEP_OUT_OF_MEMORY;
  8.1068 -        //     goto error;
  8.1069 -        // }
  8.1070 -        // memcpy(_msg, msg, sizeof(DeviceGroup_Protocol_t));
  8.1071 -        status = unicast_msg(session, me, state, msg, encrypted);
  8.1072 -        //status = unicast_msg(session, me, state, _msg, encrypted);
  8.1073 -        //free_DeviceGroup_Protocol_msg(_msg);
  8.1074 +        if (ev->fsm) {
  8.1075 +            if (ev->fsm != fsm || ev->event != event) {
  8.1076 +                status = PEP_SYNC_ILLEGAL_MESSAGE;
  8.1077 +                goto error;
  8.1078 +            }
  8.1079 +        }
  8.1080 +        else {
  8.1081 +            if (ev->event) {
  8.1082 +                status = PEP_SYNC_ILLEGAL_MESSAGE;
  8.1083 +                goto error;
  8.1084 +            }
  8.1085 +            ev->fsm = fsm;
  8.1086 +            ev->event = event;
  8.1087 +        }
  8.1088      }
  8.1089  
  8.1090 -    free_identity_list(own_identities);
  8.1091 -    return PEP_STATUS_OK;
  8.1092 +    free_Sync_message(ev->msg);
  8.1093 +    free(ev);
  8.1094 +    status = Sync_driver(session, ev->fsm, ev->event);
  8.1095 +    return status;
  8.1096  
  8.1097 -// error:
  8.1098 -//     free_identity_list(own_identities);
  8.1099 -//     return status;
  8.1100 +error:
  8.1101 +    free_Sync_message(ev->msg);
  8.1102 +    free(ev);
  8.1103 +    return status;
  8.1104  }
  8.1105  
  8.1106 -void free_group_keys_extra(group_keys_extra_t* group_keys_extra)
  8.1107 -{
  8.1108 -    identity_list *group_keys = group_keys_extra->group_keys;
  8.1109 -    char *group_id = group_keys_extra->group_id;
  8.1110 -    free_identity_list(group_keys);
  8.1111 -    free(group_id);
  8.1112 -    free(group_keys_extra);
  8.1113 -}
  8.1114 -
  8.1115 -group_keys_extra_t* group_keys_extra_dup(group_keys_extra_t* group_key_extra_src)
  8.1116 -{
  8.1117 -    group_keys_extra_t *group_key_extra_dst;
  8.1118 -    group_key_extra_dst = calloc(1,sizeof(group_keys_extra_t));
  8.1119 -    if(group_key_extra_dst == NULL){
  8.1120 -        return NULL;
  8.1121 -    }
  8.1122 -
  8.1123 -    char *group_id = strdup(group_key_extra_src->group_id);
  8.1124 -
  8.1125 -    if (group_key_extra_dst->group_id && !group_id){
  8.1126 -        free(group_key_extra_dst);
  8.1127 -        return NULL;
  8.1128 -    }
  8.1129 -    group_key_extra_dst->group_id = group_id;
  8.1130 -
  8.1131 -    identity_list *group_keys = identity_list_dup(group_key_extra_src->group_keys);;
  8.1132 -    if (!group_keys) {
  8.1133 -        free(group_id);
  8.1134 -        free(group_key_extra_dst);
  8.1135 -        return NULL;
  8.1136 -    }
  8.1137 -    group_key_extra_dst->group_keys = group_keys;
  8.1138 -
  8.1139 -    return group_key_extra_dst;
  8.1140 -}
     9.1 --- a/src/sync_impl.h	Tue Aug 07 14:24:15 2018 +0200
     9.2 +++ b/src/sync_impl.h	Tue Aug 07 17:16:03 2018 +0200
     9.3 @@ -3,60 +3,82 @@
     9.4  
     9.5  #pragma once
     9.6  
     9.7 -#include "../asn.1/DeviceGroup-Protocol.h"
     9.8 -#include "message.h"
     9.9 -#include "sync.h"
    9.10 -#include "sync_fsm.h"
    9.11 +#include "fsm_common.h"
    9.12 +#include "message_api.h"
    9.13 +#include "../asn.1/Sync.h"
    9.14  
    9.15  #ifdef __cplusplus
    9.16  extern "C" {
    9.17  #endif
    9.18  
    9.19 -typedef struct _group_keys_extra {
    9.20 -    identity_list *group_keys;
    9.21 -    char *group_id;
    9.22 -} group_keys_extra_t;
    9.23 +// event struct
    9.24  
    9.25 -void free_group_keys_extra(group_keys_extra_t* groupkeys);
    9.26 -group_keys_extra_t* group_keys_extra_dup(group_keys_extra_t* groupkeys);
    9.27 +typedef struct _Sync_event {
    9.28 +    Sync_PR fsm;
    9.29 +    int event;
    9.30 +    Sync_t *msg;
    9.31 +} Sync_event_t;
    9.32  
    9.33 -PEP_STATUS receive_sync_msg(
    9.34 -        PEP_SESSION session,
    9.35 -        sync_msg_t *sync_msg,
    9.36 -        time_t *timeout
    9.37 +// conditions
    9.38 +
    9.39 +PEP_STATUS deviceGrouped(PEP_SESSION session, bool *result);
    9.40 +PEP_STATUS challengeAccepted(PEP_SESSION session, bool *result);
    9.41 +PEP_STATUS partnerIsGrouped(PEP_SESSION session, bool *result);
    9.42 +PEP_STATUS keyElectionWon(PEP_SESSION session, bool *result);
    9.43 +// actions
    9.44 +
    9.45 +PEP_STATUS closeHandshakeDialog(PEP_SESSION session);
    9.46 +PEP_STATUS openChallenge(PEP_SESSION session);
    9.47 +PEP_STATUS storeChallenge(PEP_SESSION session);
    9.48 +PEP_STATUS openTransaction(PEP_SESSION session);
    9.49 +PEP_STATUS storeTransaction(PEP_SESSION session);
    9.50 +PEP_STATUS showSoleHandshake(PEP_SESSION session);
    9.51 +PEP_STATUS disable(PEP_SESSION session);
    9.52 +PEP_STATUS saveGroupKeys(PEP_SESSION session);
    9.53 +PEP_STATUS ownKeysAreGroupKeys(PEP_SESSION session);
    9.54 +PEP_STATUS showJoinGroupHandshake(PEP_SESSION session);
    9.55 +PEP_STATUS showGroupedHandshake(PEP_SESSION session);
    9.56 +
    9.57 +// send event to own state machine, use state to generate
    9.58 +// Sync message if necessary
    9.59 +
    9.60 +PEP_STATUS Sync_send(
    9.61 +        PEP_SESSION session, 
    9.62 +        Sync_PR fsm,
    9.63 +        int message_type
    9.64      );
    9.65  
    9.66 -PEP_STATUS inject_DeviceState_event(
    9.67 -    PEP_SESSION session, 
    9.68 -    DeviceState_event event,
    9.69 -    Identity partner,
    9.70 -    void *extra);
    9.71 +// send message to partners
    9.72  
    9.73 -PEP_STATUS receive_DeviceState_msg(
    9.74 -    PEP_SESSION session, 
    9.75 -    message *src, 
    9.76 -    PEP_rating rating, 
    9.77 -    stringlist_t *keylist);
    9.78 -
    9.79 -DeviceGroup_Protocol_t *new_DeviceGroup_Protocol_msg(DeviceGroup_Protocol__payload_PR type);
    9.80 -void free_DeviceGroup_Protocol_msg(DeviceGroup_Protocol_t *msg);
    9.81 -
    9.82 -PEP_STATUS unicast_msg(
    9.83 -        PEP_SESSION session,
    9.84 -        const Identity partner,
    9.85 -        DeviceState_state state,
    9.86 -        DeviceGroup_Protocol_t *msg,
    9.87 -        bool encrypted
    9.88 +PEP_STATUS send_Sync_message(
    9.89 +        PEP_SESSION session, 
    9.90 +        Sync_PR fsm,
    9.91 +        int event
    9.92      );
    9.93  
    9.94 -PEP_STATUS multicast_self_msg(
    9.95 -        PEP_SESSION session,
    9.96 -        DeviceState_state state,
    9.97 -        DeviceGroup_Protocol_t *msg,
    9.98 -        bool encrypted
    9.99 +// receive event, free Sync_event_t structure if call does not fail
   9.100 +// with PEP_ILLEGAL_VALUE
   9.101 +
   9.102 +PEP_STATUS recv_Sync_event(
   9.103 +        PEP_SESSION session, 
   9.104 +        Sync_event_t *ev
   9.105      );
   9.106  
   9.107 -bool is_double(DeviceGroup_Protocol_t *msg);
   9.108 +// state machine driver
   9.109 +// if fsm or event set to 0 use fields in src if present
   9.110 +
   9.111 +PEP_STATUS Sync_driver(
   9.112 +        PEP_SESSION session,
   9.113 +        Sync_PR fsm,
   9.114 +        int event
   9.115 +    );
   9.116 +
   9.117 +PEP_STATUS inject_Sync_event(
   9.118 +        PEP_SESSION session, 
   9.119 +        Sync_PR fsm,
   9.120 +        int event
   9.121 +    );
   9.122 +
   9.123  
   9.124  #ifdef __cplusplus
   9.125  }
    10.1 --- a/sync/Makefile	Tue Aug 07 14:24:15 2018 +0200
    10.2 +++ b/sync/Makefile	Tue Aug 07 17:16:03 2018 +0200
    10.3 @@ -1,38 +1,38 @@
    10.4 -# Copyright 2017, pEp Foundation
    10.5 -# This file is part of pEpEngine
    10.6 -# This file may be used under the terms of the GNU General Public License version 3
    10.7 +# This file is under GNU General Public License 3.0
    10.8  # see LICENSE.txt
    10.9  
   10.10  include ../default.conf
   10.11  
   10.12 -.PHONY: all
   10.13  all: .codegen
   10.14  
   10.15 -# Currently not in use, kept for historic reasons
   10.16 -skeleton: .actions
   10.17 +.codegen: .statemachines .actions .codecs .messages
   10.18 +	cp -f generated/*.c generated/*.h ../src
   10.19 +	touch .codegen
   10.20  
   10.21 -.codegen: .statemachines .actions
   10.22 -	cp -f generated/*.* ../src
   10.23 -	touch $@
   10.24 +.actions: sync.fsm gen_actions.ysl2 fsm.yml2 functions.ysl2 cond_act.yml2
   10.25 +	$(YML2_PROC) -y gen_actions.ysl2 $< -o $@
   10.26  
   10.27 -.actions: devicegroup.fsm gen_actions.ysl2 fsm.yml2 functions.ysl2
   10.28 -	$(YML2_PROC) $(YML2_OPTS) -y gen_actions.ysl2 $< -o $@
   10.29 +.statemachines: sync.fsm gen_statemachine.ysl2 fsm.yml2 functions.ysl2
   10.30 +	$(YML2_PROC) -y gen_statemachine.ysl2 $< -o $@
   10.31  
   10.32 -.statemachines: devicegroup.fsm gen_statemachine.ysl2 fsm.yml2 functions.ysl2
   10.33 -	$(YML2_PROC) $(YML2_OPTS) -y gen_statemachine.ysl2 $< -o $@
   10.34 +.codecs: sync.fsm gen_message_func.ysl2 fsm.yml2 functions.ysl2
   10.35 +	$(YML2_PROC) -y gen_message_func.ysl2 $< -o $@
   10.36 +
   10.37 +.messages: sync.fsm gen_messages.ysl2 fsm.yml2 functions.ysl2
   10.38 +	$(YML2_PROC) -y gen_messages.ysl2 $< -o $@
   10.39  
   10.40  .PHONY: clean
   10.41 +
   10.42  clean:
   10.43 -	rm -f *.xml *.xsl *.dot *.svg \
   10.44 -	$(patsubst generated/%,../src/%,$(wildcard generated/*.*)) \
   10.45 -	../generated/* ../skeletons/* .statemachines .actions .codegen \
   10.46 -	generated/Makefile.protocols
   10.47 +	rm -f *.xml *.xsl \
   10.48 +    $(pathsub generated/%, ../src/% $(wildcard generated/*.*)) \
   10.49 +    ../generated/* .statemachines .actions .codecs .messages *.dot *.svg
   10.50  
   10.51  %.xml: %.fsm
   10.52 -	$(YML2_PATH)/yml2c $< -o $@
   10.53 +	yml2c $< -o $@
   10.54  
   10.55 -%.dot: gen_dot.ysl2 devicegroup.fsm
   10.56 -	$(YML2_PROC) $(YML2_OPTS) -y $^
   10.57 +%.dot: sync.fsm gen_dot.ysl2
   10.58 +	yml2proc -y gen_dot.ysl2 $<
   10.59  
   10.60  %.svg: %.dot
   10.61  	dot -Tsvg -o $@ $<
    11.1 --- a/sync/fsm.yml2	Tue Aug 07 14:24:15 2018 +0200
    11.2 +++ b/sync/fsm.yml2	Tue Aug 07 17:16:03 2018 +0200
    11.3 @@ -1,19 +1,54 @@
    11.4  // This file is under GNU General Public License 3.0
    11.5  // see LICENSE.txt
    11.6  
    11.7 -// FSM Y language 1.0
    11.8 +// FSM Y language 1.2
    11.9  
   11.10 -// Copyleft (c) 2016, p≡p foundation
   11.11 +// Copyleft (c) 2016, 2017, p≡p foundation
   11.12  
   11.13  // Written by Volker Birk
   11.14  
   11.15 -decl protocol @name;
   11.16 -decl fsm @name;
   11.17 +decl version(major, minor);
   11.18 +
   11.19 +// a protocol family has a name and an ID
   11.20 +
   11.21 +decl protocol @name (id);
   11.22 +
   11.23 +// each protocol in a family has a finite state machine
   11.24 +
   11.25 +decl fsm< protocol >;
   11.26 +
   11.27 +// a state has a name and a timeout; after the timeout the state machine will
   11.28 +// be reset
   11.29 +
   11.30  decl state @name (timeout=0);
   11.31 +
   11.32 +// events have names
   11.33 +
   11.34  decl event @name, on is event;
   11.35 +
   11.36 +// a transistion moves the statemachine to another state
   11.37 +
   11.38  decl transition @target, go is transition;
   11.39 +
   11.40 +// an action is executed; if an action name starts with 'send' then it is
   11.41 +// sending a message
   11.42 +
   11.43  decl action @name, do is action;
   11.44 +
   11.45 +// a condition is for different cases
   11.46 +
   11.47  decl condition @name, if is condition;
   11.48 -decl alternative, else is alternative;
   11.49 -decl interface @name;
   11.50 -decl tag @name (id);
   11.51 +
   11.52 +// some events have messages on the line signalling the event to the
   11.53 +// communication partner
   11.54 +
   11.55 +decl message @name (id);
   11.56 +
   11.57 +// messages can have transmitted fields…
   11.58 +
   11.59 +decl field @type @name;
   11.60 +
   11.61 +// … or automatically calculated fields…
   11.62 +
   11.63 +decl auto < field >;
   11.64 +
    12.1 --- a/sync/functions.ysl2	Tue Aug 07 14:24:15 2018 +0200
    12.2 +++ b/sync/functions.ysl2	Tue Aug 07 17:16:03 2018 +0200
    12.3 @@ -8,8 +8,49 @@
    12.4      choose {
    12.5          when "not($nodes)"
    12.6              result "/..";
    12.7 -        otherwise {
    12.8 +        otherwise
    12.9              result "$nodes[1] | func:distinctName($nodes[position() > 1])[@name != $nodes[1]/@name]";
   12.10 -        }
   12.11      }
   12.12  }
   12.13 +
   12.14 +def "func:distinctType" {
   12.15 +    param "nodes", "/..";
   12.16 +    choose {
   12.17 +        when "not($nodes)"
   12.18 +            result "/..";
   12.19 +        otherwise
   12.20 +            result "$nodes[1] | func:distinctType($nodes[position() > 1])[@type != $nodes[1]/@type]";
   12.21 +    }
   12.22 +}
   12.23 +
   12.24 +def "func:asn1name"
   12.25 +    result "translate(@name, '_', '-')";
   12.26 +
   12.27 +def "func:asn1type" {
   12.28 +    choose {
   12.29 +        when "@type='bool'"
   12.30 +            result "'BOOLEAN'";
   12.31 +        when "@type='int'"
   12.32 +            result "'INTEGER'";
   12.33 +        otherwise
   12.34 +            result "translate(@type, '_', '-')";
   12.35 +    }
   12.36 +}
   12.37 +
   12.38 +def "func:basicType" {
   12.39 +    choose {
   12.40 +        when "substring(@type,1,1)=yml:lcase(substring(@type,1,1))"
   12.41 +            result "true()";
   12.42 +        otherwise
   12.43 +            result "false()";
   12.44 +    }
   12.45 +}
   12.46 +
   12.47 +def "func:ctype" {
   12.48 +    choose {
   12.49 +        when "func:basicType()"
   12.50 +            result "@type";
   12.51 +        otherwise
   12.52 +            result "concat(@type,'_t')";
   12.53 +    }
   12.54 +}
    13.1 --- a/sync/gen_actions.ysl2	Tue Aug 07 14:24:15 2018 +0200
    13.2 +++ b/sync/gen_actions.ysl2	Tue Aug 07 17:16:03 2018 +0200
    13.3 @@ -1,297 +1,79 @@
    13.4  // This file is under GNU General Public License 3.0
    13.5  // see LICENSE.txt
    13.6  
    13.7 -// generate actions skeleton
    13.8 +// generate conditions and actions
    13.9  
   13.10 -// Copyleft (c) 2016, p≡p foundation
   13.11 +// Copyleft (c) 2017, p≡p foundation
   13.12  
   13.13  // Written by Volker Birk
   13.14  
   13.15  include yslt.yml2
   13.16  
   13.17 +decl _func *name (*type) alias - {
   13.18 +    template %name=*name, %type=*type, "%type[@name='%name']"
   13.19 +        call *type with "content" content;
   13.20 +};
   13.21 +
   13.22 +decl condition is _func (*type="condition");
   13.23 +decl action is _func (*type="action");
   13.24 +
   13.25  tstylesheet {
   13.26      include standardlib.ysl2
   13.27      include ./functions.ysl2
   13.28  
   13.29 +    include ./cond_act.yml2
   13.30 +
   13.31      template "/protocol" {
   13.32 -        apply "fsm", mode=send, 0;
   13.33 -        apply "fsm", mode=other, 0;
   13.34 -    }
   13.35 +        document "generated/{@name}_actions.c", "text" {
   13.36 +            ||
   13.37 +            // This file is under GNU General Public License 3.0
   13.38 +            // see LICENSE.txt
   13.39  
   13.40 -    template "fsm", mode=send document "generated/{@filename}_send_actions.c", "text" {
   13.41 -        const "name", "@name";
   13.42 -        const "filename", "@filename";
   13.43 -        ||
   13.44 -        // Send Actions for «@name» state machine
   13.45 +            #include "«@name»_impl.h"
   13.46 +            `` for "fsm" | #include "«@name»_fsm.h"
   13.47  
   13.48 -        #include <assert.h>
   13.49 -        #include "pEp_internal.h"
   13.50 -        #include "keymanagement.h"
   13.51 -        #include "message.h"
   13.52 -        #include "«@filename»_fsm.h"
   13.53 -        #include "baseprotocol.h"
   13.54 -        #include "map_asn1.h"
   13.55 -        #include "../asn.1/DeviceGroup-Protocol.h"
   13.56 -        #include "sync_impl.h"
   13.57 -        ||
   13.58 -        for "func:distinctName(//action)"
   13.59 -            if "substring(@name, 1, 4) = 'send'"
   13.60 -                | #include "../asn.1/«substring(@name, 5, 255)».h"
   13.61 -        |
   13.62 -        for "func:distinctName(//action)"
   13.63 -            if "substring(@name, 1, 4) = 'send'"
   13.64 -                call "send_action"
   13.65 -                    with "action", ".",
   13.66 -                    with "fsm", "$name",
   13.67 -                    with "filename", "$filename";
   13.68 -
   13.69 -        ||
   13.70 -
   13.71 -        PEP_STATUS _notifyHandshake(
   13.72 -                PEP_SESSION session,
   13.73 -                Identity partner,
   13.74 -                sync_handshake_signal signal
   13.75 -            );
   13.76 -        ||
   13.77 -
   13.78 -        for "func:distinctName(//action)"
   13.79 -            if "substring(@name, 1, 6) = 'notify'"
   13.80 -                call "notify_action"
   13.81 -                    with "action", ".",
   13.82 -                    with "fsm", "$name",
   13.83 -                    with "filename", "$filename";
   13.84 -    }
   13.85 -
   13.86 -    template "fsm", mode=other document "skeletons/{@filename}_actions.c", "text" {
   13.87 -        const "name", "@name";
   13.88 -        const "filename", "@filename";
   13.89 -        ||
   13.90 -        // Actions for «@name» state machine
   13.91 -
   13.92 -        #include <assert.h>
   13.93 -        #include "pEp_internal.h"
   13.94 -        #include "keymanagement.h"
   13.95 -        #include "message.h"
   13.96 -        #include "«@filename»_fsm.h"
   13.97 -        #include "../asn.1/DeviceGroup-Protocol.h"
   13.98 -
   13.99 -        ||
  13.100 -        for "func:distinctName(//action)"
  13.101 -            if "substring(@name, 1, 4) != 'send'"
  13.102 -                call "other_action"
  13.103 -                    with "action", ".",
  13.104 -                    with "fsm", "$name",
  13.105 -                    with "filename", "$filename";
  13.106 -    }
  13.107 -
  13.108 -    function "paramcheck" {
  13.109 -        param "partner";
  13.110 -        |> assert(session);
  13.111 -        choose {
  13.112 -            when "$partner"
  13.113              ||
  13.114 -                assert(partner);
  13.115 -                if (!(session && partner))
  13.116 -                    return PEP_ILLEGAL_VALUE;
  13.117 -            ||
  13.118 -            otherwise
  13.119 -            ||
  13.120 -                assert(!partner);
  13.121 -                if (!(session && !partner))
  13.122 -                    return PEP_ILLEGAL_VALUE;
  13.123 -            ||
  13.124 +            apply "func:distinctName(//condition)", 0;
  13.125 +            apply "func:distinctName(//action[not(starts-with(@name, 'send'))])", 0;
  13.126          }
  13.127      }
  13.128  
  13.129 -    function "other_action" {
  13.130 -        param "action";
  13.131 -        param "fsm";
  13.132 -        param "filename", "'###'";
  13.133 +    template "condition" | #error condition «@name» not implemented\n
  13.134 +    template "action" | #error action «@name» not implemented\n
  13.135 +
  13.136 +    function "condition" {
  13.137 +        param "content";
  13.138 +        ||
  13.139 +        PEP_STATUS «@name»(PEP_SESSION session, bool *result)
  13.140 +        {
  13.141 +            assert(session && result);
  13.142 +            if (!(session && result))
  13.143 +                return PEP_ILLEGAL_VALUE;
  13.144  
  13.145          ||
  13.146 +        copy "$content";
  13.147 +        ||
  13.148  
  13.149 -        // «$action/@name»() - 
  13.150 -        //
  13.151 -        //  params:
  13.152 -        //      session (in)        session handle
  13.153 -        //      state (in)          state the state machine is in
  13.154 -        `` if "parm"        | //      partner (in)        partner to communicate with
  13.155 -        `` if "not(parm)"   | //      partner (in)        (must be NULL)
  13.156 -        //
  13.157 -        //  returns:
  13.158 -        //      PEP_STATUS_OK or any other value on error
  13.159 -
  13.160 -        PEP_STATUS «$action/@name»(
  13.161 -                PEP_SESSION session,
  13.162 -                «$fsm»_state state,
  13.163 -                Identity partner,
  13.164 -                void *extra
  13.165 -            )
  13.166 -        {
  13.167 -            PEP_STATUS status = PEP_STATUS_OK;
  13.168 -
  13.169 -            `` call "paramcheck" with "partner", "parm/partner";
  13.170 -
  13.171 -            // working code
  13.172 -
  13.173 -            // free extra
  13.174 -            return status;
  13.175 -
  13.176 -        enomem:
  13.177 -            status = PEP_OUT_OF_MEMORY;
  13.178 -        error:
  13.179 -            // free extra
  13.180 -            return status;
  13.181 +            return PEP_STATUS_OK;
  13.182          }
  13.183  
  13.184          ||
  13.185      }
  13.186  
  13.187 -    function "send_action" {
  13.188 -        param "action";
  13.189 -        param "fsm";
  13.190 -        param "filename", "'###'";
  13.191 -        const "name", "substring($action/@name, 5, 255)";
  13.192 -        const "lname", "concat(yml:lcase(substring($name, 1, 1)), substring($name, 2))";
  13.193 +    function "action" {
  13.194 +        param "content";
  13.195 +        ||
  13.196 +        PEP_STATUS «@name»(PEP_SESSION session)
  13.197 +        {
  13.198 +            assert(session);
  13.199 +            if (!session)
  13.200 +                return PEP_ILLEGAL_VALUE;
  13.201  
  13.202          ||
  13.203 -
  13.204 -        // «$action/@name»() - send «$name» message
  13.205 -        //
  13.206 -        //  params:
  13.207 -        //      session (in)        session handle
  13.208 -        //      state (in)          state the state machine is in
  13.209 -        `` if "parm"        | //      partner (in)        partner to communicate with
  13.210 -        `` if "not(parm)"   | //      partner (in)        (must be NULL)
  13.211 -        //
  13.212 -        //  returns:
  13.213 -        //      PEP_STATUS_OK or any other value on error
  13.214 -
  13.215 -        PEP_STATUS «$action/@name»(
  13.216 -                PEP_SESSION session,
  13.217 -                «$fsm»_state state,
  13.218 -                Identity partner,
  13.219 -                void *extra
  13.220 -            )
  13.221 -        {
  13.222 -            assert(session && state);
  13.223 -            if (!(session && state))
  13.224 -                return PEP_ILLEGAL_VALUE;
  13.225 -
  13.226 -            PEP_STATUS status = PEP_STATUS_OK;
  13.227 -            `` if "$name='GroupKeys' or $name='GroupUpdate'" |> identity_list *kl = new_identity_list(NULL);
  13.228 -
  13.229 -            DeviceGroup_Protocol_t *msg = new_DeviceGroup_Protocol_msg(DeviceGroup_Protocol__payload_PR_«$lname»);
  13.230 -            if (!msg)
  13.231 -                goto enomem;
  13.232 -        ||
  13.233 -        choose {
  13.234 -            when "$name='GroupKeys' or $name='GroupUpdate'" {
  13.235 -                |
  13.236 -                |> status = _own_identities_retrieve(session, &kl, PEP_idf_not_for_sync);
  13.237 -                |> if (status != PEP_STATUS_OK)
  13.238 -                |>> goto error;
  13.239 -                |> if (IdentityList_from_identity_list(kl, &msg->payload.choice.«$lname».ownIdentities) == NULL)
  13.240 -                |>> goto enomem;
  13.241 -            }
  13.242 -        }
  13.243 -        choose {
  13.244 -            when "$name='GroupKeys' or $name='HandshakeRequest'" {
  13.245 -                |
  13.246 -                |> msg->payload.choice.«$lname».partner_id = 
  13.247 -                |>     OCTET_STRING_new_fromBuf(&asn_DEF_UTF8String,
  13.248 -                |>                              partner->user_id, -1);
  13.249 -                |> if (partner->user_id && !msg->payload.choice.«$lname».partner_id)
  13.250 -                |>    goto enomem;
  13.251 -                |
  13.252 -                |> char *devgrp = NULL;
  13.253 -                |> status = get_device_group(session, &devgrp);
  13.254 -                |> if (status == PEP_STATUS_OK && devgrp && devgrp[0])
  13.255 -                |> msg->payload.choice.«$lname».group_id = 
  13.256 -                |>     OCTET_STRING_new_fromBuf(&asn_DEF_UTF8String,
  13.257 -                |>                              devgrp, -1);
  13.258 -                |> free(devgrp);
  13.259 -                |> if (devgrp && !msg->payload.choice.«$lname».partner_id)
  13.260 -                |>    goto enomem;
  13.261 -            }
  13.262 -        }
  13.263 +        copy "$content";
  13.264          ||
  13.265  
  13.266 -        ||
  13.267 -        choose {
  13.268 -            when "count(/protocol/unencrypted/*[name()=$action/@name]) = 0"
  13.269 -                |> bool encrypted = true;
  13.270 -            otherwise
  13.271 -                |> bool encrypted = false;
  13.272 -        }
  13.273 -        choose {
  13.274 -            when "count(/protocol/broadcast/*[name()=$action/@name]) = 0"
  13.275 -                |> status = unicast_msg(session, partner, state, msg, encrypted);
  13.276 -            otherwise
  13.277 -                |> status = multicast_self_msg(session, state, msg, encrypted);
  13.278 -        }
  13.279 -        ||
  13.280 -            if (status != PEP_STATUS_OK)
  13.281 -                goto error;
  13.282 -
  13.283 -            `` if "$name='GroupKeys' or $name='GroupUpdate'" |> free_identity_list(kl);
  13.284 -            free_DeviceGroup_Protocol_msg(msg);
  13.285              return PEP_STATUS_OK;
  13.286 -
  13.287 -        enomem:
  13.288 -            status = PEP_OUT_OF_MEMORY;
  13.289 -        error:
  13.290 -            free_DeviceGroup_Protocol_msg(msg);
  13.291 -            `` if "$name='GroupKeys'" |> free_identity_list(kl);
  13.292 -            return status;
  13.293 -        }
  13.294 -
  13.295 -        ||
  13.296 -    }
  13.297 -
  13.298 -    function "UnCamelUp" {
  13.299 -        param "text";
  13.300 -        const "tokens", "str:tokenize($text, '')";
  13.301 -
  13.302 -        for "$tokens" {
  13.303 -            choose {
  13.304 -                when "contains('ABCDEFGHIJKLMNOPQRSTUVWXYZ',.)" > _«.»
  13.305 -                otherwise value "yml:ucase(.)";
  13.306 -            }
  13.307 -        }
  13.308 -    }
  13.309 -
  13.310 -    function "notify_action" {
  13.311 -        param "action";
  13.312 -        param "fsm";
  13.313 -        param "filename", "'###'";
  13.314 -        const "name", "substring($action/@name, 7, 255)";
  13.315 -        const "uname" call "UnCamelUp" with "text", "$name";
  13.316 -        ||
  13.317 -
  13.318 -        // «$action/@name»() - notify «$name» to app
  13.319 -        //
  13.320 -        //  params:
  13.321 -        //      session (in)        session handle
  13.322 -        //      state (in)          state the state machine is in
  13.323 -        //      partner (in)        partner to communicate with
  13.324 -        //
  13.325 -        //  returns:
  13.326 -        //      PEP_STATUS_OK or any other value on error
  13.327 -
  13.328 -        PEP_STATUS «$action/@name»(
  13.329 -                PEP_SESSION session,
  13.330 -                «$fsm»_state state,
  13.331 -                Identity partner,
  13.332 -                void *extra
  13.333 -            )
  13.334 -        {
  13.335 -            assert(session && state);
  13.336 -            assert(extra == NULL);
  13.337 -            if (!(session && state && extra == NULL))
  13.338 -                return PEP_ILLEGAL_VALUE;
  13.339 -
  13.340 -            return _notifyHandshake(session, partner, SYNC_NOTIFY«$uname»);
  13.341          }
  13.342  
  13.343          ||
    14.1 --- a/sync/gen_dot.ysl2	Tue Aug 07 14:24:15 2018 +0200
    14.2 +++ b/sync/gen_dot.ysl2	Tue Aug 07 17:16:03 2018 +0200
    14.3 @@ -4,7 +4,7 @@
    14.4  include yslt.yml2
    14.5  
    14.6  tstylesheet {
    14.7 -    template "protocol/fsm" document "{@filename}.dot", "text"
    14.8 +    template "protocol/fsm" document "{@name}.dot", "text"
    14.9      ||
   14.10      digraph finite_state_machine {
   14.11          rankdir=LR;
   14.12 @@ -21,10 +21,9 @@
   14.13  
   14.14      template "event" {
   14.15          param "state";
   14.16 -        const "transitions", "transition|descendant::condition/transition|descendant::alternative/transition";
   14.17          choose {
   14.18 -            when "count($transitions) > 0"
   14.19 -                apply "$transitions", 0
   14.20 +            when "count(transition) > 0"
   14.21 +                apply "transition|condition/transition", 0
   14.22                      with "state", "$state", with "event", "@name";
   14.23              otherwise
   14.24                  if "@name != 'Init'"
    15.1 --- a/sync/gen_statemachine.ysl2	Tue Aug 07 14:24:15 2018 +0200
    15.2 +++ b/sync/gen_statemachine.ysl2	Tue Aug 07 17:16:03 2018 +0200
    15.3 @@ -3,7 +3,7 @@
    15.4  
    15.5  // generate state machine code
    15.6  
    15.7 -// Copyleft (c) 2016, p≡p foundation
    15.8 +// Copyleft (c) 2016, 2017, p≡p foundation
    15.9  
   15.10  // Written by Volker Birk
   15.11  
   15.12 @@ -14,122 +14,334 @@
   15.13      include ./functions.ysl2
   15.14  
   15.15      template "/protocol" {
   15.16 -        document "generated/Makefile.protocols", "text"
   15.17 -            apply "fsm", 0, mode="make";
   15.18 -        apply "fsm", 0, mode=gen;
   15.19 -    }
   15.20 +        document "generated/{@name}_impl.h", "text" {
   15.21 +        ||
   15.22 +        // This file is under GNU General Public License 3.0
   15.23 +        // see LICENSE.txt
   15.24  
   15.25 -    template "fsm", mode=make
   15.26 -    ||
   15.27 -    «@filename»_fsm.c: ../sync/devicegroup.fsm
   15.28 -    \tmake -C ../«@filename»
   15.29 -    ||
   15.30 -
   15.31 -    template "fsm", mode=gen {
   15.32 -        document "generated/{@filename}_fsm.h", "text" {
   15.33 -        ||
   15.34          #pragma once
   15.35  
   15.36 -        // state machine for «@name»
   15.37 -
   15.38 +        #include "fsm_common.h"
   15.39          #include "message_api.h"
   15.40 +        #include "../asn.1/Sync.h"
   15.41          
   15.42          #ifdef __cplusplus
   15.43          extern "C" {
   15.44          #endif
   15.45  
   15.46 -        // types
   15.47 +        // event struct
   15.48  
   15.49 -        typedef pEp_identity * Identity;
   15.50 -        typedef stringlist_t * Stringlist;
   15.51 -
   15.52 -        // error values
   15.53 -
   15.54 -        typedef enum _fsm_error {
   15.55 -            // these error values are corresponding to
   15.56 -            // PEP_SYNC_STATEMACHINE_ERROR - value
   15.57 -            invalid_state = -2,
   15.58 -            invalid_event = -3,
   15.59 -            invalid_condition = -4,
   15.60 -            invalid_action = -5,
   15.61 -
   15.62 -            // out of memory condition
   15.63 -            invalid_out_of_memory = -128
   15.64 -        } fsm_error;
   15.65 +        typedef struct _«@name»_event {
   15.66 +            «@name»_PR fsm;
   15.67 +            int event;
   15.68 +            «@name»_t *msg;
   15.69 +        } «@name»_event_t;
   15.70  
   15.71          // conditions
   15.72  
   15.73 -        `` for "func:distinctName(condition)" | int «@name»(PEP_SESSION session`apply "parm", 0`);
   15.74 +        ||
   15.75 +        for "func:distinctName(*//condition)"
   15.76 +            | PEP_STATUS «@name»(PEP_SESSION session, bool *result);
   15.77 +        ||
   15.78 +        // actions
   15.79 +
   15.80 +        ||
   15.81 +        const "name", "@name";
   15.82 +        for "func:distinctName(*//action[not(starts-with(@name, 'send'))])"
   15.83 +            | PEP_STATUS «@name»(PEP_SESSION session);
   15.84 +        ||
   15.85 +
   15.86 +        // send event to own state machine, use state to generate
   15.87 +        // «@name» message if necessary
   15.88 +
   15.89 +        PEP_STATUS «@name»_send(
   15.90 +                PEP_SESSION session, 
   15.91 +                «@name»_PR fsm,
   15.92 +                int message_type
   15.93 +            );
   15.94 +
   15.95 +        // send message to partners
   15.96 +
   15.97 +        PEP_STATUS send_«@name»_message(
   15.98 +                PEP_SESSION session, 
   15.99 +                «@name»_PR fsm,
  15.100 +                int event
  15.101 +            );
  15.102 +
  15.103 +        // receive event, free «@name»_event_t structure if call does not fail
  15.104 +        // with PEP_ILLEGAL_VALUE
  15.105 +
  15.106 +        PEP_STATUS recv_«@name»_event(
  15.107 +                PEP_SESSION session, 
  15.108 +                «@name»_event_t *ev
  15.109 +            );
  15.110 +    
  15.111 +        // state machine driver
  15.112 +        // if fsm or event set to 0 use fields in src if present
  15.113 +
  15.114 +        PEP_STATUS «@name»_driver(
  15.115 +                PEP_SESSION session,
  15.116 +                «@name»_PR fsm,
  15.117 +                int event
  15.118 +            );
  15.119 +
  15.120 +        PEP_STATUS inject_«@name»_event(
  15.121 +                PEP_SESSION session, 
  15.122 +                «@name»_PR fsm,
  15.123 +                int event
  15.124 +            );
  15.125 +
  15.126 +
  15.127 +        #ifdef __cplusplus
  15.128 +        }
  15.129 +        #endif
  15.130 +
  15.131 +        ||
  15.132 +        }
  15.133 +
  15.134 +        document "generated/{@name}_impl.c", "text"
  15.135 +        ||
  15.136 +        // This file is under GNU General Public License 3.0
  15.137 +        // see LICENSE.txt
  15.138 +    
  15.139 +        #include "«@name»_impl.h"
  15.140 +        #include "pEp_internal.h"
  15.141 +        `` for "fsm" | #include "«@name»_fsm.h"
  15.142 +
  15.143 +        PEP_STATUS «@name»_driver(
  15.144 +                PEP_SESSION session,
  15.145 +                «@name»_PR fsm,
  15.146 +                int event
  15.147 +            )
  15.148 +        {
  15.149 +            assert(session && fsm);
  15.150 +            if (!(session && fsm))
  15.151 +                return PEP_ILLEGAL_VALUE;
  15.152 +
  15.153 +            switch (fsm) {
  15.154 +                `` apply "fsm", 2, mode=driver               
  15.155 +                default:
  15.156 +                    return PEP_ILLEGAL_VALUE;
  15.157 +            }
  15.158 +
  15.159 +            return PEP_STATUS_OK;
  15.160 +        }
  15.161 +
  15.162 +        PEP_STATUS inject_«@name»_event(
  15.163 +                PEP_SESSION session, 
  15.164 +                «@name»_PR fsm,
  15.165 +                int event
  15.166 +            )
  15.167 +        {
  15.168 +            «@name»_t *msg = NULL;
  15.169 +            «@name»_event_t *ev = NULL;
  15.170 +
  15.171 +            assert(session && fsm > 0 && event > None);
  15.172 +            if (!(session && fsm > 0 && event > None))
  15.173 +                return PEP_ILLEGAL_VALUE;
  15.174 +
  15.175 +            PEP_STATUS status = PEP_STATUS_OK;
  15.176 +
  15.177 +            if (!session->inject_«yml:lcase(@name)»_msg) {
  15.178 +               status = PEP_«yml:ucase(@name)»_NO_INJECT_CALLBACK;
  15.179 +               goto error;
  15.180 +            }
  15.181 +
  15.182 +            if (event < Extra) {
  15.183 +                msg = new_«@name»_message(fsm, event);
  15.184 +                assert(msg);
  15.185 +                if (!msg) {
  15.186 +                    status = PEP_OUT_OF_MEMORY;
  15.187 +                    goto error;
  15.188 +                }
  15.189 +
  15.190 +                status = update_«@name»_message(session, fsm, event, msg);
  15.191 +                if (status)
  15.192 +                    goto error;
  15.193 +            }
  15.194 +
  15.195 +            ev = («@name»_event_t *) calloc(1, sizeof(«@name»_event_t));
  15.196 +            assert(ev);
  15.197 +            if (!ev) {
  15.198 +                status = PEP_OUT_OF_MEMORY;
  15.199 +                goto error;
  15.200 +            }
  15.201 +            
  15.202 +            ev->fsm = fsm;
  15.203 +            ev->event = event;
  15.204 +            ev->msg = msg;
  15.205 +
  15.206 +            int result = session->inject_«yml:lcase(@name)»_msg(ev,
  15.207 +                    session->«yml:lcase(@name)»_management);
  15.208 +            if (result) {
  15.209 +                status = PEP_STATEMACHINE_ERROR;
  15.210 +                goto error;
  15.211 +            }
  15.212 +
  15.213 +            goto the_end;
  15.214 +
  15.215 +        error:
  15.216 +            free(ev);
  15.217 +            free_«@name»_message(msg);
  15.218 +
  15.219 +        the_end:
  15.220 +            return status;
  15.221 +        }
  15.222 +
  15.223 +        PEP_STATUS «@name»_send(
  15.224 +                PEP_SESSION session, 
  15.225 +                «@name»_PR fsm,
  15.226 +                int message_type
  15.227 +            )
  15.228 +        {
  15.229 +            assert(session && fsm > 0 && message_type > 1 && message_type < Extra);
  15.230 +            if (!(session && fsm > 0 && message_type > 1 && message_type < Extra))
  15.231 +                return PEP_ILLEGAL_VALUE;
  15.232 +
  15.233 +            PEP_STATUS status = PEP_STATUS_OK;
  15.234 +
  15.235 +            «@name»_t *msg = new_«@name»_message(fsm, message_type);
  15.236 +            assert(msg);
  15.237 +            if (!msg) {
  15.238 +                status = PEP_OUT_OF_MEMORY;
  15.239 +                goto error;
  15.240 +            }
  15.241 +
  15.242 +            status = update_«@name»_message(session, fsm, message_type, msg);
  15.243 +            if (status)
  15.244 +                goto error;
  15.245 +
  15.246 +            goto the_end;
  15.247 +
  15.248 +        error:
  15.249 +            free_«@name»_message(msg);
  15.250 +
  15.251 +        the_end:
  15.252 +            return status;
  15.253 +        }
  15.254 +
  15.255 +        PEP_STATUS recv_«@name»_event(
  15.256 +                PEP_SESSION session, 
  15.257 +                «@name»_event_t *ev
  15.258 +            )
  15.259 +        {
  15.260 +            assert(session && ev);
  15.261 +            if (!(session && ev))
  15.262 +                return PEP_ILLEGAL_VALUE;
  15.263 +
  15.264 +            assert(ev->fsm >= None && ev->event >= None);
  15.265 +            if (!(ev->fsm >= None && ev->event >= None))
  15.266 +                return PEP_ILLEGAL_VALUE;
  15.267 +
  15.268 +            PEP_STATUS status = PEP_STATUS_OK;
  15.269 +
  15.270 +            if (ev->event < Extra) {
  15.271 +                «@name»_PR fsm = (int) None;
  15.272 +                int event = None;
  15.273 +
  15.274 +                status = update_«@name»_state(session, ev->msg, &fsm, &event);
  15.275 +                if (status)
  15.276 +                    goto error;
  15.277 +
  15.278 +                if (ev->fsm) {
  15.279 +                    if (ev->fsm != fsm |`> |` ev->event != event) {
  15.280 +                        status = PEP_SYNC_ILLEGAL_MESSAGE;
  15.281 +                        goto error;
  15.282 +                    }
  15.283 +                }
  15.284 +                else {
  15.285 +                    if (ev->event) {
  15.286 +                        status = PEP_SYNC_ILLEGAL_MESSAGE;
  15.287 +                        goto error;
  15.288 +                    }
  15.289 +                    ev->fsm = fsm;
  15.290 +                    ev->event = event;
  15.291 +                }
  15.292 +            }
  15.293 +
  15.294 +            free_«@name»_message(ev->msg);
  15.295 +            free(ev);
  15.296 +            status = «@name»_driver(session, ev->fsm, ev->event);
  15.297 +            return status;
  15.298 +
  15.299 +        error:
  15.300 +            free_«@name»_message(ev->msg);
  15.301 +            free(ev);
  15.302 +            return status;
  15.303 +        }
  15.304 +
  15.305 +        ||
  15.306 +
  15.307 +        apply "fsm", 0, mode=gen;
  15.308 +    }
  15.309 +
  15.310 +    template "fsm", mode=driver
  15.311 +    ||
  15.312 +    case Sync_PR_«yml:lcase(@name)»: {
  15.313 +        int state = session->sync_state.«yml:lcase(@name)».state;
  15.314 +        state = fsm_«@name»(session, state, event);
  15.315 +        if (state > 0)
  15.316 +            session->sync_state.«yml:lcase(@name)».state = state;
  15.317 +        else if (state < 0)
  15.318 +            return PEP_STATEMACHINE_ERROR - state;
  15.319 +        break;
  15.320 +    }
  15.321 +
  15.322 +    ||
  15.323 +
  15.324 +    template "fsm", mode=gen {
  15.325 +        document "generated/{@name}_fsm.h", "text" {
  15.326 +        ||
  15.327 +        // This file is under GNU General Public License 3.0
  15.328 +        // see LICENSE.txt
  15.329 +
  15.330 +        #pragma once
  15.331 +
  15.332 +        #include "«../@name»_impl.h"
  15.333 +
  15.334 +        #ifdef __cplusplus
  15.335 +        extern "C" {
  15.336 +        #endif
  15.337 +
  15.338 +        // state machine for «@name»
  15.339  
  15.340          // states
  15.341  
  15.342          typedef enum _«@name»_state {
  15.343 -            // error values also in this namespace
  15.344 -            «@name»_state_invalid_state = (int) invalid_state,
  15.345 -            «@name»_state_invalid_event = (int) invalid_event,
  15.346 -            «@name»_state_invalid_condition = (int) invalid_condition,
  15.347 -            «@name»_state_invalid_action = (int) invalid_action,
  15.348 -            «@name»_state_invalid_out_of_memory = (int) invalid_out_of_memory,
  15.349 -
  15.350 -            «@name»_state_NONE = 0,
  15.351 -        `` for "func:distinctName(state)" |> «@name»`if "position()!=last()" > , `
  15.352 +            «@name»_state_None = None,
  15.353 +            «@name»_state_Init = Init,
  15.354 +        ||
  15.355 +        for "func:distinctName(state[not(@name='InitState')])"
  15.356 +            |> «@name»`if "position()!=last()" > , `
  15.357 +        ||
  15.358          } «@name»_state;
  15.359  
  15.360          // events
  15.361  
  15.362          typedef enum _«@name»_event {
  15.363 -            «@name»_event_NONE = 0,
  15.364 +            «@name»_event_None = None,
  15.365 +            «@name»_event_Init = Init,
  15.366          ||
  15.367 -        for "func:distinctName(state/event[not(not(/protocol/fsm/tag/@name=@name))])" {
  15.368 +        for "func:distinctName(state/event[not(not(../../message/@name=@name))])" {
  15.369              const "name", "@name";
  15.370 -            |> «$name» = «/protocol/fsm/tag[@name=$name]/@id»,
  15.371 +            |> «$name» = «/protocol/fsm/message[@name=$name]/@id»,
  15.372          }
  15.373 -        for "func:distinctName(state/event[not(/protocol/fsm/tag/@name=@name)])"
  15.374 -            |> «@name»`if "position()!=last()" > , `
  15.375 +        |> «@name»_event_Extra = Extra,
  15.376 +        for "func:distinctName(state/event[not(../../message/@name=@name)])" {
  15.377 +            if "@name!='Init'"
  15.378 +                |> «@name»`if "position()!=last()" > , `
  15.379 +        }
  15.380          ||
  15.381          } «@name»_event;
  15.382  
  15.383 -        // actions
  15.384 +        // state machine
  15.385  
  15.386 -        `` const "name", "@name"
  15.387 -        `` for "func:distinctName(//action)" | PEP_STATUS «@name»(PEP_SESSION session, «$name»_state state, Identity partner, void *extra);
  15.388 -
  15.389 -        // event injector
  15.390 -
  15.391 -        PEP_STATUS inject_DeviceState_event(
  15.392 -            PEP_SESSION session, 
  15.393 -            DeviceState_event event,
  15.394 -            Identity partner,
  15.395 -            void *extra);
  15.396 -
  15.397 -        // message receiver
  15.398 -        
  15.399 -        PEP_STATUS receive_DeviceState_msg(
  15.400 -                PEP_SESSION session, 
  15.401 -                message *src, 
  15.402 -                PEP_rating rating, 
  15.403 -                stringlist_t *keylist
  15.404 -            );
  15.405 -
  15.406 -        // state machine
  15.407 +        const char *«@name»_state_name(int state);
  15.408  
  15.409          «@name»_state fsm_«@name»(
  15.410                  PEP_SESSION session,
  15.411                  «@name»_state state,
  15.412 -                «@name»_event event,
  15.413 -                Identity partner,
  15.414 -                void *extra,
  15.415 -                time_t *timeout
  15.416 -            );
  15.417 -
  15.418 -        // driver
  15.419 -
  15.420 -        DYNAMIC_API PEP_STATUS fsm_«@name»_inject(
  15.421 -                PEP_SESSION session,
  15.422 -                «@name»_event event,
  15.423 -                Identity partner,
  15.424 -                void *extra,
  15.425 -                time_t *timeout
  15.426 +                «@name»_event event
  15.427              );
  15.428  
  15.429          #ifdef __cplusplus
  15.430 @@ -138,278 +350,195 @@
  15.431  
  15.432          ||
  15.433          }
  15.434 -        document "generated/{@filename}_driver.c", "text"
  15.435 +
  15.436 +        document "generated/{@name}_fsm.c", "text" {
  15.437          ||
  15.438 -        // Driver for «@name» state machine
  15.439 +        // This file is under GNU General Public License 3.0
  15.440 +        // see LICENSE.txt
  15.441  
  15.442 -        #include <assert.h>
  15.443 -        #include "pEp_internal.h"
  15.444 +        #include "«@name»_fsm.h"
  15.445  
  15.446 +        const char *«@name»_state_name(int state)
  15.447 +        {
  15.448 +            switch (state) {
  15.449 +                case End:
  15.450 +                    return "End";
  15.451 +                case None:
  15.452 +                    return "None";
  15.453 +                case Init:
  15.454 +                    return "InitState";
  15.455 +        ||
  15.456 +        for "func:distinctName(state[not(@name='InitState')])" {
  15.457 +            |>> case «@name»:
  15.458 +            |>>> return "«@name»";
  15.459 +        }
  15.460 +        ||
  15.461 +                default:
  15.462 +                    return "unknown state";
  15.463 +            }
  15.464 +        }
  15.465  
  15.466 -        DYNAMIC_API PEP_STATUS fsm_«@name»_inject(
  15.467 +        static char *_str(int n, bool hex)
  15.468 +        {
  15.469 +            char *buf = calloc(1, 24);
  15.470 +            assert(buf);
  15.471 +            if (!buf)
  15.472 +                return NULL;
  15.473 +
  15.474 +            if (hex)
  15.475 +                snprintf(buf, 24, "%.4x", n);
  15.476 +            else
  15.477 +                snprintf(buf, 24, "%d", n);
  15.478 +            return buf;
  15.479 +        }
  15.480 +
  15.481 +        #define «@name»_ERR_LOG(t, d) log_event(session, (t), "«@name»", (d), "error")
  15.482 +
  15.483 +        static PEP_STATUS _«@name»_ERR_LOG_int(PEP_SESSION session, char *t, int n, bool hex)
  15.484 +        {
  15.485 +            char *_buf = _str(n, hex);
  15.486 +            if (!_buf)
  15.487 +                return PEP_OUT_OF_MEMORY;
  15.488 +            PEP_STATUS status = «@name»_ERR_LOG(t, _buf);
  15.489 +            free(_buf);
  15.490 +            return status;
  15.491 +        }
  15.492 +
  15.493 +        #define «@name»_ERR_LOG_INT(t, n) _«@name»_ERR_LOG_int(session, (t), (n), false)
  15.494 +        #define «@name»_ERR_LOG_HEX(t, n) _«@name»_ERR_LOG_int(session, (t), (n), true)
  15.495 +
  15.496 +        #ifndef SERVICE_LOG
  15.497 +        // SERVICE LOG is meant to check session->service_log in runtime config;
  15.498 +        // for older engines log more than needed
  15.499 +        #define SERVICE_LOG(session, t, n, d) log_event((session), (t), (n), (d), "service")
  15.500 +        #endif 
  15.501 +
  15.502 +        #define «@name»_SERVICE_LOG(t, d) SERVICE_LOG(session, (t), "«@name»", (d))
  15.503 +
  15.504 +        «@name»_state fsm_«@name»(
  15.505                  PEP_SESSION session,
  15.506 -                «@name»_event event,
  15.507 -                Identity partner,
  15.508 -                void *extra,
  15.509 -                time_t *timeout
  15.510 +                «@name»_state state,
  15.511 +                «@name»_event event
  15.512              )
  15.513          {
  15.514              assert(session);
  15.515              if (!session)
  15.516 -                return PEP_ILLEGAL_VALUE;
  15.517 -
  15.518 -            while(true)
  15.519 -            {
  15.520 -                «@name»_state new_state = fsm_«@name»(session,
  15.521 -                    session->«@filename»_state, event, partner, extra, timeout);
  15.522 -
  15.523 -                if (new_state == «@name»_state_invalid_out_of_memory)
  15.524 -                    return PEP_OUT_OF_MEMORY;
  15.525 -
  15.526 -                if (new_state < 0)
  15.527 -                    return PEP_SYNC_STATEMACHINE_ERROR - new_state;
  15.528 -                
  15.529 -                if (new_state == session->«@filename»_state)
  15.530 -                    break;
  15.531 -
  15.532 -                event = Init;
  15.533 -                extra = NULL;
  15.534 -                session->«@filename»_state = new_state;
  15.535 -            } 
  15.536 -
  15.537 -            return PEP_STATUS_OK;
  15.538 -        }
  15.539 -
  15.540 -        ||
  15.541 -        document "generated/{@filename}_fsm.c", "text"
  15.542 -        ||
  15.543 -        #include "pEp_internal.h"
  15.544 -        #include "«@filename»_fsm.h"
  15.545 -        #include "«@filename»_impl.h"
  15.546 -
  15.547 -        // local definitions for «@name»'s state machine 
  15.548 -
  15.549 -        `` apply "state", 0 mode="declStatePayload"
  15.550 -
  15.551 -        // state machine for «@name»
  15.552 -
  15.553 -        «@name»_state fsm_«@name»(
  15.554 -                PEP_SESSION session,
  15.555 -                «@name»_state state,
  15.556 -                «@name»_event event,
  15.557 -                Identity partner,
  15.558 -                void *extra,
  15.559 -                time_t *timeout
  15.560 -            )
  15.561 -        {
  15.562 -            PEP_STATUS status = PEP_STATUS_OK;
  15.563 +                return invalid_state;
  15.564  
  15.565              switch (state) {
  15.566 -            `` apply "state", 2
  15.567 +                case None:
  15.568 +                    «@name»_SERVICE_LOG("transition to state Init", "None is not a valid state");
  15.569 +                    return Init;
  15.570 +                
  15.571 +                `` apply "state", 2, mode=fsm
  15.572                  default:
  15.573 -                    return («@name»_state) invalid_state;
  15.574 +                    «@name»_ERR_LOG_INT("«@name»_fsm() called with invalid state", state);
  15.575 +                    return invalid_state;
  15.576              }
  15.577 -
  15.578 +            
  15.579              return state;
  15.580          }
  15.581  
  15.582          ||
  15.583 +        }
  15.584 +    }
  15.585 +    
  15.586 +    template "state", mode=fsm {
  15.587 +        choose {
  15.588 +            when "@name='InitState'" | case «../@name»_state_Init:
  15.589 +            otherwise | case «@name»:
  15.590 +        }
  15.591 +        ||
  15.592 +            «../@name»_SERVICE_LOG("in state", "«@name»");
  15.593 +
  15.594 +            switch (event) {
  15.595 +                case None:
  15.596 +                    «../@name»_SERVICE_LOG("received None event", "ignoring");
  15.597 +                    return state;
  15.598 +     
  15.599 +                `` apply "event", 2, mode=fsm
  15.600 +                default:
  15.601 +                    «../@name»_ERR_LOG_INT("«../@name»_fsm() called with invalid event", event);
  15.602 +                    return invalid_event;
  15.603 +            }
  15.604 +            break;
  15.605 +
  15.606 +        ||
  15.607      }
  15.608  
  15.609 -    template "state" {
  15.610 +    template "event", mode=fsm {
  15.611 +        | case «@name»: {
  15.612 +        if "condition|action" |> PEP_STATUS status;
  15.613 +        if "condition" |> bool result = false;
  15.614 +        if "condition|action" |
  15.615          ||
  15.616 -        case «@name»:
  15.617 -        {
  15.618 -            DEBUG_LOG("Entering FSM state", "«../@filename»_fsm.c", "state=«@name»")
  15.619 +            «../../@name»_SERVICE_LOG("received event", "«@name»");
  15.620 +            `` apply "transition|action|condition" with "protocol", "../../..", with "fsm", "../.."
  15.621 +        ||
  15.622 +        if "name(*[last()])!='transition'" {
  15.623 +            |
  15.624 +            |> KeySync_SERVICE_LOG("remaining in state", "«../@name»");
  15.625 +            |> break;
  15.626 +        }
  15.627 +        ||
  15.628 +        }
  15.629 +        
  15.630 +        ||
  15.631 +    }
  15.632 +
  15.633 +    template "transition" {
  15.634 +        param "fsm";
  15.635          ||
  15.636  
  15.637 -        if "count(parm) > 0" 
  15.638 -        || 
  15.639 -            assert(session->sync_state_payload);
  15.640 -            if(!session->sync_state_payload) return («../@name»_state) invalid_state;
  15.641 -            `` apply "parm", 1 mode="unpackStatePayloadParm" with "stateName", "@name"
  15.642 +        «$fsm/@name»_SERVICE_LOG("transition to state", "«@target»");
  15.643 +        state = «@target»;
  15.644 +        break;
  15.645          ||
  15.646 +    }
  15.647  
  15.648 +    template "action" {
  15.649 +        param "protocol";
  15.650 +        param "fsm";
  15.651 +        choose {
  15.652 +            when "starts-with(@name, 'send')" {
  15.653 +                const "name", "substring(@name, 5)";
  15.654 +                ||
  15.655 +
  15.656 +                «$fsm/@name»_SERVICE_LOG("send message", "«$name»");
  15.657 +                status = «$protocol/@name»_send(session, «$fsm/@id», «$name»);
  15.658 +                ||
  15.659 +            }
  15.660 +            otherwise
  15.661 +                ||
  15.662 +
  15.663 +                «$fsm/@name»_SERVICE_LOG("do action", "«@name»");
  15.664 +                status = «@name»(session);
  15.665 +                ||
  15.666 +        }
  15.667          ||
  15.668 -            switch (event) {
  15.669 -        ||
  15.670 -
  15.671 -        if "not(event[@name='Init'])" 
  15.672 -        ||
  15.673 -                case Init: 
  15.674 -                    DEBUG_LOG("FSM event", "«../@filename»_fsm.c, state=«@name»", "event=Init") 
  15.675 -                    *timeout = «@timeout»;
  15.676 -                    break;
  15.677 -        ||
  15.678 -
  15.679 -        apply "event", 2;
  15.680 -
  15.681 -        ||
  15.682 -                default:
  15.683 -                    return («../@name»_state) invalid_event;
  15.684 -            }
  15.685 -            break;
  15.686 +        if (status) {
  15.687 +            «$fsm/@name»_ERR_LOG_HEX("executing action «@name»() failed", status);
  15.688 +            return invalid_action;
  15.689          }
  15.690          ||
  15.691      }
  15.692  
  15.693 -    function "pEp_type" {
  15.694 -        param "type";
  15.695 -
  15.696 -        choose {
  15.697 -            when "$type = 'Identity'" > Identity
  15.698 -            when "$type = 'IdentityList'" > identity_list*
  15.699 -            when "$type = 'GroupKeys'" > group_keys_extra_t*
  15.700 -            otherwise value "$type";
  15.701 -        }
  15.702 -    }
  15.703 -
  15.704 -    function "pEp_type_op_radix" {
  15.705 -        param "type";
  15.706 -
  15.707 -        choose {
  15.708 -            when "$type = 'Identity'" > identity
  15.709 -            when "$type = 'IdentityList'" > identity_list
  15.710 -            when "$type = 'GroupKeys'" > group_keys_extra
  15.711 -            otherwise call "pEp_type" with "type", "$type";
  15.712 -        }
  15.713 -    }
  15.714 -
  15.715 -    template "parm" mode="unpackStatePayloadParm" 
  15.716 -    {
  15.717 -        param "stateName";
  15.718 -        const "pEpType" call "pEp_type" with "type","name(*[1])"; 
  15.719 -        | «$pEpType» «name(*[2])» = ((«$stateName»_state_payload_t*)session->sync_state_payload)->«name(*[2])»;
  15.720 -    }
  15.721 -
  15.722 -    template "state" mode="declStatePayload" if "count(parm) > 0"
  15.723 -    ||
  15.724 -    typedef struct _«@name»_state_payload {
  15.725 -        `` apply "parm", 1 mode="declStatePayloadParm"
  15.726 -    } «@name»_state_payload_t;
  15.727 -
  15.728 -    ||
  15.729 -
  15.730 -    template "parm" mode="declStatePayloadParm" {
  15.731 -        const "pEpType" call "pEp_type" with "type","name(*[1])"; 
  15.732 -        | «$pEpType» «name(*[2])»;
  15.733 -    }
  15.734 -
  15.735 -    template "event" {
  15.736 -        ||
  15.737 -        case «@name»:
  15.738 -        {
  15.739 -            DEBUG_LOG("FSM event", "«../../@filename»_fsm.c, state=«../@name»", "event=«@name»")
  15.740 -        `` if "@name='Init'" |> *timeout = «../@timeout»;
  15.741 +    template "condition" {
  15.742 +        param "protocol";
  15.743 +        param "fsm";
  15.744          ||
  15.745  
  15.746 -        if "count(parm) > 1" {
  15.747 -            // TODO get ride of void *extra, pass per-event struct incl all params.
  15.748 -            const "extrapEpType" call "pEp_type" with "type","name(parm[2]/*[1])"; 
  15.749 -            const "extraArgName","name(parm[2]/*[2])"; 
  15.750 -            |> «$extrapEpType» «$extraArgName» = («$extrapEpType»)extra;
  15.751 +        status = «@name»(session, &result);
  15.752 +        if (status) {
  15.753 +            «$fsm/@name»_ERR_LOG_HEX("computing condition «@name» failed", status);
  15.754 +            return invalid_condition;
  15.755          }
  15.756 -
  15.757 +        if (result) {
  15.758 +            KeySync_SERVICE_LOG("condition applies", "«@name»");
  15.759          ||
  15.760 -        `` apply "action|transition|condition";
  15.761 -        `` if "name(*[position()=last()]) != 'transition'" |> break;
  15.762 -        }
  15.763 -        ||
  15.764 -    }
  15.765 -
  15.766 -    template "action" {
  15.767 -        | DEBUG_LOG("FSM action", "«ancestor::fsm/@filename»_fsm.c, state=«ancestor::state/@name», event=«ancestor::event/@name»", "action=«@name»")
  15.768 -        indent(0);
  15.769 -        > status = «@name»(session, state, 
  15.770 -        choose {
  15.771 -            when "parm" > «name(parm/*)»
  15.772 -            otherwise > NULL
  15.773 -        }
  15.774 -        choose {
  15.775 -            when "count(parm) > 1" > , «name(parm[2]/*)»
  15.776 -            otherwise > , NULL
  15.777 -        }
  15.778 -        > );\n
  15.779 -        | if (status == PEP_OUT_OF_MEMORY)
  15.780 -        |> return (int) invalid_out_of_memory;
  15.781 -        | if (status != PEP_STATUS_OK)
  15.782 -        |> return (int) invalid_action;
  15.783 -    }
  15.784 -
  15.785 -    template "condition" {
  15.786 -        | {
  15.787 -        |> int cond_result = «@name»(session`apply "parm", 0`);
  15.788 -        |> #ifndef NDEBUG
  15.789 -        |> char resstr[11] = {0,};
  15.790 -        |> snprintf(resstr,10,"result=%d",cond_result);
  15.791 -        |> #endif
  15.792 -        |> DEBUG_LOG("FSM condition", "«ancestor::fsm/@filename»_fsm.c, state=«ancestor::state/@name», event=«ancestor::event/@name», condition=«@name»", resstr)
  15.793 -        |> if (cond_result < 0)
  15.794 -        |>> return cond_result;
  15.795 -        |> if (cond_result) {
  15.796 -        apply "action|transition|condition";
  15.797 -        |> }
  15.798 -        const "alternative", "./following-sibling::*[position()=1][name(.)='alternative']";
  15.799 -        if "$alternative" {
  15.800 -        |> else {
  15.801 -        apply "$alternative/action|$alternative/transition|$alternative/condition";
  15.802 -        |> }
  15.803 -        }
  15.804 +            apply "transition|action|condition"
  15.805 +                with "protocol", "$protocol", with "fsm", "$fsm";
  15.806          | }
  15.807      }
  15.808 -
  15.809 -    template "parm" choose {
  15.810 -        when "count(*) = 1"
  15.811 -            > , «name(*)»
  15.812 -        otherwise
  15.813 -            > , «name(*[1])» «name(*[2])»
  15.814 -    }
  15.815 -
  15.816 -    template "transition"{
  15.817 -        const "stateparm", "ancestor::state/child::parm";
  15.818 -        if "count($stateparm) > 0" {
  15.819 -            ||
  15.820 -            assert(session->sync_state_payload);
  15.821 -            if(!session->sync_state_payload) return («ancestor::fsm/@name»_state) invalid_state;
  15.822 -            `` apply "$stateparm", 0 mode="freeStatePayloadParm" with "stateName", "ancestor::state/@name"
  15.823 -            free(session->sync_state_payload);
  15.824 -            session->sync_state_payload = NULL;
  15.825 -            ||
  15.826 -        }
  15.827 -        if "count(parm) > 0" {
  15.828 -            const "nextstatename", "@target";
  15.829 -            const "nextstateparm", "ancestor::fsm/child::state[@name = $nextstatename]/child::parm";
  15.830 -            if "count(parm) != count($nextstateparm)" 
  15.831 -                error > different state parameters and transition parameters count state=«ancestor::state/@name», event=«ancestor::event/@name» target=«@target»
  15.832 -            ||
  15.833 -            session->sync_state_payload = malloc(sizeof(«$nextstatename»_state_payload_t));
  15.834 -            assert(session->sync_state_payload);
  15.835 -            if(!session->sync_state_payload) return («ancestor::fsm/@name»_state) invalid_out_of_memory;
  15.836 -            ||
  15.837 -            apply "$nextstateparm", 0 mode="dupStatePayloadParm" {
  15.838 -                with "stateName", "$nextstatename";
  15.839 -                with "transitionParms", "parm";
  15.840 -            }
  15.841 -        }
  15.842 -        | DEBUG_LOG("FSM transition", "«ancestor::fsm/@filename»_fsm.c, state=«ancestor::state/@name», event=«ancestor::event/@name»", "target=«@target»")
  15.843 -        | return «@target»;
  15.844 -    }
  15.845 -
  15.846 -    template "parm" mode="freeStatePayloadParm" 
  15.847 -    {
  15.848 -        param "stateName";
  15.849 -        const "pEpTypeOpRadix" call "pEp_type_op_radix" with "type","name(*[1])"; 
  15.850 -        | free_«$pEpTypeOpRadix»(((«$stateName»_state_payload_t*)session->sync_state_payload)->«name(*[2])»);
  15.851 -    }
  15.852 -
  15.853 -    template "parm" mode="dupStatePayloadParm" 
  15.854 -    {
  15.855 -        param "stateName";
  15.856 -        param "transitionParms";
  15.857 -        const "pEpTypeOpRadix" call "pEp_type_op_radix" with "type","name(*[1])"; 
  15.858 -        const "pos", "position()";
  15.859 -        | ((«$stateName»_state_payload_t*)session->sync_state_payload)->«name(*[2])» =
  15.860 -        |     «$pEpTypeOpRadix»_dup(«name($transitionParms[$pos]/*)»);
  15.861 -    }
  15.862  }
  15.863