action.c
4ac74c03
 /*
7dd0b342
  *
53c7e0f1
  * Copyright (C) 2001-2003 FhG Fokus
7dd0b342
  *
88693a29
  * This file is part of Kamailio, a free SIP server.
7dd0b342
  *
88693a29
  * Kamailio is free software; you can redistribute it and/or modify
7dd0b342
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version
  *
88693a29
  * Kamailio is distributed in the hope that it will be useful,
7dd0b342
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
f141bc93
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
9e1ff448
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
049f64c2
  *
4ac74c03
  */
5a03489e
 
1d0661db
 /*!
  * \file
88693a29
  * \brief Kamailio core :: Config file actions
1d0661db
  * \ingroup core
  * Module: \ref core
  */
 
4ac74c03
 
 
049f64c2
 #include "comp_defs.h"
7dd0b342
 
4ac74c03
 #include "action.h"
 #include "config.h"
 #include "error.h"
 #include "dprint.h"
 #include "proxy.h"
3e429f5c
 #include "forward.h"
 #include "udp_server.h"
 #include "route.h"
3881f12c
 #include "parser/msg_parser.h"
855c2e68
 #include "parser/parse_uri.h"
104316b6
 #include "ut.h"
ab7f82d2
 #include "lvalue.h"
3bf76e49
 #include "sr_module.h"
84025080
 #include "select_buf.h"
dda9dab1
 #include "mem/mem.h"
1400b772
 #include "globals.h"
caf80ae6
 #include "dset.h"
0d88ce78
 #include "onsend.h"
2f0f1a30
 #include "resolve.h"
0c5da34b
 #ifdef USE_TCP
 #include "tcp_server.h"
 #endif
ed990c31
 #ifdef USE_SCTP
7f8e7a85
 #include "sctp_core.h"
ed990c31
 #endif
955535a4
 #include "switch.h"
c2d36c17
 #include "events.h"
415f24a4
 #include "cfg/cfg_struct.h"
4ac74c03
 
a46cdb8c
 #include <sys/types.h>
 #include <sys/socket.h>
4ac74c03
 #include <netdb.h>
 #include <stdlib.h>
63fa628f
 #include <netinet/in.h>
 #include <arpa/inet.h>
e22bbdb8
 #include <string.h>
63fa628f
 
01dea124
 
03150098
 #ifdef DEBUG_DMALLOC
 #include <dmalloc.h>
 #endif
 
68b7a898
 int _last_returned_code  = 0;
0d88ce78
 struct onsend_info* p_onsend=0; /* onsend route send info */
 
4294b7bf
 /* current action executed from config file */
 static cfg_action_t *_cfg_crt_action = 0;
 
d1c60718
 /*!< maximum number of recursive calls for blocks of actions */
 static unsigned int max_recursive_level = 256;
 
 void set_max_recursive_level(unsigned int lev)
 {
 	max_recursive_level = lev;
 }
 
ca568ee6
 /* return current action executed from config file */
4294b7bf
 cfg_action_t *get_cfg_crt_action(void)
 {
 	return _cfg_crt_action;
 }
cad98b04
 
ca568ee6
 /* return line in config for current executed action */
 int get_cfg_crt_line(void)
 {
 	if(_cfg_crt_action==0)
 		return 0;
 	return _cfg_crt_action->cline;
 }
 
 /* return name of config for current executed action */
 char *get_cfg_crt_name(void)
 {
 	if(_cfg_crt_action==0)
 		return 0;
 	return _cfg_crt_action->cfile;
 }
cad98b04
 
 /* handle the exit code of a module function call.
  * (used internally in do_action())
  * @param h - script handle (h->last_retcode and h->run_flags will be set).
  * @param ret - module function (v0 or v2) retcode
  * Side-effects: sets _last_returned_code
  */
 #define MODF_HANDLE_RETCODE(h, ret) \
 	do { \
 		/* if (unlikely((ret)==0)) (h)->run_flags|=EXIT_R_F; */ \
 		(h)->run_flags |= EXIT_R_F & (((ret) != 0) -1); \
 		(h)->last_retcode=(ret); \
 		_last_returned_code = (h)->last_retcode; \
 	} while(0)
 
 
 
 /* frees parameters converted using MODF_RVE_PARAM_CONVERT() from dst.
  * (used internally in do_action())
  * Assumes src is unchanged.
  * Side-effects: clobbers i (int).
  */
d002aae9
 #define MODF_RVE_PARAM_FREE(cmd, src, dst) \
cad98b04
 		for (i=0; i < (dst)[1].u.number; i++) { \
8f3db98b
 			if ((src)[i+2].type == RVE_ST && (dst)[i+2].u.data) { \
d002aae9
 				if ((dst)[i+2].type == RVE_FREE_FIXUP_ST) {\
 					/* call free_fixup (which should restore the original
 					   string) */ \
a6c250c0
 					(void)call_fixup((cmd)->free_fixup, &(dst)[i+2].u.data, i+1); \
d002aae9
 				} else if ((dst)[i+2].type == FPARAM_DYN_ST) {\
 					/* completely frees fparam and restore original string */\
 					fparam_free_restore(&(dst)[i+2].u.data); \
8f3db98b
 				} \
d002aae9
 				/* free allocated string */ \
8f3db98b
 				pkg_free((dst)[i+2].u.data); \
 				(dst)[i+2].u.data = 0; \
cad98b04
 			} \
 		}
 
 
 /* fills dst from src, converting RVE_ST params to STRING_ST.
  * (used internally in do_action())
  * @param src - source action_u_t array, as in the action structure
  * @param dst - destination action_u_t array, will be filled from src.
  * WARNING: dst must be cleaned when done, use MODULE_RVE_PARAM_FREE()
  * Side-effects: clobbers i (int), s (str), rv (rvalue*), might jump to error.
  */
8f3db98b
 #define MODF_RVE_PARAM_CONVERT(h, msg, cmd, src, dst) \
