/* * $Id: cpl_switches.h,v 1.13.2.1 2005/06/03 00:56:22 andrei Exp $ * * Copyright (C) 2001-2003 FhG Fokus * * 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" #include "../../parser/parse_uri.h" /* UPDATED + CHECKED */ static inline char *run_address_switch( struct cpl_interpreter *intr ) { static str def_port_str = {"5060",4}; unsigned short field, subfield; char *p; char *kid; unsigned short attr_name; unsigned short n; int i; int k; 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 */ 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) { LOG(L_ERR,"ERROR:cpl-c:run_address_switch: multiple FIELD " "attrs found\n"); goto script_error; } field = n; break; case SUBFIELD_ATTR: if (subfield!=UNDEF_CHAR) { LOG(L_ERR,"ERROR:cpl-c:run_address_switch: multiple SUBFIELD" " 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; } } if (field==UNDEF_CHAR) { LOG(L_ERR,"ERROR:cpl_c:run_address_switch: mandatory param FIELD " "no found\n"); goto script_error; } /* test the condition from all the sub-nodes */ for( i=0 ; iip) ; 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 NOT_PRESENT_NODE: DBG("DEBUG:run_address_switch: NOT_PRESENT node found ->" "skipping (useless in this case)\n"); break; case OTHERWISE_NODE : 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; } DBG("DEBUG:run_address_switch: matching on OTHERWISE node\n"); return get_first_child(kid); case ADDRESS_NODE : /* check the number of attributes */ if (NR_OF_ATTR(kid)!=1) { LOG(L_ERR,"ERROR:run_address_switch: incorrect nr of attrs " "(%d) in ADDRESS node\n",NR_OF_ATTR(kid)); goto script_error; } /* get the attribute name */ p = ATTR_PTR(kid); get_basic_attr( p, attr_name, cpl_val.len, intr, script_error); if (attr_name!=IS_ATTR && attr_name!=CONTAINS_ATTR && attr_name!=SUBDOMAIN_OF_ATTR) { LOG(L_ERR,"ERROR:run_address_switch: unknown attribute " "(%d) in ADDRESS node\n",attr_name); goto script_error; } /* get attribute value */ get_str_attr( p, cpl_val.s, cpl_val.len, intr, script_error,1); 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) goto runtime_error; intr->from = &(get_from(intr->msg)->uri); } uri = intr->from; break; case DESTINATION_VAL: /* RURI */ if (!intr->ruri) 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 && (parse_headers(intr->msg,HDR_TO,0)==-1 || !intr->msg->to)) { LOG(L_ERR,"ERROR:run_address_switch: bad " "msg or missing TO header\n"); goto runtime_error; } 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); goto script_error; } 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) goto runtime_error; msg_val = &(parsed_uri.user); break; case HOST_VAL: if (parse_uri( uri->s, uri->len, &parsed_uri)<0) goto runtime_error; msg_val = &(parsed_uri.host); break; case PORT_VAL: if (parse_uri( uri->s, uri->len, &parsed_uri)<0) goto runtime_error; if (parsed_uri.port.len!=0) msg_val = &(parsed_uri.port); else msg_val = &def_port_str; break; case TEL_VAL: if (parse_uri( uri->s, uri->len, &parsed_uri)<0) goto runtime_error; if (parsed_uri.user_param_val.len==5 && memcmp(parsed_uri.user_param_val.s,"phone",5)==0) 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); goto script_error; } DBG("DEBUG:run_address_switch: extracted val. is <%.*s>\n", (msg_val==0)?0:msg_val->len, (msg_val==0)?0:msg_val->s); } /* 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"); return get_first_child(kid); } break; case CONTAINS_ATTR: if (subfield!=DISPLAY_VAL) { LOG(L_WARN,"WARNING:run_address_switch: operator " "CONTAINS applies only to DISPLAY -> ignored\n"); } 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"); return get_first_child(kid); } } break; case SUBDOMAIN_OF_ATTR: 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: LOG(L_WARN,"WARNING:run_address_switch: operator" " SUBDOMAIN_OF applies only to HOST or TEL " "-> ignored\n"); } break; } break; default: LOG(L_ERR,"ERROR:run_address_switch: unknown output node type " "(%d) for ADDRESS_SWITCH node\n",NODE_TYPE(kid)); goto script_error; } } /* none of the branches of ADDRESS_SWITCH matched -> go for default */ return DEFAULT_ACTION; runtime_error: return CPL_RUNTIME_ERROR; script_error: return CPL_SCRIPT_ERROR; } /* UPDATED + CHECKED */ static inline char *run_string_switch( struct cpl_interpreter *intr ) { unsigned short field; char *p; char *kid; char *not_present_node; unsigned short attr_name; int i; str cpl_val; str msg_val; not_present_node = 0; msg_val.s = 0; msg_val.len = 0; /* 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; } 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); goto script_error; } for( i=0 ; iip) ; 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 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; case OTHERWISE_NODE : 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; } DBG("DEBUG:run_string_switch: matching on OTHERWISE node\n"); return get_first_child(kid); case STRING_NODE : /* check the number of attributes */ if (NR_OF_ATTR(kid)!=1) { LOG(L_ERR,"ERROR:run_string_switch: incorrect nr of attrs " "(%d) in STRING node (expected 1)\n",NR_OF_ATTR(kid)); goto script_error; } /* get the attribute name */ p = ATTR_PTR(kid); get_basic_attr( p, attr_name, cpl_val.len, intr, script_error); if (attr_name!=IS_ATTR && attr_name!=CONTAINS_ATTR ) { LOG(L_ERR,"ERROR:run_string_switch: unknown attribute " "(%d) in STRING node\n",attr_name); goto script_error; } /* get attribute value */ get_str_attr( p, cpl_val.s, cpl_val.len, intr, script_error,1); 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 */ if (intr->subject==STR_NOT_FOUND) goto not_present; if (!intr->subject) { /* get the subject header */ if (!intr->msg->subject) { if (parse_headers(intr->msg, HDR_SUBJECT,0)==-1) { 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; } } intr->subject = &(intr->msg->subject->body); } trim_len( msg_val.len,msg_val.s, *(intr->subject)); break; case ORGANIZATION_VAL: /* ORGANIZATION */ if (intr->organization==STR_NOT_FOUND) goto not_present; if (!intr->organization) { /* get the organization header */ if (!intr->msg->organization) { if (parse_headers(intr->msg, HDR_ORGANIZATION,0)==-1) { 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; } } intr->organization = &(intr->msg->organization->body); } trim_len( msg_val.len,msg_val.s, *(intr->organization)); break; case USER_AGENT_VAL: /* User Agent */ if (intr->user_agent==STR_NOT_FOUND) goto not_present; if (!intr->user_agent) { /* get the header */ if (!intr->msg->user_agent) { if (parse_headers(intr->msg, HDR_USERAGENT,0)==-1) { 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; } } 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); goto script_error; } 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"); return get_first_child(kid); } break; case CONTAINS_ATTR: if (cpl_val.len<=msg_val.len && strcasestr_str(&msg_val, &cpl_val)!=0 ) { DBG("DEBUG:run_string_switch: matching on " "STRING node (CONTAINS)\n"); return get_first_child(kid); } break; } break; default: LOG(L_ERR,"ERROR:run_string_switch: unknown output node type " "(%d) for STRING_SWITCH node\n",NODE_TYPE(kid)); goto script_error; } } /* none of the branches of STRING_SWITCH matched -> go for default */ return DEFAULT_ACTION; 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(; iip) ; 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; script_error: return CPL_SCRIPT_ERROR; } /* UPDATED + CHECKED */ static inline char *run_priority_switch( struct cpl_interpreter *intr ) { static str default_val={"normal",6}; unsigned short n; 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; int i; str cpl_val = {0,0}; str msg_val = {0,0}; not_present_node = 0; msg_attr_val = NORMAL_VAL; for( i=0 ; iip) ; 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 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; case OTHERWISE_NODE : 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; } DBG("DEBUG:run_priority_switch: matching on OTHERWISE node\n"); return get_first_child(kid); case PRIORITY_NODE : if (NR_OF_ATTR(kid)!=1) goto script_error; /* get the attribute */ p = ATTR_PTR(kid); get_basic_attr( p, attr_name, attr_val, intr, script_error); if (attr_name!=LESS_ATTR && attr_name!=GREATER_ATTR && attr_name!=EQUAL_ATTR){ LOG(L_ERR,"ERROR:run_priority_switch: unknown attribute " "(%d) in PRIORITY node\n",attr_name); goto script_error; } /* 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 " "value (%d) for attribute (*d) in PRIORITY node\n",*p); goto script_error; } 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); } 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 */ if (!intr->msg->priority) { if (parse_headers(intr->msg,HDR_PRIORITY,0)==-1) { 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); } } 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 " "value found in sip_msg when string a LESS/GREATER " "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"); return get_first_child(kid); break; default: LOG(L_ERR,"ERROR:run_priority_switch: unknown output node type" " (%d) for PRIORITY_SWITCH node\n",NODE_TYPE(kid)); goto script_error; } /* end switch for NODE_TYPE */ } /* end for for all kids */ /* none of the branches of PRIORITY_SWITCH matched -> go for default */ return DEFAULT_ACTION; runtime_error: return CPL_RUNTIME_ERROR; script_error: return CPL_SCRIPT_ERROR; } inline static int set_TZ(char *tz_env) { 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); return -1; } tzset(); /* just to be sure */ return 0; } /* UPDATED + CHECKED */ static inline char *run_time_switch( struct cpl_interpreter *intr ) { char *p; char *kid; char *attr_str; unsigned short attr_name; unsigned short attr_len; unsigned char flags = 0; int nr_attrs; int i,j; str user_tz = {0,0}; ac_tm_t att; tmrec_t trt; DBG("DEBUG:cpl-c:run_time_switch: checking recv. time stamp <%d>\n", intr->recv_time); 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); } for( i=0 ; iip) ; 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 NOT_PRESENT_NODE: DBG("DEBUG:cpl-c:run_time_switch: NOT_PRESENT node found ->" "skipping (useless in this case)\n"); break; case OTHERWISE_NODE : if (i!=NR_OF_KIDS(intr->ip)-1) { LOG(L_ERR,"ERROR:cpl-c:run_time_switch: OTHERWISE node " "not found as the last sub-node!\n"); goto script_error; } DBG("DEBUG:cpl-c:run_time_switch: matching on " "OTHERWISE node\n"); return get_first_child(kid); case TIME_NODE : /* init structures */ memset( &att, 0, sizeof(att)); memset( &trt, 0, sizeof(trt)); if(ac_tm_set_time( &att, intr->recv_time)) goto runtime_error; /* 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 go for default */ ac_tm_free( &att ); tmrec_free( &trt ); return DEFAULT_ACTION; runtime_error: if ( flags&(1<<7) ) set_TZ(cpl_env.orig_tz.s); ac_tm_free( &att ); tmrec_free( &trt ); return CPL_RUNTIME_ERROR; parse_err: LOG(L_ERR,"ERROR:cpl-c:run_priority_switch: error parsing attr [%d][%s]\n", attr_name,attr_str?(char*)attr_str:"NULL"); script_error: if ( flags&(1<<7) ) set_TZ(cpl_env.orig_tz.s); ac_tm_free( &att ); tmrec_free( &trt ); return CPL_SCRIPT_ERROR; } inline static int is_lang_tag_matching(str *range,str *cpl_tag,str *cpl_subtag) { char *c; char *end; str tag = {0,0}; str subtag = {0,0}; c = range->s; end = range->s + range->len; while(c='a' && ((*c)|0x20)<='z' ) { /*DBG("--- tag ---> <%c>[%d]\n",*c,*c);*/ tag.len++; c++; } if (tag.len==0) goto error; if (c='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 (clen,cpl_tag->s,cpl_subtag->len,cpl_subtag->s); /* 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; } } /* 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-" "Language body <%.*s> at char <%c>[%d] offset %ld!\n", range->len,range->s,*c,*c,(long)(c-range->s)); return -1; } /* UPDATED + CHECKED */ static inline char *run_language_switch( struct cpl_interpreter *intr ) { char *p; char *kid; char *not_present_node; unsigned short attr_name; int nr_attr; int i,j; str attr = {0,0}; str msg_val = {0,0}; str lang_tag = {0,0}; str lang_subtag = {0,0}; not_present_node = 0; for( i=0 ; iip) ; 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 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; case OTHERWISE_NODE : 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; } DBG("DEBUG:run_language_switch: matching on OTHERWISE node\n"); return get_first_child(kid); case LANGUAGE_NODE : /* check the number of attributes */ nr_attr = NR_OF_ATTR(kid); if (nr_attr<1 || nr_attr>2) { LOG(L_ERR,"ERROR:run_string_switch: incorrect nr of attrs " "(%d) in LANGUAGE node (1 or 2)\n",NR_OF_ATTR(kid)); goto script_error; } /* get the attributes */ p = ATTR_PTR(kid); lang_tag.s = lang_subtag.s = 0; lang_tag.len = lang_subtag.len = 0; for(j=0;j if not yet, do it now * and remember it for the next times */ 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, HDR_ACCEPTLANGUAGE,0)==-1) { 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; } } 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; 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(; iip) ; 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; script_error: return CPL_SCRIPT_ERROR; }