1 /*
2  * Copyright (C) 2008 iptego GmbH
3  * Copyright (C) 2010 Stefan Sayer
4  *
5  * This file is part of SEMS, a free SIP media server.
6  *
7  * SEMS is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version. This program is released under
11  * the GPL with the additional exemption that compiling, linking,
12  * and/or using OpenSSL is allowed.
13  *
14  * For a license to use the SEMS software under conditions
15  * other than those described here, or to purchase support for this
16  * software, please contact iptel.org by e-mail at the following addresses:
17  *    info@iptel.org
18  *
19  * SEMS is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27  */
28 
29 #include "DSMCoreModule.h"
30 #include "DSMSession.h"
31 #include "AmSession.h"
32 #include "AmSessionContainer.h"
33 #include "AmUtils.h"
34 #include "AmEventDispatcher.h"
35 #include "DSM.h"
36 #include "AmB2BSession.h"
37 
38 #include "jsonArg.h"
39 
DSMCoreModule()40 DSMCoreModule::DSMCoreModule() {
41 }
42 
getAction(const string & from_str)43 DSMAction* DSMCoreModule::getAction(const string& from_str) {
44   string cmd;
45   string params;
46   splitCmd(from_str, cmd, params);
47 
48   DEF_CMD("repost", SCRepostAction);
49   DEF_CMD("jumpFSM", SCJumpFSMAction);
50   DEF_CMD("callFSM", SCCallFSMAction);
51   DEF_CMD("returnFSM", SCReturnFSMAction);
52 
53   DEF_CMD("break", SCBreakAction);
54 
55   DEF_CMD("throw", SCThrowAction);
56   DEF_CMD("throwOnError", SCThrowOnErrorAction);
57 
58   DEF_CMD("stop", SCStopAction);
59 
60   DEF_CMD("playPrompt", SCPlayPromptAction);
61   DEF_CMD("playPromptFront", SCPlayPromptFrontAction);
62   DEF_CMD("playPromptLooped", SCPlayPromptLoopedAction);
63   DEF_CMD("playFile", SCPlayFileAction);
64   DEF_CMD("playFileFront", SCPlayFileFrontAction);
65   DEF_CMD("playSilence", SCPlaySilenceAction);
66   DEF_CMD("playSilenceFront", SCPlaySilenceFrontAction);
67   DEF_CMD("playRingtone", SCPlayRingtoneAction);
68   DEF_CMD("recordFile", SCRecordFileAction);
69   DEF_CMD("stopRecord", SCStopRecordAction);
70   DEF_CMD("getRecordLength", SCGetRecordLengthAction);
71   DEF_CMD("getRecordDataSize", SCGetRecordDataSizeAction);
72   DEF_CMD("flushPlaylist", SCFlushPlaylistAction);
73   DEF_CMD("closePlaylist", SCClosePlaylistAction); // deprecated
74   DEF_CMD("setInOutPlaylist", SCSetInOutPlaylistAction);
75   DEF_CMD("setInputPlaylist", SCSetInputPlaylistAction);
76   DEF_CMD("setOutputPlaylist", SCSetOutputPlaylistAction);
77   DEF_CMD("addSeparator", SCAddSeparatorAction);
78   DEF_CMD("connectMedia", SCConnectMediaAction);
79   DEF_CMD("disconnectMedia", SCDisconnectMediaAction);
80   DEF_CMD("enableReceiving", SCEnableReceivingAction);
81   DEF_CMD("disableReceiving", SCDisableReceivingAction);
82   DEF_CMD("enableForceDTMFReceiving", SCEnableForceDTMFReceiving);
83   DEF_CMD("disableForceDTMFReceiving", SCDisableForceDTMFReceiving);
84   DEF_CMD("monitorRTPTimeout", SCMonitorRTPTimeoutAction);
85   DEF_CMD("mute", SCMuteAction);
86   DEF_CMD("unmute", SCUnmuteAction);
87   DEF_CMD("enableDTMFDetection", SCEnableDTMFDetection);
88   DEF_CMD("disableDTMFDetection", SCDisableDTMFDetection);
89   DEF_CMD("sendDTMF", SCSendDTMFAction);
90   DEF_CMD("sendDTMFSequence", SCSendDTMFSequenceAction);
91 
92   DEF_CMD("set", SCSetAction);
93   DEF_CMD("sets", SCSetSAction);
94   DEF_CMD("eval", SCEvalAction);
95   DEF_CMD("setVar", SCSetVarAction);
96   DEF_CMD("var", SCGetVarAction);
97   DEF_CMD("param", SCGetParamAction);
98   DEF_CMD("append", SCAppendAction);
99   DEF_CMD("substr", SCSubStrAction);
100   DEF_CMD("inc", SCIncAction);
101   DEF_CMD("log", SCLogAction);
102   DEF_CMD("logs", SCLogsAction);
103   DEF_CMD("dbg", SCDbgAction);
104   DEF_CMD("info", SCInfoAction);
105   DEF_CMD("warn", SCWarnAction);
106   DEF_CMD("error", SCErrorAction);
107   DEF_CMD("clear", SCClearAction);
108   DEF_CMD("clearStruct", SCClearStructAction);
109   DEF_CMD("clearArray", SCClearArrayAction);
110   DEF_CMD("size", SCSizeAction);
111   DEF_CMD("arrayIndex", SCArrayIndexAction);
112   DEF_CMD("logVars", SCLogVarsAction);
113   DEF_CMD("logParams", SCLogParamsAction);
114   DEF_CMD("logSelects", SCLogSelectsAction);
115   DEF_CMD("logAll", SCLogAllAction);
116 
117   DEF_CMD("setTimer", SCSetTimerAction);
118   DEF_CMD("removeTimer", SCRemoveTimerAction);
119   DEF_CMD("removeTimers", SCRemoveTimersAction);
120 
121   DEF_CMD("setPrompts", SCSetPromptsAction);
122 
123   DEF_CMD("postEvent", SCPostEventAction);
124 
125   DEF_CMD("registerEventQueue", SCRegisterEventQueueAction);
126   DEF_CMD("unregisterEventQueue", SCUnregisterEventQueueAction);
127   DEF_CMD("createSystemDSM", SCCreateSystemDSMAction);
128 
129   if (cmd == "DI") {
130     SCDIAction * a = new SCDIAction(params, false);
131     a->name = from_str;
132     return a;
133   }
134 
135   if (cmd == "DIgetResult") {
136     SCDIAction * a = new SCDIAction(params, true);
137     a->name = from_str;
138     return a;
139   }
140 
141   if (cmd == "DIgetResultArray") {
142     SCDIAction * a = new SCDIAction(params, true);
143     a->name = from_str;
144     return a;
145   }
146 
147   DEF_CMD("B2B.connectCallee", SCB2BConnectCalleeAction);
148   DEF_CMD("B2B.terminateOtherLeg", SCB2BTerminateOtherLegAction);
149   DEF_CMD("B2B.sendReinvite", SCB2BReinviteAction);
150   DEF_CMD("B2B.enableEarlyMediaRelay", SCB2BEnableEarlyMediaRelayAction);
151   DEF_CMD("B2B.addHeader", SCB2BAddHeaderAction);
152   DEF_CMD("B2B.removeHeader", SCB2BRemoveHeaderAction);
153   DEF_CMD("B2B.clearHeaders", SCB2BClearHeadersAction);
154   DEF_CMD("B2B.setHeaders", SCB2BSetHeadersAction);
155   DEF_CMD("B2B.relayEvent", SCRelayB2BEventAction);
156   DEF_CMD("B2B.setRelayOnly", SCB2BSetRelayOnlyAction);
157 
158   DEF_CMD("trackObject", SCTrackObjectAction);
159   DEF_CMD("releaseObject", SCReleaseObjectAction);
160   DEF_CMD("freeObject", SCFreeObjectAction);
161 
162   return NULL;
163 }
164 
getCondition(const string & from_str)165 DSMCondition* DSMCoreModule::getCondition(const string& from_str) {
166   string cmd;
167   string params;
168   splitCmd(from_str, cmd, params);
169 
170   if (cmd == "keyPress") {
171     DSMCondition* c = new DSMCondition();
172     c->name = "key pressed: " + params;
173     c->type = DSMCondition::Key;
174     c->params["key"] = params;
175     return c;
176   }
177 
178   if (cmd == "test")
179     return new TestDSMCondition(params, DSMCondition::Any);
180 
181   if ((cmd == "keyTest") || (cmd == "key"))
182     return new TestDSMCondition(params, DSMCondition::Key);
183 
184   if ((cmd == "timerTest") || (cmd == "timer"))
185     return new TestDSMCondition(params, DSMCondition::Timer);
186 
187   if ((cmd == "noAudioTest") || (cmd == "noAudio"))
188     return new TestDSMCondition(params, DSMCondition::NoAudio);
189 
190   if ((cmd == "separatorTest") || (cmd == "separator"))
191     return new TestDSMCondition(params, DSMCondition::PlaylistSeparator);
192 
193   if (cmd == "hangup")
194     return new TestDSMCondition(params, DSMCondition::Hangup);
195 
196   if ((cmd == "eventTest") || (cmd == "event"))
197     return new TestDSMCondition(params, DSMCondition::DSMEvent);
198 
199   if (cmd == "B2Bevent")
200     return new TestDSMCondition(params, DSMCondition::B2BEvent);
201 
202   if (cmd == "invite")
203     return new TestDSMCondition(params, DSMCondition::Invite);
204 
205   if (cmd == "earlySession")
206     return new TestDSMCondition(params, DSMCondition::EarlySession);
207 
208   if (cmd == "sessionStart")
209     return new TestDSMCondition(params, DSMCondition::SessionStart);
210 
211   if (cmd == "ringing")
212     return new TestDSMCondition(params, DSMCondition::Ringing);
213 
214   if (cmd == "early")
215     return new TestDSMCondition(params, DSMCondition::EarlySession);
216 
217   if (cmd == "failed")
218     return new TestDSMCondition(params, DSMCondition::FailedCall);
219 
220   if (cmd == "B2B.otherRequest")
221     return new TestDSMCondition(params, DSMCondition::B2BOtherRequest);
222 
223   if (cmd == "B2B.otherReply")
224     return new TestDSMCondition(params, DSMCondition::B2BOtherReply);
225 
226   if (cmd == "B2B.otherBye")
227     return new TestDSMCondition(params, DSMCondition::B2BOtherBye);
228 
229   if (cmd == "sipRequest")
230     return new TestDSMCondition(params, DSMCondition::SipRequest);
231 
232   if (cmd == "sipReply")
233     return new TestDSMCondition(params, DSMCondition::SipReply);
234 
235   if (cmd == "remoteDisappeared")
236     return new TestDSMCondition(params, DSMCondition::RemoteDisappeared);
237 
238   if (cmd == "sessionTimeout")
239     return new TestDSMCondition(params, DSMCondition::SessionTimeout);
240 
241   if (cmd == "rtpTimeout")
242     return new TestDSMCondition(params, DSMCondition::RtpTimeout);
243 
244   if (cmd == "jsonRpcRequest")
245     return new TestDSMCondition(params, DSMCondition::JsonRpcRequest);
246 
247   if (cmd == "jsonRpcResponse")
248     return new TestDSMCondition(params, DSMCondition::JsonRpcResponse);
249 
250   if (cmd == "subscription")
251     return new TestDSMCondition(params, DSMCondition::SIPSubscription);
252 
253   if (cmd == "startup")
254     return new TestDSMCondition(params, DSMCondition::Startup);
255 
256   if (cmd == "start")
257     return new TestDSMCondition(params, DSMCondition::Start);
258 
259   if (cmd == "beforeDestroy")
260     return new TestDSMCondition(params, DSMCondition::BeforeDestroy);
261 
262   if (cmd == "reload")
263     return new TestDSMCondition(params, DSMCondition::Reload);
264 
265   if (cmd == "system")
266     return new TestDSMCondition(params, DSMCondition::System);
267 
268   if (cmd == "rtpTimeout")
269     return new TestDSMCondition(params, DSMCondition::RTPTimeout);
270 
271   return NULL;
272 }
273 
EXEC_ACTION_START(SCPlayPromptAction)274 EXEC_ACTION_START(SCPlayPromptAction) {
275   sc_sess->playPrompt(resolveVars(arg, sess, sc_sess, event_params));
276 } EXEC_ACTION_END;
277 
EXEC_ACTION_START(SCPlayPromptFrontAction)278 EXEC_ACTION_START(SCPlayPromptFrontAction) {
279   sc_sess->playPrompt(resolveVars(arg, sess, sc_sess, event_params), false, true);
280 } EXEC_ACTION_END;
281 
EXEC_ACTION_START(SCSetPromptsAction)282 EXEC_ACTION_START(SCSetPromptsAction) {
283   sc_sess->setPromptSet(resolveVars(arg, sess, sc_sess, event_params));
284 } EXEC_ACTION_END;
285 
286 CONST_ACTION_2P(SCAddSeparatorAction, ',', true);
EXEC_ACTION_START(SCAddSeparatorAction)287 EXEC_ACTION_START(SCAddSeparatorAction){
288   bool front = resolveVars(par2, sess, sc_sess, event_params) == "true";
289   sc_sess->addSeparator(resolveVars(par1, sess, sc_sess, event_params), front);
290 } EXEC_ACTION_END;
291 
EXEC_ACTION_START(SCPlayPromptLoopedAction)292 EXEC_ACTION_START(SCPlayPromptLoopedAction){
293   sc_sess->playPrompt(resolveVars(arg, sess, sc_sess, event_params), true);
294 } EXEC_ACTION_END;
295 
setEventParameters(const DSMSession * sc_sess,const string & var,VarMapT & params)296 void setEventParameters(const DSMSession* sc_sess, const string& var, VarMapT& params) {
297   if (var.empty())
298     return;
299 
300   if (var == "var") {
301     params = sc_sess->var;
302   } else {
303     vector<string> vars = explode(var, ";");
304     for (vector<string>::iterator it = vars.begin(); it != vars.end(); it++) {
305       string varname = *it;
306 
307       if (varname.length() && varname[varname.length()-1]=='.') {
308 	DBG("adding postEvent param %s (struct)\n", varname.c_str());
309 
310 	map<string, string>::const_iterator lb = sc_sess->var.lower_bound(varname);
311 	while (lb != sc_sess->var.end()) {
312 	  if ((lb->first.length() < varname.length()) ||
313 	      strncmp(lb->first.c_str(), varname.c_str(), varname.length()))
314 	    break;
315 	  params[lb->first] = lb->second;
316 	  lb++;
317 	}
318       } else {
319 	VarMapT::const_iterator v_it = sc_sess->var.find(varname);
320 	if (v_it != sc_sess->var.end()) {
321 	  DBG("adding postEvent param %s=%s\n",
322 	      it->c_str(), v_it->second.c_str());
323 	  params[varname] = v_it->second;
324 	}
325       }
326     }
327   }
328 }
329 
330 CONST_ACTION_2P(SCPostEventAction, ',', true);
EXEC_ACTION_START(SCPostEventAction)331 EXEC_ACTION_START(SCPostEventAction){
332   string sess_id = resolveVars(par1, sess, sc_sess, event_params);
333   string var = resolveVars(par2, sess, sc_sess, event_params);
334   DSMEvent* ev = new DSMEvent();
335   setEventParameters(sc_sess, var, ev->params);
336 
337   DBG("posting event to session '%s'\n", sess_id.c_str());
338   if (!AmSessionContainer::instance()->postEvent(sess_id, ev)) {
339     sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
340     sc_sess->SET_STRERROR("event could not be posted\n");
341   } else {
342     sc_sess->CLR_ERRNO;
343   }
344 } EXEC_ACTION_END;
345 
EXEC_ACTION_START(SCRelayB2BEventAction)346 EXEC_ACTION_START(SCRelayB2BEventAction) {
347   AmB2BSession* b2b_sess = dynamic_cast<AmB2BSession*>(sess);
348   if (NULL == b2b_sess) {
349     throw DSMException("script", "cause", "relayEvent used without B2B call");
350   }
351 
352   string var = resolveVars(arg, sess, sc_sess, event_params);
353   B2BEvent* ev = new B2BEvent(E_B2B_APP, B2BEvent::B2BApplication);
354   setEventParameters(sc_sess, var, ev->params);
355 
356   b2b_sess->relayEvent(ev);
357 
358 } EXEC_ACTION_END;
359 
EXEC_ACTION_START(SCB2BSetRelayOnlyAction)360 EXEC_ACTION_START(SCB2BSetRelayOnlyAction) {
361   AmB2BSession* b2b_sess = dynamic_cast<AmB2BSession*>(sess);
362   if (NULL == b2b_sess) {
363     throw DSMException("script", "cause", "B2B.setRelayOnly used without B2B call");
364   }
365   string true_or_false = resolveVars(arg, sess, sc_sess, event_params);
366   DBG("setting sip_relay_only to '%s'\n", true_or_false.c_str());
367   b2b_sess->set_sip_relay_only(true_or_false == "true");
368 } EXEC_ACTION_END;
369 
370 CONST_ACTION_2P(SCPlayFileAction, ',', true);
EXEC_ACTION_START(SCPlayFileAction)371 EXEC_ACTION_START(SCPlayFileAction) {
372   bool loop =
373     resolveVars(par2, sess, sc_sess, event_params) == "true";
374   DBG("par1 = '%s', par2 = %s\n", par1.c_str(), par2.c_str());
375   sc_sess->playFile(resolveVars(par1, sess, sc_sess, event_params),
376 		    loop);
377 } EXEC_ACTION_END;
378 
379 CONST_ACTION_2P(SCPlayFileFrontAction, ',', true);
EXEC_ACTION_START(SCPlayFileFrontAction)380 EXEC_ACTION_START(SCPlayFileFrontAction) {
381   bool loop =
382     resolveVars(par2, sess, sc_sess, event_params) == "true";
383   DBG("par1 = '%s', par2 = %s\n", par1.c_str(), par2.c_str());
384   sc_sess->playFile(resolveVars(par1, sess, sc_sess, event_params),
385 		    loop, true);
386 } EXEC_ACTION_END;
387 
EXEC_ACTION_START(SCPlaySilenceAction)388 EXEC_ACTION_START(SCPlaySilenceAction) {
389   int length;
390   string length_str = resolveVars(arg, sess, sc_sess, event_params);
391   if (!str2int(length_str, length)) {
392     throw DSMException("core", "cause", "cannot parse number");
393   }
394   sc_sess->playSilence(length);
395 } EXEC_ACTION_END;
396 
397 
398 CONST_ACTION_2P(SCPlayRingtoneAction, ',', false);
EXEC_ACTION_START(SCPlayRingtoneAction)399 EXEC_ACTION_START(SCPlayRingtoneAction) {
400   int length = 0, on=0, off=0, f=0, f2=0;
401 
402   string varname = par1;
403   if (varname.length() && varname[0]=='$')
404     varname = varname.substr(1);
405 
406   string front = resolveVars(par2, sess, sc_sess, event_params);
407 
408 #define GET_VAR_INT(var_str, var_name)					\
409   it = sc_sess->var.find(varname+"." var_str);				\
410   if (it != sc_sess->var.end()) {					\
411     if (!str2int(it->second, var_name)) {				\
412       throw DSMException("core", "cause", "cannot parse number");	\
413     }									\
414   }
415 
416   VarMapT::iterator
417 
418   GET_VAR_INT("length", length);
419   GET_VAR_INT("on", on);
420   GET_VAR_INT("off", off);
421   GET_VAR_INT("f", f);
422   GET_VAR_INT("f2", f2);
423 
424 #undef GET_VAR_INT
425   DBG("Playing ringtone with length %d, on %d, off %d, f %d, f2 %d, front %s\n",
426       length, on, off, f, f2, front.c_str());
427   sc_sess->playRingtone(length, on, off, f, f2, front=="true");
428 } EXEC_ACTION_END;
429 
EXEC_ACTION_START(SCPlaySilenceFrontAction)430 EXEC_ACTION_START(SCPlaySilenceFrontAction) {
431   int length;
432   string length_str = resolveVars(arg, sess, sc_sess, event_params);
433   if (!str2int(length_str, length)) {
434     throw DSMException("core", "cause", "cannot parse number");
435   }
436   sc_sess->playSilence(length, true);
437 } EXEC_ACTION_END;
438 
EXEC_ACTION_START(SCRecordFileAction)439 EXEC_ACTION_START(SCRecordFileAction) {
440   sc_sess->recordFile(resolveVars(arg, sess, sc_sess, event_params));
441 } EXEC_ACTION_END;
442 
EXEC_ACTION_START(SCStopRecordAction)443 EXEC_ACTION_START(SCStopRecordAction) {
444   sc_sess->stopRecord();
445 } EXEC_ACTION_END;
446 
EXEC_ACTION_START(SCGetRecordLengthAction)447 EXEC_ACTION_START(SCGetRecordLengthAction) {
448   string varname = resolveVars(arg, sess, sc_sess, event_params);
449   if (varname.empty())
450     varname = "record_length";
451   sc_sess->var[varname]=int2str(sc_sess->getRecordLength());
452 } EXEC_ACTION_END;
453 
EXEC_ACTION_START(SCGetRecordDataSizeAction)454 EXEC_ACTION_START(SCGetRecordDataSizeAction) {
455   string varname = resolveVars(arg, sess, sc_sess, event_params);
456   if (varname.empty())
457     varname = "record_data_size";
458   sc_sess->var[varname]=int2str(sc_sess->getRecordDataSize());
459 } EXEC_ACTION_END;
460 
EXEC_ACTION_START(SCFlushPlaylistAction)461 EXEC_ACTION_START(SCFlushPlaylistAction) {
462   sc_sess->flushPlaylist();
463 } EXEC_ACTION_END;
464 
EXEC_ACTION_START(SCClosePlaylistAction)465 EXEC_ACTION_START(SCClosePlaylistAction) {
466   WARN("closePlaylist() is deprecated - please use flushPlaylist() instead\n");
467   sc_sess->flushPlaylist();
468 } EXEC_ACTION_END;
469 
470 
EXEC_ACTION_START(SCSetInOutPlaylistAction)471 EXEC_ACTION_START(SCSetInOutPlaylistAction) {
472   sc_sess->setInOutPlaylist();
473 } EXEC_ACTION_END;
474 
EXEC_ACTION_START(SCSetInputPlaylistAction)475 EXEC_ACTION_START(SCSetInputPlaylistAction) {
476   sc_sess->setInputPlaylist();
477 } EXEC_ACTION_END;
478 
EXEC_ACTION_START(SCSetOutputPlaylistAction)479 EXEC_ACTION_START(SCSetOutputPlaylistAction) {
480   sc_sess->setOutputPlaylist();
481 } EXEC_ACTION_END;
482 
EXEC_ACTION_START(SCConnectMediaAction)483 EXEC_ACTION_START(SCConnectMediaAction) {
484   sc_sess->connectMedia();
485 } EXEC_ACTION_END;
486 
EXEC_ACTION_START(SCDisconnectMediaAction)487 EXEC_ACTION_START(SCDisconnectMediaAction) {
488   sc_sess->disconnectMedia();
489 } EXEC_ACTION_END;
490 
EXEC_ACTION_START(SCEnableReceivingAction)491 EXEC_ACTION_START(SCEnableReceivingAction) {
492   DBG("enabling RTP receving in session\nb");
493   sess->setReceiving(true);
494 } EXEC_ACTION_END;
495 
EXEC_ACTION_START(SCDisableReceivingAction)496 EXEC_ACTION_START(SCDisableReceivingAction) {
497   DBG("disabling RTP receving in session\nb");
498   sess->setReceiving(false);
499 } EXEC_ACTION_END;
500 
EXEC_ACTION_START(SCEnableForceDTMFReceiving)501 EXEC_ACTION_START(SCEnableForceDTMFReceiving) {
502   DBG("enabling forced DTMF RTP receving in session\nb");
503   sess->setForceDtmfReceiving(true);
504 } EXEC_ACTION_END;
505 
EXEC_ACTION_START(SCDisableForceDTMFReceiving)506 EXEC_ACTION_START(SCDisableForceDTMFReceiving) {
507   DBG("disabling forced DTMF RTP receving in session\nb");
508   sess->setForceDtmfReceiving(false);
509 } EXEC_ACTION_END;
510 
EXEC_ACTION_START(SCMonitorRTPTimeoutAction)511 EXEC_ACTION_START(SCMonitorRTPTimeoutAction) {
512   string e = resolveVars(arg, sess, sc_sess, event_params);
513   DBG("setting RTP stream to %smonitor RTP timeout\n", e=="true"?"":"not");
514   sess->RTPStream()->setMonitorRTPTimeout(e=="true");
515 } EXEC_ACTION_END;
516 
EXEC_ACTION_START(SCMuteAction)517 EXEC_ACTION_START(SCMuteAction) {
518   sc_sess->mute();
519 } EXEC_ACTION_END;
520 
EXEC_ACTION_START(SCUnmuteAction)521 EXEC_ACTION_START(SCUnmuteAction) {
522   sc_sess->unmute();
523 } EXEC_ACTION_END;
524 
525 
EXEC_ACTION_START(SCEnableDTMFDetection)526 EXEC_ACTION_START(SCEnableDTMFDetection) {
527   sess->setDtmfDetectionEnabled(true);
528 } EXEC_ACTION_END;
529 
EXEC_ACTION_START(SCDisableDTMFDetection)530 EXEC_ACTION_START(SCDisableDTMFDetection) {
531   sess->setDtmfDetectionEnabled(false);
532 } EXEC_ACTION_END;
533 
534 CONST_ACTION_2P(SCThrowAction, ',', true);
EXEC_ACTION_START(SCThrowAction)535 EXEC_ACTION_START(SCThrowAction) {
536   map<string, string> e_args;
537   e_args["type"] = resolveVars(par1, sess, sc_sess, event_params);
538   DBG("throwing DSMException type '%s'\n", e_args["type"].c_str());
539 
540   string e_params = resolveVars(par2, sess, sc_sess, event_params);
541 
542   // inefficient param-split
543   vector<string> params = explode(e_params, ";");
544   for (vector<string>::iterator it=
545 	 params.begin(); it != params.end(); it++) {
546     vector<string> n = explode(*it, "=");
547     if (n.size()==2) {
548       e_args[n[0]]=n[1];
549     }
550   }
551 
552   throw DSMException(e_args);
553 
554 } EXEC_ACTION_END;
555 
EXEC_ACTION_START(SCThrowOnErrorAction)556 EXEC_ACTION_START(SCThrowOnErrorAction) {
557   if (sc_sess->var["errno"].empty())
558     EXEC_ACTION_STOP;
559 
560   map<string, string> e_args;
561   e_args["type"] = sc_sess->var["errno"];
562 
563   DBG("throwing DSMException type '%s'\n", e_args["type"].c_str());
564   e_args["text"] = sc_sess->var["strerror"];
565 
566   throw DSMException(e_args);
567 
568 } EXEC_ACTION_END;
569 
570 
EXEC_ACTION_START(SCStopAction)571 EXEC_ACTION_START(SCStopAction) {
572   if (resolveVars(arg, sess, sc_sess, event_params) == "true") {
573     DBG("sending bye\n");
574     sess->dlg->bye();
575   }
576   sess->setStopped();
577 } EXEC_ACTION_END;
578 
579 #define DEF_SCModActionExec(clsname)				\
580 								\
581   bool clsname::execute(AmSession* sess, DSMSession* sc_sess,	\
582 			DSMCondition::EventType event,		\
583 			map<string,string>* event_params) {	\
584     return true;						\
585   }								\
586 
587 DEF_SCModActionExec(SCRepostAction);
getSEAction(string & param,AmSession * sess,DSMSession * sc_sess,DSMCondition::EventType event,map<string,string> * event_params)588 DSMAction::SEAction SCRepostAction::getSEAction(string& param,
589 						AmSession* sess, DSMSession* sc_sess,
590 						DSMCondition::EventType event,
591 						map<string,string>* event_params) {
592   return Repost;
593 }
594 
595 DEF_SCModActionExec(SCJumpFSMAction);
getSEAction(string & param,AmSession * sess,DSMSession * sc_sess,DSMCondition::EventType event,map<string,string> * event_params)596 DSMAction::SEAction SCJumpFSMAction::getSEAction(string& param,
597 						 AmSession* sess, DSMSession* sc_sess,
598 						 DSMCondition::EventType event,
599 						 map<string,string>* event_params) {
600   param = resolveVars(arg, sess, sc_sess, event_params);
601   return Jump;
602 }
603 
604 DEF_SCModActionExec(SCBreakAction);
getSEAction(string & param,AmSession * sess,DSMSession * sc_sess,DSMCondition::EventType event,map<string,string> * event_params)605 DSMAction::SEAction SCBreakAction::getSEAction(string& param,
606 						 AmSession* sess, DSMSession* sc_sess,
607 						 DSMCondition::EventType event,
608 						 map<string,string>* event_params) {
609   param = resolveVars(arg, sess, sc_sess, event_params);
610   return Break;
611 }
612 
613 DEF_SCModActionExec(SCCallFSMAction);
getSEAction(string & param,AmSession * sess,DSMSession * sc_sess,DSMCondition::EventType event,map<string,string> * event_params)614 DSMAction::SEAction SCCallFSMAction::getSEAction(string& param,
615 						 AmSession* sess, DSMSession* sc_sess,
616 						 DSMCondition::EventType event,
617 						 map<string,string>* event_params) {
618   param = resolveVars(arg, sess, sc_sess, event_params);
619   return Call;
620 }
621 
622 DEF_SCModActionExec(SCReturnFSMAction);
getSEAction(string & param,AmSession * sess,DSMSession * sc_sess,DSMCondition::EventType event,map<string,string> * event_params)623 DSMAction::SEAction SCReturnFSMAction::getSEAction(string& param,
624 						   AmSession* sess, DSMSession* sc_sess,
625 						   DSMCondition::EventType event,
626 						   map<string,string>* event_params) {
627   return Return;
628 }
629 
630 #undef DEF_SCModActionExec
631 
632 CONST_ACTION_2P(SCLogAction, ',', false);
EXEC_ACTION_START(SCLogAction)633 EXEC_ACTION_START(SCLogAction) {
634   unsigned int lvl;
635   if (str2i(resolveVars(par1, sess, sc_sess, event_params), lvl)) {
636     ERROR("unknown log level '%s'\n", par1.c_str());
637     EXEC_ACTION_STOP;
638   }
639   string l_line = resolveVars(par2, sess, sc_sess, event_params).c_str();
640   _LOG((int)lvl, "FSM: %s '%s'\n", (par2 != l_line)?par2.c_str():"",
641        l_line.c_str());
642 } EXEC_ACTION_END;
643 
644 CONST_ACTION_2P(SCLogsAction, ',', false);
EXEC_ACTION_START(SCLogsAction)645 EXEC_ACTION_START(SCLogsAction) {
646   unsigned int lvl;
647   if (str2i(resolveVars(par1, sess, sc_sess, event_params), lvl)) {
648     ERROR("unknown log level '%s'\n", par1.c_str());
649     EXEC_ACTION_STOP;
650   }
651   string l_line = replaceParams(par2, sess, sc_sess, event_params);
652   _LOG((int)lvl, "FSM: '%s'\n", l_line.c_str());
653 } EXEC_ACTION_END;
654 
EXEC_ACTION_START(SCDbgAction)655 EXEC_ACTION_START(SCDbgAction) {
656   string l_line = replaceParams(arg, sess, sc_sess, event_params);
657   DBG("FSM: '%s'\n", l_line.c_str());
658 } EXEC_ACTION_END;
659 
EXEC_ACTION_START(SCInfoAction)660 EXEC_ACTION_START(SCInfoAction) {
661   string l_line = replaceParams(arg, sess, sc_sess, event_params);
662   INFO("FSM: '%s'\n", l_line.c_str());
663 } EXEC_ACTION_END;
664 
EXEC_ACTION_START(SCWarnAction)665 EXEC_ACTION_START(SCWarnAction) {
666   string l_line = replaceParams(arg, sess, sc_sess, event_params);
667   WARN("FSM: '%s'\n", l_line.c_str());
668 } EXEC_ACTION_END;
669 
EXEC_ACTION_START(SCErrorAction)670 EXEC_ACTION_START(SCErrorAction) {
671   string l_line = replaceParams(arg, sess, sc_sess, event_params);
672   ERROR("FSM: '%s'\n", l_line.c_str());
673 } EXEC_ACTION_END;
674 
log_vars(const string & l_arg,AmSession * sess,DSMSession * sc_sess,map<string,string> * event_params)675 void log_vars(const string& l_arg, AmSession* sess,
676 	      DSMSession* sc_sess, map<string,string>* event_params) {
677   unsigned int lvl;
678   if (str2i(resolveVars(l_arg, sess, sc_sess, event_params), lvl)) {
679     ERROR("unknown log level '%s'\n", l_arg.c_str());
680     return;
681   }
682 
683   _LOG((int)lvl, "FSM: variables set ---\n");
684   for (map<string, string>::iterator it =
685 	 sc_sess->var.begin(); it != sc_sess->var.end(); it++) {
686     _LOG((int)lvl, "FSM:  $%s='%s'\n", it->first.c_str(), it->second.c_str());
687   }
688   _LOG((int)lvl, "FSM: variables end ---\n");
689 }
690 
EXEC_ACTION_START(SCLogVarsAction)691 EXEC_ACTION_START(SCLogVarsAction) {
692   log_vars(arg, sess, sc_sess, event_params);
693 } EXEC_ACTION_END;
694 
log_params(const string & l_arg,AmSession * sess,DSMSession * sc_sess,map<string,string> * event_params)695 void log_params(const string& l_arg, AmSession* sess,
696 		DSMSession* sc_sess, map<string,string>* event_params) {
697   unsigned int lvl;
698   if (str2i(resolveVars(l_arg, sess, sc_sess, event_params), lvl)) {
699     ERROR("unknown log level '%s'\n", l_arg.c_str());
700     return;
701   }
702 
703   if (NULL == event_params) {
704     _LOG((int)lvl, "FSM: no event params ---\n");
705     return;
706   }
707 
708   _LOG((int)lvl, "FSM: params set ---\n");
709   for (map<string, string>::iterator it =
710 	 event_params->begin(); it != event_params->end(); it++) {
711     _LOG((int)lvl, "FSM:  #%s='%s'\n", it->first.c_str(), it->second.c_str());
712   }
713   _LOG((int)lvl, "FSM: params end ---\n");
714 }
715 
EXEC_ACTION_START(SCLogParamsAction)716 EXEC_ACTION_START(SCLogParamsAction) {
717   log_params(arg, sess, sc_sess, event_params);
718 } EXEC_ACTION_END;
719 
720 
log_selects(const string & l_arg,AmSession * sess,DSMSession * sc_sess,map<string,string> * event_params)721 void log_selects(const string& l_arg, AmSession* sess,
722 		 DSMSession* sc_sess, map<string,string>* event_params) {
723   unsigned int lvl;
724   if (str2i(resolveVars(l_arg, sess, sc_sess, event_params), lvl)) {
725     ERROR("unknown log level '%s'\n", l_arg.c_str());
726     return;
727   }
728 
729   _LOG((int)lvl, "FSM: selects set ---\n");
730 
731 #define SELECT_LOG(select_name)					\
732   _LOG((int)lvl, "FSM:  @%s='%s'\n", select_name,			\
733        resolveVars("@" select_name, sess, sc_sess, event_params).c_str());
734 
735   SELECT_LOG("local_tag");
736   SELECT_LOG("user");
737   SELECT_LOG("domain");
738   SELECT_LOG("remote_tag");
739   SELECT_LOG("callid");
740   SELECT_LOG("local_uri");
741   SELECT_LOG("local_party");
742   SELECT_LOG("remote_uri");
743   SELECT_LOG("remote_party");
744 #undef SELECT_LOG
745   _LOG((int)lvl, "FSM: selects end ---\n");
746 }
747 
EXEC_ACTION_START(SCLogSelectsAction)748 EXEC_ACTION_START(SCLogSelectsAction) {
749   log_selects(arg, sess, sc_sess, event_params);
750 } EXEC_ACTION_END;
751 
EXEC_ACTION_START(SCLogAllAction)752 EXEC_ACTION_START(SCLogAllAction) {
753   log_vars(arg, sess, sc_sess, event_params);
754   log_params(arg, sess, sc_sess, event_params);
755   log_selects(arg, sess, sc_sess, event_params);
756 } EXEC_ACTION_END;
757 
758 CONST_ACTION_2P(SCSetAction,'=', false);
EXEC_ACTION_START(SCSetAction)759 EXEC_ACTION_START(SCSetAction) {
760   if (par1.length() && par1[0] == '#') {
761     // set param
762     if (NULL != event_params) {
763       string res = resolveVars(par2, sess, sc_sess, event_params);
764       (*event_params)[par1.substr(1)] = res;
765       DBG("set #%s='%s'\n", par1.substr(1).c_str(), res.c_str());
766     } else {
767       DBG("not setting %s (no param set)\n", par1.c_str());
768     }
769   } else {
770     // set variable
771     string var_name = (par1.length() && par1[0] == '$')?
772       par1.substr(1) : par1;
773 
774     sc_sess->var[var_name] = resolveVars(par2, sess, sc_sess, event_params);
775 
776     DBG("set $%s='%s'\n",
777 	var_name.c_str(), sc_sess->var[var_name].c_str());
778   }
779 } EXEC_ACTION_END;
780 
replaceParams(const string & q,AmSession * sess,DSMSession * sc_sess,map<string,string> * event_params)781 string replaceParams(const string& q, AmSession* sess, DSMSession* sc_sess,
782 		     map<string,string>* event_params) {
783   string res = q;
784   size_t repl_pos = 0;
785   while (repl_pos<res.length()) {
786     size_t rstart = res.find_first_of("$#@", repl_pos);
787     repl_pos = rstart+1;
788     if (rstart == string::npos)
789       break;
790     if (rstart && (res.length() > rstart) && (res[rstart]==res[repl_pos])) {
791       res.erase(rstart, 1);
792       continue;
793     }
794     if (rstart && res[rstart-1] == '\\') // escaped
795       continue;
796     size_t rend;
797     if (res.length() > rstart+1 &&
798 	(res[rstart+1] == '(' ||
799 	 res[rstart+1] == '"' ||
800 	 res[rstart+1] == '\''
801 	 ))
802       rend = res.find_first_of(" ,()[]$#@\t;:'\"", rstart+2);
803     else
804       rend = res.find_first_of(" ,()[]$#@\t;:'\"", rstart+1);
805     if (rend==string::npos)
806       rend = res.length();
807     string keyname = res.substr(rstart+1, rend-rstart-1);
808 
809     if (keyname.length()>2) {
810       if ((keyname[0] == '(' && res[rend] == ')') ||
811 	  (keyname[0] == res[rend] &&
812 	   (keyname[0] == '"' ||keyname[0] == '\''))) {
813 	keyname = keyname.substr(1);
814 	if (rend != res.length())
815 	  rend++;
816       }
817     }
818     // todo: simply use resolveVars (?)
819     switch(res[rstart]) {
820     case '$': {
821       if (sc_sess->var.find(keyname) == sc_sess->var.end()) {
822 	res.erase(rstart, rend-rstart);
823 	if (repl_pos) repl_pos--; // repl_pos was after $
824       } else {
825 	res.replace(rstart, rend-rstart, sc_sess->var[keyname]);
826 	if (sc_sess->var[keyname].size())
827 	  repl_pos+=sc_sess->var[keyname].size()-1; // skip after new string
828       }
829     } break;
830     case '#':
831       if (NULL!=event_params) {
832 	if (event_params->find(keyname) != event_params->end()) {
833 	  res.replace(rstart, rend-rstart, (*event_params)[keyname]);
834 	  repl_pos+=(*event_params)[keyname].size()-1; // skip after new string
835 	} else {
836 	  res.erase(rstart, rend-rstart);
837 	  if (repl_pos) repl_pos--; // repl_pos was after #
838 	}
839       } break;
840     case '@': {
841       // todo: optimize
842       string n = resolveVars("@"+keyname, sess, sc_sess, event_params);
843       res.replace(rstart, rend-rstart, n);
844       if (n.size())
845 	repl_pos+=n.size()-1;  // skip after new string
846         //    rstart  rend
847 	// bla@(varname)uuuu
848         //     r
849         //         r
850         // bla12345huuuu
851     } break;
852     default: break;
853     }
854   }
855   return res;
856 }
857 CONST_ACTION_2P(SCSetSAction,'=', false);
EXEC_ACTION_START(SCSetSAction)858 EXEC_ACTION_START(SCSetSAction) {
859   if (par1.length() && par1[0] == '#') {
860     // set param
861     if (NULL != event_params) {
862       string res = replaceParams(par2, sess, sc_sess, event_params);
863       (*event_params)[par1.substr(1)] = res;
864       DBG("set #%s='%s'\n", par1.substr(1).c_str(), res.c_str());
865     } else {
866       DBG("not set %s (no param set)\n", par1.c_str());
867     }
868   } else {
869     // set variable
870     string var_name = (par1.length() && par1[0] == '$')?
871       par1.substr(1) : par1;
872 
873     sc_sess->var[var_name] = replaceParams(par2, sess, sc_sess, event_params);
874 
875     DBG("set $%s='%s'\n",
876 	var_name.c_str(), sc_sess->var[var_name].c_str());
877   }
878 } EXEC_ACTION_END;
879 
880 CONST_ACTION_2P(SCEvalAction,'=', false);
EXEC_ACTION_START(SCEvalAction)881 EXEC_ACTION_START(SCEvalAction) {
882   string var_name = (par1.length() && par1[0] == '$')?
883     par1.substr(1) : par1;
884 
885   sc_sess->var[var_name] = resolveVars(par2, sess, sc_sess, event_params, true);
886   DBG("eval $%s='%s'\n",
887       var_name.c_str(), sc_sess->var[var_name].c_str());
888 } EXEC_ACTION_END;
889 
890 CONST_ACTION_2P(SCSetVarAction,'=', false);
EXEC_ACTION_START(SCSetVarAction)891 EXEC_ACTION_START(SCSetVarAction) {
892   string var_name = resolveVars(par1, sess, sc_sess, event_params);
893   sc_sess->var[var_name] = resolveVars(par2, sess, sc_sess, event_params);
894   DBG("set $%s='%s'\n",
895       var_name.c_str(), sc_sess->var[var_name].c_str());
896 } EXEC_ACTION_END;
897 
898 CONST_ACTION_2P(SCGetParamAction,'=', false);
EXEC_ACTION_START(SCGetParamAction)899 EXEC_ACTION_START(SCGetParamAction){
900 
901   string dst_var_name = (par1.length() && par1[0] == '$')?
902     par1.substr(1) : par1;
903   string param_name = resolveVars(par2, sess, sc_sess, event_params);
904 
905   DBG("param_name = %s, dst = %s\n", param_name.c_str(), dst_var_name.c_str());
906 
907   if (NULL==event_params) {
908     sc_sess->var[dst_var_name] = "";
909     EXEC_ACTION_STOP;
910   }
911 
912   map<string, string>::iterator it = event_params->find(param_name);
913   if (it != event_params->end()) {
914     sc_sess->var[dst_var_name] = it->second;
915   } else {
916     sc_sess->var[dst_var_name] = "";
917   }
918 
919   DBG("set $%s='%s'\n",
920       dst_var_name.c_str(), sc_sess->var[dst_var_name].c_str());
921 } EXEC_ACTION_END;
922 
923 CONST_ACTION_2P(SCGetVarAction,'=', false);
EXEC_ACTION_START(SCGetVarAction)924 EXEC_ACTION_START(SCGetVarAction){
925   string dst_var_name = (par1.length() && par1[0] == '$')?
926     par1.substr(1) : par1;
927   string var_name = resolveVars(par2, sess, sc_sess, event_params);
928 
929   DBG("var_name = %s, dst = %s\n", var_name.c_str(), dst_var_name.c_str());
930   sc_sess->var[dst_var_name] = sc_sess->var[var_name];
931   DBG("set $%s='%s'\n",
932       dst_var_name.c_str(), sc_sess->var[dst_var_name].c_str());
933 } EXEC_ACTION_END;
934 
EXEC_ACTION_START(SCClearAction)935 EXEC_ACTION_START(SCClearAction) {
936   string var_name = (arg.length() && arg[0] == '$')?
937     arg.substr(1) : arg;
938   DBG("clear variable '%s'\n", var_name.c_str());
939   sc_sess->var.erase(var_name);
940 } EXEC_ACTION_END;
941 
EXEC_ACTION_START(SCClearStructAction)942 EXEC_ACTION_START(SCClearStructAction) {
943   string varprefix = (arg.length() && arg[0] == '$')?
944     arg.substr(1) : arg;
945   DBG("clear variable struct '%s.*'\n", varprefix.c_str());
946 
947   varprefix+=".";
948 
949   map<string, string>::iterator lb = sc_sess->var.lower_bound(varprefix);
950   while (lb != sc_sess->var.end()) {
951     if ((lb->first.length() < varprefix.length()) ||
952 	strncmp(lb->first.c_str(), varprefix.c_str(),varprefix.length()))
953       break;
954     map<string, string>::iterator lb_d = lb;
955     lb++;
956     sc_sess->var.erase(lb_d);
957   }
958 
959 } EXEC_ACTION_END;
960 
961 
EXEC_ACTION_START(SCClearArrayAction)962 EXEC_ACTION_START(SCClearArrayAction) {
963   string varprefix = (arg.length() && arg[0] == '$')?
964     arg.substr(1) : arg;
965   DBG("clear variable array '%s[*'\n", varprefix.c_str());
966 
967   varprefix+="[";
968 
969   VarMapT::iterator lb = sc_sess->var.lower_bound(varprefix);
970   while (lb != sc_sess->var.end()) {
971     if ((lb->first.length() < varprefix.length()) ||
972 	strncmp(lb->first.c_str(), varprefix.c_str(),varprefix.length()))
973       break;
974     // fixme: check whether it's really an array index
975     VarMapT::iterator lb_d = lb;
976     lb++;
977     sc_sess->var.erase(lb_d);
978   }
979 
980 } EXEC_ACTION_END;
981 
982 CONST_ACTION_2P(SCSizeAction, ',', false);
EXEC_ACTION_START(SCSizeAction)983 EXEC_ACTION_START(SCSizeAction) {
984   string array_name = par1;
985   if (array_name.length() && array_name[0]=='$')
986     array_name.erase(0,1);
987 
988   string dst_name = par2;
989   if (dst_name.length()&&dst_name[0]=='$')
990     dst_name.erase(0,1);
991 
992 
993   unsigned int a_size = 0;
994   while (true) {
995     string ai_name = array_name+"["+int2str(a_size)+"]";
996     VarMapT::iterator lb = sc_sess->var.lower_bound(ai_name);
997     if (lb == sc_sess->var.end() ||
998 	lb->first.substr(0,ai_name.length()) != ai_name)
999       break;
1000     a_size++;
1001   }
1002   string res = int2str(a_size);
1003   sc_sess->var[dst_name] = res;
1004   DBG("set $%s=%s\n", dst_name.c_str(), res.c_str());
1005 } EXEC_ACTION_END;
1006 
1007 CONST_ACTION_2P(SCArrayIndexAction, ',', false);
EXEC_ACTION_START(SCArrayIndexAction)1008 EXEC_ACTION_START(SCArrayIndexAction) {
1009   string array_name = par1;
1010   if (array_name.length() && array_name[0]=='$')
1011     array_name.erase(0,1);
1012 
1013   string val = resolveVars(par2, sess, sc_sess, event_params);
1014   unsigned int i = 0;
1015   bool found = false;
1016   while (true) {
1017     VarMapT::iterator lb = sc_sess->var.find(array_name+"["+int2str(i)+"]");
1018     if (lb == sc_sess->var.end())
1019       break;
1020     if (val == lb->second) {
1021       found = true;
1022       break;
1023     }
1024     i++;
1025   }
1026 
1027   string res = found ? int2str(i) : "nil";
1028   if (par2[0]=='$') {
1029     sc_sess->var[par2.substr(1)+".index"] = res;
1030     DBG("set %s=%s\n", (par2+".index").c_str(), res.c_str());
1031   } else {
1032     sc_sess->var["index"] = res;
1033     DBG("set $index=%s\n", res.c_str());
1034   }
1035 } EXEC_ACTION_END;
1036 
1037 CONST_ACTION_2P(SCAppendAction,',', false);
EXEC_ACTION_START(SCAppendAction)1038 EXEC_ACTION_START(SCAppendAction) {
1039   string var_name = (par1.length() && par1[0] == '$')?
1040     par1.substr(1) : par1;
1041 
1042   sc_sess->var[var_name] += resolveVars(par2, sess, sc_sess, event_params);
1043 
1044   DBG("$%s now '%s'\n",
1045       var_name.c_str(), sc_sess->var[var_name].c_str());
1046 } EXEC_ACTION_END;
1047 
1048 CONST_ACTION_2P(SCSubStrAction,',', false);
EXEC_ACTION_START(SCSubStrAction)1049 EXEC_ACTION_START(SCSubStrAction) {
1050   string var_name = (par1.length() && par1[0] == '$')?
1051     par1.substr(1) : par1;
1052   unsigned int pos = 0;
1053   unsigned int pos2 = 0;
1054   size_t c_pos = par2.find(",");
1055   if (c_pos == string::npos) {
1056     if (str2i(resolveVars(par2, sess, sc_sess, event_params), pos)) {
1057       ERROR("substr length '%s' unparseable\n",
1058 	    resolveVars(par2, sess, sc_sess, event_params).c_str());
1059       return false;
1060     }
1061   } else {
1062     if (str2i(resolveVars(par2.substr(0, c_pos), sess, sc_sess, event_params), pos)) {
1063       ERROR("substr length '%s' unparseable\n",
1064 	    resolveVars(par2.substr(0, c_pos), sess, sc_sess, event_params).c_str());
1065       return false;
1066     }
1067 
1068     if (str2i(resolveVars(par2.substr(c_pos+1), sess, sc_sess, event_params), pos2)) {
1069       ERROR("substr length '%s' unparseable\n",
1070 	    resolveVars(par2.substr(0, c_pos-1), sess, sc_sess, event_params).c_str());
1071       return false;
1072     }
1073   }
1074 
1075   try {
1076     if (pos2 == 0)
1077       sc_sess->var[var_name] = sc_sess->var[var_name].substr(pos);
1078     else
1079       sc_sess->var[var_name] = sc_sess->var[var_name].substr(pos, pos2);
1080   } catch(...) {
1081     ERROR("in substr\n");
1082     return false;
1083   }
1084 
1085   DBG("$%s now '%s'\n",
1086       var_name.c_str(), sc_sess->var[var_name].c_str());
1087 } EXEC_ACTION_END;
1088 
EXEC_ACTION_START(SCIncAction)1089 EXEC_ACTION_START(SCIncAction) {
1090   string var_name = (arg.length() && arg[0] == '$')?
1091     arg.substr(1) : arg;
1092   unsigned int val = 0;
1093   str2i(sc_sess->var[var_name], val);
1094   sc_sess->var[var_name] = int2str(val+1);
1095 
1096   DBG("inc: $%s now '%s'\n",
1097       var_name.c_str(), sc_sess->var[var_name].c_str());
1098 
1099 } EXEC_ACTION_END;
1100 
1101 CONST_ACTION_2P(SCSetTimerAction,',', false);
EXEC_ACTION_START(SCSetTimerAction)1102 EXEC_ACTION_START(SCSetTimerAction) {
1103 
1104   unsigned int timerid;
1105   if (str2i(resolveVars(par1, sess, sc_sess, event_params), timerid)) {
1106     ERROR("timer id '%s' not decipherable\n",
1107 	  resolveVars(par1, sess, sc_sess, event_params).c_str());
1108     sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
1109     sc_sess->SET_STRERROR("timer id '"+
1110 			  resolveVars(par1, sess, sc_sess, event_params)+
1111 			  "' not decipherable\n");
1112     EXEC_ACTION_STOP;
1113   }
1114 
1115   unsigned int timeout;
1116   if (str2i(resolveVars(par2, sess, sc_sess, event_params), timeout)) {
1117     ERROR("timeout value '%s' not decipherable\n",
1118 	  resolveVars(par2, sess, sc_sess, event_params).c_str());
1119     sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
1120     sc_sess->SET_STRERROR("timeout value '"+
1121 			  resolveVars(par2, sess, sc_sess, event_params)+
1122 			  "' not decipherable\n");
1123     EXEC_ACTION_STOP;
1124   }
1125 
1126   if (!sess->setTimer(timerid, timeout)) {
1127     ERROR("load session_timer module for timers.\n");
1128     sc_sess->SET_ERRNO(DSM_ERRNO_CONFIG);
1129     sc_sess->SET_STRERROR("load sess_timer module for timers.\n");
1130     EXEC_ACTION_STOP;
1131   }
1132 
1133   sc_sess->CLR_ERRNO;
1134 } EXEC_ACTION_END;
1135 
1136 
EXEC_ACTION_START(SCRemoveTimerAction)1137 EXEC_ACTION_START(SCRemoveTimerAction) {
1138 
1139   unsigned int timerid;
1140   string timerid_s = resolveVars(arg, sess, sc_sess, event_params);
1141   if (str2i(timerid_s, timerid)) {
1142     ERROR("timer id '%s' not decipherable\n", timerid_s.c_str());
1143     sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
1144     sc_sess->SET_STRERROR("timer id '"+timerid_s+"' not decipherable\n");
1145     return false;
1146   }
1147 
1148   if (!sess->removeTimer(timerid)) {
1149     ERROR("load session_timer module for timers.\n");
1150     sc_sess->SET_ERRNO(DSM_ERRNO_CONFIG);
1151     sc_sess->SET_STRERROR("load session_timer module for timers.\n");
1152     EXEC_ACTION_STOP;
1153   }
1154 
1155   sc_sess->CLR_ERRNO;
1156 } EXEC_ACTION_END;
1157 
EXEC_ACTION_START(SCRemoveTimersAction)1158 EXEC_ACTION_START(SCRemoveTimersAction) {
1159 
1160   DBG("removing timers for session %s\n", sess->getLocalTag().c_str());
1161   if (!sess->removeTimers()) {
1162     ERROR("load session_timer module for timers.\n");
1163     sc_sess->SET_ERRNO(DSM_ERRNO_CONFIG);
1164     sc_sess->SET_STRERROR("load sess_timer module for timers.\n");
1165     EXEC_ACTION_STOP;
1166   }
1167 
1168   sc_sess->CLR_ERRNO;
1169 } EXEC_ACTION_END;
1170 
1171 
1172 
1173 // TODO: replace with real expression matching
TestDSMCondition(const string & expr,DSMCondition::EventType evt)1174 TestDSMCondition::TestDSMCondition(const string& expr, DSMCondition::EventType evt) {
1175 
1176   type = evt;
1177 
1178   if (expr.empty()) {
1179     ttype = Always;
1180     return;
1181   }
1182 
1183   ttype = None;
1184 
1185   size_t p = expr.find("==");
1186   size_t p2;
1187   if (p != string::npos) {
1188     ttype = Eq; p2 = p+2;
1189   } else {
1190     p = expr.find("!=");
1191     if (p != string::npos)  {
1192       ttype = Neq; p2 = p+2;
1193     } else {
1194       p = expr.find("<");
1195       if (p != string::npos) {
1196 	ttype = Less; p2 = p+1;
1197       } else {
1198 	p = expr.find(">");
1199 	if (p != string::npos)  {
1200 	  ttype = Gt; p2 = p+1;
1201 	} else {
1202 	  ERROR("expression '%s' not understood\n",
1203 		expr.c_str());
1204 	  return;
1205 	}
1206       }
1207     }
1208   }
1209 
1210   lhs = trim(expr.substr(0, p), " ");
1211   rhs = trim(expr.substr(p2,expr.length()-p2+1), " ");
1212 
1213   name = expr;
1214 }
1215 
match(AmSession * sess,DSMSession * sc_sess,DSMCondition::EventType event,map<string,string> * event_params)1216 bool TestDSMCondition::match(AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event,
1217 			  map<string,string>* event_params) {
1218   if (ttype == None || (type != DSMCondition::Any && type != event))
1219     return false;
1220 
1221   if (ttype == Always)
1222     return true;
1223 
1224   if (!sc_sess) {
1225     ERROR("wrong session type\n");
1226     return false;
1227   }
1228 
1229   string l;
1230   string r;
1231   if (lhs.length() > 5 &&
1232       (lhs.substr(0, 4) == "len(") && lhs[lhs.length()-1] == ')') {
1233     l = int2str((unsigned int)resolveVars(lhs.substr(4, lhs.length()-5), sess, sc_sess, event_params).length());
1234   } else {
1235     l   = resolveVars(lhs, sess, sc_sess, event_params);
1236   }
1237   if (rhs.length() > 5 &&
1238       rhs.substr(0, 4) == "len(" && rhs[rhs.length()-1] == ')') {
1239     r = resolveVars(rhs.substr(4, rhs.length()-5), sess, sc_sess, event_params).length();
1240   } else {
1241     r   = resolveVars(rhs, sess, sc_sess, event_params);
1242   }
1243 
1244 //   string r = resolveVars(rhs, sess, sc_sess, event_params);
1245 
1246   DBG("test '%s' vs '%s'\n", l.c_str(), r.c_str());
1247 
1248   switch (ttype) {
1249   case Eq: {
1250     size_t starpos = r.find("*");
1251     if (starpos==string::npos)
1252       return l == r;
1253     else {
1254       if (l.size()<starpos)
1255 	return false;
1256       return r.substr(0, starpos) == l.substr(0, starpos);
1257     }
1258   }
1259   case Neq: return l != r;
1260   case Less: {
1261     char* endptr = NULL;
1262     long l_i = strtol(l.c_str(), &endptr, 10);
1263     if (endptr && *endptr  == '\0') {
1264       long r_i = strtol(r.c_str(), &endptr, 10);
1265       if (endptr && *endptr  == '\0')
1266 	return l_i < r_i;
1267       }
1268     return l < r;
1269   }
1270   case Gt: {
1271     char* endptr = NULL;
1272     long l_i = strtol(l.c_str(), &endptr, 10);
1273     if (endptr && *endptr  == '\0') {
1274       long r_i = strtol(r.c_str(), &endptr, 10);
1275       if (endptr && *endptr  == '\0')
1276 	return l_i > r_i;
1277       }
1278     return l > r;
1279   }
1280   default: return false;
1281   }
1282 }
1283 
1284 
SCDIAction(const string & arg,bool get_res)1285 SCDIAction::SCDIAction(const string& arg, bool get_res)
1286   : get_res(get_res) {
1287   // TODO: don't ignore "" (don't use explode here)
1288   params = explode(arg,",");
1289   if (params.size()<2) {
1290     ERROR("DI needs at least: mod_name, "
1291 	  "function_name\n");
1292     return;
1293   }
1294 }
1295 
string2argarray(const string & key,const string & val,AmArg & res)1296 void string2argarray(const string& key, const string& val, AmArg& res) {
1297   if (key.empty())
1298     return;
1299 
1300   if (!(isArgStruct(res) || isArgUndef(res))) {
1301     WARN("array element [%s] is shadowed by value '%s'\n",
1302 	 key.c_str(), AmArg::print(res).c_str());
1303     return;
1304   }
1305 
1306   size_t delim = key.find(".");
1307   if (delim == string::npos) {
1308     res[key]=val;
1309     return;
1310   }
1311   string2argarray(key.substr(delim+1), val, res[key.substr(0,delim)]);
1312 }
1313 
EXEC_ACTION_START(SCDIAction)1314 EXEC_ACTION_START(SCDIAction) {
1315 
1316   if (params.size() < 2) {
1317     ERROR("DI needs at least: mod_name, "
1318 	  "function_name (in '%s')\n", name.c_str());
1319     sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
1320     sc_sess->SET_STRERROR("DI needs at least: mod_name, "
1321 			  "function_name (in '"+name+"%s')\n");
1322     EXEC_ACTION_STOP;
1323   }
1324 
1325   vector<string>::iterator p_it=params.begin();
1326   string fact_name = trim(*p_it, " \"");
1327   AmDynInvokeFactory* fact =
1328     AmPlugIn::instance()->getFactory4Di(fact_name);
1329 
1330   if(!fact) {
1331     ERROR("load module for factory '%s'.\n", fact_name.c_str());
1332     sc_sess->SET_ERRNO(DSM_ERRNO_CONFIG);
1333     sc_sess->SET_STRERROR("load module for factory '"+fact_name+"'.\n");
1334     EXEC_ACTION_STOP;
1335   }
1336   AmDynInvoke* di_inst = fact->getInstance();
1337   if(!di_inst) {
1338     ERROR("load module for factory '%s'\n", fact_name.c_str());
1339     sc_sess->SET_ERRNO(DSM_ERRNO_CONFIG);
1340     sc_sess->SET_STRERROR("load module for factory '"+fact_name+"'.\n");
1341     EXEC_ACTION_STOP;
1342   }
1343   p_it++;
1344 
1345   string func_name = trim(*p_it, " \"");
1346   p_it++;
1347 
1348   AmArg di_args;
1349 
1350   while (p_it != params.end()) {
1351     string p = trim(*p_it, " \t");
1352     if (p.length() && p[0] == '"') {
1353       di_args.push(trim(p,"\"").c_str());
1354     } else if (p.length() > 5 &&
1355 	       p.substr(0, 5) =="(int)") {
1356       p = resolveVars(p.substr(5), sess, sc_sess, event_params);
1357       char* endptr = NULL;
1358       long p_i = strtol(p.c_str(), &endptr, 10);
1359       if (endptr && *endptr  == '\0') {
1360 	di_args.push((int)p_i);
1361       } else {
1362 	ERROR("converting value '%s' to int\n",
1363 	      p.c_str());
1364 	sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
1365 	sc_sess->SET_STRERROR("converting value '"+p+"' to int\n");
1366 	EXEC_ACTION_STOP;
1367       }
1368     } else if (p.length() > 8 &&
1369 	       p.substr(0, 8) =="(struct)") {
1370       p.erase(0, 8);
1371       AmArg var_struct;
1372       string varprefix = p+".";
1373       //bool has_vars = false;
1374       map<string, string>::iterator lb = sc_sess->var.lower_bound(varprefix);
1375       while (lb != sc_sess->var.end()) {
1376 	if ((lb->first.length() < varprefix.length()) ||
1377 	    strncmp(lb->first.c_str(), varprefix.c_str(),varprefix.length()))
1378 	  break;
1379 
1380 	string varname = lb->first.substr(varprefix.length());
1381 	if (varname.find(".") == string::npos)
1382 	  var_struct[varname] = lb->second;
1383 	else
1384 	  string2argarray(varname, lb->second, var_struct);
1385 
1386 	lb++;
1387 	//has_vars = true;
1388       }
1389       di_args.push(var_struct);
1390     } else if (p.length() > 7 &&
1391 	       p.substr(0, 7) =="(array)") {
1392       p.erase(0, 7);
1393       di_args.push(AmArg());
1394       AmArg& var_array = di_args.get(di_args.size()-1);
1395 
1396       unsigned int i=0;
1397       while (true) {
1398 	map<string, string>::iterator it =
1399 	  sc_sess->var.find(p+"["+int2str(i)+"]");
1400 	if (it == sc_sess->var.end())
1401 	  break;
1402 	var_array.push(it->second);
1403 	i++;
1404       }
1405     } else if (p.length() > 6 &&
1406 	       p.substr(0, 6) == "(json)") {
1407       p.erase(0, 6);
1408       if (p.length() && p[0] == '"') {
1409 	// remove quotes if parameter in form (json)"{"json":"object"}"
1410 	p = trim(p,"\"");
1411       } else {
1412 	p = resolveVars(p, sess, sc_sess, event_params);
1413       }
1414 
1415       di_args.push(AmArg());
1416       AmArg& var_json = di_args.get(di_args.size()-1);
1417       if (!json2arg(p, var_json)) {
1418 	WARN("Error parsing JSON object '%s'\n", p.c_str());
1419 	// todo: throw exception?
1420       }
1421     } else {
1422       di_args.push(resolveVars(p, sess, sc_sess, event_params).c_str());
1423     }
1424     p_it++;
1425   }
1426 
1427   sc_sess->di_res.clear();
1428   DBG("executing DI function '%s'\n", func_name.c_str());
1429   try {
1430     di_inst->invoke(func_name, di_args, sc_sess->di_res);
1431   } catch (const AmDynInvoke::NotImplemented& ni) {
1432     ERROR("not implemented DI function '%s'\n",
1433 	  ni.what.c_str());
1434     sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
1435     sc_sess->SET_STRERROR("not implemented DI function '"+ni.what+"'\n");
1436     EXEC_ACTION_STOP;
1437   } catch (const AmArg::OutOfBoundsException& oob) {
1438     ERROR("out of bounds in  DI call '%s'\n",
1439 	  name.c_str());
1440     sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
1441     sc_sess->SET_STRERROR("out of bounds in  DI call '"+name+"'\n");
1442     EXEC_ACTION_STOP;
1443   } catch (const AmArg::TypeMismatchException& oob) {
1444     ERROR("type mismatch  in  DI call '%s'\n",
1445 	  name.c_str());
1446     sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
1447     sc_sess->SET_STRERROR("type mismatch in  DI call '"+name+"'\n");
1448     EXEC_ACTION_STOP;
1449   } catch (...) {
1450     ERROR("unexpected Exception  in  DI call '%s'\n",
1451 	  name.c_str());
1452     sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
1453     sc_sess->SET_STRERROR("unexpected Exception in  DI call '"+name+"'\n");
1454     EXEC_ACTION_STOP;
1455   }
1456 
1457   bool flag_error = false;
1458   if (get_res) {
1459     // rudimentary variables conversion...
1460     if (isArgCStr(sc_sess->di_res))
1461       sc_sess->var["DI_res"] = sc_sess->di_res.asCStr();
1462     else if (isArgInt(sc_sess->di_res))
1463       sc_sess->var["DI_res"] = int2str(sc_sess->di_res.asInt());
1464     else if (isArgArray(sc_sess->di_res)) {
1465       if (name.compare(0, 12, "DIgetResult(") == 0) {
1466 	// copy results to $DI_res0..$DI_resn
1467 	for (size_t i=0;i<sc_sess->di_res.size();i++) {
1468 	  switch (sc_sess->di_res.get(i).getType()) {
1469 	  case AmArg::CStr: {
1470 	    sc_sess->var["DI_res"+int2str((unsigned int)i)] =
1471 	      sc_sess->di_res.get(i).asCStr();
1472 	  } break;
1473 	  case AmArg::Int: {
1474 	    sc_sess->var["DI_res"+int2str((unsigned int)i)] =
1475 	      int2str(sc_sess->di_res.get(i).asInt());
1476 	  } break;
1477 	  default: {
1478 	    ERROR("unsupported AmArg return type!");
1479 	    flag_error = true;
1480 	    sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
1481 	    sc_sess->SET_STRERROR("unsupported AmArg return type");
1482 	  }
1483 	  }
1484 	}
1485       } else {
1486 	// copy results to $DI_res[0]..$DI_res[n] and n to $DI_res_size
1487 	for (size_t i=0;i<sc_sess->di_res.size();i++) {
1488 	  switch (sc_sess->di_res.get(i).getType()) {
1489 	  case AmArg::CStr: {
1490 	    sc_sess->var["DI_res["+int2str((unsigned int)i)+"]"] =
1491 	      sc_sess->di_res.get(i).asCStr();
1492 	  } break;
1493 	  case AmArg::Int: {
1494 	    sc_sess->var["DI_res["+int2str((unsigned int)i)+"]"] =
1495 	      int2str(sc_sess->di_res.get(i).asInt());
1496 	  } break;
1497 	  default: {
1498 	    ERROR("unsupported AmArg return type!");
1499 	    flag_error = true;
1500 	    sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
1501 	    sc_sess->SET_STRERROR("unsupported AmArg return type");
1502 	  }
1503 	  }
1504 	}
1505 	sc_sess->var["DI_res_size"] = int2str((int)sc_sess->di_res.size());
1506       }
1507     }
1508   }
1509   if (!flag_error) {
1510     sc_sess->CLR_ERRNO;
1511   }
1512 
1513 } EXEC_ACTION_END;
1514 
1515 
1516 CONST_ACTION_2P(SCB2BConnectCalleeAction,',', false);
EXEC_ACTION_START(SCB2BConnectCalleeAction)1517 EXEC_ACTION_START(SCB2BConnectCalleeAction) {
1518   string remote_party = resolveVars(par1, sess, sc_sess, event_params);
1519   string remote_uri = resolveVars(par2, sess, sc_sess, event_params);
1520   bool relayed_invite = false;
1521   VarMapT::iterator it = sc_sess->var.find(DSM_B2B_RELAYED_INVITE);
1522   if (it != sc_sess->var.end() && it->second == "true")
1523     relayed_invite = true;
1524   DBG("B2B connecting callee '%s', URI '%s', relayed: %s\n",
1525       remote_party.c_str(), remote_uri.c_str(), relayed_invite?"yes":"no");
1526   sc_sess->B2BconnectCallee(remote_party, remote_uri, relayed_invite);
1527 } EXEC_ACTION_END;
1528 
EXEC_ACTION_START(SCB2BTerminateOtherLegAction)1529 EXEC_ACTION_START(SCB2BTerminateOtherLegAction) {
1530   sc_sess->B2BterminateOtherLeg();
1531 } EXEC_ACTION_END;
1532 
1533 CONST_ACTION_2P(SCB2BReinviteAction,',', true);
EXEC_ACTION_START(SCB2BReinviteAction)1534 EXEC_ACTION_START(SCB2BReinviteAction) {
1535   bool updateSDP = par1=="true";
1536   sess->sendReinvite(updateSDP, par2);
1537 } EXEC_ACTION_END;
1538 
EXEC_ACTION_START(SCB2BEnableEarlyMediaRelayAction)1539 EXEC_ACTION_START(SCB2BEnableEarlyMediaRelayAction) {
1540   string val = resolveVars(arg, sess, sc_sess, event_params);
1541   DBG("B2B: %sabling early media SDP relay as re-Invite\n", (val=="true")?"En":"Dis");
1542   sc_sess->B2BsetRelayEarlyMediaSDP(val=="true");
1543 } EXEC_ACTION_END;
1544 
EXEC_ACTION_START(SCB2BAddHeaderAction)1545 EXEC_ACTION_START(SCB2BAddHeaderAction) {
1546   string val = resolveVars(arg, sess, sc_sess, event_params);
1547   DBG("adding B2B header '%s'\n", val.c_str());
1548   sc_sess->B2BaddHeader(val);
1549 } EXEC_ACTION_END;
1550 
EXEC_ACTION_START(SCB2BRemoveHeaderAction)1551 EXEC_ACTION_START(SCB2BRemoveHeaderAction) {
1552   string val = resolveVars(arg, sess, sc_sess, event_params);
1553   DBG("removing B2B header '%s'\n", val.c_str());
1554   sc_sess->B2BremoveHeader(val);
1555 } EXEC_ACTION_END;
1556 
1557 CONST_ACTION_2P(SCB2BSetHeadersAction,',', true);
EXEC_ACTION_START(SCB2BSetHeadersAction)1558 EXEC_ACTION_START(SCB2BSetHeadersAction) {
1559   string val = resolveVars(par1, sess, sc_sess, event_params);
1560   string repl = resolveVars(par2, sess, sc_sess, event_params);
1561   bool replace_crlf = false;
1562   if (repl == "true")
1563     replace_crlf = true;
1564   DBG("setting B2B headers to '%s' (%sreplacing CRLF)\n",
1565       val.c_str(), replace_crlf?"":"not ");
1566   sc_sess->B2BsetHeaders(val, replace_crlf);
1567 } EXEC_ACTION_END;
1568 
EXEC_ACTION_START(SCB2BClearHeadersAction)1569 EXEC_ACTION_START(SCB2BClearHeadersAction) {
1570   DBG("clearing B2B headers\n");
1571   sc_sess->B2BclearHeaders();
1572 } EXEC_ACTION_END;
1573 
1574 CONST_ACTION_2P(SCSendDTMFAction,',', true);
EXEC_ACTION_START(SCSendDTMFAction)1575 EXEC_ACTION_START(SCSendDTMFAction) {
1576   string event = resolveVars(par1, sess, sc_sess, event_params);
1577   string duration = resolveVars(par2, sess, sc_sess, event_params);
1578 
1579   unsigned int event_i;
1580   if (str2i(event, event_i)) {
1581     ERROR("event '%s' not a valid DTMF event\n", event.c_str());
1582     throw DSMException("core", "cause", "invalid DTMF:"+ event);
1583   }
1584 
1585   unsigned int duration_i;
1586   if (duration.empty()) {
1587     duration_i = 500; // default
1588   } else {
1589     if (str2i(duration, duration_i)) {
1590       ERROR("event duration '%s' not a valid DTMF duration\n", duration.c_str());
1591       throw DSMException("core", "cause", "invalid DTMF duration:"+ duration);
1592     }
1593   }
1594 
1595   sess->sendDtmf(event_i, duration_i);
1596 } EXEC_ACTION_END;
1597 
1598 CONST_ACTION_2P(SCSendDTMFSequenceAction,',', true);
EXEC_ACTION_START(SCSendDTMFSequenceAction)1599 EXEC_ACTION_START(SCSendDTMFSequenceAction) {
1600   string events = resolveVars(par1, sess, sc_sess, event_params);
1601   string duration = resolveVars(par2, sess, sc_sess, event_params);
1602 
1603   unsigned int duration_i;
1604   if (duration.empty()) {
1605     duration_i = 500; // default
1606   } else {
1607     if (str2i(duration, duration_i)) {
1608       ERROR("event duration '%s' not a valid DTMF duration\n", duration.c_str());
1609       throw DSMException("core", "cause", "invalid DTMF duration:"+ duration);
1610     }
1611   }
1612 
1613   for (size_t i=0;i<events.length();i++) {
1614     if ((events[i]<'0' || events[i]>'9')
1615 	&& (events[i] != '#') && (events[i] != '*')
1616 	&& (events[i] <'A' || events[i] >'F')) {
1617 	DBG("skipping non-DTMF event char '%c'\n", events[i]);
1618 	continue;
1619     }
1620     int event = events[i] - '0';
1621     if (events[i] == '*')
1622       event = 10;
1623     else if (events[i] == '#')
1624       event = 11;
1625     else if (events[i] >= 'A' && events[i] <= 'F' )
1626       event = 12 + (events[i] - 'A');
1627     DBG("sending event %d duration %u\n", event, duration_i);
1628     sess->sendDtmf(event, duration_i);
1629   }
1630 } EXEC_ACTION_END;
1631 
EXEC_ACTION_START(SCRegisterEventQueueAction)1632 EXEC_ACTION_START(SCRegisterEventQueueAction) {
1633   string q_name = resolveVars(arg, sess, sc_sess, event_params);
1634   DBG("Registering event queue '%s'\n", q_name.c_str());
1635   if (q_name.empty()) {
1636     WARN("Registering empty event queue name!\n");
1637   }
1638   AmEventDispatcher::instance()->addEventQueue(q_name, sess);
1639 } EXEC_ACTION_END;
1640 
EXEC_ACTION_START(SCUnregisterEventQueueAction)1641 EXEC_ACTION_START(SCUnregisterEventQueueAction) {
1642   string q_name = resolveVars(arg, sess, sc_sess, event_params);
1643   DBG("Unregistering event queue '%s'\n", q_name.c_str());
1644   if (q_name.empty()) {
1645     WARN("Unregistering empty event queue name!\n");
1646   }
1647   AmEventDispatcher::instance()->delEventQueue(q_name);
1648 } EXEC_ACTION_END;
1649 
1650 CONST_ACTION_2P(SCCreateSystemDSMAction,',', false);
EXEC_ACTION_START(SCCreateSystemDSMAction)1651 EXEC_ACTION_START(SCCreateSystemDSMAction) {
1652   string conf_name = resolveVars(par1, sess, sc_sess, event_params);
1653   string script_name = resolveVars(par2, sess, sc_sess, event_params);
1654 
1655   if (conf_name.empty() || script_name.empty()) {
1656     throw DSMException("core", "cause", "parameters missing - "
1657 		       "need both conf_name and script_name for createSystemDSM");
1658   }
1659 
1660   DBG("creating system DSM conf_name %s, script_name %s\n",
1661       conf_name.c_str(), script_name.c_str());
1662   string status;
1663   if (!DSMFactory::instance()->createSystemDSM(conf_name, script_name, false, status)) {
1664     ERROR("creating system DSM: %s\n", status.c_str());
1665     throw DSMException("core", "cause", status);
1666   }
1667 
1668 } EXEC_ACTION_END;
1669 
getObjectFromVariable(DSMSession * sc_sess,const string & var_name)1670 DSMDisposable* getObjectFromVariable(DSMSession* sc_sess, const string& var_name) {
1671   AVarMapT::iterator it = sc_sess->avar.find(var_name);
1672   if (it == sc_sess->avar.end()) {
1673     DBG("object '%s' not found\n", var_name.c_str());
1674     sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
1675     sc_sess->SET_STRERROR("object '"+var_name+"' not found\n");
1676     return NULL;
1677   }
1678 
1679   DSMDisposable* disp = dynamic_cast<DSMDisposable*>(it->second.asObject());
1680   if (NULL == disp) {
1681     DBG("object '%s' is not a DSMDisposable\n", var_name.c_str());
1682     sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
1683     sc_sess->SET_STRERROR("object '"+var_name+"' is not a DSMDisposable\n");
1684     return NULL;
1685   }
1686   return disp;
1687 }
1688 
EXEC_ACTION_START(SCTrackObjectAction)1689 EXEC_ACTION_START(SCTrackObjectAction) {
1690   string var_name = resolveVars(arg, sess, sc_sess, event_params);
1691   DSMDisposable* disp = getObjectFromVariable(sc_sess, var_name);
1692   if (NULL == disp) {
1693     EXEC_ACTION_STOP;
1694   }
1695   sc_sess->transferOwnership(disp);
1696 } EXEC_ACTION_END;
1697 
EXEC_ACTION_START(SCReleaseObjectAction)1698 EXEC_ACTION_START(SCReleaseObjectAction) {
1699   string var_name = resolveVars(arg, sess, sc_sess, event_params);
1700   DSMDisposable* disp = getObjectFromVariable(sc_sess, var_name);
1701   if (NULL == disp) {
1702     EXEC_ACTION_STOP;
1703   }
1704   sc_sess->releaseOwnership(disp);
1705 } EXEC_ACTION_END;
1706 
EXEC_ACTION_START(SCFreeObjectAction)1707 EXEC_ACTION_START(SCFreeObjectAction) {
1708   string var_name = resolveVars(arg, sess, sc_sess, event_params);
1709   DSMDisposable* disp = getObjectFromVariable(sc_sess, var_name);
1710   if (NULL == disp) {
1711     EXEC_ACTION_STOP;
1712   }
1713   delete disp;
1714   sc_sess->avar.erase(var_name);
1715 } EXEC_ACTION_END;
1716