=============================
-- comment
#include "script.dsm"
#include "/path/to/anotherscript.dsm"
import(mod_name);

[initial] state name 
	  [ enter { 
	      action; 
	      action;
	      ...
	    } ] 
	  [ exit { 
	      action;
	      action;
	      ...
	    } ]
      ;

transition name s1 - [exception;] [ { [not] condition; [not] condition; ... } ] [/ { action; action; ...} ]  -> s2;
 or 
transition name (s1a, s1b[, s1c, ...])  - [ { [not] condition; [not] condition; ... } ] [/ { action; action; ...} ]  -> s2;

=============================
#paramname uses the event parameter 'paramname' (from current event)
$varname uses the variable varname (from session's variable map)
@selectname uses the "select" 'selectname' (from the session's dialog)
=============================
core actions:
 -- reprocess the current event after transition:
 repost()

 -- call/jump/return sub-FSM
 jumpFSM(name)
 callFSM(name)
 returnFSM()

 stop(<send bye>)
   e.g. stop(false), stop(true)

 playPrompt(param)
   from promptCollection, e.g. playPrompt("hello");
   if $prompts.default_fallback=yes, default prompt set is tried if
   prompt not found in current prompt set
   Throws "prompt" exeption with #name if prompt not found.

 playPromptLooped(param)

 setPromptSet(name)
   select active prompt set if more prompt sets are loaded
   Throws "prompt" exeption with #name if prompt set not found

 playFile(filename [, loop=true])
   e.g. playFile($myfile, true); will play the file looped.
   Throws "file" exeption with #path if file can not be opened

 playFileFront(filename [, loop=true])
   e.g. playFileFront($myfile, true); will play the file at first
   position in the playlist, and looped.
   Throws "file" exeption with #path if file can not be opened

 recordFile(filename)
   Throws "file" exeption with #path if file can not be opened for recording

 stopRecord()
 getRecordLength([dst_varname])   -- only while recording! default dst var: record_length
 getRecordDataSize([dst_varname]) -- only while recording! default dst var: record_data_size
 closePlaylist(notify=true)
   if notify=true, send an event
 setInOutPlaylist() 
   set playlist as input and output
 addSeparator(id [, bool front])
   fires event when playlist hits it ; front=[true|false]
 connectMedia() 
   set playlist as input and output of session, and connect to mediaprocessor 
 disconnectMedia() 
   disconnect from mediaprocessor

 mute() 
   set RTP stream to muted (don't send and receive RTP packets)
 unmute() 
   set RTP stream to unmuted (send and receive RTP packets)

 postEvent(sess_id[, variable_name;variable_name;...])
   post dsm event to session sess_id; variables copied as event parameters
   e.g. postEvent(@local_tag, PAI) : post event to ourselves
        postEvent($some_call, var1;var2;var3)     post event with var1, var2, var3
   * sets $errno (arg)

 postEvent(sess_id, var)
   all local variables copied as event variables
   * sets $errno (arg)

 enableDTMFDetection() 
 disableDTMFDetection()

sendDTMF(key [, duration_ms])
  send a DTMF event (RFC4733 event)
  duration_ms defaults to 500ms

sendDTMFSequence(sequence [, duration_ms])
  send a sequence of DTMF events (RFC4733 event), e.g. 123#45*1
  duration_ms defaults to 500ms

 B2B.connectCallee(remote_party, remote_uri)
   connect second leg of B2B session (see AmB2BSession)

 B2B.terminateOtherLeg
   disconnect second leg of B2B session (see AmB2BSession)

 B2B.sendReinvite(generate_sdp [, string extra_headers])
   send a reinvite in caller leg (first leg), e.g. to 
   reconnect first leg after B2B.otherBye received. 
   generate_sdp can be 'true' or 'false'
   (B2B.sendReinvite(true) recommended)

 B2B.clearHeaders()
   clear the headers used for outgoing INVITE on B leg

 B2B.addHeader(string header)
  add a header for outgoing INVITE on B leg
 
 B2B.setHeaders(string headers [, replace_crlf=true|false])
  set headers for outgoing INVITE on B leg
  replace_crlf=true for replacing \r\n with CRLF
  e.g. 
  B2B.setHeaders("P-One: value\r\nP-Two: anothervalue", true)

 setPrompts(name) 
   if more than one prompt sets are loaded

 set($var=value)
  e.g.  set($var="text"); set($var=$var2); set($var=#key)
 sets($var=value)
  e.g.  set($var="text and some $variable and some #param");
 var($dstvar=srcvarname)
  e.g.  var($dstvar=$var_counter)
 eval($var=value) 
  evaluate expression (only simple binary + and - supported)
  e.g.  set($var=1+5); set($var=$var2); set($var=#key)
 append($var, value)
 e.g. append($var, "text"); append($var, #key);
      append($var, @select); append($var, $var2);
 substr($var, pos)
  e.g. substr($myvar, 5);

 inc($var)
 clear($var)
 clearArray($var)
  clears all var.* variables

 log(level, text)
   e.g. log(1, $var1)
 -- log all variables:
 logVars(level) 
 -- log all selects:
 logSelects(level) 
 -- log all Params (only in actions of a transition):
 logParams(level) 
 -- log everything:
 logAll(level) 

 setTimer(timer_id, timeout)
   e.g. setTimer(1, $timeout)
   * sets $errno (arg,config)
 removeTimer(timer_id)
   * sets $errno (arg,config)
 removeTimers()
   * sets $errno (config)

  DI(factory, function [, params...])
  e.g. DI(factory, function, $var_param, (int)int_param, "str param", @select_par, (array)arrayname, (struct)structname, (json)json_object...)
       DI(user_timer, setTimer, (int)1, (int)5, @local_tag);

       set($sweets.candy="nice");
       set($sweets.fruit="superb");
       set($sweets.cake.tahini="great");
       DI(myfactory, myfunc, (struct)sweets);

       set($bi[0]="ba");
       set($bi[1]="butzki");
       DI(myfactory, myfunc, (array)bi);
        
       set($js="{"x":"y", "a": 1}");
       DI(myfactory, myfunc, (json)$js);

   * sets $errno (arg,config)

  DIgetResult(factory, function, param,...)
    saves result from DI call to DI_res or DI_res0, DI_res1, ...
   * sets $errno (arg,config)

  throw(<type>[,arg1=val1;arg2=val2;...])
   e.g. throw(bad_command),  throw(bad_command,cmd=help;reason=whynot)

  throwOnError()

  registerEventQueue(queue_name)
    register session to receive events under the name queue_name
    WARNING: make sure to unregister the event queue before ending the session!

  unregisterEventQueue(queue_name)
    unregister events queue queue_name

============================= 
conditions:
 
 test(#key == 1)
 test(#key == prefix*)
 test(#key != 1)
 test(#key < 1)
 test(#key > 1)

 test($var == 1)
 test($var == prefix*)
 test($var != 1)
 test($var < 1)
 test($var < 1)

 test(len($var) < len(#key))
 test(len($var) < len(@user))

 -- like test(expr), but only on key press
 key or keyTest(expr)
 timer or timerTest(expr)
 noAudio or noAudioTest(expr)
 separator or separatorTest(expr)
  e.g. separatorTest(#id == 5)

 event or eventTest(expr)

 keyPress(no) 
  -- bye received: 
 hangup  

  -- event is invite (only with run_invite_event):
 invite
  -- event is ringing, 180 (only with run_invite_event):
 ringing
  -- event is early session, 183 (only with run_invite_event):
 early
  -- event is failed call (only with run_invite_event):
 failed
  -- event is start of session (with run_invite_event, otherwise its always true):
 sessionStart

 -- event is startup
 startup

 -- event is reload
 startup

 -- event is system event
 system

 B2B.otherReply 
   Reply on other leg received (see AmB2BSession)
    #code    - reply code
    #reason  - reply reason
    #hdrs    - headers
     
 B2B.otherBye
   BYE on other leg received
    #hdrs    - headers

=============================
@selects :
 local_tag
 user
 domain
 remote_tag
 callid
 local_uri
 remote_uri
=============================
imports:
 module imported with import(mod_name); loads mod_name.so in 
 module load path. modules provide conditions and actions.
 modules' actions/conditions-factory is checked first 
 (modules can override core conditions/actions)
=============================
special variables:
    connect_session     "0" -> after the start event (initial transition):
                                  do not connect session to 
                                  media processor on start

                            -> after the invite event:
                                  do not reply with 200 OK and do not 
                                  connect session to media processor on start
    
=============================
errors:
   actions set $errno
     #define DSM_ERRNO_OK          ""
     #define DSM_ERRNO_FILE        "1"
     #define DSM_ERRNO_UNKNOWN_ARG "2"
     #define DSM_ERRNO_GENERAL     "99"
     ...
