modules_s/cpl-c/cpl_switches.h
f507eb0a
 /*
  * $Id$
  *
95072403
  * Copyright (C) 2001-2003 FhG Fokus
f507eb0a
  *
  * 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 
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  * History:
  * -------
  * 2003-06-27: file created (bogdan)
  */
 
 #include "cpl_time.h"
 #include "../../parser/parse_from.h"
75b94f40
 #include "../../parser/parse_uri.h"
f507eb0a
 
 
 
cf648820
 /* UPDATED + CHECKED
  */
64b49597
 static inline char *run_address_switch( struct cpl_interpreter *intr )
f507eb0a
 {
03f6db11
 	static str def_port_str = STR_STATIC_INIT("5060");
cf648820
 	unsigned short field, subfield;
64b49597
 	char  *p;
 	char  *kid;
 	unsigned short  attr_name;
cf648820
 	unsigned short n;
f507eb0a
 	int i;
cf648820
 	int k;
f507eb0a
 	str cpl_val;
 	str *msg_val;
 	str *uri;
 	struct sip_uri parsed_uri;
 
 	field = subfield = UNDEF_CHAR;
 	msg_val = 0;
 
 	p=ATTR_PTR(intr->ip);
 	/* parse the attributes */
cf648820
 	for( i=NR_OF_ATTR(intr->ip) ; i>0 ; i-- ) {
 		get_basic_attr( p, attr_name, n, intr, script_error);
 		switch (attr_name) {
 			case FIELD_ATTR:
 				if (field!=UNDEF_CHAR) {
95072403
 					LOG(L_ERR,"ERROR:cpl-c:run_address_switch: multiple FIELD "
cf648820
 						"attrs found\n");
 					goto script_error;
 				}
 				field = n;
 				break;
 			case SUBFIELD_ATTR:
 				if (subfield!=UNDEF_CHAR) {
95072403
 					LOG(L_ERR,"ERROR:cpl-c:run_address_switch: multiple SUBFIELD"
cf648820
 						" attrs found\n");
 					goto script_error;
 				}
 				subfield = n; break;
 			default:
 				LOG(L_ERR,"ERROR:cpl_c:run_address_switch: unknown attribute "
 					"(%d) in ADDRESS_SWITCH node\n",*p);
 				goto script_error;
f507eb0a
 		}
 	}
 
 	if (field==UNDEF_CHAR) {
a98061d8
 		LOG(L_ERR,"ERROR:cpl_c:run_address_switch: mandatory param FIELD "
 			"no found\n");
 		goto script_error;
f507eb0a
 	}
 
 	/* test the condition from all the sub-nodes */
 	for( i=0 ; i<NR_OF_KIDS(intr->ip) ; i++ ) {
 		kid = intr->ip + KID_OFFSET(intr->ip,i);
a98061d8
 		check_overflow_by_ptr( kid+SIMPLE_NODE_SIZE(kid), intr, script_error);
f507eb0a
 		switch ( NODE_TYPE(kid) ) {
31204084
 			case NOT_PRESENT_NODE:
 				DBG("DEBUG:run_address_switch: NOT_PRESENT node found ->"
 					"skipping (useless in this case)\n");
 				break;
f507eb0a
 			case OTHERWISE_NODE :
31204084
 				if (i!=NR_OF_KIDS(intr->ip)-1) {
 					LOG(L_ERR,"ERROR:run_address_switch: OTHERWISE node "
 						"not found as the last sub-node!\n");
 					goto script_error;
 				}
f507eb0a
 				DBG("DEBUG:run_address_switch: matching on OTHERWISE node\n");
a98061d8
 				return get_first_child(kid);
f507eb0a
 			case ADDRESS_NODE :
 				/* check the number of attributes */
 				if (NR_OF_ATTR(kid)!=1) {
95072403
 					LOG(L_ERR,"ERROR:run_address_switch: incorrect nr of attrs "
d7d1e3ae
 						"(%d) in ADDRESS node\n",NR_OF_ATTR(kid));
a98061d8
 					goto script_error;
f507eb0a
 				}
 				/* get the attribute name */
 				p = ATTR_PTR(kid);
cf648820
 				get_basic_attr( p, attr_name, cpl_val.len, intr, script_error);
f507eb0a
 				if (attr_name!=IS_ATTR && attr_name!=CONTAINS_ATTR &&
 				attr_name!=SUBDOMAIN_OF_ATTR) {
95072403
 					LOG(L_ERR,"ERROR:run_address_switch: unknown attribute "
d7d1e3ae
 						"(%d) in ADDRESS node\n",attr_name);
a98061d8
 					goto script_error;
f507eb0a
 				}
 				/* get attribute value */
cf648820
 				get_str_attr( p, cpl_val.s, cpl_val.len, intr, script_error,1);
f507eb0a
 				DBG("DEBUG:run_address_switch: testing ADDRESS branch "
 					" attr_name=%d attr_val=[%.*s](%d)..\n",
 					attr_name,cpl_val.len,cpl_val.s,cpl_val.len);
 				/* extract the needed value from the message */
 				if (!msg_val) {
 					switch (field) {
 						case ORIGIN_VAL: /* FROM */
 							if (!intr->from) {
 								/* get the header */
 								if (parse_from_header( intr->msg )==-1)
a98061d8
 									goto runtime_error;
f507eb0a
 								intr->from = &(get_from(intr->msg)->uri);
 							}
 							uri = intr->from;
 						break;
 						case DESTINATION_VAL: /* RURI */
a98061d8
 							if (!intr->ruri)
f507eb0a
 								intr->ruri = GET_RURI( intr->msg );
 							uri = intr->ruri;
 							break;
 						case ORIGINAL_DESTINATION_VAL: /* TO */
 							if (!intr->to) {
 								/* get and parse the header */
 								if (!intr->msg->to &&
0bfbf63f
 								(parse_headers(intr->msg,HDR_TO_F,0)==-1 ||
f507eb0a
 								!intr->msg->to)) {
 									LOG(L_ERR,"ERROR:run_address_switch: bad "
 										"msg or missing TO header\n");
a98061d8
 									goto runtime_error;
f507eb0a
 								}
 								intr->to = &(get_to(intr->msg)->uri);
 							}
 							uri = intr->to;
 							break;
 						default:
 							LOG(L_ERR,"ERROR:run_address_switch: unknown "
 								"attribute (%d) in ADDRESS node\n",field);
a98061d8
 							goto script_error;
f507eb0a
 					}
 					DBG("DEBUG:run_address_switch: extracted uri is <%.*s>\n",
 						uri->len, uri->s);
 					switch (subfield) {
 						case UNDEF_CHAR:
 							msg_val = uri;
 							break;
 						case USER_VAL:
 							if (parse_uri( uri->s, uri->len, &parsed_uri)<0)
a98061d8
 								goto runtime_error;
f507eb0a
 							msg_val = &(parsed_uri.user);
 							break;
 						case HOST_VAL:
 							if (parse_uri( uri->s, uri->len, &parsed_uri)<0)
a98061d8
 								goto runtime_error;
f507eb0a
 							msg_val = &(parsed_uri.host);
 							break;
 						case PORT_VAL:
 							if (parse_uri( uri->s, uri->len, &parsed_uri)<0)
a98061d8
 								goto runtime_error;
cf648820
 							if (parsed_uri.port.len!=0)
 								msg_val = &(parsed_uri.port);
 							else
 								msg_val = &def_port_str;
f507eb0a
 							break;
 						case TEL_VAL:
 							if (parse_uri( uri->s, uri->len, &parsed_uri)<0)
a98061d8
 								goto runtime_error;
cf648820
 							if (parsed_uri.user_param_val.len==5 &&
 							memcmp(parsed_uri.user_param_val.s,"phone",5)==0)
f507eb0a
 								msg_val = &(parsed_uri.user);
 							break;
 						case ADDRESS_TYPE_VAL:
 						case DISPLAY_VAL:
 						default:
 							LOG(L_ERR,"ERROR:run_address_switch: unsupported "
 								"value attribute (%d) in ADDRESS node\n",
 								subfield);
a98061d8
 							goto script_error;
f507eb0a
 					}
 					DBG("DEBUG:run_address_switch: extracted val. is <%.*s>\n",
cf648820
 						(msg_val==0)?0:msg_val->len, (msg_val==0)?0:msg_val->s);
f507eb0a
 				}
 				/* does the value from script match the one from message? */
 				switch (attr_name) {
 					case IS_ATTR:
 						if ( (!msg_val && !cpl_val.s) ||
 						(msg_val && msg_val->len==cpl_val.len &&
 						strncasecmp(msg_val->s,cpl_val.s,cpl_val.len)==0)) {
 							DBG("DEBUG:run_address_switch: matching on "
 								"ADDRESS node (IS)\n");
a98061d8
 							return get_first_child(kid);
f507eb0a
 						}
 						break;
 					case CONTAINS_ATTR:
 						if (subfield!=DISPLAY_VAL) {
95072403
 							LOG(L_WARN,"WARNING:run_address_switch: operator "
 							"CONTAINS applies only to DISPLAY -> ignored\n");
f507eb0a
 						} else {
 							if ( msg_val && cpl_val.len<=msg_val->len &&
 							strcasestr_str(msg_val, &cpl_val)!=0 ) {
 								DBG("DEBUG:run_address_switch: matching on "
 									"ADDRESS node (CONTAINS)\n");
a98061d8
 								return get_first_child(kid);
f507eb0a
 							}
 						}
 						break;
 					case SUBDOMAIN_OF_ATTR:
cf648820
 						switch (subfield) {
 							case HOST_VAL:
 								k = msg_val->len - cpl_val.len;
 								if (k>=0 && (k==0 || msg_val->s[k-1]=='.') &&
 								!strncasecmp(cpl_val.s,msg_val->s+k,cpl_val.len)
 								) {
 									DBG("DEBUG:run_address_switch: matching on "
 										"ADDRESS node (SUBDOMAIN_OF)\n");
 									return get_first_child(kid);
 								}
 								break;
 							case TEL_VAL:
 								if (msg_val==0) break;
 								if (msg_val->len>=cpl_val.len && !strncasecmp(
 								cpl_val.s,msg_val->s,cpl_val.len)) {
 									DBG("DEBUG:run_address_switch: matching on "
 										"ADDRESS node (SUBDOMAIN_OF)\n");
 									return get_first_child(kid);
 								}
 								break;
 							default:
95072403
 								LOG(L_WARN,"WARNING:run_address_switch: operator"
 									" SUBDOMAIN_OF applies only to HOST or TEL "
cf648820
 									"-> ignored\n");
f507eb0a
 						}
 						break;
 				}
 				break;
 			default:
 				LOG(L_ERR,"ERROR:run_address_switch: unknown output node type "
 					"(%d) for ADDRESS_SWITCH node\n",NODE_TYPE(kid));
ef163c8f
 				goto script_error;
f507eb0a
 		}
 	}
 
95072403
 	/* none of the branches of ADDRESS_SWITCH matched -> go for default */
a98061d8
 	return DEFAULT_ACTION;
 runtime_error:
 	return CPL_RUNTIME_ERROR;
 script_error:
 	return CPL_SCRIPT_ERROR;
f507eb0a
 }
 
 
 
