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