diff --git a/apps/dsm/DSMCall.cpp b/apps/dsm/DSMCall.cpp index 9ba196b9..dafed428 100644 --- a/apps/dsm/DSMCall.cpp +++ b/apps/dsm/DSMCall.cpp @@ -57,10 +57,6 @@ DSMCall::~DSMCall() for (set::iterator it= used_prompt_sets.begin(); it != used_prompt_sets.end(); it++) (*it)->cleanup((long)this); - -// for (map::iterator it= -// prompt_sets.begin(); it != prompt_sets.end(); it++) -// it->second->cleanup((long)this); } /** returns whether var exists && var==value*/ @@ -192,7 +188,10 @@ void DSMCall::onDtmf(int event, int duration_msec) { void DSMCall::onBye(const AmSipRequest& req) { DBG("onBye\n"); - engine.runEvent(this, DSMCondition::Hangup, NULL); + map params; + params["headers"] = req.hdrs; + + engine.runEvent(this, DSMCondition::Hangup, ¶ms); } void DSMCall::process(AmEvent* event) @@ -246,14 +245,14 @@ void DSMCall::playPrompt(const string& name, bool loop) { if ((var["prompts.default_fallback"] != "yes") || default_prompts->addToPlaylist(name, (long)this, playlist, /*front =*/ false, loop)) { - DBG("checked [%p]\n", default_prompts); - SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG); + DBG("checked [%p]\n", default_prompts); + throw DSMException("prompt", "name", name); } else { used_prompt_sets.insert(default_prompts); - SET_ERRNO(DSM_ERRNO_OK); + SET_RES(DSM_RES_OK); } } else { - SET_ERRNO(DSM_ERRNO_OK); + SET_RES(DSM_RES_OK); } } @@ -273,7 +272,9 @@ void DSMCall::playFile(const string& name, bool loop, bool front) { ERROR("audio file '%s' could not be opened for reading.\n", name.c_str()); delete af; - SET_ERRNO(DSM_ERRNO_FILE); + + throw DSMException("file", "path", name); + return; } if (loop) @@ -285,7 +286,7 @@ void DSMCall::playFile(const string& name, bool loop, bool front) { playlist.addToPlaylist(new AmPlaylistItem(af, NULL)); audiofiles.push_back(af); - SET_ERRNO(DSM_ERRNO_OK); + SET_RES(DSM_RES_OK); } void DSMCall::recordFile(const string& name) { @@ -299,28 +300,28 @@ void DSMCall::recordFile(const string& name) { name.c_str()); delete rec_file; rec_file = NULL; - SET_ERRNO(DSM_ERRNO_FILE); + throw DSMException("file", "path", name); return; } setInput(rec_file); - SET_ERRNO(DSM_ERRNO_OK); + SET_RES(DSM_RES_OK); } unsigned int DSMCall::getRecordLength() { if (!rec_file) { - SET_ERRNO(DSM_ERRNO_FILE); + SET_RES(DSM_RES_SCRIPT); return 0; } - SET_ERRNO(DSM_ERRNO_OK); + SET_RES(DSM_RES_OK); return rec_file->getLength(); } unsigned int DSMCall::getRecordDataSize() { if (!rec_file) { - SET_ERRNO(DSM_ERRNO_FILE); + SET_RES(DSM_RES_SCRIPT); return 0; } - SET_ERRNO(DSM_ERRNO_OK); + SET_RES(DSM_RES_OK); return rec_file->getDataSize(); } @@ -330,10 +331,10 @@ void DSMCall::stopRecord() { rec_file->close(); delete rec_file; rec_file = NULL; - SET_ERRNO(DSM_ERRNO_OK); + SET_RES(DSM_RES_OK); } else { WARN("stopRecord: we are not recording\n"); - SET_ERRNO(DSM_ERRNO_FILE); + SET_RES(DSM_RES_SCRIPT); return; } } @@ -343,8 +344,10 @@ void DSMCall::addPromptSet(const string& name, if (prompt_set) { DBG("adding prompt set '%s'\n", name.c_str()); prompt_sets[name] = prompt_set; + SET_RES(DSM_RES_OK); } else { ERROR("trying to add NULL prompt set\n"); + SET_RES(DSM_RES_INTERNAL); } } @@ -359,21 +362,21 @@ void DSMCall::setPromptSet(const string& name) { if (it == prompt_sets.end()) { ERROR("prompt set %s unknown\n", name.c_str()); - SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG); + throw DSMException("prompt", "name", name); return; } DBG("setting prompt set '%s'\n", name.c_str()); used_prompt_sets.insert(prompts); prompts = it->second; - SET_ERRNO(DSM_ERRNO_OK); + SET_RES(DSM_RES_OK); } void DSMCall::addSeparator(const string& name, bool front) { unsigned int id = 0; if (str2i(name, id)) { - SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG); + SET_RES(DSM_RES_UNKNOWN_ARG); return; } @@ -384,7 +387,7 @@ void DSMCall::addSeparator(const string& name, bool front) { playlist.addToPlaylist(new AmPlaylistItem(sep, sep)); // for garbage collector audiofiles.push_back(sep); - SET_ERRNO(DSM_ERRNO_OK); + SET_RES(DSM_RES_OK); } void DSMCall::transferOwnership(DSMDisposable* d) { diff --git a/apps/dsm/DSMCoreModule.cpp b/apps/dsm/DSMCoreModule.cpp index fcef7870..e1a7bd17 100644 --- a/apps/dsm/DSMCoreModule.cpp +++ b/apps/dsm/DSMCoreModule.cpp @@ -183,9 +183,9 @@ EXEC_ACTION_START(SCPostEventAction){ DBG("posting event to session '%s'\n", sess_id.c_str()); if (!AmSessionContainer::instance()->postEvent(sess_id, ev)) - sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG); + sc_sess->SET_RES(DSM_RES_UNKNOWN_ARG); else - sc_sess->SET_ERRNO(DSM_ERRNO_OK); + sc_sess->SET_RES(DSM_RES_OK); } EXEC_ACTION_END; CONST_ACTION_2P(SCPlayFileAction, ',', true); @@ -219,6 +219,7 @@ EXEC_ACTION_START(SCGetRecordLengthAction) { if (varname.empty()) varname = "record_length"; sc_sess->var[varname]=int2str(sc_sess->getRecordLength()); + sc_sess->SET_RES(DSM_RES_OK); } EXEC_ACTION_END; EXEC_ACTION_START(SCGetRecordDataSizeAction) { @@ -232,31 +233,38 @@ EXEC_ACTION_START(SCClosePlaylistAction) { bool notify = resolveVars(arg, sess, sc_sess, event_params) == "true"; sc_sess->closePlaylist(notify); + sc_sess->SET_RES(DSM_RES_OK); } EXEC_ACTION_END; EXEC_ACTION_START(SCConnectMediaAction) { sc_sess->connectMedia(); + sc_sess->SET_RES(DSM_RES_OK); } EXEC_ACTION_END; EXEC_ACTION_START(SCDisconnectMediaAction) { sc_sess->disconnectMedia(); + sc_sess->SET_RES(DSM_RES_OK); } EXEC_ACTION_END; EXEC_ACTION_START(SCMuteAction) { sc_sess->mute(); + sc_sess->SET_RES(DSM_RES_OK); } EXEC_ACTION_END; EXEC_ACTION_START(SCUnmuteAction) { sc_sess->unmute(); + sc_sess->SET_RES(DSM_RES_OK); } EXEC_ACTION_END; EXEC_ACTION_START(SCEnableDTMFDetection) { sess->setDtmfDetectionEnabled(true); + sc_sess->SET_RES(DSM_RES_OK); } EXEC_ACTION_END; EXEC_ACTION_START(SCDisableDTMFDetection) { sess->setDtmfDetectionEnabled(false); + sc_sess->SET_RES(DSM_RES_OK); } EXEC_ACTION_END; CONST_ACTION_2P(SCThrowAction, ',', true); @@ -328,11 +336,13 @@ EXEC_ACTION_START(SCLogAction) { unsigned int lvl; if (str2i(resolveVars(par1, sess, sc_sess, event_params), lvl)) { ERROR("unknown log level '%s'\n", par1.c_str()); + sc_sess->SET_RES(DSM_RES_UNKNOWN_ARG); return false; } string l_line = resolveVars(par2, sess, sc_sess, event_params).c_str(); _LOG((int)lvl, "FSM: %s '%s'\n", (par2 != l_line)?par2.c_str():"", l_line.c_str()); + sc_sess->SET_RES(DSM_RES_OK); } EXEC_ACTION_END; EXEC_ACTION_START(SCLogVarsAction) { @@ -348,6 +358,7 @@ EXEC_ACTION_START(SCLogVarsAction) { _LOG((int)lvl, "FSM: $%s='%s'\n", it->first.c_str(), it->second.c_str()); } _LOG((int)lvl, "FSM: variables end ---\n"); + sc_sess->SET_RES(DSM_RES_OK); } EXEC_ACTION_END; CONST_ACTION_2P(SCSetAction,'=', false); @@ -358,6 +369,7 @@ EXEC_ACTION_START(SCSetAction) { sc_sess->var[var_name] = resolveVars(par2, sess, sc_sess, event_params); DBG("set $%s='%s'\n", var_name.c_str(), sc_sess->var[var_name].c_str()); + sc_sess->SET_RES(DSM_RES_OK); } EXEC_ACTION_END; CONST_ACTION_2P(SCSetVarAction,'=', false); @@ -366,6 +378,7 @@ EXEC_ACTION_START(SCSetVarAction) { sc_sess->var[var_name] = resolveVars(par2, sess, sc_sess, event_params); DBG("set $%s='%s'\n", var_name.c_str(), sc_sess->var[var_name].c_str()); + sc_sess->SET_RES(DSM_RES_OK); } EXEC_ACTION_END; @@ -386,6 +399,7 @@ EXEC_ACTION_START(SCClearAction) { arg.substr(1) : arg; DBG("clear variable '%s'\n", var_name.c_str()); sc_sess->var.erase(var_name); + sc_sess->SET_RES(DSM_RES_OK); } EXEC_ACTION_END; @@ -398,6 +412,7 @@ EXEC_ACTION_START(SCAppendAction) { DBG("$%s now '%s'\n", var_name.c_str(), sc_sess->var[var_name].c_str()); + sc_sess->SET_RES(DSM_RES_OK); } EXEC_ACTION_END; CONST_ACTION_2P(SCSubStrAction,',', false); @@ -408,19 +423,20 @@ EXEC_ACTION_START(SCSubStrAction) { if (str2i(resolveVars(par2, sess, sc_sess, event_params), pos)) { ERROR("substr length '%s'\n", resolveVars(par2, sess, sc_sess, event_params).c_str()); - sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG); + sc_sess->SET_RES(DSM_RES_UNKNOWN_ARG); return false; } try { sc_sess->var[var_name] = sc_sess->var[var_name].substr(pos); } catch(...) { ERROR("in substr\n"); - sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG); + sc_sess->SET_RES(DSM_RES_UNKNOWN_ARG); return false; } DBG("$%s now '%s'\n", var_name.c_str(), sc_sess->var[var_name].c_str()); + sc_sess->SET_RES(DSM_RES_OK); } EXEC_ACTION_END; EXEC_ACTION_START(SCIncAction) { @@ -432,6 +448,8 @@ EXEC_ACTION_START(SCIncAction) { DBG("inc: $%s now '%s'\n", var_name.c_str(), sc_sess->var[var_name].c_str()); + + sc_sess->SET_RES(DSM_RES_OK); } EXEC_ACTION_END; CONST_ACTION_2P(SCSetTimerAction,',', false); @@ -441,6 +459,7 @@ EXEC_ACTION_START(SCSetTimerAction) { if (str2i(resolveVars(par1, sess, sc_sess, event_params), timerid)) { ERROR("timer id '%s' not decipherable\n", resolveVars(par1, sess, sc_sess, event_params).c_str()); + sc_sess->SET_RES(DSM_RES_UNKNOWN_ARG); return false; } @@ -448,6 +467,7 @@ EXEC_ACTION_START(SCSetTimerAction) { if (str2i(resolveVars(par2, sess, sc_sess, event_params), timeout)) { ERROR("timeout value '%s' not decipherable\n", resolveVars(par2, sess, sc_sess, event_params).c_str()); + sc_sess->SET_RES(DSM_RES_UNKNOWN_ARG); return false; } @@ -457,11 +477,13 @@ EXEC_ACTION_START(SCSetTimerAction) { if(!user_timer_fact) { ERROR("load sess_timer module for timers.\n"); + sc_sess->SET_RES(DSM_RES_ADMIN); return false; } AmDynInvoke* user_timer = user_timer_fact->getInstance(); if(!user_timer) { ERROR("load sess_timer module for timers.\n"); + sc_sess->SET_RES(DSM_RES_ADMIN); return false; } @@ -471,6 +493,7 @@ EXEC_ACTION_START(SCSetTimerAction) { di_args.push(sess->getLocalTag().c_str()); user_timer->invoke("setTimer", di_args, ret); + sc_sess->SET_RES(DSM_RES_OK); } EXEC_ACTION_END; @@ -480,6 +503,7 @@ EXEC_ACTION_START(SCRemoveTimerAction) { if (str2i(resolveVars(arg, sess, sc_sess, event_params), timerid)) { ERROR("timer id '%s' not decipherable\n", resolveVars(arg, sess, sc_sess, event_params).c_str()); + sc_sess->SET_RES(DSM_RES_ADMIN); return false; } @@ -488,11 +512,13 @@ EXEC_ACTION_START(SCRemoveTimerAction) { AmPlugIn::instance()->getFactory4Di("user_timer"); if(!user_timer_fact) { + sc_sess->SET_RES(DSM_RES_ADMIN); ERROR("load sess_timer module for timers.\n"); return false; } AmDynInvoke* user_timer = user_timer_fact->getInstance(); if(!user_timer) { + sc_sess->SET_RES(DSM_RES_ADMIN); ERROR("load sess_timer module for timers.\n"); return false; } @@ -502,6 +528,7 @@ EXEC_ACTION_START(SCRemoveTimerAction) { di_args.push(sess->getLocalTag().c_str()); user_timer->invoke("removeTimer", di_args, ret); + sc_sess->SET_RES(DSM_RES_OK); } EXEC_ACTION_END; EXEC_ACTION_START(SCRemoveTimersAction) { @@ -513,11 +540,13 @@ EXEC_ACTION_START(SCRemoveTimersAction) { if(!user_timer_fact) { ERROR("load sess_timer module for timers.\n"); + sc_sess->SET_RES(DSM_RES_ADMIN); return false; } AmDynInvoke* user_timer = user_timer_fact->getInstance(); if(!user_timer) { ERROR("load sess_timer module for timers.\n"); + sc_sess->SET_RES(DSM_RES_ADMIN); return false; } @@ -525,6 +554,7 @@ EXEC_ACTION_START(SCRemoveTimersAction) { di_args.push(sess->getLocalTag().c_str()); user_timer->invoke("removeUserTimers", di_args, ret); + sc_sess->SET_RES(DSM_RES_OK); } EXEC_ACTION_END; @@ -648,6 +678,7 @@ EXEC_ACTION_START(SCDIAction) { if (params.size() < 2) { ERROR("DI needs at least: mod_name, " "function_name (in '%s'\n", name.c_str()); + sc_sess->SET_RES(DSM_RES_UNKNOWN_ARG); return false; } @@ -658,11 +689,13 @@ EXEC_ACTION_START(SCDIAction) { if(!fact) { ERROR("load module for factory '%s'.\n", fact_name.c_str()); + sc_sess->SET_RES(DSM_RES_ADMIN); return false; } AmDynInvoke* di_inst = fact->getInstance(); if(!di_inst) { ERROR("load module for factory '%s'\n", fact_name.c_str()); + sc_sess->SET_RES(DSM_RES_ADMIN); return false; } p_it++; @@ -686,6 +719,7 @@ EXEC_ACTION_START(SCDIAction) { } else { ERROR("converting value '%s' to int\n", p.c_str()); + sc_sess->SET_RES(DSM_RES_UNKNOWN_ARG); return false; } } else { @@ -701,21 +735,26 @@ EXEC_ACTION_START(SCDIAction) { } catch (const AmDynInvoke::NotImplemented& ni) { ERROR("not implemented DI function '%s'\n", ni.what.c_str()); + sc_sess->SET_RES(DSM_RES_UNKNOWN_ARG); return false; } catch (const AmArg::OutOfBoundsException& oob) { ERROR("out of bounds in DI call '%s'\n", name.c_str()); + sc_sess->SET_RES(DSM_RES_UNKNOWN_ARG); return false; } catch (const AmArg::TypeMismatchException& oob) { ERROR("type mismatch in DI call '%s'\n", name.c_str()); + sc_sess->SET_RES(DSM_RES_UNKNOWN_ARG); return false; } catch (...) { ERROR("unexpected Exception in DI call '%s'\n", name.c_str()); + sc_sess->SET_RES(DSM_RES_UNKNOWN); return false; } + bool flag_error = false; if (get_res) { // rudimentary variables conversion... if (isArgCStr(sc_sess->di_res)) @@ -736,13 +775,21 @@ EXEC_ACTION_START(SCDIAction) { } break; default: { ERROR("unsupported AmArg return type!"); + flag_error = true; + sc_sess->SET_RES(DSM_RES_UNKNOWN); } } } } else { ERROR("unsupported AmArg return type!"); + flag_error = true; + sc_sess->SET_RES(DSM_RES_UNKNOWN); } } + if (!flag_error) { + sc_sess->SET_RES(DSM_RES_OK); + } + } EXEC_ACTION_END; @@ -751,14 +798,17 @@ EXEC_ACTION_START(SCB2BConnectCalleeAction) { string remote_party = resolveVars(par1, sess, sc_sess, event_params); string remote_uri = resolveVars(par2, sess, sc_sess, event_params); sc_sess->B2BconnectCallee(remote_party, remote_uri); + sc_sess->SET_RES(DSM_RES_OK); } EXEC_ACTION_END; EXEC_ACTION_START(SCB2BTerminateOtherLegAction) { sc_sess->B2BterminateOtherLeg(); + sc_sess->SET_RES(DSM_RES_OK); } EXEC_ACTION_END; CONST_ACTION_2P(SCB2BReinviteAction,',', true); EXEC_ACTION_START(SCB2BReinviteAction) { bool updateSDP = par1=="true"; sess->sendReinvite(updateSDP, par2); + sc_sess->SET_RES(DSM_RES_OK); } EXEC_ACTION_END; diff --git a/apps/dsm/DSMSession.h b/apps/dsm/DSMSession.h index 5ec10037..39771050 100644 --- a/apps/dsm/DSMSession.h +++ b/apps/dsm/DSMSession.h @@ -54,6 +54,17 @@ using std::map; #define SET_ERRNO(new_errno) \ var["errno"] = new_errno +#define DSM_RES_OK "" +#define DSM_RES_UNKNOWN "1" // unknown error +#define DSM_RES_UNKNOWN_ARG "2" // unknown argument/argument error +#define DSM_RES_ADMIN "3" // configuration error +#define DSM_RES_SCRIPT "4" // DSM script error +#define DSM_RES_INTERNAL "5" // internal error + +#define SET_RES(new_res) \ + var["res"] = new_res + + class DSMDisposable; class AmPlaylistItem; diff --git a/apps/dsm/DSMStateEngine.h b/apps/dsm/DSMStateEngine.h index e219f150..8d994df4 100644 --- a/apps/dsm/DSMStateEngine.h +++ b/apps/dsm/DSMStateEngine.h @@ -167,6 +167,18 @@ class DSMException { DSMException(const string& e_type) { params["type"] = e_type; } + DSMException(const string& e_type, + const string& key1, const string& val1) + { params["type"] = e_type; + params[key1] = val1; } + + DSMException(const string& e_type, + const string& key1, const string& val1, + const string& key2, const string& val2) + { params["type"] = e_type; + params[key1] = val1; + params[key2] = val2; } + DSMException(map& params) : params(params) { } diff --git a/apps/dsm/doc/dsm_syntax.txt b/apps/dsm/doc/dsm_syntax.txt index ed6c74dc..b3620c20 100644 --- a/apps/dsm/doc/dsm_syntax.txt +++ b/apps/dsm/doc/dsm_syntax.txt @@ -40,14 +40,23 @@ actions: 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) - if more prompt sets are loaded + select active prompt set if more prompt sets are loaded + Throws "prompt" exeption with #name if prompt set not found playFile(filename) + Throws "file" exeption with #path if file can not be opened + playFileFront(filename) + 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 diff --git a/apps/dsm/doc/examples/test_byehdr.dsm b/apps/dsm/doc/examples/test_byehdr.dsm new file mode 100644 index 00000000..1425a54e --- /dev/null +++ b/apps/dsm/doc/examples/test_byehdr.dsm @@ -0,0 +1,7 @@ + +initial state START + enter { + playFile(wav/default_en.wav); + }; +transition "got bye" START - hangup / log(1, #headers) -> end; +state end; \ No newline at end of file diff --git a/apps/dsm/mods/mod_utils/Readme.mod_utils.txt b/apps/dsm/mods/mod_utils/Readme.mod_utils.txt index f8752417..ee4c00d1 100644 --- a/apps/dsm/mods/mod_utils/Readme.mod_utils.txt +++ b/apps/dsm/mods/mod_utils/Readme.mod_utils.txt @@ -3,13 +3,23 @@ Actions: utils.playCountRight(int cnt [, string basedir]) play count for laguages that have single digits after the 10s (like english) + Throws "file" exeption with #path if file can not be opened utils.playCountLeft(int cnt [, string basedir]) play count for laguages that have single digits befire the 10s (like german) + Throws "file" exeption with #path if file can not be opened utils.spell(string word[, string basedir]) plays each character in the word (e.g. utils.spell(321,wav/digits/) plays wav/digits/3.wav, wav/digits/2.wav, wav/digits/1.wav - like SayDigits + (like SayDigits from *) + Throws "file" exeption with #path if file can not be opened + + + utils.rand(string varname [, int modulo]) + generates random number: $varname=rand()%modulo or $varname = rand() + + utils.srand() + seed the RNG with time(). Conditions: