mirror of https://github.com/sipwise/sems.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1805 lines
56 KiB
1805 lines
56 KiB
/*
|
|
* Copyright (C) 2008 iptego GmbH
|
|
* Copyright (C) 2010 Stefan Sayer
|
|
*
|
|
* This file is part of SEMS, a free SIP media server.
|
|
*
|
|
* SEMS is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version. This program is released under
|
|
* the GPL with the additional exemption that compiling, linking,
|
|
* and/or using OpenSSL is allowed.
|
|
*
|
|
* For a license to use the SEMS software under conditions
|
|
* other than those described here, or to purchase support for this
|
|
* software, please contact iptel.org by e-mail at the following addresses:
|
|
* info@iptel.org
|
|
*
|
|
* SEMS is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "DSMCoreModule.h"
|
|
#include "DSMSession.h"
|
|
#include "AmSession.h"
|
|
#include "AmSessionContainer.h"
|
|
#include "AmUtils.h"
|
|
#include "AmEventDispatcher.h"
|
|
#include "DSM.h"
|
|
#include "AmB2BSession.h"
|
|
|
|
#include "jsonArg.h"
|
|
|
|
DSMCoreModule::DSMCoreModule() {
|
|
}
|
|
|
|
DSMAction* DSMCoreModule::getAction(const string& from_str) {
|
|
string cmd;
|
|
string params;
|
|
splitCmd(from_str, cmd, params);
|
|
|
|
DEF_CMD("repost", SCRepostAction);
|
|
DEF_CMD("jumpFSM", SCJumpFSMAction);
|
|
DEF_CMD("callFSM", SCCallFSMAction);
|
|
DEF_CMD("returnFSM", SCReturnFSMAction);
|
|
|
|
DEF_CMD("throw", SCThrowAction);
|
|
DEF_CMD("throwOnError", SCThrowOnErrorAction);
|
|
|
|
DEF_CMD("stop", SCStopAction);
|
|
|
|
DEF_CMD("playPrompt", SCPlayPromptAction);
|
|
DEF_CMD("playPromptFront", SCPlayPromptFrontAction);
|
|
DEF_CMD("playPromptLooped", SCPlayPromptLoopedAction);
|
|
DEF_CMD("playFile", SCPlayFileAction);
|
|
DEF_CMD("playFileFront", SCPlayFileFrontAction);
|
|
DEF_CMD("playSilence", SCPlaySilenceAction);
|
|
DEF_CMD("playSilenceFront", SCPlaySilenceFrontAction);
|
|
DEF_CMD("playRingtone", SCPlayRingtoneAction);
|
|
DEF_CMD("recordFile", SCRecordFileAction);
|
|
DEF_CMD("stopRecord", SCStopRecordAction);
|
|
DEF_CMD("getRecordLength", SCGetRecordLengthAction);
|
|
DEF_CMD("getRecordDataSize", SCGetRecordDataSizeAction);
|
|
DEF_CMD("flushPlaylist", SCFlushPlaylistAction);
|
|
DEF_CMD("closePlaylist", SCClosePlaylistAction); // deprecated
|
|
DEF_CMD("setInOutPlaylist", SCSetInOutPlaylistAction);
|
|
DEF_CMD("setInputPlaylist", SCSetInputPlaylistAction);
|
|
DEF_CMD("setOutputPlaylist", SCSetOutputPlaylistAction);
|
|
DEF_CMD("addSeparator", SCAddSeparatorAction);
|
|
DEF_CMD("connectMedia", SCConnectMediaAction);
|
|
DEF_CMD("disconnectMedia", SCDisconnectMediaAction);
|
|
DEF_CMD("enableReceiving", SCEnableReceivingAction);
|
|
DEF_CMD("disableReceiving", SCDisableReceivingAction);
|
|
DEF_CMD("enableForceDTMFReceiving", SCEnableForceDTMFReceiving);
|
|
DEF_CMD("disableForceDTMFReceiving", SCDisableForceDTMFReceiving);
|
|
DEF_CMD("monitorRTPTimeout", SCMonitorRTPTimeoutAction);
|
|
DEF_CMD("mute", SCMuteAction);
|
|
DEF_CMD("unmute", SCUnmuteAction);
|
|
DEF_CMD("enableDTMFDetection", SCEnableDTMFDetection);
|
|
DEF_CMD("disableDTMFDetection", SCDisableDTMFDetection);
|
|
DEF_CMD("sendDTMF", SCSendDTMFAction);
|
|
DEF_CMD("sendDTMFSequence", SCSendDTMFSequenceAction);
|
|
|
|
DEF_CMD("set", SCSetAction);
|
|
DEF_CMD("sets", SCSetSAction);
|
|
DEF_CMD("eval", SCEvalAction);
|
|
DEF_CMD("setVar", SCSetVarAction);
|
|
DEF_CMD("var", SCGetVarAction);
|
|
DEF_CMD("param", SCGetParamAction);
|
|
DEF_CMD("append", SCAppendAction);
|
|
DEF_CMD("substr", SCSubStrAction);
|
|
DEF_CMD("inc", SCIncAction);
|
|
DEF_CMD("log", SCLogAction);
|
|
DEF_CMD("logs", SCLogsAction);
|
|
DEF_CMD("dbg", SCDbgAction);
|
|
DEF_CMD("info", SCInfoAction);
|
|
DEF_CMD("warn", SCWarnAction);
|
|
DEF_CMD("error", SCErrorAction);
|
|
DEF_CMD("clear", SCClearAction);
|
|
DEF_CMD("clearStruct", SCClearStructAction);
|
|
DEF_CMD("clearArray", SCClearArrayAction);
|
|
DEF_CMD("size", SCSizeAction);
|
|
DEF_CMD("arrayIndex", SCArrayIndexAction);
|
|
DEF_CMD("logVars", SCLogVarsAction);
|
|
DEF_CMD("logParams", SCLogParamsAction);
|
|
DEF_CMD("logSelects", SCLogSelectsAction);
|
|
DEF_CMD("logAll", SCLogAllAction);
|
|
|
|
DEF_CMD("setTimer", SCSetTimerAction);
|
|
DEF_CMD("removeTimer", SCRemoveTimerAction);
|
|
DEF_CMD("removeTimers", SCRemoveTimersAction);
|
|
|
|
DEF_CMD("setPrompts", SCSetPromptsAction);
|
|
|
|
DEF_CMD("postEvent", SCPostEventAction);
|
|
|
|
DEF_CMD("registerEventQueue", SCRegisterEventQueueAction);
|
|
DEF_CMD("unregisterEventQueue", SCUnregisterEventQueueAction);
|
|
DEF_CMD("createSystemDSM", SCCreateSystemDSMAction);
|
|
|
|
DEF_CMD("removeFromString", SCRemovePatternAction);
|
|
|
|
DEF_CMD("getErrorCodePlayback", SCGetErrorCodePlaybackAction);
|
|
|
|
if (cmd == "DI") {
|
|
SCDIAction * a = new SCDIAction(params, false);
|
|
a->name = from_str;
|
|
return a;
|
|
}
|
|
|
|
if (cmd == "DIgetResult") {
|
|
SCDIAction * a = new SCDIAction(params, true);
|
|
a->name = from_str;
|
|
return a;
|
|
}
|
|
|
|
DEF_CMD("B2B.connectCallee", SCB2BConnectCalleeAction);
|
|
DEF_CMD("B2B.terminateOtherLeg", SCB2BTerminateOtherLegAction);
|
|
DEF_CMD("B2B.sendReinvite", SCB2BReinviteAction);
|
|
DEF_CMD("B2B.sendEstablishedReinvite", SCB2BSendEstablishedReinviteAction);
|
|
DEF_CMD("B2B.enableEarlyMediaRelay", SCB2BEnableEarlyMediaRelayAction);
|
|
DEF_CMD("B2B.addHeader", SCB2BAddHeaderAction);
|
|
DEF_CMD("B2B.getHeaderRequest", SCB2BGetHeaderRequestAction);
|
|
DEF_CMD("B2B.getHeaderReply", SCB2BGetHeaderReplyAction);
|
|
DEF_CMD("B2B.getHeaderParamRequest", SCB2BGetHeaderParamRequestAction);
|
|
DEF_CMD("B2B.getHeaderParamReply", SCB2BGetHeaderParamReplyAction);
|
|
DEF_CMD("B2B.removeHeader", SCB2BRemoveHeaderAction);
|
|
DEF_CMD("B2B.clearHeaders", SCB2BClearHeadersAction);
|
|
DEF_CMD("B2B.setHeaders", SCB2BSetHeadersAction);
|
|
DEF_CMD("B2B.relayEvent", SCRelayB2BEventAction);
|
|
|
|
DEF_CMD("trackObject", SCTrackObjectAction);
|
|
DEF_CMD("releaseObject", SCReleaseObjectAction);
|
|
DEF_CMD("freeObject", SCFreeObjectAction);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
DSMCondition* DSMCoreModule::getCondition(const string& from_str) {
|
|
string cmd;
|
|
string params;
|
|
splitCmd(from_str, cmd, params);
|
|
|
|
if (cmd == "keyPress") {
|
|
DSMCondition* c = new DSMCondition();
|
|
c->name = "key pressed: " + params;
|
|
c->type = DSMCondition::Key;
|
|
c->params["key"] = params;
|
|
return c;
|
|
}
|
|
|
|
if (cmd == "test")
|
|
return new TestDSMCondition(params, DSMCondition::Any);
|
|
|
|
if ((cmd == "keyTest") || (cmd == "key"))
|
|
return new TestDSMCondition(params, DSMCondition::Key);
|
|
|
|
if ((cmd == "timerTest") || (cmd == "timer"))
|
|
return new TestDSMCondition(params, DSMCondition::Timer);
|
|
|
|
if ((cmd == "noAudioTest") || (cmd == "noAudio"))
|
|
return new TestDSMCondition(params, DSMCondition::NoAudio);
|
|
|
|
if ((cmd == "separatorTest") || (cmd == "separator"))
|
|
return new TestDSMCondition(params, DSMCondition::PlaylistSeparator);
|
|
|
|
if (cmd == "hangup")
|
|
return new TestDSMCondition(params, DSMCondition::Hangup);
|
|
|
|
if ((cmd == "eventTest") || (cmd == "event"))
|
|
return new TestDSMCondition(params, DSMCondition::DSMEvent);
|
|
|
|
if (cmd == "B2Bevent")
|
|
return new TestDSMCondition(params, DSMCondition::B2BEvent);
|
|
|
|
if (cmd == "invite")
|
|
return new TestDSMCondition(params, DSMCondition::Invite);
|
|
|
|
if (cmd == "earlySession")
|
|
return new TestDSMCondition(params, DSMCondition::EarlySession);
|
|
|
|
if (cmd == "sessionStart")
|
|
return new TestDSMCondition(params, DSMCondition::SessionStart);
|
|
|
|
if (cmd == "ringing")
|
|
return new TestDSMCondition(params, DSMCondition::Ringing);
|
|
|
|
if (cmd == "early")
|
|
return new TestDSMCondition(params, DSMCondition::EarlySession);
|
|
|
|
if (cmd == "failed")
|
|
return new TestDSMCondition(params, DSMCondition::FailedCall);
|
|
|
|
if (cmd == "B2B.otherRequest")
|
|
return new TestDSMCondition(params, DSMCondition::B2BOtherRequest);
|
|
|
|
if (cmd == "B2B.otherReply")
|
|
return new TestDSMCondition(params, DSMCondition::B2BOtherReply);
|
|
|
|
if (cmd == "B2B.otherBye")
|
|
return new TestDSMCondition(params, DSMCondition::B2BOtherBye);
|
|
|
|
if (cmd == "sipRequest")
|
|
return new TestDSMCondition(params, DSMCondition::SipRequest);
|
|
|
|
if (cmd == "sipReply")
|
|
return new TestDSMCondition(params, DSMCondition::SipReply);
|
|
|
|
if (cmd == "remoteDisappeared")
|
|
return new TestDSMCondition(params, DSMCondition::RemoteDisappeared);
|
|
|
|
if (cmd == "sessionTimeout")
|
|
return new TestDSMCondition(params, DSMCondition::SessionTimeout);
|
|
|
|
if (cmd == "rtpTimeout")
|
|
return new TestDSMCondition(params, DSMCondition::RtpTimeout);
|
|
|
|
if (cmd == "jsonRpcRequest")
|
|
return new TestDSMCondition(params, DSMCondition::JsonRpcRequest);
|
|
|
|
if (cmd == "jsonRpcResponse")
|
|
return new TestDSMCondition(params, DSMCondition::JsonRpcResponse);
|
|
|
|
if (cmd == "subscription")
|
|
return new TestDSMCondition(params, DSMCondition::SIPSubscription);
|
|
|
|
if (cmd == "startup")
|
|
return new TestDSMCondition(params, DSMCondition::Startup);
|
|
|
|
if (cmd == "start")
|
|
return new TestDSMCondition(params, DSMCondition::Start);
|
|
|
|
if (cmd == "beforeDestroy")
|
|
return new TestDSMCondition(params, DSMCondition::BeforeDestroy);
|
|
|
|
if (cmd == "reload")
|
|
return new TestDSMCondition(params, DSMCondition::Reload);
|
|
|
|
if (cmd == "system")
|
|
return new TestDSMCondition(params, DSMCondition::System);
|
|
|
|
if (cmd == "rtpTimeout")
|
|
return new TestDSMCondition(params, DSMCondition::RTPTimeout);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
EXEC_ACTION_START(SCPlayPromptAction) {
|
|
sc_sess->playPrompt(resolveVars(arg, sess, sc_sess, event_params));
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCPlayPromptFrontAction) {
|
|
sc_sess->playPrompt(resolveVars(arg, sess, sc_sess, event_params), false, true);
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCSetPromptsAction) {
|
|
sc_sess->setPromptSet(resolveVars(arg, sess, sc_sess, event_params));
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_2P(SCAddSeparatorAction, ',', true);
|
|
EXEC_ACTION_START(SCAddSeparatorAction){
|
|
bool front = resolveVars(par2, sess, sc_sess, event_params) == "true";
|
|
sc_sess->addSeparator(resolveVars(par1, sess, sc_sess, event_params), front);
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCPlayPromptLoopedAction){
|
|
sc_sess->playPrompt(resolveVars(arg, sess, sc_sess, event_params), true);
|
|
} EXEC_ACTION_END;
|
|
|
|
void setEventParameters(const DSMSession* sc_sess, const string& var, VarMapT& params) {
|
|
if (var.empty())
|
|
return;
|
|
|
|
if (var == "var") {
|
|
params = sc_sess->var;
|
|
} else {
|
|
vector<string> vars = explode(var, ";");
|
|
for (vector<string>::iterator it = vars.begin(); it != vars.end(); it++) {
|
|
string varname = *it;
|
|
|
|
if (varname.length() && varname[varname.length()-1]=='.') {
|
|
DBG("adding postEvent param %s (struct)\n", varname.c_str());
|
|
|
|
map<string, string>::const_iterator lb = sc_sess->var.lower_bound(varname);
|
|
while (lb != sc_sess->var.end()) {
|
|
if ((lb->first.length() < varname.length()) ||
|
|
strncmp(lb->first.c_str(), varname.c_str(), varname.length()))
|
|
break;
|
|
params[lb->first] = lb->second;
|
|
lb++;
|
|
}
|
|
} else {
|
|
VarMapT::const_iterator v_it = sc_sess->var.find(varname);
|
|
if (v_it != sc_sess->var.end()) {
|
|
DBG("adding postEvent param %s=%s\n",
|
|
it->c_str(), v_it->second.c_str());
|
|
params[varname] = v_it->second;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CONST_ACTION_2P(SCPostEventAction, ',', true);
|
|
EXEC_ACTION_START(SCPostEventAction){
|
|
string sess_id = resolveVars(par1, sess, sc_sess, event_params);
|
|
string var = resolveVars(par2, sess, sc_sess, event_params);
|
|
DSMEvent* ev = new DSMEvent();
|
|
setEventParameters(sc_sess, var, ev->params);
|
|
|
|
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_STRERROR("event could not be posted\n");
|
|
} else {
|
|
sc_sess->CLR_ERRNO;
|
|
}
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCRelayB2BEventAction) {
|
|
AmB2BSession* b2b_sess = dynamic_cast<AmB2BSession*>(sess);
|
|
if (NULL == b2b_sess) {
|
|
throw DSMException("script", "cause", "relayEvent used without B2B call");
|
|
}
|
|
|
|
string var = resolveVars(arg, sess, sc_sess, event_params);
|
|
B2BEvent* ev = new B2BEvent(E_B2B_APP, B2BEvent::B2BApplication);
|
|
setEventParameters(sc_sess, var, ev->params);
|
|
|
|
b2b_sess->relayEvent(ev);
|
|
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_2P(SCPlayFileAction, ',', true);
|
|
EXEC_ACTION_START(SCPlayFileAction) {
|
|
bool loop =
|
|
resolveVars(par2, sess, sc_sess, event_params) == "true";
|
|
DBG("par1 = '%s', par2 = %s\n", par1.c_str(), par2.c_str());
|
|
sc_sess->playFile(resolveVars(par1, sess, sc_sess, event_params),
|
|
loop);
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_2P(SCPlayFileFrontAction, ',', true);
|
|
EXEC_ACTION_START(SCPlayFileFrontAction) {
|
|
bool loop =
|
|
resolveVars(par2, sess, sc_sess, event_params) == "true";
|
|
DBG("par1 = '%s', par2 = %s\n", par1.c_str(), par2.c_str());
|
|
sc_sess->playFile(resolveVars(par1, sess, sc_sess, event_params),
|
|
loop, true);
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCPlaySilenceAction) {
|
|
int length;
|
|
string length_str = resolveVars(arg, sess, sc_sess, event_params);
|
|
if (!str2int(length_str, length)) {
|
|
throw DSMException("core", "cause", "cannot parse number");
|
|
}
|
|
sc_sess->playSilence(length);
|
|
} EXEC_ACTION_END;
|
|
|
|
|
|
CONST_ACTION_2P(SCPlayRingtoneAction, ',', false);
|
|
EXEC_ACTION_START(SCPlayRingtoneAction) {
|
|
int length = 0, on=0, off=0, f=0, f2=0;
|
|
|
|
string varname = par1;
|
|
if (varname.length() && varname[0]=='$')
|
|
varname = varname.substr(1);
|
|
|
|
string front = resolveVars(par2, sess, sc_sess, event_params);
|
|
|
|
#define GET_VAR_INT(var_str, var_name) \
|
|
it = sc_sess->var.find(varname+"." var_str); \
|
|
if (it != sc_sess->var.end()) { \
|
|
if (!str2int(it->second, var_name)) { \
|
|
throw DSMException("core", "cause", "cannot parse number"); \
|
|
} \
|
|
}
|
|
|
|
VarMapT::iterator
|
|
|
|
GET_VAR_INT("length", length);
|
|
GET_VAR_INT("on", on);
|
|
GET_VAR_INT("off", off);
|
|
GET_VAR_INT("f", f);
|
|
GET_VAR_INT("f2", f2);
|
|
|
|
#undef GET_VAR_INT
|
|
DBG("Playing ringtone with length %d, on %d, off %d, f %d, f2 %d, front %s\n",
|
|
length, on, off, f, f2, front.c_str());
|
|
sc_sess->playRingtone(length, on, off, f, f2, front=="true");
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCPlaySilenceFrontAction) {
|
|
int length;
|
|
string length_str = resolveVars(arg, sess, sc_sess, event_params);
|
|
if (!str2int(length_str, length)) {
|
|
throw DSMException("core", "cause", "cannot parse number");
|
|
}
|
|
sc_sess->playSilence(length, true);
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCRecordFileAction) {
|
|
sc_sess->recordFile(resolveVars(arg, sess, sc_sess, event_params));
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCStopRecordAction) {
|
|
sc_sess->stopRecord();
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCGetRecordLengthAction) {
|
|
string varname = resolveVars(arg, sess, sc_sess, event_params);
|
|
if (varname.empty())
|
|
varname = "record_length";
|
|
sc_sess->var[varname]=int2str(sc_sess->getRecordLength());
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCGetRecordDataSizeAction) {
|
|
string varname = resolveVars(arg, sess, sc_sess, event_params);
|
|
if (varname.empty())
|
|
varname = "record_data_size";
|
|
sc_sess->var[varname]=int2str(sc_sess->getRecordDataSize());
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCFlushPlaylistAction) {
|
|
sc_sess->flushPlaylist();
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCClosePlaylistAction) {
|
|
WARN("closePlaylist() is deprecated - please use flushPlaylist() instead\n");
|
|
sc_sess->flushPlaylist();
|
|
} EXEC_ACTION_END;
|
|
|
|
|
|
EXEC_ACTION_START(SCSetInOutPlaylistAction) {
|
|
sc_sess->setInOutPlaylist();
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCSetInputPlaylistAction) {
|
|
sc_sess->setInputPlaylist();
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCSetOutputPlaylistAction) {
|
|
sc_sess->setOutputPlaylist();
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCConnectMediaAction) {
|
|
sc_sess->connectMedia();
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCDisconnectMediaAction) {
|
|
sc_sess->disconnectMedia();
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCEnableReceivingAction) {
|
|
DBG("enabling RTP receving in session\nb");
|
|
sess->setReceiving(true);
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCDisableReceivingAction) {
|
|
DBG("disabling RTP receving in session\nb");
|
|
sess->setReceiving(false);
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCEnableForceDTMFReceiving) {
|
|
DBG("enabling forced DTMF RTP receving in session\nb");
|
|
sess->setForceDtmfReceiving(true);
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCDisableForceDTMFReceiving) {
|
|
DBG("disabling forced DTMF RTP receving in session\nb");
|
|
sess->setForceDtmfReceiving(false);
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCMonitorRTPTimeoutAction) {
|
|
string e = resolveVars(arg, sess, sc_sess, event_params);
|
|
DBG("setting RTP stream to %smonitor RTP timeout\n", e=="true"?"":"not");
|
|
sess->RTPStream()->setMonitorRTPTimeout(e=="true");
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCMuteAction) {
|
|
sc_sess->mute();
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCUnmuteAction) {
|
|
sc_sess->unmute();
|
|
} EXEC_ACTION_END;
|
|
|
|
|
|
EXEC_ACTION_START(SCEnableDTMFDetection) {
|
|
sess->setDtmfDetectionEnabled(true);
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCDisableDTMFDetection) {
|
|
sess->setDtmfDetectionEnabled(false);
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_2P(SCThrowAction, ',', true);
|
|
EXEC_ACTION_START(SCThrowAction) {
|
|
map<string, string> e_args;
|
|
e_args["type"] = resolveVars(par1, sess, sc_sess, event_params);
|
|
DBG("throwing DSMException type '%s'\n", e_args["type"].c_str());
|
|
|
|
string e_params = resolveVars(par2, sess, sc_sess, event_params);
|
|
|
|
// inefficient param-split
|
|
vector<string> params = explode(e_params, ";");
|
|
for (vector<string>::iterator it=
|
|
params.begin(); it != params.end(); it++) {
|
|
vector<string> n = explode(*it, "=");
|
|
if (n.size()==2) {
|
|
e_args[n[0]]=n[1];
|
|
}
|
|
}
|
|
|
|
throw DSMException(e_args);
|
|
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCThrowOnErrorAction) {
|
|
if (sc_sess->var["errno"].empty())
|
|
EXEC_ACTION_STOP;
|
|
|
|
map<string, string> e_args;
|
|
e_args["type"] = sc_sess->var["errno"];
|
|
|
|
DBG("throwing DSMException type '%s'\n", e_args["type"].c_str());
|
|
e_args["text"] = sc_sess->var["strerror"];
|
|
|
|
throw DSMException(e_args);
|
|
|
|
} EXEC_ACTION_END;
|
|
|
|
|
|
EXEC_ACTION_START(SCStopAction) {
|
|
if (resolveVars(arg, sess, sc_sess, event_params) == "true") {
|
|
DBG("sending bye\n");
|
|
sess->dlg->bye();
|
|
}
|
|
sess->setStopped();
|
|
} EXEC_ACTION_END;
|
|
|
|
#define DEF_SCModActionExec(clsname) \
|
|
\
|
|
bool clsname::execute(AmSession* sess, DSMSession* sc_sess, \
|
|
DSMCondition::EventType event, \
|
|
map<string,string>* event_params) { \
|
|
return true; \
|
|
} \
|
|
|
|
DEF_SCModActionExec(SCRepostAction);
|
|
DSMAction::SEAction SCRepostAction::getSEAction(string& param,
|
|
AmSession* sess, DSMSession* sc_sess,
|
|
DSMCondition::EventType event,
|
|
map<string,string>* event_params) {
|
|
return Repost;
|
|
}
|
|
|
|
DEF_SCModActionExec(SCJumpFSMAction);
|
|
DSMAction::SEAction SCJumpFSMAction::getSEAction(string& param,
|
|
AmSession* sess, DSMSession* sc_sess,
|
|
DSMCondition::EventType event,
|
|
map<string,string>* event_params) {
|
|
param = resolveVars(arg, sess, sc_sess, event_params);
|
|
return Jump;
|
|
}
|
|
|
|
DEF_SCModActionExec(SCCallFSMAction);
|
|
DSMAction::SEAction SCCallFSMAction::getSEAction(string& param,
|
|
AmSession* sess, DSMSession* sc_sess,
|
|
DSMCondition::EventType event,
|
|
map<string,string>* event_params) {
|
|
param = resolveVars(arg, sess, sc_sess, event_params);
|
|
return Call;
|
|
}
|
|
|
|
DEF_SCModActionExec(SCReturnFSMAction);
|
|
DSMAction::SEAction SCReturnFSMAction::getSEAction(string& param,
|
|
AmSession* sess, DSMSession* sc_sess,
|
|
DSMCondition::EventType event,
|
|
map<string,string>* event_params) {
|
|
return Return;
|
|
}
|
|
|
|
#undef DEF_SCModActionExec
|
|
|
|
CONST_ACTION_2P(SCLogAction, ',', false);
|
|
EXEC_ACTION_START(SCLogAction) {
|
|
unsigned int lvl;
|
|
if (str2int(resolveVars(par1, sess, sc_sess, event_params), lvl)) {
|
|
ERROR("unknown log level '%s'\n", par1.c_str());
|
|
EXEC_ACTION_STOP;
|
|
}
|
|
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());
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_2P(SCLogsAction, ',', false);
|
|
EXEC_ACTION_START(SCLogsAction) {
|
|
unsigned int lvl;
|
|
if (str2int(resolveVars(par1, sess, sc_sess, event_params), lvl)) {
|
|
ERROR("unknown log level '%s'\n", par1.c_str());
|
|
EXEC_ACTION_STOP;
|
|
}
|
|
string l_line = replaceParams(par2, sess, sc_sess, event_params);
|
|
_LOG((int)lvl, "FSM: '%s'\n", l_line.c_str());
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCDbgAction) {
|
|
string l_line = replaceParams(arg, sess, sc_sess, event_params);
|
|
DBG("FSM: '%s'\n", l_line.c_str());
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCInfoAction) {
|
|
string l_line = replaceParams(arg, sess, sc_sess, event_params);
|
|
INFO("FSM: '%s'\n", l_line.c_str());
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCWarnAction) {
|
|
string l_line = replaceParams(arg, sess, sc_sess, event_params);
|
|
WARN("FSM: '%s'\n", l_line.c_str());
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCErrorAction) {
|
|
string l_line = replaceParams(arg, sess, sc_sess, event_params);
|
|
ERROR("FSM: '%s'\n", l_line.c_str());
|
|
} EXEC_ACTION_END;
|
|
|
|
void log_vars(const string& l_arg, AmSession* sess,
|
|
DSMSession* sc_sess, map<string,string>* event_params) {
|
|
unsigned int lvl;
|
|
if (str2int(resolveVars(l_arg, sess, sc_sess, event_params), lvl)) {
|
|
ERROR("unknown log level '%s'\n", l_arg.c_str());
|
|
return;
|
|
}
|
|
|
|
_LOG((int)lvl, "FSM: variables set ---\n");
|
|
for (map<string, string>::iterator it =
|
|
sc_sess->var.begin(); it != sc_sess->var.end(); it++) {
|
|
_LOG((int)lvl, "FSM: $%s='%s'\n", it->first.c_str(), it->second.c_str());
|
|
}
|
|
_LOG((int)lvl, "FSM: variables end ---\n");
|
|
}
|
|
|
|
EXEC_ACTION_START(SCLogVarsAction) {
|
|
log_vars(arg, sess, sc_sess, event_params);
|
|
} EXEC_ACTION_END;
|
|
|
|
void log_params(const string& l_arg, AmSession* sess,
|
|
DSMSession* sc_sess, map<string,string>* event_params) {
|
|
unsigned int lvl;
|
|
if (str2int(resolveVars(l_arg, sess, sc_sess, event_params), lvl)) {
|
|
ERROR("unknown log level '%s'\n", l_arg.c_str());
|
|
return;
|
|
}
|
|
|
|
if (NULL == event_params) {
|
|
_LOG((int)lvl, "FSM: no event params ---\n");
|
|
return;
|
|
}
|
|
|
|
_LOG((int)lvl, "FSM: params set ---\n");
|
|
for (map<string, string>::iterator it =
|
|
event_params->begin(); it != event_params->end(); it++) {
|
|
_LOG((int)lvl, "FSM: #%s='%s'\n", it->first.c_str(), it->second.c_str());
|
|
}
|
|
_LOG((int)lvl, "FSM: params end ---\n");
|
|
}
|
|
|
|
EXEC_ACTION_START(SCLogParamsAction) {
|
|
log_params(arg, sess, sc_sess, event_params);
|
|
} EXEC_ACTION_END;
|
|
|
|
|
|
void log_selects(const string& l_arg, AmSession* sess,
|
|
DSMSession* sc_sess, map<string,string>* event_params) {
|
|
unsigned int lvl;
|
|
if (str2int(resolveVars(l_arg, sess, sc_sess, event_params), lvl)) {
|
|
ERROR("unknown log level '%s'\n", l_arg.c_str());
|
|
return;
|
|
}
|
|
|
|
_LOG((int)lvl, "FSM: selects set ---\n");
|
|
|
|
#define SELECT_LOG(select_name) \
|
|
_LOG((int)lvl, "FSM: @%s='%s'\n", select_name, \
|
|
resolveVars("@" select_name, sess, sc_sess, event_params).c_str());
|
|
|
|
SELECT_LOG("local_tag");
|
|
SELECT_LOG("user");
|
|
SELECT_LOG("domain");
|
|
SELECT_LOG("remote_tag");
|
|
SELECT_LOG("callid");
|
|
SELECT_LOG("local_uri");
|
|
SELECT_LOG("local_party");
|
|
SELECT_LOG("remote_uri");
|
|
SELECT_LOG("remote_party");
|
|
#undef SELECT_LOG
|
|
_LOG((int)lvl, "FSM: selects end ---\n");
|
|
}
|
|
|
|
EXEC_ACTION_START(SCLogSelectsAction) {
|
|
log_selects(arg, sess, sc_sess, event_params);
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCLogAllAction) {
|
|
log_vars(arg, sess, sc_sess, event_params);
|
|
log_params(arg, sess, sc_sess, event_params);
|
|
log_selects(arg, sess, sc_sess, event_params);
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_2P(SCSetAction,'=', false);
|
|
EXEC_ACTION_START(SCSetAction) {
|
|
if (par1.length() && par1[0] == '#') {
|
|
// set param
|
|
if (NULL != event_params) {
|
|
string res = resolveVars(par2, sess, sc_sess, event_params);
|
|
(*event_params)[par1.substr(1)] = res;
|
|
DBG("set #%s='%s'\n", par1.substr(1).c_str(), res.c_str());
|
|
} else {
|
|
DBG("not setting %s (no param set)\n", par1.c_str());
|
|
}
|
|
} else {
|
|
// set variable
|
|
string var_name = (par1.length() && par1[0] == '$')?
|
|
par1.substr(1) : par1;
|
|
|
|
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());
|
|
}
|
|
} EXEC_ACTION_END;
|
|
|
|
string replaceParams(const string& q, AmSession* sess, DSMSession* sc_sess,
|
|
map<string,string>* event_params) {
|
|
string res = q;
|
|
size_t repl_pos = 0;
|
|
while (repl_pos<res.length()) {
|
|
size_t rstart = res.find_first_of("$#@", repl_pos);
|
|
repl_pos = rstart+1;
|
|
if (rstart == string::npos)
|
|
break;
|
|
if (rstart && (res.length() > rstart) && (res[rstart]==res[repl_pos])) {
|
|
res.erase(rstart, 1);
|
|
continue;
|
|
}
|
|
if (rstart && res[rstart-1] == '\\') // escaped
|
|
continue;
|
|
size_t rend;
|
|
if (res.length() > rstart+1 &&
|
|
(res[rstart+1] == '(' ||
|
|
res[rstart+1] == '"' ||
|
|
res[rstart+1] == '\''
|
|
))
|
|
rend = res.find_first_of(" ,()[]$#@\t;:'\"", rstart+2);
|
|
else
|
|
rend = res.find_first_of(" ,()[]$#@\t;:'\"", rstart+1);
|
|
if (rend==string::npos)
|
|
rend = res.length();
|
|
string keyname = res.substr(rstart+1, rend-rstart-1);
|
|
|
|
if (keyname.length()>2) {
|
|
if ((keyname[0] == '(' && res[rend] == ')') ||
|
|
(keyname[0] == res[rend] &&
|
|
(keyname[0] == '"' ||keyname[0] == '\''))) {
|
|
keyname = keyname.substr(1);
|
|
if (rend != res.length())
|
|
rend++;
|
|
}
|
|
}
|
|
// todo: simply use resolveVars (?)
|
|
switch(res[rstart]) {
|
|
case '$': {
|
|
if (sc_sess->var.find(keyname) == sc_sess->var.end()) {
|
|
res.erase(rstart, rend-rstart);
|
|
if (repl_pos) repl_pos--; // repl_pos was after $
|
|
} else {
|
|
res.replace(rstart, rend-rstart, sc_sess->var[keyname]);
|
|
if (sc_sess->var[keyname].size())
|
|
repl_pos+=sc_sess->var[keyname].size()-1; // skip after new string
|
|
}
|
|
} break;
|
|
case '#':
|
|
if (NULL!=event_params) {
|
|
if (event_params->find(keyname) != event_params->end()) {
|
|
res.replace(rstart, rend-rstart, (*event_params)[keyname]);
|
|
repl_pos+=(*event_params)[keyname].size()-1; // skip after new string
|
|
} else {
|
|
res.erase(rstart, rend-rstart);
|
|
if (repl_pos) repl_pos--; // repl_pos was after #
|
|
}
|
|
} break;
|
|
case '@': {
|
|
// todo: optimize
|
|
string n = resolveVars("@"+keyname, sess, sc_sess, event_params);
|
|
res.replace(rstart, rend-rstart, n);
|
|
if (n.size())
|
|
repl_pos+=n.size()-1; // skip after new string
|
|
// rstart rend
|
|
// bla@(varname)uuuu
|
|
// r
|
|
// r
|
|
// bla12345huuuu
|
|
} break;
|
|
default: break;
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
CONST_ACTION_2P(SCSetSAction,'=', false);
|
|
EXEC_ACTION_START(SCSetSAction) {
|
|
if (par1.length() && par1[0] == '#') {
|
|
// set param
|
|
if (NULL != event_params) {
|
|
string res = replaceParams(par2, sess, sc_sess, event_params);
|
|
(*event_params)[par1.substr(1)] = res;
|
|
DBG("set #%s='%s'\n", par1.substr(1).c_str(), res.c_str());
|
|
} else {
|
|
DBG("not set %s (no param set)\n", par1.c_str());
|
|
}
|
|
} else {
|
|
// set variable
|
|
string var_name = (par1.length() && par1[0] == '$')?
|
|
par1.substr(1) : par1;
|
|
|
|
sc_sess->var[var_name] = replaceParams(par2, sess, sc_sess, event_params);
|
|
|
|
DBG("set $%s='%s'\n",
|
|
var_name.c_str(), sc_sess->var[var_name].c_str());
|
|
}
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_2P(SCEvalAction,'=', false);
|
|
EXEC_ACTION_START(SCEvalAction) {
|
|
string var_name = (par1.length() && par1[0] == '$')?
|
|
par1.substr(1) : par1;
|
|
|
|
sc_sess->var[var_name] = resolveVars(par2, sess, sc_sess, event_params, true);
|
|
DBG("eval $%s='%s'\n",
|
|
var_name.c_str(), sc_sess->var[var_name].c_str());
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_2P(SCSetVarAction,'=', false);
|
|
EXEC_ACTION_START(SCSetVarAction) {
|
|
string var_name = resolveVars(par1, sess, sc_sess, event_params);
|
|
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());
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_2P(SCGetParamAction,'=', false);
|
|
EXEC_ACTION_START(SCGetParamAction){
|
|
|
|
string dst_var_name = (par1.length() && par1[0] == '$')?
|
|
par1.substr(1) : par1;
|
|
string param_name = resolveVars(par2, sess, sc_sess, event_params);
|
|
|
|
DBG("param_name = %s, dst = %s\n", param_name.c_str(), dst_var_name.c_str());
|
|
|
|
if (NULL==event_params) {
|
|
sc_sess->var[dst_var_name] = "";
|
|
EXEC_ACTION_STOP;
|
|
}
|
|
|
|
map<string, string>::iterator it = event_params->find(param_name);
|
|
if (it != event_params->end()) {
|
|
sc_sess->var[dst_var_name] = it->second;
|
|
} else {
|
|
sc_sess->var[dst_var_name] = "";
|
|
}
|
|
|
|
DBG("set $%s='%s'\n",
|
|
dst_var_name.c_str(), sc_sess->var[dst_var_name].c_str());
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_2P(SCGetVarAction,'=', false);
|
|
EXEC_ACTION_START(SCGetVarAction){
|
|
string dst_var_name = (par1.length() && par1[0] == '$')?
|
|
par1.substr(1) : par1;
|
|
string var_name = resolveVars(par2, sess, sc_sess, event_params);
|
|
|
|
DBG("var_name = %s, dst = %s\n", var_name.c_str(), dst_var_name.c_str());
|
|
sc_sess->var[dst_var_name] = sc_sess->var[var_name];
|
|
DBG("set $%s='%s'\n",
|
|
dst_var_name.c_str(), sc_sess->var[dst_var_name].c_str());
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCClearAction) {
|
|
string var_name = (arg.length() && arg[0] == '$')?
|
|
arg.substr(1) : arg;
|
|
DBG("clear variable '%s'\n", var_name.c_str());
|
|
sc_sess->var.erase(var_name);
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCClearStructAction) {
|
|
string varprefix = (arg.length() && arg[0] == '$')?
|
|
arg.substr(1) : arg;
|
|
DBG("clear variable struct '%s.*'\n", varprefix.c_str());
|
|
|
|
varprefix+=".";
|
|
|
|
map<string, string>::iterator lb = sc_sess->var.lower_bound(varprefix);
|
|
while (lb != sc_sess->var.end()) {
|
|
if ((lb->first.length() < varprefix.length()) ||
|
|
strncmp(lb->first.c_str(), varprefix.c_str(),varprefix.length()))
|
|
break;
|
|
map<string, string>::iterator lb_d = lb;
|
|
lb++;
|
|
sc_sess->var.erase(lb_d);
|
|
}
|
|
|
|
} EXEC_ACTION_END;
|
|
|
|
|
|
EXEC_ACTION_START(SCClearArrayAction) {
|
|
string varprefix = (arg.length() && arg[0] == '$')?
|
|
arg.substr(1) : arg;
|
|
DBG("clear variable array '%s[*'\n", varprefix.c_str());
|
|
|
|
varprefix+="[";
|
|
|
|
VarMapT::iterator lb = sc_sess->var.lower_bound(varprefix);
|
|
while (lb != sc_sess->var.end()) {
|
|
if ((lb->first.length() < varprefix.length()) ||
|
|
strncmp(lb->first.c_str(), varprefix.c_str(),varprefix.length()))
|
|
break;
|
|
// fixme: check whether it's really an array index
|
|
VarMapT::iterator lb_d = lb;
|
|
lb++;
|
|
sc_sess->var.erase(lb_d);
|
|
}
|
|
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_2P(SCSizeAction, ',', false);
|
|
EXEC_ACTION_START(SCSizeAction) {
|
|
string array_name = par1;
|
|
if (array_name.length() && array_name[0]=='$')
|
|
array_name.erase(0,1);
|
|
|
|
string dst_name = par2;
|
|
if (dst_name.length()&&dst_name[0]=='$')
|
|
dst_name.erase(0,1);
|
|
|
|
|
|
unsigned int a_size = 0;
|
|
while (true) {
|
|
string ai_name = array_name+"["+int2str(a_size)+"]";
|
|
VarMapT::iterator lb = sc_sess->var.lower_bound(ai_name);
|
|
if (lb == sc_sess->var.end() ||
|
|
lb->first.substr(0,ai_name.length()) != ai_name)
|
|
break;
|
|
a_size++;
|
|
}
|
|
string res = int2str(a_size);
|
|
sc_sess->var[dst_name] = res;
|
|
DBG("set $%s=%s\n", dst_name.c_str(), res.c_str());
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_2P(SCArrayIndexAction, ',', false);
|
|
EXEC_ACTION_START(SCArrayIndexAction) {
|
|
string array_name = par1;
|
|
if (array_name.length() && array_name[0]=='$')
|
|
array_name.erase(0,1);
|
|
|
|
string val = resolveVars(par2, sess, sc_sess, event_params);
|
|
unsigned int i = 0;
|
|
bool found = false;
|
|
while (true) {
|
|
VarMapT::iterator lb = sc_sess->var.find(array_name+"["+int2str(i)+"]");
|
|
if (lb == sc_sess->var.end())
|
|
break;
|
|
if (val == lb->second) {
|
|
found = true;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
string res = found ? int2str(i) : "nil";
|
|
if (par2[0]=='$') {
|
|
sc_sess->var[par2.substr(1)+".index"] = res;
|
|
DBG("set %s=%s\n", (par2+".index").c_str(), res.c_str());
|
|
} else {
|
|
sc_sess->var["index"] = res;
|
|
DBG("set $index=%s\n", res.c_str());
|
|
}
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_2P(SCRemovePatternAction, ',', false);
|
|
EXEC_ACTION_START(SCRemovePatternAction) {
|
|
string source_name = (par1.length() && par1[0] == '$') ? par1.substr(1) : par1;
|
|
string source_value = resolveVars(par1, sess, sc_sess, event_params);
|
|
string pattern = par2;
|
|
size_t pos = std::string::npos;
|
|
while ((pos = source_value.find(pattern)) != std::string::npos)
|
|
{
|
|
source_value.erase(pos, pattern.length());
|
|
}
|
|
sc_sess->var[source_name] = source_value;
|
|
} EXEC_ACTION_END;
|
|
|
|
|
|
CONST_ACTION_3P(SCGetErrorCodePlaybackAction, ',', false);
|
|
EXEC_ACTION_START(SCGetErrorCodePlaybackAction) {
|
|
string source_value = resolveVars(par1, sess, sc_sess, event_params);
|
|
string pattern = resolveVars(par2, sess, sc_sess, event_params);
|
|
string destination_variable = (par3.length() && par3[0] == '$') ? par3.substr(1) : par3;
|
|
string result; /* empty by default */
|
|
size_t pos = 0;
|
|
size_t end_pos;
|
|
/* parses strings like "var1:val1,var2:val2,var3:val3" */
|
|
while ((end_pos = source_value.find(',', pos)) != std::string::npos || pos < source_value.size())
|
|
{
|
|
string pair = source_value.substr(pos, end_pos - pos);
|
|
size_t separator_pos = pair.find(':');
|
|
if (separator_pos != std::string::npos) {
|
|
string current_var = pair.substr(0, separator_pos);
|
|
string current_val = pair.substr(separator_pos + 1);
|
|
if (current_var == pattern) {
|
|
result = current_val;
|
|
break;
|
|
}
|
|
}
|
|
pos = (end_pos == std::string::npos) ? source_value.size() : end_pos + 1;
|
|
}
|
|
/* rewrite only if we got something */
|
|
if (!result.empty())
|
|
sc_sess->var[destination_variable] = result;
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_2P(SCAppendAction,',', false);
|
|
EXEC_ACTION_START(SCAppendAction) {
|
|
string var_name = (par1.length() && par1[0] == '$')?
|
|
par1.substr(1) : par1;
|
|
|
|
sc_sess->var[var_name] += resolveVars(par2, sess, sc_sess, event_params);
|
|
|
|
DBG("$%s now '%s'\n",
|
|
var_name.c_str(), sc_sess->var[var_name].c_str());
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_2P(SCSubStrAction,',', false);
|
|
EXEC_ACTION_START(SCSubStrAction) {
|
|
string var_name = (par1.length() && par1[0] == '$')?
|
|
par1.substr(1) : par1;
|
|
unsigned int pos = 0;
|
|
unsigned int pos2 = 0;
|
|
size_t c_pos = par2.find(",");
|
|
if (c_pos == string::npos) {
|
|
if (str2int(resolveVars(par2, sess, sc_sess, event_params), pos)) {
|
|
ERROR("substr length '%s' unparseable\n",
|
|
resolveVars(par2, sess, sc_sess, event_params).c_str());
|
|
return false;
|
|
}
|
|
} else {
|
|
if (str2int(resolveVars(par2.substr(0, c_pos), sess, sc_sess, event_params), pos)) {
|
|
ERROR("substr length '%s' unparseable\n",
|
|
resolveVars(par2.substr(0, c_pos), sess, sc_sess, event_params).c_str());
|
|
return false;
|
|
}
|
|
|
|
if (str2int(resolveVars(par2.substr(c_pos+1), sess, sc_sess, event_params), pos2)) {
|
|
ERROR("substr length '%s' unparseable\n",
|
|
resolveVars(par2.substr(0, c_pos-1), sess, sc_sess, event_params).c_str());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
try {
|
|
if (pos2 == 0)
|
|
sc_sess->var[var_name] = sc_sess->var[var_name].substr(pos);
|
|
else
|
|
sc_sess->var[var_name] = sc_sess->var[var_name].substr(pos, pos2);
|
|
} catch(...) {
|
|
ERROR("in substr\n");
|
|
return false;
|
|
}
|
|
|
|
DBG("$%s now '%s'\n",
|
|
var_name.c_str(), sc_sess->var[var_name].c_str());
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCIncAction) {
|
|
string var_name = (arg.length() && arg[0] == '$')?
|
|
arg.substr(1) : arg;
|
|
unsigned int val = 0;
|
|
str2int(sc_sess->var[var_name], val);
|
|
sc_sess->var[var_name] = int2str(val+1);
|
|
|
|
DBG("inc: $%s now '%s'\n",
|
|
var_name.c_str(), sc_sess->var[var_name].c_str());
|
|
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_2P(SCSetTimerAction,',', false);
|
|
EXEC_ACTION_START(SCSetTimerAction) {
|
|
|
|
unsigned int timerid;
|
|
if (str2int(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_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
|
|
sc_sess->SET_STRERROR("timer id '"+
|
|
resolveVars(par1, sess, sc_sess, event_params)+
|
|
"' not decipherable\n");
|
|
EXEC_ACTION_STOP;
|
|
}
|
|
|
|
unsigned int timeout;
|
|
if (str2int(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_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
|
|
sc_sess->SET_STRERROR("timeout value '"+
|
|
resolveVars(par2, sess, sc_sess, event_params)+
|
|
"' not decipherable\n");
|
|
EXEC_ACTION_STOP;
|
|
}
|
|
|
|
if (!sess->setTimer(timerid, timeout)) {
|
|
ERROR("load session_timer module for timers.\n");
|
|
sc_sess->SET_ERRNO(DSM_ERRNO_CONFIG);
|
|
sc_sess->SET_STRERROR("load sess_timer module for timers.\n");
|
|
EXEC_ACTION_STOP;
|
|
}
|
|
|
|
sc_sess->CLR_ERRNO;
|
|
} EXEC_ACTION_END;
|
|
|
|
|
|
EXEC_ACTION_START(SCRemoveTimerAction) {
|
|
|
|
unsigned int timerid;
|
|
string timerid_s = resolveVars(arg, sess, sc_sess, event_params);
|
|
if (str2int(timerid_s, timerid)) {
|
|
ERROR("timer id '%s' not decipherable\n", timerid_s.c_str());
|
|
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
|
|
sc_sess->SET_STRERROR("timer id '"+timerid_s+"' not decipherable\n");
|
|
return false;
|
|
}
|
|
|
|
if (!sess->removeTimer(timerid)) {
|
|
ERROR("load session_timer module for timers.\n");
|
|
sc_sess->SET_ERRNO(DSM_ERRNO_CONFIG);
|
|
sc_sess->SET_STRERROR("load session_timer module for timers.\n");
|
|
EXEC_ACTION_STOP;
|
|
}
|
|
|
|
sc_sess->CLR_ERRNO;
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCRemoveTimersAction) {
|
|
|
|
DBG("removing timers for session %s\n", sess->getLocalTag().c_str());
|
|
if (!sess->removeTimers()) {
|
|
ERROR("load session_timer module for timers.\n");
|
|
sc_sess->SET_ERRNO(DSM_ERRNO_CONFIG);
|
|
sc_sess->SET_STRERROR("load sess_timer module for timers.\n");
|
|
EXEC_ACTION_STOP;
|
|
}
|
|
|
|
sc_sess->CLR_ERRNO;
|
|
} EXEC_ACTION_END;
|
|
|
|
|
|
|
|
// TODO: replace with real expression matching
|
|
TestDSMCondition::TestDSMCondition(const string& expr, DSMCondition::EventType evt) {
|
|
|
|
type = evt;
|
|
|
|
if (expr.empty()) {
|
|
ttype = Always;
|
|
return;
|
|
}
|
|
|
|
ttype = None;
|
|
|
|
size_t p = expr.find("==");
|
|
size_t p2;
|
|
if (p != string::npos) {
|
|
ttype = Eq; p2 = p+2;
|
|
} else {
|
|
p = expr.find("!=");
|
|
if (p != string::npos) {
|
|
ttype = Neq; p2 = p+2;
|
|
} else {
|
|
p = expr.find("<");
|
|
if (p != string::npos) {
|
|
ttype = Less; p2 = p+1;
|
|
} else {
|
|
p = expr.find(">");
|
|
if (p != string::npos) {
|
|
ttype = Gt; p2 = p+1;
|
|
} else {
|
|
ERROR("expression '%s' not understood\n",
|
|
expr.c_str());
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
lhs = trim(expr.substr(0, p), " ");
|
|
rhs = trim(expr.substr(p2,expr.length()-p2+1), " ");
|
|
|
|
name = expr;
|
|
}
|
|
|
|
bool TestDSMCondition::match(AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event,
|
|
map<string,string>* event_params) {
|
|
if (ttype == None || (type != DSMCondition::Any && type != event))
|
|
return false;
|
|
|
|
if (ttype == Always)
|
|
return true;
|
|
|
|
if (!sc_sess) {
|
|
ERROR("wrong session type\n");
|
|
return false;
|
|
}
|
|
|
|
string l;
|
|
string r;
|
|
if (lhs.length() > 5 &&
|
|
(lhs.substr(0, 4) == "len(") && lhs[lhs.length()-1] == ')') {
|
|
l = int2str((unsigned int)resolveVars(lhs.substr(4, lhs.length()-5), sess, sc_sess, event_params).length());
|
|
} else {
|
|
l = resolveVars(lhs, sess, sc_sess, event_params);
|
|
}
|
|
if (rhs.length() > 5 &&
|
|
rhs.substr(0, 4) == "len(" && rhs[rhs.length()-1] == ')') {
|
|
r = resolveVars(rhs.substr(4, rhs.length()-5), sess, sc_sess, event_params).length();
|
|
} else {
|
|
r = resolveVars(rhs, sess, sc_sess, event_params);
|
|
}
|
|
|
|
// string r = resolveVars(rhs, sess, sc_sess, event_params);
|
|
|
|
DBG("test '%s' vs '%s'\n", l.c_str(), r.c_str());
|
|
|
|
switch (ttype) {
|
|
case Eq: {
|
|
size_t starpos = r.find("*");
|
|
if (starpos==string::npos)
|
|
return l == r;
|
|
else {
|
|
if (l.size()<starpos)
|
|
return false;
|
|
return r.substr(0, starpos) == l.substr(0, starpos);
|
|
}
|
|
}
|
|
case Neq: return l != r;
|
|
case Less: {
|
|
char* endptr = NULL;
|
|
long l_i = strtol(l.c_str(), &endptr, 10);
|
|
if (endptr && *endptr == '\0') {
|
|
long r_i = strtol(r.c_str(), &endptr, 10);
|
|
if (endptr && *endptr == '\0')
|
|
return l_i < r_i;
|
|
}
|
|
return l < r;
|
|
}
|
|
case Gt: {
|
|
char* endptr = NULL;
|
|
long l_i = strtol(l.c_str(), &endptr, 10);
|
|
if (endptr && *endptr == '\0') {
|
|
long r_i = strtol(r.c_str(), &endptr, 10);
|
|
if (endptr && *endptr == '\0')
|
|
return l_i > r_i;
|
|
}
|
|
return l > r;
|
|
}
|
|
default: return false;
|
|
}
|
|
}
|
|
|
|
|
|
SCDIAction::SCDIAction(const string& arg, bool get_res)
|
|
: get_res(get_res) {
|
|
// TODO: don't ignore "" (don't use explode here)
|
|
params = explode(arg,",");
|
|
if (params.size()<2) {
|
|
ERROR("DI needs at least: mod_name, "
|
|
"function_name\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
void string2argarray(const string& key, const string& val, AmArg& res) {
|
|
if (key.empty())
|
|
return;
|
|
|
|
if (!(isArgStruct(res) || isArgUndef(res))) {
|
|
WARN("array element [%s] is shadowed by value '%s'\n",
|
|
key.c_str(), AmArg::print(res).c_str());
|
|
return;
|
|
}
|
|
|
|
size_t delim = key.find(".");
|
|
if (delim == string::npos) {
|
|
res[key]=val;
|
|
return;
|
|
}
|
|
string2argarray(key.substr(delim+1), val, res[key.substr(0,delim)]);
|
|
}
|
|
|
|
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_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
|
|
sc_sess->SET_STRERROR("DI needs at least: mod_name, "
|
|
"function_name (in '"+name+"%s')\n");
|
|
EXEC_ACTION_STOP;
|
|
}
|
|
|
|
vector<string>::iterator p_it=params.begin();
|
|
string fact_name = trim(*p_it, " \"");
|
|
AmDynInvokeFactory* fact =
|
|
AmPlugIn::instance()->getFactory4Di(fact_name);
|
|
|
|
if(!fact) {
|
|
ERROR("load module for factory '%s'.\n", fact_name.c_str());
|
|
sc_sess->SET_ERRNO(DSM_ERRNO_CONFIG);
|
|
sc_sess->SET_STRERROR("load module for factory '"+fact_name+"'.\n");
|
|
EXEC_ACTION_STOP;
|
|
}
|
|
AmDynInvoke* di_inst = fact->getInstance();
|
|
if(!di_inst) {
|
|
ERROR("load module for factory '%s'\n", fact_name.c_str());
|
|
sc_sess->SET_ERRNO(DSM_ERRNO_CONFIG);
|
|
sc_sess->SET_STRERROR("load module for factory '"+fact_name+"'.\n");
|
|
EXEC_ACTION_STOP;
|
|
}
|
|
p_it++;
|
|
|
|
string func_name = trim(*p_it, " \"");
|
|
p_it++;
|
|
|
|
AmArg di_args;
|
|
|
|
while (p_it != params.end()) {
|
|
string p = trim(*p_it, " \t");
|
|
if (p.length() && p[0] == '"') {
|
|
di_args.push(trim(p,"\"").c_str());
|
|
} else if (p.length() > 5 &&
|
|
p.substr(0, 5) =="(int)") {
|
|
p = resolveVars(p.substr(5), sess, sc_sess, event_params);
|
|
char* endptr = NULL;
|
|
long p_i = strtol(p.c_str(), &endptr, 10);
|
|
if (endptr && *endptr == '\0') {
|
|
di_args.push((int)p_i);
|
|
} else {
|
|
ERROR("converting value '%s' to int\n",
|
|
p.c_str());
|
|
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
|
|
sc_sess->SET_STRERROR("converting value '"+p+"' to int\n");
|
|
EXEC_ACTION_STOP;
|
|
}
|
|
} else if (p.length() > 8 &&
|
|
p.substr(0, 8) =="(struct)") {
|
|
p.erase(0, 8);
|
|
AmArg var_struct;
|
|
string varprefix = p+".";
|
|
//bool has_vars = false;
|
|
map<string, string>::iterator lb = sc_sess->var.lower_bound(varprefix);
|
|
while (lb != sc_sess->var.end()) {
|
|
if ((lb->first.length() < varprefix.length()) ||
|
|
strncmp(lb->first.c_str(), varprefix.c_str(),varprefix.length()))
|
|
break;
|
|
|
|
string varname = lb->first.substr(varprefix.length());
|
|
if (varname.find(".") == string::npos)
|
|
var_struct[std::move(varname)] = lb->second;
|
|
else
|
|
string2argarray(varname, lb->second, var_struct);
|
|
|
|
lb++;
|
|
//has_vars = true;
|
|
}
|
|
|
|
if (var_struct.getType() != AmArg::Undef)
|
|
di_args.push(var_struct);
|
|
|
|
} else if (p.length() > 7 &&
|
|
p.substr(0, 7) =="(array)") {
|
|
p.erase(0, 7);
|
|
di_args.push(AmArg());
|
|
AmArg& var_array = di_args.get(di_args.size()-1);
|
|
|
|
unsigned int i=0;
|
|
while (true) {
|
|
map<string, string>::iterator it =
|
|
sc_sess->var.find(p+"["+int2str(i)+"]");
|
|
if (it == sc_sess->var.end())
|
|
break;
|
|
var_array.push(it->second);
|
|
i++;
|
|
}
|
|
} else if (p.length() > 6 &&
|
|
p.substr(0, 6) == "(json)") {
|
|
p.erase(0, 6);
|
|
if (p.length() && p[0] == '"') {
|
|
// remove quotes if parameter in form (json)"{"json":"object"}"
|
|
p = trim(p,"\"");
|
|
} else {
|
|
p = resolveVars(p, sess, sc_sess, event_params);
|
|
}
|
|
|
|
di_args.push(AmArg());
|
|
AmArg& var_json = di_args.get(di_args.size()-1);
|
|
if (!json2arg(p, var_json)) {
|
|
WARN("Error parsing JSON object '%s'\n", p.c_str());
|
|
// todo: throw exception?
|
|
}
|
|
} else {
|
|
di_args.push(resolveVars(p, sess, sc_sess, event_params).c_str());
|
|
}
|
|
p_it++;
|
|
}
|
|
|
|
sc_sess->di_res.clear();
|
|
DBG("executing DI function '%s'\n", func_name.c_str());
|
|
try {
|
|
di_inst->invoke(func_name, di_args, sc_sess->di_res);
|
|
} catch (const AmDynInvoke::NotImplemented& ni) {
|
|
ERROR("not implemented DI function '%s'\n",
|
|
ni.what.c_str());
|
|
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
|
|
sc_sess->SET_STRERROR("not implemented DI function '"+ni.what+"'\n");
|
|
EXEC_ACTION_STOP;
|
|
} catch (const AmArg::OutOfBoundsException& oob) {
|
|
ERROR("out of bounds in DI call '%s'\n",
|
|
name.c_str());
|
|
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
|
|
sc_sess->SET_STRERROR("out of bounds in DI call '"+name+"'\n");
|
|
EXEC_ACTION_STOP;
|
|
} catch (const AmArg::TypeMismatchException& oob) {
|
|
ERROR("type mismatch in DI call '%s'\n",
|
|
name.c_str());
|
|
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
|
|
sc_sess->SET_STRERROR("type mismatch in DI call '"+name+"'\n");
|
|
EXEC_ACTION_STOP;
|
|
} catch (...) {
|
|
ERROR("unexpected Exception in DI call '%s'\n",
|
|
name.c_str());
|
|
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
|
|
sc_sess->SET_STRERROR("unexpected Exception in DI call '"+name+"'\n");
|
|
EXEC_ACTION_STOP;
|
|
}
|
|
|
|
bool flag_error = false;
|
|
if (get_res) {
|
|
// rudimentary variables conversion...
|
|
if (isArgCStr(sc_sess->di_res))
|
|
sc_sess->var["DI_res"] = sc_sess->di_res.asCStr();
|
|
else if (isArgInt(sc_sess->di_res))
|
|
sc_sess->var["DI_res"] = int2str(sc_sess->di_res.asInt());
|
|
else if (isArgArray(sc_sess->di_res)) {
|
|
// copy results to $DI_res0..$DI_resn
|
|
for (size_t i=0;i<sc_sess->di_res.size();i++) {
|
|
switch (sc_sess->di_res.get(i).getType()) {
|
|
case AmArg::CStr: {
|
|
sc_sess->var["DI_res"+int2str((unsigned int)i)] =
|
|
sc_sess->di_res.get(i).asCStr();
|
|
} break;
|
|
case AmArg::Int: {
|
|
sc_sess->var["DI_res"+int2str((unsigned int)i)] =
|
|
int2str(sc_sess->di_res.get(i).asInt());
|
|
} break;
|
|
default: {
|
|
ERROR("unsupported AmArg return type!");
|
|
flag_error = true;
|
|
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
|
|
sc_sess->SET_STRERROR("unsupported AmArg return type");
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
ERROR("unsupported AmArg return type!");
|
|
flag_error = true;
|
|
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
|
|
sc_sess->SET_STRERROR("unsupported AmArg return type");
|
|
}
|
|
}
|
|
if (!flag_error) {
|
|
sc_sess->CLR_ERRNO;
|
|
}
|
|
|
|
} EXEC_ACTION_END;
|
|
|
|
|
|
CONST_ACTION_2P(SCB2BConnectCalleeAction,',', false);
|
|
EXEC_ACTION_START(SCB2BConnectCalleeAction) {
|
|
string remote_party = resolveVars(par1, sess, sc_sess, event_params);
|
|
string remote_uri = resolveVars(par2, sess, sc_sess, event_params);
|
|
bool relayed_invite = false;
|
|
VarMapT::iterator it = sc_sess->var.find(DSM_B2B_RELAYED_INVITE);
|
|
if (it != sc_sess->var.end() && it->second == "true")
|
|
relayed_invite = true;
|
|
DBG("B2B connecting callee '%s', URI '%s', relayed: %s\n",
|
|
remote_party.c_str(), remote_uri.c_str(), relayed_invite?"yes":"no");
|
|
sc_sess->B2BconnectCallee(remote_party, remote_uri, relayed_invite);
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCB2BTerminateOtherLegAction) {
|
|
sc_sess->B2BterminateOtherLeg();
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_2P(SCB2BReinviteAction,',', true);
|
|
EXEC_ACTION_START(SCB2BReinviteAction) {
|
|
bool updateSDP = par1=="true";
|
|
sess->sendReinvite(updateSDP, par2);
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCB2BSendEstablishedReinviteAction) {
|
|
AmB2BSession* b2b_sess = dynamic_cast<AmB2BSession*>(sess);
|
|
string hdrs = resolveVars(arg, sess, sc_sess, event_params);
|
|
|
|
sc_sess->replaceHdrsCRLF(hdrs);
|
|
|
|
if (NULL != b2b_sess) {
|
|
b2b_sess->sendEstablishedReInvite(hdrs);
|
|
} else {
|
|
ERROR("internal: Session object is not B2B session (huh?), not reinviting\n");
|
|
}
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCB2BEnableEarlyMediaRelayAction) {
|
|
string val = resolveVars(arg, sess, sc_sess, event_params);
|
|
DBG("B2B: %sabling early media SDP relay as re-Invite\n", (val=="true")?"En":"Dis");
|
|
sc_sess->B2BsetRelayEarlyMediaSDP(val=="true");
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCB2BAddHeaderAction) {
|
|
string val = resolveVars(arg, sess, sc_sess, event_params);
|
|
DBG("adding B2B header '%s'\n", val.c_str());
|
|
sc_sess->B2BaddHeader(val);
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_2P(SCB2BGetHeaderRequestAction,',', false);
|
|
EXEC_ACTION_START(SCB2BGetHeaderRequestAction) {
|
|
string hdr_name = resolveVars(par1, sess, sc_sess, event_params);
|
|
string destination_variable = (par2.length() && par2[0] == '$') ? par2.substr(1) : par2;
|
|
string result;
|
|
|
|
if (hdr_name.empty() || destination_variable.empty())
|
|
throw DSMException("core", "cause", "parameters missing");
|
|
|
|
sc_sess->B2BgetHeaderRequest(hdr_name, result);
|
|
|
|
/* write only if we got something */
|
|
if (!result.empty())
|
|
sc_sess->var[destination_variable] = std::move(result);
|
|
else
|
|
DBG("No header with name '%s' found.\n", hdr_name.c_str());
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_3P(SCB2BGetHeaderParamRequestAction,',', false);
|
|
EXEC_ACTION_START(SCB2BGetHeaderParamRequestAction) {
|
|
string hdr_name = resolveVars(par1, sess, sc_sess, event_params);
|
|
string param_name = resolveVars(par2, sess, sc_sess, event_params);
|
|
string destination_variable = (par3.length() && par3[0] == '$') ? par3.substr(1) : par3;
|
|
string result;
|
|
if (hdr_name.empty() || param_name.empty() || destination_variable.empty())
|
|
throw DSMException("core", "cause", "parameters missing");
|
|
sc_sess->B2BgetHeaderParamRequest(hdr_name, param_name, result);
|
|
/* write only if we got something */
|
|
if (!result.empty())
|
|
sc_sess->var[destination_variable] = result;
|
|
else
|
|
DBG("No header param with name '%s' found.\n", hdr_name.c_str());
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_2P(SCB2BGetHeaderReplyAction,',', false);
|
|
EXEC_ACTION_START(SCB2BGetHeaderReplyAction) {
|
|
string hdr_name = resolveVars(par1, sess, sc_sess, event_params);
|
|
string destination_variable = (par2.length() && par2[0] == '$') ? par2.substr(1) : par2;
|
|
string result;
|
|
|
|
if (hdr_name.empty() || destination_variable.empty())
|
|
throw DSMException("core", "cause", "parameters missing");
|
|
|
|
sc_sess->B2BgetHeaderReply(hdr_name, result);
|
|
|
|
/* write only if we got something */
|
|
if (!result.empty())
|
|
sc_sess->var[destination_variable] = result;
|
|
else
|
|
DBG("No header with name '%s' found.\n", hdr_name.c_str());
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_3P(SCB2BGetHeaderParamReplyAction,',', false);
|
|
EXEC_ACTION_START(SCB2BGetHeaderParamReplyAction) {
|
|
string hdr_name = resolveVars(par1, sess, sc_sess, event_params);
|
|
string param_name = resolveVars(par2, sess, sc_sess, event_params);
|
|
string destination_variable = (par3.length() && par3[0] == '$') ? par3.substr(1) : par3;
|
|
string result;
|
|
if (hdr_name.empty() || param_name.empty() || destination_variable.empty())
|
|
throw DSMException("core", "cause", "parameters missing");
|
|
sc_sess->B2BgetHeaderParamReply(hdr_name, param_name, result);
|
|
/* write only if we got something */
|
|
if (!result.empty())
|
|
sc_sess->var[destination_variable] = result;
|
|
else
|
|
DBG("No header param with name '%s' found.\n", hdr_name.c_str());
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCB2BRemoveHeaderAction) {
|
|
string val = resolveVars(arg, sess, sc_sess, event_params);
|
|
DBG("removing B2B header '%s'\n", val.c_str());
|
|
sc_sess->B2BremoveHeader(val);
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_2P(SCB2BSetHeadersAction,',', true);
|
|
EXEC_ACTION_START(SCB2BSetHeadersAction) {
|
|
string val = resolveVars(par1, sess, sc_sess, event_params);
|
|
string repl = resolveVars(par2, sess, sc_sess, event_params);
|
|
bool replace_crlf = false;
|
|
if (repl == "true")
|
|
replace_crlf = true;
|
|
DBG("setting B2B headers to '%s' (%sreplacing CRLF)\n",
|
|
val.c_str(), replace_crlf?"":"not ");
|
|
sc_sess->B2BsetHeaders(val, replace_crlf);
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCB2BClearHeadersAction) {
|
|
DBG("clearing B2B headers\n");
|
|
sc_sess->B2BclearHeaders();
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_2P(SCSendDTMFAction,',', true);
|
|
EXEC_ACTION_START(SCSendDTMFAction) {
|
|
string event = resolveVars(par1, sess, sc_sess, event_params);
|
|
string duration = resolveVars(par2, sess, sc_sess, event_params);
|
|
|
|
unsigned int event_i;
|
|
if (str2int(event, event_i)) {
|
|
ERROR("event '%s' not a valid DTMF event\n", event.c_str());
|
|
throw DSMException("core", "cause", "invalid DTMF:"+ event);
|
|
}
|
|
|
|
unsigned int duration_i;
|
|
if (duration.empty()) {
|
|
duration_i = 500; // default
|
|
} else {
|
|
if (str2int(duration, duration_i)) {
|
|
ERROR("event duration '%s' not a valid DTMF duration\n", duration.c_str());
|
|
throw DSMException("core", "cause", "invalid DTMF duration:"+ duration);
|
|
}
|
|
}
|
|
|
|
sess->sendDtmf(event_i, duration_i);
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_2P(SCSendDTMFSequenceAction,',', true);
|
|
EXEC_ACTION_START(SCSendDTMFSequenceAction) {
|
|
string events = resolveVars(par1, sess, sc_sess, event_params);
|
|
string duration = resolveVars(par2, sess, sc_sess, event_params);
|
|
|
|
unsigned int duration_i;
|
|
if (duration.empty()) {
|
|
duration_i = 500; // default
|
|
} else {
|
|
if (str2int(duration, duration_i)) {
|
|
ERROR("event duration '%s' not a valid DTMF duration\n", duration.c_str());
|
|
throw DSMException("core", "cause", "invalid DTMF duration:"+ duration);
|
|
}
|
|
}
|
|
|
|
for (size_t i=0;i<events.length();i++) {
|
|
if ((events[i]<'0' || events[i]>'9')
|
|
&& (events[i] != '#') && (events[i] != '*')
|
|
&& (events[i] <'A' || events[i] >'F')) {
|
|
DBG("skipping non-DTMF event char '%c'\n", events[i]);
|
|
continue;
|
|
}
|
|
int event = events[i] - '0';
|
|
if (events[i] == '*')
|
|
event = 10;
|
|
else if (events[i] == '#')
|
|
event = 11;
|
|
else if (events[i] >= 'A' && events[i] <= 'F' )
|
|
event = 12 + (events[i] - 'A');
|
|
DBG("sending event %d duration %u\n", event, duration_i);
|
|
sess->sendDtmf(event, duration_i);
|
|
}
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCRegisterEventQueueAction) {
|
|
string q_name = resolveVars(arg, sess, sc_sess, event_params);
|
|
DBG("Registering event queue '%s'\n", q_name.c_str());
|
|
if (q_name.empty()) {
|
|
WARN("Registering empty event queue name!\n");
|
|
}
|
|
AmEventDispatcher::instance()->addEventQueue(q_name, sess);
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCUnregisterEventQueueAction) {
|
|
string q_name = resolveVars(arg, sess, sc_sess, event_params);
|
|
DBG("Unregistering event queue '%s'\n", q_name.c_str());
|
|
if (q_name.empty()) {
|
|
WARN("Unregistering empty event queue name!\n");
|
|
}
|
|
AmEventDispatcher::instance()->delEventQueue(q_name);
|
|
} EXEC_ACTION_END;
|
|
|
|
CONST_ACTION_2P(SCCreateSystemDSMAction,',', false);
|
|
EXEC_ACTION_START(SCCreateSystemDSMAction) {
|
|
string conf_name = resolveVars(par1, sess, sc_sess, event_params);
|
|
string script_name = resolveVars(par2, sess, sc_sess, event_params);
|
|
|
|
if (conf_name.empty() || script_name.empty()) {
|
|
throw DSMException("core", "cause", "parameters missing - "
|
|
"need both conf_name and script_name for createSystemDSM");
|
|
}
|
|
|
|
DBG("creating system DSM conf_name %s, script_name %s\n",
|
|
conf_name.c_str(), script_name.c_str());
|
|
string status;
|
|
if (!DSMFactory::instance()->createSystemDSM(conf_name, script_name, false, status)) {
|
|
ERROR("creating system DSM: %s\n", status.c_str());
|
|
throw DSMException("core", "cause", status);
|
|
}
|
|
|
|
} EXEC_ACTION_END;
|
|
|
|
DSMDisposable* getObjectFromVariable(DSMSession* sc_sess, const string& var_name) {
|
|
AVarMapT::iterator it = sc_sess->avar.find(var_name);
|
|
if (it == sc_sess->avar.end()) {
|
|
DBG("object '%s' not found\n", var_name.c_str());
|
|
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
|
|
sc_sess->SET_STRERROR("object '"+var_name+"' not found\n");
|
|
return NULL;
|
|
}
|
|
|
|
DSMDisposable* disp = dynamic_cast<DSMDisposable*>(it->second.asObject());
|
|
if (NULL == disp) {
|
|
DBG("object '%s' is not a DSMDisposable\n", var_name.c_str());
|
|
sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
|
|
sc_sess->SET_STRERROR("object '"+var_name+"' is not a DSMDisposable\n");
|
|
return NULL;
|
|
}
|
|
return disp;
|
|
}
|
|
|
|
EXEC_ACTION_START(SCTrackObjectAction) {
|
|
string var_name = resolveVars(arg, sess, sc_sess, event_params);
|
|
DSMDisposable* disp = getObjectFromVariable(sc_sess, var_name);
|
|
if (NULL == disp) {
|
|
EXEC_ACTION_STOP;
|
|
}
|
|
sc_sess->transferOwnership(disp);
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCReleaseObjectAction) {
|
|
string var_name = resolveVars(arg, sess, sc_sess, event_params);
|
|
DSMDisposable* disp = getObjectFromVariable(sc_sess, var_name);
|
|
if (NULL == disp) {
|
|
EXEC_ACTION_STOP;
|
|
}
|
|
sc_sess->releaseOwnership(disp);
|
|
} EXEC_ACTION_END;
|
|
|
|
EXEC_ACTION_START(SCFreeObjectAction) {
|
|
string var_name = resolveVars(arg, sess, sc_sess, event_params);
|
|
DSMDisposable* disp = getObjectFromVariable(sc_sess, var_name);
|
|
if (NULL == disp) {
|
|
EXEC_ACTION_STOP;
|
|
}
|
|
delete disp;
|
|
sc_sess->avar.erase(var_name);
|
|
} EXEC_ACTION_END;
|