obsolete/cpl-c/cpl_run.c
7803bac4
 /*
  * $Id$
  *
95072403
  * Copyright (C) 2001-2003 FhG Fokus
7803bac4
  *
  * This file is part of ser, a free SIP server.
  *
  * ser is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version
  *
  * For a license to use the ser software under conditions
  * other than those described here, or to purchase support for this
  * software, please contact iptel.org by e-mail at the following addresses:
  *    info@iptel.org
  *
  * ser is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
9e1ff448
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
c71af56c
  *
  * History:
  * -------
  * 2003-01-23 : created (bogdan)
  * 2003-09-11 : build_lump_rpl() merged into add_lump_rpl() (bogdan)
f2bf348d
  * 2004-06-14 : all global variables merged into cpl_env and cpl_fct;
  *              append_branches param added to lookup node (bogdan)
95072403
  * 2004-06-14 : flag CPL_IS_STATEFUL is set now immediately after the 
f2bf348d
  *              transaction is created (bogdan)
c71af56c
 */
7803bac4
 
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
 #include <stdlib.h>
 
 #include "../../mem/mem.h"
 #include "../../mem/shm_mem.h"
 #include "../../str.h"
 #include "../../dprint.h"
 #include "../../parser/msg_parser.h"
 #include "../../data_lump_rpl.h"
7a7f1a7b
 #include "../../modules/tm/tm_load.h"
73c55030
 #include "../usrloc/usrloc.h"
7803bac4
 #include "CPL_tree.h"
 #include "loc_set.h"
9b4f27e3
 #include "cpl_utils.h"
92aaf946
 #include "cpl_nonsig.h"
e01c6479
 #include "cpl_sig.h"
f2bf348d
 #include "cpl_env.h"
7803bac4
 #include "cpl_run.h"
 
 
64b49597
 #define EO_SCRIPT            ((char*)0xffffffff)
 #define DEFAULT_ACTION       ((char*)0xfffffffe)
 #define CPL_SCRIPT_ERROR     ((char*)0xfffffffd)
 #define CPL_RUNTIME_ERROR    ((char*)0xfffffffc)
 #define CPL_TO_CONTINUE      ((char*)0xfffffffb)
a98061d8
 
7803bac4
 #define HDR_NOT_FOUND        ((char*)0xffffffff)
 #define UNDEF_CHAR           (0xff)
 
cf648820
 
 
7498d697
 #define check_overflow_by_ptr(_ptr_,_intr_,_error_) \
 	do {\
18179930
 		if ( (char*)(_ptr_)>(_intr_)->script.len+(_intr_)->script.s ) {\
 			LOG(L_ERR,"ERROR:cpl_c: overflow detected ip=%p ptr=%p in "\
43134ac6
 			"func. %s, line %d\n",(_intr_)->ip,_ptr_,__FILE__,__LINE__);\
7498d697
 			goto _error_; \
18179930
 		} \
7498d697
 	}while(0)
 
 #define check_overflow_by_offset(_len_,_intr_,_error_) \
 	do {\
 		if ( (char*)((_intr_)->ip+(_len_)) > \
18179930
 		(_intr_)->script.len+(_intr_)->script.s ) {\
 			LOG(L_ERR,"ERROR:cpl_c: overflow detected ip=%p offset=%d in "\
43134ac6
 			"func. %s, line %d\n",(_intr_)->ip,_len_,__FILE__,__LINE__);\
7498d697
 			goto _error_; \
18179930
 		} \
7498d697
 	}while(0)
 
a98061d8
 #define get_first_child(_node_) \
 	((NR_OF_KIDS(_node_)==0)?DEFAULT_ACTION:(_node_)+KID_OFFSET(_node_,0))
 
cf648820
 #define get_basic_attr(_p_,_code_,_n_,_intr_,_error_) \
 	do{\
 		check_overflow_by_ptr( (_p_)+BASIC_ATTR_SIZE, _intr_, _error_);\
 		_code_ = ntohs( *((unsigned short*)(_p_)) );\
 		_n_ =  ntohs( *((unsigned short*)((_p_)+2)) );\
 		(_p_) += 4;\
 	}while(0)
 
 #define get_str_attr(_p_,_s_,_len_,_intr_,_error_,_FIXUP_) \
 	do{\
 		if ( ((int)(_len_))-(_FIXUP_)<=0 ) {\
 			LOG(L_ERR,"ERROR:cpl_c:%s:%d: attribute is an empty string\n",\
43134ac6
 				__FILE__,__LINE__);\
cf648820
 			goto _error_; \
 		} else {\
 			check_overflow_by_ptr( (_p_)+(_len_), _intr_, _error_);\
 			_s_ = _p_;\
 			(_p_) += (_len_) + 1*(((_len_)&0x0001)==1);\
 			(_len_) -= (_FIXUP_);\
 		}\
 	}while(0)
 
7803bac4
 
 
a98061d8
 struct cpl_interpreter* new_cpl_interpreter( struct sip_msg *msg, str *script)
