Browse code

=AVP core extended to be aware of multiple AVPs with the same name exist in the list. There are three possibilities of correct script syntax...

$prefix.name - it MUST be only one AVP with that name to match binary
operators or on the right side of assignment

$prefix.name[] - allowed on both sides of assignment
on left side means - enable more AVPS with the same name
on the right side - all AVPs with the name are added (correctly ordered)

$prefix.name[index] - allowed on right side of assignment and as binary
operand, corresponds to value of index-th AVP in the list (if such exists)

1 means the AVP, which was added FIRST to the list (this unfortunatelly
means, that the AVP name is scanned through the whole list)
-1 means the AVP, which was added LAST to the list

prefix is one of following
f - FROM USER
t - TO USER
fd- FROM DOMAIN
td- TO DOMAIN
g - GLOBAL

and if ommited, the default FROM USER is used

=new function parse_avp_name, needs to be enhanced (does not accept
whitespace as the script parser does)

=new function search_avp_by_index, usable even for variant without the
brackets (then it checks the name exclusivity)

=xlog module uses new avp parse and search_by_index function
format string is %avp_syntax, e.g. %$MyAVP[1]

=avp module merged functions from another branch, not updated to new AVP
syntax fully

=script parser updated to new syntax

Michal Matyska authored on 07/01/2006 21:28:49
Showing 9 changed files
... ...
@@ -1,3 +1,4 @@
1
+
1 2
 /*
2 3
  * $Id$
3 4
  *
... ...
@@ -714,6 +715,12 @@ int do_action(struct action* a, struct sip_msg* msg)
714 714
 
715 715
 	        case ADD_T:
716 716
 	        case ASSIGN_T:
717
+		
718
+			/* If the left attr was specified withou indexing brackets delete
719
+			 * existing AVPs before adding new ones
720
+			 */
721
+			if ((a->p1.attr->type & AVP_INDEX_ALL) != AVP_INDEX_ALL) delete_avp(a->p1.attr->type, a->p1.attr->name);
722
+			
717 723
 			if (a->p2_type == STRING_ST) {
718 724
 				value.s = a->p2.str;
719 725
 				flags = a->p1.attr->type | AVP_VAL_STR;
... ...
@@ -750,27 +757,45 @@ int do_action(struct action* a, struct sip_msg* msg)
750 750
 			} else if (a->p2_type == AVP_ST) {
751 751
 				struct search_state st;
752 752
 				avp_t* avp; 
753
+				avp_t* avp_mark;
753 754
 				
754
-				     /* If the action is assign then remove the old avp value before adding
755
-				      * new ones
756
-				      */
757
-				if ((unsigned char)a->type == ASSIGN_T) delete_avp(a->p1.attr->type, a->p1.attr->name);
758
-
759
-				avp = search_first_avp(a->p2.attr->type, a->p2.attr->name, &value, &st);
760
-				while(avp) {
761
-					     /* We take only the type of value and name from the source avp
762
-					      * and reset class and track flags
763
-					      */
764
-					flags = a->p1.attr->type | (avp->flags & ~(AVP_CLASS_ALL|AVP_TRACK_ALL));
765
-					if (add_avp(flags, name, value) < 0) {
766
-						LOG(L_CRIT, "ERROR: Failed to assign value to attribute\n");
767
-					 	ret=E_UNSPEC;
755
+				avp_mark = NULL;
756
+				if ((a->p2.attr->type & AVP_INDEX_ALL) == AVP_INDEX_ALL) {
757
+					avp = search_first_avp(a->p2.attr->type, a->p2.attr->name, &value, &st);
758
+					while(avp) {
759
+						     /* We take only the type of value and name from the source avp
760
+						      * and reset class and track flags
761
+						      */
762
+						flags = (a->p1.attr->type & ~AVP_INDEX_ALL) | (avp->flags & ~(AVP_CLASS_ALL|AVP_TRACK_ALL));
763
+						
764
+						if (add_avp_before(avp_mark, flags, a->p1.attr->name, value) < 0) {
765
+							LOG(L_CRIT, "ERROR: Failed to assign value to attribute\n");
766
+							ret=E_UNSPEC;
767
+							break;
768
+						}
769
+						
770
+						/* move the mark, so the next found AVP will come before the one currently added
771
+						 * so they will have the same order as in the source list
772
+						 */
773
+						if (avp_mark) {
774
+							avp_mark=avp_mark->next;
775
+						} else {
776
+							avp_mark=search_first_avp(flags, a->p1.attr->name, NULL, NULL);
777
+						}
778
+							
779
+						avp = search_next_avp(&st, &value);
780
+					}
781
+					ret = 1;
782
+					break;
783
+				} else {
784
+					avp = search_avp_by_index(a->p2.attr->type, a->p2.attr->name, &value, a->p2.attr->index);
785
+					if (avp) {
786
+						flags = a->p1.attr->type | (avp->flags & ~(AVP_CLASS_ALL|AVP_TRACK_ALL));
787
+					} else {
788
+						ret = E_UNSPEC;
768 789
 						break;
769 790
 					}
770
-					avp = search_next_avp(&st, &value);
771 791
 				}
772
-				ret = 1;
773
-				break;
774 792
 			} else if (a->p2_type == SELECT_ST) {
775 793
 				int r;
776 794
 				r = run_select(&value.s, a->p2.select, msg);
... ...
@@ -793,8 +818,8 @@ int do_action(struct action* a, struct sip_msg* msg)
793 793
 
794 794
 			/* If the action is assign then remove the old avp value
795 795
 			 * before adding new ones */
796
-			if ((unsigned char)a->type == ASSIGN_T) delete_avp(flags, name);
797
-			if (add_avp(flags, name, value) < 0) {
796
+//			if ((unsigned char)a->type == ASSIGN_T) delete_avp(flags, name);
797
+			if (add_avp(flags & ~AVP_INDEX_ALL, name, value) < 0) {
798 798
 				LOG(L_CRIT, "ERROR: Failed to assign value to attribute\n");
799 799
 				ret=E_UNSPEC;
800 800
 				break;
... ...
@@ -510,6 +510,10 @@ EAT_ABLE	[\ \t\b\r]
510 510
 <ATTR>{ATTR_TODOMAIN}   { count(); return ATTR_TODOMAIN; }
511 511
 <ATTR>{ATTR_GLOBAL}     { count(); return ATTR_GLOBAL; }
512 512
 <ATTR>{DOT}             { count(); return DOT; }
513
+<ATTR>{LBRACK}          { count(); return LBRACK; }
514
+<ATTR>{RBRACK}          { count(); return RBRACK; }
515
+<ATTR>{STAR}		{ count(); return STAR; }
516
+<ATTR>{DECNUMBER}	{ count(); yylval.intval=atoi(yytext);return NUMBER; }
513 517
 <ATTR>{ID}		{ count(); addstr(&s_buf, yytext, yyleng); 
514 518
                            yylval.strval=s_buf.s;
515 519
 			   memset(&s_buf, 0, sizeof(s_buf));
... ...
@@ -67,6 +67,7 @@
67 67
  * 2005-12-11  added onsend_route support, fcmd (filtered cmd),
68 68
  *             snd_{ip,port,proto,af}, to_{ip,proto} (andrei)
69 69
  * 2005-12-19  select framework (mma)
70
+ * 2006-01-06  AVP index support (mma)
70 71
  *
71 72
  */
72 73
 
... ...
@@ -336,6 +337,11 @@ static struct socket_id* mk_listen_id(char*, int, int);
336 336
 %type <strval> host_sep
337 337
 %type <intval> uri_type
338 338
 %type <attr> attr_id
339
+%type <attr> attr_id_num_idx
340
+%type <attr> attr_id_no_idx
341
+%type <attr> attr_id_ass
342
+%type <attr> attr_id_val
343
+%type <attr> attr_id_any
339 344
 //%type <intval> class_id
340 345
 %type <intval> assign_op
341 346
 %type <select> select_id
... ...
@@ -957,7 +963,7 @@ uri_type:	URI			{$$=URI_O;}
957 957
 		;
958 958
 
959 959
 exp_elem:	METHOD strop STRING	{$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
960
-                | METHOD strop attr_id  {$$ = mk_elem($2, METHOD_O, 0, AVP_ST, $3); }
960
+                | METHOD strop attr_id_val  {$$ = mk_elem($2, METHOD_O, 0, AVP_ST, $3); }
961 961
                 | METHOD strop select_id {$$ = mk_elem($2, METHOD_O, 0, SELECT_ST, $3); }
962 962
 		| METHOD strop  ID	{$$ = mk_elem($2, METHOD_O, 0, STRING_ST,$3); }
963 963
 		| METHOD strop error { $$=0; yyerror("string expected"); }
... ...
@@ -966,7 +972,7 @@ exp_elem:	METHOD strop STRING	{$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
966 966
 						}
967 967
 		| uri_type strop STRING	{$$ = mk_elem($2, $1, 0, STRING_ST, $3); }
968 968
                 | uri_type strop host 	{$$ = mk_elem($2, $1, 0, STRING_ST, $3); }
969
-                | uri_type strop attr_id {$$ = mk_elem($2, $1, 0, AVP_ST, $3); }
969
+                | uri_type strop attr_id_val {$$ = mk_elem($2, $1, 0, AVP_ST, $3); }
970 970
                 | uri_type strop select_id {$$ = mk_elem($2, $1, 0, SELECT_ST, $3); }
971 971
                 | uri_type equalop MYSELF {$$=mk_elem($2, $1, 0, MYSELF_ST, 0); }
972 972
 		| uri_type strop error { $$=0; yyerror("string or MYSELF expected"); }
... ...
@@ -974,19 +980,19 @@ exp_elem:	METHOD strop STRING	{$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
974 974
 									" == , != or =~ expected");
975 975
 					}
976 976
 		| SRCPORT intop NUMBER	{ $$=mk_elem($2, SRCPORT_O, 0, NUMBER_ST, (void*)$3 ); }
977
-		| SRCPORT intop attr_id { $$=mk_elem($2, SRCPORT_O, 0, AVP_ST, (void*)$3 ); }
977
+		| SRCPORT intop attr_id_val { $$=mk_elem($2, SRCPORT_O, 0, AVP_ST, (void*)$3 ); }
978 978
 		| SRCPORT intop error { $$=0; yyerror("number expected"); }
979 979
 		| SRCPORT error { $$=0; yyerror("==, !=, <,>, >= or <=  expected"); }
980 980
 
981 981
 		| DSTPORT intop NUMBER	{ $$=mk_elem($2, DSTPORT_O, 0, NUMBER_ST, (void*)$3 ); }
982
-		| DSTPORT intop attr_id	{ $$=mk_elem($2, DSTPORT_O, 0, AVP_ST, (void*)$3 ); }
982
+		| DSTPORT intop attr_id_val	{ $$=mk_elem($2, DSTPORT_O, 0, AVP_ST, (void*)$3 ); }
983 983
 		| DSTPORT intop error { $$=0; yyerror("number expected"); }
984 984
 		| DSTPORT error { $$=0; yyerror("==, !=, <,>, >= or <=  expected"); }
985 985
 
986 986
 		| SNDPORT intop NUMBER	{	onsend_check("snd_port");
987 987
 									$$=mk_elem($2, SNDPORT_O, 0, NUMBER_ST,
988 988
 												(void*)$3 ); }
989
-		| SNDPORT intop attr_id {	onsend_check("snd_port");
989
+		| SNDPORT intop attr_id_val {	onsend_check("snd_port");
990 990
 									$$=mk_elem($2, SNDPORT_O, 0, AVP_ST,
991 991
 												(void*)$3 ); }
992 992
 		| SNDPORT intop error { $$=0; yyerror("number expected"); }
... ...
@@ -995,14 +1001,14 @@ exp_elem:	METHOD strop STRING	{$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
995 995
 		| TOPORT intop NUMBER	{	onsend_check("to_port");
996 996
 									$$=mk_elem($2, TOPORT_O, 0, NUMBER_ST,
997 997
 												(void*)$3 ); }
998
-		| TOPORT intop attr_id {	onsend_check("to_port");
998
+		| TOPORT intop attr_id_val {	onsend_check("to_port");
999 999
 									$$=mk_elem($2, TOPORT_O, 0, AVP_ST,
1000 1000
 												(void*)$3 ); }
1001 1001
 		| TOPORT intop error { $$=0; yyerror("number expected"); }
1002 1002
 		| TOPORT error { $$=0; yyerror("==, !=, <,>, >= or <=  expected"); }
1003 1003
 
1004 1004
 		| PROTO intop proto	{ $$=mk_elem($2, PROTO_O, 0, NUMBER_ST, (void*)$3 ); }
1005
-		| PROTO intop attr_id	{ $$=mk_elem($2, PROTO_O, 0, AVP_ST, (void*)$3 ); }
1005
+		| PROTO intop attr_id_val	{ $$=mk_elem($2, PROTO_O, 0, AVP_ST, (void*)$3 ); }
1006 1006
 		| PROTO intop error { $$=0;
1007 1007
 								yyerror("protocol expected (udp, tcp or tls)");
1008 1008
 							}
... ...
@@ -1011,7 +1017,7 @@ exp_elem:	METHOD strop STRING	{$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
1011 1011
 		| SNDPROTO intop proto	{	onsend_check("snd_proto");
1012 1012
 									$$=mk_elem($2, SNDPROTO_O, 0, NUMBER_ST,
1013 1013
 										(void*)$3 ); }
1014
-		| SNDPROTO intop attr_id {	onsend_check("snd_proto");
1014
+		| SNDPROTO intop attr_id_val {	onsend_check("snd_proto");
1015 1015
 									$$=mk_elem($2, SNDPROTO_O, 0, AVP_ST,
1016 1016
 										(void*)$3 ); }
1017 1017
 		| SNDPROTO intop error { $$=0;
... ...
@@ -1020,28 +1026,28 @@ exp_elem:	METHOD strop STRING	{$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
1020 1020
 		| SNDPROTO error { $$=0; yyerror("equal/!= operator expected"); }
1021 1021
 
1022 1022
 		| AF intop NUMBER	{ $$=mk_elem($2, AF_O, 0, NUMBER_ST,(void *) $3 ); }
1023
-		| AF intop attr_id	{ $$=mk_elem($2, AF_O, 0, AVP_ST,(void *) $3 ); }
1023
+		| AF intop attr_id_val	{ $$=mk_elem($2, AF_O, 0, AVP_ST,(void *) $3 ); }
1024 1024
 		| AF intop error { $$=0; yyerror("number expected"); }
1025 1025
 		| AF error { $$=0; yyerror("equal/!= operator expected"); }
1026 1026
 
1027 1027
 		| SNDAF intop NUMBER	{	onsend_check("snd_af");
1028 1028
 									$$=mk_elem($2, SNDAF_O, 0, NUMBER_ST,
1029 1029
 										(void *) $3 ); }
1030
-		| SNDAF intop attr_id	{	onsend_check("snd_af");
1030
+		| SNDAF intop attr_id_val	{	onsend_check("snd_af");
1031 1031
 									$$=mk_elem($2, SNDAF_O, 0, AVP_ST,
1032 1032
 										(void *) $3 ); }
1033 1033
 		| SNDAF intop error { $$=0; yyerror("number expected"); }
1034 1034
 		| SNDAF error { $$=0; yyerror("equal/!= operator expected"); }
1035 1035
 
1036 1036
 		| MSGLEN intop NUMBER	{ $$=mk_elem($2, MSGLEN_O, 0, NUMBER_ST, (void *) $3 ); }
1037
-		| MSGLEN intop attr_id	{ $$=mk_elem($2, MSGLEN_O, 0, AVP_ST, (void *) $3 ); }
1037
+		| MSGLEN intop attr_id_val	{ $$=mk_elem($2, MSGLEN_O, 0, AVP_ST, (void *) $3 ); }
1038 1038
 		| MSGLEN intop MAX_LEN	{ $$=mk_elem($2, MSGLEN_O, 0, NUMBER_ST, (void *) BUF_SIZE); }
1039 1039
 		| MSGLEN intop error { $$=0; yyerror("number expected"); }
1040 1040
 		| MSGLEN error { $$=0; yyerror("equal/!= operator expected"); }
1041 1041
 
1042 1042
 		| RETCODE intop NUMBER	{ $$=mk_elem($2, RETCODE_O, 0,
1043 1043
 												NUMBER_ST, (void *) $3 ); }
1044
-		| RETCODE intop attr_id	{ $$=mk_elem($2, RETCODE_O, 0,
1044
+		| RETCODE intop attr_id_val	{ $$=mk_elem($2, RETCODE_O, 0,
1045 1045
 												AVP_ST, (void *) $3 ); }
1046 1046
 		| RETCODE intop error { $$=0; yyerror("number expected"); }
1047 1047
 		| RETCODE error { $$=0; yyerror("equal/!= operator expected"); }
... ...
@@ -1172,16 +1178,16 @@ exp_elem:	METHOD strop STRING	{$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
1172 1172
 		| exp_stm			{ $$=mk_elem( NO_OP, ACTION_O, 0, ACTIONS_ST, $1);  }
1173 1173
 		| NUMBER		{$$=mk_elem( NO_OP, NUMBER_O, 0, NUMBER_ST, (void*)$1 ); }
1174 1174
 
1175
-		| attr_id		{$$=mk_elem( NO_OP, AVP_O, (void*)$1, 0, 0); }
1176
-		| attr_id strop STRING	{$$=mk_elem( $2, AVP_O, (void*)$1, STRING_ST, $3); }
1177
-		| attr_id strop select_id {$$=mk_elem( $2, AVP_O, (void*)$1, SELECT_ST, $3); }
1178
-		| attr_id intop NUMBER	{$$=mk_elem( $2, AVP_O, (void*)$1, NUMBER_ST, (void*)$3); }
1179
-		| attr_id binop NUMBER	{$$=mk_elem( $2, AVP_O, (void*)$1, NUMBER_ST, (void*)$3); }
1180
-                | attr_id strop attr_id {$$=mk_elem( $2, AVP_O, (void*)$1, AVP_ST, (void*)$3); }
1175
+		| attr_id_val		{$$=mk_elem( NO_OP, AVP_O, (void*)$1, 0, 0); }
1176
+		| attr_id_val strop STRING	{$$=mk_elem( $2, AVP_O, (void*)$1, STRING_ST, $3); }
1177
+		| attr_id_val strop select_id {$$=mk_elem( $2, AVP_O, (void*)$1, SELECT_ST, $3); }
1178
+		| attr_id_val intop NUMBER	{$$=mk_elem( $2, AVP_O, (void*)$1, NUMBER_ST, (void*)$3); }
1179
+		| attr_id_val binop NUMBER	{$$=mk_elem( $2, AVP_O, (void*)$1, NUMBER_ST, (void*)$3); }
1180
+                | attr_id_val strop attr_id_val {$$=mk_elem( $2, AVP_O, (void*)$1, AVP_ST, (void*)$3); }
1181 1181
 
1182 1182
                 | select_id                 { $$=mk_elem( NO_OP, SELECT_O, $1, 0, 0); }
1183 1183
 		| select_id strop STRING    { $$=mk_elem( $2, SELECT_O, $1, STRING_ST, $3); }
1184
-		| select_id strop attr_id   { $$=mk_elem( $2, SELECT_O, $1, AVP_ST, (void*)$3); }
1184
+		| select_id strop attr_id_val   { $$=mk_elem( $2, SELECT_O, $1, AVP_ST, (void*)$3); }
1185 1185
 		| select_id strop select_id { $$=mk_elem( $2, SELECT_O, $1, SELECT_ST, $3); }
1186 1186
 ;
1187 1187
 
... ...
@@ -1334,67 +1340,62 @@ select_id : SELECT_MARK { sel.n = 0; sel.f = 0; } select_params {
1334 1334
 }
1335 1335
 ;
1336 1336
 
1337
+attr_class_spec: ATTR_FROMUSER { s_attr->type |= AVP_TRACK_FROM | AVP_CLASS_USER; } 
1338
+		|ATTR_TOUSER { s_attr->type |= AVP_TRACK_TO | AVP_CLASS_USER; } 
1339
+		|ATTR_FROMDOMAIN { s_attr->type |= AVP_TRACK_FROM | AVP_CLASS_DOMAIN; } 
1340
+		|ATTR_TODOMAIN { s_attr->type |= AVP_TRACK_TO | AVP_CLASS_DOMAIN; } 
1341
+		|ATTR_GLOBAL { s_attr->type |= AVP_TRACK_ALL | AVP_CLASS_GLOBAL; } 
1337 1342
 
1338
-attr_id : ATTR_MARK ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
1339
-                         if (!s_attr) { yyerror("No memory left"); }
1340
-                         s_attr->type = AVP_NAME_STR;                   
1341
-                         s_attr->name.s.s = $2; s_attr->name.s.len = strlen($2); 
1342
-                         $$ = s_attr; 
1343
-                       }
1344
-//        | ATTR_MARK class_id DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
1345
-//                                      if (!s_attr) { yyerror("No memory left"); }
1346
-//                                      s_attr->type = AVP_NAME_STR | $2;
1347
-//                                      s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4); 
1348
-//                                      $$ = s_attr; 
1349
-//                                    }
1350
-        | ATTR_MARK ATTR_FROMUSER DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
1351
-                                       if (!s_attr) { yyerror("No memory left"); }
1352
-                                       s_attr->type = AVP_NAME_STR | AVP_TRACK_FROM | AVP_CLASS_USER;
1353
-                                       s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4);
1354
-                                       $$ = s_attr;
1355
-                                     }
1356
-        | ATTR_MARK ATTR_TOUSER DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
1357
-                                       if (!s_attr) { yyerror("No memory left"); }
1358
-                                       s_attr->type = AVP_NAME_STR | AVP_TRACK_TO | AVP_CLASS_USER;
1359
-                                       s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4);
1360
-                                       $$ = s_attr;
1361
-                                     }
1362
-        | ATTR_MARK ATTR_FROMDOMAIN DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
1363
-                                       if (!s_attr) { yyerror("No memory left"); }
1364
-                                       s_attr->type = AVP_NAME_STR | AVP_TRACK_FROM | AVP_CLASS_DOMAIN;
1365
-                                       s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4);
1366
-                                       $$ = s_attr;
1367
-                                     }
1368
-        | ATTR_MARK ATTR_TODOMAIN DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
1369
-                                       if (!s_attr) { yyerror("No memory left"); }
1370
-                                       s_attr->type = AVP_NAME_STR | AVP_TRACK_TO | AVP_CLASS_DOMAIN;
1371
-                                       s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4);
1372
-                                       $$ = s_attr;
1373
-                                     }
1374
-        | ATTR_MARK ATTR_GLOBAL DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
1375
-                                       if (!s_attr) { yyerror("No memory left"); }
1376
-                                       s_attr->type = AVP_NAME_STR | AVP_CLASS_GLOBAL;
1377
-                                       s_attr->name.s.s = $4; s_attr->name.s.len = strlen($4);
1378
-                                       $$ = s_attr;
1379
-                                     }
1380
-//        | ATTR_MARK ATTR_TO class_id DOT ID { s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
1381
-//                                              if (!s_attr) { yyerror("No memory left"); }
1382
-//                                              s_attr->type = AVP_NAME_STR | AVP_TRACK_TO | $3;
1383
-//                                              s_attr->name.s.s = $5; s_attr->name.s.len = strlen($5);
1384
-//                                             $$ = s_attr;
1385
-//                                            }
1343
+attr_name_spec : ID { s_attr->type |= AVP_NAME_STR; s_attr->name.s.s = $1; s_attr->name.s.len = strlen ($1); }
1344
+;
1345
+	       
1346
+attr_spec : attr_name_spec |
1347
+	    attr_class_spec DOT attr_name_spec
1348
+;
1349
+
1350
+attr_mark : ATTR_MARK 
1351
+	{	s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
1352
+                if (!s_attr) { yyerror("No memory left"); }
1353
+                s_attr->type = 0;  
1354
+	}
1355
+;
1356
+
1357
+attr_id : attr_mark attr_spec { $$ = s_attr; }	  
1358
+;
1359
+
1360
+attr_id_num_idx : attr_mark attr_spec LBRACK NUMBER RBRACK
1361
+	       	{	s_attr->type|= (AVP_NAME_STR | ($4<0?AVP_INDEX_BACKWARD:AVP_INDEX_FORWARD)); 
1362
+			s_attr->index = ($4<0?-$4:$4);
1363
+	       		$$ = s_attr; 
1364
+	       	}	  
1365
+;
1366
+
1367
+attr_id_no_idx : attr_mark attr_spec LBRACK RBRACK
1368
+	       	{	s_attr->type|= AVP_INDEX_ALL; 
1369
+	       		$$ = s_attr;
1370
+		}	  
1371
+;
1372
+
1373
+attr_id_ass : attr_id | attr_id_no_idx
1374
+;
1375
+
1376
+attr_id_val : attr_id | attr_id_num_idx
1377
+;
1378
+
1379
+attr_id_any : attr_id | attr_id_no_idx | attr_id_num_idx
1386 1380
 ;
1387 1381
 
1388
-assign_op : ADDEQ { $$ = ADD_T; }
1389
-          | EQUAL { $$ = ASSIGN_T; }
1382
+//assign_op : ADDEQ { $$ = ADD_T; }
1383
+//          | EQUAL { $$ = ASSIGN_T; }
1384
+assign_op : EQUAL { $$ = ASSIGN_T; }
1390 1385
 ;
1391 1386
 
1392
-assign_action:   attr_id assign_op STRING  { $$=mk_action($2, AVP_ST, STRING_ST, $1, $3); }
1393
-               | attr_id assign_op NUMBER  { $$=mk_action($2, AVP_ST, NUMBER_ST, $1, (void*)$3); }
1394
-               | attr_id assign_op fcmd    { $$=mk_action($2, AVP_ST, ACTION_ST, $1, $3); }
1395
-               | attr_id assign_op attr_id { $$=mk_action($2, AVP_ST, AVP_ST, $1, $3); }
1396
-               | attr_id assign_op select_id { $$=mk_action($2, AVP_ST, SELECT_ST, (void*)$1, (void*)$3); }
1397
-               | attr_id assign_op LPAREN exp RPAREN { $$ = mk_action($2, AVP_ST, EXPR_ST, $1, $4); }
1387
+assign_action:   attr_id_ass assign_op STRING  { $$=mk_action($2, AVP_ST, STRING_ST, $1, $3); }
1388
+               | attr_id_ass assign_op NUMBER  { $$=mk_action($2, AVP_ST, NUMBER_ST, $1, (void*)$3); }
1389
+               | attr_id_ass assign_op fcmd    { $$=mk_action($2, AVP_ST, ACTION_ST, $1, $3); }
1390
+               | attr_id_ass assign_op attr_id_any { $$=mk_action($2, AVP_ST, AVP_ST, $1, $3); }
1391
+               | attr_id_ass assign_op select_id { $$=mk_action($2, AVP_ST, SELECT_ST, (void*)$1, (void*)$3); }
1392
+               | attr_id_ass assign_op LPAREN exp RPAREN { $$ = mk_action($2, AVP_ST, EXPR_ST, $1, $4); }
1398 1393
 ;
1399 1394
 
1400 1395
 cmd:		FORWARD LPAREN host RPAREN	{ $$=mk_action(	FORWARD_T,
... ...
@@ -198,6 +198,7 @@ int parse_tw_append( modparam_t type, void* val)
198 198
 	char bar;
199 199
 	str foo;
200 200
 	int n;
201
+	int index;
201 202
 	
202 203
 	if (val==0 || ((char*)val)[0]==0)
203 204
 		return 0;
... ...
@@ -314,7 +315,7 @@ int parse_tw_append( modparam_t type, void* val)
314 314
 		/* process and optimize the element name */
315 315
 		if (ha->type==ELEM_IS_AVP) {
316 316
 			/* element is AVP */
317
-			if ( parse_avp_spec( &foo, &n, &avp_name)!=0 ) {
317
+			if ( parse_avp_spec( &foo, &n, &avp_name, &index)!=0 ) {
318 318
 				LOG(L_ERR,"ERROR:tm:parse_tw_append: bad alias spec "
319 319
 					"<%.*s>\n",foo.len, foo.s);
320 320
 				goto error;
... ...
@@ -67,9 +67,11 @@
67 67
 static int     fr_timer_avp_type = 0;
68 68
 static int_str fr_timer_avp = {0};
69 69
 static str     fr_timer_str;
70
+static int     fr_timer_index = 0;
70 71
 static int     fr_inv_timer_avp_type = 0;
71 72
 static int_str fr_inv_timer_avp = {0};
72 73
 static str     fr_inv_timer_str;
74
+static int     fr_inv_timer_index = 0;
73 75
 
74 76
 
75 77
 /* ----------------------------------------------------- */
... ...
@@ -298,7 +300,7 @@ int init_avp_params(char *fr_timer_param, char *fr_inv_timer_param)
298 298
 		fr_timer_str.s = fr_timer_param;
299 299
 		fr_timer_str.len = strlen(fr_timer_str.s);
300 300
 		if (parse_avp_spec( &fr_timer_str, &fr_timer_avp_type,
301
-		&fr_timer_avp)<0) {
301
+		&fr_timer_avp, &fr_timer_index)<0) {
302 302
 			LOG(L_CRIT,"ERROR:tm:init_avp_params: invalid fr_timer "
303 303
 				"AVP specs \"%s\"\n", fr_timer_param);
304 304
 			return -1;
... ...
@@ -309,7 +311,7 @@ int init_avp_params(char *fr_timer_param, char *fr_inv_timer_param)
309 309
 		fr_inv_timer_str.s = fr_inv_timer_param;
310 310
 		fr_inv_timer_str.len = strlen(fr_inv_timer_str.s);
311 311
 		if (parse_avp_spec( &fr_inv_timer_str, &fr_inv_timer_avp_type, 
312
-		&fr_inv_timer_avp)<0) {
312
+		&fr_inv_timer_avp, &fr_inv_timer_index)<0) {
313 313
 			LOG(L_CRIT,"ERROR:tm:init_avp_params: invalid fr_inv_timer "
314 314
 				"AVP specs \"%s\"\n", fr_inv_timer_param);
315 315
 			return -1;
... ...
@@ -367,7 +367,7 @@ inline static int comp_num(int op, long left, int rtype, union exp_op* r)
367 367
 	long right;
368 368
 	
369 369
 	if (rtype == AVP_ST) {
370
-		avp = search_first_avp(r->attr->type, r->attr->name, &val, 0);
370
+		avp = search_avp_by_index(r->attr->type, r->attr->name, &val, r->attr->index);
371 371
 		if (avp && !(avp->flags & AVP_VAL_STR)) right = val.n;
372 372
 		else return 0; /* Always fail */
373 373
 	} else if (rtype == NUMBER_ST) {
... ...
@@ -406,7 +406,7 @@ inline static int comp_str(int op, str* left, int rtype, union exp_op* r, struct
406 406
 	right=0; /* warning fix */
407 407
 	
408 408
 	if (rtype == AVP_ST) {
409
-		avp = search_first_avp(r->attr->type, r->attr->name, &val, 0);
409
+		avp = search_avp_by_index(r->attr->type, r->attr->name, &val, r->attr->index);
410 410
 		if (avp && (avp->flags & AVP_VAL_STR)) right = &val.s;
411 411
 		else return 0;
412 412
 	} else if (rtype == SELECT_ST) {
... ...
@@ -531,7 +531,7 @@ inline static int comp_avp(int op, avp_spec_t* spec, int rtype, union exp_op* r,
531 531
 	avp_t* avp;
532 532
 	int_str val;
533 533
 
534
-	avp = search_first_avp(spec->type, spec->name, &val, 0);
534
+	avp = search_avp_by_index(spec->type, spec->name, &val, spec->index);
535 535
 	if (!avp) return 0;
536 536
 
537 537
 	switch(op) {
... ...
@@ -30,6 +30,7 @@
30 30
  *  2004-10-09  interface more flexible - more function available (bogdan)
31 31
  *  2004-11-07  AVP string values are kept 0 terminated (bogdan)
32 32
  *  2004-11-14  global aliases support added
33
+ *  2005-01-05  parse avp name according new syntax
33 34
  */
34 35
 
35 36
 
... ...
@@ -131,7 +132,7 @@ inline static unsigned short compute_ID( str *name )
131 131
 }
132 132
 
133 133
 
134
-int add_avp_list(avp_list_t* list, unsigned short flags, int_str name, int_str val)
134
+avp_t *create_avp (unsigned short flags, int_str name, int_str val)
135 135
 {
136 136
 	avp_t *avp;
137 137
 	str *s;
... ...
@@ -139,13 +140,11 @@ int add_avp_list(avp_list_t* list, unsigned short flags, int_str name, int_str v
139 139
 	struct str_str_data *ssd;
140 140
 	int len;
141 141
 
142
-	assert(list != 0);
143
-
144 142
 	if (name.s.s == 0 && name.s.len == 0) {
145 143
 		LOG(L_ERR,"ERROR:avp:add_avp: 0 ID or NULL NAME AVP!");
146 144
 		goto error;
147 145
 	}
148
-
146
+	
149 147
 	/* compute the required mem size */
150 148
 	len = sizeof(struct usr_avp);
151 149
 	if (flags&AVP_NAME_STR) {
... ...
@@ -168,14 +167,12 @@ int add_avp_list(avp_list_t* list, unsigned short flags, int_str name, int_str v
168 168
 	avp = (struct usr_avp*)shm_malloc( len );
169 169
 	if (avp==0) {
170 170
 		LOG(L_ERR,"ERROR:avp:add_avp: no more shm mem\n");
171
-		goto error;
171
+		return 0;
172 172
 	}
173 173
 
174 174
 	avp->flags = flags;
175 175
 	avp->id = (flags&AVP_NAME_STR)? compute_ID(&name.s) : name.n ;
176
-
177
-	avp->next = *list;
178
-	*list = avp;
176
+	avp->next = NULL;
179 177
 
180 178
 	switch ( flags&(AVP_NAME_STR|AVP_VAL_STR) )
181 179
 	{
... ...
@@ -213,9 +210,23 @@ int add_avp_list(avp_list_t* list, unsigned short flags, int_str name, int_str v
213 213
 			ssd->val.s[ssd->val.len] = 0;
214 214
 			break;
215 215
 	}
216
-
217
-	return 0;
216
+	return avp;
218 217
 error:
218
+	return 0;
219
+}
220
+
221
+int add_avp_list(avp_list_t* list, unsigned short flags, int_str name, int_str val)
222
+{
223
+	avp_t *avp;
224
+
225
+	assert(list != 0);
226
+
227
+	if ((avp = create_avp(flags, name, val))) {
228
+		avp->next = *list;
229
+		*list = avp;
230
+		return 0;
231
+	}
232
+	
219 233
 	return -1;
220 234
 }
221 235
 
... ...
@@ -242,6 +253,28 @@ int add_avp(unsigned short flags, int_str name, int_str val)
242 242
 	return add_avp_list(list, flags & (~(AVP_CLASS_ALL) | avp_class), name, val);
243 243
 }
244 244
 
245
+int add_avp_before(avp_t *avp, unsigned short flags, int_str name, int_str val)
246
+{
247
+	avp_t *new_avp;
248
+	
249
+	if (!avp) {
250
+		return add_avp(flags, name, val);
251
+	}
252
+
253
+	if ((flags & AVP_CLASS_ALL) == 0) flags |= (avp->flags & AVP_CLASS_ALL);
254
+	if ((flags & AVP_TRACK_ALL) == 0) flags |= (avp->flags & AVP_TRACK_ALL);
255
+	
256
+	if ((avp->flags & (AVP_CLASS_ALL|AVP_TRACK_ALL)) != (flags & (AVP_CLASS_ALL|AVP_TRACK_ALL))) {
257
+		ERR("add_avp_before:Source and target AVPs have different CLASS/TRACK\n");
258
+		return -1;
259
+	}
260
+	if ((new_avp=create_avp(flags, name, val))) {
261
+		new_avp->next=avp->next;
262
+		avp->next=new_avp;
263
+		return 0;
264
+	}
265
+	return -1;
266
+}
245 267
 
246 268
 /* get value functions */
247 269
 inline str* get_avp_name(avp_t *avp)
... ...
@@ -358,6 +391,13 @@ avp_t *search_first_avp(unsigned short flags, int_str name, int_str *val, struct
358 358
 		LOG(L_ERR,"ERROR:avp:search_first_avp: 0 ID or NULL NAME AVP!");
359 359
 		return 0;
360 360
 	}
361
+	
362
+	switch (flags & AVP_INDEX_ALL) {
363
+		case AVP_INDEX_BACKWARD:
364
+		case AVP_INDEX_FORWARD:
365
+			WARN("AVP specified with index, but not used for search\n");
366
+			break;
367
+	}
361 368
 
362 369
 	if (!s) s = &st;
363 370
 
... ...
@@ -366,6 +406,17 @@ avp_t *search_first_avp(unsigned short flags, int_str name, int_str *val, struct
366 366
 		      * all of them by default
367 367
 		      */
368 368
 		flags |= AVP_CLASS_ALL;
369
+		
370
+		if ((flags & AVP_TRACK_ALL) == 0) {
371
+		    /* The caller did not specify even the track to search in, so try
372
+		     * track_from first, and if not found try track_to
373
+		     */
374
+		     	ret = search_first_avp(flags | AVP_TRACK_FROM, name, val, s);
375
+		     	if (ret) {
376
+		     		return ret;
377
+		     	}
378
+		     	flags |= AVP_TRACK_TO;
379
+		}
369 380
 	}
370 381
 
371 382
 	list = select_list(flags);
... ...
@@ -399,6 +450,13 @@ avp_t *search_next_avp(struct search_state* s, int_str *val )
399 399
 		return 0;
400 400
 	}
401 401
 
402
+	switch (s->flags & AVP_INDEX_ALL) {
403
+		case AVP_INDEX_BACKWARD:
404
+		case AVP_INDEX_FORWARD:
405
+			WARN("AVP specified with index, but not used for search\n");
406
+			break;
407
+	}
408
+
402 409
 	while(1) {
403 410
 		for( ; s->avp; s->avp = s->avp->next) {
404 411
 			if (s->flags & AVP_NAME_RE) {
... ...
@@ -431,6 +489,54 @@ avp_t *search_next_avp(struct search_state* s, int_str *val )
431 431
 	return 0;
432 432
 }
433 433
 
434
+int search_reverse( avp_t *cur, struct search_state* st,
435
+                     unsigned short index, avp_list_t *ret)
436
+{
437
+	unsigned short lvl;
438
+	
439
+	if (!cur)
440
+		return 0;
441
+	lvl = search_reverse(search_next_avp(st, NULL), st, index, ret)+1;
442
+	if (index==lvl)
443
+		*ret=cur;
444
+	return lvl;
445
+}
446
+                            
447
+avp_t *search_avp_by_index( unsigned short flags, int_str name,
448
+                            int_str *val, unsigned short index) 	
449
+{
450
+	avp_t *ret, *cur;
451
+	struct search_state st;
452
+	
453
+	if (flags & AVP_NAME_RE) {
454
+		BUG("search_by_index not supported for AVP_NAME_RE\n");
455
+		return 0;
456
+	}
457
+	switch (flags & AVP_INDEX_ALL) {
458
+		case 0:
459
+			ret = search_first_avp(flags, name, val, &st);
460
+			if (!ret || search_next_avp(&st, NULL))
461
+				return 0;
462
+			else
463
+				return ret;
464
+		case AVP_INDEX_ALL:
465
+			BUG("search_by_index not supported for anonymous index []\n");
466
+			return 0;
467
+		case AVP_INDEX_FORWARD:
468
+			ret = NULL;
469
+			cur = search_first_avp(flags & ~AVP_INDEX_ALL, name, NULL, &st);
470
+			search_reverse(cur, &st, index, &ret);
471
+			if (ret && val)
472
+				get_avp_val(ret, val);
473
+			return ret;
474
+		case AVP_INDEX_BACKWARD:
475
+			ret = search_first_avp(flags & ~AVP_INDEX_ALL, name, val, &st);
476
+			for (index--; (ret && index); ret=search_next_avp(&st, val), index--);
477
+			return ret;
478
+	}
479
+		
480
+	return 0;
481
+}                            
434 482
 
435 483
 /* FIXME */
436 484
 /********* free functions ********/
... ...
@@ -647,16 +753,28 @@ int lookup_avp_galias(str *alias, int *type, int_str *avp_name)
647 647
 
648 648
 
649 649
 /* parsing functions */
650
+#define ERR_IF_CONTAINS(name,chr) \
651
+	if (memchr(name->s,chr,name->len)) { \
652
+		ERR("Unexpected control character '%c' in AVP name\n", chr); \
653
+		goto error; \
654
+	}
650 655
 
651
-int parse_avp_name( str *name, int *type, int_str *avp_name)
656
+int parse_avp_name( str *name, int *type, int_str *avp_name, int *index)
652 657
 {
653 658
 	unsigned int id;
654 659
 	char c;
660
+	char *p;
661
+	str s;
655 662
 
656
-	if (name==0 || name->s==0 || name->len==0)
663
+	if (name==0 || name->s==0 || name->len==0) {
664
+		ERR("NULL name or name->s or name->len\n");
657 665
 		goto error;
666
+	}
658 667
 
659
-	if (name->len>=2 && name->s[1]==':') {
668
+	if (index) *index = 0;
669
+	ERR("Parsing '%.*s'\n", name->len, name->s);
670
+	if (name->len>=2 && name->s[1]==':') { // old fashion i: or s:
671
+		WARN("i: and s: avp name syntax is deprecated!\n");
660 672
 		c = name->s[0];
661 673
 		name->s += 2;
662 674
 		name->len -= 2;
... ...
@@ -670,17 +788,108 @@ int parse_avp_name( str *name, int *type, int_str *avp_name)
670 670
 			case 'i': case 'I':
671 671
 				*type = 0;
672 672
 				if (str2int( name, &id)!=0) {
673
-					LOG(L_ERR, "ERROR:parse_avp_name: invalid ID "
673
+					ERR("invalid ID "
674 674
 						"<%.*s> - not a number\n", name->len, name->s);
675 675
 					goto error;
676 676
 				}
677 677
 				avp_name->n = (int)id;
678 678
 				break;
679 679
 			default:
680
-				LOG(L_ERR, "ERROR:parse_avp_name: unsupported type "
680
+				ERR("unsupported type "
681 681
 					"[%c]\n", c);
682 682
 				goto error;
683 683
 		}
684
+	} else if ((p=memchr(name->s, '.', name->len))) {
685
+		if (p-name->s==1) {
686
+			id=name->s[0];
687
+			name->s +=2;
688
+			name->len -=2;
689
+		} else if (p-name->s==2) {
690
+			id=name->s[0]<<8 | name->s[1];
691
+			name->s +=3;
692
+			name->len -=3;
693
+		} else {
694
+			ERR("AVP unknown class prefix '%.*s'\n", p-name->s,name->s);
695
+			goto error;
696
+		}
697
+		if (name->len==0) {
698
+			ERR("AVP name not specified after the prefix separator\n");
699
+			goto error;
700
+		}
701
+		switch (id) {
702
+			case 'f':
703
+				*type = AVP_TRACK_FROM | AVP_CLASS_USER;
704
+				break;
705
+			case 't':
706
+				*type = AVP_TRACK_TO | AVP_CLASS_USER;
707
+				break;
708
+			case 0x6664: //'fd'
709
+				*type = AVP_TRACK_FROM | AVP_CLASS_DOMAIN;
710
+				break;
711
+			case 0x7464: // 'td'
712
+				*type = AVP_TRACK_TO | AVP_CLASS_DOMAIN;
713
+				break;
714
+			case 'g':
715
+				*type = AVP_TRACK_ALL | AVP_CLASS_GLOBAL;
716
+				break;
717
+			default:
718
+				if (id < 1<<8)
719
+					ERR("AVP unknown class prefix '%c'\n", id);
720
+				else
721
+					ERR("AVP unknown class prefix '%c%c'\n", id>>8,id);
722
+				goto error;
723
+		}
724
+		if (name->s[name->len-1]==']') {
725
+			p=memchr(name->s, '[', name->len);
726
+			if (!p) {
727
+				ERR("missing '[' for AVP index\n");
728
+				goto error; 
729
+			}
730
+			s.s=p+1;
731
+			s.len=name->len-(p-name->s)-2; // [ and ]
732
+			if (s.len == 0) {
733
+				*type |= AVP_INDEX_ALL;
734
+			} else {
735
+				if (s.s[0]=='-') {
736
+					*type |= AVP_INDEX_BACKWARD;
737
+					s.s++;s.len--;
738
+				} else {
739
+					*type |= AVP_INDEX_FORWARD;
740
+				}	
741
+				if ((str2int(&s, &id) != 0)||(id==0)) {
742
+					ERR("Invalid AVP index '%.*s'\n", s.len, s.s);
743
+					goto error;
744
+				}
745
+				if (index){
746
+					*index = id;
747
+				} else {
748
+					WARN("AVP index correcly specified, but called without placeholed\n");
749
+				}
750
+			}
751
+			name->len=p-name->s;
752
+		}
753
+		ERR_IF_CONTAINS(name,'.');
754
+		ERR_IF_CONTAINS(name,'[');
755
+		ERR_IF_CONTAINS(name,']');
756
+		if ((name->len > 2) && (name->s[0]=='/') && (name->s[name->len-1]=='/')) {
757
+			avp_name->re=pkg_malloc(sizeof(regex_t));
758
+			if (!avp_name->re) {
759
+				BUG("No free memory to allocate AVP_NAME_RE regex\n");
760
+				goto error;
761
+			}
762
+			c=name->s[name->len];
763
+			name->s[name->len]=0;
764
+			if (regcomp(avp_name->re, name->s, REG_EXTENDED|REG_NOSUB|REG_ICASE)) {
765
+				pkg_free(avp_name->re);
766
+				name->s[name->len] = c;
767
+				goto error;
768
+			}
769
+			*type |= AVP_NAME_RE;
770
+		} else {
771
+			ERR_IF_CONTAINS(name,'/');
772
+			*type |= AVP_NAME_STR;
773
+		}
774
+		avp_name->s = *name;
684 775
 	} else {
685 776
 		/*default is string name*/
686 777
 		*type = AVP_NAME_STR;
... ...
@@ -693,7 +902,7 @@ error:
693 693
 }
694 694
 
695 695
 
696
-int parse_avp_spec( str *name, int *type, int_str *avp_name)
696
+int parse_avp_spec( str *name, int *type, int_str *avp_name, int *index)
697 697
 {
698 698
 	str alias;
699 699
 
... ...
@@ -710,10 +919,15 @@ int parse_avp_spec( str *name, int *type, int_str *avp_name)
710 710
 		alias.len = name->len-1;
711 711
 		return lookup_avp_galias( &alias, type, avp_name);
712 712
 	} else {
713
-		return parse_avp_name( name, type, avp_name);
713
+		return parse_avp_name( name, type, avp_name, index);
714 714
 	}
715 715
 }
716 716
 
717
+void free_avp_name( int *type, int_str *avp_name)
718
+{
719
+	if ((*type & AVP_NAME_RE) && (avp_name->re))
720
+		pkg_free(avp_name->re);
721
+}
717 722
 
718 723
 int add_avp_galias_str(char *alias_definition)
719 724
 {
... ...
@@ -722,7 +936,8 @@ int add_avp_galias_str(char *alias_definition)
722 722
 	str  name;
723 723
 	str  alias;
724 724
 	int  type;
725
-
725
+	int  index;
726
+	
726 727
 	s = alias_definition;
727 728
 	while(*s && isspace((int)*s))
728 729
 		s++;
... ...
@@ -761,7 +976,7 @@ int add_avp_galias_str(char *alias_definition)
761 761
 				goto parse_error;
762 762
 		}
763 763
 
764
-		if (parse_avp_name( &name, &type, &avp_name)!=0) {
764
+		if (parse_avp_name( &name, &type, &avp_name, &index)!=0) {
765 765
 			LOG(L_ERR, "ERROR:add_avp_galias_str: <%.*s> not a valid AVP "
766 766
 				"name\n", name.len, name.s);
767 767
 			goto error;
... ...
@@ -52,7 +52,8 @@
52 52
  *     7        core              avp is in global list
53 53
  *     8        core              avp is in the from avp list
54 54
  *     9        core              avp is in the to avp list
55
- *
55
+ *    10	core		  avp name with positive index
56
+ *    11	core		  avp name with negative index
56 57
  */
57 58
 
58 59
 #include "str.h"
... ...
@@ -65,6 +66,7 @@
65 65
 #define AVP_FR_INV_TIMER "fr_inv_timer"  /* Value of final response invite timer */
66 66
 #define AVP_RPID         "rpid"          /* Remote-Party-ID */
67 67
 #define AVP_GFLAGS       "gflags"        /* global flags */
68
+#define AVP_FLAGS	 "flags"	 /* message flags */
68 69
 
69 70
 struct str_int_data {
70 71
 	str name;
... ...
@@ -109,6 +111,7 @@ struct search_state {
109 109
 typedef struct avp_spec {
110 110
 	int type;
111 111
 	int_str name;
112
+	int index;
112 113
 } avp_spec_t;
113 114
 
114 115
 /* AVP types */
... ...
@@ -128,6 +131,11 @@ typedef struct avp_spec {
128 128
 
129 129
 #define AVP_CLASS_ALL (AVP_CLASS_USER|AVP_CLASS_DOMAIN|AVP_CLASS_GLOBAL)
130 130
 
131
+/* AVP name index */
132
+#define AVP_INDEX_FORWARD	(1<<10)
133
+#define AVP_INDEX_BACKWARD	(1<<11)
134
+#define AVP_INDEX_ALL		(AVP_INDEX_FORWARD | AVP_INDEX_BACKWARD)
135
+
131 136
 #define GALIAS_CHAR_MARKER  '$'
132 137
 
133 138
 /* Initialize memory structures */
... ...
@@ -135,6 +143,7 @@ int init_avps(void);
135 135
 
136 136
 /* add avp to the list of avps */
137 137
 int add_avp(unsigned short flags, int_str name, int_str val);
138
+int add_avp_before(avp_t *avp, unsigned short flags, int_str name, int_str val);
138 139
 int add_avp_list(avp_list_t* list, unsigned short flags, int_str name, int_str val);
139 140
 
140 141
 /* Delete avps with given type and name */
... ...
@@ -145,6 +154,8 @@ avp_t *search_first_avp( unsigned short flags, int_str name,
145 145
 			 int_str *val, struct search_state* state);
146 146
 avp_t *search_next_avp(struct search_state* state, int_str *val);
147 147
 
148
+avp_t *search_avp_by_index( unsigned short flags, int_str name,
149
+                            int_str *val, unsigned short index);
148 150
 /* free functions */
149 151
 void reset_avps(void);
150 152
 
... ...
@@ -164,7 +175,8 @@ avp_list_t* set_avp_list(unsigned short flags, avp_list_t* list);
164 164
 int add_avp_galias_str(char *alias_definition);
165 165
 int lookup_avp_galias(str *alias, int *type, int_str *avp_name);
166 166
 int add_avp_galias(str *alias, int type, int_str avp_name);
167
-int parse_avp_name( str *name, int *type, int_str *avp_name);
168
-int parse_avp_spec( str *name, int *type, int_str *avp_name);
167
+int parse_avp_name( str *name, int *type, int_str *avp_name, int *index);
168
+int parse_avp_spec( str *name, int *type, int_str *avp_name, int *index);
169
+void free_avp_name( int *type, int_str *avp_name);
169 170
 
170 171
 #endif
... ...
@@ -178,27 +178,53 @@ static inline int btostr( char *p,  unsigned char val)
178 178
 
179 179
 #define INT2STR_MAX_LEN  (19+1+1) /* 2^64~= 16*10^18 => 19+1 digits + \0 */
180 180
 
181
-/* returns a pointer to a static buffer containing l in asciiz & sets len */
182
-static inline char* int2str(unsigned long l, int* len)
181
+/* 
182
+ * returns a pointer to a static buffer containing l in asciiz (with base "base") & sets len 
183
+ * left padded with 0 to "size"
184
+ */
185
+static inline char* int2str_base_0pad(unsigned int l, int* len, int base, int size)
183 186
 {
184
-	static char r[INT2STR_MAX_LEN];
185
-	int i;
186
-	
187
-	i=INT2STR_MAX_LEN-2;
188
-	r[INT2STR_MAX_LEN-1]=0; /* null terminate */
189
-	do{
190
-		r[i]=l%10+'0';
191
-		i--;
192
-		l/=10;
193
-	}while(l && (i>=0));
194
-	if (l && (i<0)){
195
-		LOG(L_CRIT, "BUG: int2str: overflow\n");
196
-	}
197
-	if (len) *len=(INT2STR_MAX_LEN-2)-i;
198
-	return &r[i+1];
187
+        static char r[INT2STR_MAX_LEN];
188
+        int i, j;
189
+
190
+        if (base < 2) {
191
+                BUG("base underflow\n");
192
+		return NULL;
193
+        }
194
+        if (base > 36) {
195
+                BUG("base overflow\n");
196
+		return NULL;
197
+        }
198
+        i=INT2STR_MAX_LEN-2;
199
+        j=i-size;
200
+        r[INT2STR_MAX_LEN-1]=0; /* null terminate */
201
+        do{
202
+                r[i]=l%base;
203
+                if (r[i]<10)
204
+                        r[i]+='0';
205
+                else
206
+                        r[i]+='a'-10;
207
+                i--;
208
+                l/=base;
209
+        }while((l || i>j) && (i>=0));
210
+        if (l && (i<0)){
211
+                BUG("result buffer overflow\n");
212
+        }
213
+        if (len) *len=(INT2STR_MAX_LEN-2)-i;
214
+        return &r[i+1];
199 215
 }
200 216
 
217
+/* returns a pointer to a static buffer containing l in asciiz (with base "base") & sets len */
218
+static inline char* int2str_base(unsigned int l, int* len, int base)
219
+{
220
+        return int2str_base_0pad(l, len, base, 0);
221
+}
201 222
 
223
+/* returns a pointer to a static buffer containing l in asciiz & sets len */
224
+static inline char* int2str(unsigned int l, int* len)
225
+{
226
+     return int2str_base(l, len, 10);
227
+}
202 228
 
203 229
 /* faster memchr version */
204 230
 static inline char* q_memchr(char* p, int c, unsigned int size)