modules_k/cpl-c/cpl_switches.h

00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License 
00019  * along with this program; if not, write to the Free Software 
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  * History:
00023  * -------
00024  * 2003-06-27: file created (bogdan)
00025  */
00026 
00027 #include "cpl_time.h"
00028 #include "../../parser/parse_from.h"
00029 #include "../../parser/parse_uri.h"
00030 
00031 
00032 
00033 /* UPDATED + CHECKED
00034  */
00035 static inline char *run_address_switch( struct cpl_interpreter *intr )
00036 {
00037         static str def_port_str = {"5060",4};
00038         unsigned short field, subfield;
00039         char  *p;
00040         char  *kid;
00041         unsigned short  attr_name;
00042         unsigned short n;
00043         int i;
00044         int k;
00045         str cpl_val;
00046         str *msg_val;
00047         str *uri;
00048         struct sip_uri parsed_uri;
00049 
00050         field = subfield = UNDEF_CHAR;
00051         msg_val = 0;
00052 
00053         p=ATTR_PTR(intr->ip);
00054         /* parse the attributes */
00055         for( i=NR_OF_ATTR(intr->ip) ; i>0 ; i-- ) {
00056                 get_basic_attr( p, attr_name, n, intr, script_error);
00057                 switch (attr_name) {
00058                         case FIELD_ATTR:
00059                                 if (field!=UNDEF_CHAR) {
00060                                         LM_ERR("multiple FIELD attrs found\n");
00061                                         goto script_error;
00062                                 }
00063                                 field = n;
00064                                 break;
00065                         case SUBFIELD_ATTR:
00066                                 if (subfield!=UNDEF_CHAR) {
00067                                         LM_ERR("multiple SUBFIELD attrs found\n");
00068                                         goto script_error;
00069                                 }
00070                                 subfield = n; break;
00071                         default:
00072                                 LM_ERR("unknown attribute "
00073                                         "(%d) in ADDRESS_SWITCH node\n",*p);
00074                                 goto script_error;
00075                 }
00076         }
00077 
00078         if (field==UNDEF_CHAR) {
00079                 LM_ERR("mandatory param FIELD no found\n");
00080                 goto script_error;
00081         }
00082 
00083         /* test the condition from all the sub-nodes */
00084         for( i=0 ; i<NR_OF_KIDS(intr->ip) ; i++ ) {
00085                 kid = intr->ip + KID_OFFSET(intr->ip,i);
00086                 check_overflow_by_ptr( kid+SIMPLE_NODE_SIZE(kid), intr, script_error);
00087                 switch ( NODE_TYPE(kid) ) {
00088                         case NOT_PRESENT_NODE:
00089                                 LM_DBG("NOT_PRESENT node found ->"
00090                                         "skipping (useless in this case)\n");
00091                                 break;
00092                         case OTHERWISE_NODE :
00093                                 if (i!=NR_OF_KIDS(intr->ip)-1) {
00094                                         LM_ERR("OTHERWISE node not found as the last sub-node!\n");
00095                                         goto script_error;
00096                                 }
00097                                 LM_DBG("matching on OTHERWISE node\n");
00098                                 return get_first_child(kid);
00099                         case ADDRESS_NODE :
00100                                 /* check the number of attributes */
00101                                 if (NR_OF_ATTR(kid)!=1) {
00102                                         LM_ERR("incorrect nr of attrs "
00103                                                 "(%d) in ADDRESS node\n",NR_OF_ATTR(kid));
00104                                         goto script_error;
00105                                 }
00106                                 /* get the attribute name */
00107                                 p = ATTR_PTR(kid);
00108                                 get_basic_attr( p, attr_name, cpl_val.len, intr, script_error);
00109                                 if (attr_name!=IS_ATTR && attr_name!=CONTAINS_ATTR &&
00110                                 attr_name!=SUBDOMAIN_OF_ATTR) {
00111                                         LM_ERR("unknown attribute "
00112                                                 "(%d) in ADDRESS node\n",attr_name);
00113                                         goto script_error;
00114                                 }
00115                                 /* get attribute value */
00116                                 get_str_attr( p, cpl_val.s, cpl_val.len, intr, script_error,1);
00117                                 LM_DBG("testing ADDRESS branch "
00118                                         " attr_name=%d attr_val=[%.*s](%d)..\n",
00119                                         attr_name,cpl_val.len,cpl_val.s,cpl_val.len);
00120                                 /* extract the needed value from the message */
00121                                 if (!msg_val) {
00122                                         switch (field) {
00123                                                 case ORIGIN_VAL: /* FROM */
00124                                                         if (!intr->from) {
00125                                                                 /* get the header */
00126                                                                 if (parse_from_header( intr->msg )<0)
00127                                                                         goto runtime_error;
00128                                                                 intr->from = &(get_from(intr->msg)->uri);
00129                                                         }
00130                                                         uri = intr->from;
00131                                                 break;
00132                                                 case DESTINATION_VAL: /* RURI */
00133                                                         if (!intr->ruri)
00134                                                                 intr->ruri = GET_RURI( intr->msg );
00135                                                         uri = intr->ruri;
00136                                                         break;
00137                                                 case ORIGINAL_DESTINATION_VAL: /* TO */
00138                                                         if (!intr->to) {
00139                                                                 /* get and parse the header */
00140                                                                 if (!intr->msg->to &&
00141                                                                 (parse_headers(intr->msg,HDR_TO_F,0)==-1 ||
00142                                                                 !intr->msg->to)) {
00143                                                                         LM_ERR("bad msg or missing TO header\n");
00144                                                                         goto runtime_error;
00145                                                                 }
00146                                                                 intr->to = &(get_to(intr->msg)->uri);
00147                                                         }
00148                                                         uri = intr->to;
00149                                                         break;
00150                                                 default:
00151                                                         LM_ERR("unknown "
00152                                                                 "attribute (%d) in ADDRESS node\n",field);
00153                                                         goto script_error;
00154                                         }
00155                                         LM_DBG("extracted uri is <%.*s>\n",
00156                                                 uri->len, uri->s);
00157                                         switch (subfield) {
00158                                                 case UNDEF_CHAR:
00159                                                         msg_val = uri;
00160                                                         break;
00161                                                 case USER_VAL:
00162                                                         if (parse_uri( uri->s, uri->len, &parsed_uri)<0)
00163                                                                 goto runtime_error;
00164                                                         msg_val = &(parsed_uri.user);
00165                                                         break;
00166                                                 case HOST_VAL:
00167                                                         if (parse_uri( uri->s, uri->len, &parsed_uri)<0)
00168                                                                 goto runtime_error;
00169                                                         msg_val = &(parsed_uri.host);
00170                                                         break;
00171                                                 case PORT_VAL:
00172                                                         if (parse_uri( uri->s, uri->len, &parsed_uri)<0)
00173                                                                 goto runtime_error;
00174                                                         if (parsed_uri.port.len!=0)
00175                                                                 msg_val = &(parsed_uri.port);
00176                                                         else
00177                                                                 msg_val = &def_port_str;
00178                                                         break;
00179                                                 case TEL_VAL:
00180                                                         if (parse_uri( uri->s, uri->len, &parsed_uri)<0)
00181                                                                 goto runtime_error;
00182                                                         if (parsed_uri.user_param_val.len==5 &&
00183                                                         memcmp(parsed_uri.user_param_val.s,"phone",5)==0)
00184                                                                 msg_val = &(parsed_uri.user);
00185                                                         break;
00186                                                 case ADDRESS_TYPE_VAL:
00187                                                 case DISPLAY_VAL:
00188                                                 default:
00189                                                         LM_ERR("unsupported "
00190                                                                 "value attribute (%d) in ADDRESS node\n",
00191                                                                 subfield);
00192                                                         goto script_error;
00193                                         }
00194                                         LM_DBG("extracted val. is <%.*s>\n",
00195                                                 (msg_val==0)?0:msg_val->len, (msg_val==0)?0:msg_val->s);
00196                                 }
00197                                 /* does the value from script match the one from message? */
00198                                 switch (attr_name) {
00199                                         case IS_ATTR:
00200                                                 if ( (!msg_val && !cpl_val.s) ||
00201                                                 (msg_val && msg_val->len==cpl_val.len &&
00202                                                 strncasecmp(msg_val->s,cpl_val.s,cpl_val.len)==0)) {
00203                                                         LM_DBG("matching on ADDRESS node (IS)\n");
00204                                                         return get_first_child(kid);
00205                                                 }
00206                                                 break;
00207                                         case CONTAINS_ATTR:
00208                                                 if (subfield!=DISPLAY_VAL) {
00209                                                         LM_WARN("operator "
00210                                                         "CONTAINS applies only to DISPLAY -> ignored\n");
00211                                                 } else {
00212                                                         if ( msg_val && cpl_val.len<=msg_val->len &&
00213                                                         strcasestr_str(msg_val, &cpl_val)!=0 ) {
00214                                                                 LM_DBG("matching on "
00215                                                                         "ADDRESS node (CONTAINS)\n");
00216                                                                 return get_first_child(kid);
00217                                                         }
00218                                                 }
00219                                                 break;
00220                                         case SUBDOMAIN_OF_ATTR:
00221                                                 switch (subfield) {
00222                                                         case HOST_VAL:
00223                                                                 k = msg_val->len - cpl_val.len;
00224                                                                 if (k>=0 && (k==0 || msg_val->s[k-1]=='.') &&
00225                                                                 !strncasecmp(cpl_val.s,msg_val->s+k,cpl_val.len)
00226                                                                 ) {
00227                                                                         LM_DBG("matching on "
00228                                                                                 "ADDRESS node (SUBDOMAIN_OF)\n");
00229                                                                         return get_first_child(kid);
00230                                                                 }
00231                                                                 break;
00232                                                         case TEL_VAL:
00233                                                                 if (msg_val==0) break;
00234                                                                 if (msg_val->len>=cpl_val.len && !strncasecmp(
00235                                                                 cpl_val.s,msg_val->s,cpl_val.len)) {
00236                                                                         LM_DBG("matching on "
00237                                                                                 "ADDRESS node (SUBDOMAIN_OF)\n");
00238                                                                         return get_first_child(kid);
00239                                                                 }
00240                                                                 break;
00241                                                         default:
00242                                                                 LM_WARN("operator SUBDOMAIN_OF applies "
00243                                                                         "only to HOST or TEL -> ignored\n");
00244                                                 }
00245                                                 break;
00246                                 }
00247                                 break;
00248                         default:
00249                                 LM_ERR("unknown output node type "
00250                                         "(%d) for ADDRESS_SWITCH node\n",NODE_TYPE(kid));
00251                                 goto script_error;
00252                 }
00253         }
00254 
00255         /* none of the branches of ADDRESS_SWITCH matched -> go for default */
00256         return DEFAULT_ACTION;
00257 runtime_error:
00258         return CPL_RUNTIME_ERROR;
00259 script_error:
00260         return CPL_SCRIPT_ERROR;
00261 }
00262 
00263 
00264 
00265 /* UPDATED + CHECKED
00266  */
00267 static inline char *run_string_switch( struct cpl_interpreter *intr )
00268 {
00269         unsigned short field;
00270         char *p;
00271         char *kid;
00272         char *not_present_node;
00273         unsigned short attr_name;
00274         int i;
00275         str cpl_val;
00276         str msg_val;
00277 
00278         not_present_node = 0;
00279         msg_val.s = 0;
00280         msg_val.len = 0;
00281 
00282         /* parse the attribute */
00283         if (NR_OF_ATTR(intr->ip)!=1) {
00284                 LM_ERR("node should have 1 attr, not"
00285                         " (%d)\n",NR_OF_ATTR(intr->ip));
00286                 goto script_error;
00287         }
00288         p=ATTR_PTR(intr->ip);
00289         get_basic_attr( p, attr_name, field, intr, script_error);
00290         if (attr_name!=FIELD_ATTR) {
00291                 LM_ERR("unknown param type (%d)"
00292                         " for STRING_SWITCH node\n",*p);
00293                 goto script_error;
00294         }
00295 
00296         for( i=0 ; i<NR_OF_KIDS(intr->ip) ; i++ ) {
00297                 kid = intr->ip + KID_OFFSET(intr->ip,i);
00298                 check_overflow_by_ptr( kid+SIMPLE_NODE_SIZE(kid), intr, script_error);
00299                 switch ( NODE_TYPE(kid) ) {
00300                         case NOT_PRESENT_NODE:
00301                                 if (not_present_node) {
00302                                         LM_ERR("NOT_PRESENT node found twice!\n");
00303                                         goto script_error;
00304                                 }
00305                                 not_present_node = kid;
00306                                 break;
00307                         case OTHERWISE_NODE :
00308                                 if (i!=NR_OF_KIDS(intr->ip)-1) {
00309                                         LM_ERR("OTHERWISE node "
00310                                                 "not found as the last sub-node!\n");
00311                                         goto script_error;
00312                                 }
00313                                 LM_DBG("matching on OTHERWISE node\n");
00314                                 return get_first_child(kid);
00315                         case STRING_NODE :
00316                                 /* check the number of attributes */
00317                                 if (NR_OF_ATTR(kid)!=1) {
00318                                         LM_ERR("incorrect nr of attrs "
00319                                                 "(%d) in STRING node (expected 1)\n",NR_OF_ATTR(kid));
00320                                         goto script_error;
00321                                 }
00322                                 /* get the attribute name */
00323                                 p = ATTR_PTR(kid);
00324                                 get_basic_attr( p, attr_name, cpl_val.len, intr, script_error);
00325                                 if (attr_name!=IS_ATTR && attr_name!=CONTAINS_ATTR ) {
00326                                         LM_ERR("unknown attribute "
00327                                                 "(%d) in STRING node\n",attr_name);
00328                                         goto script_error;
00329                                 }
00330                                 /* get attribute value */
00331                                 get_str_attr( p, cpl_val.s, cpl_val.len, intr, script_error,1);
00332                                 LM_DBG("testing STRING branch "
00333                                         "attr_name=%d attr_val=[%.*s](%d)..\n",
00334                                         attr_name,cpl_val.len,cpl_val.s,cpl_val.len);
00335                                 if (!msg_val.s) {
00336                                         switch (field) {
00337                                                 case SUBJECT_VAL: /* SUBJECT */
00338                                                         if (intr->subject==STR_NOT_FOUND)
00339                                                                 goto not_present;
00340                                                         if (!intr->subject) {
00341                                                                 /* get the subject header */
00342                                                                 if (!intr->msg->subject) {
00343                                                                         if (parse_headers(intr->msg,
00344                                                                         HDR_SUBJECT_F,0)==-1) {
00345                                                                                 LM_ERR("bad SUBJECT header\n");
00346                                                                                 goto runtime_error;
00347                                                                         } else if (!intr->msg->subject) {
00348                                                                                 /* hdr not present */
00349                                                                                 intr->subject = STR_NOT_FOUND;
00350                                                                                 goto not_present;
00351                                                                         }
00352                                                                 }
00353                                                                 intr->subject =
00354                                                                         &(intr->msg->subject->body);
00355                                                         }
00356                                                         trim_len( msg_val.len,msg_val.s,
00357                                                                 *(intr->subject));
00358                                                         break;
00359                                                 case ORGANIZATION_VAL: /* ORGANIZATION */
00360                                                         if (intr->organization==STR_NOT_FOUND)
00361                                                                 goto not_present;
00362                                                         if (!intr->organization) {
00363                                                                 /* get the organization header */
00364                                                                 if (!intr->msg->organization) {
00365                                                                         if (parse_headers(intr->msg,
00366                                                                         HDR_ORGANIZATION_F,0)==-1) {
00367                                                                                 LM_ERR("bad ORGANIZATION hdr\n");
00368                                                                                 goto runtime_error;
00369                                                                         } else if (!intr->msg->organization) {
00370                                                                                 /* hdr not present */
00371                                                                                 intr->organization = STR_NOT_FOUND;
00372                                                                                 goto not_present;
00373                                                                         }
00374                                                                 }
00375                                                                 intr->organization =
00376                                                                         &(intr->msg->organization->body);
00377                                                         }
00378                                                         trim_len( msg_val.len,msg_val.s,
00379                                                                 *(intr->organization));
00380                                                         break;
00381                                                 case USER_AGENT_VAL: /* User Agent */
00382                                                         if (intr->user_agent==STR_NOT_FOUND)
00383                                                                 goto not_present;
00384                                                         if (!intr->user_agent) {
00385                                                                 /* get the  header */
00386                                                                 if (!intr->msg->user_agent) {
00387                                                                         if (parse_headers(intr->msg,
00388                                                                         HDR_USERAGENT_F,0)==-1) {
00389                                                                                 LM_ERR("bad USERAGENT hdr\n");
00390                                                                                 goto runtime_error;
00391                                                                         } else if (!intr->msg->user_agent) {
00392                                                                                 /* hdr not present */
00393                                                                                 intr->user_agent = STR_NOT_FOUND;
00394                                                                                 goto not_present;
00395                                                                         }
00396                                                                 }
00397                                                                 intr->user_agent =
00398                                                                         &(intr->msg->user_agent->body);
00399                                                         }
00400                                                         trim_len( msg_val.len,msg_val.s,
00401                                                                 *(intr->user_agent));
00402                                                         break;
00403                                                 default:
00404                                                         LM_ERR("unknown "
00405                                                                 "attribute (%d) in STRING node\n",field);
00406                                                         goto script_error;
00407                                         }
00408                                         LM_DBG("extracted msg string is "
00409                                                 "<%.*s>\n",msg_val.len, msg_val.s);
00410                                 }
00411                                 /* does the value from script match the one from message? */
00412                                 switch (attr_name) {
00413                                         case IS_ATTR:
00414                                                 if ( (!msg_val.s && !cpl_val.s) ||
00415                                                 (msg_val.len==cpl_val.len &&
00416                                                 strncasecmp(msg_val.s,cpl_val.s,cpl_val.len)==0)) {
00417                                                         LM_DBG("matching on STRING node (IS)\n");
00418                                                         return get_first_child(kid);
00419                                                 }
00420                                                 break;
00421                                         case CONTAINS_ATTR:
00422                                                 if (cpl_val.len<=msg_val.len &&
00423                                                 strcasestr_str(&msg_val, &cpl_val)!=0 ) {
00424                                                         LM_DBG("matching on STRING node (CONTAINS)\n");
00425                                                         return get_first_child(kid);
00426                                                 }
00427                                                 break;
00428                                 }
00429                                 break;
00430                         default:
00431                                 LM_ERR("unknown output node type "
00432                                         "(%d) for STRING_SWITCH node\n",NODE_TYPE(kid));
00433                                 goto script_error;
00434                 }
00435         }
00436 
00437         /* none of the branches of STRING_SWITCH matched -> go for default */
00438         return DEFAULT_ACTION;
00439 not_present:
00440         LM_DBG("required hdr not present in sip msg\n");
00441         if (not_present_node)
00442                 return get_first_child(not_present_node);
00443         /* look for the NOT_PRESENT node */
00444         LM_DBG("searching for NOT_PRESENT sub-node..\n");
00445         for(; i<NR_OF_KIDS(intr->ip) ; i++ ) {
00446                 kid = intr->ip + KID_OFFSET(intr->ip,i);
00447                 check_overflow_by_ptr( kid+SIMPLE_NODE_SIZE(kid), intr, script_error);
00448                 if (NODE_TYPE(kid)==NOT_PRESENT_NODE)
00449                         return get_first_child(kid);
00450         }
00451         return DEFAULT_ACTION;
00452 runtime_error:
00453         return CPL_RUNTIME_ERROR;
00454 script_error:
00455         return CPL_SCRIPT_ERROR;
00456 }
00457 
00458 
00459 
00460 /* UPDATED + CHECKED
00461  */
00462 static inline char *run_priority_switch( struct cpl_interpreter *intr )
00463 {
00464         static str default_val={"normal",6};
00465         unsigned short n;
00466         char *p;
00467         char *kid;
00468         char *not_present_node;
00469         unsigned short attr_name;
00470         unsigned short attr_val;
00471         unsigned short msg_attr_val;
00472         unsigned short msg_prio;
00473         int i;
00474         str cpl_val = {0,0};
00475         str msg_val = {0,0};
00476 
00477         not_present_node = 0;
00478         msg_attr_val = NORMAL_VAL;
00479 
00480         for( i=0 ; i<NR_OF_KIDS(intr->ip) ; i++ ) {
00481                 kid = intr->ip + KID_OFFSET(intr->ip,i);
00482                 check_overflow_by_ptr( kid+SIMPLE_NODE_SIZE(kid), intr, script_error);
00483                 switch ( NODE_TYPE(kid) ) {
00484                         case NOT_PRESENT_NODE:
00485                                 if (not_present_node) {
00486                                         LM_ERR("NOT_PRESENT node found twice!\n");
00487                                         goto script_error;
00488                                 }
00489                                 not_present_node = kid;
00490                                 break;
00491                         case OTHERWISE_NODE :
00492                                 if (i!=NR_OF_KIDS(intr->ip)-1) {
00493                                         LM_ERR("OTHERWISE node not found as the last sub-node!\n");
00494                                         goto script_error;
00495                                 }
00496                                 LM_DBG("matching on OTHERWISE node\n");
00497                                 return get_first_child(kid);
00498                         case PRIORITY_NODE :
00499                                 if (NR_OF_ATTR(kid)!=1)
00500                                         goto script_error;
00501                                 /* get the attribute */
00502                                 p = ATTR_PTR(kid);
00503                                 get_basic_attr( p, attr_name, attr_val, intr, script_error);
00504                                 if (attr_name!=LESS_ATTR && attr_name!=GREATER_ATTR &&
00505                                 attr_name!=EQUAL_ATTR){
00506                                         LM_ERR("unknown attribute "
00507                                                 "(%d) in PRIORITY node\n",attr_name);
00508                                         goto script_error;
00509                                 }
00510                                 /* attribute's encoded value */
00511                                 if (attr_val!=EMERGENCY_VAL && attr_val!=URGENT_VAL &&
00512                                 attr_val!=NORMAL_VAL && attr_val!=NON_URGENT_VAL &&
00513                                 attr_val!=UNKNOWN_PRIO_VAL) {
00514                                         LM_ERR("unknown encoded "
00515                                                 "value (%d) for attribute (*d) in PRIORITY node\n",*p);
00516                                         goto script_error;
00517                                 }
00518                                 if (attr_val==UNKNOWN_PRIO_VAL) {
00519                                         if (attr_name!=EQUAL_ATTR) {
00520                                                 LM_ERR("bad PRIORITY"
00521                                                         " branch: attr=EQUAL doesn't match val=UNKNOWN\n");
00522                                                 goto script_error;
00523                                         }
00524                                         /* if the attr is UNKNOWN, its string value is present  */
00525                                         get_basic_attr(p, n,cpl_val.len, intr, script_error);
00526                                         if (n!=PRIOSTR_ATTR) {
00527                                                 LM_ERR("expected PRIOSTR"
00528                                                         "(%d) attr, found (%d)\n",PRIOSTR_ATTR,n);
00529                                                 goto script_error;
00530                                         }
00531                                         get_str_attr(p, cpl_val.s, cpl_val.len,intr,script_error,1);
00532                                 }
00533 
00534                                 LM_DBG("testing PRIORITY branch "
00535                                         "(attr=%d,val=%d) [%.*s](%d)..\n",
00536                                         attr_name,attr_val,cpl_val.len,cpl_val.s,cpl_val.len);
00537                                 if (!msg_val.s) {
00538                                         if (!intr->priority) {
00539                                                 /* get the PRIORITY header from message */
00540                                                 if (!intr->msg->priority) {
00541                                                         if (parse_headers(intr->msg,HDR_PRIORITY_F,
00542                                                         0)==-1) {
00543                                                                 LM_ERR("bad sip msg or PRIORITY header !\n");
00544                                                                 goto runtime_error;
00545                                                         } else if (!intr->msg->priority) {
00546                                                                 LM_NOTICE("missing PRIORITY header -> using "
00547                                                                         "default value \"normal\"!\n");
00548                                                                 intr->priority = &default_val;
00549                                                         } else {
00550                                                                 intr->priority =
00551                                                                         &(intr->msg->priority->body);
00552                                                         }
00553                                                 } else {
00554                                                         intr->priority =
00555                                                                 &(intr->msg->priority->body);
00556                                                 }
00557                                         }
00558                                         trim_len( msg_val.len, msg_val.s, *(intr->priority));
00559                                         /* encode attribute's value from SIP message */
00560                                         if ( msg_val.len==EMERGENCY_STR_LEN &&
00561                                         !strncasecmp(msg_val.s,EMERGENCY_STR,msg_val.len) ) {
00562                                                 msg_attr_val = EMERGENCY_VAL;
00563                                         } else if ( msg_val.len==URGENT_STR_LEN &&
00564                                         !strncasecmp(msg_val.s,URGENT_STR,msg_val.len) ) {
00565                                                 msg_attr_val = URGENT_VAL;
00566                                         } else if ( msg_val.len==NORMAL_STR_LEN &&
00567                                         !strncasecmp(msg_val.s,NORMAL_STR,msg_val.len) ) {
00568                                                 msg_attr_val = NORMAL_VAL;
00569                                         } else if ( msg_val.len==NON_URGENT_STR_LEN &&
00570                                         !strncasecmp(msg_val.s,NON_URGENT_STR,msg_val.len) ) {
00571                                                 msg_attr_val = NON_URGENT_VAL;
00572                                         } else {
00573                                                 msg_attr_val = UNKNOWN_PRIO_VAL;
00574                                         }
00575                                         LM_DBG("extracted msg priority is "
00576                                                 "<%.*s> decoded as [%d]\n",
00577                                                 msg_val.len,msg_val.s,msg_attr_val);
00578                                 }
00579                                 LM_DBG("using msg string <%.*s>\n",
00580                                         msg_val.len, msg_val.s);
00581                                 /* attr_val (from cpl) cannot be UNKNOWN - we already
00582                                  * check it -> check only for msg_attr_val for non-EQUAL op */
00583                                 if (msg_attr_val==UNKNOWN_PRIO_VAL && attr_name!=EQUAL_ATTR) {
00584                                         LM_NOTICE("UNKNOWN "
00585                                                 "value found in sip_msg when string a LESS/GREATER "
00586                                                 "cmp -> force the value to default \"normal\"\n");
00587                                         msg_prio = NORMAL_VAL;
00588                                 } else {
00589                                         msg_prio = msg_attr_val;
00590                                 }
00591                                 /* does the value from script match the one from message? */
00592                                 switch (attr_name) {
00593                                         case LESS_ATTR:
00594                                                 switch (attr_val) {
00595                                                         case EMERGENCY_VAL:
00596                                                                 if (msg_prio!=EMERGENCY_VAL) break; /*OK*/
00597                                                                 else continue; /* for cycle for all kids */
00598                                                         case URGENT_VAL:
00599                                                                 if (msg_prio!=EMERGENCY_VAL &&
00600                                                                         msg_prio!=URGENT_VAL) break; /* OK */
00601                                                                 else continue; /* for cycle for all kids */
00602                                                         case NORMAL_VAL:
00603                                                                 if (msg_prio==NON_URGENT_VAL) break; /*OK*/
00604                                                                 else continue; /* for cycle for all kids */
00605                                                         case NON_URGENT_VAL:
00606                                                                 continue; /* for cycle for all kids */
00607                                                 }
00608                                                 break;
00609                                         case GREATER_ATTR:
00610                                                 switch (attr_val) {
00611                                                         case EMERGENCY_VAL:
00612                                                                 continue; /* for cycle for all kids */
00613                                                         case URGENT_VAL:
00614                                                                 if (msg_prio!=EMERGENCY_VAL) break; /*OK*/
00615                                                                 else continue; /* for cycle for all kids */
00616                                                         case NORMAL_VAL:
00617                                                                 if (msg_prio!=NON_URGENT_VAL &&
00618                                                                         msg_prio!=NORMAL_VAL) break; /*OK*/
00619                                                                 else continue; /* for cycle for all kids */
00620                                                         case NON_URGENT_VAL:
00621                                                                 if (msg_prio!=NON_URGENT_VAL) break; /*OK*/
00622                                                                 else continue; /* for cycle for all kids */
00623                                                 }
00624                                                 break;
00625                                         case EQUAL_ATTR:
00626                                                 if ( attr_val==msg_prio ) {
00627                                                         if (attr_val==UNKNOWN_PRIO_VAL) {
00628                                                                 if ( msg_val.len==cpl_val.len &&
00629                                                                 !strncasecmp(msg_val.s,cpl_val.s,msg_val.len)){
00630                                                                         break; /* OK */
00631                                                                 }
00632                                                         } else {
00633                                                                 break; /* OK */
00634                                                         }
00635                                                 }
00636                                                 continue; /* for cycle for all kids */
00637                                                 break;
00638                                 } /* end switch for attr_name */
00639                                 LM_DBG("matching current PRIORITY node\n");
00640                                 return get_first_child(kid);
00641                                 break;
00642                         default:
00643                                 LM_ERR("unknown output node type"
00644                                         " (%d) for PRIORITY_SWITCH node\n",NODE_TYPE(kid));
00645                                 goto script_error;
00646                 } /* end switch for NODE_TYPE */
00647         } /* end for for all kids */
00648 
00649         /* none of the branches of PRIORITY_SWITCH matched -> go for default */
00650         return DEFAULT_ACTION;
00651 runtime_error:
00652         return CPL_RUNTIME_ERROR;
00653 script_error:
00654         return CPL_SCRIPT_ERROR;
00655 }
00656 
00657 
00658 
00659 inline static int set_TZ(char *tz_env)
00660 {
00661         LM_DBG("switching TZ as \"%s\"\n",tz_env);
00662         if (putenv( tz_env )==-1) {
00663                 LM_ERR("setenv failed -> unable to set TZ "
00664                         " \"%s\"\n",tz_env);
00665                 return -1;
00666         }
00667         tzset(); /* just to be sure */
00668         return 0;
00669 }
00670 
00671 
00672 
00673 /* UPDATED + CHECKED
00674  */
00675 static inline char *run_time_switch( struct cpl_interpreter *intr )
00676 {
00677         char  *p;
00678         char  *kid;
00679         char  *attr_str;
00680         unsigned short attr_name;
00681         unsigned short attr_len;
00682         unsigned char  flags = 0;
00683         int nr_attrs;
00684         int i,j;
00685         str user_tz = {0,0};
00686         ac_tm_t att;
00687         tmrec_t trt;
00688 
00689         LM_DBG("checking recv. time stamp <%d>\n",
00690                 intr->recv_time);
00691         switch (NR_OF_ATTR(intr->ip)) {
00692                 case 1:
00693                         p = ATTR_PTR(intr->ip);
00694                         get_basic_attr( p, attr_name, user_tz.len, intr, script_error);
00695                         if (attr_name!=TZID_ATTR) {
00696                                 LM_ERR("bad attribute -> "
00697                                         " expected=%d, found=%d\n",TZID_ATTR,attr_name);
00698                                 goto script_error;
00699                         }
00700                         get_str_attr( p, user_tz.s, user_tz.len, intr, script_error, 1);
00701                 case 0:
00702                         break;
00703                 default:
00704                         LM_ERR("incorrect number of attr ->"
00705                                 " found=%d expected=(0,1)\n",NR_OF_ATTR(intr->ip));
00706                         goto script_error;
00707         }
00708 
00709         if (user_tz.s && user_tz.len) {
00710                 if (set_TZ(user_tz.s)==-1)
00711                         goto runtime_error;
00712                 flags |= (1<<7);
00713         }
00714 
00715         for( i=0 ; i<NR_OF_KIDS(intr->ip) ; i++ ) {
00716                 kid = intr->ip + KID_OFFSET(intr->ip,i);
00717                 check_overflow_by_ptr( kid+SIMPLE_NODE_SIZE(kid), intr, script_error);
00718                 switch ( NODE_TYPE(kid) ) {
00719                         case NOT_PRESENT_NODE:
00720                                 LM_DBG("NOT_PRESENT node found ->"
00721                                         "skipping (useless in this case)\n");
00722                                 break;
00723                         case OTHERWISE_NODE :
00724                                 if (i!=NR_OF_KIDS(intr->ip)-1) {
00725                                         LM_ERR("OTHERWISE node "
00726                                                 "not found as the last sub-node!\n");
00727                                         goto script_error;
00728                                 }
00729                                 LM_DBG("matching on OTHERWISE node\n");
00730                                 return get_first_child(kid);
00731                         case TIME_NODE :
00732                                 /* init structures */
00733                                 memset( &att, 0, sizeof(att));
00734                                 memset( &trt, 0, sizeof(trt));
00735                                 if(ac_tm_set_time( &att, intr->recv_time))
00736                                         goto runtime_error;
00737                                 /* let's see how many attributes we have */
00738                                 nr_attrs = NR_OF_ATTR(kid);
00739                                 /* get the attributes */
00740                                 p = ATTR_PTR(kid);
00741                                 for(j=0;j<nr_attrs;j++) {
00742                                         /* get the attribute */
00743                                         get_basic_attr( p, attr_name, attr_len, intr, script_error);
00744                                         get_str_attr( p, attr_str, attr_len, intr, script_error,1);
00745                                         /* process the attribute */
00746                                         LM_DBG("attribute [%d] found :"
00747                                                 "[%s]\n",attr_name, attr_str);
00748                                         switch (attr_name) {
00749                                                 case DTSTART_ATTR:
00750                                                         if( !attr_str || tr_parse_dtstart(&trt, attr_str))
00751                                                                 goto parse_err;
00752                                                         flags ^= (1<<0);
00753                                                         break;
00754                                                 case DTEND_ATTR:
00755                                                         if( !attr_str || tr_parse_dtend(&trt, attr_str))
00756                                                                 goto parse_err;
00757                                                         flags ^= (1<<1);
00758                                                         break;
00759                                                 case DURATION_ATTR:
00760                                                         if( !attr_str || tr_parse_duration(&trt, attr_str))
00761                                                                 goto parse_err;
00762                                                         flags ^= (1<<1);
00763                                                         break;
00764                                                 case FREQ_ATTR:
00765                                                         if( attr_str && tr_parse_freq(&trt, attr_str))
00766                                                                 goto parse_err;
00767                                                         break;
00768                                                 case UNTIL_ATTR:
00769                                                         if( attr_str && tr_parse_until(&trt, attr_str))
00770                                                                 goto parse_err;
00771                                                         break;
00772                                                 case INTERVAL_ATTR:
00773                                                         if( attr_str && tr_parse_interval(&trt, attr_str))
00774                                                                 goto parse_err;
00775                                                         break;
00776                                                 case BYDAY_ATTR:
00777                                                         if( attr_str && tr_parse_byday(&trt, attr_str))
00778                                                                 goto parse_err;
00779                                                         break;
00780                                                 case BYMONTHDAY_ATTR:
00781                                                         if( attr_str && tr_parse_bymday(&trt, attr_str))
00782                                                                 goto parse_err;
00783                                                         break;
00784                                                 case BYYEARDAY_ATTR:
00785                                                         if( attr_str && tr_parse_byyday(&trt, attr_str))
00786                                                                 goto parse_err;
00787                                                         break;
00788                                                 case BYMONTH_ATTR:
00789                                                         if( attr_str && tr_parse_bymonth(&trt, attr_str))
00790                                                                 goto parse_err;
00791                                                         break;
00792                                                 case BYWEEKNO_ATTR:
00793                                                         if( attr_str && tr_parse_byweekno(&trt, attr_str))
00794                                                                 goto parse_err;
00795                                                         break;
00796                                                 case WKST_ATTR:
00797                                                         if( attr_str && tr_parse_wkst(&trt, attr_str))
00798                                                                 goto parse_err;
00799                                                         break;
00800                                                 default:
00801                                                         LM_ERR("unsupported attribute [%d] found in TIME "
00802                                                                 "node\n",attr_name);
00803                                                         goto script_error;
00804                                         } /* end attribute switch */
00805                                 } /* end for*/
00806                                 /* check the mandatory attributes */
00807                                 if ( (flags&0x03)!=((1<<0)|(1<<1)) ) {
00808                                         LM_ERR("attribute DTSTART"
00809                                                 ",DTEND,DURATION missing or multi-present\n");
00810                                         goto script_error;
00811                                 }
00812                                 /* does the recv_time match the specified interval?  */
00813                                 j = check_tmrec( &trt, &att, 0);
00814                                 /* restore the orig TZ */
00815                                 if ( flags&(1<<7) )
00816                                         set_TZ(cpl_env.orig_tz.s);
00817                                 /* free structs that I don't need any more */
00818                                 ac_tm_free( &att );
00819                                 tmrec_free( &trt );
00820                                 /* let's see the result ;-) */
00821                                 switch  (j) {
00822                                         case 0:
00823                                                 LM_DBG("matching current TIME node\n");
00824                                                 return get_first_child(kid);
00825                                         case -1:
00826                                                 LM_ERR("check_tmrec "
00827                                                         "ret. err. when testing time cond. !\n");
00828                                                 goto runtime_error;
00829                                                 break;
00830                                         case 1:
00831                                                 LM_DBG("time cond. doesn't match !\n");
00832                                                 break;
00833                                 }
00834                                 break;
00835                         default:
00836                                 LM_ERR("unknown output node"
00837                                         " type (%d) for PRIORITY_SWITCH node\n",NODE_TYPE(kid));
00838                                 goto script_error;
00839                 } /* end switch for NODE_TYPE */
00840         } /* end for for all kids */
00841 
00842 
00843         /* none of the branches of TIME_SWITCH matched -> go for default */
00844         ac_tm_free( &att );
00845         tmrec_free( &trt );
00846         return DEFAULT_ACTION;
00847 runtime_error:
00848         if ( flags&(1<<7) )
00849                 set_TZ(cpl_env.orig_tz.s);
00850         ac_tm_free( &att );
00851         tmrec_free( &trt );
00852         return CPL_RUNTIME_ERROR;
00853 parse_err:
00854         LM_ERR("error parsing attr [%d][%s]\n",
00855                 attr_name,attr_str?(char*)attr_str:"NULL");
00856 script_error:
00857         if ( flags&(1<<7) )
00858                 set_TZ(cpl_env.orig_tz.s);
00859         ac_tm_free( &att );
00860         tmrec_free( &trt );
00861         return CPL_SCRIPT_ERROR;
00862 }
00863 
00864 
00865 
00866 inline static int is_lang_tag_matching(str *range,str *cpl_tag,str *cpl_subtag)
00867 {
00868         char *c;
00869         char *end;
00870         str tag = {0,0};
00871         str subtag = {0,0};
00872 
00873         c = range->s;
00874         end = range->s + range->len;
00875 
00876         while(c<end) {
00877                 /* eat all spaces to first letter */
00878                 while(c<end && (*c==' ' || *c=='\t')) c++;
00879                 if (c==end) goto error;
00880                 /* init tag and subtag */
00881                 tag.len = 0;
00882                 subtag.len = 0;
00883                 /* get the tag */
00884                 tag.s = c;
00885                 if (*c=='*' && (c+1==end||*(c+1)!='-')) {
00886                         tag.len++;
00887                         c++;
00888                 } else while (c<end && ((*c)|0x20)>='a' && ((*c)|0x20)<='z' ) {
00889                         /*DBG("--- tag ---> <%c>[%d]\n",*c,*c);*/
00890                         tag.len++;
00891                         c++;
00892                 }
00893                 if (tag.len==0) goto error;
00894                 if (c<end && *c=='-') {
00895                         /* go for the subtag */
00896                         subtag.s = ++c;
00897                         while (c<end && ((*c)|0x20)>='a' && ((*c)|0x20)<='z' ) {
00898                                 /*DBG("--- subtag ---> <%c>[%d]\n",*c,*c);*/
00899                                 subtag.len++;
00900                                 c++;
00901                         }
00902                         if (subtag.len==0) goto error;
00903                 } else {
00904                         subtag.s = 0;
00905                 }
00906                 if (c<end && *c==';') {
00907                         /* eat all the params to the ',' */
00908                         while(c<end && *c!=',') c++;
00909                         if (c==end) goto no_matche;
00910                 }
00911                 while(c<end && (*c==' '||*c=='\t')) c++;
00912                 if (c==end || *c==',') {
00913                         /* do compare */
00914                         LM_DBG("testing range [%.*s]-[%.*s] against tag [%.*s]-[%.*s]\n",
00915                                 tag.len,tag.s,subtag.len,subtag.s,
00916                                 cpl_tag->len,cpl_tag->s,cpl_subtag->len,cpl_subtag->s);
00917                         /* language range of "*" is ignored for the purpose of matching*/
00918                         if ( !(tag.len==1 && *tag.s=='*') ) {
00919                                 /* does the language tag matches ? */
00920                                 if (tag.len==cpl_tag->len && !strncasecmp(tag.s,cpl_tag->s,
00921                                 tag.len)) {
00922                                         /* if the subtag of the range is void -> matche */
00923                                         if (subtag.len==0)
00924                                                 return 1;
00925                                         /* the subtags equals -> matche */
00926                                         if (subtag.len==cpl_subtag->len &&
00927                                         !strncasecmp(subtag.s,cpl_subtag->s,subtag.len) )
00928                                                 return 1;
00929                                 }
00930                         }
00931                         /* if ',' go for the next language range */
00932                         if (*c==',') c++;
00933                 } else {
00934                         goto error;
00935                 }
00936         }
00937 
00938 no_matche:
00939         return 0;
00940 error:
00941         LM_ERR("parse error in Accept-"
00942                 "Language body <%.*s> at char <%c>[%d] offset %ld!\n",
00943                 range->len,range->s,*c,*c,(long)(c-range->s));
00944         return -1;
00945 }
00946 
00947 
00948 
00949 /* UPDATED + CHECKED
00950  */
00951 static inline char *run_language_switch( struct cpl_interpreter *intr )
00952 {
00953         char  *p;
00954         char  *kid;
00955         char  *not_present_node;
00956         unsigned short attr_name;
00957         int nr_attr;
00958         int i,j;
00959         str attr = {0,0};
00960         str msg_val = {0,0};
00961         str lang_tag = {0,0};
00962         str lang_subtag = {0,0};
00963 
00964         not_present_node = 0;
00965 
00966         for( i=0 ; i<NR_OF_KIDS(intr->ip) ; i++ ) {
00967                 kid = intr->ip + KID_OFFSET(intr->ip,i);
00968                 check_overflow_by_ptr( kid+SIMPLE_NODE_SIZE(kid), intr, script_error);
00969                 switch ( NODE_TYPE(kid) ) {
00970                         case NOT_PRESENT_NODE:
00971                                 if (not_present_node) {
00972                                         LM_ERR("NOT_PRESENT node found twice!\n");
00973                                         goto script_error;
00974                                 }
00975                                 not_present_node = kid;
00976                                 break;
00977                         case OTHERWISE_NODE :
00978                                 if (i!=NR_OF_KIDS(intr->ip)-1) {
00979                                         LM_ERR("OTHERWISE node "
00980                                                 "not found as the last sub-node!\n");
00981                                         goto script_error;
00982                                 }
00983                                 LM_DBG("matching on OTHERWISE node\n");
00984                                 return get_first_child(kid);
00985                         case LANGUAGE_NODE :
00986                                 /* check the number of attributes */
00987                                 nr_attr = NR_OF_ATTR(kid);
00988                                 if (nr_attr<1 || nr_attr>2) {
00989                                         LM_ERR("incorrect nr of attrs "
00990                                                 "(%d) in LANGUAGE node (1 or 2)\n",NR_OF_ATTR(kid));
00991                                         goto script_error;
00992                                 }
00993                                 /* get the attributes */
00994                                 p = ATTR_PTR(kid);
00995                                 lang_tag.s = lang_subtag.s = 0;
00996                                 lang_tag.len = lang_subtag.len = 0;
00997                                 for(j=0;j<nr_attr;j++) {
00998                                         get_basic_attr( p, attr_name, attr.len, intr, script_error);
00999                                         get_str_attr( p, attr.s, attr.len, intr, script_error,0);
01000                                         if (attr_name==MATCHES_TAG_ATTR ) {
01001                                                 lang_tag = attr;
01002                                                 LM_DBG("language-tag is"
01003                                                         " [%.*s]\n",attr.len,attr.s);
01004                                         }else if (attr_name==MATCHES_SUBTAG_ATTR) {
01005                                                 lang_subtag = attr;
01006                                                 LM_DBG("language-subtag"
01007                                                         " is [%.*s]\n",attr.len,attr.s);
01008                                         }else {
01009                                                 LM_ERR("unknown attribute"
01010                                                 " (%d) in LANGUAGE node\n",attr_name);
01011                                                 goto script_error;
01012                                         }
01013                                 }
01014                                 
01015                                 /* get the value from the SIP message -> if not yet, do it now
01016                                  * and remember it for the next times */
01017                                 if (!msg_val.s) {
01018                                         if (intr->accept_language==STR_NOT_FOUND)
01019                                                 goto not_present;
01020                                         if (!intr->accept_language) {
01021                                                 /* get the accept_language header */
01022                                                 if (!intr->msg->accept_language) {
01023                                                         if (parse_headers(intr->msg,
01024                                                         HDR_ACCEPTLANGUAGE_F,0)==-1) {
01025                                                                 LM_ERR("bad ACCEPT_LANGUAGE header\n");
01026                                                                 goto runtime_error;
01027                                                         } else if (!intr->msg->accept_language) {
01028                                                                 /* hdr not present */
01029                                                                 intr->accept_language = STR_NOT_FOUND;
01030                                                                 goto not_present;
01031                                                         }
01032                                                 }
01033                                                 intr->subject =
01034                                                         &(intr->msg->accept_language->body);
01035                                         }
01036                                 }
01037                                 trim_len( msg_val.len,msg_val.s, *(intr->subject));
01038                                 LM_DBG("extracted msg string is "
01039                                         "<%.*s>\n",msg_val.len, msg_val.s);
01040                                 
01041                                 /* does the value from script match the one from message? */
01042                                 if (msg_val.len && msg_val.s) {
01043                                         j = is_lang_tag_matching(&msg_val,&lang_tag,&lang_subtag);
01044                                         if (j==1) {
01045                                                 LM_DBG("matching on LANGUAGE node\n");
01046                                                 return get_first_child(kid);
01047                                         }else if (j==-1) {
01048                                                 goto runtime_error;
01049                                         }
01050                                 }
01051                                 break;
01052                         default:
01053                                 LM_ERR("unknown output "
01054                                         "node type (%d) for LANGUAGE_SWITCH node\n",
01055                                         NODE_TYPE(kid));
01056                                 goto script_error;
01057                 } /* end switch for NODE_TYPE */
01058         } /* end for for all kids */
01059 
01060         return DEFAULT_ACTION;
01061 not_present:
01062         LM_DBG("required hdr not present in sip msg\n");
01063         if (not_present_node)
01064                 return get_first_child(not_present_node);
01065         /* look for the NOT_PRESENT node */
01066         LM_DBG("searching for NOT_PRESENT sub-node..\n");
01067         for(; i<NR_OF_KIDS(intr->ip) ; i++ ) {
01068                 kid = intr->ip + KID_OFFSET(intr->ip,i);
01069                 check_overflow_by_ptr( kid+SIMPLE_NODE_SIZE(kid), intr, script_error);
01070                 if (NODE_TYPE(kid)==NOT_PRESENT_NODE)
01071                         return get_first_child(kid);
01072         }
01073         return DEFAULT_ACTION;
01074 runtime_error:
01075         return CPL_RUNTIME_ERROR;
01076 script_error:
01077         return CPL_SCRIPT_ERROR;
01078 }