7803bac4
 {
 	struct cpl_interpreter *intr = 0;
 
 	intr = (struct cpl_interpreter*)shm_malloc(sizeof(struct cpl_interpreter));
 	if (!intr) {
 		LOG(L_ERR,"ERROR:build_cpl_interpreter: no more free memory!\n");
 		goto error;
 	}
 	memset( intr, 0, sizeof(struct cpl_interpreter));
 
7498d697
 	/* init the interpreter*/
7803bac4
 	intr->script.s = script->s;
 	intr->script.len = script->len;
 	intr->recv_time = time(0);
 	intr->ip = script->s;
 	intr->msg = msg;
 
95072403
 	/* check the beginning of the script */
7803bac4
 	if ( NODE_TYPE(intr->ip)!=CPL_NODE ) {
 		LOG(L_ERR,"ERROR:build_cpl_interpreter: first node is not CPL!!\n");
 		goto error;
 	}
 
 	return intr;
 error:
 	return 0;
 }
 
 
 
 void free_cpl_interpreter(struct cpl_interpreter *intr)
 {
 	if (intr) {
321214b2
 		empty_location_set( &(intr->loc_set) );
7803bac4
 		if (intr->script.s)
 			shm_free( intr->script.s);
321214b2
 		if (intr->user.s)
73c55030
 			shm_free(intr->user.s);
cfef5046
 		if (intr->flags&CPL_RURI_DUPLICATED)
 			shm_free(intr->ruri);
 		if (intr->flags&CPL_TO_DUPLICATED)
 			shm_free(intr->to);
 		if (intr->flags&CPL_FROM_DUPLICATED)
 			shm_free(intr->from);
 		if (intr->flags&CPL_SUBJECT_DUPLICATED)
 			shm_free(intr->subject);
 		if (intr->flags&CPL_ORGANIZATION_DUPLICATED)
 			shm_free(intr->organization);
 		if (intr->flags&CPL_USERAGENT_DUPLICATED)
 			shm_free(intr->user_agent);
 		if (intr->flags&CPL_ACCEPTLANG_DUPLICATED)
 			shm_free(intr->accept_language);
 		if (intr->flags&CPL_PRIORITY_DUPLICATED)
 			shm_free(intr->priority);
7803bac4
 		shm_free(intr);
 	}
 }
 
 
 
cf648820
 /* UPDATED + CHECKED
  */
64b49597
 static inline char *run_cpl_node( struct cpl_interpreter *intr )
7803bac4
 {
64b49597
 	char *kid;
a98061d8
 	unsigned char start;
7803bac4
 	int i;
 
a98061d8
 	start = (intr->flags&CPL_RUN_INCOMING)?INCOMING_NODE:OUTGOING_NODE;
 	/* look for the starting node (incoming or outgoing) */
7803bac4
 	for(i=0;i<NR_OF_KIDS(intr->ip);i++) {
 		kid= intr->ip + KID_OFFSET(intr->ip,i);
a98061d8
 		if ( NODE_TYPE(kid)==start ) {
 			return get_first_child(kid);
 		} else
 		if (NODE_TYPE(kid)==SUBACTION_NODE ||
 		NODE_TYPE(kid)==ANCILLARY_NODE ||
 		NODE_TYPE(kid)==INCOMING_NODE  ||
18179930
 		NODE_TYPE(kid)==OUTGOING_NODE ) {
7803bac4
 			continue;
 		} else {
cf648820
 			LOG(L_ERR,"ERROR:cpl_c:run_cpl_node: unknown child type (%d) "
7803bac4
 				"for CPL node!!\n",NODE_TYPE(kid));
a98061d8
 			return CPL_SCRIPT_ERROR;
7803bac4
 		}
 	}
 
a98061d8
 	DBG("DEBUG:cpl_c:run_cpl_node: CPL node has no %d subnode -> default\n",
 		start);
 	return DEFAULT_ACTION;
7803bac4
 }
 
 
 
cf648820
 /* UPDATED + CHECKED
  */
64b49597
 static inline char *run_lookup( struct cpl_interpreter *intr )
cfef5046
 {
73c55030
 	unsigned short attr_name;
 	unsigned short n;
 	unsigned char  clear;
 	char *p;
64b49597
 	char *kid;
 	char *failure_kid = 0;
73c55030
 	char *success_kid = 0;
 	char *notfound_kid = 0;
 	int  i;
 	time_t      tc;
 	urecord_t*  r;
 	ucontact_t* contact;
 
 	clear = NO_VAL;
 
 	/* check the params */
 	for( i=NR_OF_ATTR(intr->ip),p=ATTR_PTR(intr->ip) ; i>0 ; i-- ) {
 		get_basic_attr(p,attr_name,n,intr,script_error);
 		switch (attr_name) {
 			case CLEAR_ATTR:
 				if (n!=YES_VAL && n!=NO_VAL)
 					LOG(L_WARN,"WARNING:run_lookup: invalid value (%u) found"
 						" for param. CLEAR in LOOKUP node -> using "
 						"default (%u)!\n",n,clear);
 				else
 					clear = n;
 				break;
 			default:
 				LOG(L_ERR,"ERROR:run_lookup: unknown attribute (%d) in "
 					"LOOKUP node\n",attr_name);
 				goto script_error;
 		}
 	}
cfef5046
 
73c55030
 	/* check the kids */
cfef5046
 	for( i=0 ; i<NR_OF_KIDS(intr->ip) ; i++ ) {
 		kid = intr->ip + KID_OFFSET(intr->ip,i);
 		check_overflow_by_ptr( kid+SIMPLE_NODE_SIZE(kid), intr, script_error);
 		switch ( NODE_TYPE(kid) ) {
 			case SUCCESS_NODE :
73c55030
 				success_kid = kid;
 				break;
cfef5046
 			case NOTFOUND_NODE:
73c55030
 				notfound_kid = kid;
cfef5046
 				break;
 			case FAILURE_NODE:
 				failure_kid = kid;
 				break;
 			default:
 				LOG(L_ERR,"ERROR:run_lookup: unknown output node type"
 					" (%d) for LOOKUP node\n",NODE_TYPE(kid));
 				goto script_error;
 		}
 	}
 
73c55030
 	kid = failure_kid;
 
f2bf348d
 	if (cpl_env.lu_domain) {
73c55030
 		/* fetch user's contacts via usrloc */
 		tc = time(0);
f2bf348d
 		cpl_fct.ulb.lock_udomain( cpl_env.lu_domain );
 		i = cpl_fct.ulb.get_urecord( cpl_env.lu_domain, &intr->user, &r);
73c55030
 		if (i < 0) {
 			/* failure */
 			LOG(L_ERR, "ERROR:run_lookup: Error while querying usrloc\n");
f2bf348d
 			cpl_fct.ulb.unlock_udomain( cpl_env.lu_domain );
73c55030
 		} else if (i > 0) {
 			/* not found */
 			DBG("DBG:cpl-c:run_lookup: '%.*s' Not found in usrloc\n",
 				intr->user.len, intr->user.s);
f2bf348d
 			cpl_fct.ulb.unlock_udomain( cpl_env.lu_domain );
73c55030
 			kid = notfound_kid;
 		} else {
 			contact = r->contacts;
 			/* skip expired contacts */
74c07c51
 			while ( contact && contact->expires <= tc)
73c55030
 				contact = contact->next;
0c1465e7
 			/* any contacts left? */
73c55030
 			if (contact) {
 				/* clear loc set if requested */
 				if (clear)
 					empty_location_set( &(intr->loc_set) );
f2bf348d
 				/* start adding locations to set */
 				do {
 					DBG("DBG:cpl-c:run_lookup: adding <%.*s>q=%d\n",
 						contact->c.len,contact->c.s,(int)(10*contact->q));
 					if (add_location( &(intr->loc_set), &contact->c,
 					(int)(10*contact->q),
 					CPL_LOC_DUPL|((contact->flags & FL_NAT)*CPL_LOC_NATED)
 					)==-1) {
 						LOG(L_ERR,"ERROR:cpl-c:run_lookup: unable to add "
 							"location to set :-(\n");
 						cpl_fct.ulb.unlock_udomain( cpl_env.lu_domain );
 						goto runtime_error;
 					}
 					contact = contact->next;
 				}while( contact && cpl_env.lu_append_branches);
95072403
 				/* set the flag for modifying the location set */
73c55030
 				intr->flags |= CPL_LOC_SET_MODIFIED;
a8da2d5f
 				/* we found a valid contact */
 				kid = success_kid;
 			} else {
 				/* no valid contact found */
 				kid = notfound_kid;
73c55030
 			}
f2bf348d
 			cpl_fct.ulb.unlock_udomain( cpl_env.lu_domain );
73c55030
 		}
 
 	}
 
 	if (kid)
 		return get_first_child(kid);
cfef5046
 	return DEFAULT_ACTION;
73c55030
 runtime_error:
 	return CPL_RUNTIME_ERROR;
cfef5046
 script_error:
 	return CPL_SCRIPT_ERROR;
 }
 
 
 