cf648820
 /* UPDATED + CHECKED
  */
64b49597
 static inline char *run_string_switch( struct cpl_interpreter *intr )
f507eb0a
 {
cf648820
 	unsigned short field;
64b49597
 	char *p;
 	char *kid;
 	char *not_present_node;
 	unsigned short attr_name;
f507eb0a
 	int i;
 	str cpl_val;
 	str msg_val;
 
31204084
 	not_present_node = 0;
f507eb0a
 	msg_val.s = 0;
 	msg_val.len = 0;
 
cf648820
 	/* parse the attribute */
 	if (NR_OF_ATTR(intr->ip)!=1) {
 		LOG(L_ERR,"ERROR:cpl_c:run_string_switch: node should have 1 attr, not"
 			" (%d)\n",NR_OF_ATTR(intr->ip));
 		goto script_error;
f507eb0a
 	}
cf648820
 	p=ATTR_PTR(intr->ip);
 	get_basic_attr( p, attr_name, field, intr, script_error);
 	if (attr_name!=FIELD_ATTR) {
 		LOG(L_ERR,"ERROR:cpl_c:run_string_switch: unknown param type (%d)"
 			" for STRING_SWITCH node\n",*p);
a98061d8
 		goto script_error;
f507eb0a
 	}
 
 	for( i=0 ; i<NR_OF_KIDS(intr->ip) ; i++ ) {
 		kid = intr->ip + KID_OFFSET(intr->ip,i);
a98061d8
 		check_overflow_by_ptr( kid+SIMPLE_NODE_SIZE(kid), intr, script_error);
f507eb0a
 		switch ( NODE_TYPE(kid) ) {
31204084
 			case NOT_PRESENT_NODE:
 				if (not_present_node) {
 					LOG(L_ERR,"ERROR:run_string_switch: NOT_PRESENT node "
 						"found twice!\n");
 					goto script_error;
 				}
 				not_present_node = kid;
 				break;
f507eb0a
 			case OTHERWISE_NODE :
31204084
 				if (i!=NR_OF_KIDS(intr->ip)-1) {
 					LOG(L_ERR,"ERROR:run_string_switch: OTHERWISE node "
 						"not found as the last sub-node!\n");
 					goto script_error;
 				}
f507eb0a
 				DBG("DEBUG:run_string_switch: matching on OTHERWISE node\n");
a98061d8
 				return get_first_child(kid);
f507eb0a
 			case STRING_NODE :
 				/* check the number of attributes */
 				if (NR_OF_ATTR(kid)!=1) {
95072403
 					LOG(L_ERR,"ERROR:run_string_switch: incorrect nr of attrs "
cf648820
 						"(%d) in STRING node (expected 1)\n",NR_OF_ATTR(kid));
a98061d8
 					goto script_error;
f507eb0a
 				}
 				/* get the attribute name */
 				p = ATTR_PTR(kid);
cf648820
 				get_basic_attr( p, attr_name, cpl_val.len, intr, script_error);
f507eb0a
 				if (attr_name!=IS_ATTR && attr_name!=CONTAINS_ATTR ) {
95072403
 					LOG(L_ERR,"ERROR:run_string_switch: unknown attribute "
cf648820
 						"(%d) in STRING node\n",attr_name);
a98061d8
 					goto script_error;
f507eb0a
 				}
 				/* get attribute value */
cf648820
 				get_str_attr( p, cpl_val.s, cpl_val.len, intr, script_error,1);
f507eb0a
 				DBG("DEBUG:run_string_switch: testing STRING branch "
 					"attr_name=%d attr_val=[%.*s](%d)..\n",
 					attr_name,cpl_val.len,cpl_val.s,cpl_val.len);
 				if (!msg_val.s) {
 					switch (field) {
 						case SUBJECT_VAL: /* SUBJECT */
31204084
 							if (intr->subject==STR_NOT_FOUND)
 								goto not_present;
f507eb0a
 							if (!intr->subject) {
 								/* get the subject header */
31204084
 								if (!intr->msg->subject) {
 									if (parse_headers(intr->msg,
0bfbf63f
 									HDR_SUBJECT_F,0)==-1) {
31204084
 										LOG(L_ERR,"ERROR:run_string_switch: "
 										"bad SUBJECT header\n");
 										goto runtime_error;
 									} else if (!intr->msg->subject) {
 										/* hdr not present */
 										intr->subject = STR_NOT_FOUND;
 										goto not_present;
 									}
f507eb0a
 								}
 								intr->subject =
 									&(intr->msg->subject->body);
 							}
 							trim_len( msg_val.len,msg_val.s,
 								*(intr->subject));
 							break;
 						case ORGANIZATION_VAL: /* ORGANIZATION */
31204084
 							if (intr->organization==STR_NOT_FOUND)
 								goto not_present;
f507eb0a
 							if (!intr->organization) {
 								/* get the organization header */
31204084
 								if (!intr->msg->organization) {
 									if (parse_headers(intr->msg,
0bfbf63f
 									HDR_ORGANIZATION_F,0)==-1) {
31204084
 										LOG(L_ERR,"ERROR:run_string_switch: "
 										"bad ORGANIZATION hdr\n");
 										goto runtime_error;
 									} else if (!intr->msg->organization) {
 										/* hdr not present */
 										intr->organization = STR_NOT_FOUND;
 										goto not_present;
 									}
f507eb0a
 								}
 								intr->organization =
 									&(intr->msg->organization->body);
 							}
 							trim_len( msg_val.len,msg_val.s,
 								*(intr->organization));
 							break;
 						case USER_AGENT_VAL: /* User Agent */
31204084
 							if (intr->user_agent==STR_NOT_FOUND)
 								goto not_present;
f507eb0a
 							if (!intr->user_agent) {
 								/* get the  header */
31204084
 								if (!intr->msg->user_agent) {
 									if (parse_headers(intr->msg,
0bfbf63f
 									HDR_USERAGENT_F,0)==-1) {
31204084
 										LOG(L_ERR,"ERROR:run_string_switch: "
 										"bad USERAGENT hdr\n");
 										goto runtime_error;
 									} else if (!intr->msg->user_agent) {
 										/* hdr not present */
 										intr->user_agent = STR_NOT_FOUND;
 										goto not_present;
 									}
f507eb0a
 								}
 								intr->user_agent =
 									&(intr->msg->user_agent->body);
 							}
 							trim_len( msg_val.len,msg_val.s,
 								*(intr->user_agent));
 							break;
 						default:
 							LOG(L_ERR,"ERROR:run_string_switch: unknown "
 								"attribute (%d) in STRING node\n",field);
a98061d8
 							goto script_error;
f507eb0a
 					}
 					DBG("DEBUG:run_string_switch: extracted msg string is "
 						"<%.*s>\n",msg_val.len, msg_val.s);
 				}
 				/* does the value from script match the one from message? */
 				switch (attr_name) {
 					case IS_ATTR:
 						if ( (!msg_val.s && !cpl_val.s) ||
 						(msg_val.len==cpl_val.len &&
 						strncasecmp(msg_val.s,cpl_val.s,cpl_val.len)==0)) {
 							DBG("DEBUG:run_string_switch: matching on "
 								"STRING node (IS)\n");
a98061d8
 							return get_first_child(kid);
f507eb0a
 						}
 						break;
 					case CONTAINS_ATTR:
cf648820
 						if (cpl_val.len<=msg_val.len &&
f507eb0a
 						strcasestr_str(&msg_val, &cpl_val)!=0 ) {
 							DBG("DEBUG:run_string_switch: matching on "
 								"STRING node (CONTAINS)\n");
a98061d8
 							return get_first_child(kid);
f507eb0a
 						}
 						break;
 				}
 				break;
 			default:
 				LOG(L_ERR,"ERROR:run_string_switch: unknown output node type "
 					"(%d) for STRING_SWITCH node\n",NODE_TYPE(kid));
a98061d8
 				goto script_error;
f507eb0a
 		}
 	}
 
95072403
 	/* none of the branches of STRING_SWITCH matched -> go for default */
a98061d8
 	return DEFAULT_ACTION;
31204084
 not_present:
 	DBG("DEBUG:run_string_switch: required hdr not present in sip msg\n");
 	if (not_present_node)
 		return get_first_child(not_present_node);
 	/* look for the NOT_PRESENT node */
 	DBG("DEBUG:run_string_switch: searching for NOT_PRESENT sub-node..\n");
 	for(; 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);
 		if (NODE_TYPE(kid)==NOT_PRESENT_NODE)
 			return get_first_child(kid);
 	}
 	return DEFAULT_ACTION;
