- AVPs can be used in place of strings and integers in expressions
authorJan Janak <jan@iptel.org>
Wed, 30 Nov 2005 16:26:50 +0000 (16:26 +0000)
committerJan Janak <jan@iptel.org>
Wed, 30 Nov 2005 16:26:50 +0000 (16:26 +0000)
  (if (method == %method))
- Support for AVP assign statements ( %var1 = "value"; %var1 += "value2"; )
- Support for binary operators & and | in expressions
- AVPs can be tested in expressions (if (%var1 == 4))
- fixed a bug in string comparisons in expressions
- extended parameters of expression evaluation functions
- fixed possible buffer overflow vulnerability in log("dfd") script function
- default memory buffers enlarged
- length of string is calculated in expression fixup
- fixed bug in function printing route statements (traversed the list
  recursively several times)

action.c
cfg.y
config.h
dprint.h
main.c
route.c
route_struct.c
route_struct.h

index f1e3ec7..a946936 100644 (file)
--- a/action.c
+++ b/action.c
@@ -92,6 +92,8 @@ int do_action(struct action* a, struct sip_msg* msg)
        struct sip_uri *u;
        unsigned short port;
        int proto;
+       unsigned short flags;
+       int_str name, value;
 
        /* reset the value of error to E_UNSPEC so avoid unknowledgable
           functions to return with error (status<0) and not setting it
@@ -271,7 +273,7 @@ int do_action(struct action* a, struct sip_msg* msg)
                                ret=E_BUG;
                                break;
                        }
-                       LOG(a->p1.number, a->p2.string);
+                       LOG(a->p1.number, "%s", a->p2.string);
                        ret=1;
                        break;
 
@@ -675,6 +677,83 @@ int do_action(struct action* a, struct sip_msg* msg)
                        msg->force_send_socket=(struct socket_info*)a->p1.data;
                        ret=1; /* continue processing */
                        break;
+
+               case ADD_T:
+               case ASSIGN_T:
+                       if (a->p2_type == STRING_ST) {
+                               value.s = a->p2.str;
+                               flags = a->p1.attr->type | AVP_VAL_STR;
+                               name = a->p1.attr->name;
+                               ret = 1;
+                       } else if (a->p2_type == NUMBER_ST) {
+                               value.n = a->p2.number;
+                               flags = a->p1.attr->type;
+                               name = a->p1.attr->name;
+                               ret = 1;
+                       } else if (a->p2_type == ACTION_ST) {
+                               flags = a->p1.attr->type;
+                               name = a->p1.attr->name;
+                               if (&a->p2.data) {
+                                       value.n = run_actions((struct action*)a->p2.data, msg);
+                               } else {
+                                       value.n = -1;
+                               }
+                               ret = value.n;
+                       } else if(a->p2_type == EXPR_ST && a->p2.data) {
+                               v = eval_expr((struct expr*)a->p2.data, msg);
+                               if (v < 0) {
+                                       if (v == EXPR_DROP){ /* hack to quit on DROP*/
+                                               ret = 0;
+                                               break;
+                                       } else {
+                                               LOG(L_WARN,"WARNING: do_action: error in expression\n");
+                                       }
+                               }
+                               
+                               flags = a->p1.attr->type;
+                               name = a->p1.attr->name;
+                               value.n = v;
+                       } else if (a->p2_type == AVP_ST) {
+                               struct search_state st;
+                               avp_t* avp; 
+                               
+                                    /* If the action is assign then remove the old avp value before adding
+                                     * new ones
+                                     */
+                               if ((unsigned char)a->type == ASSIGN_T) delete_avp(a->p1.attr->type, a->p1.attr->name);
+
+                               avp = search_first_avp(a->p2.attr->type, a->p2.attr->name, &value, &st);
+                               while(avp) {
+                                            /* We take only the type of value and name from the source avp
+                                             * and reset class and track flags
+                                             */
+                                       flags = a->p1.attr->type | (avp->flags & ~(AVP_CLASS_ALL|AVP_TRACK_ALL));
+                                       if (add_avp(flags, name, value) < 0) {
+                                               LOG(L_CRIT, "ERROR: Failed to assign value to attribute\n");
+                                               ret=E_UNSPEC;
+                                               break;
+                                       }
+                                       avp = search_next_avp(&st, &value);
+                               }
+                               ret = 1;
+                               break;
+                       } else {
+                               LOG(L_CRIT, "BUG: do_action: Bad right side of avp assignment\n");
+                               ret=E_BUG;
+                               break;
+                       }
+
+                            /* If the action is assign then remove the old avp value before adding
+                             * new ones
+                             */
+                       if ((unsigned char)a->type == ASSIGN_T) delete_avp(flags, name);
+                       if (add_avp(flags, name, value) < 0) {
+                               LOG(L_CRIT, "ERROR: Failed to assign value to attribute\n");
+                               ret=E_UNSPEC;
+                               break;
+                       }
+                       break;
+
                default:
                        LOG(L_CRIT, "BUG: do_action: unknown type %d\n", a->type);
        }
diff --git a/cfg.y b/cfg.y
index ef024b0..5b93e3b 100644 (file)
--- a/cfg.y
+++ b/cfg.y
@@ -91,7 +91,6 @@
 #include "ut.h"
 #include "dset.h"
 
-
 #include "config.h"
 #ifdef USE_TLS
 #include "tls/tls_config.h"
@@ -116,10 +115,10 @@ static int rt;  /* Type of route block for find_export */
 static str* str_tmp;
 static str s_tmp;
 static struct ip_addr* ip_tmp;
+static struct avp_spec* s_attr;
 
 static void warn(char* s);
 static struct socket_id* mk_listen_id(char*, int, int);
 
 %}
 
@@ -132,6 +131,7 @@ static struct socket_id* mk_listen_id(char*, int, int);
        struct net* ipnet;
        struct ip_addr* ipaddr;
        struct socket_id* sockid;
+       struct avp_spec* attr;
 }
 
 /* terminals */
@@ -263,8 +263,13 @@ static struct socket_id* mk_listen_id(char*, int, int);
 %token MCAST_TTL
 %token TOS
 
-
-
+%token ATTR_MARK
+%token ATTR_FROM
+%token ATTR_TO
+%token ATTR_USER
+%token ATTR_DOMAIN
+%token ATTR_GLOBAL
+%token ADD
 
 /* operators */
 %nonassoc EQUAL
@@ -275,11 +280,12 @@ static struct socket_id* mk_listen_id(char*, int, int);
 %nonassoc LTE
 %nonassoc DIFF
 %nonassoc MATCH
-%left OR
-%left AND
-%left NOT
-%left PLUS
-%left MINUS
+%left LOG_OR
+%left LOG_AND
+%left BIN_OR
+%left BIN_AND 
+%left PLUS MINUS
+%right NOT
 
 /* values */
 %token <intval> NUMBER
@@ -305,7 +311,7 @@ static struct socket_id* mk_listen_id(char*, int, int);
 
 /*non-terminals */
 %type <expr> exp exp_elem /*, condition*/
-%type <action> action actions cmd if_cmd stm exp_stm
+%type <action> action actions cmd if_cmd stm exp_stm assign_action
 %type <ipaddr> ipv4 ipv6 ipv6addr ip
 %type <ipnet> ipnet
 %type <strval> host
@@ -313,9 +319,12 @@ static struct socket_id* mk_listen_id(char*, int, int);
 %type <sockid>  id_lst
 %type <sockid>  phostport
 %type <intval> proto port
-%type <intval> equalop strop intop
+%type <intval> equalop strop intop binop
 %type <strval> host_sep
 %type <intval> uri_type
+%type <attr> attr_id
+%type <intval> class_id
+%type <intval> assign_op
 /*%type <route_el> rules;
   %type <route_el> rule;
 */