cf648820
 /* UPDATED + CHECKED
  */
64b49597
 static inline char *run_location( struct cpl_interpreter *intr )
7803bac4
 {
cf648820
 	unsigned short attr_name;
 	unsigned short n;
64b49597
 	char  *p;
cf648820
 	unsigned char  prio;
 	unsigned char  clear;
7803bac4
 	str url;
 	int i;
 
 	clear = NO_VAL;
 	prio = 10;
 	url.s = (char*)UNDEF_CHAR;
9c225fbe
 	url.len = 0; /* fixes gcc 4.0 warning */
7803bac4
 
ef163c8f
 	/* sanity check */
 	if (NR_OF_KIDS(intr->ip)>1) {
 		LOG(L_ERR,"ERROR:run_location: LOCATION node suppose to have max "
 			"one child, not %d!\n",NR_OF_KIDS(intr->ip));
 		goto script_error;
 	}
 
7803bac4
 	for( i=NR_OF_ATTR(intr->ip),p=ATTR_PTR(intr->ip) ; i>0 ; i-- ) {
cf648820
 		get_basic_attr(p,attr_name,n,intr,script_error);
 		switch (attr_name) {
7803bac4
 			case URL_ATTR:
cf648820
 				url.len = n;
 				get_str_attr( p, url.s, url.len, intr, script_error,1);
7803bac4
 				break;
 			case PRIORITY_ATTR:
 				if ( n>10)
 					LOG(L_WARN,"WARNING:run_location: invalid value (%u) found"
 						" for param. PRIORITY in LOCATION node -> using "
 						"default (%u)!\n",n,prio);
 				else
 					prio = n;
 				break;
 			case CLEAR_ATTR:
 				if (n!=YES_VAL && n!=NO_VAL)
 					LOG(L_WARN,"WARNING:run_location: invalid value (%u) found"
 						" for param. CLEAR in LOCATION node -> using "
 						"default (%u)!\n",n,clear);
 				else
 					clear = n;
 				break;
 			default:
cf648820
 				LOG(L_ERR,"ERROR:run_location: unknown attribute (%d) in "
 					"LOCATION node\n",attr_name);
a98061d8
 				goto script_error;
7803bac4
 		}
 	}
 
 	if (url.s==(char*)UNDEF_CHAR) {
 		LOG(L_ERR,"ERROR:run_location: param. URL missing in LOCATION node\n");
a98061d8
 		goto script_error;
7803bac4
 	}
 
 	if (clear)
 		empty_location_set( &(intr->loc_set) );
9d1e8b98
 	if (add_location( &(intr->loc_set), &url, prio, 0/*no dup*/ )==-1) {
18179930
 		LOG(L_ERR,"ERROR:run_location: unable to add location to set :-(\n");
a98061d8
 		goto runtime_error;
18179930
 	}
95072403
 	/* set the flag for modifying the location set */
e01c6479
 	intr->flags |= CPL_LOC_SET_MODIFIED;
7803bac4
 
a98061d8
 	return get_first_child(intr->ip);
 runtime_error:
 	return CPL_RUNTIME_ERROR;
 script_error:
 	return CPL_SCRIPT_ERROR;
7803bac4
 }
 
 
 
cf648820
 /* UPDATED + CHECKED
  */
64b49597
 static inline char *run_remove_location( struct cpl_interpreter *intr )