a98061d8
 runtime_error:
 	return CPL_RUNTIME_ERROR;
 script_error:
 	return CPL_SCRIPT_ERROR;
f507eb0a
 }
 
 
 
cf648820
 /* UPDATED + CHECKED
  */
64b49597
 static inline char *run_priority_switch( struct cpl_interpreter *intr )
f507eb0a
 {
03f6db11
 	static str default_val=STR_STATIC_INIT("normal");
cf648820
 	unsigned short n;
64b49597
 	char *p;
 	char *kid;
 	char *not_present_node;
 	unsigned short attr_name;
 	unsigned short attr_val;
 	unsigned short msg_attr_val;
 	unsigned short msg_prio;
f507eb0a
 	int i;
03f6db11
 	str cpl_val = STR_NULL;
 	str msg_val = STR_NULL;
f507eb0a
 
31204084
 	not_present_node = 0;
f507eb0a
 	msg_attr_val = NORMAL_VAL;
 
 	for( i=0 ; i<NR_OF_KIDS(intr->ip) ; i++ ) {
 		kid = intr->ip + KID_OFFSET(intr->ip,i);
a98061d8
 		check_overflow_by_ptr( kid+SIMPLE_NODE_SIZE(kid), intr, script_error);
f507eb0a
 		switch ( NODE_TYPE(kid) ) {
31204084
 			case NOT_PRESENT_NODE:
 				if (not_present_node) {
 					LOG(L_ERR,"ERROR:run_priority_switch: NOT_PRESENT node "
 						"found twice!\n");
 					goto script_error;
 				}
 				not_present_node = kid;
 				break;
f507eb0a
 			case OTHERWISE_NODE :
31204084
 				if (i!=NR_OF_KIDS(intr->ip)-1) {
 					LOG(L_ERR,"ERROR:run_priority_switch: OTHERWISE node "
 						"not found as the last sub-node!\n");
 					goto script_error;
 				}
f507eb0a
 				DBG("DEBUG:run_priority_switch: matching on OTHERWISE node\n");
cf648820
 				return get_first_child(kid);
f507eb0a
 			case PRIORITY_NODE :
 				if (NR_OF_ATTR(kid)!=1)
a98061d8
 					goto script_error;
f507eb0a
 				/* get the attribute */
 				p = ATTR_PTR(kid);
cf648820
 				get_basic_attr( p, attr_name, attr_val, intr, script_error);
f507eb0a
 				if (attr_name!=LESS_ATTR && attr_name!=GREATER_ATTR &&
 				attr_name!=EQUAL_ATTR){
95072403
 					LOG(L_ERR,"ERROR:run_priority_switch: unknown attribute "
cf648820
 						"(%d) in PRIORITY node\n",attr_name);
a98061d8
 					goto script_error;
f507eb0a
 				}
 				/* attribute's encoded value */
 				if (attr_val!=EMERGENCY_VAL && attr_val!=URGENT_VAL &&
 				attr_val!=NORMAL_VAL && attr_val!=NON_URGENT_VAL &&
 				attr_val!=UNKNOWN_PRIO_VAL) {
 					LOG(L_ERR,"ERROR:run_priority_switch: unknown encoded "
cf648820
 						"value (%d) for attribute (*d) in PRIORITY node\n",*p);
a98061d8
 					goto script_error;
f507eb0a
 				}
cf648820
 				if (attr_val==UNKNOWN_PRIO_VAL) {
 					if (attr_name!=EQUAL_ATTR) {
 						LOG(L_ERR,"ERROR:cpl_c:run_priority_switch:bad PRIORITY"
 							" branch: attr=EQUAL doesn't match val=UNKNOWN\n");
 						goto script_error;
 					}
 					/* if the attr is UNKNOWN, its string value is present  */
 					get_basic_attr(p, n,cpl_val.len, intr, script_error);
 					if (n!=PRIOSTR_ATTR) {
 						LOG(L_ERR,"ERROR:run_priority_switch: expected PRIOSTR"
 							"(%d) attr, found (%d)\n",PRIOSTR_ATTR,n);
 						goto script_error;
 					}
 					get_str_attr(p, cpl_val.s, cpl_val.len,intr,script_error,1);
f507eb0a
 				}
 
 				DBG("DEBUG:run_priority_switch: testing PRIORITY branch "
 					"(attr=%d,val=%d) [%.*s](%d)..\n",
 					attr_name,attr_val,cpl_val.len,cpl_val.s,cpl_val.len);
 				if (!msg_val.s) {
 					if (!intr->priority) {
 						/* get the PRIORITY header from message */
31204084
 						if (!intr->msg->priority) {
0bfbf63f
 							if (parse_headers(intr->msg,HDR_PRIORITY_F,0)==-1){
31204084
 								LOG(L_ERR,"ERROR:run_priority_switch: bad "
 									"sip msg or PRIORITY header !\n");
 								goto runtime_error;
 							} else if (!intr->msg->priority) {
 								LOG(L_NOTICE,"NOTICE:run_priority_switch: "
 									"missing PRIORITY header -> using "
 									"default value \"normal\"!\n");
 								intr->priority = &default_val;
 							} else {
 								intr->priority =
 									&(intr->msg->priority->body);
 							}
f507eb0a
 						} else {
 							intr->priority =
 								&(intr->msg->priority->body);
 						}
 					}
 					trim_len( msg_val.len, msg_val.s, *(intr->priority));
 					/* encode attribute's value from SIP message */
 					if ( msg_val.len==EMERGENCY_STR_LEN &&
 					!strncasecmp(msg_val.s,EMERGENCY_STR,msg_val.len) ) {
 						msg_attr_val = EMERGENCY_VAL;
 					} else if ( msg_val.len==URGENT_STR_LEN &&
 					!strncasecmp(msg_val.s,URGENT_STR,msg_val.len) ) {
 						msg_attr_val = URGENT_VAL;
 					} else if ( msg_val.len==NORMAL_STR_LEN &&
 					!strncasecmp(msg_val.s,NORMAL_STR,msg_val.len) ) {
 						msg_attr_val = NORMAL_VAL;
 					} else if ( msg_val.len==NON_URGENT_STR_LEN &&
 					!strncasecmp(msg_val.s,NON_URGENT_STR,msg_val.len) ) {
 						msg_attr_val = NON_URGENT_VAL;
 					} else {
 						msg_attr_val = UNKNOWN_PRIO_VAL;
 					}
 					DBG("DEBUG:run_priority_switch: extracted msg priority is "
 						"<%.*s> decoded as [%d]\n",
 						msg_val.len,msg_val.s,msg_attr_val);
 				}
 				DBG("DEBUG:run_priority_switch: using msg string <%.*s>\n",
 					msg_val.len, msg_val.s);
 				/* attr_val (from cpl) cannot be UNKNOWN - we already
 				 * check it -> check only for msg_attr_val for non-EQUAL op */
 				if (msg_attr_val==UNKNOWN_PRIO_VAL && attr_name!=EQUAL_ATTR) {
 					LOG(L_NOTICE,"NOTICE:run_priority_switch: UNKNOWN "
95072403
 						"value found in sip_msg when string a LESS/GREATER "
f507eb0a
 						"cmp -> force the value to default \"normal\"\n");
 					msg_prio = NORMAL_VAL;
 				} else {
 					msg_prio = msg_attr_val;
 				}
 				/* does the value from script match the one from message? */
 				switch (attr_name) {
 					case LESS_ATTR:
 						switch (attr_val) {
 							case EMERGENCY_VAL:
 								if (msg_prio!=EMERGENCY_VAL) break; /*OK*/
 								else continue; /* for cycle for all kids */
 							case URGENT_VAL:
 								if (msg_prio!=EMERGENCY_VAL &&
 									msg_prio!=URGENT_VAL) break; /* OK */
 								else continue; /* for cycle for all kids */
 							case NORMAL_VAL:
 								if (msg_prio==NON_URGENT_VAL) break; /*OK*/
 								else continue; /* for cycle for all kids */
 							case NON_URGENT_VAL:
 								continue; /* for cycle for all kids */
 						}
 						break;
 					case GREATER_ATTR:
 						switch (attr_val) {
 							case EMERGENCY_VAL:
 								continue; /* for cycle for all kids */
 							case URGENT_VAL:
 								if (msg_prio!=EMERGENCY_VAL) break; /*OK*/
 								else continue; /* for cycle for all kids */
 							case NORMAL_VAL:
 								if (msg_prio!=NON_URGENT_VAL &&
 									msg_prio!=NORMAL_VAL) break; /*OK*/
 								else continue; /* for cycle for all kids */
 							case NON_URGENT_VAL:
 								if (msg_prio!=NON_URGENT_VAL) break; /*OK*/
 								else continue; /* for cycle for all kids */
 						}
 						break;
 					case EQUAL_ATTR:
 						if ( attr_val==msg_prio ) {
 							if (attr_val==UNKNOWN_PRIO_VAL) {
 								if ( msg_val.len==cpl_val.len &&
 								!strncasecmp(msg_val.s,cpl_val.s,msg_val.len)){
 									break; /* OK */
 								}
 							} else {
 								break; /* OK */
 							}
 						}
 						continue; /* for cycle for all kids */
 						break;
 				} /* end switch for attr_name */
 				DBG("DEBUG:run_priority_switch: matching current "
 					"PRIORITY node\n");
a98061d8
 				return get_first_child(kid);
f507eb0a
 				break;
 			default:
 				LOG(L_ERR,"ERROR:run_priority_switch: unknown output node type"
 					" (%d) for PRIORITY_SWITCH node\n",NODE_TYPE(kid));
a98061d8
 				goto script_error;
f507eb0a
 		} /* end switch for NODE_TYPE */
 	} /* end for for all kids */
 
95072403
 	/* none of the branches of PRIORITY_SWITCH matched -> go for default */
a98061d8
 	return DEFAULT_ACTION;
31204084
 runtime_error:
 	return CPL_RUNTIME_ERROR;
a98061d8
 script_error:
 	return CPL_SCRIPT_ERROR;
f507eb0a
 }
 
 
 
