diff --git a/apps/dsm/DSM.cpp b/apps/dsm/DSM.cpp index 2ec2847b..1923e977 100644 --- a/apps/dsm/DSM.cpp +++ b/apps/dsm/DSM.cpp @@ -172,6 +172,22 @@ int DSMFactory::onLoad() return -1; } } + + string RegisterDiags = cfg.getParameter("register_apps"); + vector register_names = explode(RegisterDiags, ","); + for (vector::iterator it= + register_names.begin(); it != register_names.end(); it++) { + if (diags.hasDiagram(*it)) { + bool res = AmPlugIn::instance()->registerFactory4App(*it,this); + if(res) + INFO("DSM state machine registered: %s.\n", + it->c_str()); + } else { + ERROR("trying to register application '%s' which is not loaded.\n", + it->c_str()); + return -1; + } + } InboundStartDiag = cfg.getParameter("inbound_start_diag"); if (InboundStartDiag.empty()) { @@ -200,21 +216,35 @@ void DSMFactory::prepareSession(DSMDialog* s) { AmSession* DSMFactory::onInvite(const AmSipRequest& req) { - if (InboundStartDiag.empty()) { - ERROR("no inbound calls allowed\n"); - throw AmSession::Exception(488, "Not Acceptable Here"); + string start_diag; + if (req.cmd == MOD_NAME) { + if (InboundStartDiag.empty()) { + ERROR("no inbound calls allowed\n"); + throw AmSession::Exception(488, "Not Acceptable Here"); + } + start_diag = InboundStartDiag; + } else { + start_diag = req.cmd; } - DSMDialog* s = new DSMDialog(prompts, diags, InboundStartDiag, NULL); + + DSMDialog* s = new DSMDialog(prompts, diags, start_diag, NULL); prepareSession(s); return s; } AmSession* DSMFactory::onInvite(const AmSipRequest& req, - AmArg& session_params) + AmArg& session_params) { - if (OutboundStartDiag.empty()) { - ERROR("no outbound calls allowed\n"); + + string start_diag; + + if (req.cmd == MOD_NAME) { + if (OutboundStartDiag.empty()) { + ERROR("no outbound calls allowed\n"); throw AmSession::Exception(488, "Not Acceptable Here"); + } + } else { + start_diag = req.cmd; } UACAuthCred* cred = NULL; @@ -224,7 +254,7 @@ AmSession* DSMFactory::onInvite(const AmSipRequest& req, cred = dynamic_cast(cred_obj); } - DSMDialog* s = new DSMDialog(prompts, diags, OutboundStartDiag, cred); + DSMDialog* s = new DSMDialog(prompts, diags, start_diag, cred); prepareSession(s); if (NULL == cred) { diff --git a/apps/dsm/DSMChartReader.cpp b/apps/dsm/DSMChartReader.cpp index c05443cc..5b8b7cbc 100644 --- a/apps/dsm/DSMChartReader.cpp +++ b/apps/dsm/DSMChartReader.cpp @@ -112,13 +112,21 @@ DSMAction* DSMChartReader::actionFromToken(const string& str) { return core_mod.getAction(str); } -DSMCondition* DSMChartReader::conditionFromToken(const string& str) { +DSMCondition* DSMChartReader::conditionFromToken(const string& str, bool invert) { for (vector::iterator it= mods.begin(); it!= mods.end(); it++) { DSMCondition* c=(*it)->getCondition(str); - if (c) return c; + if (c) { + c->invert = invert; + return c; + } } - return core_mod.getCondition(str); + + DSMCondition* c = core_mod.getCondition(str); + if (c) + c->invert = invert; + + return c; } void splitCmd(const string& from_str, @@ -332,8 +340,15 @@ bool DSMChartReader::decode(DSMStateDiagram* e, const string& chart, } continue; } + + if (token == "not") { + cl->invert_next = !cl->invert_next; + continue; + } + // DBG("new condition: '%s'\n", token.c_str()); - DSMCondition* c = conditionFromToken(token); + DSMCondition* c = conditionFromToken(token, cl->invert_next); + cl->invert_next = false; if (!c) return false; diff --git a/apps/dsm/DSMChartReader.h b/apps/dsm/DSMChartReader.h index b56f5ec4..e28b1ca0 100644 --- a/apps/dsm/DSMChartReader.h +++ b/apps/dsm/DSMChartReader.h @@ -69,8 +69,9 @@ class ActionList : public DSMElement { }; struct DSMConditionList : public DSMElement { - DSMConditionList() { } + DSMConditionList() : invert_next(false) { } vector conditions; + bool invert_next; }; class DSMChartReader { @@ -80,7 +81,7 @@ class DSMChartReader { string getToken(string str, size_t& pos); DSMAction* actionFromToken(const string& str); - DSMCondition* conditionFromToken(const string& str); + DSMCondition* conditionFromToken(const string& str, bool invert); bool importModule(const string& mod_cmd, const string& mod_path); vector mods; diff --git a/apps/dsm/DSMStateDiagramCollection.cpp b/apps/dsm/DSMStateDiagramCollection.cpp index 6146f5a9..d2dc4955 100644 --- a/apps/dsm/DSMStateDiagramCollection.cpp +++ b/apps/dsm/DSMStateDiagramCollection.cpp @@ -69,6 +69,15 @@ bool DSMStateDiagramCollection::loadFile(const string& filename, const string& n return true; } +bool DSMStateDiagramCollection::hasDiagram(const string& name) { + for (vector::iterator it= + diags.begin(); it != diags.end(); it++) + if (it->getName() == name) + return true; + + return false; +} + void DSMStateDiagramCollection::addToEngine(DSMStateEngine* e) { DBG("adding %zd diags to engine\n", diags.size()); for (vector ::iterator it = diff --git a/apps/dsm/DSMStateDiagramCollection.h b/apps/dsm/DSMStateDiagramCollection.h index e83bedba..899e2658 100644 --- a/apps/dsm/DSMStateDiagramCollection.h +++ b/apps/dsm/DSMStateDiagramCollection.h @@ -45,6 +45,7 @@ class DSMStateDiagramCollection bool loadFile(const string& filename, const string& name, const string& mod_path); void addToEngine(DSMStateEngine* e); + bool hasDiagram(const string& name); }; #endif diff --git a/apps/dsm/DSMStateEngine.cpp b/apps/dsm/DSMStateEngine.cpp index 2d00df24..d59e9f11 100644 --- a/apps/dsm/DSMStateEngine.cpp +++ b/apps/dsm/DSMStateEngine.cpp @@ -28,6 +28,7 @@ #include "DSMStateEngine.h" #include "DSMModule.h" +#include "AmUtils.h" #include "AmSession.h" #include "log.h" @@ -63,25 +64,53 @@ void DSMStateDiagram::addState(const State& state, bool is_initial) { } bool DSMStateDiagram::addTransition(const DSMTransition& trans) { - DBG("adding Transition '%s' %s -()-> %s\n", + DBG("adding Transition '%s' %s -(...)-> %s\n", trans.name.c_str(), trans.from_state.c_str(), trans.to_state.c_str()); for (vector::const_iterator it= trans.precond.begin(); it != trans.precond.end(); it++) { - DBG(" DSMCondition '%s'\n", (*it)->name.c_str()); + DBG(" DSMCondition %s'%s'\n", + (*it)->invert?"not ":"", (*it)->name.c_str()); } for (vector::const_iterator it= trans.actions.begin(); it != trans.actions.end(); it++) { DBG(" Action '%s'\n", (*it)->name.c_str()); } - State* source_st = getState(trans.from_state); - if (!source_st) { - ERROR("state '%s' for transition '%s' not found\n", - trans.from_state.c_str(), trans.name.c_str()); - return false; + vector from_states; + + if (trans.from_state.find_first_of("(") != string::npos) { + + string states = trans.from_state; + if (states.length() && states[0] == '(') + states = states.substr(1); + if (states.length() && states[states.length()-1] == ')') + states = states.substr(0, states.length()-1); + + from_states = explode(states, ","); + for (vector::iterator it=from_states.begin(); + it != from_states.end(); it++) { + if (it->length() && (*it)[0] == ' ') + *it = it->substr(1); + if (it->length() && (*it)[it->length()-1] == ' ') + *it = it->substr(0, it->length()-1); + } + + } else { + from_states.push_back(trans.from_state); } - - source_st->transitions.push_back(trans); + + for (vector::iterator it= + from_states.begin(); it != from_states.end(); it++) { + State* source_st = getState(*it); + if (!source_st) { + ERROR("state '%s' for transition '%s' not found\n", + it->c_str(), trans.name.c_str()); + return false; + } + + source_st->transitions.push_back(trans); + } + return true; } @@ -183,6 +212,13 @@ bool DSMStateEngine::init(AmSession* sess, const string& startDiagram, return true; } +bool DSMCondition::_match(AmSession* sess, + DSMCondition::EventType event, + map* event_params) { + // or xor + return invert?(!match(sess,event,event_params)):match(sess,event,event_params); +} + bool DSMCondition::match(AmSession* sess, DSMCondition::EventType event, map* event_params) { @@ -220,7 +256,7 @@ void DSMStateEngine::runEvent(AmSession* sess, vector::iterator con=tr->precond.begin(); while (con!=tr->precond.end()) { - if (!(*con)->match(sess, event, event_params)) + if (!(*con)->_match(sess, event, event_params)) break; con++; } diff --git a/apps/dsm/DSMStateEngine.h b/apps/dsm/DSMStateEngine.h index 6788895a..ed7b95f2 100644 --- a/apps/dsm/DSMStateEngine.h +++ b/apps/dsm/DSMStateEngine.h @@ -73,12 +73,17 @@ class DSMCondition PlaylistSeparator }; - DSMCondition() { } + bool invert; + + DSMCondition() : invert(false) { } virtual ~DSMCondition() { } EventType type; map params; + bool _match(AmSession* sess, DSMCondition::EventType event, + map* event_params); + virtual bool match(AmSession* sess, DSMCondition::EventType event, map* event_params); }; diff --git a/apps/dsm/doc/dsm_syntax.txt b/apps/dsm/doc/dsm_syntax.txt index 63373576..94988689 100644 --- a/apps/dsm/doc/dsm_syntax.txt +++ b/apps/dsm/doc/dsm_syntax.txt @@ -15,7 +15,9 @@ import(mod_name); } ] ; -transition name s1 - [ { condition; condition; ... } ] [/ { action; action; ...} ] -> s2; +transition name s1 - [ { [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) @@ -41,8 +43,8 @@ actions: setPromptSet(name) if more prompt sets are loaded - set($var, value) - e.g. set($var, "text"); set($var, $var2); set($var, #key) + set($var=value) + e.g. set($var="text"); set($var=$var2); set($var=#key) append($var, value) e.g. append($var, "text"); append($var, #key); append($var, @select); append($var, $var2); diff --git a/apps/dsm/doc/dsm_todo.txt b/apps/dsm/doc/dsm_todo.txt index 1dc9bef4..60101c84 100644 --- a/apps/dsm/doc/dsm_todo.txt +++ b/apps/dsm/doc/dsm_todo.txt @@ -2,10 +2,13 @@ o checking of FSM consitency (e.g. target state names) o better error reporting in script compilation (e.g. line number) o better error handling (exceptions) - o 'not' operator on conditions + x 'not' operator on conditions o 'or' operator x provide session init function for modules o embed python interpreter in module ? -> py( ... python code ... ) condition and action o correct en/decode DI args (e.g. arrays) + o replace DSMSession::map var with map + x register scripts as app o mod_mysql + o session creation from module diff --git a/apps/dsm/etc/dsm.conf b/apps/dsm/etc/dsm.conf index a70c9535..87142a7e 100644 --- a/apps/dsm/etc/dsm.conf +++ b/apps/dsm/etc/dsm.conf @@ -3,6 +3,10 @@ diag_path=/usr/local/lib/sems/dsm/ load_diags=inbound_call,outbound_call +# register these diagrams as 'application' in SEMS +# so it can be used in application= in sems.conf +#register_apps=inbound_cann,outbound_call + # for import(mod_name) mod_path=/usr/local/lib/sems/dsm/