@@ -908,8 +917,8 @@ rule:       condition       actions CR {
 condition:     exp {$$=$1;}
 */
 
-exp:   exp AND exp     { $$=mk_exp(AND_OP, $1, $3); }
-       | exp OR  exp           { $$=mk_exp(OR_OP, $1, $3);  }
+exp:   exp LOG_AND exp         { $$=mk_exp(LOGAND_OP, $1, $3); }
+       | exp LOG_OR  exp               { $$=mk_exp(LOGOR_OP, $1, $3);  }
        | NOT exp                       { $$=mk_exp(NOT_OP, $2, 0);  }
        | LPAREN exp RPAREN     { $$=$2; }
        | exp_elem                      { $$=$1; }
@@ -925,6 +934,10 @@ intop:     equalop {$$=$1; }
                | GTE   {$$=GTE_OP; }
                | LTE   {$$=LTE_OP; }
                ;
+
+binop : BIN_OR { $$= BINOR_OP; }
+      | BIN_AND { $$ = BINAND_OP; }
+;
                
 strop: equalop {$$=$1; }
                | MATCH {$$=MATCH_OP; }
@@ -935,82 +948,74 @@ uri_type: URI                     {$$=URI_O;}
                |       TO_URI          {$$=TO_URI_O;}
                ;
 
-exp_elem:      METHOD strop STRING     {$$= mk_elem(   $2, STRING_ST, 
-                                                                                                       METHOD_O, $3);
-                                                                       }
-               | METHOD strop  ID      {$$ = mk_elem(  $2, STRING_ST,
-                                                                                       METHOD_O, $3); 
-                                                       }
+exp_elem:      METHOD strop STRING     {$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
+                | METHOD strop attr_id  {$$ = mk_elem($2, METHOD_O, 0, AVP_ST, $3); }
+               | METHOD strop  ID      {$$ = mk_elem($2, METHOD_O, 0, STRING_ST,$3); }
                | METHOD strop error { $$=0; yyerror("string expected"); }
                | METHOD error  { $$=0; yyerror("invalid operator,"
                                                                                "== , !=, or =~ expected");
                                                }
-               | uri_type strop STRING {$$ = mk_elem(  $2, STRING_ST,
-                                                                                               $1, $3); 
-                                                               }
-               | uri_type strop host   {$$ = mk_elem(  $2, STRING_ST,
-                                                                                       $1, $3); 
-                                                       }
-               | uri_type equalop MYSELF       { $$=mk_elem(   $2, MYSELF_ST,
-                                                                                                       $1, 0);
-                                                               }
+               | uri_type strop STRING {$$ = mk_elem($2, $1, 0, STRING_ST, $3); }
+                | uri_type strop host  {$$ = mk_elem($2, $1, 0, STRING_ST, $3); }
+                | uri_type strop attr_id {$$ = mk_elem($2, $1, 0, AVP_ST, $3); }
+                | uri_type equalop MYSELF {$$=mk_elem($2, $1, 0, MYSELF_ST, 0); }
                | uri_type strop error { $$=0; yyerror("string or MYSELF expected"); }
                | uri_type error        { $$=0; yyerror("invalid operator,"
                                                                        " == , != or =~ expected");
                                        }
-               | SRCPORT intop NUMBER  { $$=mk_elem(   $2, NUMBER_ST,
-                                                                                               SRCPORT_O, (void *) $3 ); }
+               | SRCPORT intop NUMBER  { $$=mk_elem($2, SRCPORT_O, 0, NUMBER_ST, (void*)$3 ); }
+                | SRCPORT intop attr_id { $$=mk_elem($2, SRCPORT_O, 0, AVP_ST, (void*)$3 ); }
                | SRCPORT intop error { $$=0; yyerror("number expected"); }
                | SRCPORT error { $$=0; yyerror("==, !=, <,>, >= or <=  expected"); }
-               | DSTPORT intop NUMBER  { $$=mk_elem(   $2, NUMBER_ST,
-                                                                                               DSTPORT_O, (void *) $3 ); }
+
+               | DSTPORT intop NUMBER  { $$=mk_elem($2, DSTPORT_O, 0, NUMBER_ST, (void*)$3 ); }
+               | DSTPORT intop attr_id { $$=mk_elem($2, DSTPORT_O, 0, AVP_ST, (void*)$3 ); }
                | DSTPORT intop error { $$=0; yyerror("number expected"); }
                | DSTPORT error { $$=0; yyerror("==, !=, <,>, >= or <=  expected"); }
-               | PROTO intop proto     { $$=mk_elem(   $2, NUMBER_ST,
-                                                                                               PROTO_O, (void *) $3 ); }
+
+               | PROTO intop proto     { $$=mk_elem($2, PROTO_O, 0, NUMBER_ST, (void*)$3 ); }
+               | PROTO intop attr_id   { $$=mk_elem($2, PROTO_O, 0, AVP_ST, (void*)$3 ); }
                | PROTO intop error { $$=0;
                                                                yyerror("protocol expected (udp, tcp or tls)");
                                                        }
                | PROTO error { $$=0; yyerror("equal/!= operator expected"); }
-               | AF intop NUMBER       { $$=mk_elem(   $2, NUMBER_ST,
-                                                                                               AF_O, (void *) $3 ); }
+
+               | AF intop NUMBER       { $$=mk_elem($2, AF_O, 0, NUMBER_ST,(void *) $3 ); }
+               | AF intop attr_id      { $$=mk_elem($2, AF_O, 0, AVP_ST,(void *) $3 ); }
                | AF intop error { $$=0; yyerror("number expected"); }
                | AF error { $$=0; yyerror("equal/!= operator expected"); }
-               | MSGLEN intop NUMBER   { $$=mk_elem(   $2, NUMBER_ST,
-                                                                                               MSGLEN_O, (void *) $3 ); }
-               | MSGLEN intop MAX_LEN  { $$=mk_elem(   $2, NUMBER_ST,
-                                                                                               MSGLEN_O, (void *) BUF_SIZE); }
+
+               | MSGLEN intop NUMBER   { $$=mk_elem($2, MSGLEN_O, 0, NUMBER_ST, (void *) $3 ); }
+               | MSGLEN intop attr_id  { $$=mk_elem($2, MSGLEN_O, 0, AVP_ST, (void *) $3 ); }
+               | MSGLEN intop MAX_LEN  { $$=mk_elem($2, MSGLEN_O, 0, NUMBER_ST, (void *) BUF_SIZE); }
                | MSGLEN intop error { $$=0; yyerror("number expected"); }
                | MSGLEN error { $$=0; yyerror("equal/!= operator expected"); }
-               | SRCIP equalop ipnet   { $$=mk_elem(   $2, NET_ST,
-                                                                                               SRCIP_O, $3);
-                                                               }
+
+               | SRCIP equalop ipnet   { $$=mk_elem($2, SRCIP_O, 0, NET_ST, $3); }
                | SRCIP strop STRING    {       s_tmp.s=$3;
                                                                        s_tmp.len=strlen($3);
                                                                        ip_tmp=str2ip(&s_tmp);
                                                                        if (ip_tmp==0)
                                                                                ip_tmp=str2ip6(&s_tmp);
                                                                        if (ip_tmp){
-                                                                               $$=mk_elem(     $2, NET_ST, SRCIP_O,
+                                                                               $$=mk_elem(     $2, SRCIP_O, 0, NET_ST,
                                                                                                mk_net_bitlen(ip_tmp, 
                                                                                                                ip_tmp->len*8) );
                                                                        }else{
-                                                                               $$=mk_elem(     $2, STRING_ST,
-                                                                                               SRCIP_O, $3);
+                                                                               $$=mk_elem(     $2, SRCIP_O, 0, STRING_ST,
+                                                                                               $3);
                                                                        }
                                                                }
-               | SRCIP strop host      { $$=mk_elem(   $2, STRING_ST,
-                                                                                               SRCIP_O, $3);
-                                                               }
-               | SRCIP equalop MYSELF  { $$=mk_elem(   $2, MYSELF_ST,
-                                                                                               SRCIP_O, 0);
+               | SRCIP strop host      { $$=mk_elem(   $2, SRCIP_O, 0, STRING_ST, $3); }
+               | SRCIP equalop MYSELF  { $$=mk_elem(   $2, SRCIP_O, 0, MYSELF_ST,
+                                                                                               0);
                                                                }
                | SRCIP strop error { $$=0; yyerror( "ip address or hostname"
                                                 "expected" ); }
                | SRCIP error  { $$=0; 
                                                 yyerror("invalid operator, ==, != or =~ expected");}
-               | DSTIP equalop ipnet   { $$=mk_elem(   $2, NET_ST,
-                                                                                               DSTIP_O, $3);
+               | DSTIP equalop ipnet   { $$=mk_elem(   $2, DSTIP_O, 0, NET_ST,
+                                                                                               (void*)$3);
                                                                }
                | DSTIP strop STRING    {       s_tmp.s=$3;
                                                                        s_tmp.len=strlen($3);
@@ -1018,41 +1023,49 @@ exp_elem:       METHOD strop STRING     {$$= mk_elem(   $2, STRING_ST,
                                                                        if (ip_tmp==0)
                                                                                ip_tmp=str2ip6(&s_tmp);
                                                                        if (ip_tmp){
-                                                                               $$=mk_elem(     $2, NET_ST, DSTIP_O,
+                                                                               $$=mk_elem(     $2, DSTIP_O, 0, NET_ST,
                                                                                                mk_net_bitlen(ip_tmp, 
                                                                                                                ip_tmp->len*8) );
                                                                        }else{
-                                                                               $$=mk_elem(     $2, STRING_ST,
-                                                                                               DSTIP_O, $3);
+                                                                               $$=mk_elem(     $2, DSTIP_O, 0, STRING_ST,
+                                                                                               $3);
                                                                        }
                                                                }
-               | DSTIP strop host      { $$=mk_elem(   $2, STRING_ST,
-                                                                                               DSTIP_O, $3);
+               | DSTIP strop host      { $$=mk_elem(   $2, DSTIP_O, 0, STRING_ST,
+                                                                                               $3);
                                                                }
-               | DSTIP equalop MYSELF  { $$=mk_elem(   $2, MYSELF_ST,
-                                                                                               DSTIP_O, 0);
+               | DSTIP equalop MYSELF  { $$=mk_elem(   $2, DSTIP_O, 0, MYSELF_ST,
+                                                                                               0);
                                                                }
                | DSTIP strop error { $$=0; yyerror( "ip address or hostname"
                                                                        "expected" ); }
                | DSTIP error { $$=0; 
                                                yyerror("invalid operator, ==, != or =~ expected");}
-               | MYSELF equalop uri_type       { $$=mk_elem(   $2, MYSELF_ST,
-                                                                                                       $3, 0);
+
+               | MYSELF equalop uri_type       { $$=mk_elem(   $2, $3, 0, MYSELF_ST,
+                                                                                                      0);
                                                                }
-               | MYSELF equalop SRCIP  { $$=mk_elem(   $2, MYSELF_ST,
-                                                                                               SRCIP_O, 0);
+               | MYSELF equalop SRCIP  { $$=mk_elem(   $2, SRCIP_O, 0, MYSELF_ST,
+                                                                                               0);
                                                                }
-               | MYSELF equalop DSTIP  { $$=mk_elem(   $2, MYSELF_ST,
-                                                                                               DSTIP_O, 0);
+                | MYSELF equalop DSTIP  { $$=mk_elem(  $2, DSTIP_O, 0, MYSELF_ST,
+                                                       0);
                                                                }
                | MYSELF equalop error {        $$=0; 
                                                                        yyerror(" URI, SRCIP or DSTIP expected"); }
                | MYSELF error  { $$=0; 
                                                        yyerror ("invalid operator, == or != expected");
                                                }
-               | exp_stm                       { $$=mk_elem( NO_OP, ACTIONS_ST, ACTION_O, $1 );  }
-               | NUMBER                {$$=mk_elem( NO_OP, NUMBER_ST, NUMBER_O, (void*)$1 ); }
-       ;
+               | exp_stm                       { $$=mk_elem( NO_OP, ACTION_O, 0, ACTIONS_ST, $1);  }
+               | NUMBER                {$$=mk_elem( NO_OP, NUMBER_O, 0, NUMBER_ST, (void*)$1 ); }
+
+               | attr_id               {$$=mk_elem( NO_OP, AVP_ST, (void*)$1, 0, 0); }
+               | attr_id strop STRING  {$$=mk_elem( $2, AVP_ST, (void*)$1, STRING_ST, $3); }
+               | attr_id intop NUMBER  {$$=mk_elem( $2, AVP_ST, (void*)$1, NUMBER_ST, (void*)$3); }
+               | attr_id binop NUMBER  {$$=mk_elem( $2, AVP_ST, (void*)$1, NUMBER_ST, (void*)$3); }
+                | attr_id strop attr_id {$$=mk_elem( $2, AVP_ST, (void*)$1, AVP_ST, (void*)$3); }
+;
+
 
 ipnet: ip SLASH ip     { $$=mk_net($1, $3); } 
        | ip SLASH NUMBER       {       if (($3<0) || ($3>$1->len*8)){
@@ -1097,6 +1110,7 @@ host:     ID                              { $$=$1; }
 
 exp_stm:       cmd                                             { $$=$1; }
                |       if_cmd                                  { $$=$1; }
+                |       assign_action { $$ = $1; }
                |       LBRACE actions RBRACE   { $$=$2; }
        ;
 
@@ -1111,6 +1125,7 @@ actions:  actions action  {$$=append_action($1, $2); }
 
 action:                cmd SEMICOLON {$$=$1;}
                | if_cmd {$$=$1;}
+                | assign_action SEMICOLON {$$=$1}
                | SEMICOLON /* null action */ {$$=0;}
                | cmd error { $$=0; yyerror("bad command: missing ';'?"); }
        ;
@@ -1133,6 +1148,61 @@ if_cmd:          IF exp stm                              { $$=mk_action3( IF_T,
                                                                        }
        ;
 
+class_id : LBRACK ATTR_USER RBRACK { $$ = AVP_CLASS_USER; }
+         | LBRACK ATTR_DOMAIN RBRACK { $$ = AVP_CLASS_DOMAIN; }
+         | LBRACK ATTR_GLOBAL RBRACK { $$ = AVP_CLASS_GLOBAL; }
+;
+
+attr_id : ATTR_MARK ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
+                         if (!s_attr) { LOG(L_CRIT, "No memory left"); return 0;}
+                         s_attr->type = AVP_NAME_STR;                   
+                         s_attr->name.s.s = $2; s_attr->name.s.len = strlen($2); 
+                         $$ = s_attr; 
+                       }
+        | ATTR_MARK class_id DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
+                                      if (!s_attr) { LOG(L_CRIT, "No memory left"); return 0;}
+                                      s_attr->type = AVP_NAME_STR | $2;
+                                      s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4); 
+                                      $$ = s_attr; 
+                                    }
+        | ATTR_MARK ATTR_FROM DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
+                                       if (!s_attr) { LOG(L_CRIT, "No memory left"); return 0;}
+                                       s_attr->type = AVP_NAME_STR | AVP_TRACK_FROM;
+                                       s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4);
+                                       $$ = s_attr;
+                                     }
+        | ATTR_MARK ATTR_TO DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
+                                     if (!s_attr) { LOG(L_CRIT, "No memory left"); return 0;}
+                                     s_attr->type = AVP_NAME_STR | AVP_TRACK_TO; 
+                                     s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4); 
+                                     $$ = s_attr;
+                                   }
+        | ATTR_MARK ATTR_FROM class_id DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
+                                               if (!s_attr) { LOG(L_CRIT, "No memory left"); return 0;}
+                                               s_attr->type = AVP_NAME_STR | AVP_TRACK_FROM | $3; 
+                                               s_attr->name.s.s = $5; 
+                                               s_attr->name.s.len = strlen($5);
+                                               $$ = s_attr;
+                                              }
+        | ATTR_MARK ATTR_TO class_id DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
+                                              if (!s_attr) { LOG(L_CRIT, "No memory left"); return 0;}
+                                              s_attr->type = AVP_NAME_STR | AVP_TRACK_TO | $3;
+                                              s_attr->name.s.s = $5; s_attr->name.s.len = strlen($5);
+                                             $$ = s_attr;
+                                            }
+;
+
+assign_op : ADD { $$ = ADD_T; }
+          | EQUAL { $$ = ASSIGN_T; }
+;
+
+assign_action:   attr_id assign_op STRING  { $$=mk_action($2, AVP_ST, STRING_ST, $1, $3); }
+               | attr_id assign_op NUMBER  { $$=mk_action($2, AVP_ST, NUMBER_ST, $1, (void*)$3); }
+               | attr_id assign_op cmd     { $$=mk_action($2, AVP_ST, ACTION_ST, $1, $3); }
+               | attr_id assign_op attr_id { $$=mk_action($2, AVP_ST, AVP_ST, $1, $3); }
+               | attr_id assign_op LPAREN exp RPAREN { $$ = mk_action($2, AVP_ST, EXPR_ST, $1, $4); }
+;
+
 cmd:           FORWARD LPAREN host RPAREN      { $$=mk_action( FORWARD_T,
                                                                                                                STRING_ST,
                                                                                                                NUMBER_ST,
index e7d9140..2b1db5d 100644 (file)
--- a/config.h
+++ b/config.h
 #define SRV_MAX_PREFIX_LEN SRV_TLS_PREFIX_LEN
 
 /*used only if PKG_MALLOC is defined*/
-#define PKG_MEM_POOL_SIZE 1024*1024
+#define PKG_MEM_POOL_SIZE 4*1024*1024
 
 /*used if SH_MEM is defined*/
-#define SHM_MEM_SIZE 32
+#define SHM_MEM_SIZE 128
 
 #define TIMER_TICK 1
 
index 17b2fc2..2076ee2 100644 (file)
--- a/dprint.h
+++ b/dprint.h
@@ -142,25 +142,25 @@ int str2facility(char *s);
                                        else { \
                                                switch(lev){ \
                                                        case L_CRIT: \
-                                                               syslog(LOG_CRIT|log_facility, fmt, ##args); \
+                                                               syslog(LOG_CRIT|log_facility, "CRIT: " fmt, ##args); \
                                                                break; \
                                                        case L_ALERT: \
-                                                               syslog(LOG_ALERT|log_facility, fmt, ##args); \
+                                                               syslog(LOG_ALERT|log_facility, "ALERT: " fmt, ##args); \
                                                                break; \
                                                        case L_ERR: \
-                                                               syslog(LOG_ERR|log_facility, fmt, ##args); \
+                                                               syslog(LOG_ERR|log_facility, "ERROR: " fmt, ##args); \
                                                                break; \
                                                        case L_WARN: \
-                                                               syslog(LOG_WARNING|log_facility, fmt, ##args);\
+                                                               syslog(LOG_WARNING|log_facility, "WARNING: " fmt, ##args);\
                                                                break; \
                                                        case L_NOTICE: \
-                                                               syslog(LOG_NOTICE|log_facility, fmt, ##args); \
+                                                               syslog(LOG_NOTICE|log_facility, "NOTICE: " fmt, ##args); \
                                                                break; \
                                                        case L_INFO: \
-                                                               syslog(LOG_INFO|log_facility, fmt, ##args); \
+                                                               syslog(LOG_INFO|log_facility, "INFO: " fmt, ##args); \
                                                                break; \
                                                        case L_DBG: \
-                                                               syslog(LOG_DEBUG|log_facility, fmt, ##args); \
+                                                               syslog(LOG_DEBUG|log_facility, "DEBUG: " fmt, ##args); \
                                                                break; \
                                                } \
                                        } \
diff --git a/main.c b/main.c
index 45935bf..21e9c0f 100644 (file)
--- a/main.c
+++ b/main.c
 #include "tls/tls_init.h"
 #endif
 #endif
-
+#include "usr_avp.h"
 
 
 #include "stats.h"
@@ -1568,6 +1568,8 @@ try_again:
                goto error;
        }
        
+       if (init_avps()<0) goto error;
+
 #ifdef USE_TCP
        if (!tcp_disable){
                /*init tcp*/
diff --git a/route.c b/route.c
index 374acb6..a82aaa6 100644 (file)
--- a/route.c
+++ b/route.c
@@ -92,8 +92,8 @@ static int fix_expr(struct expr* exp)
        }
        if (exp->type==EXP_T){
                switch(exp->op){
-                       case AND_OP:
-                       case OR_OP:
+                       case LOGAND_OP:
+                       case LOGOR_OP:
                                                if ((ret=fix_expr(exp->l.expr))!=0)
                                                        return ret;
                                                ret=fix_expr(exp->r.expr);
@@ -107,7 +107,11 @@ static int fix_expr(struct expr* exp)
                }
        }else if (exp->type==ELEM_T){
                        if (exp->op==MATCH_OP){
-                               if (exp->subtype==STRING_ST){
+                                    /* right side either has to be string, in which case
+                                     * we turn it into regular expression, or it is regular
+                                     * expression already. In that case we do nothing
+                                     */
+                               if (exp->r_type==STRING_ST){
                                        re=(regex_t*)pkg_malloc(sizeof(regex_t));
                                        if (re==0){
                                                LOG(L_CRIT, "ERROR: fix_expr: memory allocation"
@@ -123,19 +127,34 @@ static int fix_expr(struct expr* exp)
                                        }
                                        /* replace the string with the re */
                                        pkg_free(exp->r.param);
-                                       exp->r.param=re;
-                                       exp->subtype=RE_ST;
-                               }else if (exp->subtype!=RE_ST){
+                                       exp->r.re=re;
+                                       exp->r_type=RE_ST;
+                               }else if (exp->r_type!=RE_ST && exp->r_type != AVP_ST){
                                        LOG(L_CRIT, "BUG: fix_expr : invalid type for match\n");
                                        return E_BUG;
                                }
                        }
-                       if (exp->l.operand==ACTION_O){
+                       if (exp->l_type==ACTION_O){
                                ret=fix_actions((struct action*)exp->r.param);
                                if (ret!=0){
                                        LOG(L_CRIT, "ERROR: fix_expr : fix_actions error\n");
                                        return ret;
                                }
+                       }
+                            /* Calculate lengths of strings */
+                       if (exp->l_type==STRING_ST) {
+                               int len;
+                               if (exp->l.string) len = strlen(exp->l.string);
+                               else len = 0;
+                               exp->l.str.s = exp->l.string;
+                               exp->l.str.len = len;
+                       }
+                       if (exp->r_type==STRING_ST) {
+                               int len;
+                               if (exp->l.string) len = strlen(exp->r.string);
+                               else len = 0;
+                               exp->r.str.s = exp->r.string;
+                               exp->r.str.len = len;
                        }
                        ret=0;
        }
@@ -230,6 +249,37 @@ static int fix_actions(struct action* a)
                                                return ret;
                                }
                                break;
+
+                       case ASSIGN_T:
+                       case ADD_T:
+                               if (t->p1_type != AVP_ST) {
+                                       LOG(L_CRIT, "BUG: fix_actions: Invalid left side of assignment\n");
+                                       return E_BUG;
+                               }
+                               if (t->p1.attr->type & AVP_CLASS_DOMAIN) {
+                                       LOG(L_ERR, "ERROR: You cannot change domain attributes from the script, they are read-only\n");
+                                       return E_BUG;
+                               } else if (t->p1.attr->type & AVP_CLASS_GLOBAL) {
+                                       LOG(L_ERR, "ERROR: You cannot change global attributes from the script, they are read-only\n");
+                                       return E_BUG;
+                               }
+
+                               if (t->p2_type == ACTION_ST && t->p2.data) {
+                                       if ((ret = fix_actions((struct action*)t->p2.data)) < 0) {
+                                               return ret;
+                                       }
+                               } else if (t->p2_type == EXPR_ST && t->p2.data) {
+                                       if ((ret = fix_expr((struct expr*)t->p2.data)) < 0) {
+                                               return ret;
+                                       }
+                               } else if (t->p2_type == STRING_ST) {
+                                       int len;
+                                       len = strlen(t->p2.data);
+                                       t->p2.str.s = t->p2.data;
+                                       t->p2.str.len = len;
+                               }
+                               break;
+
                        case MODULE_T:
                                if ((mod=find_module(t->p1.data, &cmd))!=0){
                                        DBG("fixing %s %s\n", mod->path, cmd->name);
@@ -280,78 +330,113 @@ static int fix_actions(struct action* a)
 }
 
 
-inline static int comp_no( int port, void *param, int op, int subtype )
+/* Compare parameters as ordinary numbers
+ *
+ * Left and right operands can be either numbers or
+ * attributes. If either of the attributes if of string type then the length of
+ * its value will be used.
+ */
+inline static int comp_num(int op, long left, int rtype, union exp_op* r)
 {
+       int_str val;
+       avp_t* avp;
+       long right;
        
-       if (subtype!=NUMBER_ST) {
-               LOG(L_CRIT, "BUG: comp_no: number expected: %d\n", subtype );
+       if (rtype == AVP_ST) {
+               avp = search_first_avp(r->attr->type, r->attr->name, &val, 0);
+               if (avp && !(avp->flags & AVP_VAL_STR)) right = val.n;
+               else return 0; /* Always fail */
+       } else if (rtype == NUMBER_ST) {
+               right = r->intval;
+       } else {
+               LOG(L_CRIT, "BUG: comp_num: Invalid right operand (%d)\n", rtype);
                return E_BUG;
        }
+
        switch (op){
-               case EQUAL_OP:
-                       return port==(long)param;
-               case DIFF_OP:
-                       return port!=(long)param;
-               case GT_OP:
-                       return port>(long)param;
-               case LT_OP:
-                       return port<(long)param;
-               case GTE_OP:
-                       return port>=(long)param;
-               case LTE_OP:
-                       return port<=(long)param;
-               default:
-               LOG(L_CRIT, "BUG: comp_no: unknown operator: %d\n", op );
+       case EQUAL_OP: return (long)left == (long)right;
+       case DIFF_OP:  return (long)left != (long)right;
+       case GT_OP:    return (long)left >  (long)right;
+       case LT_OP:    return (long)left <  (long)right;
+       case GTE_OP:   return (long)left >= (long)right;
+       case LTE_OP:   return (long)left <= (long)right;
+       default:
+               LOG(L_CRIT, "BUG: comp_num: unknown operator: %d\n", op);
                return E_BUG;
        }
 }
 
-/* eval_elem helping function, returns str op param */
-inline static int comp_strstr(str* str, void* param, int op, int subtype)
+/*
+ * Compare given string "left" with right side of expression
+ */
+inline static int comp_str(int op, str* left, int rtype, union exp_op* r)
 {
+       str* right;
+       int_str val;
+       avp_t* avp;
        int ret;
        char backup;
        
+       if (rtype == AVP_ST) {
+               avp = search_first_avp(r->attr->type, r->attr->name, &val, 0);
+               if (avp && (avp->flags & AVP_VAL_STR)) right = &val.s;
+               else return 0;
+       } else if ((op == MATCH_OP && rtype == RE_ST)) {
+       } else if (op != MATCH_OP && rtype == STRING_ST) {
+               right = &r->str;
+       } else {
+               LOG(L_CRIT, "BUG: comp_str: Bad type %d, "
+                   "string or RE expected\n", rtype);
+               goto error;
+       }
+
        ret=-1;
        switch(op){
                case EQUAL_OP:
-                       if (subtype!=STRING_ST){
-                               LOG(L_CRIT, "BUG: comp_str: bad type %d, "
-                                               "string expected\n", subtype);
-                               goto error;
-                       }
-                       ret=(strncasecmp(str->s, (char*)param, str->len)==0);
+                       if (left->len != right->len) return 0;
+                       ret=(strncasecmp(left->s, right->s, left->len)==0);
                        break;
                case DIFF_OP:
-                       if (subtype!=STRING_ST){
-                               LOG(L_CRIT, "BUG: comp_str: bad type %d, "
-                                               "string expected\n", subtype);
-                               goto error;
-                       }
-                       ret=(strncasecmp(str->s, (char*)param, str->len)!=0);
+                       if (left->len != right->len) return 1;
+                       ret = (strncasecmp(left->s, right->s, left->len)!=0);
                        break;
                case MATCH_OP:
-                       if (subtype!=RE_ST){
-                               LOG(L_CRIT, "BUG: comp_str: bad type %d, "
-                                               " RE expected\n", subtype);
-                               goto error;
+                            /* this is really ugly -- we put a temporary zero-terminating
+                             * character in the original string; that's because regexps
+                             * take 0-terminated strings and our messages are not
+                             * zero-terminated; it should not hurt as long as this function
+                             * is applied to content of pkg mem, which is always the case
+                             * with calls from route{}; the same goes for fline in reply_route{};
+                             *
+                             * also, the received function should always give us an extra
+                             * character, into which we can put the 0-terminator now;
+                             * an alternative would be allocating a new piece of memory,
+                             * which might be too slow
+                             * -jiri
+                             *
+                             * janakj: AVPs are zero terminated too so this is not problem either
+                             */
+                       backup=left->s[left->len];
+                       left->s[left->len]='\0';
+                       if (rtype == AVP_ST) {
+                               regex_t* re;
+                                    /* For AVPs we need to compile the RE on the fly */
+                               re=(regex_t*)pkg_malloc(sizeof(regex_t));
+                               if (re==0){
+                                       LOG(L_CRIT, "ERROR: comp_strstr: memory allocation"
+                                           " failure\n");
+                                       goto error;
+                               }
+                               if (regcomp(re, right->s, REG_EXTENDED|REG_NOSUB|REG_ICASE)) {
+                                       pkg_free(re);
+                                       goto error;
+                               }                               
+                               ret=(regexec(re, left->s, 0, 0, 0)==0);
+                               pkg_free(re);
+                       } else {
+                               ret=(regexec(r->re, left->s, 0, 0, 0)==0);
                        }
-               /* this is really ugly -- we put a temporary zero-terminating
-                * character in the original string; that's because regexps
-         * take 0-terminated strings and our messages are not
-         * zero-terminated; it should not hurt as long as this function
-                * is applied to content of pkg mem, which is always the case
-                * with calls from route{}; the same goes for fline in reply_route{};
-         *
-         * also, the received function should always give us an extra
-         * character, into which we can put the 0-terminator now;
-         * an alternative would be allocating a new piece of memory,
-         * which might be too slow
-         * -jiri
-         */
-                       backup=str->s[str->len];str->s[str->len]=0;
-                       ret=(regexec((regex_t*)param, str->s, 0, 0, 0)==0);
-                       str->s[str->len]=backup;
+                       left->s[left->len] = backup;
                        break;
                default:
                        LOG(L_CRIT, "BUG: comp_str: unknown op %d\n", op);
@@ -363,39 +448,40 @@ error:
        return -1;
 }
 
+
 /* eval_elem helping function, returns str op param */
-inline static int comp_str(char* str, void* param, int op, int subtype)
+inline static int comp_string(int op, char* left, int rtype, union exp_op* r)
 {
        int ret;
        
        ret=-1;
        switch(op){
                case EQUAL_OP:
-                       if (subtype!=STRING_ST){
-                               LOG(L_CRIT, "BUG: comp_str: bad type %d, "
-                                               "string expected\n", subtype);
+                       if (rtype!=STRING_ST){
+                               LOG(L_CRIT, "BUG: comp_string: bad type %d, "
+                                               "string expected\n", rtype);
                                goto error;
                        }
-                       ret=(strcasecmp(str, (char*)param)==0);
+                       ret=(strcasecmp(left, r->str.s)==0);
                        break;
                case DIFF_OP:
-                       if (subtype!=STRING_ST){
-                               LOG(L_CRIT, "BUG: comp_str: bad type %d, "
-                                               "string expected\n", subtype);
+                       if (rtype!=STRING_ST){
+                               LOG(L_CRIT, "BUG: comp_string: bad type %d, "
+                                               "string expected\n", rtype);
                                goto error;
                        }
-                       ret=(strcasecmp(str, (char*)param)!=0);
+                       ret=(strcasecmp(left, r->str.s)!=0);
                        break;
                case MATCH_OP:
-                       if (subtype!=RE_ST){
-                               LOG(L_CRIT, "BUG: comp_str: bad type %d, "
-                                               " RE expected\n", subtype);
+                       if (rtype!=RE_ST){
+                               LOG(L_CRIT, "BUG: comp_string: bad type %d, "
+                                               " RE expected\n", rtype);
                                goto error;
                        }
-                       ret=(regexec((regex_t*)param, str, 0, 0, 0)==0);
+                       ret=(regexec(r->re, left, 0, 0, 0)==0);
                        break;
                default:
-                       LOG(L_CRIT, "BUG: comp_str: unknown op %d\n", op);
+                       LOG(L_CRIT, "BUG: comp_string: unknown op %d\n", op);
                        goto error;
        }
        return ret;
@@ -405,6 +491,42 @@ error:
 }
 
 
+inline static int comp_avp(int op, avp_spec_t* spec, int rtype, union exp_op* r)
+{
+       avp_t* avp;
+       int_str val;
+
+       avp = search_first_avp(spec->type, spec->name, &val, 0);
+       if (!avp) return 0;
+
+       switch(op) {
+       case NO_OP:
+               if (avp->flags & AVP_VAL_STR) {
+                       return val.s.len;
+               } else {
+                       return val.n != 0;
+               }
+               break;
+
+       case BINOR_OP:
+               return val.n | r->intval;
+               break;
+
+       case BINAND_OP:
+               return val.n & r->intval;
+               break;
+       }
+
+       if (avp->flags & AVP_VAL_STR) {
+               return comp_str(op, &val.s, rtype, r);
+       } else {
+               return comp_num(op, val.n, rtype, r);
+       }
+}
+
+
+
+
 /* check_self wrapper -- it checks also for the op */
 inline static int check_self_op(int op, str* s, unsigned short p)
 {
@@ -426,7 +548,7 @@ inline static int check_self_op(int op, str* s, unsigned short p)
 
 
 /* eval_elem helping function, returns an op param */
-inline static int comp_ip(struct ip_addr* ip, void* param, int op, int subtype)
+inline static int comp_ip(int op, struct ip_addr* ip, int rtype, union exp_op* r)
 {
        struct hostent* he;
        char ** h;
@@ -434,14 +556,14 @@ inline static int comp_ip(struct ip_addr* ip, void* param, int op, int subtype)
        str tmp;
 
        ret=-1;
-       switch(subtype){
+       switch(rtype){
                case NET_ST:
                        switch(op){
                                case EQUAL_OP:
-                                       ret=(matchnet(ip, (struct net*) param)==1);
+                                       ret=(matchnet(ip, r->net)==1);
                                        break;
                                case DIFF_OP:
-                                       ret=(matchnet(ip, (struct net*) param)!=1);
+                                       ret=(matchnet(ip, r->net)!=1);
                                        break;
                                default:
                                        goto error_op;
@@ -453,14 +575,14 @@ inline static int comp_ip(struct ip_addr* ip, void* param, int op, int subtype)
                                case EQUAL_OP:
                                case MATCH_OP:
                                        /* 1: compare with ip2str*/
-                                       ret=comp_str(ip_addr2a(ip), param, op, subtype);
+                                       ret=comp_string(op, ip_addr2a(ip), rtype, r);
                                        if (ret==1) break;
                                        /* 2: resolve (name) & compare w/ all the ips */
-                                       if (subtype==STRING_ST){
-                                               he=resolvehost((char*)param);
+                                       if (rtype==STRING_ST){
+                                               he=resolvehost(r->str.s);
                                                if (he==0){
                                                        DBG("comp_ip: could not resolve %s\n",
-                                                                       (char*)param);
+                                                           r->str.s);
                                                }else if (he->h_addrtype==ip->af){
                                                        for(h=he->h_addr_list;(ret!=1)&& (*h); h++){
                                                                ret=(memcmp(ip->u.addr, *h, ip->len)==0);
@@ -478,15 +600,15 @@ inline static int comp_ip(struct ip_addr* ip, void* param, int op, int subtype)
                                        ret=0;
                                        }else{
                                                /*  compare with primary host name */
-                                               ret=comp_str(he->h_name, param, op, subtype);
+                                               ret=comp_string(op, he->h_name, rtype, r);
                                                /* compare with all the aliases */
                                                for(h=he->h_aliases; (ret!=1) && (*h); h++){
-                                                       ret=comp_str(*h, param, op, subtype);
+                                                       ret=comp_string(op, *h, rtype, r);
                                                }
                                        }
                                        break;
                                case DIFF_OP:
-                                       ret=comp_ip(ip, param, EQUAL_OP, subtype);
+                                       ret=comp_ip(EQUAL_OP, ip, rtype, r);
                                        if (ret>=0) ret=!ret;
                                        break;
                                default:
@@ -500,7 +622,7 @@ inline static int comp_ip(struct ip_addr* ip, void* param, int op, int subtype)
                        break;
                default:
                        LOG(L_CRIT, "BUG: comp_ip: invalid type for "
-                                               " src_ip or dst_ip (%d)\n", subtype);
+                                               " src_ip or dst_ip (%d)\n", rtype);
                        ret=-1;
        }
        return ret;
@@ -511,11 +633,9 @@ error_op:
 }
 
 
-
 /* returns: 0/1 (false/true) or -1 on error, -127 EXPR_DROP */
 static int eval_elem(struct expr* e, struct sip_msg* msg)
 {
-
        struct sip_uri uri;
        int ret;
        ret=E_BUG;
@@ -524,110 +644,127 @@ static int eval_elem(struct expr* e, struct sip_msg* msg)
                LOG(L_CRIT," BUG: eval_elem: invalid type\n");
                goto error;
        }
-       switch(e->l.operand){
-               case METHOD_O:
-                               ret=comp_strstr(&msg->first_line.u.request.method, e->r.param,
-                                                               e->op, e->subtype);
-                               break;
-               case URI_O:
-                               if(msg->new_uri.s){
-                                       if (e->subtype==MYSELF_ST){
-                                               if (parse_sip_msg_uri(msg)<0) ret=-1;
-                                               else    ret=check_self_op(e->op, &msg->parsed_uri.host,
-                                                                       msg->parsed_uri.port_no?
-                                                                       msg->parsed_uri.port_no:SIP_PORT);
-                                       }else{
-                                               ret=comp_strstr(&msg->new_uri, e->r.param,
-                                                                               e->op, e->subtype);
-                                       }
-                               }else{
-                                       if (e->subtype==MYSELF_ST){
-                                               if (parse_sip_msg_uri(msg)<0) ret=-1;
-                                               else    ret=check_self_op(e->op, &msg->parsed_uri.host,
-                                                                       msg->parsed_uri.port_no?
-                                                                       msg->parsed_uri.port_no:SIP_PORT);
-                                       }else{
-                                               ret=comp_strstr(&msg->first_line.u.request.uri,
-                                                                                e->r.param, e->op, e->subtype);
-                                       }
-                               }
-                               break;
-               case FROM_URI_O:
-                               if (parse_from_header(msg)!=0){
-                                       LOG(L_ERR, "ERROR: eval_elem: bad or missing"
-                                                               " From: header\n");
-                                       goto error;
-                               }
-                               if (e->subtype==MYSELF_ST){
-                                       if (parse_uri(get_from(msg)->uri.s, get_from(msg)->uri.len,
-                                                                       &uri) < 0){
-                                               LOG(L_ERR, "ERROR: eval_elem: bad uri in From:\n");
-                                               goto error;
-                                       }
-                                       ret=check_self_op(e->op, &uri.host,
-                                                                               uri.port_no?uri.port_no:SIP_PORT);
-                               }else{
-                                       ret=comp_strstr(&get_from(msg)->uri,
-                                                       e->r.param, e->op, e->subtype);
-                               }
-                               break;
-               case TO_URI_O:
-                               if ((msg->to==0) && ((parse_headers(msg, HDR_TO_F, 0)==-1) ||
-                                                       (msg->to==0))){
-                                       LOG(L_ERR, "ERROR: eval_elem: bad or missing"
-                                                               " To: header\n");
-                                       goto error;
-                               }
-                               /* to content is parsed automatically */
-                               if (e->subtype==MYSELF_ST){
-                                       if (parse_uri(get_to(msg)->uri.s, get_to(msg)->uri.len,
-                                                                       &uri) < 0){
-                                               LOG(L_ERR, "ERROR: eval_elem: bad uri in To:\n");
-                                               goto error;
-                                       }
-                                       ret=check_self_op(e->op, &uri.host,
-                                                                               uri.port_no?uri.port_no:SIP_PORT);
-                               }else{
-                                       ret=comp_strstr(&get_to(msg)->uri,
-                                                                               e->r.param, e->op, e->subtype);
-                               }
-                               break;
-               case SRCIP_O:
-                               ret=comp_ip(&msg->rcv.src_ip, e->r.param, e->op, e->subtype);
-                               break;
-               case DSTIP_O:
-                               ret=comp_ip(&msg->rcv.dst_ip, e->r.param, e->op, e->subtype);
-                               break;
-               case NUMBER_O:
-                               ret=!(!e->r.intval); /* !! to transform it in {0,1} */
-                               break;
-               case ACTION_O:
-                               ret=run_actions( (struct action*)e->r.param, msg);
-                               if (ret<=0) ret=(ret==0)?EXPR_DROP:0;
-                               else ret=1;
-                               break;
-               case SRCPORT_O:
-                               ret=comp_no(msg->rcv.src_port, 
-                                       e->r.param, /* e.g., 5060 */
-                                       e->op, /* e.g. == */
-                                       e->subtype /* 5060 is number */);
-                               break;
-               case DSTPORT_O:
-                               ret=comp_no(msg->rcv.dst_port, e->r.param, e->op, 
-                                                       e->subtype);
-                               break;
-               case PROTO_O:
-                               ret=comp_no(msg->rcv.proto, e->r.param, e->op, e->subtype);
-                               break;
-               case AF_O:
-                               ret=comp_no(msg->rcv.src_ip.af, e->r.param, e->op, e->subtype);
-                               break;
-               case MSGLEN_O:
-                               ret=comp_no(msg->len, e->r.param, e->op, e->subtype);
-                               break;
-               default:
-                               LOG(L_CRIT, "BUG: eval_elem: invalid operand %d\n",
-                                                       e->l.operand);
+       switch(e->l_type){
+       case METHOD_O:
+               ret=comp_str(e->op, &msg->first_line.u.request.method, 
+                            e->r_type, &e->r);
+               break;
+       case URI_O:
+               if(msg->new_uri.s) {
+                       if (e->r_type==MYSELF_ST){
+                               if (parse_sip_msg_uri(msg)<0) ret=-1;
+                               else ret=check_self_op(e->op, &msg->parsed_uri.host,
+                                                      msg->parsed_uri.port_no?
+                                                      msg->parsed_uri.port_no:SIP_PORT);
+                       }else{
+                               ret=comp_str(e->op, &msg->new_uri, 
+                                            e->r_type, &e->r);
+                       }
+               }else{
+                       if (e->r_type==MYSELF_ST){
+                               if (parse_sip_msg_uri(msg)<0) ret=-1;
+                               else ret=check_self_op(e->op, &msg->parsed_uri.host,
+                                                      msg->parsed_uri.port_no?
+                                                      msg->parsed_uri.port_no:SIP_PORT);
+                       }else{
+                               ret=comp_str(e->op, &msg->first_line.u.request.uri,
+                                            e->r_type, &e->r);
+                       }
+               }
+               break;
+               
+       case FROM_URI_O:
+               if (parse_from_header(msg)!=0){
+                       LOG(L_ERR, "ERROR: eval_elem: bad or missing"
+                           " From: header\n");
+                       goto error;
+               }
+               if (e->r_type==MYSELF_ST){
+                       if (parse_uri(get_from(msg)->uri.s, get_from(msg)->uri.len,
+                                     &uri) < 0){
+                               LOG(L_ERR, "ERROR: eval_elem: bad uri in From:\n");
+                               goto error;
+                       }
+                       ret=check_self_op(e->op, &uri.host,
+                                         uri.port_no?uri.port_no:SIP_PORT);
+               }else{
+                       ret=comp_str(e->op, &get_from(msg)->uri,
+                                    e->r_type, &e->r);
+               }
+               break;
+
+       case TO_URI_O:
+               if ((msg->to==0) && ((parse_headers(msg, HDR_TO_F, 0)==-1) ||
+                                    (msg->to==0))){
+                       LOG(L_ERR, "ERROR: eval_elem: bad or missing"
+                           " To: header\n");
+                       goto error;
+               }
+                    /* to content is parsed automatically */
+               if (e->r_type==MYSELF_ST){
+                       if (parse_uri(get_to(msg)->uri.s, get_to(msg)->uri.len,
+                                     &uri) < 0){
+                               LOG(L_ERR, "ERROR: eval_elem: bad uri in To:\n");
+                               goto error;
+                       }
+                       ret=check_self_op(e->op, &uri.host,
+                                         uri.port_no?uri.port_no:SIP_PORT);
+               }else{
+                       ret=comp_str(e->op, &get_to(msg)->uri,
+                                    e->r_type, &e->r);
+               }
+               break;
+               
+       case SRCIP_O:
+               ret=comp_ip(e->op, &msg->rcv.src_ip, e->r_type, &e->r);
+               break;
+               
+       case DSTIP_O:
+               ret=comp_ip(e->op, &msg->rcv.dst_ip, e->r_type, &e->r);
+               break;
+
+       case NUMBER_O:
+               ret=!(!e->r.intval); /* !! to transform it in {0,1} */
+               break;
+
+       case ACTION_O:
+               ret=run_actions( (struct action*)e->r.param, msg);
+               if (ret<=0) ret=(ret==0)?EXPR_DROP:0;
+               else ret=1;
+               break;
+               
+       case SRCPORT_O:
+               ret=comp_num(e->op, (int)msg->rcv.src_port, 
+                            e->r_type, &e->r);
+               break;
+               
+       case DSTPORT_O:
+               ret=comp_num(e->op, (int)msg->rcv.dst_port, 
+                            e->r_type, &e->r);
+               break;
+               
+       case PROTO_O:
+               ret=comp_num(e->op, msg->rcv.proto, 
+                            e->r_type, &e->r);
+               break;
+               
+       case AF_O:
+               ret=comp_num(e->op, (int)msg->rcv.src_ip.af, 
+                            e->r_type, &e->r);
+               break;
+
+       case MSGLEN_O:
+               ret=comp_num(e->op, (int)msg->len, 
+                               e->r_type, &e->r);
+               break;
+
+       case AVP_ST:
+               ret = comp_avp(e->op, e->l.attr, e->r_type, &e->r);
+               break;
+               
+       default:
+               LOG(L_CRIT, "BUG: eval_elem: invalid operand %d\n",
+                   e->l_type);
        }
        return ret;
 error:
@@ -654,13 +791,13 @@ int eval_expr(struct expr* e, struct sip_msg* msg)
                ret=eval_elem(e, msg);
        }else if (e->type==EXP_T){
                switch(e->op){
-                       case AND_OP:
+                       case LOGAND_OP:
                                ret=eval_expr(e->l.expr, msg);
                                /* if error or false stop evaluating the rest */
                                if (ret!=1) break;
                                ret=eval_expr(e->r.expr, msg); /*ret1 is 1*/
                                break;
-                       case OR_OP:
+                       case LOGOR_OP:
                                ret=eval_expr(e->l.expr, msg);
                                /* if true or error stop evaluating the rest */
                                if (ret!=0) break;
@@ -756,8 +893,7 @@ int fix_rls()
 /* debug function, prints main routing table */
 void print_rl()
 {
-       struct action* t;
-       int i,j;
+       int j;
 
        for(j=0; j<RT_NO; j++){
                if (rlist[j]==0){
@@ -765,9 +901,7 @@ void print_rl()
                        continue;
                }
                DBG("routing table %d:\n",j);
-               for (t=rlist[j],i=0; t; i++, t=t->next){
-                       print_action(t);
-               }
+               print_actions(rlist[j]);
                DBG("\n");
        }
        for(j=0; j<ONREPLY_RT_NO; j++){
@@ -775,9 +909,7 @@ void print_rl()
                        continue;
                }
                DBG("onreply routing table %d:\n",j);
-               for (t=onreply_rlist[j],i=0; t; i++, t=t->next){
-                       print_action(t);
-               }
+               print_actions(onreply_rlist[j]);
                DBG("\n");
        }
        for(j=0; j<FAILURE_RT_NO; j++){
@@ -785,9 +917,7 @@ void print_rl()
                        continue;
                }
                DBG("failure routing table %d:\n",j);
-               for (t=failure_rlist[j],i=0; t; i++, t=t->next){
-                       print_action(t);
-               }
+               print_actions(failure_rlist[j]);
                DBG("\n");
        }
        for(j=0; j<BRANCH_RT_NO; j++){
@@ -795,9 +925,7 @@ void print_rl()
                        continue;
                }
                DBG("branch routing table %d:\n",j);
-               for (t=branch_rlist[j],i=0; t; i++, t=t->next){
-                       print_action(t);
-               }
+               print_actions(branch_rlist[j]);
                DBG("\n");
        }
 }
index 6838284..a68e7f7 100644 (file)
@@ -46,6 +46,7 @@
 #include "dprint.h"
 #include "ip_addr.h"
 #include "mem/mem.h"
+#include "usr_avp.h"
 #include "ut.h" /* ZSW() */
 
 
@@ -65,16 +66,17 @@ error:
 }
 
 
-struct expr* mk_elem(int op, int subtype, int operand, void* param)
+struct expr* mk_elem(int op, int ltype, void* lparam, int rtype, void* rparam)
 {
        struct expr * e;
        e=(struct expr*)pkg_malloc(sizeof (struct expr));
        if (e==0) goto error;
        e->type=ELEM_T;
        e->op=op;
-       e->subtype=subtype;
-       e->l.operand=operand;
-       e->r.param=param;
+       e->l_type=ltype;
+       e->l.param=lparam;
+       e->r_type = rtype;
+       e->r.param=rparam;
        return e;
 error:
        LOG(L_CRIT, "ERROR: mk_elem: memory allocation failure\n");
@@ -84,7 +86,7 @@ error:
 
 
 struct action* mk_action(int type, int p1_type, int p2_type,
-                                                                                       void* p1, void* p2)
+                        void* p1, void* p2)
 {
        struct action* a;
        a=(struct action*)pkg_malloc(sizeof(struct action));
@@ -140,7 +142,7 @@ void print_expr(struct expr* exp)
                return;
        }
        if (exp->type==ELEM_T){
-               switch(exp->l.operand){
+               switch(exp->l_type){
                        case METHOD_O:
                                DBG("method");
                                break;
@@ -169,6 +171,10 @@ void print_expr(struct expr* exp)
                                break;
                        case ACTION_O:
                                break;
+                       case AVP_ST:
+                               DBG("attr");
+                               break;
+                       
                        default:
                                DBG("UNKNOWN");
                }
@@ -199,7 +205,7 @@ void print_expr(struct expr* exp)
                        default:
                                DBG("<UNKNOWN>");
                }
-               switch(exp->subtype){
+               switch(exp->r_type){
                        case NOSUBTYPE: 
                                        DBG("N/A");
                                        break;
@@ -213,7 +219,7 @@ void print_expr(struct expr* exp)
                                        print_ip("", (struct ip_addr*)exp->r.param, "");
                                        break;
                        case ACTIONS_ST:
-                                       print_action((struct action*)exp->r.param);
+                                       print_actions((struct action*)exp->r.param);
                                        break;
                        case NUMBER_ST:
                                        DBG("%d",exp->r.intval);
@@ -221,19 +227,23 @@ void print_expr(struct expr* exp)
                        case MYSELF_ST:
                                        DBG("_myself_");
                                        break;
+                       case AVP_ST:
+                               DBG("attr");
+                               break;
+                       
                        default:
-                                       DBG("type<%d>", exp->subtype);
+                                       DBG("type<%d>", exp->r_type);
                }
        }else if (exp->type==EXP_T){
                switch(exp->op){
-                       case AND_OP:
+                       case LOGAND_OP:
                                        DBG("AND( ");
                                        print_expr(exp->l.expr);
                                        DBG(", ");
                                        print_expr(exp->r.expr);
                                        DBG(" )");
                                        break;
-                       case OR_OP:
+                       case LOGOR_OP:
                                        DBG("OR( ");
                                        print_expr(exp->l.expr);
                                        DBG(", ");
@@ -257,201 +267,214 @@ void print_expr(struct expr* exp)
 
                                        
 
-void print_action(struct action* a)
+void print_action(struct action* t)
 {
-       struct action* t;
-       for(t=a; t!=0;t=t->next){
-               switch(t->type){
-                       case FORWARD_T:
-                                       DBG("forward(");
-                                       break;
-                       case FORWARD_TCP_T:
-                                       DBG("forward_tcp(");
-                                       break;
-                       case FORWARD_UDP_T:
-                                       DBG("forward_udp(");
-                                       break;
-                       case SEND_T:
-                                       DBG("send(");
-                                       break;
-                       case SEND_TCP_T:
-                                       DBG("send_tcp(");
-                                       break;
-                       case DROP_T:
-                                       DBG("drop(");
-                                       break;
-                       case LOG_T:
-                                       DBG("log(");
-                                       break;
-                       case ERROR_T:
-                                       DBG("error(");
-                                       break;
-                       case ROUTE_T:
-                                       DBG("route(");
-                                       break;
-                       case EXEC_T:
-                                       DBG("exec(");
-                                       break;
-                       case REVERT_URI_T:
-                                       DBG("revert_uri(");
-                                       break;
-                       case STRIP_T:
-                                       DBG("strip(");
-                                       break;
-                       case APPEND_BRANCH_T:
-                                       DBG("append_branch(");
-                                       break;
-                       case PREFIX_T:
-                                       DBG("prefix(");
-                                       break;
-                       case LEN_GT_T:
-                                       DBG("len_gt(");
-                                       break;
-                       case SETFLAG_T:
-                                       DBG("setflag(");
-                                       break;
-                       case RESETFLAG_T:
-                                       DBG("resetflag(");
-                                       break;
-                       case ISFLAGSET_T:
-                                       DBG("isflagset(");
-                                       break;
-                       case SET_HOST_T:
-                                       DBG("sethost(");
-                                       break;
-                       case SET_HOSTPORT_T:
-                                       DBG("sethostport(");
-                                       break;
-                       case SET_USER_T:
-                                       DBG("setuser(");
-                                       break;
-                       case SET_USERPASS_T:
-                                       DBG("setuserpass(");
-                                       break;
-                       case SET_PORT_T:
-                                       DBG("setport(");
-                                       break;
-                       case SET_URI_T:
-                                       DBG("seturi(");
-                                       break;
-                       case IF_T:
-                                       DBG("if (");
-                                       break;
-                       case MODULE_T:
-                                       DBG(" external_module_call(");
-                                       break;
-                       case FORCE_RPORT_T:
-                                       DBG("force_rport(");
-                                       break;
-                       case SET_ADV_ADDR_T:
-                                       DBG("set_advertised_address(");
-                                       break;
-                       case SET_ADV_PORT_T:
-                                       DBG("set_advertised_port(");
-                                       break;
-                       case FORCE_TCP_ALIAS_T:
-                                       DBG("force_tcp_alias(");
-                                       break;
-                       case LOAD_AVP_T:
-                                       DBG("load_avp(");
-                                       break;
-                       case AVP_TO_URI_T:
-                                       DBG("avp_to_attr");
-                                       break;
-                       case FORCE_SEND_SOCKET_T:
-                                       DBG("force_send_socket");
-                                       break;
-                       default:
-                                       DBG("UNKNOWN(");
-               }
-               switch(t->p1_type){
-                       case STRING_ST:
-                                       DBG("\"%s\"", ZSW(t->p1.string));
-                                       break;
-                       case NUMBER_ST:
-                                       DBG("%lu",t->p1.number);
-                                       break;
-                       case IP_ST:
-                                       print_ip("", (struct ip_addr*)t->p1.data, "");
-                                       break;
-                       case EXPR_ST:
-                                       print_expr((struct expr*)t->p1.data);
-                                       break;
-                       case ACTIONS_ST:
-                                       print_action((struct action*)t->p1.data);
-                                       break;
-                       case CMDF_ST:
-                                       DBG("f_ptr<%p>",t->p1.data);
-                                       break;
-                       case SOCKID_ST:
-                                       DBG("%d:%s:%d",
-                                                       ((struct socket_id*)t->p1.data)->proto,
-                                                       ZSW(((struct socket_id*)t->p1.data)->name),
-                                                       ((struct socket_id*)t->p1.data)->port
-                                                       );
-                                       break;
-                       default:
-                                       DBG("type<%d>", t->p1_type);
-               }
-               if (t->type==IF_T) DBG(") {");
-               switch(t->p2_type){
-                       case NOSUBTYPE:
-                                       break;
-                       case STRING_ST:
-                                       DBG(", \"%s\"", ZSW(t->p2.string));
-                                       break;
-                       case NUMBER_ST:
-                                       DBG(", %lu",t->p2.number);
-                                       break;
-                       case EXPR_ST:
-                                       print_expr((struct expr*)t->p2.data);
-                                       break;
-                       case ACTIONS_ST:
-                                       print_action((struct action*)t->p2.data);
-                                       break;
-                       case SOCKID_ST:
-                                       DBG("%d:%s:%d",
-                                                       ((struct socket_id*)t->p1.data)->proto,
-                                                       ZSW(((struct socket_id*)t->p1.data)->name),
-                                                       ((struct socket_id*)t->p1.data)->port
-                                                       );
-                                       break;
-                       default:
-                                       DBG(", type<%d>", t->p2_type);
-               }
-               if (t->type==IF_T) DBG("} else {");
-               switch(t->p3_type){
-                       case NOSUBTYPE:
-                                       break;
-                       case STRING_ST:
-                                       DBG(", \"%s\"", ZSW(t->p3.string));
-                                       break;
-                       case NUMBER_ST:
-                                       DBG(", %lu",t->p3.number);
-                                       break;
-                       case EXPR_ST:
-                                       print_expr((struct expr*)t->p3.data);
-                                       break;
-                       case ACTIONS_ST:
-                                       print_action((struct action*)t->p3.data);
-                                       break;
-                       case SOCKID_ST:
-                                       DBG("%d:%s:%d",
-                                                       ((struct socket_id*)t->p1.data)->proto,
-                                                       ZSW(((struct socket_id*)t->p1.data)->name),
-                                                       ((struct socket_id*)t->p1.data)->port
-                                                       );
-                                       break;
-                       default:
-                                       DBG(", type<%d>", t->p3_type);
-               }
-               if (t->type==IF_T) DBG("}; ");
-               else    DBG("); ");
+       switch(t->type){
+       case FORWARD_T:
+               DBG("forward(");
+               break;
+       case FORWARD_TCP_T:
+               DBG("forward_tcp(");
+               break;
+       case FORWARD_UDP_T:
+               DBG("forward_udp(");
+               break;
+       case SEND_T:
+               DBG("send(");
+               break;
+       case SEND_TCP_T:
+               DBG("send_tcp(");
+               break;
+       case DROP_T:
+               DBG("drop(");
+               break;
+       case LOG_T:
+               DBG("log(");
+               break;
+       case ERROR_T:
+               DBG("error(");
+               break;
+       case ROUTE_T:
+               DBG("route(");
+               break;
+       case EXEC_T:
+               DBG("exec(");
+               break;
+       case REVERT_URI_T:
+               DBG("revert_uri(");
+               break;
+       case STRIP_T:
+               DBG("strip(");
+               break;
+       case APPEND_BRANCH_T:
+               DBG("append_branch(");
+               break;
+       case PREFIX_T:
+               DBG("prefix(");
+               break;
+       case LEN_GT_T:
+               DBG("len_gt(");
+               break;
+       case SETFLAG_T:
+               DBG("setflag(");
+               break;
+       case RESETFLAG_T:
+               DBG("resetflag(");
+               break;
+       case ISFLAGSET_T:
+               DBG("isflagset(");
+               break;
+       case SET_HOST_T:
+               DBG("sethost(");
+               break;
+       case SET_HOSTPORT_T:
+               DBG("sethostport(");
+               break;
+       case SET_USER_T:
+               DBG("setuser(");
+               break;
+       case SET_USERPASS_T:
+               DBG("setuserpass(");
+               break;
+       case SET_PORT_T:
+               DBG("setport(");
+               break;
+       case SET_URI_T:
+               DBG("seturi(");
+               break;
+       case IF_T:
+               DBG("if (");
+               break;
+       case MODULE_T:
+               DBG(" external_module_call(");
+               break;
+       case FORCE_RPORT_T:
+               DBG("force_rport(");
+               break;
+       case SET_ADV_ADDR_T:
+               DBG("set_advertised_address(");
+               break;
+       case SET_ADV_PORT_T:
+               DBG("set_advertised_port(");
+               break;
+       case FORCE_TCP_ALIAS_T:
+               DBG("force_tcp_alias(");
+               break;
+       case LOAD_AVP_T:
+               DBG("load_avp(");
+               break;
+       case AVP_TO_URI_T:
+               DBG("avp_to_attr");
+               break;
+       case FORCE_SEND_SOCKET_T:
+               DBG("force_send_socket");
+               break;
+       case ASSIGN_T
+:              DBG("assign(");
+               break;
+       case ADD_T:
+               DBG("assign_add(");
+               break;
+       default:
+               DBG("UNKNOWN(");
+       }
+       switch(t->p1_type){
+       case STRING_ST:
+               DBG("\"%s\"", ZSW(t->p1.string));
+               break;
+       case NUMBER_ST:
+               DBG("%lu",t->p1.number);
+               break;
+       case IP_ST:
+               print_ip("", (struct ip_addr*)t->p1.data, "");
+               break;
+       case EXPR_ST:
+               print_expr((struct expr*)t->p1.data);
+               break;
+       case ACTIONS_ST:
+               print_actions((struct action*)t->p1.data);
+               break;
+       case CMDF_ST:
+               DBG("f_ptr<%p>",t->p1.data);
+               break;
+       case SOCKID_ST:
+               DBG("%d:%s:%d",
+                   ((struct socket_id*)t->p1.data)->proto,
+                   ZSW(((struct socket_id*)t->p1.data)->name),
+                   ((struct socket_id*)t->p1.data)->port
+                   );
+               break;
+       case AVP_ST:
+               DBG("avp(%u,%.*s)", t->p1.attr->type, t->p1.attr->name.s.len, ZSW(t->p1.attr->name.s.s));
+               break;
+       default:
+               DBG("type<%d>", t->p1_type);
        }
+       if (t->type==IF_T) DBG(") {");
+       switch(t->p2_type){
+       case NOSUBTYPE:
+               break;
+       case STRING_ST:
+               DBG(", \"%s\"", ZSW(t->p2.string));
+               break;
+       case NUMBER_ST:
+               DBG(", %lu",t->p2.number);
+               break;
+       case EXPR_ST:
+               print_expr((struct expr*)t->p2.data);
+               break;
+       case ACTION_ST:
+       case ACTIONS_ST:
+               print_actions((struct action*)t->p2.data);
+               break;
+               
+       case SOCKID_ST:
+               DBG("%d:%s:%d",
+                   ((struct socket_id*)t->p1.data)->proto,
+                   ZSW(((struct socket_id*)t->p1.data)->name),
+                   ((struct socket_id*)t->p1.data)->port
+                   );
+               break;
+       case AVP_ST:
+               DBG(", avp(%u,%.*s)", t->p2.attr->type, t->p2.attr->name.s.len, ZSW(t->p2.attr->name.s.s));
+               break;
+       default:
+               DBG(", type<%d>", t->p2_type);
+       }
+       if (t->type==IF_T) DBG("} else {");
+       switch(t->p3_type){
+       case NOSUBTYPE:
+               break;
+       case STRING_ST:
+               DBG(", \"%s\"", ZSW(t->p3.string));
+               break;
+       case NUMBER_ST:
+               DBG(", %lu",t->p3.number);
+               break;
+       case EXPR_ST:
+               print_expr((struct expr*)t->p3.data);
+               break;
+       case ACTIONS_ST:
+               print_actions((struct action*)t->p3.data);
+               break;
+       case SOCKID_ST:
+               DBG("%d:%s:%d",
+                   ((struct socket_id*)t->p1.data)->proto,
+                   ZSW(((struct socket_id*)t->p1.data)->name),
+                   ((struct socket_id*)t->p1.data)->port
+                   );
+               break;
+       default:
+               DBG(", type<%d>", t->p3_type);
+       }
+       if (t->type==IF_T) DBG("}; ");
+       else    DBG("); ");
 }
-                       
-       
-
-       
-       
 
+void print_actions(struct action* a)
+{
+       while(a) {
+               print_action(a);
+               a = a->next;
+       }
+}
index de42c21..42429ab 100644 (file)
@@ -39,6 +39,9 @@
 #ifndef route_struct_h
 #define route_struct_h
 
+#include <regex.h>
+#include "usr_avp.h"
+
 #define EXPR_DROP -127  /* used only by the expression and if evaluator */
 /*
  * Other important values (no macros for them yet):
 
 
 enum { EXP_T=1, ELEM_T };
-enum { AND_OP=1, OR_OP, NOT_OP };
+enum { LOGAND_OP=1, LOGOR_OP, NOT_OP, BINAND_OP, BINOR_OP };
 enum { EQUAL_OP=10, MATCH_OP, GT_OP, LT_OP, GTE_OP, LTE_OP, DIFF_OP, NO_OP };
 enum { METHOD_O=1, URI_O, FROM_URI_O, TO_URI_O, SRCIP_O, SRCPORT_O,
           DSTIP_O, DSTPORT_O, PROTO_O, AF_O, MSGLEN_O, DEFAULT_O, ACTION_O,
-          NUMBER_O};
+          NUMBER_O, AVP_O};
 
 enum { FORWARD_T=1, SEND_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T,
                SET_HOST_T, SET_HOSTPORT_T, SET_USER_T, SET_USERPASS_T, 
@@ -76,26 +79,34 @@ enum { FORWARD_T=1, SEND_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T,
                FORCE_TCP_ALIAS_T,
                LOAD_AVP_T,
                AVP_TO_URI_T,
-               FORCE_SEND_SOCKET_T
+                FORCE_SEND_SOCKET_T,
+                ASSIGN_T,
+                ADD_T
+       
 };
 enum { NOSUBTYPE=0, STRING_ST, NET_ST, NUMBER_ST, IP_ST, RE_ST, PROXY_ST,
                EXPR_ST, ACTIONS_ST, CMDF_ST, MODFIXUP_ST, URIHOST_ST, URIPORT_ST,
-               MYSELF_ST, STR_ST, SOCKID_ST, SOCKETINFO_ST };
-
+               MYSELF_ST, STR_ST, SOCKID_ST, SOCKETINFO_ST, ACTION_ST, AVP_ST };
+
+
+/* Expression operand */
+union exp_op {
+       struct expr* expr;
+       str str;
+       char* string;
+       void* param;
+       int intval;
+       avp_spec_t* attr;
+       regex_t* re;
+       struct net* net;
+};
        
 struct expr{
        int type; /* exp, exp_elem */
        int op; /* and, or, not | ==,  =~ */
-       int  subtype;
-       union {
-               struct expr* expr;
-               int operand;
-       }l;
-       union {
-               struct expr* expr;
-               void* param;
-               int   intval;
-       }r;
+       int l_type, r_type;
+       union exp_op l;
+       union exp_op r;
 };
 
 
@@ -107,15 +118,16 @@ struct action{
        union {
                long number;
                char* string;
+               str str;
                void* data;
+               avp_spec_t* attr;
        }p1, p2, p3;
        struct action* next;
 };
 
-
-
 struct expr* mk_exp(int op, struct expr* left, struct expr* right);
-struct expr* mk_elem(int op, int subtype, int operand, void* param);
+struct expr* mk_elem(int op, int ltype, void* lparam, int rtype, void* rparam);
+
 struct action* mk_action(int type, int p1_type, int p2_type,
                                                        void* p1, void* p2);
 struct action* mk_action3(int type, int p1_type, int p2_type, int p3_type, 
@@ -124,6 +136,7 @@ struct action* append_action(struct action* a, struct action* b);
 
 
 void print_action(struct action* a);
+void print_actions(struct action* a);
 void print_expr(struct expr* exp);