cad98b04
 	do { \
 		(dst)[1]=(src)[1]; \
 		for (i=0; i < (src)[1].u.number; i++) { \
 			if ((src)[2+i].type == RVE_ST) { \
 				rv=rval_expr_eval((h), (msg), (src)[i+2].u.data); \
 				if (unlikely(rv == 0 || \
 					rval_get_str((h), (msg), &s, rv, 0) < 0)) { \
 					rval_destroy(rv); \
 					ERR("failed to convert RVE to string\n"); \
 					(dst)[1].u.number = i; \
d002aae9
 					MODF_RVE_PARAM_FREE(cmd, src, dst); \
cad98b04
 					goto error; \
 				} \
35657139
 				(dst)[i+2].type = STRING_RVE_ST; \
cad98b04
 				(dst)[i+2].u.string = s.s; \
 				(dst)[i+2].u.str.len = s.len; \
 				rval_destroy(rv); \
d002aae9
 				if ((cmd)->fixup) {\
 					if ((cmd)->free_fixup) {\
 						if (likely( call_fixup((cmd)->fixup, \
 										&(dst)[i+2].u.data, i+1) >= 0) ) { \
 							/* success => mark it for calling free fixup */ \
 							if (likely((dst)[i+2].u.data != s.s)) \
 								(dst)[i+2].type = RVE_FREE_FIXUP_ST; \
 						} else { \
 							/* error calling fixup => mark conv. parameter \
 							   and return error */ \
 							(dst)[1].u.number = i; \
 							ERR("runtime fixup failed for %s param %d\n", \
 									(cmd)->name, i+1); \
 							MODF_RVE_PARAM_FREE(cmd, src, dst); \
 							goto error; \
 						} \
 					} else if ((cmd)->fixup_flags & FIXUP_F_FPARAM_RVE) { \
 						if (likely( call_fixup((cmd)->fixup, \
 										&(dst)[i+2].u.data, i+1) >= 0)) { \
 							if ((dst)[i+2].u.data != s.s) \
 								(dst)[i+2].type = FPARAM_DYN_ST; \
 						} else { \
 							/* error calling fixup => mark conv. parameter \
 							   and return error */ \
 							(dst)[1].u.number = i; \
 							ERR("runtime fixup failed for %s param %d\n", \
 									(cmd)->name, i+1); \
 							MODF_RVE_PARAM_FREE(cmd, src, dst); \
 							goto error; \
 						}\
 					} \
8f3db98b
 				} \
cad98b04
 			} else \
 				(dst)[i+2]=(src)[i+2]; \
 		} \
 	} while(0)
 
 
 
 /* call a module function with normal STRING_ST params.
  * (used internally in do_action())
  * @param f_type - cmd_function type
  * @param h
  * @param msg
  * @param src - source action_u_t array (e.g. action->val)
  * @param params... - variable list of parameters, passed to the module
  *               function
8f3db98b
  * Side-effects: sets ret, clobbers i (int), s (str), rv (rvalue*), cmd,
cad98b04
  *               might jump to error.
  *
  */
 #ifdef __SUNPRO_C
 #define MODF_CALL(f_type, h, msg, src, ...) \
 	do { \
8f3db98b
 		cmd=(src)[0].u.data; \
dee21fff
 		ret=((f_type)cmd->function)((msg), __VAR_ARGS__); \
cad98b04
 		MODF_HANDLE_RETCODE(h, ret); \
 	} while (0)
 #else  /* ! __SUNPRO_C  (gcc, icc a.s.o) */
 #define MODF_CALL(f_type, h, msg, src, params...) \
 	do { \
8f3db98b
 		cmd=(src)[0].u.data; \
dee21fff
 		ret=((f_type)cmd->function)((msg), ## params ); \
cad98b04
 		MODF_HANDLE_RETCODE(h, ret); \
 	} while (0)
 #endif /* __SUNPRO_C */
 
 
 
 /* call a module function with possible RVE params.
  * (used internally in do_action())
  * @param f_type - cmd_function type
  * @param h
  * @param msg
  * @param src - source action_u_t array (e.g. action->val)
  * @param dst - temporary action_u_t array used for conversions. It can be
  *              used for the function parameters. It's contents it's not
  *              valid after the call.
  * @param params... - variable list of parameters, passed to the module
  *               function
  * Side-effects: sets ret, clobbers i (int), s (str), rv (rvalue*), f, dst,
  *               might jump to error.
  *
  */
 #ifdef __SUNPRO_C
 #define MODF_RVE_CALL(f_type, h, msg, src, dst, ...) \
 	do { \
8f3db98b
 		cmd=(src)[0].u.data; \
 		MODF_RVE_PARAM_CONVERT(h, msg, cmd, src, dst); \
dee21fff
 		ret=((f_type)cmd->function)((msg), __VAR_ARGS__); \
cad98b04
 		MODF_HANDLE_RETCODE(h, ret); \
8f3db98b
 		/* free strings allocated by us or fixups */ \
d002aae9
 		MODF_RVE_PARAM_FREE(cmd, src, dst); \
cad98b04
 	} while (0)
 #else  /* ! __SUNPRO_C  (gcc, icc a.s.o) */
 #define MODF_RVE_CALL(f_type, h, msg, src, dst, params...) \
 	do { \
8f3db98b
 		cmd=(src)[0].u.data; \
 		MODF_RVE_PARAM_CONVERT(h, msg, cmd, src, dst); \
dee21fff
 		ret=((f_type)cmd->function)((msg), ## params ); \
cad98b04
 		MODF_HANDLE_RETCODE(h, ret); \
8f3db98b
 		/* free strings allocated by us or fixups */ \
d002aae9
 		MODF_RVE_PARAM_FREE(cmd, src, dst); \
cad98b04
 	} while (0)
 #endif /* __SUNPRO_C */
 
 
f141bc93
 /* ret= 0! if action -> end of list(e.g DROP),
7268726e
       > 0 to continue processing next actions
    and <0 on error */
20fded1f
 int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
4ac74c03
 {
 	int ret;
f20a56a2
 	int v;
e6a2b12e
 	struct dest_info dst;
7268726e
 	char* tmp;
 	char *new_uri, *end, *crt;
dee21fff
 	sr31_cmd_export_t* cmd;
7268726e
 	int len;
45072d7a
 	int user;
9de57c42
 	struct sip_uri uri, next_hop;
1bee75ad
 	struct sip_uri *u;
5ada8f8a
 	unsigned short port;
dcb59e67
 	str* dst_host;
dfda974c
 	int i, flags;
8a90dd35
 	avp_t* avp;
 	struct search_state st;
955535a4
 	struct switch_cond_table* sct;
 	struct switch_jmp_table*  sjt;
dfda974c
 	struct rval_expr* rve;
cfeefb4a
 	struct match_cond_table* mct;
 	struct rvalue* rv;
 	struct rvalue* rv1;
 	struct rval_cache c1;
 	str s;
c2d36c17
 	void *srevp[2];
cad98b04
 	/* temporary storage space for a struct action.val[] working copy
 	 (needed to transform RVE intro STRING before calling module
 	   functions). [0] is not used (corresp. to the module export pointer),
 	   [1] contains the number of params, and [2..] the param values.
 	   We need [1], because some fixup function use it
 	  (see fixup_get_param_count()).  */
 	static action_u_t mod_f_params[MAX_ACTIONS];
4ac74c03
 
1400b772
 	/* reset the value of error to E_UNSPEC so avoid unknowledgable
53c7e0f1
 	   functions to return with error (status<0) and not setting it
1400b772
 	   leaving there previous error; cache the previous value though
 	   for functions which want to process it */
 	prev_ser_error=ser_error;
 	ser_error=E_UNSPEC;
 
c2d36c17
 	/* hook for every executed action (in use by cfg debugger) */
5c679ad1
 	if(unlikely(sr_event_enabled(SREV_CFG_RUN_ACTION)))
 	{
 		srevp[0] = (void*)a;
 		srevp[1] = (void*)msg;
 		sr_event_exec(SREV_CFG_RUN_ACTION, (void*)srevp);
 	}
c2d36c17
 
3e429f5c
 	ret=E_BUG;
f2f969dd
 	switch ((unsigned char)a->type){
4ac74c03
 		case DROP_T:
ee308afd
 				switch(a->val[0].type){
 					case NUMBER_ST:
 						ret=(int) a->val[0].u.number;
 						break;
 					case RVE_ST:
 						rve=(struct rval_expr*)a->val[0].u.data;
 						rval_expr_eval_int(h, msg, &ret, rve);
 						break;
 					case RETCODE_ST:
 						ret=h->last_retcode;
 						break;
 					default:
 						BUG("unexpected subtype %d in DROP_T\n",
 								a->val[0].type);
 						ret=0;
8c69c503
 						goto error;
ee308afd
 				}
20fded1f
 				h->run_flags|=(unsigned int)a->val[1].u.number;
4ac74c03
 			break;
 		case FORWARD_T:
f2f969dd
 #ifdef USE_TCP
 		case FORWARD_TCP_T:
 #endif
8e807134
 #ifdef USE_TLS
 		case FORWARD_TLS_T:
 #endif
ed990c31
 #ifdef USE_SCTP
 		case FORWARD_SCTP_T:
 #endif
f2f969dd
 		case FORWARD_UDP_T:
2f0f1a30
 			/* init dst */
 			init_dest_info(&dst);
 			if (a->type==FORWARD_UDP_T) dst.proto=PROTO_UDP;
f2f969dd
 #ifdef USE_TCP
2f0f1a30
 			else if (a->type==FORWARD_TCP_T) dst.proto= PROTO_TCP;
f2f969dd
 #endif
e9b02e8e
 #ifdef USE_TLS
2f0f1a30
 			else if (a->type==FORWARD_TLS_T) dst.proto= PROTO_TLS;
e9b02e8e
 #endif
ed990c31
 #ifdef USE_SCTP
 			else if (a->type==FORWARD_SCTP_T) dst.proto=PROTO_SCTP;
 #endif
 			else dst.proto=PROTO_NONE;
f141bc93
 			if (a->val[0].type==URIHOST_ST){
5ada8f8a
 				/*parse uri*/
9de57c42
 
 				if (msg->dst_uri.len) {
7a068ff3
 					ret = parse_uri(msg->dst_uri.s, msg->dst_uri.len,
 									&next_hop);
9de57c42
 					u = &next_hop;
 				} else {
 					ret = parse_sip_msg_uri(msg);
 					u = &msg->parsed_uri;
 				}
 
1400b772
 				if (ret<0) {
bb718138
 					LM_ERR("forward: bad_uri dropping packet\n");
8c69c503
 					goto error;
5ada8f8a
 				}
f141bc93
 
 				switch (a->val[1].type){
5ada8f8a
 					case URIPORT_ST:
1baa06b5
 									port=u->port_no;
5ada8f8a
 									break;
 					case NUMBER_ST:
f141bc93
 									port=a->val[1].u.number;
5ada8f8a
 									break;
 					default:
bb718138
 							LM_CRIT("bad forward 2nd param type (%d)\n", a->val[1].type);
7f858173
 							ret=E_UNSPEC;
 							goto error_fwd_uri;
5ada8f8a
 				}
2f0f1a30
 				if (dst.proto == PROTO_NONE){ /* only if proto not set get it
87deb93f
 											 from the uri */
 					switch(u->proto){
 						case PROTO_NONE:
dd4ffbb7
 							/*dst.proto=PROTO_UDP; */
 							/* no proto, try to get it from the dns */
87deb93f
 							break;
 						case PROTO_UDP:
f2e456c3
 #ifdef USE_TCP
87deb93f
 						case PROTO_TCP:
1123ed46
 						case PROTO_WS:
f2e456c3
 #endif
e9b02e8e
 #ifdef USE_TLS
87deb93f
 						case PROTO_TLS:
1123ed46
 						case PROTO_WSS:
e9b02e8e
 #endif
ed990c31
 #ifdef USE_SCTP
 						case PROTO_SCTP:
 #endif
2f0f1a30
 							dst.proto=u->proto;
87deb93f
 							break;
 						default:
bb718138
 							LM_ERR("forward: bad uri transport %d\n", u->proto);
87deb93f
 							ret=E_BAD_PROTO;
 							goto error_fwd_uri;
 					}
3f601bd0
 #ifdef USE_TLS
2518c900
 					if (u->type==SIPS_URI_T){
87deb93f
 						if (u->proto==PROTO_UDP){
bb718138
 							LM_ERR("forward: secure uri incompatible with transport %d\n",
2518c900
 									u->proto);
87deb93f
 							ret=E_BAD_PROTO;
 							goto error_fwd_uri;
3d4a77d8
 						} else if (u->proto!=PROTO_WSS)
 							dst.proto=PROTO_TLS;
 						else
 							dst.proto=PROTO_WSS;
3f601bd0
 					}
 #endif
87deb93f
 				}
17bae7f1
 
bf79b581
 #ifdef HONOR_MADDR
dcb59e67
 				if (u->maddr_val.s && u->maddr_val.len)
 					dst_host=&u->maddr_val;
 				else
17bae7f1
 #endif
dcb59e67
 					dst_host=&u->host;
7a068ff3
 #ifdef USE_COMP
 				dst.comp=u->comp;
 #endif
dcb59e67
 				ret=forward_request(msg, dst_host, port, &dst);
 				if (ret>=0){
 					ret=1;
 				}
f141bc93
 			}else if ((a->val[0].type==PROXY_ST) && (a->val[1].type==NUMBER_ST)){
2f0f1a30
 				if (dst.proto==PROTO_NONE)
 					dst.proto=msg->rcv.proto;
 				proxy2su(&dst.to,  (struct proxy_l*)a->val[0].u.data);
dcb59e67
 				ret=forward_request(msg, 0, 0, &dst);
2f0f1a30
 				if (ret>=0){
 					ret=1;
 					proxy_mark((struct proxy_l*)a->val[0].u.data, ret);
 				}else if (ser_error!=E_OK){
 					proxy_mark((struct proxy_l*)a->val[0].u.data, ret);
 				}
5ada8f8a
 			}else{
bb718138
 				LM_CRIT("bad forward() types %d, %d\n",
f141bc93
 						a->val[0].type, a->val[1].type);
4ac74c03
 				ret=E_BUG;
8c69c503
 				goto error;
4ac74c03
 			}
 			break;
 		case LOG_T:
f141bc93
 			if ((a->val[0].type!=NUMBER_ST)|(a->val[1].type!=STRING_ST)){
bb718138
 				LM_CRIT("bad log() types %d, %d\n",
f141bc93
 						a->val[0].type, a->val[1].type);
3e429f5c
 				ret=E_BUG;
8c69c503
 				goto error;
3e429f5c
 			}
e8249ab7
 			LOG_(DEFAULT_FACILITY, a->val[0].u.number, "<script>: ", "%s", 
 				 a->val[1].u.string);
4ac74c03
 			ret=1;
 			break;
3881f12c
 
caf80ae6
 		/* jku -- introduce a new branch */
 		case APPEND_BRANCH_T:
394e061f
 			if (unlikely(a->val[0].type!=STR_ST)) {
bb718138
 				LM_CRIT("bad append_branch_t %d\n", a->val[0].type );
caf80ae6
 				ret=E_BUG;
8c69c503
 				goto error;
caf80ae6
 			}
394e061f
 			getbflagsval(0, (flag_t*)&flags);
 			ret=append_branch(msg, &a->val[0].u.str, &msg->dst_uri,
571e4e3f
 					  &msg->path_vec, a->val[1].u.number,
 					  (flag_t)flags, msg->force_send_socket,
8ca114df
 					  0, 0, 0, 0);
4cd7a346
 			/* if the uri is the ruri and q was also not changed, mark
 			   ruri as consumed, to avoid having an identical branch */
 			if ((a->val[0].u.str.s == 0 || a->val[0].u.str.len == 0) &&
 					a->val[1].u.number == Q_UNSPECIFIED)
 				ruri_mark_consumed();
caf80ae6
 			break;
 
9fa304f1
 		/* remove last branch */
 		case REMOVE_BRANCH_T:
 			if (a->val[0].type!=NUMBER_ST) {
 				ret=drop_sip_branch(0) ? -1 : 1;
 			} else {
 				ret=drop_sip_branch(a->val[0].u.number) ? -1 : 1;
 			}
 			break;
 
 		/* remove all branches */
 		case CLEAR_BRANCHES_T:
 			clear_branches();
 			ret=1;
 			break;
 
1f377e97
 		/* jku begin: is_length_greater_than */
 		case LEN_GT_T:
f141bc93
 			if (a->val[0].type!=NUMBER_ST) {
bb718138
 				LM_CRIT("bad len_gt type %d\n", a->val[0].type );
1f377e97
 				ret=E_BUG;
8c69c503
 				goto error;
1f377e97
 			}
393fc062
 			/* LM_DBG("message length %d, max %d\n",
f141bc93
 				msg->len, a->val[0].u.number ); */
 			ret = msg->len >= a->val[0].u.number ? 1 : -1;
1f377e97
 			break;
 		/* jku end: is_length_greater_than */
f141bc93
 
3881f12c
 		/* jku - begin : flag processing */
 
 		case SETFLAG_T:
f141bc93
 			if (a->val[0].type!=NUMBER_ST) {
bb718138
 				LM_CRIT("bad setflag() type %d\n", a->val[0].type );
3881f12c
 				ret=E_BUG;
8c69c503
 				goto error;
3881f12c
 			}
f141bc93
 			if (!flag_in_range( a->val[0].u.number )) {
3881f12c
 				ret=E_CFG;
8c69c503
 				goto error;
3881f12c
 			}
f141bc93
 			setflag( msg, a->val[0].u.number );
3881f12c
 			ret=1;
 			break;
 
 		case RESETFLAG_T:
f141bc93
 			if (a->val[0].type!=NUMBER_ST) {
bb718138
 				LM_CRIT("bad resetflag() type %d\n", a->val[0].type );
3881f12c
 				ret=E_BUG;
8c69c503
 				goto error;
3881f12c
 			}
f141bc93
 			if (!flag_in_range( a->val[0].u.number )) {
3881f12c
 				ret=E_CFG;
8c69c503
 				goto error;
3881f12c
 			}
f141bc93
 			resetflag( msg, a->val[0].u.number );
3881f12c
 			ret=1;
 			break;
f141bc93
 
3881f12c
 		case ISFLAGSET_T:
f141bc93
 			if (a->val[0].type!=NUMBER_ST) {
bb718138
 				LM_CRIT("bad isflagset() type %d\n", a->val[0].type );
3881f12c
 				ret=E_BUG;
8c69c503
 				goto error;
3881f12c
 			}
f141bc93
 			if (!flag_in_range( a->val[0].u.number )) {
3881f12c
 				ret=E_CFG;
8c69c503
 				goto error;
3881f12c
 			}
f141bc93
 			ret=isflagset( msg, a->val[0].u.number );
3881f12c
 			break;
 		/* jku - end : flag processing */
 
8a90dd35
 		case AVPFLAG_OPER_T:
85d4627f
 			ret = 0;
8a90dd35
 			if ((a->val[0].u.attr->type & AVP_INDEX_ALL) == AVP_INDEX_ALL ||
 					(a->val[0].u.attr->type & AVP_NAME_RE)!=0) {
 				for (avp=search_first_avp(a->val[0].u.attr->type,
 							a->val[0].u.attr->name, NULL, &st);
 						avp;
 						avp = search_next_avp(&st, NULL)) {
 					switch (a->val[2].u.number) {
 						/* oper: 0..reset, 1..set, -1..no change */
85d4627f
 						case 0:
 							avp->flags &= ~(avp_flags_t)a->val[1].u.number;
 							break;
 						case 1:
 							avp->flags |= (avp_flags_t)a->val[1].u.number;
 							break;
 						default:;
 					}
8a90dd35
 					ret = ret ||
 						((avp->flags & (avp_flags_t)a->val[1].u.number) != 0);
85d4627f
 				}
8a90dd35
 			} else {
 				avp = search_avp_by_index(a->val[0].u.attr->type,
 											a->val[0].u.attr->name, NULL,
 											a->val[0].u.attr->index);
85d4627f
 				if (avp) {
8a90dd35
 					switch (a->val[2].u.number) {
 						/* oper: 0..reset, 1..set, -1..no change */
85d4627f
 						case 0:
 							avp->flags &= ~(avp_flags_t)a->val[1].u.number;
 							break;
 						case 1:
 							avp->flags |= (avp_flags_t)a->val[1].u.number;
 							break;
 						default:;
 					}
 					ret = (avp->flags & (avp_flags_t)a->val[1].u.number) != 0;
 				}
 			}
 			if (ret==0)
 				ret = -1;
 			break;
4ac74c03
 		case ERROR_T:
f141bc93
 			if ((a->val[0].type!=STRING_ST)|(a->val[1].type!=STRING_ST)){
bb718138
 				LM_CRIT("bad error() types %d, %d\n", a->val[0].type, a->val[1].type);
3e429f5c
 				ret=E_BUG;
8c69c503
 				goto error;
3e429f5c
 			}
bb718138
 			LM_NOTICE("error(\"%s\", \"%s\") "
f141bc93
 					"not implemented yet\n", a->val[0].u.string, a->val[1].u.string);
4ac74c03
 			ret=1;
 			break;
 		case ROUTE_T:
d75db62d
 			if (likely(a->val[0].type == NUMBER_ST))
 				i = a->val[0].u.number;
 			else if (a->val[0].type == RVE_ST) {
 				rv = rval_expr_eval(h, msg, a->val[0].u.data);
 				rval_cache_init(&c1);
 				if (unlikely(rv == 0 ||
 						rval_get_tmp_str(h, msg, &s, rv, 0, &c1) < 0)) {
 					rval_destroy(rv);
 					rval_cache_clean(&c1);
 					ERR("failed to convert RVE to string\n");
 					ret = E_UNSPEC;
 					goto error;
 				}
 				i = route_lookup(&main_rt, s.s);
 				if (unlikely(i < 0)) {
 					ERR("route \"%s\" not found at %s:%d\n",
 							s.s, (a->cfile)?a->cfile:"line", a->cline);
c26801f4
 					rval_destroy(rv);
d75db62d
 					rval_cache_clean(&c1);
 					s.s = 0;
 					ret = E_SCRIPT;
 					goto error;
 				}
c26801f4
 				rval_destroy(rv);
d75db62d
 				rval_cache_clean(&c1);
 				s.s = 0;
 			} else {
bb718138
 				LM_CRIT("bad route() type %d\n", a->val[0].type);
3e429f5c
 				ret=E_BUG;
8c69c503
 				goto error;
3e429f5c
 			}
d75db62d
 			if (unlikely((i>=main_rt.idx)||(i<0))){
bb718138
 				LM_ERR("invalid routing table number in"
d75db62d
 							"route(%lu) at %s:%d\n", a->val[0].u.number,
 							(a->cfile)?a->cfile:"line", a->cline);
3e429f5c
 				ret=E_CFG;
8c69c503
 				goto error;
3e429f5c
 			}
d75db62d
 			/*ret=((ret=run_actions(rlist[a->val[0].u.number],msg))<0)?ret:1;*/
 			ret=run_actions(h, main_rt.rlist[i], msg);
20fded1f
 			h->last_retcode=ret;
68b7a898
 			_last_returned_code = h->last_retcode;
955535a4
 			h->run_flags&=~(RETURN_R_F|BREAK_R_F); /* absorb return & break */
4ac74c03
 			break;
 		case EXEC_T:
f141bc93
 			if (a->val[0].type!=STRING_ST){
bb718138
 				LM_CRIT("bad exec() type %d\n", a->val[0].type);
3e429f5c
 				ret=E_BUG;
8c69c503
 				goto error;
3e429f5c
 			}
bb718138
 			LM_NOTICE("exec(\"%s\") not fully implemented,"
f141bc93
 						" using dumb version...\n", a->val[0].u.string);
 			ret=system(a->val[0].u.string);
4ac74c03
 			if (ret!=0){
bb718138
 				LM_NOTICE("exec() returned %d\n", ret);
4ac74c03
 			}
 			ret=1;
 			break;
caf80ae6
 		case REVERT_URI_T:
 			if (msg->new_uri.s) {
 				pkg_free(msg->new_uri.s);
 				msg->new_uri.len=0;
 				msg->new_uri.s=0;
a6982b85
 				msg->parsed_uri_ok=0; /* invalidate current parsed uri*/
914a4c04
 				ruri_mark_new(); /* available for forking */
caf80ae6
 			};
 			ret=1;
 			break;
7268726e
 		case SET_HOST_T:
 		case SET_HOSTPORT_T:
6973e34c
 		case SET_HOSTPORTTRANS_T:
cec6ad97
 		case SET_HOSTALL_T:
7268726e
 		case SET_USER_T:
 		case SET_USERPASS_T:
 		case SET_PORT_T:
 		case SET_URI_T:
1f377e97
 		case PREFIX_T:
 		case STRIP_T:
1d9f91d6
 		case STRIP_TAIL_T:
536065b8
 		case SET_USERPHONE_T:
45072d7a
 				user=0;
1d9f91d6
 				if (a->type==STRIP_T || a->type==STRIP_TAIL_T) {
f141bc93
 					if (a->val[0].type!=NUMBER_ST) {
bb718138
 						LM_CRIT("bad set*() type %d\n", a->val[0].type);
536065b8
 						ret=E_BUG;
8c69c503
 						goto error;
1f377e97
 					}
536065b8
 				} else if (a->type!=SET_USERPHONE_T) {
 					if (a->val[0].type!=STRING_ST) {
bb718138
 						LM_CRIT("bad set*() type %d\n", a->val[0].type);
536065b8
 						ret=E_BUG;
8c69c503
 						goto error;
536065b8
 					}
7268726e
 				}
 				if (a->type==SET_URI_T){
f8d46776
 					if (msg->new_uri.s) {
b78959d0
 							pkg_free(msg->new_uri.s);
f8d46776
 							msg->new_uri.len=0;
903766ce
 					}
a6982b85
 					msg->parsed_uri_ok=0;
f141bc93
 					len=strlen(a->val[0].u.string);
b78959d0
 					msg->new_uri.s=pkg_malloc(len+1);
f8d46776
 					if (msg->new_uri.s==0){
bb718138
 						LM_ERR("memory allocation failure\n");
7268726e
 						ret=E_OUT_OF_MEM;
8c69c503
 						goto error;
7268726e
 					}
f141bc93
 					memcpy(msg->new_uri.s, a->val[0].u.string, len);
f8d46776
 					msg->new_uri.s[len]=0;
 					msg->new_uri.len=len;
914a4c04
 					ruri_mark_new(); /* available for forking */
f141bc93
 
7268726e
 					ret=1;
 					break;
 				}
773f8568
 				if (msg->parsed_uri_ok==0) {
6973e34c
 					if (msg->new_uri.s) {
 						tmp=msg->new_uri.s;
 						len=msg->new_uri.len;
 					}else{
 						tmp=msg->first_line.u.request.uri.s;
 						len=msg->first_line.u.request.uri.len;
 					}
 					if (parse_uri(tmp, len, &uri)<0){
bb718138
 						LM_ERR("bad uri <%s>, dropping packet\n", tmp);
6973e34c
 						ret=E_UNSPEC;
8c69c503
 						goto error;
6973e34c
 					}
 				} else {
 					uri=msg->parsed_uri;
7268726e
 				}
f141bc93
 
536065b8
 				/* skip SET_USERPHONE_T action if the URI is already
 				 * a tel: or tels: URI, or contains the user=phone param */
 				if ((a->type==SET_USERPHONE_T) 
 					&& ((uri.type==TEL_URI_T) || (uri.type==TELS_URI_T)
 						|| ((uri.user_param_val.len==5) && (memcmp(uri.user_param_val.s, "phone", 5)==0)))
 				) {
 					ret=1;
 					break;
 				}
 				/* SET_PORT_T does not work with tel: URIs */
 				if ((a->type==SET_PORT_T)
 					&& ((uri.type==TEL_URI_T) || (uri.type==TELS_URI_T))
 					&& ((uri.flags & URI_SIP_USER_PHONE)==0)
 				) {
bb718138
 					LM_ERR("port number of a tel: URI cannot be set\n");
536065b8
 					ret=E_UNSPEC;
8c69c503
 					goto error;
536065b8
 				}
 
b78959d0
 				new_uri=pkg_malloc(MAX_URI_SIZE);
7268726e
 				if (new_uri==0){
bb718138
 					LM_ERR("memory allocation failure\n");
7268726e
 					ret=E_OUT_OF_MEM;
8c69c503
 					goto error;
7268726e
 				}
 				end=new_uri+MAX_URI_SIZE;
 				crt=new_uri;
 				/* begin copying */
536065b8
 				/* Preserve the URI scheme unless the host part needs
 				 * to be rewritten, and the shceme is tel: or tels: */
 				switch (uri.type) {
 				case SIP_URI_T:
 					len=s_sip.len;
 					tmp=s_sip.s;
 					break;
 
 				case SIPS_URI_T:
 					len=s_sips.len;
 					tmp=s_sips.s;
 					break;
 
 				case TEL_URI_T:
 					if ((uri.flags & URI_SIP_USER_PHONE)
 						|| (a->type==SET_HOST_T)
 						|| (a->type==SET_HOSTPORT_T)
 						|| (a->type==SET_HOSTPORTTRANS_T)
 					) {
 						len=s_sip.len;
 						tmp=s_sip.s;
 						break;
 					}
 					len=s_tel.len;
 					tmp=s_tel.s;
 					break;
 
 				case TELS_URI_T:
 					if ((uri.flags & URI_SIP_USER_PHONE)
 						|| (a->type==SET_HOST_T)
 						|| (a->type==SET_HOSTPORT_T)
 						|| (a->type==SET_HOSTPORTTRANS_T)
 					) {
 						len=s_sips.len;
 						tmp=s_sips.s;
 						break;
 					}
 					len=s_tels.len;
 					tmp=s_tels.s;
 					break;
 
 				default:
bb718138
 					LM_ERR("Unsupported URI scheme (%d), reverted to sip:\n",
536065b8
 						uri.type);
 					len=s_sip.len;
 					tmp=s_sip.s;
 				}
 				if(crt+len+1 /* colon */ >end) goto error_uri;
 				memcpy(crt,tmp,len);crt+=len;
 				*crt=':'; crt++;
1f377e97
 
7268726e
 				/* user */
1f377e97
 
 				/* prefix (-jiri) */
 				if (a->type==PREFIX_T) {
f141bc93
 					tmp=a->val[0].u.string;
7268726e
 					len=strlen(tmp); if(crt+len>end) goto error_uri;
 					memcpy(crt,tmp,len);crt+=len;
f141bc93
 					/* whatever we had before, with prefix we have username
b621d616
 					   now */
1f377e97
 					user=1;
 				}
 
 				if ((a->type==SET_USER_T)||(a->type==SET_USERPASS_T)) {
f141bc93
 					tmp=a->val[0].u.string;
1f377e97
 					len=strlen(tmp);
 				} else if (a->type==STRIP_T) {
f141bc93
 					if (a->val[0].u.number>uri.user.len) {
bb718138
 						LM_WARN("too long strip asked; deleting username: %lu of <%.*s>\n",
f141bc93
 									a->val[0].u.number, uri.user.len, uri.user.s );
1f377e97
 						len=0;
f141bc93
 					} else if (a->val[0].u.number==uri.user.len) {
1f377e97
 						len=0;
 					} else {
f141bc93
 						tmp=uri.user.s + a->val[0].u.number;
 						len=uri.user.len - a->val[0].u.number;
1f377e97
 					}
1d9f91d6
 				} else if (a->type==STRIP_TAIL_T) {
f141bc93
 					if (a->val[0].u.number>uri.user.len) {
bb718138
 						LM_WARN("too long strip_tail asked; "
b667b278
 									" deleting username: %lu of <%.*s>\n",
f141bc93
 									a->val[0].u.number, uri.user.len, uri.user.s );
1d9f91d6
 						len=0;
f141bc93
 					} else if (a->val[0].u.number==uri.user.len) {
1d9f91d6
 						len=0;
 					} else {
 						tmp=uri.user.s;
f141bc93
 						len=uri.user.len - a->val[0].u.number;
1d9f91d6
 					}
1f377e97
 				} else {
 					tmp=uri.user.s;
 					len=uri.user.len;
 				}
 
 				if (len){
 					if(crt+len>end) goto error_uri;
 					memcpy(crt,tmp,len);crt+=len;
45072d7a
 					user=1; /* we have an user field so mark it */
7268726e
 				}
1f377e97
 
7268726e
 				if (a->type==SET_USERPASS_T) tmp=0;
f8d46776
 				else tmp=uri.passwd.s;
8c3d167b
 				/* passwd - keep it only if user is set */
 				if (user && tmp){
b621d616
 					len=uri.passwd.len; if(crt+len+1>end) goto error_uri;
 					*crt=':'; crt++;
7268726e
 					memcpy(crt,tmp,len);crt+=len;
 				}
773f8568
 				/* tel: URI parameters */
 				if ((uri.type==TEL_URI_T)
 					|| (uri.type==TELS_URI_T)
 				) {
 					tmp=uri.params.s;
 					if (tmp){
 						len=uri.params.len; if(crt+len+1>end) goto error_uri;
 						*crt=';'; crt++;
 						memcpy(crt,tmp,len);crt+=len;
 					}
 				}
7268726e
 				/* host */
6973e34c
 				if ((a->type==SET_HOST_T)
 						|| (a->type==SET_HOSTPORT_T)
cec6ad97
 						|| (a->type==SET_HOSTALL_T)
536065b8
 						|| (a->type==SET_HOSTPORTTRANS_T)
 				) {
f141bc93
 					tmp=a->val[0].u.string;
a6982b85
 					if (tmp) len = strlen(tmp);
b621d616
 					else len=0;
536065b8
 				} else if ((uri.type==SIP_URI_T)
 					|| (uri.type==SIPS_URI_T)
 					|| (uri.flags & URI_SIP_USER_PHONE)
 				) {
f8d46776
 					tmp=uri.host.s;
536065b8
 					len=uri.host.len;
 				} else {
 					tmp=0;
a6982b85
 				}
7268726e
 				if (tmp){
536065b8
 					if (user) { /* add @ */
 						if(crt+1>end) goto error_uri;
 						*crt='@'; crt++;
 					}
a6982b85
 					if(crt+len>end) goto error_uri;
7268726e
 					memcpy(crt,tmp,len);crt+=len;
 				}
cec6ad97
 				if(a->type==SET_HOSTALL_T)
 					goto done_seturi;
7268726e
 				/* port */
6973e34c
 				if ((a->type==SET_HOSTPORT_T)
 						|| (a->type==SET_HOSTPORTTRANS_T))
 					tmp=0;
a6982b85
 				else if (a->type==SET_PORT_T) {
f141bc93
 					tmp=a->val[0].u.string;
d260b2cb
 					if (tmp) {
 						len = strlen(tmp);
 						if(len==0) tmp = 0;
 					} else len = 0;
a6982b85
 				} else {
 					tmp=uri.port.s;
 					len = uri.port.len;
 				}
7268726e
 				if (tmp){
b621d616
 					if(crt+len+1>end) goto error_uri;
 					*crt=':'; crt++;
7268726e
 					memcpy(crt,tmp,len);crt+=len;
 				}
 				/* params */
773f8568
 				if ((a->type==SET_HOSTPORTTRANS_T)
 					&& uri.sip_params.s
 					&& uri.transport.s
 				) {
6973e34c
 					/* bypass the transport parameter */
773f8568
 					if (uri.sip_params.s < uri.transport.s) {
6973e34c
 						/* there are parameters before transport */
773f8568
 						len = uri.transport.s - uri.sip_params.s - 1;
6973e34c
 							/* ignore the ';' at the end */
 						if (crt+len+1>end) goto error_uri;
 						*crt=';'; crt++;
773f8568
 						memcpy(crt,uri.sip_params.s,len);crt+=len;
6973e34c
 					}
773f8568
 					len = (uri.sip_params.s + uri.sip_params.len) -
6973e34c
 						(uri.transport.s + uri.transport.len);
 					if (len > 0) {
 						/* there are parameters after transport */
 						if (crt+len>end) goto error_uri;
 						tmp = uri.transport.s + uri.transport.len;
 						memcpy(crt,tmp,len);crt+=len;
 					}
 				} else {
773f8568
 					tmp=uri.sip_params.s;
6973e34c
 					if (tmp){
773f8568
 						len=uri.sip_params.len; if(crt+len+1>end) goto error_uri;
6973e34c
 						*crt=';'; crt++;
 						memcpy(crt,tmp,len);crt+=len;
 					}
7268726e
 				}
536065b8
 				/* Add the user=phone param if a tel: or tels:
 				 * URI was converted to sip: or sips:.
 				 * (host part of a tel/tels URI was set.)
 				 * Or in case of sip: URI and SET_USERPHONE_T action */
 				if (((((uri.type==TEL_URI_T) || (uri.type==TELS_URI_T))
 					&& ((uri.flags & URI_SIP_USER_PHONE)==0))
 					&& ((a->type==SET_HOST_T)
 						|| (a->type==SET_HOSTPORT_T)
 						|| (a->type==SET_HOSTPORTTRANS_T)))
 					|| (a->type==SET_USERPHONE_T)
 				) {
 					tmp=";user=phone";
 					len=strlen(tmp);
 					if(crt+len>end) goto error_uri;
 					memcpy(crt,tmp,len);crt+=len;
 				}
7268726e
 				/* headers */
f8d46776
 				tmp=uri.headers.s;
7268726e
 				if (tmp){
b621d616
 					len=uri.headers.len; if(crt+len+1>end) goto error_uri;
 					*crt='?'; crt++;
7268726e
 					memcpy(crt,tmp,len);crt+=len;
 				}
cec6ad97
 	done_seturi:
7268726e
 				*crt=0; /* null terminate the thing */
 				/* copy it to the msg */
b78959d0
 				if (msg->new_uri.s) pkg_free(msg->new_uri.s);
f8d46776
 				msg->new_uri.s=new_uri;
 				msg->new_uri.len=crt-new_uri;
a6982b85
 				msg->parsed_uri_ok=0;
914a4c04
 				ruri_mark_new(); /* available for forking */
7268726e
 				ret=1;
 				break;
f20a56a2
 		case IF_T:
8637f340
 					rve=(struct rval_expr*)a->val[0].u.data;
 					if (unlikely(rval_expr_eval_int(h, msg, &v, rve) != 0)){
 						ERR("if expression evaluation failed (%d,%d-%d,%d)\n",
 								rve->fpos.s_line, rve->fpos.s_col,
 								rve->fpos.e_line, rve->fpos.e_col);
 						v=0; /* false */
f20a56a2
 					}
8637f340
 					if (unlikely(h->run_flags & EXIT_R_F)){
01dea124
 						ret=0;
 						break;
 					}
955535a4
 					h->run_flags &= ~(RETURN_R_F|BREAK_R_F); /* catch return &
 															    break in expr*/
9e973a63
 					ret=1;  /*default is continue */
9598488f
 					if (v>0) {
f141bc93
 						if ((a->val[1].type==ACTIONS_ST)&&a->val[1].u.data){
bf79b581
 							ret=run_actions(h,
20fded1f
 										(struct action*)a->val[1].u.data, msg);
f20a56a2
 						}
f141bc93
 					}else if ((a->val[2].type==ACTIONS_ST)&&a->val[2].u.data){
bf79b581
 							ret=run_actions(h,
20fded1f
 										(struct action*)a->val[2].u.data, msg);
f20a56a2
 					}
 			break;
cad98b04
 		case MODULE0_T:
 			MODF_CALL(cmd_function, h, msg, a->val, 0, 0);
a2da0c58
 			break;
 		/* instead of using the parameter number, we use different names
 		 * for calls to functions with 3, 4, 5, 6 or variable number of
 		 * parameters due to performance reasons */
cad98b04
 		case MODULE1_T:
 			MODF_CALL(cmd_function, h, msg, a->val,
 										(char*)a->val[2].u.data,
 										0
 					);
 			break;
 		case MODULE2_T:
 			MODF_CALL(cmd_function, h, msg, a->val,
 										(char*)a->val[2].u.data,
 										(char*)a->val[3].u.data
 					);
 			break;
a2da0c58
 		case MODULE3_T:
cad98b04
 			MODF_CALL(cmd_function3, h, msg, a->val,
a2da0c58
 										(char*)a->val[2].u.data,
 										(char*)a->val[3].u.data,
 										(char*)a->val[4].u.data
cad98b04
 					);
a2da0c58
 			break;
 		case MODULE4_T:
cad98b04
 			MODF_CALL(cmd_function4, h, msg, a->val,
a2da0c58
 										(char*)a->val[2].u.data,
 										(char*)a->val[3].u.data,
 										(char*)a->val[4].u.data,
 										(char*)a->val[5].u.data
cad98b04
 					);
a2da0c58
 			break;
 		case MODULE5_T:
cad98b04
 			MODF_CALL(cmd_function5, h, msg, a->val,
a2da0c58
 										(char*)a->val[2].u.data,
 										(char*)a->val[3].u.data,
 										(char*)a->val[4].u.data,
 										(char*)a->val[5].u.data,
 										(char*)a->val[6].u.data
cad98b04
 					);
a2da0c58
 			break;
 		case MODULE6_T:
cad98b04
 			MODF_CALL(cmd_function6, h, msg, a->val,
a2da0c58
 										(char*)a->val[2].u.data,
 										(char*)a->val[3].u.data,
 										(char*)a->val[4].u.data,
 										(char*)a->val[5].u.data,
 										(char*)a->val[6].u.data,
 										(char*)a->val[7].u.data
cad98b04
 					);
a2da0c58
 			break;
 		case MODULEX_T:
cad98b04
 			MODF_CALL(cmd_function_var, h, msg, a->val,
 							a->val[1].u.number, &a->val[2]);
 			break;
 		case MODULE1_RVE_T:
 			MODF_RVE_CALL(cmd_function, h, msg, a->val, mod_f_params,
 											(char*)mod_f_params[2].u.data,
 											0
 					);
 			break;
 		case MODULE2_RVE_T:
 			MODF_RVE_CALL(cmd_function, h, msg, a->val, mod_f_params,
 											(char*)mod_f_params[2].u.data,
 											(char*)mod_f_params[3].u.data
 					);
 			break;
 		case MODULE3_RVE_T:
 			MODF_RVE_CALL(cmd_function3, h, msg, a->val, mod_f_params,
 											(char*)mod_f_params[2].u.data,
 											(char*)mod_f_params[3].u.data,
 											(char*)mod_f_params[4].u.data
 					);
 			break;
 		case MODULE4_RVE_T:
 			MODF_RVE_CALL(cmd_function4, h, msg, a->val, mod_f_params,
 											(char*)mod_f_params[2].u.data,
 											(char*)mod_f_params[3].u.data,
 											(char*)mod_f_params[4].u.data,
 											(char*)mod_f_params[5].u.data
 					);
 			break;
 		case MODULE5_RVE_T:
 			MODF_RVE_CALL(cmd_function5, h, msg, a->val, mod_f_params,
 											(char*)mod_f_params[2].u.data,
 											(char*)mod_f_params[3].u.data,
 											(char*)mod_f_params[4].u.data,
 											(char*)mod_f_params[5].u.data,
 											(char*)mod_f_params[6].u.data
 					);
 			break;
 		case MODULE6_RVE_T:
 			MODF_RVE_CALL(cmd_function6, h, msg, a->val, mod_f_params,
 											(char*)mod_f_params[2].u.data,
 											(char*)mod_f_params[3].u.data,
 											(char*)mod_f_params[4].u.data,
 											(char*)mod_f_params[5].u.data,
 											(char*)mod_f_params[6].u.data,
 											(char*)mod_f_params[7].u.data
 					);
 			break;
 		case MODULEX_RVE_T:
 			MODF_RVE_CALL(cmd_function_var, h, msg, a->val, mod_f_params,
 							a->val[1].u.number, &mod_f_params[2]);
3bf76e49
 			break;
955535a4
 		case EVAL_T:
 			/* only eval the expression to account for possible
 			   side-effect */
 			rval_expr_eval_int(h, msg, &v,
 					(struct rval_expr*)a->val[0].u.data);
 			if (h->run_flags & EXIT_R_F){
 				ret=0;
 				break;
 			}
 			h->run_flags &= ~RETURN_R_F|BREAK_R_F; /* catch return & break in
 													  expr */
 			ret=1; /* default is continue */
 			break;
 		case SWITCH_COND_T:
 			sct=(struct switch_cond_table*)a->val[1].u.data;
 			if (unlikely( rval_expr_eval_int(h, msg, &v,
 									(struct rval_expr*)a->val[0].u.data) <0)){
 				/* handle error in expression => use default */
 				ret=-1;
 				goto sw_cond_def;
 			}
 			if (h->run_flags & EXIT_R_F){
 				ret=0;
 				break;
 			}
 			h->run_flags &= ~(RETURN_R_F|BREAK_R_F); /* catch return & break
 													    in expr */
 			ret=1; /* default is continue */
 			for(i=0; i<sct->n; i++)
 				if (sct->cond[i]==v){
 					if (likely(sct->jump[i])){
 						ret=run_actions(h, sct->jump[i], msg);
 						h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
 													   returns passthrough */
 					}
 					goto skip;
 				}
 sw_cond_def:
 			if (sct->def){
 				ret=run_actions(h, sct->def, msg);
 				h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
 											   returns passthrough */
 			}
 			break;
 		case SWITCH_JT_T:
 			sjt=(struct switch_jmp_table*)a->val[1].u.data;
 			if (unlikely( rval_expr_eval_int(h, msg, &v,
 									(struct rval_expr*)a->val[0].u.data) <0)){
 				/* handle error in expression => use default */
 				ret=-1;
 				goto sw_jt_def;
 			}
 			if (h->run_flags & EXIT_R_F){
 				ret=0;
 				break;
 			}
 			h->run_flags &= ~(RETURN_R_F|BREAK_R_F); /* catch return & break
 													    in expr */
 			ret=1; /* default is continue */
 			if (likely(v >= sjt->first && v <= sjt->last)){
 				if (likely(sjt->tbl[v - sjt->first])){
 					ret=run_actions(h, sjt->tbl[v - sjt->first], msg);
 					h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
 												   returns passthrough */
 				}
 				break; 
 			}else{
 				for(i=0; i<sjt->rest.n; i++)
 					if (sjt->rest.cond[i]==v){
 						if (likely(sjt->rest.jump[i])){
 							ret=run_actions(h, sjt->rest.jump[i], msg);
 							h->run_flags &= ~BREAK_R_F; /* catch breaks, but 
 														   let returns pass */
 						}
 						goto skip;
 					}
 			}
 			/* not found => try default */
 sw_jt_def:
 			if (sjt->rest.def){
 				ret=run_actions(h, sjt->rest.def, msg);
 				h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
 											   returns passthrough */
 			}
 			break;
 		case BLOCK_T:
 			if (likely(a->val[0].u.data)){
 				ret=run_actions(h, (struct action*)a->val[0].u.data, msg);
 				h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
 											   returns passthrough */
 			}
 			break;
cfeefb4a
 		case MATCH_COND_T:
 			mct=(struct match_cond_table*)a->val[1].u.data;
 			rval_cache_init(&c1);
 			rv=0;
 			rv1=0;
 			ret=rval_expr_eval_rvint(h, msg, &rv, &v, 
 									(struct rval_expr*)a->val[0].u.data, &c1);
 									
 			if (unlikely( ret<0)){
 				/* handle error in expression => use default */
 				ret=-1;
 				goto match_cond_def;
 			}
 			if (h->run_flags & EXIT_R_F){
 				ret=0;
 				break;
 			}
 			h->run_flags &= ~(RETURN_R_F|BREAK_R_F); /* catch return & break
 													    in expr */
 			if (likely(rv)){
 				rv1=rval_convert(h, msg, RV_STR, rv, &c1);
 				if (unlikely(rv1==0)){
 					ret=-1;
 					goto match_cond_def;
 				}
 				s=rv1->v.s;
 			}else{
 				/* int result in v */
 				rval_cache_clean(&c1);
 				s.s=sint2str(v, &s.len);
 			}
 			ret=1; /* default is continue */
 			for(i=0; i<mct->n; i++)
 				if (( mct->match[i].type==MATCH_STR &&
 						mct->match[i].l.s.len==s.len &&
 						memcmp(mct->match[i].l.s.s, s.s, s.len) == 0 ) ||
 					 ( mct->match[i].type==MATCH_RE &&
 					  regexec(mct->match[i].l.regex, s.s, 0, 0, 0) == 0)
 					){
 					if (likely(mct->jump[i])){
6ab93de3
 						/* make sure we cleanup first, in case run_actions()
 						   exits the script directly via longjmp() */
 						if (rv1){
 							rval_destroy(rv1);
 							rval_destroy(rv);
 							rval_cache_clean(&c1);
 						}else if (rv){
 							rval_destroy(rv);
 							rval_cache_clean(&c1);
 						}
cfeefb4a
 						ret=run_actions(h, mct->jump[i], msg);
 						h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
 													   returns passthrough */
c9586e18
 						goto skip;
cfeefb4a
 					}
 					goto match_cleanup;
 				}
 match_cond_def:
 			if (mct->def){
6ab93de3
 				/* make sure we cleanup first, in case run_actions()
 				   exits the script directly via longjmp() */
 				if (rv1){
 					rval_destroy(rv1);
 					rval_destroy(rv);
 					rval_cache_clean(&c1);
 				}else if (rv){
 					rval_destroy(rv);
 					rval_cache_clean(&c1);
 				}
cfeefb4a
 				ret=run_actions(h, mct->def, msg);
 				h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
 											   returns passthrough */
6ab93de3
 				break;
cfeefb4a
 			}
 match_cleanup:
 			if (rv1){
 				rval_destroy(rv1);
 				rval_destroy(rv);
 				rval_cache_clean(&c1);
 			}else if (rv){
 				rval_destroy(rv);
 				rval_cache_clean(&c1);
 			}
 			break;
dfda974c
 		case WHILE_T:
 			i=0;
 			flags=0;
 			rve=(struct rval_expr*)a->val[0].u.data;
 			ret=1;
0581efe0
 			while(!(flags & (BREAK_R_F|RETURN_R_F|EXIT_R_F)) &&
dfda974c
 					(rval_expr_eval_int(h, msg, &v, rve) == 0) && v){
d4396716
 				if (cfg_get(core, core_cfg, max_while_loops) > 0)
 					i++;
 
dfda974c
 				if (unlikely(i > cfg_get(core, core_cfg, max_while_loops))){
bb718138
 					LM_ERR("runaway while (%d, %d): more then %d loops\n", 
dfda974c
 								rve->fpos.s_line, rve->fpos.s_col,
 								cfg_get(core, core_cfg, max_while_loops));
 					ret=-1;
8c69c503
 					goto error;
dfda974c
 				}
 				if (likely(a->val[1].u.data)){
 					ret=run_actions(h, (struct action*)a->val[1].u.data, msg);
 					flags|=h->run_flags;
 					h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
0581efe0
 												   returns pass-through */
dfda974c
 				}
 			}
 			break;
3e8c3475
 		case FORCE_RPORT_T:
 			msg->msg_flags|=FL_FORCE_RPORT;
 			ret=1; /* continue processing */
 			break;
c37c22b4
 		case ADD_LOCAL_RPORT_T:
 			msg->msg_flags|=FL_ADD_LOCAL_RPORT;
 			ret=1; /* continue processing */
 			break;
f62c96d8
 		case UDP_MTU_TRY_PROTO_T:
 			msg->msg_flags|= (unsigned int)a->val[0].u.number & FL_MTU_FB_MASK;
 			ret=1; /* continue processing */
 			break;
6bfaa042
 		case SET_ADV_ADDR_T:
f141bc93
 			if (a->val[0].type!=STR_ST){
bb718138
 				LM_CRIT("bad set_advertised_address() type %d\n", a->val[0].type);
6bfaa042
 				ret=E_BUG;
8c69c503
 				goto error;
6bfaa042
 			}
f141bc93
 			msg->set_global_address=*((str*)a->val[0].u.data);
6bfaa042
 			ret=1; /* continue processing */
 			break;
 		case SET_ADV_PORT_T:
f141bc93
 			if (a->val[0].type!=STR_ST){
bb718138
 				LM_CRIT("bad set_advertised_port() type %d\n", a->val[0].type);
6bfaa042
 				ret=E_BUG;
8c69c503
 				goto error;
6bfaa042
 			}
f141bc93
 			msg->set_global_port=*((str*)a->val[0].u.data);
6bfaa042
 			ret=1; /* continue processing */
 			break;
59653eb8
 #ifdef USE_TCP
 		case FORCE_TCP_ALIAS_T:
 			if ( msg->rcv.proto==PROTO_TCP
 #ifdef USE_TLS
 					|| msg->rcv.proto==PROTO_TLS
 #endif
 			   ){
f141bc93
 
 				if (a->val[0].type==NOSUBTYPE)	port=msg->via1->port;
 				else if (a->val[0].type==NUMBER_ST) port=(int)a->val[0].u.number;
59653eb8
 				else{
bb718138
 					LM_CRIT("bad force_tcp_alias"
f141bc93
 							" port type %d\n", a->val[0].type);
59653eb8
 					ret=E_BUG;
8c69c503
 					goto error;
59653eb8
 				}
f141bc93
 
59653eb8
 				if (tcpconn_add_alias(msg->rcv.proto_reserved1, port,
 									msg->rcv.proto)!=0){
bb718138
 					LM_ERR("receive_msg: tcp alias failed\n");
59653eb8
 					ret=E_UNSPEC;
8c69c503
 					goto error;
59653eb8
 				}
 			}
 #endif
 			ret=1; /* continue processing */
 			break;
6cd48835
 		case FORCE_SEND_SOCKET_T:
f141bc93
 			if (a->val[0].type!=SOCKETINFO_ST){
bb718138
 				LM_CRIT("bad force_send_socket argument"
f141bc93
 						" type: %d\n", a->val[0].type);
6cd48835
 				ret=E_BUG;
8c69c503
 				goto error;
6cd48835
 			}
8fb1a212
 			set_force_socket(msg, (struct socket_info*)a->val[0].u.data);
6cd48835
 			ret=1; /* continue processing */
 			break;
74ce7043
 
bf79b581
 		case ADD_T:
 		case ASSIGN_T:
ab7f82d2
 			v=lval_assign(h, msg, (struct lvalue*)a->val[0].u.data,
 								  (struct rval_expr*)a->val[1].u.data);
a07e7447
 			if (likely(v>=0))
74ce7043
 				ret = 1;
ab7f82d2
 			else if (unlikely (v == EXPR_DROP)) /* hack to quit on DROP*/
 				ret=0;
 			else
 				ret=v;
74ce7043
 			break;
58cbf7f7
 		case SET_FWD_NO_CONNECT_T:
8cf5dde5
 			msg->fwd_send_flags.f|= SND_F_FORCE_CON_REUSE;
58cbf7f7
 			ret=1; /* continue processing */
 			break;
 		case SET_RPL_NO_CONNECT_T:
8cf5dde5
 			msg->rpl_send_flags.f|= SND_F_FORCE_CON_REUSE;
58cbf7f7
 			ret=1; /* continue processing */
 			break;
 		case SET_FWD_CLOSE_T:
8cf5dde5
 			msg->fwd_send_flags.f|= SND_F_CON_CLOSE;
58cbf7f7
 			ret=1; /* continue processing */
 			break;
 		case SET_RPL_CLOSE_T:
8cf5dde5
 			msg->rpl_send_flags.f|= SND_F_CON_CLOSE;
58cbf7f7
 			ret=1; /* continue processing */
 			break;
415f24a4
 		case CFG_SELECT_T:
 			if (a->val[0].type != CFG_GROUP_ST) {
 				BUG("unsupported parameter in CFG_SELECT_T: %d\n",
 						a->val[0].type);
 				ret=-1;
 				goto error;
 			}
 			switch(a->val[1].type) {
 				case NUMBER_ST:
 					v=(int)a->val[1].u.number;
 					break;
 				case RVE_ST:
 					if (rval_expr_eval_int(h, msg, &v, (struct rval_expr*)a->val[1].u.data) < 0) {
 						ret=-1;
 						goto error;
 					}
 					break;
 				default:
 					BUG("unsupported group id type in CFG_SELECT_T: %d\n",
 							a->val[1].type);
 					ret=-1;
 					goto error;
 			}
 			ret=(cfg_select((cfg_group_t*)a->val[0].u.data, v) == 0) ? 1 : -1;
 			break;
 		case CFG_RESET_T:
 			if (a->val[0].type != CFG_GROUP_ST) {
 				BUG("unsupported parameter in CFG_RESET_T: %d\n",
 						a->val[0].type);
 				ret=-1;
 				goto error;
 			}
 			ret=(cfg_reset((cfg_group_t*)a->val[0].u.data) == 0) ? 1 : -1;
 			break;
aa9fa735
 /*
4ac74c03
 		default:
bb718138
 			LM_CRIT("unknown type %d\n", a->type);
aa9fa735
 */
4ac74c03
 	}
955535a4
 skip:
4ac74c03
 	return ret;
f141bc93
 
7268726e
 error_uri:
bb718138
 	LM_ERR("set*: uri too long\n");
764df2b2
 	if (new_uri) pkg_free(new_uri);
8c69c503
 	LM_ERR("run action error at: %s:%d\n", (a->cfile)?a->cfile:"", a->cline);
7268726e
 	return E_UNSPEC;
7f858173
 error_fwd_uri:
855c2e68
 	/*free_uri(&uri); -- not needed anymore, using msg->parsed_uri*/
8c69c503
 error:
 	LM_ERR("run action error at: %s:%d\n", (a->cfile)?a->cfile:"", a->cline);
7f858173
 	return ret;
4ac74c03
 }
 
 
 
f20a56a2
 /* returns: 0, or 1 on success, <0 on error */
 /* (0 if drop or break encountered, 1 if not ) */
20fded1f
 int run_actions(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
4ac74c03
 {
 	struct action* t;
f8f678c3
 	int ret;
4bd1673d
 	struct sr_module *mod;
79cd4919
 	unsigned int ms = 0;
3e429f5c
 
f8f678c3
 	ret=E_UNSPEC;
20fded1f
 	h->rec_lev++;
d1c60718
 	if (unlikely(h->rec_lev>max_recursive_level)){
bb718138
 		LM_ERR("too many recursive routing table lookups (%d) giving up!\n", h->rec_lev);
3e429f5c
 		ret=E_UNSPEC;
 		goto error;
 	}
cf2ecfaa
 	if (unlikely(h->rec_lev==1)){
20fded1f
 		h->run_flags=0;
 		h->last_retcode=0;
68b7a898
 		_last_returned_code = h->last_retcode;
20fded1f
 #ifdef USE_LONGJMP
cf2ecfaa
 		if (unlikely(setjmp(h->jmp_env))){
20fded1f
 			h->rec_lev=0;
 			ret=h->last_retcode;
01dea124
 			goto end;
 		}
20fded1f
 #endif
01dea124
 	}
f141bc93
 
cf2ecfaa
 	if (unlikely(a==0)){
393fc062
 		LM_DBG("null action list (rec_level=%d)\n", h->rec_lev);
f9ac51fb
 		ret=1;
4ac74c03
 	}
 
 	for (t=a; t!=0; t=t->next){
930aba29
 		if(unlikely(cfg_get(core, core_cfg, latency_limit_action)>0))
 			ms = TICKS_TO_MS(get_ticks_raw());
4294b7bf
 		_cfg_crt_action = t;
20fded1f
 		ret=do_action(h, t, msg);
4294b7bf
 		_cfg_crt_action = 0;
930aba29
 		if(unlikely(cfg_get(core, core_cfg, latency_limit_action)>0)) {
 			ms = TICKS_TO_MS(get_ticks_raw()) - ms;
 			if(ms >= cfg_get(core, core_cfg, latency_limit_action)) {
 				LOG(cfg_get(core, core_cfg, latency_log),
 						"alert - action [%s (%d)]"
 						" cfg [%s:%d] took too long [%u ms]\n",
 						is_mod_func(t) ?
 							((cmd_export_common_t*)(t->val[0].u.data))->name
 							: "corefunc",
 						t->type, (t->cfile)?t->cfile:"", t->cline, ms);
 			}
 		}
955535a4
 		/* break, return or drop/exit stop execution of the current
 		   block */
cf2ecfaa
 		if (unlikely(h->run_flags & (BREAK_R_F|RETURN_R_F|EXIT_R_F))){
 			if (unlikely(h->run_flags & EXIT_R_F)) {
20fded1f
 				h->last_retcode=ret;
68b7a898
 				_last_returned_code = h->last_retcode;
cf2ecfaa
 #ifdef USE_LONGJMP
20fded1f
 				longjmp(h->jmp_env, ret);
 #endif
01dea124
 			}
 			break;
 		}
 		/* ignore error returns */
4ac74c03
 	}
f141bc93
 
20fded1f
 	h->rec_lev--;
01dea124
 end:
4bd1673d
 	/* process module onbreak handlers if present */
28a88287
 	if (unlikely(h->rec_lev==0 && ret==0 &&
 					!(h->run_flags & IGNORE_ON_BREAK_R_F)))
f141bc93
 		for (mod=modules;mod;mod=mod->next)
99cff510
 			if (unlikely(mod->exports.onbreak_f)) {
dee21fff
 				mod->exports.onbreak_f( msg );
4bd1673d
 			}
f20a56a2
 	return ret;
f141bc93
 
4ac74c03
 
 error:
20fded1f
 	h->rec_lev--;
4ac74c03
 	return ret;
 }
84025080
 
 
28a88287
 
 #ifdef USE_LONGJMP
 /** safe version of run_actions().
  * It always return (it doesn't longjmp on forced script end).
  * @returns 0, or 1 on success, <0 on error
  * (0 if drop or break encountered, 1 if not ) */
 int run_actions_safe(struct run_act_ctx* h, struct action* a,
 						struct sip_msg* msg)
 {
 	struct run_act_ctx ctx;
 	int ret;
 	int ign_on_break;
 	
 	/* start with a fresh action context */
 	init_run_actions_ctx(&ctx);
 	ctx.last_retcode = h->last_retcode;
 	ign_on_break = h->run_flags & IGNORE_ON_BREAK_R_F;
 	ctx.run_flags = h->run_flags | IGNORE_ON_BREAK_R_F;
 	ret = run_actions(&ctx, a, msg);
 	h->last_retcode = ctx.last_retcode;
 	h->run_flags = (ctx.run_flags & ~IGNORE_ON_BREAK_R_F) | ign_on_break;
 	return ret;
 }
 #endif /* USE_LONGJMP */
 
 
 
4ce1715d
 int run_top_route(struct action* a, sip_msg_t* msg, struct run_act_ctx *c)
84025080
 {
 	struct run_act_ctx ctx;
4ce1715d
 	struct run_act_ctx *p;
40a28527
 	int ret;
 	flag_t sfbk;
 
4ce1715d
 	p = (c)?c:&ctx;
40a28527
 	sfbk = getsflags();
84025080
 	setsflagsval(0);
 	reset_static_buffer();
4ce1715d
 	init_run_actions_ctx(p);
40a28527
 	ret = run_actions(p, a, msg);
 	setsflagsval(sfbk);
 	return ret;
84025080
 }