7803bac4
 {
cf648820
 	unsigned short attr_name;
 	unsigned short n;
64b49597
 	char *p;
7803bac4
 	str url;
 	int i;
 
 	url.s = (char*)UNDEF_CHAR;
 
ef163c8f
 	/* sanity check */
 	if (NR_OF_KIDS(intr->ip)>1) {
 		LOG(L_ERR,"ERROR:cpl_c:run_remove_location: REMOVE_LOCATION node "
 			"suppose to have max one child, not %d!\n",
 			NR_OF_KIDS(intr->ip));
 		goto script_error;
 	}
 
e01c6479
 	/* dirty hack to speed things up in when loc set is already empty */
 	if (intr->loc_set==0)
 		goto done;
 
7803bac4
 	for( i=NR_OF_ATTR(intr->ip),p=ATTR_PTR(intr->ip) ; i>0 ; i-- ) {
cf648820
 		get_basic_attr(p,attr_name,n,intr,script_error);
 		switch (attr_name) {
7803bac4
 			case LOCATION_ATTR:
cf648820
 				url.len = n;
 				get_str_attr( p, url.s, url.len, intr, script_error,1);
7803bac4
 				break;
 			default:
a98061d8
 				LOG(L_ERR,"ERROR:run_remove_location: unknown attribute "
cf648820
 					"(%d) in REMOVE_LOCATION node\n",attr_name);
a98061d8
 				goto script_error;
7803bac4
 		}
 	}
 
cf648820
 	if (url.s==(char*)UNDEF_CHAR) {
e01c6479
 		DBG("DEBUG:run_remove_location: remove all locs from loc_set\n");
7803bac4
 		empty_location_set( &(intr->loc_set) );
 	} else {
 		remove_location( &(intr->loc_set), url.s, url.len );
 	}
95072403
 	/* set the flag for modifying the location set */
e01c6479
 	intr->flags |= CPL_LOC_SET_MODIFIED;
7803bac4
 
e01c6479
 done:
a98061d8
 	return get_first_child(intr->ip);
 script_error:
 	return CPL_SCRIPT_ERROR;
7803bac4
 }
 
 
 
cf648820
 /* UPDATED + CHECKED
  */
64b49597
 static inline char *run_sub( struct cpl_interpreter *intr )
f507eb0a
 {
64b49597
 	char  *p;
f507eb0a
 	unsigned short offset;
cf648820
 	unsigned short attr_name;
f507eb0a
 	int i;
 
ef163c8f
 	/* sanity check */
 	if (NR_OF_KIDS(intr->ip)!=0) {
 		LOG(L_ERR,"ERROR:cpl_c:run_sub: SUB node doesn't suppose to have any "
 			"sub-nodes. Found %d!\n",NR_OF_KIDS(intr->ip));
 		goto script_error;
 	}
 
f507eb0a
 	/* check the number of attr */
 	i = NR_OF_ATTR( intr->ip );
 	if (i!=1) {
 		LOG(L_ERR,"ERROR:cpl_c:run_sub: incorrect nr. of attr. %d (<>1) in "
 			"SUB node\n",i);
a98061d8
 		goto script_error;
f507eb0a
 	}
 	/* get attr's name */
 	p = ATTR_PTR(intr->ip);
cf648820
 	get_basic_attr( p, attr_name, offset, intr, script_error);
 	if (attr_name!=REF_ATTR) {
f507eb0a
 		LOG(L_ERR,"ERROR:cpl_c:run_sub: invalid attr. %d (expected %d)in "
cf648820
 			"SUB node\n", attr_name, REF_ATTR);
a98061d8
 		goto script_error;
f507eb0a
 	}
 	/* make the jump */
 	p = intr->ip - offset;
 	/* check the destination pointer -> are we still inside the buffer ;-) */
 	if (((char*)p)<intr->script.s) {
 		LOG(L_ERR,"ERROR:cpl_c:run_sub: jump offset lower than the script "
 			"beginning -> underflow!\n");
a98061d8
 		goto script_error;
f507eb0a
 	}
a98061d8
 	check_overflow_by_ptr( p+SIMPLE_NODE_SIZE(intr->ip), intr, script_error);
f507eb0a
 	/* check to see if we hit a subaction node */
 	if ( NODE_TYPE(p)!=SUBACTION_NODE ) {
 		LOG(L_ERR,"ERROR:cpl_c:run_sub: sub. jump hit a nonsubaction node!\n");
a98061d8
 		goto script_error;
f507eb0a
 	}
cf648820
 	if ( NR_OF_ATTR(p)!=0 ) {
95072403
 		LOG(L_ERR,"ERROR:cpl_c:run_sub: invalid subaction node reached "
cf648820
 		"(attrs=%d); expected (0)!\n",NR_OF_ATTR(p));
a98061d8
 		goto script_error;
f507eb0a
 	}
 
a98061d8
 	return get_first_child(p);
 script_error:
 	return CPL_SCRIPT_ERROR;
f507eb0a
 }
 
 
 
cf648820
 /* UPDATED + CHECKED
  */
64b49597
 static inline char *run_reject( struct cpl_interpreter *intr )
