1 /*
2 * Copyright (C) 2008 iptego GmbH
3 *
4 * This file is part of SEMS, a free SIP media server.
5 *
6 * SEMS is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version. This program is released under
10 * the GPL with the additional exemption that compiling, linking,
11 * and/or using OpenSSL is allowed.
12 *
13 * For a license to use the SEMS software under conditions
14 * other than those described here, or to purchase support for this
15 * software, please contact iptel.org by e-mail at the following addresses:
16 * info@iptel.org
17 *
18 * SEMS is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 */
27 #include "ModDlg.h"
28 #include "log.h"
29 #include "AmUtils.h"
30
31 #include "DSMSession.h"
32 #include "AmSession.h"
33 #include "AmB2BSession.h"
34 #include <string.h>
35 #include "AmSipHeaders.h"
36
37 #include "AmUAC.h"
38 #include "ampi/UACAuthAPI.h"
39
40 SC_EXPORT(MOD_CLS_NAME);
41
42
MOD_ACTIONEXPORT_BEGIN(MOD_CLS_NAME)43 MOD_ACTIONEXPORT_BEGIN(MOD_CLS_NAME) {
44
45 DEF_CMD("dlg.reply", DLGReplyAction);
46 DEF_CMD("dlg.replyRequest", DLGReplyRequestAction);
47 DEF_CMD("dlg.acceptInvite", DLGAcceptInviteAction);
48 DEF_CMD("dlg.bye", DLGByeAction);
49 DEF_CMD("dlg.connectCalleeRelayed", DLGConnectCalleeRelayedAction);
50 DEF_CMD("dlg.dialout", DLGDialoutAction);
51
52 DEF_CMD("dlg.getRequestBody", DLGGetRequestBodyAction)
53 DEF_CMD("dlg.getReplyBody", DLGGetReplyBodyAction)
54
55 DEF_CMD("dlg.getOtherId", DLGGetOtherIdAction)
56 DEF_CMD("dlg.getRtpRelayMode", DLGGetRtpRelayModeAction)
57
58 DEF_CMD("dlg.refer", DLGReferAction);
59 DEF_CMD("dlg.info", DLGInfoAction);
60 DEF_CMD("dlg.relayError", DLGB2BRelayErrorAction);
61 DEF_CMD("dlg.relayReply", DLGB2BRelayErrorAction); // alias
62
63 DEF_CMD("dlg.addReplyBodyPart", DLGAddReplyBodyPartAction);
64 DEF_CMD("dlg.deleteReplyBodyPart", DLGDeleteReplyBodyPartAction);
65
66 } MOD_ACTIONEXPORT_END;
67
68 //MOD_CONDITIONEXPORT_NONE(MOD_CLS_NAME);
69
70
MOD_CONDITIONEXPORT_BEGIN(MOD_CLS_NAME)71 MOD_CONDITIONEXPORT_BEGIN(MOD_CLS_NAME) {
72 if (cmd == "dlg.replyHasContentType")
73 return new DLGReplyHasContentTypeCondition(params, false);
74
75 if (cmd == "dlg.requestHasContentType")
76 return new DLGRequestHasContentTypeCondition(params, false);
77
78 } MOD_CONDITIONEXPORT_END;
79
onInvite(const AmSipRequest & req,DSMSession * sess)80 bool DLGModule::onInvite(const AmSipRequest& req, DSMSession* sess) {
81 // save inivital invite to last_req
82 // todo: save this in avar
83 sess->last_req.reset(new AmSipRequest(req));
84 return true;
85 }
86
replaceLineEnds(string input)87 string replaceLineEnds(string input)
88 {
89 string result;
90 size_t last = 0;
91 size_t pos;
92 while ((pos = input.find("\\r\\n", last)) != string::npos) {
93 result += input.substr(last, pos-last);
94 result += "\r\n";
95 last = pos + 4;
96 }
97 if (!input.substr(last).empty()) {
98 result += input.substr(last);
99 result += "\r\n";
100 }
101 return result;
102 }
103
104 // todo: convert errors to exceptions
replyRequest(DSMSession * sc_sess,AmSession * sess,EventParamT * event_params,const string & par1,const string & par2,const AmSipRequest & req)105 void replyRequest(DSMSession* sc_sess, AmSession* sess,
106 EventParamT* event_params,
107 const string& par1, const string& par2,
108 const AmSipRequest& req) {
109 string code = resolveVars(par1, sess, sc_sess, event_params);
110 string reason = resolveVars(par2, sess, sc_sess, event_params);
111 string hdrs = replaceLineEnds(resolveVars("$dlg.reply.hdrs", sess, sc_sess, event_params));
112 unsigned int code_i;
113 if (str2i(code, code_i)) {
114 ERROR("decoding reply code '%s'\n", code.c_str());
115 sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
116 return;
117 }
118
119 DBG("replying with %i %s, hdrs='%s'\n", code_i, reason.c_str(), hdrs.c_str());
120
121 if (sess->dlg->reply(req, code_i, reason, NULL, hdrs)) {
122 sc_sess->SET_ERRNO(DSM_ERRNO_GENERAL);
123 sc_sess->SET_STRERROR("error sending reply");
124 } else
125 sc_sess->CLR_ERRNO;
126 }
127
128 CONST_ACTION_2P(DLGReplyAction, ',', true);
EXEC_ACTION_START(DLGReplyAction)129 EXEC_ACTION_START(DLGReplyAction) {
130
131 if (!sc_sess->last_req.get()) {
132 ERROR("no last request to reply\n");
133 sc_sess->SET_ERRNO(DSM_ERRNO_GENERAL);
134 sc_sess->SET_STRERROR("no last request to reply");
135 return false;
136 }
137
138 replyRequest(sc_sess, sess, event_params, par1, par2, *sc_sess->last_req.get());
139 } EXEC_ACTION_END;
140
141 // todo (?) move replyRequest to core module (?)
142 CONST_ACTION_2P(DLGReplyRequestAction, ',', true);
EXEC_ACTION_START(DLGReplyRequestAction)143 EXEC_ACTION_START(DLGReplyRequestAction) {
144 DSMSipRequest* sip_req;
145
146 AVarMapT::iterator it = sc_sess->avar.find(DSM_AVAR_REQUEST);
147 if (it == sc_sess->avar.end() ||
148 !isArgAObject(it->second) ||
149 !(sip_req = dynamic_cast<DSMSipRequest*>(it->second.asObject()))) {
150 throw DSMException("dlg", "cause", "no request");
151 }
152
153 replyRequest(sc_sess, sess, event_params, par1, par2, *sip_req->req);
154 } EXEC_ACTION_END;
155
156 CONST_ACTION_2P(DLGAcceptInviteAction, ',', true);
EXEC_ACTION_START(DLGAcceptInviteAction)157 EXEC_ACTION_START(DLGAcceptInviteAction) {
158 // defaults to 200 OK
159 unsigned int code_i=200;
160 string reason = "OK";
161 string code = resolveVars(par1, sess, sc_sess, event_params);
162 string hdrs = replaceLineEnds(resolveVars("$dlg.reply.hdrs", sess, sc_sess, event_params));
163
164 if (code.length()) {
165 reason = resolveVars(par2, sess, sc_sess, event_params);
166 if (str2i(code, code_i)) {
167 ERROR("decoding reply code '%s'\n", code.c_str());
168 sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
169 sc_sess->SET_STRERROR("decoding reply code '"+
170 code+"%s'\n");
171 return false;
172 }
173 }
174
175 DBG("replying with %i %s, hdrs='%s'\n", code_i, reason.c_str(), hdrs.c_str());
176
177 if (!sc_sess->last_req.get()) {
178 ERROR("no last request to reply\n");
179 sc_sess->SET_ERRNO(DSM_ERRNO_GENERAL);
180 sc_sess->SET_STRERROR("no last request to reply");
181 return false;
182 }
183
184 try {
185 AmMimeBody sdp_body;
186 if(sess->dlg->reply(*sc_sess->last_req.get(),code_i, reason,
187 sdp_body.addPart(SIP_APPLICATION_SDP), hdrs) != 0)
188 throw AmSession::Exception(500,"could not send response");
189
190 }catch(const AmSession::Exception& e){
191
192 ERROR("%i %s\n",e.code,e.reason.c_str());
193 sess->setStopped();
194 sess->dlg->reply(*sc_sess->last_req.get(),e.code,e.reason);
195
196 sc_sess->SET_ERRNO(DSM_ERRNO_DLG);
197 sc_sess->SET_STRERROR("Error accepting call: "+ int2str(e.code) + " "+ e.reason);
198 }
199 } EXEC_ACTION_END;
200
EXEC_ACTION_START(DLGByeAction)201 EXEC_ACTION_START(DLGByeAction) {
202 string hdrs = replaceLineEnds(resolveVars(arg, sess, sc_sess, event_params));
203
204 if (sess->dlg->bye(hdrs)) {
205 sc_sess->SET_ERRNO(DSM_ERRNO_GENERAL);
206 sc_sess->SET_STRERROR("Error sending bye");
207 } else {
208 sc_sess->SET_ERRNO(DSM_ERRNO_OK);
209 }
210 } EXEC_ACTION_END;
211
212
213 CONST_ACTION_2P(DLGConnectCalleeRelayedAction,',', false);
EXEC_ACTION_START(DLGConnectCalleeRelayedAction)214 EXEC_ACTION_START(DLGConnectCalleeRelayedAction) {
215 string remote_party = resolveVars(par1, sess, sc_sess, event_params);
216 string remote_uri = resolveVars(par2, sess, sc_sess, event_params);
217
218 // if (sc_sess->last_req.get()) {
219 // sc_sess->B2BaddReceivedRequest(*sc_sess->last_req.get());
220 // } else {
221 // WARN("internal error: initial INVITE request missing.\n");
222 // }
223 // AmB2BSession* b2b_sess = dynamic_cast<AmB2BSession*>(sess);
224 // if (b2b_sess)
225 // b2b_sess->set_sip_relay_only(true);
226 // else
227 // ERROR("getting B2B session.\n");
228
229 sc_sess->B2BconnectCallee(remote_party, remote_uri, true);
230 } EXEC_ACTION_END;
231
EXEC_ACTION_START(DLGDialoutAction)232 EXEC_ACTION_START(DLGDialoutAction) {
233 string arrayname = resolveVars(arg, sess, sc_sess, event_params);
234
235 #define GET_VARIABLE_MANDATORY(varname_suffix, outvar) \
236 it = sc_sess->var.find(arrayname+varname_suffix); \
237 if (it == sc_sess->var.end()) { \
238 WARN("%s", std::string("need " + arrayname + varname_suffix " set for dlg.dialoutSimple("+arrayname+")").c_str()); \
239 sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG); \
240 return false; \
241 } \
242 outvar = it->second;
243
244 #define GET_VARIABLE_OPTIONAL(varname_suffix, outvar) \
245 it = sc_sess->var.find(arrayname+varname_suffix); \
246 if (it != sc_sess->var.end()) \
247 outvar = it->second;
248
249 map<string, string>::iterator it;
250
251 string v_from;
252 GET_VARIABLE_MANDATORY("_caller", v_from);
253 string v_to;
254 GET_VARIABLE_MANDATORY("_callee", v_to);
255 string v_domain;
256 GET_VARIABLE_MANDATORY("_domain", v_domain);
257 string app_name;
258 GET_VARIABLE_MANDATORY("_app", app_name);
259
260 string user = v_from;
261 string r_uri = "sip:"+v_to+"@"+v_domain;
262
263 GET_VARIABLE_OPTIONAL("_r_uri", r_uri);
264
265 string from = "<sip:"+v_from+"@"+v_domain+">";
266 GET_VARIABLE_OPTIONAL("_from", from);
267
268 string from_uri = "sip:"+v_from+"@"+v_domain;
269 GET_VARIABLE_OPTIONAL("_from_uri", from_uri);
270
271 string to = "<sip:"+v_to+"@"+v_domain+">";
272 GET_VARIABLE_OPTIONAL("_to", to);
273
274 string auth_user;
275 GET_VARIABLE_OPTIONAL("_auth_user", auth_user);
276
277 string auth_pwd;
278 GET_VARIABLE_OPTIONAL("_auth_pwd", auth_pwd);
279
280 string ltag;
281 GET_VARIABLE_OPTIONAL("_ltag", ltag);
282
283 string hdrs;
284 GET_VARIABLE_OPTIONAL("_hdrs", hdrs);
285
286 if (hdrs.length()) {
287 size_t crpos;
288 while ((crpos=hdrs.find("\\r\\n")) != string::npos) {
289 hdrs.replace(crpos, 4, "\r\n");
290 }
291 }
292
293 #undef GET_VARIABLE_MANDATORY
294 #undef GET_VARIABLE_OPTIONAL
295
296 DBG("placing UAC call: user <%s>, app <%s>, ruri <%s>, from <%s> "
297 "from_uri <%s>, to <%s>, ltag <%s>, hdrs <%s>, auth_user <%s>, auth_pwd <not shown>\n",
298 user.c_str(), app_name.c_str(), r_uri.c_str(), from.c_str(),
299 from_uri.c_str(), to.c_str(), ltag.c_str(), hdrs.c_str(), auth_user.c_str());
300
301 AmArg* sess_params = new AmArg();
302 bool has_auth = false;
303 if (!auth_user.empty() && !auth_pwd.empty()) {
304 AmArg auth_param;
305 auth_param.setBorrowedPointer(new UACAuthCred("", auth_user,auth_pwd));
306 sess_params->push(auth_param);
307 has_auth = true;
308 }
309 AmArg var_struct;
310 string varprefix = arrayname+"_var.";
311 bool has_vars = false;
312 map<string, string>::iterator lb = sc_sess->var.lower_bound(varprefix);
313 while (lb != sc_sess->var.end()) {
314 if ((lb->first.length() < varprefix.length()) ||
315 strncmp(lb->first.c_str(), varprefix.c_str(),varprefix.length()))
316 break;
317 string varname = lb->first.substr(varprefix.length());
318 if (!has_auth) // sess_params is variable struct
319 (*sess_params)[varname] = lb->second;
320 else // variable struct is in sess_params array
321 var_struct[varname] = lb->second;
322
323 lb++;
324 has_vars = true;
325 }
326
327 if (has_vars && has_auth)
328 sess_params->push(var_struct);
329
330 DBG("sess_params: '%s'\n", AmArg::print(*sess_params).c_str());
331
332 string new_sess_tag = AmUAC::dialout(user, app_name, r_uri, from, from_uri, to, ltag, hdrs, sess_params);
333
334 if (!new_sess_tag.empty()) {
335 sc_sess->var[arrayname + "_ltag"] = new_sess_tag;
336 } else {
337 sc_sess->var[arrayname + "_ltag"] = "";
338 sc_sess->SET_ERRNO(DSM_ERRNO_GENERAL);
339 }
340
341 } EXEC_ACTION_END;
342
MATCH_CONDITION_START(DLGReplyHasContentTypeCondition)343 MATCH_CONDITION_START(DLGReplyHasContentTypeCondition) {
344 AVarMapT::iterator it = sc_sess->avar.find(DSM_AVAR_REPLY);
345 if (it == sc_sess->avar.end()) {
346 ERROR("DSM script error: dlg.replyHasContentType condition used for "
347 "other event than sipReply event\n");
348 return false;
349 }
350
351 DSMSipReply* dsm_reply = NULL;
352 if (!isArgAObject(sc_sess->avar[DSM_AVAR_REPLY]) ||
353 (NULL ==
354 (dsm_reply = dynamic_cast<DSMSipReply*>(sc_sess->avar[DSM_AVAR_REPLY].asObject())))) {
355 ERROR("internal: DSM could not get DSMSipReply\n");
356 return false;
357 }
358
359 bool res = dsm_reply->reply->body.hasContentType(arg);
360
361 DBG("checking for content_type '%s': %s\n", arg.c_str(), res?"has it":"doesn't have it");
362 return res;
363 } MATCH_CONDITION_END;
364
MATCH_CONDITION_START(DLGRequestHasContentTypeCondition)365 MATCH_CONDITION_START(DLGRequestHasContentTypeCondition) {
366 AVarMapT::iterator it = sc_sess->avar.find(DSM_AVAR_REQUEST);
367 if (it == sc_sess->avar.end()) {
368 ERROR("DSM script error: dlg.requestHasContentType condition used for "
369 "other event than sipRequest event\n");
370 return false;
371 }
372
373 DSMSipRequest* dsm_req = NULL;
374 if (!isArgAObject(sc_sess->avar[DSM_AVAR_REQUEST]) ||
375 (NULL ==
376 (dsm_req = dynamic_cast<DSMSipRequest*>(sc_sess->avar[DSM_AVAR_REQUEST].asObject())))) {
377 ERROR("internal: DSM could not get DSMSipRequest\n");
378 return false;
379 }
380
381 bool res = dsm_req->req->body.hasContentType(arg);
382
383 DBG("checking for content_type '%s': %s\n", arg.c_str(), res?"has it":"doesn't have it");
384 return res;
385 } MATCH_CONDITION_END;
386
387 CONST_ACTION_2P(DLGGetRequestBodyAction, ',', false);
EXEC_ACTION_START(DLGGetRequestBodyAction)388 EXEC_ACTION_START(DLGGetRequestBodyAction) {
389 DSMSipRequest* sip_req;
390
391 AVarMapT::iterator it = sc_sess->avar.find(DSM_AVAR_REQUEST);
392 if (it == sc_sess->avar.end() ||
393 !isArgAObject(it->second) ||
394 !(sip_req = dynamic_cast<DSMSipRequest*>(it->second.asObject()))) {
395 throw DSMException("dlg", "cause", "no request");
396 }
397
398 string content_type = resolveVars(par1, sess, sc_sess, event_params);
399 string dstvar = resolveVars(par2, sess, sc_sess, event_params);
400
401 const AmMimeBody* msg_body = sip_req->req->body.hasContentType(content_type);
402 if (NULL == msg_body) {
403 DBG("body with content_type %s not found\n", content_type.c_str());
404 sc_sess->var.erase(dstvar);
405 } else {
406 sc_sess->var[dstvar] = string((const char*)msg_body->getPayload());
407 DBG("set $%s='%s'\n", dstvar.c_str(), sc_sess->var[dstvar].c_str());
408 }
409 } EXEC_ACTION_END;
410
411 CONST_ACTION_2P(DLGGetReplyBodyAction, ',', false);
EXEC_ACTION_START(DLGGetReplyBodyAction)412 EXEC_ACTION_START(DLGGetReplyBodyAction) {
413 DSMSipReply* sip_req;
414
415 AVarMapT::iterator it = sc_sess->avar.find(DSM_AVAR_REPLY);
416 if (it == sc_sess->avar.end() ||
417 !isArgAObject(it->second) ||
418 !(sip_req = dynamic_cast<DSMSipReply*>(it->second.asObject()))) {
419 throw DSMException("dlg", "cause", "no reply");
420 }
421
422 string content_type = resolveVars(par1, sess, sc_sess, event_params);
423 string dstvar = resolveVars(par2, sess, sc_sess, event_params);
424
425 const AmMimeBody* msg_body = sip_req->reply->body.hasContentType(content_type);
426 if (NULL == msg_body) {
427 DBG("body with content_type %s not found\n", content_type.c_str());
428 sc_sess->var.erase(dstvar);
429 } else {
430 sc_sess->var[dstvar] = string((const char*)msg_body->getPayload());
431 DBG("set $%s='%s'\n", dstvar.c_str(), sc_sess->var[dstvar].c_str());
432 }
433 } EXEC_ACTION_END;
434
EXEC_ACTION_START(DLGGetOtherIdAction)435 EXEC_ACTION_START(DLGGetOtherIdAction) {
436 string varname = arg;
437 AmB2BSession* b2b_sess = dynamic_cast<AmB2BSession*>(sess);
438 if (NULL == b2b_sess) {
439 DBG("script writer error: dlg.getOtherId used without B2B session object.\n");
440 EXEC_ACTION_STOP;
441 }
442
443 if (varname.size() && varname[0] == '$')
444 varname.erase(0, 1);
445 sc_sess->var[varname] = b2b_sess->getOtherId();
446 } EXEC_ACTION_END;
447
EXEC_ACTION_START(DLGGetRtpRelayModeAction)448 EXEC_ACTION_START(DLGGetRtpRelayModeAction) {
449 string varname = arg;
450 AmB2BSession* b2b_sess = dynamic_cast<AmB2BSession*>(sess);
451 if (NULL == b2b_sess) {
452 DBG("script writer error: dlg.getOtherId used without B2B session object.\n");
453 EXEC_ACTION_STOP;
454 }
455
456 if (varname.size() && varname[0] == '$')
457 varname.erase(0, 1);
458 switch (b2b_sess->getRtpRelayMode()) {
459 case AmB2BSession::RTP_Direct: sc_sess->var[varname] = "RTP_Direct"; break;
460 case AmB2BSession::RTP_Relay: sc_sess->var[varname] = "RTP_Relay"; break;
461 case AmB2BSession::RTP_Transcoding: sc_sess->var[varname] = "RTP_Transcoding"; break;
462 default: sc_sess->var[varname] = "Unknown"; break;
463 }
464
465 DBG("get RTP relay mode: %s='%s'\n", varname.c_str(), sc_sess->var[varname].c_str());
466 } EXEC_ACTION_END;
467
468 CONST_ACTION_2P(DLGReferAction, ',', true);
EXEC_ACTION_START(DLGReferAction)469 EXEC_ACTION_START(DLGReferAction) {
470
471 AmSession* b2b_sess = dynamic_cast<AmSession*>(sess);
472 if (NULL == b2b_sess) {
473 throw DSMException("sbc", "type", "param", "cause",
474 "dlg.refer used on non-session");
475 }
476
477 string refer_to = resolveVars(par1, sess, sc_sess, event_params);
478 string expires_s = resolveVars(par2, sess, sc_sess, event_params);
479
480 int expires = -1;
481 if (!expires_s.empty()) {
482 if (!str2int(expires_s, expires)) {
483 throw DSMException("sbc", "type", "param", "cause",
484 "expires "+expires_s+" not valid");
485 }
486 }
487
488 if (NULL == b2b_sess->dlg) {
489 throw DSMException("sbc", "type", "param", "cause",
490 "call doesn't have SIP dialog (OOPS!)");
491 }
492
493 if (b2b_sess->dlg->refer(refer_to, expires)) {
494 sc_sess->SET_ERRNO(DSM_ERRNO_DLG);
495 sc_sess->SET_STRERROR("sending REFER failed");
496 } else {
497 sc_sess->CLR_ERRNO;
498 }
499 } EXEC_ACTION_END;
500
501 CONST_ACTION_2P(DLGInfoAction, ',', true);
EXEC_ACTION_START(DLGInfoAction)502 EXEC_ACTION_START(DLGInfoAction) {
503
504 AmSession* b2b_sess = dynamic_cast<AmSession*>(sess);
505 if (NULL == b2b_sess) {
506 throw DSMException("sbc", "type", "param", "cause",
507 "dlg.info used on non-session");
508 }
509
510 string content_type = resolveVars(par1, sess, sc_sess, event_params);
511 string body_str = resolveVars(par2, sess, sc_sess, event_params);
512
513 if (NULL == b2b_sess->dlg) {
514 throw DSMException("sbc", "type", "param", "cause",
515 "call doesn't have SIP dialog (OOPS!)");
516 }
517
518 string body_crlf = body_str;
519 AmMimeBody *body = new AmMimeBody();
520 if (!content_type.empty()) {
521 DBG("body_crlf is '%s'\n", body_crlf.c_str());
522 while (true) {
523 size_t p = body_crlf.find("\\r\\n");
524 if (p==string::npos)
525 break;
526 body_crlf.replace(p, 4, "\r\n");
527 }
528 DBG("-> body_crlf is '%s'\n", body_crlf.c_str());
529 if (body->parse(content_type,
530 reinterpret_cast<const unsigned char*>(body_crlf.c_str()),
531 body_crlf.length())) {
532 throw DSMException("sbc", "type", "param", "cause",
533 "parsing of INFO body failed");
534 }
535 }
536
537 if (b2b_sess->dlg->info("", body)) {
538 sc_sess->SET_ERRNO(DSM_ERRNO_DLG);
539 sc_sess->SET_STRERROR("sending INFO failed");
540 } else {
541 sc_sess->CLR_ERRNO;
542 }
543
544 } EXEC_ACTION_END;
545
546 #define GET_B2B_SESSION(action) \
547 AmB2BSession* b2b_sess = dynamic_cast<AmB2BSession*>(sess); \
548 if (NULL == b2b_sess) { \
549 throw DSMException("sbc", "type", "param", "cause", \
550 #action " used on non-b2b-session"); \
551 }
552
553 CONST_ACTION_2P(DLGB2BRelayErrorAction, ',', false);
EXEC_ACTION_START(DLGB2BRelayErrorAction)554 EXEC_ACTION_START(DLGB2BRelayErrorAction) {
555 DSMSipRequest* sip_req;
556
557 AVarMapT::iterator it = sc_sess->avar.find(DSM_AVAR_REQUEST);
558 if (it == sc_sess->avar.end() ||
559 !isArgAObject(it->second) ||
560 !(sip_req = dynamic_cast<DSMSipRequest*>(it->second.asObject()))) {
561 throw DSMException("dlg", "cause", "no request");
562 }
563 GET_B2B_SESSION(dlg.relayError);
564
565 string code = resolveVars(par1, sess, sc_sess, event_params);
566 string reason = resolveVars(par2, sess, sc_sess, event_params);
567 unsigned int code_i;
568 if (str2i(code, code_i)) {
569 ERROR("decoding reply code '%s'\n", code.c_str());
570 sc_sess->SET_ERRNO(DSM_ERRNO_UNKNOWN_ARG);
571 EXEC_ACTION_STOP;
572 }
573
574 b2b_sess->relayError(sip_req->req->method, sip_req->req->cseq, true, code_i, reason.c_str());
575 } EXEC_ACTION_END;
576
577 CONST_ACTION_2P(DLGAddReplyBodyPartAction, ',', false);
EXEC_ACTION_START(DLGAddReplyBodyPartAction)578 EXEC_ACTION_START(DLGAddReplyBodyPartAction) {
579 DSMMutableSipReply* sip_reply;
580
581 AVarMapT::iterator it = sc_sess->avar.find(DSM_AVAR_REPLY);
582 if (it == sc_sess->avar.end() ||
583 !isArgAObject(it->second) ||
584 !(sip_reply = dynamic_cast<DSMMutableSipReply*>(it->second.asObject()))) {
585 throw DSMException("dlg", "cause", "no reply");
586 }
587
588 string content_type = resolveVars(par1, sess, sc_sess, event_params);
589 string body_part = resolveVars(par2, sess, sc_sess, event_params);
590
591 AmMimeBody* new_part;
592
593 new_part = sip_reply->mutable_reply->body.addPart(content_type);
594 new_part->setPayload((const unsigned char*)body_part.c_str(),
595 body_part.length());
596 DBG("added to reply body part %s='%s'\n",
597 content_type.c_str(), body_part.c_str());
598 } EXEC_ACTION_END;
599
EXEC_ACTION_START(DLGDeleteReplyBodyPartAction)600 EXEC_ACTION_START(DLGDeleteReplyBodyPartAction) {
601 DSMMutableSipReply* sip_reply;
602
603 AVarMapT::iterator it = sc_sess->avar.find(DSM_AVAR_REPLY);
604 if (it == sc_sess->avar.end() ||
605 !isArgAObject(it->second) ||
606 !(sip_reply = dynamic_cast<DSMMutableSipReply*>(it->second.asObject()))) {
607 throw DSMException("dlg", "cause", "no reply");
608 }
609
610 if (sip_reply->mutable_reply->body.deletePart(arg)) {
611 DBG("failed to delete reply body part '%s'\n", arg.c_str());
612 } else {
613 DBG("deleted reply body part '%s'\n", arg.c_str());
614 }
615 } EXEC_ACTION_END;
616