sync/gen_statemachine.ysl2
author buff <andreas@pep-project.org>
Fri, 23 Oct 2020 11:08:11 +0200
branchRelease_2.1
changeset 5139 2d551164adeb
parent 5034 ad76ee3dce6b
child 5169 f4b476b218e4
permissions -rw-r--r--
Xcode: drops iOS <12 support
krista@2271
     1
// This file is under GNU General Public License 3.0
krista@2271
     2
// see LICENSE.txt
krista@2271
     3
krista@2271
     4
// generate state machine code
krista@2271
     5
vb@4340
     6
// Copyleft (c) 2016-2020, p≡p foundation
krista@2271
     7
krista@2271
     8
// Written by Volker Birk
krista@2271
     9
krista@2271
    10
include yslt.yml2
krista@2271
    11
krista@2271
    12
tstylesheet {
krista@2271
    13
    include standardlib.ysl2
krista@2271
    14
    include ./functions.ysl2
krista@2271
    15
krista@2271
    16
    template "/protocol" {
vb@2838
    17
        document "generated/{@name}_event.h", "text"
vb@2838
    18
        ||
vb@2838
    19
        // This file is under GNU General Public License 3.0
vb@2838
    20
        // see LICENSE.txt
vb@2838
    21
vb@2838
    22
        #pragma once
vb@2838
    23
vb@3534
    24
        #include "pEpEngine.h"
vb@2838
    25
vb@2838
    26
        #ifdef __cplusplus
vb@2838
    27
        extern "C" {
vb@2838
    28
        #endif
vb@2838
    29
vb@3020
    30
        typedef struct «@name» «yml:ucase(@name)»;
vb@3020
    31
        typedef int «yml:ucase(@name)»_PR;
vb@2838
    32
vb@2847
    33
        typedef struct «@name»_event {
vb@3534
    34
            // state machine data
vb@3020
    35
            «yml:ucase(@name)»_PR fsm;
vb@2838
    36
            int event;
vb@3020
    37
            «yml:ucase(@name)» *msg;
vb@3534
    38
vb@3534
    39
            // transport data
vb@3534
    40
            pEp_identity *from;
vb@3779
    41
            char *sender_fpr;
vb@3540
    42
vb@3540
    43
            identity_list *own_identities;
vb@2838
    44
        } «@name»_event_t;
vb@2838
    45
vb@2838
    46
 
vb@2838
    47
        // new_«@name»_event() - allocate a new «@name»_event
vb@2838
    48
        //
vb@2838
    49
        //  parameters:
vb@2838
    50
        //      fsm (in)        finite state machine the event is for
vb@2838
    51
        //      event (in)      event or None
vb@2838
    52
        //      msg (in)        message to compute event from
vb@2838
    53
        //
vb@2838
    54
        //  return value:
vb@2838
    55
        //      pointer to new event or NULL in case of failure
vb@2838
    56
        //
vb@2838
    57
        //  caveat:
vb@2838
    58
        //      event must be valid for fsm or None
vb@2838
    59
        //      in case msg is given event will be calculated out of message
vb@2838
    60
vb@4183
    61
        DYNAMIC_API «@name»_event_t *new_«@name»_event(«yml:ucase(@name)»_PR fsm, int event, «yml:ucase(@name)» *msg);
vb@2838
    62
vb@2910
    63
        #define «yml:ucase(@name)»_TIMEOUT_EVENT new_«@name»_event(«@name»_PR_NOTHING, 0, NULL);
vb@2910
    64
vb@3338
    65
    
vb@2838
    66
        // free_«@name»_event() - free memory occupied by event
vb@2838
    67
        //
vb@2838
    68
        //  parameters:
vb@2838
    69
        //      ev (in)         event to free
vb@2838
    70
vb@4183
    71
        DYNAMIC_API void free_«@name»_event(«@name»_event_t *ev);
vb@2838
    72
vb@2838
    73
vb@2838
    74
        #ifdef __cplusplus
vb@2838
    75
        }
vb@2838
    76
        #endif
vb@2838
    77
vb@2838
    78
        ||
vb@2838
    79
vb@2838
    80
        document "generated/{@name}_event.c", "text"
vb@2838
    81
        ||
vb@2838
    82
        // This file is under GNU General Public License 3.0
vb@2838
    83
        // see LICENSE.txt
vb@2838
    84
vb@3062
    85
        #include "platform.h"
vb@3062
    86
vb@2838
    87
        #include "pEp_internal.h"
vb@2838
    88
        #include "«@name»_event.h"
vb@2838
    89
        #include "«@name»_func.h"
vb@2839
    90
        `` for "fsm" | #include "«@name»_fsm.h"
vb@2838
    91
vb@4183
    92
        DYNAMIC_API «@name»_event_t *new_«@name»_event(«yml:ucase(@name)»_PR fsm, int event, «@name»_t *msg)
vb@2838
    93
        {
vb@2838
    94
            «@name»_event_t *ev = («@name»_event_t *) calloc(1, sizeof(«@name»_event_t));
vb@2838
    95
            assert(ev);
vb@2838
    96
            if (!ev)
vb@2838
    97
                return NULL;
vb@2838
    98
vb@2838
    99
            ev->fsm = fsm;
vb@2838
   100
            ev->event = event;
vb@2838
   101
            ev->msg = msg;
vb@2838
   102
vb@2838
   103
            if (msg) {
vb@2838
   104
                switch (fsm) {
vb@2838
   105
                    `` apply "fsm", 3, mode=event
vb@2838
   106
                    default:
vb@2838
   107
                        // unknown protocol
vb@2838
   108
                        free(ev);
vb@2838
   109
                        return NULL;
vb@2838
   110
                }
vb@2838
   111
            }
vb@2838
   112
vb@2838
   113
            return ev;
vb@2838
   114
        }
vb@2838
   115
vb@4183
   116
        DYNAMIC_API void free_«@name»_event(«@name»_event_t *ev)
vb@2838
   117
        {
vb@2838
   118
            if (ev) {
vb@3540
   119
                free_identity_list(ev->own_identities);
vb@2838
   120
                free_«@name»_message(ev->msg);
vb@3534
   121
                free_identity(ev->from);
vb@3779
   122
                free(ev->sender_fpr);
vb@2838
   123
                free(ev);
vb@2838
   124
            }
vb@2838
   125
        }
vb@2838
   126
vb@2838
   127
        ||
vb@2838
   128
vb@2829
   129
        document "generated/{@name}_impl.h", "text" {
vb@2870
   130
            ||
vb@2870
   131
            // This file is under GNU General Public License 3.0
vb@2870
   132
            // see LICENSE.txt
krista@2271
   133
vb@2870
   134
            #pragma once
krista@2271
   135
vb@2870
   136
            #include "fsm_common.h"
vb@2889
   137
            #include "«@name»_event.h"
vb@2870
   138
            #include "message_api.h"
vb@3020
   139
            #include "../asn.1/«@name».h"
vb@2870
   140
            
vb@2909
   141
            #define «yml:ucase(@name)»_THRESHOLD «@threshold»
vb@2909
   142
            `` for "fsm" | #define «yml:ucase(@name)»_THRESHOLD «@threshold»
vb@2909
   143
vb@2870
   144
            #ifdef __cplusplus
vb@2870
   145
            extern "C" {
vb@2870
   146
            #endif
vb@2870
   147
vb@2870
   148
            // conditions
vb@2870
   149
vb@2870
   150
            ||
vb@2870
   151
            for "func:distinctName(*//condition)"
vb@2870
   152
                | PEP_STATUS «@name»(PEP_SESSION session, bool *result);
vb@2870
   153
            ||
vb@2870
   154
vb@2870
   155
            // actions
vb@2870
   156
vb@2870
   157
            ||
vb@2870
   158
            for "func:distinctName(*//action)"
vb@2870
   159
                | PEP_STATUS «@name»(PEP_SESSION session);
vb@2870
   160
            ||
vb@2870
   161
vb@2914
   162
            // timeout handler
vb@2914
   163
            
vb@2914
   164
            ||
vb@2914
   165
            for "fsm[@threshold > 0]"
vb@2914
   166
                | PEP_STATUS «@name»TimeoutHandler(PEP_SESSION session);
vb@2914
   167
            ||
vb@2914
   168
vb@2870
   169
            // send message about an event to communication partners using state
vb@2870
   170
vb@2870
   171
            PEP_STATUS send_«@name»_message(
vb@2870
   172
                    PEP_SESSION session, 
vb@2870
   173
                    «@name»_PR fsm,
vb@2870
   174
                    int message_type
vb@2870
   175
                );
vb@2870
   176
vb@2870
   177
            // receive message and store it in state
vb@2870
   178
vb@2870
   179
            PEP_STATUS recv_«@name»_event(
vb@2870
   180
                    PEP_SESSION session,
vb@2870
   181
                    «@name»_event_t *ev
vb@2870
   182
                );
krista@2271
   183
        
vb@2870
   184
            // state machine driver
vb@2870
   185
            // if fsm or event set to 0 use fields in src if present
krista@2271
   186
vb@2870
   187
            PEP_STATUS «@name»_driver(
vb@2870
   188
                    PEP_SESSION session,
vb@2870
   189
                    «@name»_PR fsm,
vb@2870
   190
                    int event
vb@2870
   191
                );
krista@2271
   192
vb@2888
   193
            // API being used by the engine internally
vb@2888
   194
vb@2888
   195
            // call this if you need to signal an external event
vb@3540
   196
            // caveat: the ownership of own_identities goes to the callee
vb@2888
   197
vb@2880
   198
            PEP_STATUS signal_«@name»_event(
vb@2870
   199
                    PEP_SESSION session, 
vb@2870
   200
                    «@name»_PR fsm,
vb@3540
   201
                    int event,
vb@3540
   202
                    identity_list *own_identities
vb@2870
   203
                );
vb@2888
   204
            
vb@2889
   205
            // call this if you are a transport and are receiving
vb@2889
   206
            // a «@name» message
vb@2834
   207
vb@2888
   208
            PEP_STATUS signal_«@name»_message(
vb@2888
   209
                    PEP_SESSION session, 
vb@2888
   210
                    PEP_rating rating,
vb@2888
   211
                    const char *data,
vb@3143
   212
                    size_t size,
vb@3363
   213
                    const pEp_identity *from,
vb@3779
   214
                    const char *sender_fpr
vb@2888
   215
                );
vb@2829
   216
vb@2870
   217
            #ifdef __cplusplus
vb@2870
   218
            }
vb@2870
   219
            #endif
vb@2829
   220
vb@2870
   221
            ||
vb@2829
   222
        }
vb@2829
   223
vb@2870
   224
        document "generated/{@name}_impl.c", "text" {
vb@2870
   225
            ||
vb@2870
   226
            // This file is under GNU General Public License 3.0
vb@2870
   227
            // see LICENSE.txt
vb@2870
   228
        
vb@2870
   229
            #include "«@name»_impl.h"
vb@2870
   230
            #include "pEp_internal.h"
vb@2870
   231
            #include "«@name»_event.h"
vb@2899
   232
            #include "«yml:lcase(@name)»_codec.h"
vb@2870
   233
            #include "baseprotocol.h"
vb@4251
   234
            #include "security_checks.h"
vb@2870
   235
            `` for "fsm" | #include "«@name»_fsm.h"
vb@2829
   236
vb@2909
   237
            `` apply "fsm", 0, mode=timeout
vb@2870
   238
            PEP_STATUS «@name»_driver(
vb@2870
   239
                    PEP_SESSION session,
vb@2870
   240
                    «@name»_PR fsm,
vb@2870
   241
                    int event
vb@2870
   242
                )
vb@2870
   243
            {
vb@2910
   244
                assert(session);
vb@2910
   245
                if (!session)
vb@2870
   246
                    return PEP_ILLEGAL_VALUE;
vb@2829
   247
vb@2909
   248
                switch (fsm) {
vb@2910
   249
                    case None:
vb@2910
   250
                        if (!event) {
vb@2910
   251
                            // timeout occured
vb@2910
   252
                        `` for "fsm" |>>>> «../@name»_driver(session, «../@name»_PR_«yml:lcase(@name)», None);
vb@2910
   253
                            return PEP_STATUS_OK;
vb@2910
   254
                        }
vb@2910
   255
                        return PEP_ILLEGAL_VALUE;
vb@2910
   256
vb@2909
   257
                    `` apply "fsm", mode=reset_state_machine;
vb@2909
   258
                    default:
vb@2909
   259
                        return PEP_ILLEGAL_VALUE;
vb@2909
   260
                }
vb@2909
   261
vb@2870
   262
                int next_state = None;
vb@2870
   263
                do {
vb@2870
   264
                    switch (fsm) {
vb@2870
   265
                        `` apply "fsm", 3, mode=driver               
vb@2870
   266
                        default:
vb@2870
   267
                            return PEP_ILLEGAL_VALUE;
vb@2870
   268
                    }
vb@2870
   269
                }  while (next_state);
vb@2829
   270
vb@2870
   271
                return PEP_STATUS_OK;
vb@2829
   272
            }
vb@2829
   273
vb@2880
   274
            PEP_STATUS signal_«@name»_event(
vb@2870
   275
                    PEP_SESSION session, 
vb@2870
   276
                    «@name»_PR fsm,
vb@3540
   277
                    int event,
vb@3540
   278
                    identity_list *own_identities
vb@2870
   279
                )
vb@2870
   280
            {
vb@2870
   281
                «@name»_t *msg = NULL;
vb@2870
   282
                «@name»_event_t *ev = NULL;
vb@2870
   283
vb@2870
   284
                assert(session && fsm > 0 && event > None);
vb@2870
   285
                if (!(session && fsm > 0 && event > None))
vb@2870
   286
                    return PEP_ILLEGAL_VALUE;
vb@2870
   287
vb@2870
   288
                PEP_STATUS status = PEP_STATUS_OK;
vb@2870
   289
vb@2888
   290
                if (!session->inject_«yml:lcase(@name)»_event)
vb@2888
   291
                   return PEP_«yml:ucase(@name)»_NO_INJECT_CALLBACK;
vb@2870
   292
vb@2870
   293
                if (event < Extra) {
vb@4902
   294
                    // FIXME: there should be a mapping between event and message type
vb@4902
   295
                    //        with current implementation they've got an offset of 1
vb@4902
   296
                    msg = new_«@name»_message(fsm, event - 1);
vb@2870
   297
                    if (!msg) {
vb@2870
   298
                        status = PEP_OUT_OF_MEMORY;
vb@2888
   299
                        goto the_end;
vb@2870
   300
                    }
vb@2870
   301
vb@2870
   302
                    status = update_«@name»_message(session, msg);
vb@2870
   303
                    if (status)
vb@2888
   304
                        goto the_end;
vb@2870
   305
                }
vb@2870
   306
vb@2888
   307
                ev = new_«@name»_event(fsm, event, msg);
vb@2870
   308
                if (!ev) {
vb@2870
   309
                    status = PEP_OUT_OF_MEMORY;
vb@2888
   310
                    goto the_end;
vb@2870
   311
                }
vb@2870
   312
krista@4206
   313
                status = set_all_userids_to_own(session, own_identities);
krista@4206
   314
                if (status != PEP_STATUS_OK)
krista@4206
   315
                    goto the_end;
krista@4206
   316
                    
vb@3540
   317
                ev->own_identities = own_identities;
vb@3540
   318
vb@2870
   319
                int result = session->inject_«yml:lcase(@name)»_event(ev,
vb@2870
   320
                        session->«yml:lcase(@name)»_management);
vb@2870
   321
                if (result) {
vb@2870
   322
                    status = PEP_STATEMACHINE_ERROR;
vb@2888
   323
                    goto the_end;
vb@2870
   324
                }
vb@2888
   325
                return PEP_STATUS_OK;
vb@2870
   326
vb@2870
   327
            the_end:
krista@3331
   328
                free_«@name»_event(ev); // msg gets freed here
vb@2870
   329
                return status;
vb@2870
   330
            }
vb@2870
   331
vb@2888
   332
            PEP_STATUS signal_«@name»_message(
vb@2870
   333
                    PEP_SESSION session, 
vb@2888
   334
                    PEP_rating rating,
vb@2888
   335
                    const char *data,
vb@3143
   336
                    size_t size,
vb@3363
   337
                    const pEp_identity *from,
vb@3779
   338
                    const char *sender_fpr
vb@2870
   339
                )
vb@2870
   340
            {
vb@2888
   341
                assert(session && data && size);
vb@2888
   342
                if (!(session && data && size))
vb@2870
   343
                    return PEP_ILLEGAL_VALUE;
vb@2870
   344
vb@2888
   345
                if (!session->inject_«yml:lcase(@name)»_event)
vb@2888
   346
                   return PEP_«yml:ucase(@name)»_NO_INJECT_CALLBACK;
vb@2870
   347
vb@3341
   348
                PEP_STATUS status = PEP_STATUS_OK;
vb@2890
   349
                «@name»_event_t *ev = NULL;
vb@2890
   350
vb@3341
   351
                «@name»_t *msg = NULL;
vb@3341
   352
                status = decode_«@name»_message(data, size, &msg);
vb@3341
   353
                if (status)
vb@3341
   354
                    return status;
vb@3341
   355
vb@3341
   356
                «@name»_PR fsm = msg->present;
vb@3341
   357
                int event = 0;
vb@3593
   358
                bool is_own_key = false;
vb@3341
   359
vb@3341
   360
                switch (fsm) {
vb@3341
   361
                    `` apply "fsm", 2, mode=signal_message
vb@3341
   362
                    default:
vb@3341
   363
                        status = PEP_«yml:ucase(@name)»_ILLEGAL_MESSAGE;
vb@3341
   364
                        goto the_end;
vb@3341
   365
                }
vb@3341
   366
vb@3117
   367
                ev = new_«@name»_event(fsm, event, msg);
vb@2888
   368
                if (!ev) {
vb@2829
   369
                    status = PEP_OUT_OF_MEMORY;
vb@2888
   370
                    goto the_end;
vb@2829
   371
                }
vb@2829
   372
vb@3534
   373
                // add transport data
vb@3534
   374
vb@3534
   375
                if (from) {
vb@3534
   376
                    ev->from = identity_dup(from);
vb@3534
   377
                    if (!ev->from) {
vb@3534
   378
                        status = PEP_OUT_OF_MEMORY;
vb@3534
   379
                        goto the_end;
vb@3534
   380
                    }
vb@3534
   381
                }
vb@3534
   382
vb@3779
   383
                if (sender_fpr) {
vb@3779
   384
                    ev->sender_fpr = strdup(sender_fpr);
vb@3779
   385
                    assert(ev->sender_fpr);
vb@3779
   386
                    if (!ev->sender_fpr) {
vb@3534
   387
                        status = PEP_OUT_OF_MEMORY;
vb@3534
   388
                        goto the_end;
vb@3534
   389
                    }
vb@3534
   390
                }
vb@3534
   391
vb@2888
   392
                int result = session->inject_«yml:lcase(@name)»_event(ev,
vb@2888
   393
                        session->«yml:lcase(@name)»_management);
vb@2888
   394
                if (result) {
vb@2888
   395
                    status = PEP_STATEMACHINE_ERROR;
vb@2888
   396
                    goto the_end;
vb@2888
   397
                }
vb@3143
   398
vb@2888
   399
                return PEP_STATUS_OK;
vb@2870
   400
vb@2870
   401
            the_end:
krista@3331
   402
                free_«@name»_event(ev); // msg gets freed here
vb@2870
   403
                return status;
vb@2829
   404
            }
vb@2829
   405
vb@2870
   406
            PEP_STATUS send_«@name»_message(
vb@2870
   407
                    PEP_SESSION session, 
vb@2870
   408
                    «@name»_PR fsm,
vb@2870
   409
                    int message_type
vb@2870
   410
                )
vb@2870
   411
            {
vb@2870
   412
                PEP_STATUS status = PEP_STATUS_OK;
vb@2829
   413
vb@2870
   414
                assert(session && fsm > None && message_type > None);
vb@2870
   415
                if (!(session && fsm > None && message_type > None))
vb@2870
   416
                    return PEP_ILLEGAL_VALUE;
vb@4546
   417
            ||
vb@4546
   418
            if "fsm/message[@ratelimit>0]" {
vb@4546
   419
            ||
vb@4546
   420
vb@4548
   421
                // test if a message with a rate limit was just sent; in case drop
vb@4546
   422
                time_t now = time(NULL);
vb@4546
   423
                switch (fsm) {
vb@4546
   424
            ||
vb@4546
   425
            for "fsm[message/@ratelimit>0]" {
vb@4546
   426
            ||
vb@4546
   427
                    case Sync_PR_«yml:lcase(@name)»:
vb@4546
   428
                        switch (message_type) {
vb@4546
   429
            ||
vb@4546
   430
            for "message[@ratelimit>0]"
vb@4546
   431
            ||
vb@4546
   432
                            case «../@name»_PR_«yml:mixedCase(@name)»:
vb@4546
   433
                                if (now < session->«yml:lcase(../../@name)»_state.own.last_«../@name»_«@name» + «@ratelimit»)
vb@4546
   434
                                    return PEP_STATUS_OK;
vb@4546
   435
                                break;
vb@4546
   436
            ||
vb@4546
   437
            ||
vb@4546
   438
                            default:
vb@4546
   439
                                break;
vb@4546
   440
                        }
vb@4546
   441
                        break;
vb@4546
   442
            ||
vb@4546
   443
            }
vb@4546
   444
            ||
vb@4546
   445
                    default:
vb@4546
   446
                        break;
vb@4546
   447
                }
vb@4546
   448
            ||
vb@4546
   449
            }
vb@4546
   450
            ||
vb@4546
   451
vb@2870
   452
                «@name»_t *msg = new_«@name»_message(fsm, message_type);
vb@2870
   453
                if (!msg)
vb@2870
   454
                    return PEP_OUT_OF_MEMORY;
vb@2870
   455
vb@2870
   456
                char *data = NULL;
vb@2870
   457
                message *m = NULL;
vb@2870
   458
                identity_list *channels = NULL;
vb@3545
   459
                char *key_data = NULL;
vb@3545
   460
                size_t key_data_size = 0;
vb@3594
   461
                stringlist_t *extra = NULL;
vb@3594
   462
                bool transaction;
vb@2870
   463
vb@2870
   464
                status = update_«@name»_message(session, msg);
vb@2870
   465
                if (status)
vb@2870
   466
                    goto the_end;
vb@2870
   467
vb@2870
   468
                size_t size = 0;
vb@2870
   469
                status = encode_«@name»_message(msg, &data, &size);
vb@2870
   470
                if (status)
vb@2870
   471
                    goto the_end;
vb@2870
   472
vb@4405
   473
                // we never use this
vb@4405
   474
                if (session->«yml:lcase(@name)»_state.comm_partner.identity
vb@4407
   475
                        && session->«yml:lcase(@name)»_state.comm_partner.identity->fpr) {
vb@4407
   476
                    free(session->«yml:lcase(@name)»_state.comm_partner.identity->fpr);
vb@4407
   477
                    session->«yml:lcase(@name)»_state.comm_partner.identity->fpr = NULL;
vb@4405
   478
                }
vb@4405
   479
vb@4406
   480
                // if we have this we always use this
vb@4406
   481
                if (session->«yml:lcase(@name)»_state.comm_partner.sender_fpr) {
vb@4406
   482
                    free(session->«yml:lcase(@name)»_state.transport.sender_fpr);
vb@4406
   483
                    session->«yml:lcase(@name)»_state.transport.sender_fpr =
vb@4406
   484
                            strdup(session->«yml:lcase(@name)»_state.comm_partner.sender_fpr);
vb@4406
   485
                    assert(session->«yml:lcase(@name)»_state.transport.sender_fpr);
vb@4406
   486
                    if (!session->«yml:lcase(@name)»_state.transport.sender_fpr) {
vb@4406
   487
                        status = PEP_OUT_OF_MEMORY;
vb@4406
   488
                        goto the_end;
vb@4406
   489
                    }
vb@4406
   490
                }
vb@4406
   491
vb@2870
   492
                switch (message_type) {
vb@2871
   493
                    // these messages are being broadcasted
vb@3509
   494
                    `` for "fsm/message[@type='broadcast']" |>> case «../@name»_PR_«yml:mixedCase(@name)»:
vb@2871
   495
                        status = _own_identities_retrieve(session, &channels, PEP_idf_not_for_«yml:lcase(@name)»);
vb@2875
   496
                        if (status)
vb@2870
   497
                            goto the_end;
vb@2871
   498
vb@2871
   499
                        if (!(channels && channels->ident)) {
vb@3240
   500
                            // status = PEP_«yml:ucase(@name)»_NO_CHANNEL;
vb@3240
   501
                            // we don't check for having a channel, because if
vb@3240
   502
                            // this is initial setup before having an own
vb@3240
   503
                            // identity we're fine
vb@2871
   504
                            goto the_end;
vb@2871
   505
                        }
vb@2870
   506
                        break;
vb@2870
   507
vb@2877
   508
                    // these go anycast; previously used address is sticky (unicast)
vb@3509
   509
                    `` for "fsm/message[@type='anycast']" |>> case «../@name»_PR_«yml:mixedCase(@name)»:
vb@4404
   510
                        // if we have a comm_partner fixed send it there
vb@4404
   511
                        if (session->«yml:lcase(@name)»_state.comm_partner.identity) {
vb@4404
   512
                            pEp_identity *channel = identity_dup(session->«yml:lcase(@name)»_state.comm_partner.identity);
vb@4404
   513
                            if (!channel) {
vb@4404
   514
                                status = PEP_OUT_OF_MEMORY;
vb@4404
   515
                                goto the_end;
vb@4404
   516
                            }
vb@2870
   517
vb@4404
   518
                            channels = new_identity_list(channel);
vb@4404
   519
                            if (!channels) {
vb@4404
   520
                                status = PEP_OUT_OF_MEMORY;
vb@2870
   521
                                goto the_end;
vb@2870
   522
                            }
vb@2870
   523
                        }
vb@4404
   524
                        // if we can reply just do
vb@4404
   525
                        else if (session->«yml:lcase(@name)»_state.transport.from) {
vb@3779
   526
                            pEp_identity *channel = identity_dup(session->«yml:lcase(@name)»_state.transport.from);
vb@2870
   527
                            if (!channel) {
vb@2870
   528
                                status = PEP_OUT_OF_MEMORY;
vb@2870
   529
                                goto the_end;
vb@2870
   530
                            }
vb@2870
   531
vb@2870
   532
                            channels = new_identity_list(channel);
vb@2870
   533
                            if (!channels) {
vb@2870
   534
                                status = PEP_OUT_OF_MEMORY;
vb@2870
   535
                                goto the_end;
vb@2870
   536
                            }
vb@2870
   537
                        }
vb@4404
   538
                        // real anycast, send it to the first matching
vb@4404
   539
                        else {
vb@4404
   540
                            status = _own_identities_retrieve(session, &channels, PEP_idf_not_for_«yml:lcase(@name)»);
vb@4404
   541
                            if (status)
vb@4404
   542
                                goto the_end;
vb@4404
   543
                            if (!channels)
vb@4404
   544
                                goto the_end;
vb@4404
   545
vb@4404
   546
                            if (channels->next) {
vb@4404
   547
                                free_identity_list(channels->next);
vb@4404
   548
                                channels->next = NULL;
vb@4404
   549
                            }
vb@4404
   550
                        }
vb@3340
   551
                        break;
vb@2877
   552
vb@2877
   553
                    default:
vb@2877
   554
                        status = PEP_«yml:ucase(@name)»_ILLEGAL_MESSAGE;
vb@2877
   555
                        goto the_end;
vb@2870
   556
                }
vb@2870
   557
vb@2870
   558
                for (identity_list *li = channels; li && li->ident ; li = li->next) {
vb@2878
   559
                    message *_m = NULL;
vb@2944
   560
                    char *_data = NULL;
vb@2944
   561
                    
vb@2944
   562
                    _data = malloc(size);
vb@2944
   563
                    assert(_data);
vb@2944
   564
                    if (!_data) {
vb@2944
   565
                        status = PEP_OUT_OF_MEMORY;
vb@2944
   566
                        goto the_end;
vb@2944
   567
                    }
vb@2944
   568
                    memcpy(_data, data, size);
vb@2875
   569
vb@2878
   570
                    switch (message_type) {
vb@4403
   571
                    `` for "fsm/message[@security='unencrypted' and ../@name!='KeySync']" | #error unencrypted only allowed with KeySync
vb@4403
   572
                    `` for "fsm/message[@security='unencrypted' and ../@name='KeySync']" |>>> case «../@name»_PR_«yml:mixedCase(@name)»:
vb@4777
   573
                            status = try_base_prepare_message(
vb@3143
   574
                                    session,
vb@3129
   575
                                    li->ident,
vb@3129
   576
                                    li->ident,
vb@4280
   577
                                    BASE_SYNC,
vb@3129
   578
                                    _data,
vb@3129
   579
                                    size,
vb@3129
   580
                                    li->ident->fpr,
vb@3129
   581
                                    &_m
vb@3129
   582
                                );
vb@3129
   583
                            if (status) {
vb@3129
   584
                                free(_data);
vb@3129
   585
                                goto the_end;
vb@3129
   586
                            }
Thomas@3127
   587
                            attach_own_key(session, _m);
vb@5003
   588
                            decorate_message(session, _m, PEP_rating_undefined, NULL, true, true);
vb@2878
   589
                            m = _m;
vb@2878
   590
                            break;
vb@2878
   591
vb@4403
   592
                    `` for "fsm/message[@security='untrusted' and ../@name!='KeySync']" | #error untrusted only allowed with KeySync
vb@4403
   593
                    `` for "fsm/message[@security='untrusted' and ../@name='KeySync']" |>>> case «../@name»_PR_«yml:mixedCase(@name)»:
vb@3594
   594
                            // add fpr of key of comm partner
vb@3594
   595
vb@4403
   596
                            assert(session->«yml:lcase(@name)»_state.transport.sender_fpr);
vb@4403
   597
                            if (!session->«yml:lcase(@name)»_state.transport.sender_fpr) {
vb@3519
   598
                                status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
vb@3519
   599
                                goto the_end;
vb@3519
   600
                            }
vb@3594
   601
vb@4403
   602
                            extra = new_stringlist(session->«yml:lcase(@name)»_state.transport.sender_fpr);
vb@3594
   603
                            if (!extra) {
vb@3594
   604
                                status = PEP_OUT_OF_MEMORY;
vb@3594
   605
                                goto the_end;
vb@3594
   606
                            }
vb@3594
   607
vb@3594
   608
                            status = base_prepare_message(
vb@3594
   609
                                    session,
vb@3594
   610
                                    li->ident,
vb@3594
   611
                                    li->ident,
vb@4280
   612
                                    BASE_SYNC,
vb@3594
   613
                                    _data,
vb@3594
   614
                                    size,
vb@3594
   615
                                    NULL,
vb@3594
   616
                                    &_m
vb@3594
   617
                                );
vb@3594
   618
                            if (status) {
vb@3594
   619
                                free(_data);
vb@3594
   620
                                goto the_end;
vb@3594
   621
                            }
vb@3594
   622
vb@4775
   623
                            status = try_encrypt_message(session, _m, extra, &m, PEP_enc_PEP, 0);
vb@3594
   624
                            if (status) {
vb@3594
   625
                                status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
vb@3594
   626
                                goto the_end;
vb@3594
   627
                            }
vb@3924
   628
                            add_opt_field(m, "pEp-auto-consume", "yes");
dz@4064
   629
                            m->in_reply_to = stringlist_add(m->in_reply_to, "pEp-auto-consume@pEp.foundation");
vb@3594
   630
                            free_message(_m);
vb@3594
   631
                            break;
vb@3594
   632
vb@4461
   633
                        // attach own keys for new member
vb@4461
   634
                        `` for "fsm/message[@security='attach_own_keys_for_new_member']" |>>> case «../@name»_PR_«yml:mixedCase(@name)»:
vb@3773
   635
                            // check if we had a former negotiation
vb@3594
   636
vb@3594
   637
                            transaction = false;
vb@3773
   638
                            for (int i=0; i < session->«yml:lcase(@name)»_state.own.negotiation.size; i++) {
vb@3773
   639
                                if (session->«yml:lcase(@name)»_state.own.negotiation.buf[i]) {
vb@3594
   640
                                    transaction = true;
vb@3594
   641
                                    break;
vb@3594
   642
                                }
vb@3594
   643
                            }
vb@3594
   644
    
vb@3594
   645
                            // if it is a former negotiation check if the key
vb@3594
   646
                            // is fully trusted and the sender key of this
vb@3594
   647
                            // transaction; if so add the sender key to extra
vb@3594
   648
                            // keys allowing this new partner to read the
vb@3594
   649
                            // secret keys
vb@3594
   650
vb@3594
   651
                            if (transaction) {
vb@3779
   652
                                assert(session->«yml:lcase(@name)»_state.comm_partner.sender_fpr &&
vb@3779
   653
                                    session->«yml:lcase(@name)»_state.transport.from &&
vb@3779
   654
                                    session->«yml:lcase(@name)»_state.transport.from->user_id);
vb@3779
   655
                                if (!(session->«yml:lcase(@name)»_state.comm_partner.sender_fpr &&
vb@3779
   656
                                        session->«yml:lcase(@name)»_state.transport.from &&
vb@3779
   657
                                        session->«yml:lcase(@name)»_state.transport.from->user_id))
vb@3594
   658
                                {
vb@3594
   659
                                    status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
vb@3594
   660
                                    goto the_end;
vb@3594
   661
                                }
vb@3519
   662
                            
vb@3594
   663
                                // test if this is a green channel
vb@3594
   664
vb@3519
   665
                                pEp_identity *ident = new_identity(NULL,
vb@3779
   666
                                        session->«yml:lcase(@name)»_state.comm_partner.sender_fpr,
vb@3779
   667
                                        session->«yml:lcase(@name)»_state.transport.from->user_id,
vb@3519
   668
                                        NULL
vb@3519
   669
                                    );
vb@3519
   670
                                if (!ident) {
vb@3519
   671
                                    status = PEP_OUT_OF_MEMORY;
vb@3519
   672
                                    goto the_end;
vb@3519
   673
                                }
vb@3519
   674
                                status = get_trust(session, ident);
vb@3519
   675
                                if (status) {
vb@3519
   676
                                    free_identity(ident);
vb@3519
   677
                                    goto the_end;
vb@3519
   678
                                }
vb@3519
   679
                                assert(ident->comm_type == PEP_ct_pEp); // we don't deliver otherwise
vb@3519
   680
                                if (ident->comm_type != PEP_ct_pEp) {
vb@3519
   681
                                    free_identity(ident);
vb@3519
   682
                                    status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
vb@3519
   683
                                    goto the_end;
vb@3519
   684
                                }
vb@3519
   685
                                free_identity(ident);
vb@3594
   686
vb@3594
   687
                                // test if we accepted this as own key already
vb@3594
   688
vb@3594
   689
                                bool is_own_key = false;
vb@3594
   690
                                status = own_key_is_listed(session,
vb@3779
   691
                                        session->«yml:lcase(@name)»_state.comm_partner.sender_fpr,
vb@3594
   692
                                        &is_own_key);
vb@3594
   693
                                assert(!status);
vb@3594
   694
                                if (status)
vb@3594
   695
                                    goto the_end;
vb@3594
   696
                                assert(is_own_key);
vb@3594
   697
                                if (!is_own_key) {
vb@3594
   698
                                    status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
vb@3594
   699
                                    goto the_end;
vb@3594
   700
                                }
vb@3594
   701
vb@3594
   702
                                // if so add key of comm partner to extra keys
vb@3594
   703
vb@3779
   704
                                extra = new_stringlist(session->«yml:lcase(@name)»_state.comm_partner.sender_fpr);
vb@3594
   705
                                if (!extra) {
vb@3594
   706
                                    status = PEP_OUT_OF_MEMORY;
vb@3594
   707
                                    goto the_end;
vb@3594
   708
                                }
vb@3519
   709
                            }
vb@3593
   710
                            
vb@3393
   711
                            status = base_prepare_message(
vb@3393
   712
                                    session,
vb@3393
   713
                                    li->ident,
vb@3393
   714
                                    li->ident,
vb@4280
   715
                                    BASE_SYNC,
vb@3393
   716
                                    _data,
vb@3393
   717
                                    size,
vb@3393
   718
                                    NULL,
vb@3393
   719
                                    &_m
vb@3393
   720
                                );
vb@3393
   721
                            if (status) {
vb@3393
   722
                                free(_data);
vb@3393
   723
                                goto the_end;
vb@3393
   724
                            }
vb@3509
   725
vb@3545
   726
                            // export secret keys into memory
vb@3545
   727
vb@3545
   728
                            key_data = strdup("");
vb@3545
   729
                            assert(key_data);
vb@3545
   730
                            if (!key_data) {
vb@3545
   731
                                free(_data);
vb@3567
   732
                                free_message(_m);
vb@3545
   733
                                status = PEP_OUT_OF_MEMORY;
vb@3545
   734
                                goto the_end;
vb@3545
   735
                            }
krista@3645
   736
                            key_data_size = 1; // N.B. If null termination makes us happy for debugging, fine, but 
krista@3645
   737
                                               // if we include this in the size, libetpan will null terminate and 
krista@3645
   738
                                               // go bananas. We can't have a NUL in the mime text.
vb@3545
   739
vb@3773
   740
                            for (stringlist_t *sl = session->«yml:lcase(@name)»_state.own.keys;
vb@3545
   741
                                    sl && sl->value ; sl = sl->next)
vb@3545
   742
                            {
vb@3545
   743
                                char *_key_data = NULL;
vb@3545
   744
                                size_t _size = 0;
vb@3545
   745
                                status = export_secret_key(session, sl->value, &_key_data, &_size);
vb@3545
   746
                                if (status && status != PEP_KEY_NOT_FOUND) {
vb@3545
   747
                                    free(_data);
vb@3567
   748
                                    free_message(_m);
vb@3545
   749
                                    goto the_end;
vb@3545
   750
                                }
vb@3545
   751
vb@3545
   752
                                if (status != PEP_KEY_NOT_FOUND) {
vb@3545
   753
                                    assert(_key_data && _size);
vb@3545
   754
                                    char *n = realloc(key_data, key_data_size + _size);
vb@3545
   755
                                    if (!n) {
vb@3545
   756
                                        free(_data);
vb@3567
   757
                                        free_message(_m);
vb@3545
   758
                                        status = PEP_OUT_OF_MEMORY;
vb@3545
   759
                                        goto the_end;
vb@3545
   760
                                    }
vb@3545
   761
                                    key_data = n;
vb@3545
   762
                                    key_data_size += _size;
vb@3545
   763
                                    strlcat(key_data, _key_data, key_data_size);
vb@3545
   764
                                    free(_key_data);
vb@3545
   765
                                    _key_data = NULL;
vb@3545
   766
                                }
vb@3545
   767
                                status = export_key(session, sl->value, &_key_data, &_size);
vb@3545
   768
                                if (status && status != PEP_KEY_NOT_FOUND) {
vb@3545
   769
                                    free(_data);
vb@3567
   770
                                    free_message(_m);
vb@3545
   771
                                    goto the_end;
vb@3545
   772
                                }
vb@3545
   773
vb@3545
   774
                                if (status != PEP_KEY_NOT_FOUND) {
vb@3545
   775
                                    assert(_key_data && _size);
vb@3545
   776
                                    char *n = realloc(key_data, key_data_size + _size);
vb@3545
   777
                                    if (!n) {
vb@3545
   778
                                        free(_data);
vb@3567
   779
                                        free_message(_m);
vb@3545
   780
                                        status = PEP_OUT_OF_MEMORY;
vb@3545
   781
                                        goto the_end;
vb@3545
   782
                                    }
vb@3545
   783
                                    key_data = n;
vb@3545
   784
                                    key_data_size += _size;
vb@3545
   785
                                    strlcat(key_data, _key_data, key_data_size);
vb@3545
   786
                                    free(_key_data);
vb@3545
   787
                                    _key_data = NULL;
vb@3545
   788
                                }
vb@3545
   789
                            }
vb@3545
   790
vb@3545
   791
                            // add secret key data as attachment
vb@3545
   792
krista@3645
   793
                            // N.B. The -1 makes sure we do NOT add a NUL into the mime stream!
krista@3645
   794
                            bloblist_t *bl = bloblist_add(_m->attachments, key_data, key_data_size - 1,
vb@3545
   795
                                    "application/octet-stream", "file://own.key");
vb@3545
   796
                            if (!bl) {
vb@3545
   797
                                free(_data);
vb@3567
   798
                                free_message(_m);
vb@3545
   799
                                status = PEP_OUT_OF_MEMORY;
vb@3545
   800
                                goto the_end;
vb@3545
   801
                            }
vb@3545
   802
                            key_data = NULL;
vb@3545
   803
vb@4775
   804
                            status = try_encrypt_message(session, _m, extra, &m, PEP_enc_PEP, 0);
vb@3393
   805
                            if (status) {
vb@3393
   806
                                status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
vb@3393
   807
                                goto the_end;
vb@3393
   808
                            }
vb@3924
   809
                            add_opt_field(m, "pEp-auto-consume", "yes");
dz@4064
   810
                            m->in_reply_to = stringlist_add(m->in_reply_to, "pEp-auto-consume@pEp.foundation");
vb@3393
   811
                            free_message(_m);
vb@3393
   812
                            break;
vb@3393
   813
vb@4461
   814
                        // attach own keys for group
vb@4461
   815
                        `` for "fsm/message[@security='attach_own_keys_for_group']" |>>> case «../@name»_PR_«yml:mixedCase(@name)»:
vb@4251
   816
                            status = base_prepare_message(
vb@4251
   817
                                    session,
vb@4251
   818
                                    li->ident,
vb@4251
   819
                                    li->ident,
vb@4280
   820
                                    BASE_SYNC,
vb@4251
   821
                                    _data,
vb@4251
   822
                                    size,
vb@4251
   823
                                    NULL,
vb@4251
   824
                                    &_m
vb@4251
   825
                                );
vb@4251
   826
                            if (status) {
vb@4251
   827
                                free(_data);
vb@4251
   828
                                goto the_end;
vb@4251
   829
                            }
vb@4251
   830
vb@4251
   831
                            // export secret keys into memory
vb@4251
   832
vb@4251
   833
                            key_data = strdup("");
vb@4251
   834
                            assert(key_data);
vb@4251
   835
                            if (!key_data) {
vb@4251
   836
                                free(_data);
vb@4251
   837
                                free_message(_m);
vb@4251
   838
                                status = PEP_OUT_OF_MEMORY;
vb@4251
   839
                                goto the_end;
vb@4251
   840
                            }
vb@4251
   841
                            key_data_size = 1; // N.B. If null termination makes us happy for debugging, fine, but 
vb@4251
   842
                                               // if we include this in the size, libetpan will null terminate and 
vb@4251
   843
                                               // go bananas. We can't have a NUL in the mime text.
vb@4251
   844
vb@4251
   845
                            for (stringlist_t *sl = session->«yml:lcase(@name)»_state.own.keys;
vb@4251
   846
                                    sl && sl->value ; sl = sl->next)
vb@4251
   847
                            {
vb@4251
   848
                                char *_key_data = NULL;
vb@4251
   849
                                size_t _size = 0;
vb@4251
   850
                                status = export_secret_key(session, sl->value, &_key_data, &_size);
vb@4251
   851
                                if (status && status != PEP_KEY_NOT_FOUND) {
vb@4251
   852
                                    free(_data);
vb@4251
   853
                                    free_message(_m);
vb@4251
   854
                                    goto the_end;
vb@4251
   855
                                }
vb@4251
   856
vb@4251
   857
                                if (status != PEP_KEY_NOT_FOUND) {
vb@4251
   858
                                    assert(_key_data && _size);
vb@4251
   859
                                    char *n = realloc(key_data, key_data_size + _size);
vb@4251
   860
                                    if (!n) {
vb@4251
   861
                                        free(_data);
vb@4251
   862
                                        free_message(_m);
vb@4251
   863
                                        status = PEP_OUT_OF_MEMORY;
vb@4251
   864
                                        goto the_end;
vb@4251
   865
                                    }
vb@4251
   866
                                    key_data = n;
vb@4251
   867
                                    key_data_size += _size;
vb@4251
   868
                                    strlcat(key_data, _key_data, key_data_size);
vb@4251
   869
                                    free(_key_data);
vb@4251
   870
                                    _key_data = NULL;
vb@4251
   871
                                }
vb@4251
   872
                                status = export_key(session, sl->value, &_key_data, &_size);
vb@4251
   873
                                if (status && status != PEP_KEY_NOT_FOUND) {
vb@4251
   874
                                    free(_data);
vb@4251
   875
                                    free_message(_m);
vb@4251
   876
                                    goto the_end;
vb@4251
   877
                                }
vb@4251
   878
vb@4251
   879
                                if (status != PEP_KEY_NOT_FOUND) {
vb@4251
   880
                                    assert(_key_data && _size);
vb@4251
   881
                                    char *n = realloc(key_data, key_data_size + _size);
vb@4251
   882
                                    if (!n) {
vb@4251
   883
                                        free(_data);
vb@4251
   884
                                        free_message(_m);
vb@4251
   885
                                        status = PEP_OUT_OF_MEMORY;
vb@4251
   886
                                        goto the_end;
vb@4251
   887
                                    }
vb@4251
   888
                                    key_data = n;
vb@4251
   889
                                    key_data_size += _size;
vb@4251
   890
                                    strlcat(key_data, _key_data, key_data_size);
vb@4251
   891
                                    free(_key_data);
vb@4251
   892
                                    _key_data = NULL;
vb@4251
   893
                                }
vb@4251
   894
                            }
vb@4251
   895
vb@4251
   896
                            // add secret key data as attachment
vb@4251
   897
vb@4251
   898
                            // N.B. The -1 makes sure we do NOT add a NUL into the mime stream!
vb@4251
   899
                            bl = bloblist_add(_m->attachments, key_data, key_data_size - 1,
vb@4251
   900
                                    "application/octet-stream", "file://own.key");
vb@4251
   901
                            if (!bl) {
vb@4251
   902
                                free(_data);
vb@4251
   903
                                free_message(_m);
vb@4251
   904
                                status = PEP_OUT_OF_MEMORY;
vb@4251
   905
                                goto the_end;
vb@4251
   906
                            }
vb@4251
   907
                            key_data = NULL;
vb@4251
   908
vb@4289
   909
                            // we do not support extra keys here and will only encrypt to ourselves
vb@4775
   910
                            status = try_encrypt_message(session, _m, NULL, &m, PEP_enc_PEP, 0);
vb@4251
   911
                            if (status) {
vb@4251
   912
                                status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
vb@4251
   913
                                goto the_end;
vb@4251
   914
                            }
vb@4251
   915
                            add_opt_field(m, "pEp-auto-consume", "yes");
vb@4251
   916
                            m->in_reply_to = stringlist_add(m->in_reply_to, "pEp-auto-consume@pEp.foundation");
vb@4251
   917
                            free_message(_m);
vb@4251
   918
                            break;
vb@4251
   919
vb@3594
   920
                        default: // security=trusted only
vb@3129
   921
                            status = base_prepare_message(
vb@3143
   922
                                    session,
vb@3129
   923
                                    li->ident,
vb@3129
   924
                                    li->ident,
vb@4280
   925
                                    BASE_SYNC,
vb@3129
   926
                                    _data,
vb@3129
   927
                                    size,
vb@3129
   928
                                    NULL,
vb@3129
   929
                                    &_m
vb@3129
   930
                                );
vb@3129
   931
                            if (status) {
vb@3129
   932
                                free(_data);
vb@3129
   933
                                goto the_end;
vb@3129
   934
                            }
vb@3509
   935
vb@4775
   936
                            status = try_encrypt_message(session, _m, NULL, &m, PEP_enc_PEP, 0);
vb@2879
   937
                            if (status) {
vb@2899
   938
                                status = PEP_«yml:ucase(@name)»_CANNOT_ENCRYPT;
vb@2878
   939
                                goto the_end;
vb@2879
   940
                            }
vb@3924
   941
                            add_opt_field(m, "pEp-auto-consume", "yes");
dz@4064
   942
                            m->in_reply_to = stringlist_add(m->in_reply_to, "pEp-auto-consume@pEp.foundation");
vb@2878
   943
                            free_message(_m);
vb@2878
   944
                    }
vb@2878
   945
vb@2899
   946
                    status = session->messageToSend(m);
vb@2870
   947
                    m = NULL;
vb@2870
   948
                }
vb@4549
   949
            ||
vb@4549
   950
            if "fsm/message[@ratelimit>0]" {
vb@4549
   951
            ||
vb@4549
   952
vb@4549
   953
                switch (fsm) {
vb@4549
   954
            ||
vb@4549
   955
            for "fsm[message/@ratelimit>0]" {
vb@4549
   956
            ||
vb@4549
   957
                    case Sync_PR_«yml:lcase(@name)»:
vb@4549
   958
                        switch (message_type) {
vb@4549
   959
            ||
vb@4549
   960
            for "message[@ratelimit>0]"
vb@4549
   961
            ||
vb@4549
   962
                            case «../@name»_PR_«yml:mixedCase(@name)»:
vb@4549
   963
                                session->«yml:lcase(../../@name)»_state.own.last_«../@name»_«@name» = now;
vb@4549
   964
                                break;
vb@4549
   965
            ||
vb@4549
   966
            ||
vb@4549
   967
                            default:
vb@4549
   968
                                break;
vb@4549
   969
                        }
vb@4549
   970
                        break;
vb@4549
   971
            ||
vb@4549
   972
            }
vb@4549
   973
            ||
vb@4549
   974
                    default:
vb@4549
   975
                        break;
vb@4549
   976
                }
vb@4549
   977
            ||
vb@4549
   978
            }
vb@4549
   979
            ||
vb@2870
   980
vb@2870
   981
            the_end:
vb@3594
   982
                free_stringlist(extra);
vb@2870
   983
                free_identity_list(channels);
vb@2870
   984
                free_message(m);
vb@2870
   985
                free(data);
vb@3545
   986
                free(key_data);
vb@2870
   987
                free_«@name»_message(msg);
vb@3747
   988
                if (status)
vb@3747
   989
                    SERVICE_ERROR_LOG(session, "send_«@name»_message()", status);
vb@2870
   990
                return status;
vb@2829
   991
            }
vb@2829
   992
vb@2870
   993
            PEP_STATUS recv_«@name»_event(
vb@2870
   994
                    PEP_SESSION session,
vb@2870
   995
                    «@name»_event_t *ev
vb@2870
   996
                )
vb@2870
   997
            {
vb@2870
   998
                assert(session && ev);
vb@2870
   999
                if (!(session && ev))
vb@2870
  1000
                    return PEP_ILLEGAL_VALUE;
vb@2829
  1001
vb@2870
  1002
                PEP_STATUS status = PEP_STATUS_OK;
vb@2888
  1003
                «@name»_PR fsm = (int) None;
vb@2888
  1004
                int event = None;
vb@2829
  1005
vb@2910
  1006
                if (ev->event > None && ev->event < Extra) {
vb@2870
  1007
                    status = update_«@name»_state(session, ev->msg, &fsm, &event);
vb@2870
  1008
                    if (status)
vb@2888
  1009
                        goto the_end;
vb@2829
  1010
vb@2870
  1011
                    if (ev->fsm) {
vb@2870
  1012
                        if (ev->fsm != fsm |`> |` ev->event != event) {
vb@2870
  1013
                            status = PEP_«yml:ucase(@name)»_ILLEGAL_MESSAGE;
vb@2888
  1014
                            goto the_end;
vb@2870
  1015
                        }
vb@2870
  1016
                    }
vb@2888
  1017
                    else if (ev->event) {
vb@2888
  1018
                        status = PEP_«yml:ucase(@name)»_ILLEGAL_MESSAGE;
vb@2888
  1019
                        goto the_end;
vb@2870
  1020
                    }
vb@2870
  1021
                }
vb@2888
  1022
                else {
vb@2888
  1023
                    fsm = ev->fsm;
vb@2888
  1024
                    event = ev->event;
vb@2888
  1025
                }
vb@2829
  1026
vb@3534
  1027
                // update transport data
vb@3534
  1028
vb@3534
  1029
                if (ev->from) {
vb@3774
  1030
                    free_identity(session->«yml:lcase(@name)»_state.transport.from);
vb@3774
  1031
                    session->«yml:lcase(@name)»_state.transport.from = ev->from;
vb@3540
  1032
                    ev->from = NULL;
vb@3534
  1033
                }
vb@3534
  1034
vb@3779
  1035
                if (ev->sender_fpr) {
vb@3779
  1036
                    free(session->«yml:lcase(@name)»_state.transport.sender_fpr);
vb@3779
  1037
                    session->«yml:lcase(@name)»_state.transport.sender_fpr = ev->sender_fpr;
krista@4047
  1038
                    
krista@4088
  1039
                    /* Removed for temp ENGINE-647 fix. Will be reenabled once better sync debugging is in.
krista@4047
  1040
                    // Check against saved comm_partner sender_fpr state, if there is one yet
krista@4047
  1041
                    if (session->«yml:lcase(@name)»_state.comm_partner.sender_fpr) {
krista@4047
  1042
                        // 1. Does it match sender_fpr?
krista@4047
  1043
                        if (strcasecmp(session->«yml:lcase(@name)»_state.comm_partner.sender_fpr, ev->sender_fpr) != 0) {
krista@4047
  1044
                            // 2. If not, is it a group key?
krista@4047
  1045
                            bool is_own_key = false;
krista@4047
  1046
                            status = own_key_is_listed(session, ev->sender_fpr, &is_own_key);
krista@4047
  1047
                            if (status)
krista@4047
  1048
                                goto the_end;
krista@4047
  1049
                            if (!is_own_key) {
krista@4047
  1050
                                status = PEP_ILLEGAL_VALUE;
krista@4047
  1051
                                goto the_end;
krista@4047
  1052
                            }    
krista@4047
  1053
                        }
krista@4047
  1054
                    }
krista@4088
  1055
                    */
krista@4047
  1056
                                                            
vb@3779
  1057
                    ev->sender_fpr = NULL;
vb@3540
  1058
                }
vb@3540
  1059
vb@3540
  1060
                // update own identities
vb@3540
  1061
vb@3540
  1062
                if (ev->own_identities && ev->own_identities->ident) {
vb@3773
  1063
                    free_identity_list(session->«yml:lcase(@name)»_state.own.identities);
vb@3773
  1064
                    session->«yml:lcase(@name)»_state.own.identities = ev->own_identities;
vb@3540
  1065
                    ev->own_identities = NULL;
vb@3534
  1066
                }
vb@3534
  1067
krista@4047
  1068
                
vb@2888
  1069
                status = «@name»_driver(session, fsm, event);
vb@2870
  1070
vb@2888
  1071
            the_end:
krista@3331
  1072
                //free_«@name»_event(ev); // FIXME: We don't own this pointer. Are we sure it gets freed externally?
vb@2870
  1073
                return status;
vb@2829
  1074
            }
vb@2829
  1075
vb@2870
  1076
            ||
vb@2829
  1077
        }
vb@2829
  1078
vb@2829
  1079
        apply "fsm", 0, mode=gen;
vb@2829
  1080
    }
vb@2829
  1081
vb@2909
  1082
    template "fsm", mode=timeout
vb@2909
  1083
    ||
vb@2909
  1084
    static bool _«@name»_timeout(int state)
vb@2909
  1085
    {
vb@2909
  1086
        static int last_state = None;
vb@2909
  1087
        static time_t switch_time = 0;
vb@2909
  1088
vb@2909
  1089
        if (state > Init) {
vb@2909
  1090
            if (state == last_state) {
vb@2909
  1091
                if (time(NULL) - switch_time > «yml:ucase(@name)»_THRESHOLD) {
vb@2909
  1092
                    last_state = None;
vb@2909
  1093
                    switch_time = 0;
vb@2909
  1094
                    return true;
vb@2909
  1095
                }
vb@2909
  1096
            }
vb@2909
  1097
            else {
vb@2909
  1098
                last_state = state;
vb@2909
  1099
                switch_time = time(NULL);
vb@2909
  1100
            }
vb@2909
  1101
        }
vb@2909
  1102
        else {
vb@2909
  1103
            last_state = None;
vb@2909
  1104
            switch_time = 0;
vb@2909
  1105
        }
vb@2909
  1106
vb@2909
  1107
        return false;
vb@2909
  1108
    }
vb@2909
  1109
vb@2909
  1110
    ||
vb@2909
  1111
vb@2909
  1112
    template "fsm", mode=reset_state_machine
vb@2909
  1113
    ||
vb@2909
  1114
        case «../@name»_PR_«yml:lcase(@name)»: {
vb@2909
  1115
            int state = session->«yml:lcase(../@name)»_state.«yml:lcase(@name)».state;
vb@2909
  1116
            switch (state) {
vb@2909
  1117
                `` for "state[@name!='InitState' and @timeout != 'off']" |>>> case «@name»:
vb@2909
  1118
                    if (_«@name»_timeout(state)) {
vb@2909
  1119
                        session->«yml:lcase(../@name)»_state.«yml:lcase(@name)».state = Init;
vb@2909
  1120
                        event = Init;
vb@2914
  1121
                        `` if "@threshold > 0" |>>>>> «@name»TimeoutHandler(session);
vb@2909
  1122
                    }
vb@2909
  1123
                    break;
vb@2909
  1124
                
vb@2909
  1125
                default:
vb@2909
  1126
                    _«@name»_timeout(None);
vb@2909
  1127
            }
vb@2909
  1128
            break;
vb@2909
  1129
        }
vb@2909
  1130
vb@2909
  1131
    ||
vb@2909
  1132
vb@2890
  1133
    template "fsm", mode=signal_message
vb@2890
  1134
    {
vb@2890
  1135
        ||
vb@2890
  1136
        case «../@name»_PR_«yml:lcase(@name)»:
vb@3509
  1137
            switch (msg->choice.«yml:lcase(@name)».present) {
vb@2891
  1138
        ||
vb@3518
  1139
        for "message[@security='unencrypted']" {
vb@3518
  1140
        if "position()=1" |>> // these messages require a detached signature
vb@3518
  1141
        ||
vb@3518
  1142
                case «../@name»_PR_«yml:mixedCase(@name)»:
vb@3779
  1143
                    if (!sender_fpr) {
vb@3518
  1144
                        status = PEP_«yml:ucase(ancestor::protocol/@name)»_ILLEGAL_MESSAGE;
vb@3518
  1145
                        goto the_end;
vb@3518
  1146
                    }
vb@3518
  1147
                    event = «@name»;
vb@3518
  1148
                    break;
vb@2890
  1149
vb@3518
  1150
        ||
vb@2891
  1151
        }
vb@3518
  1152
        for "message[@security='untrusted']" {
vb@3518
  1153
        if "position()=1" |>> // these messages must arrive encrypted
vb@3518
  1154
        ||
vb@3518
  1155
                case «../@name»_PR_«yml:mixedCase(@name)»:
vb@3518
  1156
                    if (rating < PEP_rating_reliable) {
vb@3518
  1157
                        status = PEP_«yml:ucase(ancestor::protocol/@name)»_ILLEGAL_MESSAGE;
vb@3518
  1158
                        goto the_end;
vb@3518
  1159
                    }
vb@3518
  1160
                    event = «@name»;
vb@3518
  1161
                    break;
vb@3338
  1162
vb@3518
  1163
        ||
vb@3338
  1164
        }
vb@3518
  1165
        for "message[@security!='unencrypted' and @security!='untrusted']" {
vb@3518
  1166
        if "position()=1" |>> // these messages must come through a trusted channel
vb@3518
  1167
        ||
vb@3518
  1168
                case «../@name»_PR_«yml:mixedCase(@name)»:
vb@3518
  1169
                    if (rating < PEP_rating_trusted) {
vb@3518
  1170
                        status = PEP_«yml:ucase(ancestor::protocol/@name)»_ILLEGAL_MESSAGE;
vb@3518
  1171
                        goto the_end;
vb@3518
  1172
                    }
vb@3779
  1173
                    status = own_key_is_listed(session, sender_fpr, &is_own_key);
vb@3593
  1174
                    if (status)
vb@3593
  1175
                        goto the_end;
vb@3593
  1176
                    if (!is_own_key) {
vb@3593
  1177
                        status = PEP_«yml:ucase(ancestor::protocol/@name)»_ILLEGAL_MESSAGE;
vb@3593
  1178
                        goto the_end;
vb@3593
  1179
                    }
vb@3518
  1180
                    event = «@name»;
vb@3518
  1181
                    break;
vb@3338
  1182
vb@3518
  1183
        ||
vb@3338
  1184
        }
vb@2891
  1185
        ||
vb@2890
  1186
                default:
vb@2890
  1187
                    status = PEP_«yml:ucase(ancestor::protocol/@name)»_ILLEGAL_MESSAGE;
vb@2890
  1188
                    goto the_end;
vb@2890
  1189
            }
vb@2890
  1190
            break;
vb@2890
  1191
vb@2890
  1192
        ||
vb@2890
  1193
    }
vb@2890
  1194
vb@2838
  1195
    template "fsm", mode=event
vb@2838
  1196
    {
vb@2838
  1197
    ||
vb@2843
  1198
    case «../@name»_PR_«yml:lcase(@name)»: {
vb@3509
  1199
        switch (msg->choice.«yml:lcase(@name)».present) {
vb@2838
  1200
    ||
vb@2838
  1201
    for "message"
vb@2838
  1202
    ||
vb@3509
  1203
            case «../@name»_PR_«yml:mixedCase(@name)»:
vb@2838
  1204
                ev->event = «@name»;
vb@2838
  1205
                break;
vb@2838
  1206
    ||
vb@2838
  1207
    ||
vb@2838
  1208
            default:
vb@2838
  1209
                // unknown message type
vb@2838
  1210
                free(ev);
vb@2838
  1211
                return NULL;
vb@2838
  1212
        }
vb@2838
  1213
        break;
vb@2838
  1214
    }
vb@2838
  1215
vb@2838
  1216
    ||
vb@2838
  1217
    }
vb@2838
  1218
vb@2829
  1219
    template "fsm", mode=driver
vb@2829
  1220
    ||
vb@2843
  1221
    case «../@name»_PR_«yml:lcase(@name)»: {
vb@2839
  1222
        int state = session->«yml:lcase(../@name)»_state.«yml:lcase(@name)».state;
vb@2839
  1223
        next_state = fsm_«@name»(session, state, event);
vb@2838
  1224
        if (next_state > None) {
vb@2838
  1225
            session->«yml:lcase(../@name)»_state.«yml:lcase(@name)».state = next_state;
vb@2838
  1226
            event = Init;
vb@2838
  1227
        }
vb@2838
  1228
        else if (next_state < None) {
Hussein@3167
  1229
            return PEP_STATEMACHINE_ERROR - next_state;
vb@2838
  1230
        }
vb@2829
  1231
        break;
vb@2829
  1232
    }
vb@2829
  1233
vb@2829
  1234
    ||
vb@2829
  1235
vb@2829
  1236
    template "fsm", mode=gen {
vb@2829
  1237
        document "generated/{@name}_fsm.h", "text" {
vb@2829
  1238
        ||
vb@2829
  1239
        // This file is under GNU General Public License 3.0
vb@2829
  1240
        // see LICENSE.txt
vb@2829
  1241
vb@2829
  1242
        #pragma once
vb@2829
  1243
vb@2829
  1244
        #include "«../@name»_impl.h"
vb@2829
  1245
vb@2829
  1246
        #ifdef __cplusplus
vb@2829
  1247
        extern "C" {
vb@2829
  1248
        #endif
vb@2829
  1249
vb@2829
  1250
        // state machine for «@name»
krista@2271
  1251
krista@2271
  1252
        // states
krista@2271
  1253
krista@2271
  1254
        typedef enum _«@name»_state {
vb@2829
  1255
            «@name»_state_None = None,
vb@2829
  1256
            «@name»_state_Init = Init,
vb@2829
  1257
        ||
vb@2829
  1258
        for "func:distinctName(state[not(@name='InitState')])"
vb@2829
  1259
            |> «@name»`if "position()!=last()" > , `
vb@2829
  1260
        ||
krista@2271
  1261
        } «@name»_state;
krista@2271
  1262
krista@2271
  1263
        // events
krista@2271
  1264
krista@2271
  1265
        typedef enum _«@name»_event {
vb@4417
  1266
            «@name»_event_Timeout = None,
vb@2829
  1267
            «@name»_event_Init = Init,
krista@2271
  1268
        ||
vb@3388
  1269
        for "message" {
krista@2271
  1270
            const "name", "@name";
vb@2829
  1271
            |> «$name» = «/protocol/fsm/message[@name=$name]/@id»,
krista@2271
  1272
        }
vb@2829
  1273
        |> «@name»_event_Extra = Extra,
vb@3387
  1274
        for "external" {
vb@3385
  1275
            if "@id < 128"
vb@3385
  1276
                error > external «@name» must have ID >= 128 but it's «@id»
vb@3384
  1277
            |> «@name» = «@id»,
vb@3385
  1278
        }
vb@2830
  1279
        for "func:distinctName(state/event[not(../../message/@name=@name or ../../external/@name=@name)])" {
vb@2829
  1280
            if "@name!='Init'"
vb@2829
  1281
                |> «@name»`if "position()!=last()" > , `
vb@2829
  1282
        }
krista@2271
  1283
        ||
krista@2271
  1284
        } «@name»_event;
krista@2271
  1285
vb@2829
  1286
        // state machine
krista@2271
  1287
vb@3913
  1288
        #ifndef NDEBUG
vb@2829
  1289
        const char *«@name»_state_name(int state);
vb@2881
  1290
        const char *«@name»_event_name(int event);
vb@3913
  1291
        #endif
krista@2271
  1292
vb@2838
  1293
        // the state machine function is returning the next state in case of a
vb@2838
  1294
        // transition or None for staying
vb@2838
  1295
krista@2271
  1296
        «@name»_state fsm_«@name»(
krista@2271
  1297
                PEP_SESSION session,
krista@2271
  1298
                «@name»_state state,
vb@2829
  1299
                «@name»_event event
krista@2271
  1300
            );
krista@2271
  1301
krista@2271
  1302
        #ifdef __cplusplus
krista@2271
  1303
        }
krista@2271
  1304
        #endif
krista@2271
  1305
krista@2271
  1306
        ||
krista@2271
  1307
        }
vb@2829
  1308
vb@2829
  1309
        document "generated/{@name}_fsm.c", "text" {
krista@2271
  1310
        ||
vb@2829
  1311
        // This file is under GNU General Public License 3.0
vb@2829
  1312
        // see LICENSE.txt
krista@2271
  1313
vb@2829
  1314
        #include "«@name»_fsm.h"
vb@2847
  1315
        #include <stdlib.h>
krista@2271
  1316
vb@3913
  1317
        #ifdef NDEBUG
vb@3913
  1318
        static
vb@3913
  1319
        #endif
vb@2829
  1320
        const char *«@name»_state_name(int state)
vb@2829
  1321
        {
vb@2829
  1322
            switch (state) {
vb@2829
  1323
                case End:
vb@2829
  1324
                    return "End";
vb@2829
  1325
                case None:
vb@2829
  1326
                    return "None";
vb@2829
  1327
                case Init:
vb@2829
  1328
                    return "InitState";
vb@2829
  1329
        ||
vb@2829
  1330
        for "func:distinctName(state[not(@name='InitState')])" {
vb@2829
  1331
            |>> case «@name»:
vb@2829
  1332
            |>>> return "«@name»";
vb@2829
  1333
        }
vb@2829
  1334
        ||
vb@2829
  1335
                default:
vb@4140
  1336
                    assert(0);
vb@2829
  1337
                    return "unknown state";
vb@2829
  1338
            }
vb@2829
  1339
        }
krista@2271
  1340
vb@3913
  1341
        #ifdef NDEBUG
vb@3913
  1342
        static
vb@3913
  1343
        #endif
vb@2881
  1344
        const char *«@name»_event_name(int event)
vb@2881
  1345
        {
vb@2881
  1346
            switch (event) {
vb@2881
  1347
                case None:
vb@4416
  1348
                    return "Timeout";
vb@2881
  1349
                case Init:
vb@2881
  1350
                    return "Init";
vb@2881
  1351
        ||
vb@5034
  1352
        for "func:distinctName(state/event[not(@name='Init')]|message)" {
vb@2881
  1353
            |>> case «@name»:
vb@2881
  1354
            |>>> return "«@name»";
vb@2881
  1355
        }
vb@2881
  1356
        ||
vb@2881
  1357
                default:
vb@4140
  1358
                    assert(0);
vb@2881
  1359
                    return "unknown event";
vb@2881
  1360
            }
vb@2881
  1361
        }
vb@2881
  1362
vb@2881
  1363
vb@2829
  1364
        static char *_str(int n, bool hex)
vb@2829
  1365
        {
vb@2829
  1366
            char *buf = calloc(1, 24);
vb@2829
  1367
            assert(buf);
vb@2829
  1368
            if (!buf)
vb@2829
  1369
                return NULL;
vb@2829
  1370
vb@2829
  1371
            if (hex)
vb@2829
  1372
                snprintf(buf, 24, "%.4x", n);
vb@2829
  1373
            else
vb@2829
  1374
                snprintf(buf, 24, "%d", n);
vb@2829
  1375
            return buf;
vb@2829
  1376
        }
vb@2829
  1377
vb@2829
  1378
        #define «@name»_ERR_LOG(t, d) log_event(session, (t), "«@name»", (d), "error")
vb@2829
  1379
vb@2829
  1380
        static PEP_STATUS _«@name»_ERR_LOG_int(PEP_SESSION session, char *t, int n, bool hex)
vb@2829
  1381
        {
vb@2829
  1382
            char *_buf = _str(n, hex);
vb@2829
  1383
            if (!_buf)
vb@2829
  1384
                return PEP_OUT_OF_MEMORY;
vb@2829
  1385
            PEP_STATUS status = «@name»_ERR_LOG(t, _buf);
vb@2829
  1386
            free(_buf);
vb@2829
  1387
            return status;
vb@2829
  1388
        }
vb@2829
  1389
vb@2829
  1390
        #define «@name»_ERR_LOG_INT(t, n) _«@name»_ERR_LOG_int(session, (t), (n), false)
vb@2829
  1391
        #define «@name»_ERR_LOG_HEX(t, n) _«@name»_ERR_LOG_int(session, (t), (n), true)
vb@2829
  1392
        #define «@name»_SERVICE_LOG(t, d) SERVICE_LOG(session, (t), "«@name»", (d))
vb@2829
  1393
vb@2829
  1394
        «@name»_state fsm_«@name»(
krista@2271
  1395
                PEP_SESSION session,
vb@2829
  1396
                «@name»_state state,
vb@2829
  1397
                «@name»_event event
krista@2271
  1398
            )
krista@2271
  1399
        {
krista@2271
  1400
            assert(session);
krista@2271
  1401
            if (!session)
vb@2829
  1402
                return invalid_state;
krista@2271
  1403
vb@3365
  1404
            if (state == None)
vb@3365
  1405
                state = «@name»_state_Init;
vb@3365
  1406
krista@2271
  1407
            switch (state) {
vb@2829
  1408
                `` apply "state", 2, mode=fsm
krista@2271
  1409
                default:
vb@3912
  1410
                    «@name»_ERR_LOG("invalid state", «@name»_state_name(state));
vb@4140
  1411
                    assert(0);
vb@2829
  1412
                    return invalid_state;
krista@2271
  1413
            }
vb@2829
  1414
            
vb@2838
  1415
            return None;
krista@2271
  1416
        }
krista@2271
  1417
krista@2271
  1418
        ||
vb@2829
  1419
        }
vb@2829
  1420
    }
vb@2829
  1421
    
vb@2829
  1422
    template "state", mode=fsm {
vb@2829
  1423
        choose {
vb@2829
  1424
            when "@name='InitState'" | case «../@name»_state_Init:
vb@2829
  1425
            otherwise | case «@name»:
vb@2829
  1426
        }
vb@2829
  1427
        ||
vb@2829
  1428
            «../@name»_SERVICE_LOG("in state", "«@name»");
vb@2829
  1429
vb@2829
  1430
            switch (event) {
vb@3366
  1431
                case None:
vb@4416
  1432
                    «../@name»_SERVICE_LOG("received Timeout event", "ignoring");
vb@3366
  1433
                    break;
vb@3366
  1434
     
vb@2838
  1435
        ||
vb@2838
  1436
        if "not(event[@name='Init'])"
vb@2838
  1437
        ||
vb@2838
  1438
                case Init:
vb@3379
  1439
                    «../@name»_SERVICE_LOG("received Init but nothing to do", "Init");
vb@2838
  1440
                    break;
vb@2838
  1441
vb@2838
  1442
        ||
vb@2838
  1443
        ||
vb@2829
  1444
                `` apply "event", 2, mode=fsm
vb@2829
  1445
                default:
vb@2885
  1446
                    // ignore events not handled here
vb@3594
  1447
                    «../@name»_SERVICE_LOG("ignoring event", «../@name»_event_name(event));
vb@3362
  1448
                    return invalid_event;
vb@2829
  1449
            }
vb@2829
  1450
            break;
vb@2829
  1451
vb@2829
  1452
        ||
krista@2271
  1453
    }
krista@2271
  1454
vb@2829
  1455
    template "event", mode=fsm {
vb@2829
  1456
        | case «@name»: {
vb@2865
  1457
        if "condition|action|send" |> PEP_STATUS status;
vb@2829
  1458
        if "condition" |> bool result = false;
vb@2865
  1459
        if "condition|action|send" |
krista@2271
  1460
        ||
vb@2829
  1461
            «../../@name»_SERVICE_LOG("received event", "«@name»");
vb@4337
  1462
            `` apply "transition|action|condition|else|send|debug";
vb@2829
  1463
        ||
vb@2829
  1464
        if "name(*[last()])!='transition'" {
vb@2829
  1465
            |
vb@2843
  1466
            |> «../../@name»_SERVICE_LOG("remaining in state", "«../@name»");
vb@2829
  1467
            |> break;
vb@2829
  1468
        }
vb@2829
  1469
        ||
vb@2829
  1470
        }
vb@2829
  1471
        
vb@2829
  1472
        ||
vb@2829
  1473
    }
vb@2829
  1474
vb@2829
  1475
    template "transition" {
vb@2865
  1476
        const "fsm", "ancestor::fsm";
krista@2271
  1477
        ||
krista@2271
  1478
vb@2829
  1479
        «$fsm/@name»_SERVICE_LOG("transition to state", "«@target»");
vb@2838
  1480
        return «@target»;
krista@2271
  1481
        ||
vb@2829
  1482
    }
krista@2271
  1483
vb@2865
  1484
    template "send" {
vb@2865
  1485
        const "fsm", "ancestor::fsm";
vb@2865
  1486
        const "protocol", "ancestor::protocol";
vb@2865
  1487
        ||
vb@2865
  1488
vb@2865
  1489
        «$fsm/@name»_SERVICE_LOG("send message", "«@name»");
vb@3509
  1490
        status = send_«$protocol/@name»_message(session, «$fsm/@id», «$fsm/@name»_PR_«yml:mixedCase(@name)»);
vb@3089
  1491
        if (status == PEP_OUT_OF_MEMORY)
vb@3089
  1492
            return out_of_memory;
vb@3089
  1493
        if (status) {
vb@3089
  1494
            «$fsm/@name»_ERR_LOG_HEX("sending «@name» failed", status);
vb@3089
  1495
            return cannot_send;
vb@3089
  1496
        }
vb@2865
  1497
        ||
vb@2865
  1498
    }
vb@2865
  1499
vb@4337
  1500
    template "debug"
vb@4337
  1501
        | KeySync_SERVICE_LOG("«.»", "«ancestor::protocol/@name»");
vb@4337
  1502
vb@2829
  1503
    template "action" {
vb@2865
  1504
        const "fsm", "ancestor::fsm";
vb@2865
  1505
        ||
vb@2829
  1506
vb@2865
  1507
        «$fsm/@name»_SERVICE_LOG("do action", "«@name»");
vb@2865
  1508
        status = «@name»(session);
vb@3089
  1509
        if (status == PEP_OUT_OF_MEMORY)
vb@3089
  1510
            return out_of_memory;
vb@2829
  1511
        if (status) {
vb@2829
  1512
            «$fsm/@name»_ERR_LOG_HEX("executing action «@name»() failed", status);
vb@4140
  1513
            assert(0);
vb@2829
  1514
            return invalid_action;
krista@2271
  1515
        }
krista@2271
  1516
        ||
krista@2271
  1517
    }
krista@2271
  1518
vb@2829
  1519
    template "condition" {
vb@2865
  1520
        const "fsm", "ancestor::fsm";
krista@2271
  1521
        ||
krista@2271
  1522
vb@2829
  1523
        status = «@name»(session, &result);
vb@3089
  1524
        if (status == PEP_OUT_OF_MEMORY)
vb@3089
  1525
            return out_of_memory;
vb@2829
  1526
        if (status) {
vb@2829
  1527
            «$fsm/@name»_ERR_LOG_HEX("computing condition «@name» failed", status);
vb@4140
  1528
            assert(0);
vb@2829
  1529
            return invalid_condition;
krista@2271
  1530
        }
vb@2829
  1531
        if (result) {
vb@2843
  1532
            «$fsm/@name»_SERVICE_LOG("condition applies", "«@name»");
krista@2271
  1533
        ||
vb@4337
  1534
        apply "transition|action|condition|else|send|debug";
vb@2907
  1535
        | }
vb@2907
  1536
    }
vb@2907
  1537
vb@2907
  1538
    template "else" {
vb@3520
  1539
        if "not(name(preceding-sibling::*[1]) = 'condition')"
vb@2907
  1540
            error "else without if";
vb@2907
  1541
vb@2907
  1542
        | else {
vb@2907
  1543
        |> «ancestor::fsm/@name»_SERVICE_LOG("condition does not apply", "«preceding-sibling::*[last()]/@name»");
vb@4337
  1544
        apply "transition|action|condition|else|send|debug";
krista@2271
  1545
        | }
krista@2271
  1546
    }
krista@2271
  1547
}