7803bac4
 {
cf648820
 	unsigned short attr_name;
7803bac4
 	unsigned short status;
cf648820
 	unsigned short n;
18179930
 	char *reason_s;
64b49597
 	char *p;
7803bac4
 	int i;
 
18179930
 	reason_s = (char*)UNDEF_CHAR;
7803bac4
 	status = UNDEF_CHAR;
 
 	/* sanity check */
 	if (NR_OF_KIDS(intr->ip)!=0) {
cf648820
 		LOG(L_ERR,"ERROR:cpl_c:run_reject: REJECT node doesn't suppose to have "
 			"any sub-nodes. Found %d!\n",NR_OF_KIDS(intr->ip));
a98061d8
 		goto script_error;
7803bac4
 	}
 
 	for( i=NR_OF_ATTR(intr->ip),p=ATTR_PTR(intr->ip) ; i>0 ; i-- ) {
cf648820
 		get_basic_attr( p, attr_name, n, intr, script_error);
 		switch (attr_name) {
7803bac4
 			case STATUS_ATTR:
cf648820
 				status = n;
7803bac4
 				break;
 			case REASON_ATTR:
cf648820
 				get_str_attr( p, reason_s, n, intr, script_error,1);
7803bac4
 				break;
 			default:
cf648820
 				LOG(L_ERR,"ERROR:cpl_c:run_reject: unknown attribute "
 					"(%d) in REJECT node\n",attr_name);
a98061d8
 				goto script_error;
7803bac4
 		}
 	}
 
cf648820
 	if (status==UNDEF_CHAR) {
 		LOG(L_ERR,"ERROR:cpl_c:run_reject: mandatory attribute STATUS "
 			"not found\n");
 		goto script_error;
 	}
ed32ece9
 	if (status<400 || status>=700) {
 		LOG(L_ERR,"ERROR:cpl_c:run_reject: bad attribute STATUS "
 			"(%d)\n",status);
 		goto script_error;
 	}
cf648820
 
18179930
 	if (reason_s==(char*)UNDEF_CHAR ) {
7803bac4
 		switch (status) {
 			case 486:
18179930
 				reason_s = "Busy Here";
7803bac4
 				break;
 			case 404:
18179930
 				reason_s = "Not Found";
7803bac4
 				break;
 			case 603:
18179930
 				reason_s = "Decline";
7803bac4
 				break;
 			case 500:
18179930
 				reason_s = "Internal Server Error";
cf648820
 				break;
7803bac4
 			default:
cf648820
 				reason_s = "Generic Error";
7803bac4
 		}
 	}
 
ed32ece9
 	/* if still stateless and FORCE_STATEFUL set -> build the transaction */
f2bf348d
 	if ( !(intr->flags&CPL_IS_STATEFUL) && intr->flags&CPL_FORCE_STATEFUL) {
 		i = cpl_fct.tmb.t_newtran( intr->msg );
ed32ece9
 		if (i<0) {
 			LOG(L_ERR,"ERROR:cpl-c:run_reject: failed to build new "
 				"transaction!\n");
 			goto runtime_error;
 		} else if (i==0) {
 			LOG(L_ERR,"ERROR:cpl-c:run_reject: processed INVITE is a "
 				"retransmission!\n");
028e598f
 			/* instead of generating an error is better just to break the
 			 * script by returning EO_SCRIPT */
 			return EO_SCRIPT;
ed32ece9
 		}
f2bf348d
 		intr->flags |= CPL_IS_STATEFUL;
ed32ece9
 	}
 
 	/* send the reply */
f2bf348d
 	if ( intr->flags&CPL_IS_STATEFUL ) {
ed32ece9
 		/* reply statefully */
f2bf348d
 		i = cpl_fct.tmb.t_reply(intr->msg, (int)status, reason_s );
ed32ece9
 	} else {
 		/* reply statelessly */
4bfe7ea8
 		i = cpl_fct.slb.zreply(intr->msg, status, reason_s );
ed32ece9
 	}
 
 	if ( i!=1 ) {
7803bac4
 		LOG(L_ERR,"ERROR:run_reject: unable to send reject reply!\n");
a98061d8
 		goto runtime_error;
7803bac4
 	}
 
 	return EO_SCRIPT;
a98061d8
 runtime_error:
 	return CPL_RUNTIME_ERROR;
 script_error:
 	return CPL_SCRIPT_ERROR;
7803bac4
 }
 
 
 
cf648820
 /* UPDATED + CHECKED
  */
64b49597
 static inline char *run_redirect( struct cpl_interpreter *intr )