245357ba
 inline static int set_TZ(char *tz_env)
b98af8ba
 {
245357ba
 	DBG("DEBUG:cpl-c:set_TZ: switching TZ as \"%s\"\n",tz_env);
 	if (putenv( tz_env )==-1) {
 		LOG(L_ERR,"ERROR:cpl-c:set_TZ: setenv failed -> unable to set TZ "
 			" \"%s\"\n",tz_env);
b98af8ba
 		return -1;
 	}
 	tzset(); /* just to be sure */
 	return 0;
 }
 
 
 
cf648820
 /* UPDATED + CHECKED
  */
64b49597
 static inline char *run_time_switch( struct cpl_interpreter *intr )
f507eb0a
 {
64b49597
 	char  *p;
 	char  *kid;
 	char  *attr_str;
b98af8ba
 	unsigned short attr_name;
f507eb0a
 	unsigned short attr_len;
b98af8ba
 	unsigned char  flags = 0;
f507eb0a
 	int nr_attrs;
 	int i,j;
03f6db11
 	str user_tz = STR_NULL;
f507eb0a
 	ac_tm_t att;
 	tmrec_t trt;
 
b98af8ba
 	DBG("DEBUG:cpl-c:run_time_switch: checking recv. time stamp <%d>\n",
f507eb0a
 		intr->recv_time);
b98af8ba
 	switch (NR_OF_ATTR(intr->ip)) {
 		case 1:
 			p = ATTR_PTR(intr->ip);
 			get_basic_attr( p, attr_name, user_tz.len, intr, script_error);
 			if (attr_name!=TZID_ATTR) {
 				LOG(L_ERR,"ERROR:cpl-c:run_time_switch: bad attribute -> "
 					" expected=%d, found=%d\n",TZID_ATTR,attr_name);
 				goto script_error;
 			}
 			get_str_attr( p, user_tz.s, user_tz.len, intr, script_error, 1);
 		case 0:
 			break;
 		default:
 			LOG(L_ERR,"ERROR:cpl-c:run_time_switch: incorrect number of attr ->"
 				" found=%d expected=(0,1)\n",NR_OF_ATTR(intr->ip));
 			goto script_error;
 	}
 
 	if (user_tz.s && user_tz.len) {
 		if (set_TZ(user_tz.s)==-1)
 			goto runtime_error;
 		flags |= (1<<7);
 	}
f507eb0a
 
 	for( i=0 ; i<NR_OF_KIDS(intr->ip) ; i++ ) {
 		kid = intr->ip + KID_OFFSET(intr->ip,i);
a98061d8
 		check_overflow_by_ptr( kid+SIMPLE_NODE_SIZE(kid), intr, script_error);
f507eb0a
 		switch ( NODE_TYPE(kid) ) {
31204084
 			case NOT_PRESENT_NODE:
b98af8ba
 				DBG("DEBUG:cpl-c:run_time_switch: NOT_PRESENT node found ->"
31204084
 					"skipping (useless in this case)\n");
 				break;
f507eb0a
 			case OTHERWISE_NODE :
31204084
 				if (i!=NR_OF_KIDS(intr->ip)-1) {
b98af8ba
 					LOG(L_ERR,"ERROR:cpl-c:run_time_switch: OTHERWISE node "
31204084
 						"not found as the last sub-node!\n");
 					goto script_error;
 				}
b98af8ba
 				DBG("DEBUG:cpl-c:run_time_switch: matching on "
 					"OTHERWISE node\n");
a98061d8
 				return get_first_child(kid);
f507eb0a
 			case TIME_NODE :
 				/* init structures */
 				memset( &att, 0, sizeof(att));
 				memset( &trt, 0, sizeof(trt));
 				if(ac_tm_set_time( &att, intr->recv_time))
a98061d8
 					goto runtime_error;
f507eb0a
 				/* let's see how many attributes we have */
 				nr_attrs = NR_OF_ATTR(kid);
 				/* get the attributes */
 				p = ATTR_PTR(kid);
 				for(j=0;j<nr_attrs;j++) {
cf648820
 					/* get the attribute */
 					get_basic_attr( p, attr_name, attr_len, intr, script_error);
 					get_str_attr( p, attr_str, attr_len, intr, script_error,1);
f507eb0a
 					/* process the attribute */
 					DBG("DEBUG:cpl_c:run_time_node: attribute [%d] found :"
 						"[%s]\n",attr_name, attr_str);
 					switch (attr_name) {
 						case DTSTART_ATTR:
 							if( !attr_str || tr_parse_dtstart(&trt, attr_str))
 								goto parse_err;
 							flags ^= (1<<0);
 							break;
 						case DTEND_ATTR:
 							if( !attr_str || tr_parse_dtend(&trt, attr_str))
 								goto parse_err;
 							flags ^= (1<<1);
 							break;
 						case DURATION_ATTR:
 							if( !attr_str || tr_parse_duration(&trt, attr_str))
 								goto parse_err;
 							flags ^= (1<<1);
 							break;
 						case FREQ_ATTR:
 							if( attr_str && tr_parse_freq(&trt, attr_str))
 								goto parse_err;
 							break;
 						case UNTIL_ATTR:
 							if( attr_str && tr_parse_until(&trt, attr_str))
 								goto parse_err;
 							break;
 						case INTERVAL_ATTR:
 							if( attr_str && tr_parse_interval(&trt, attr_str))
 								goto parse_err;
 							break;
 						case BYDAY_ATTR:
 							if( attr_str && tr_parse_byday(&trt, attr_str))
 								goto parse_err;
 							break;
 						case BYMONTHDAY_ATTR:
 							if( attr_str && tr_parse_bymday(&trt, attr_str))
 								goto parse_err;
 							break;
 						case BYYEARDAY_ATTR:
 							if( attr_str && tr_parse_byyday(&trt, attr_str))
 								goto parse_err;
 							break;
 						case BYMONTH_ATTR:
 							if( attr_str && tr_parse_bymonth(&trt, attr_str))
 								goto parse_err;
 							break;
 						case BYWEEKNO_ATTR:
 							if( attr_str && tr_parse_byweekno(&trt, attr_str))
 								goto parse_err;
 							break;
 						case WKST_ATTR:
 							if( attr_str && tr_parse_wkst(&trt, attr_str))
 								goto parse_err;
 							break;
 						default:
a98061d8
 							LOG(L_ERR,"ERROR:cpl_c:run_time_switch: "
f507eb0a
 								"unsupported attribute [%d] found in TIME "
a98061d8
 								"node\n",attr_name);
 							goto script_error;
f507eb0a
 					} /* end attribute switch */
 				} /* end for*/
 				/* check the mandatory attributes */
b98af8ba
 				if ( (flags&0x03)!=((1<<0)|(1<<1)) ) {
f507eb0a
 					LOG(L_ERR,"ERROR:cpl_c:run_time_switch: attribute DTSTART"
 						",DTEND,DURATION missing or multi-present\n");
a98061d8
 					goto script_error;
f507eb0a
 				}
 				/* does the recv_time match the specified interval?  */
 				j = check_tmrec( &trt, &att, 0);
b98af8ba
 				/* restore the orig TZ */
245357ba
 				if ( flags&(1<<7) )
f2bf348d
 					set_TZ(cpl_env.orig_tz.s);
b98af8ba
 				/* free structs that I don't need any more */
f507eb0a
 				ac_tm_free( &att );
 				tmrec_free( &trt );
b98af8ba
 				/* let's see the result ;-) */
f507eb0a
 				switch  (j) {
 					case 0:
 						DBG("DEBUG:run_time_switch: matching current "
 							"TIME node\n");
a98061d8
 						return get_first_child(kid);
f507eb0a
 					case -1:
 						LOG(L_ERR,"ERROR:cpl_c:run_time_switch: check_tmrec "
 							"ret. err. when testing time cond. !\n");
a98061d8
 						goto runtime_error;
f507eb0a
 						break;
 					case 1:
 						DBG("DEBUG:cpl_c:run_time_switch: time cond. doesn't"
 							" match !\n");
 						break;
 				}
 				break;
 			default:
b98af8ba
 				LOG(L_ERR,"ERROR:cpl-c:run_priority_switch: unknown output node"
 					" type (%d) for PRIORITY_SWITCH node\n",NODE_TYPE(kid));
ef163c8f
 				goto script_error;
f507eb0a
 		} /* end switch for NODE_TYPE */
 	} /* end for for all kids */
 
a98061d8
 
95072403
 	/* none of the branches of TIME_SWITCH matched -> go for default */
a98061d8
 	ac_tm_free( &att );
 	tmrec_free( &trt );
 	return DEFAULT_ACTION;
 runtime_error:
245357ba
 	if ( flags&(1<<7) )
f2bf348d
 		set_TZ(cpl_env.orig_tz.s);
f507eb0a
 	ac_tm_free( &att );
 	tmrec_free( &trt );
a98061d8
 	return CPL_RUNTIME_ERROR;
f507eb0a
 parse_err:
b98af8ba
 	LOG(L_ERR,"ERROR:cpl-c:run_priority_switch: error parsing attr [%d][%s]\n",
f507eb0a
 		attr_name,attr_str?(char*)attr_str:"NULL");
a98061d8
 script_error:
245357ba
 	if ( flags&(1<<7) )
f2bf348d
 		set_TZ(cpl_env.orig_tz.s);
f507eb0a
 	ac_tm_free( &att );
 	tmrec_free( &trt );
a98061d8
 	return CPL_SCRIPT_ERROR;
f507eb0a
 }
 
 