7803bac4
 {
 	struct location *loc;
 	struct lump_rpl *lump;
cf648820
 	unsigned short attr_name;
 	unsigned short permanent;
 	unsigned short n;
64b49597
 	char *p;
7803bac4
 	str lump_str;
 	char *cp;
 	int i;
 
 	permanent = NO_VAL;
 
 	/* sanity check */
 	if (NR_OF_KIDS(intr->ip)!=0) {
cf648820
 		LOG(L_ERR,"ERROR:cpl-c:run_redirect: REDIRECT node doesn't suppose "
 			"to have any sub-nodes. Found %d!\n",NR_OF_KIDS(intr->ip));
a98061d8
 		goto script_error;
7803bac4
 	}
 
 	/* read the attributes of the REDIRECT node*/
 	for( i=NR_OF_ATTR(intr->ip),p=ATTR_PTR(intr->ip) ; i>0 ; i-- ) {
cf648820
 		get_basic_attr( p, attr_name, n, intr, script_error);
 		switch (attr_name) {
7803bac4
 			case PERMANENT_ATTR:
cf648820
 				if (n!=YES_VAL && n!=NO_VAL) {
 					LOG(L_ERR,"ERROR:cpl-c:run_redirect: unsupported value (%d)"
 						" in attribute PERMANENT for REDIRECT node",n);
a98061d8
 					goto script_error;
7803bac4
 				}
cf648820
 				permanent = n;
7803bac4
 				break;
 			default:
92aaf946
 				LOG(L_ERR,"ERROR:run_redirect: unknown attribute "
cf648820
 					"(%d) in REDIRECT node\n",attr_name);
a98061d8
 				goto script_error;
7803bac4
 		}
 	}
 
 	/* build the lump for Contact header */
 	lump_str.len = 9 /*"Contact: "*/;
 	for(loc=intr->loc_set;loc;loc=loc->next)
 		lump_str.len += 1/*"<"*/ + loc->addr.uri.len + 7/*">;q=x.x"*/ +
 			2*(loc->next!=0)/*" ,"*/;
 	lump_str.len += CRLF_LEN;
 
 	lump_str.s = pkg_malloc( lump_str.len );
 	if(!lump_str.s) {
cf648820
 		LOG(L_ERR,"ERROR:cpl-c:run_redirect: out of pkg memory!\n");
a98061d8
 		goto runtime_error;
7803bac4
 	}
 	cp = lump_str.s;
 	memcpy( cp , "Contact: " , 9);
 	cp += 9;
 	for(loc=intr->loc_set;loc;loc=loc->next) {
 		*(cp++) = '<';
 		memcpy(cp,loc->addr.uri.s,loc->addr.uri.len);
 		cp += loc->addr.uri.len;
 		memcpy(cp,">;q=",4);
 		cp += 4;
 		*(cp++) = (loc->addr.priority!=10)?'0':'1';
 		*(cp++) = '.';
 		*(cp++) = '0'+(loc->addr.priority%10);
 		if (loc->next) {
 			*(cp++) = ' ';
 			*(cp++) = ',';
 		}
 	}
 	memcpy(cp,CRLF,CRLF_LEN);
 
ed32ece9
 	/* if still stateless and FORCE_STATEFUL set -> build the transaction */
f2bf348d
 	if ( !(intr->flags&CPL_IS_STATEFUL) && intr->flags&CPL_FORCE_STATEFUL) {
 		i = cpl_fct.tmb.t_newtran( intr->msg );
ed32ece9
 		if (i<0) {
 			LOG(L_ERR,"ERROR:cpl-c:run_redirect: failed to build new "
 				"transaction!\n");
028e598f
 			pkg_free( lump_str.s );
ed32ece9
 			goto runtime_error;
 		} else if (i==0) {
 			LOG(L_ERR,"ERROR:cpl-c:run_redirect: processed INVITE is a "
 				"retransmission!\n");
028e598f
 			/* instead of generating an error is better just to break the
 			 * script by returning EO_SCRIPT */
 			pkg_free( lump_str.s );
 			return EO_SCRIPT;
ed32ece9
 		}
f2bf348d
 		intr->flags |= CPL_IS_STATEFUL;
ed32ece9
 	}
 
7803bac4
 	/* add the lump to the reply */
c71af56c
 	lump = add_lump_rpl( intr->msg, lump_str.s , lump_str.len , LUMP_RPL_HDR);
7803bac4
 	if(!lump) {
c71af56c
 		LOG(L_ERR,"ERROR:cpl-c:run_redirect: unable to add lump_rpl! \n");
7803bac4
 		pkg_free( lump_str.s );
a98061d8
 		goto runtime_error;
7803bac4
 	}
 
 	/* send the reply */
f2bf348d
 	if ( intr->flags&CPL_IS_STATEFUL ) {
ed32ece9
 		/* reply statefully */
 		if (permanent)
f2bf348d
 			i = cpl_fct.tmb.t_reply( intr->msg, (int)301, "Moved permanently");
ed32ece9
 		else
f2bf348d
 			i = cpl_fct.tmb.t_reply( intr->msg, (int)302, "Moved temporarily");
ed32ece9
 	} else {
 		/* reply statelessly */
 		if (permanent)
4bfe7ea8
 			i = cpl_fct.slb.zreply( intr->msg, 301, "Moved permanently");
ed32ece9
 		else
4bfe7ea8
 			i = cpl_fct.slb.zreply( intr->msg, 302, "Moved temporarily");
ed32ece9
 	}
c372be49
 
c71af56c
 	/* msg which I'm working on can be in private memory or is a clone into
c372be49
 	 * shared memory (if I'm after a failed proxy); So, it's better to removed
95072403
 	 * by myself the lump that I added previously */
c372be49
 	unlink_lump_rpl( intr->msg, lump);
 	free_lump_rpl( lump );
 
d0431ebf
 	if (i!=1) {
ed32ece9
 		LOG(L_ERR,"ERROR:cpl-c:run_redirect: unable to send "
 			"redirect reply!\n");
a98061d8
 		goto runtime_error;
7803bac4
 	}
 
 	return EO_SCRIPT;
a98061d8
 runtime_error:
 	return CPL_RUNTIME_ERROR;
 script_error:
 	return CPL_SCRIPT_ERROR;
7803bac4
 }
 
 
 
cf648820
 /* UPDATED + CHECKED
  */
64b49597
 static inline char *run_log( struct cpl_interpreter *intr )
92aaf946
 {
64b49597
 	char  *p;
cf648820
 	unsigned short attr_name;
 	unsigned short n;
03f6db11
 	str name    = STR_NULL;
 	str comment = STR_NULL;
a98061d8
 	str user;
92aaf946
 	int i;
 
 	/* sanity check */
 	if (NR_OF_KIDS(intr->ip)>1) {
cf648820
 		LOG(L_ERR,"ERROR:cpl_c:run_log: LOG node suppose to have max one child"
 			", not %d!\n",NR_OF_KIDS(intr->ip));
a98061d8
 		goto script_error;
92aaf946
 	}
 
95072403
 	/* is logging enabled? */
f2bf348d
 	if ( cpl_env.log_dir==0 )
92aaf946
 		goto done;
 
 	/* read the attributes of the LOG node*/
cf648820
 	p = ATTR_PTR(intr->ip);
 	for( i=NR_OF_ATTR(intr->ip); i>0 ; i-- ) {
 		get_basic_attr( p, attr_name, n, intr, script_error);
 		switch (attr_name) {
92aaf946
 			case NAME_ATTR:
cf648820
 				get_str_attr( p, name.s, n, intr, script_error,1);
 				name.len = n;
92aaf946
 				break;
 			case COMMENT_ATTR:
cf648820
 				get_str_attr( p, comment.s, n, intr, script_error,1);
 				comment.len = n;
92aaf946
 				break;
 			default:
cf648820
 				LOG(L_ERR,"ERROR:cpl_c:run_log: unknown attribute "
 					"(%d) in LOG node\n",attr_name);
a98061d8
 				goto script_error;
92aaf946
 		}
 	}
 
a98061d8
 	if (comment.len==0) {
cf648820
 		LOG(L_NOTICE,"NOTICE:cpl_c:run_log: LOG node has no comment attr -> "
a98061d8
 			"skipping\n");
92aaf946
 		goto done;
 	}
 
cf648820
 	user.len = intr->user.len + name.len + comment.len;
a98061d8
 	/* duplicate the attrs in shm memory */
cf648820
 	user.s = p = (char*)shm_malloc( user.len );
 	if (!user.s) {
92aaf946
 		LOG(L_ERR,"ERROR:cpl_c:run_log: no more shm memory!\n");
a98061d8
 		goto runtime_error;
92aaf946
 	}
cf648820
 	/* copy the user name */
 	memcpy( p, intr->user.s, intr->user.len);
a98061d8
 	user.len = intr->user.len;
cf648820
 	p += intr->user.len;
 	/* copy the log name */
 	if (name.len) {
 		memcpy( p, name.s, name.len );
 		name.s = p;
 		p += name.len;
 	}
 	/* copy the comment */
 	memcpy( p, comment.s, comment.len);
ed32ece9
 	comment.s = p;
92aaf946
 
a98061d8
 	/* send the command */
 	write_cpl_cmd( CPL_LOG_CMD, &user, &name, &comment );
 
 done:
 	return get_first_child(intr->ip);
 runtime_error:
 	return CPL_RUNTIME_ERROR;
 script_error:
 	return CPL_SCRIPT_ERROR;
 }
 
 
 
cf648820
 /* UPDATED + CHECKED
  */
64b49597
 static inline char *run_mail( struct cpl_interpreter *intr )
a98061d8
 {
cf648820
 	unsigned short attr_name;
 	unsigned short n;
64b49597
 	char  *p;
03f6db11
 	str subject = STR_NULL;
 	str body    = STR_NULL;
 	str to      = STR_NULL;
a98061d8
 	int i;
 
 	/* sanity check */
 	if (NR_OF_KIDS(intr->ip)>1) {
 		LOG(L_ERR,"ERROR:cpl_c:run_mail: MAIL node suppose to have max one"
 			" child, not %d!\n",NR_OF_KIDS(intr->ip));
 		goto script_error;
 	}
 
 	/* read the attributes of the MAIL node*/
 	for( i=NR_OF_ATTR(intr->ip),p=ATTR_PTR(intr->ip) ; i>0 ; i-- ) {
cf648820
 		get_basic_attr(p, attr_name, n, intr, script_error);
 		switch (attr_name) {
a98061d8
 			case TO_ATTR:
cf648820
 				get_str_attr(p, to.s, n, intr, script_error,0);
 				to.len = n;
a98061d8
 				break;
 			case SUBJECT_ATTR:
cf648820
 				get_str_attr(p, subject.s, n, intr, script_error,0);
 				subject.len = n;
a98061d8
 				break;
 			case BODY_ATTR:
cf648820
 				get_str_attr(p, body.s, n, intr, script_error,0);
 				body.len = n;
a98061d8
 				break;
 			default:
 				LOG(L_ERR,"ERROR:run_mail: unknown attribute "
cf648820
 					"(%d) in MAIL node\n",attr_name);
a98061d8
 				goto script_error;
 		}
 	}
 
 	if (to.len==0) {
 		LOG(L_ERR,"ERROR:cpl_c:run_mail: email has an empty TO hdr!\n");
 		goto script_error;
 	}
cf648820
 	if (body.len==0 && subject.len==0) {
 		LOG(L_WARN,"WARNING:cpl_c:run_mail: I refuse to send email with no "
 			"body and no subject -> skipping...\n");
a98061d8
 		goto done;
 	}
 
 	/* duplicate the attrs in shm memory */
cf648820
 	p = (char*)shm_malloc( to.len + subject.len + body.len );
 	if (!p) {
a98061d8
 		LOG(L_ERR,"ERROR:cpl_c:run_mail: no more shm memory!\n");
 		goto runtime_error;
 	}
 	/* copy the TO */
 	memcpy( p, to.s, to.len );
 	to.s = p;
 	p += to.len;
 	/* copy the subject */
cf648820
 	if (subject.len) {
 		memcpy( p, subject.s, subject.len );
 		subject.s = p;
 		p += subject.len;
 	}
a98061d8
 	/* copy the body */
cf648820
 	if (body.len) {
 		memcpy( p, body.s, body.len );
 		body.s = p;
 		p += body.len;
 	}
92aaf946
 
 	/* send the command */
a98061d8
 	write_cpl_cmd( CPL_MAIL_CMD, &to, &subject, &body);
92aaf946
 
 done:
a98061d8
 	return get_first_child(intr->ip);
 runtime_error:
 	return CPL_RUNTIME_ERROR;
 script_error:
 	return CPL_SCRIPT_ERROR;
92aaf946
 }
 
 
7803bac4
 
e01c6479
 static inline int run_default( struct cpl_interpreter *intr )
 {
25902434
 	if (!(intr->flags&CPL_PROXY_DONE)) {
95072403
 		/* no signaling operations */
25902434
 		if ( !(intr->flags&CPL_LOC_SET_MODIFIED) ) {
e01c6479
 			/*  no location modifications */
 			if (intr->loc_set==0 ) {
95072403
 				/* case 1 : no location modifications or signaling operations
e01c6479
 				 * performed, location set empty ->
 				 * Look up the user's location through whatever mechanism the
 				 * server would use if no CPL script were in effect */
 				return SCRIPT_DEFAULT;
 			} else {
95072403
 				/* case 2 : no location modifications or signaling operations
e01c6479
 				 * performed, location set non-empty: (This can only happen 
 				 * for outgoing calls.) ->
cf1f03bc
 				 * Proxy the call to the address in the location set.
 				 * With other words, let ser to continue processing the
 				 * request as nothing happened */
d8c20bbf
 				return SCRIPT_DEFAULT;
e01c6479
 			}
 		} else {
95072403
 			/* case 3 : location modifications performed, no signaling 
e01c6479
 			 * operations ->
 			 * Proxy the call to the addresses in the location set */
f2bf348d
 			if (!cpl_proxy_to_loc_set(intr->msg,&(intr->loc_set),intr->flags))
cfef5046
 				return SCRIPT_END;
 			return SCRIPT_RUN_ERROR;
e01c6479
 		}
 	} else {
23ae6d47
 		/* case 4 : proxy operation previously taken -> return whatever the 
 		 * "best" response is of all accumulated responses to the call to this
95072403
 		 * point, according to the rules of the underlying signaling
23ae6d47
 		 * protocol. */
 		/* we will let ser to choose and forward one of the replies -> for this
95072403
 		 * nothing must be done */
23ae6d47
 		return SCRIPT_END;
e01c6479
 	}
69e88f9c
 	/*return SCRIPT_RUN_ERROR;*/
e01c6479
 }
 
 
7803bac4
 
23ae6d47
 /* include all inline functions for processing the switches */
 #include "cpl_switches.h"
 /* include inline function for running proxy node */
 #include "cpl_proxy.h"
 
 
 