ef163c8f
 
d7d1e3ae
 inline static int is_lang_tag_matching(str *range,str *cpl_tag,str *cpl_subtag)
 {
 	char *c;
 	char *end;
03f6db11
 	str tag = STR_NULL;
 	str subtag = STR_NULL;
d7d1e3ae
 
 	c = range->s;
 	end = range->s + range->len;
 
 	while(c<end) {
 		/* eat all spaces to first letter */
 		while(c<end && (*c==' ' || *c=='\t')) c++;
 		if (c==end) goto error;
 		/* init tag and subtag */
 		tag.len = 0;
 		subtag.len = 0;
 		/* get the tag */
 		tag.s = c;
 		if (*c=='*' && (c+1==end||*(c+1)!='-')) {
 			tag.len++;
 			c++;
 		} else while (c<end && ((*c)|0x20)>='a' && ((*c)|0x20)<='z' ) {
 			/*DBG("--- tag ---> <%c>[%d]\n",*c,*c);*/
 			tag.len++;
 			c++;
 		}
 		if (tag.len==0) goto error;
 		if (c<end && *c=='-') {
 			/* go for the subtag */
 			subtag.s = ++c;
 			while (c<end && ((*c)|0x20)>='a' && ((*c)|0x20)<='z' ) {
 				/*DBG("--- subtag ---> <%c>[%d]\n",*c,*c);*/
 				subtag.len++;
 				c++;
 			}
 			if (subtag.len==0) goto error;
 		} else {
 			subtag.s = 0;
 		}
 		if (c<end && *c==';') {
 			/* eat all the params to the ',' */
 			while(c<end && *c!=',') c++;
 			if (c==end) goto no_matche;
 		}
 		while(c<end && (*c==' '||*c=='\t')) c++;
 		if (c==end || *c==',') {
 			/* do compare */
 			DBG("DEBUG:cpl-c:is_lang_tag_matching: testing range [%.*s]-[%.*s]"
 				" against tag [%.*s]-[%.*s]\n",
 				tag.len,tag.s,subtag.len,subtag.s,
 				cpl_tag->len,cpl_tag->s,cpl_subtag->len,cpl_subtag->s);
cf648820
 			/* language range of "*" is ignored for the purpose of matching*/
 			if ( !(tag.len==1 && *tag.s=='*') ) {
 				/* does the language tag matches ? */
 				if (tag.len==cpl_tag->len && !strncasecmp(tag.s,cpl_tag->s,
 				tag.len)) {
 					DBG("cucu bau \n");
 					/* if the subtag of the range is void -> matche */
 					if (subtag.len==0)
 						return 1;
 					/* the subtags equals -> matche */
 					if (subtag.len==cpl_subtag->len &&
 					!strncasecmp(subtag.s,cpl_subtag->s,subtag.len) )
 						return 1;
 				}
d7d1e3ae
 			}
 			/* if ',' go for the next language range */
 			if (*c==',') c++;
 		} else {
 			goto error;
 		}
 	}
 
 no_matche:
 	return 0;
 error:
 	LOG(L_ERR,"ERROR:cpl-c:is_lang_tag_matching: parse error in Accept-"
5bb9fc98
 		"Language body <%.*s> at char <%c>[%d] offset %ld!\n",
 		range->len,range->s,*c,*c,(long)(c-range->s));
d7d1e3ae
 	return -1;
 }
 
 