20476545
 int cpl_run_script( struct cpl_interpreter *intr )
7803bac4
 {
1c14d29e
 	char *new_ip;
 
7803bac4
 	do {
7498d697
 		check_overflow_by_offset( SIMPLE_NODE_SIZE(intr->ip), intr, error);
7803bac4
 		switch ( NODE_TYPE(intr->ip) ) {
 			case CPL_NODE:
20476545
 				DBG("DEBUG:cpl_run_script: processing CPL node \n");
1c14d29e
 				new_ip = run_cpl_node( intr ); /*UPDATED&TESTED*/
7803bac4
 				break;
 			case ADDRESS_SWITCH_NODE:
20476545
 				DBG("DEBUG:cpl_run_script: processing address-switch node\n");
1c14d29e
 				new_ip = run_address_switch( intr ); /*UPDATED&TESTED*/
7803bac4
 				break;
9b4f27e3
 			case STRING_SWITCH_NODE:
20476545
 				DBG("DEBUG:cpl_run_script: processing string-switch node\n");
1c14d29e
 				new_ip = run_string_switch( intr ); /*UPDATED&TESTED*/
9b4f27e3
 				break;
812e30e7
 			case PRIORITY_SWITCH_NODE:
20476545
 				DBG("DEBUG:cpl_run_script: processing priority-switch node\n");
1c14d29e
 				new_ip = run_priority_switch( intr ); /*UPDATED&TESTED*/
812e30e7
 				break;
18179930
 			case TIME_SWITCH_NODE:
20476545
 				DBG("DEBUG:cpl_run_script: processing time-switch node\n");
1c14d29e
 				new_ip = run_time_switch( intr ); /*UPDATED&TESTED*/
18179930
 				break;
ef163c8f
 			case LANGUAGE_SWITCH_NODE:
20476545
 				DBG("DEBUG:cpl_run_script: processing language-switch node\n");
1c14d29e
 				new_ip = run_language_switch( intr ); /*UPDATED&TESTED*/
ef163c8f
 				break;
cfef5046
 			case LOOKUP_NODE:
20476545
 				DBG("DEBUG:cpl_run_script: processing lookup node\n");
1c14d29e
 				new_ip = run_lookup( intr ); /*UPDATED&TESTED*/
cfef5046
 				break;
7803bac4
 			case LOCATION_NODE:
20476545
 				DBG("DEBUG:cpl_run_script: processing location node\n");
1c14d29e
 				new_ip = run_location( intr ); /*UPDATED&TESTED*/
7803bac4
 				break;
 			case REMOVE_LOCATION_NODE:
20476545
 				DBG("DEBUG:cpl_run_script: processing remove_location node\n");
1c14d29e
 				new_ip = run_remove_location( intr ); /*UPDATED&TESTED*/
7803bac4
 				break;
31204084
 			case PROXY_NODE:
20476545
 				DBG("DEBUG:cpl_run_script: processing proxy node\n");
1c14d29e
 				new_ip = run_proxy( intr );/*UPDATED&TESTED*/
31204084
 				break;
7803bac4
 			case REJECT_NODE:
20476545
 				DBG("DEBUG:cpl_run_script: processing reject node\n");
1c14d29e
 				new_ip = run_reject( intr ); /*UPDATED&TESTED*/
7803bac4
 				break;
 			case REDIRECT_NODE:
20476545
 				DBG("DEBUG:cpl_run_script: processing redirect node\n");
1c14d29e
 				new_ip = run_redirect( intr ); /*UPDATED&TESTED*/
7803bac4
 				break;
92aaf946
 			case LOG_NODE:
20476545
 				DBG("DEBUG:cpl_run_script: processing log node\n");
1c14d29e
 				new_ip = run_log( intr ); /*UPDATED&TESTED*/
92aaf946
 				break;
a98061d8
 			case MAIL_NODE:
20476545
 				DBG("DEBUG:cpl_run_script: processing mail node\n");
1c14d29e
 				new_ip = run_mail( intr ); /*UPDATED&TESTED*/
a98061d8
 				break;
f507eb0a
 			case SUB_NODE:
20476545
 				DBG("DEBUG:cpl_run_script: processing sub node\n");
1c14d29e
 				new_ip = run_sub( intr ); /*UPDATED&TESTED*/
f507eb0a
 				break;
7803bac4
 			default:
20476545
 				LOG(L_ERR,"ERROR:cpl_run_script: unknown type node (%d)\n",
7803bac4
 					NODE_TYPE(intr->ip));
 				goto error;
 		}
a98061d8
 
1c14d29e
 		if (new_ip==CPL_RUNTIME_ERROR) {
20476545
 			LOG(L_ERR,"ERROR:cpl_c:cpl_run_script: runtime error\n");
e01c6479
 			return SCRIPT_RUN_ERROR;
1c14d29e
 		} else if (new_ip==CPL_SCRIPT_ERROR) {
20476545
 			LOG(L_ERR,"ERROR:cpl_c:cpl_run_script: script error\n");
e01c6479
 			return SCRIPT_FORMAT_ERROR;
1c14d29e
 		} else if (new_ip==DEFAULT_ACTION) {
20476545
 			DBG("DEBUG:cpl_c:cpl_run_script: running default action\n");
e01c6479
 			return run_default(intr);
1c14d29e
 		} else if (new_ip==EO_SCRIPT) {
20476545
 			DBG("DEBUG:cpl_c:cpl_run_script: script interpretation done!\n");
a98061d8
 			return SCRIPT_END;
1c14d29e
 		} else if (new_ip==CPL_TO_CONTINUE) {
20476545
 			DBG("DEBUG:cpl_c:cpl_run_script: done for the moment; waiting "
cfef5046
 				"after signaling!\n");
 			return SCRIPT_TO_BE_CONTINUED;
a98061d8
 		}
1c14d29e
 		/* move to the new instruction */
 		intr->ip = new_ip;
a98061d8
 	}while(1);
7803bac4
 
 error:
e01c6479
 	return SCRIPT_FORMAT_ERROR;
7803bac4
 }