ef163c8f
 
cf648820
 /* UPDATED + CHECKED
  */
64b49597
 static inline char *run_language_switch( struct cpl_interpreter *intr )
ef163c8f
 {
64b49597
 	char  *p;
 	char  *kid;
 	char  *not_present_node;
 	unsigned short attr_name;
d7d1e3ae
 	int nr_attr;
 	int i,j;
03f6db11
 	str attr = STR_NULL;
 	str msg_val = STR_NULL;
 	str lang_tag = STR_NULL;
 	str lang_subtag = STR_NULL;
ef163c8f
 
31204084
 	not_present_node = 0;
 
ef163c8f
 	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) ) {
31204084
 			case NOT_PRESENT_NODE:
 				if (not_present_node) {
 					LOG(L_ERR,"ERROR:run_language_switch: NOT_PRESENT node "
 						"found twice!\n");
 					goto script_error;
 				}
 				not_present_node = kid;
 				break;
ef163c8f
 			case OTHERWISE_NODE :
31204084
 				if (i!=NR_OF_KIDS(intr->ip)-1) {
 					LOG(L_ERR,"ERROR:run_language_switch: OTHERWISE node "
 						"not found as the last sub-node!\n");
 					goto script_error;
 				}
ef163c8f
 				DBG("DEBUG:run_language_switch: matching on OTHERWISE node\n");
 				return get_first_child(kid);
31204084
 			case LANGUAGE_NODE :
d7d1e3ae
 				/* check the number of attributes */
 				nr_attr = NR_OF_ATTR(kid);
 				if (nr_attr<1 || nr_attr>2) {
95072403
 					LOG(L_ERR,"ERROR:run_string_switch: incorrect nr of attrs "
d7d1e3ae
 						"(%d) in LANGUAGE node (1 or 2)\n",NR_OF_ATTR(kid));
 					goto script_error;
 				}
 				/* get the attributes */
 				p = ATTR_PTR(kid);
cf648820
 				lang_tag.s = lang_subtag.s = 0;
 				lang_tag.len = lang_subtag.len = 0;
d7d1e3ae
 				for(j=0;j<nr_attr;j++) {
cf648820
 					get_basic_attr( p, attr_name, attr.len, intr, script_error);
 					get_str_attr( p, attr.s, attr.len, intr, script_error,0);
d7d1e3ae
 					if (attr_name==MATCHES_TAG_ATTR ) {
 						lang_tag = attr;
 						DBG("DEBUG:cpl-c:run_language_string: language-tag is"
 							" [%.*s]\n",attr.len,attr.s);
 					}else if (attr_name==MATCHES_SUBTAG_ATTR) {
 						lang_subtag = attr;
 						DBG("DEBUG:cpl-c:run_language_string: language-subtag"
 							" is [%.*s]\n",attr.len,attr.s);
 					}else {
95072403
 						LOG(L_ERR,"ERROR:run_language_switch: unknown attribute"
d7d1e3ae
 						" (%d) in LANGUAGE node\n",attr_name);
 						goto script_error;
 					}
 				}
 				
 				/* get the value from the SIP message -> if not yet, do it now
95072403
 				 * and remember it for the next times */
d7d1e3ae
 				if (!msg_val.s) {
 					if (intr->accept_language==STR_NOT_FOUND)
 						goto not_present;
 					if (!intr->accept_language) {
 						/* get the accept_language header */
 						if (!intr->msg->accept_language) {
 							if (parse_headers(intr->msg,
0bfbf63f
 							HDR_ACCEPTLANGUAGE_F,0)==-1) {
d7d1e3ae
 								LOG(L_ERR,"ERROR:run_language_switch: "
 									"bad ACCEPT_LANGUAGE header\n");
 								goto runtime_error;
 							} else if (!intr->msg->accept_language) {
 								/* hdr not present */
 								intr->accept_language = STR_NOT_FOUND;
 								goto not_present;
 							}
 						}
 						intr->subject =
 							&(intr->msg->accept_language->body);
 					}
 				}
 				trim_len( msg_val.len,msg_val.s, *(intr->subject));
 				DBG("DEBUG:run_language_switch: extracted msg string is "
 					"<%.*s>\n",msg_val.len, msg_val.s);
 				
 				/* does the value from script match the one from message? */
 				if (msg_val.len && msg_val.s) {
 					j = is_lang_tag_matching(&msg_val,&lang_tag,&lang_subtag);
 					if (j==1) {
 						DBG("DEBUG:run_language_switch: matching on "
 							"LANGUAGE node\n");
 						return get_first_child(kid);
 					}else if (j==-1) {
 						goto runtime_error;
 					}
 				}
ef163c8f
 				break;
 			default:
 				LOG(L_ERR,"ERROR:cpl_c:run_language_switch: unknown output "
 					"node type (%d) for LANGUAGE_SWITCH node\n",
 					NODE_TYPE(kid));
 				goto script_error;
 		} /* end switch for NODE_TYPE */
 	} /* end for for all kids */
 
 	return DEFAULT_ACTION;
d7d1e3ae
 not_present:
 	DBG("DEBUG:run_string_switch: required hdr not present in sip msg\n");
 	if (not_present_node)
 		return get_first_child(not_present_node);
 	/* look for the NOT_PRESENT node */
 	DBG("DEBUG:run_string_switch: searching for NOT_PRESENT sub-node..\n");
 	for(; 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);
 		if (NODE_TYPE(kid)==NOT_PRESENT_NODE)
 			return get_first_child(kid);
 	}
 	return DEFAULT_ACTION;
 runtime_error:
 	return CPL_RUNTIME_ERROR;
ef163c8f
 script_error:
 	return CPL_SCRIPT_ERROR;
 }