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 715
 
715 716
 	        case ADD_T:
716 717
 	        case ASSIGN_T:
718
+		
719
+			/* If the left attr was specified withou indexing brackets delete
720
+			 * existing AVPs before adding new ones
721
+			 */
722
+			if ((a->p1.attr->type & AVP_INDEX_ALL) != AVP_INDEX_ALL) delete_avp(a->p1.attr->type, a->p1.attr->name);
723
+			
717 724
 			if (a->p2_type == STRING_ST) {
718 725
 				value.s = a->p2.str;
719 726
 				flags = a->p1.attr->type | AVP_VAL_STR;
... ...
@@ -750,27 +757,45 @@ int do_action(struct action* a, struct sip_msg* msg)
750 757
 			} else if (a->p2_type == AVP_ST) {
751 758
 				struct search_state st;
752 759
 				avp_t* avp; 
760
+				avp_t* avp_mark;
753 761
 				
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;
762
+				avp_mark = NULL;
763
+				if ((a->p2.attr->type & AVP_INDEX_ALL) == AVP_INDEX_ALL) {
764
+					avp = search_first_avp(a->p2.attr->type, a->p2.attr->name, &value, &st);
765
+					while(avp) {
766
+						     /* We take only the type of value and name from the source avp
767
+						      * and reset class and track flags
768
+						      */
769
+						flags = (a->p1.attr->type & ~AVP_INDEX_ALL) | (avp->flags & ~(AVP_CLASS_ALL|AVP_TRACK_ALL));
770
+						
771
+						if (add_avp_before(avp_mark, flags, a->p1.attr->name, value) < 0) {
772
+							LOG(L_CRIT, "ERROR: Failed to assign value to attribute\n");
773
+							ret=E_UNSPEC;
774
+							break;
775
+						}
776
+						
777
+						/* move the mark, so the next found AVP will come before the one currently added
778
+						 * so they will have the same order as in the source list
779
+						 */
780
+						if (avp_mark) {
781
+							avp_mark=avp_mark->next;
782
+						} else {
783
+							avp_mark=search_first_avp(flags, a->p1.attr->name, NULL, NULL);
784
+						}
785
+							
786
+						avp = search_next_avp(&st, &value);
787
+					}
788
+					ret = 1;
789
+					break;
790
+				} else {
791
+					avp = search_avp_by_index(a->p2.attr->type, a->p2.attr->name, &value, a->p2.attr->index);
792
+					if (avp) {
793
+						flags = a->p1.attr->type | (avp->flags & ~(AVP_CLASS_ALL|AVP_TRACK_ALL));
794
+					} else {
795
+						ret = E_UNSPEC;
768 796
 						break;
769 797
 					}
770
-					avp = search_next_avp(&st, &value);
771 798
 				}
772
-				ret = 1;
773
-				break;
774 799
 			} else if (a->p2_type == SELECT_ST) {
775 800
 				int r;
776 801
 				r = run_select(&value.s, a->p2.select, msg);
... ...
@@ -793,8 +818,8 @@ int do_action(struct action* a, struct sip_msg* msg)
793 818
 
794 819
 			/* If the action is assign then remove the old avp value
795 820
 			 * before adding new ones */
796
-			if ((unsigned char)a->type == ASSIGN_T) delete_avp(flags, name);
797
-			if (add_avp(flags, name, value) < 0) {
821
+//			if ((unsigned char)a->type == ASSIGN_T) delete_avp(flags, name);
822
+			if (add_avp(flags & ~AVP_INDEX_ALL, name, value) < 0) {
798 823
 				LOG(L_CRIT, "ERROR: Failed to assign value to attribute\n");
799 824
 				ret=E_UNSPEC;
800 825
 				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 337
 %type <strval> host_sep
337 338
 %type <intval> uri_type
338 339
 %type <attr> attr_id
340
+%type <attr> attr_id_num_idx
341
+%type <attr> attr_id_no_idx
342
+%type <attr> attr_id_ass
343
+%type <attr> attr_id_val
344
+%type <attr> attr_id_any
339 345
 //%type <intval> class_id
340 346
 %type <intval> assign_op
341 347
 %type <select> select_id
... ...
@@ -957,7 +963,7 @@ uri_type:	URI			{$$=URI_O;}
957 963
 		;
958 964
 
959 965
 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); }
966
+                | METHOD strop attr_id_val  {$$ = mk_elem($2, METHOD_O, 0, AVP_ST, $3); }
961 967
                 | METHOD strop select_id {$$ = mk_elem($2, METHOD_O, 0, SELECT_ST, $3); }
962 968
 		| METHOD strop  ID	{$$ = mk_elem($2, METHOD_O, 0, STRING_ST,$3); }
963 969
 		| 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 972
 						}
967 973
 		| uri_type strop STRING	{$$ = mk_elem($2, $1, 0, STRING_ST, $3); }
968 974
                 | 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); }
975
+                | uri_type strop attr_id_val {$$ = mk_elem($2, $1, 0, AVP_ST, $3); }
970 976
                 | uri_type strop select_id {$$ = mk_elem($2, $1, 0, SELECT_ST, $3); }
971 977
                 | uri_type equalop MYSELF {$$=mk_elem($2, $1, 0, MYSELF_ST, 0); }
972 978
 		| 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 980
 									" == , != or =~ expected");
975 981
 					}
976 982
 		| 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 ); }
983
+		| SRCPORT intop attr_id_val { $$=mk_elem($2, SRCPORT_O, 0, AVP_ST, (void*)$3 ); }
978 984
 		| SRCPORT intop error { $$=0; yyerror("number expected"); }
979 985
 		| SRCPORT error { $$=0; yyerror("==, !=, <,>, >= or <=  expected"); }
980 986
 
981 987
 		| 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 ); }
988
+		| DSTPORT intop attr_id_val	{ $$=mk_elem($2, DSTPORT_O, 0, AVP_ST, (void*)$3 ); }
983 989
 		| DSTPORT intop error { $$=0; yyerror("number expected"); }
984 990
 		| DSTPORT error { $$=0; yyerror("==, !=, <,>, >= or <=  expected"); }
985 991
 
986 992
 		| SNDPORT intop NUMBER	{	onsend_check("snd_port");
987 993
 									$$=mk_elem($2, SNDPORT_O, 0, NUMBER_ST,
988 994
 												(void*)$3 ); }
989
-		| SNDPORT intop attr_id {	onsend_check("snd_port");
995
+		| SNDPORT intop attr_id_val {	onsend_check("snd_port");
990 996
 									$$=mk_elem($2, SNDPORT_O, 0, AVP_ST,
991 997
 												(void*)$3 ); }
992 998
 		| 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 1001
 		| TOPORT intop NUMBER	{	onsend_check("to_port");
996 1002
 									$$=mk_elem($2, TOPORT_O, 0, NUMBER_ST,
997 1003
 												(void*)$3 ); }
998
-		| TOPORT intop attr_id {	onsend_check("to_port");
1004
+		| TOPORT intop attr_id_val {	onsend_check("to_port");
999 1005
 									$$=mk_elem($2, TOPORT_O, 0, AVP_ST,
1000 1006
 												(void*)$3 ); }
1001 1007
 		| TOPORT intop error { $$=0; yyerror("number expected"); }
1002 1008
 		| TOPORT error { $$=0; yyerror("==, !=, <,>, >= or <=  expected"); }
1003 1009
 
1004 1010
 		| 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 ); }
1011
+		| PROTO intop attr_id_val	{ $$=mk_elem($2, PROTO_O, 0, AVP_ST, (void*)$3 ); }
1006 1012
 		| PROTO intop error { $$=0;
1007 1013
 								yyerror("protocol expected (udp, tcp or tls)");
1008 1014
 							}
... ...
@@ -1011,7 +1017,7 @@ exp_elem:	METHOD strop STRING	{$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
1011 1017
 		| SNDPROTO intop proto	{	onsend_check("snd_proto");
1012 1018
 									$$=mk_elem($2, SNDPROTO_O, 0, NUMBER_ST,
1013 1019
 										(void*)$3 ); }
1014
-		| SNDPROTO intop attr_id {	onsend_check("snd_proto");
1020
+		| SNDPROTO intop attr_id_val {	onsend_check("snd_proto");
1015 1021
 									$$=mk_elem($2, SNDPROTO_O, 0, AVP_ST,
1016 1022
 										(void*)$3 ); }
1017 1023
 		| SNDPROTO intop error { $$=0;
... ...
@@ -1020,28 +1026,28 @@ exp_elem:	METHOD strop STRING	{$$= mk_elem($2, METHOD_O, 0, STRING_ST, $3);}
1020 1026
 		| SNDPROTO error { $$=0; yyerror("equal/!= operator expected"); }
1021 1027
 
1022 1028
 		| 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 ); }
1029
+		| AF intop attr_id_val	{ $$=mk_elem($2, AF_O, 0, AVP_ST,(void *) $3 ); }
1024 1030
 		| AF intop error { $$=0; yyerror("number expected"); }
1025 1031
 		| AF error { $$=0; yyerror("equal/!= operator expected"); }
1026 1032
 
1027 1033
 		| SNDAF intop NUMBER	{	onsend_check("snd_af");
1028 1034
 									$$=mk_elem($2, SNDAF_O, 0, NUMBER_ST,
1029 1035
 										(void *) $3 ); }
1030
-		| SNDAF intop attr_id	{	onsend_check("snd_af");
1036
+		| SNDAF intop attr_id_val	{	onsend_check("snd_af");
1031 1037
 									$$=mk_elem($2, SNDAF_O, 0, AVP_ST,
1032 1038
 										(void *) $3 ); }
1033 1039
 		| SNDAF intop error { $$=0; yyerror("number expected"); }
1034 1040
 		| SNDAF error { $$=0; yyerror("equal/!= operator expected"); }
1035 1041
 
1036 1042
 		| 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 ); }
1043
+		| MSGLEN intop attr_id_val	{ $$=mk_elem($2, MSGLEN_O, 0, AVP_ST, (void *) $3 ); }
1038 1044
 		| MSGLEN intop MAX_LEN	{ $$=mk_elem($2, MSGLEN_O, 0, NUMBER_ST, (void *) BUF_SIZE); }
1039 1045
 		| MSGLEN intop error { $$=0; yyerror("number expected"); }
1040 1046
 		| MSGLEN error { $$=0; yyerror("equal/!= operator expected"); }
1041 1047
 
1042 1048
 		| RETCODE intop NUMBER	{ $$=mk_elem($2, RETCODE_O, 0,
1043 1049
 												NUMBER_ST, (void *) $3 ); }
1044
-		| RETCODE intop attr_id	{ $$=mk_elem($2, RETCODE_O, 0,
1050
+		| RETCODE intop attr_id_val	{ $$=mk_elem($2, RETCODE_O, 0,
1045 1051
 												AVP_ST, (void *) $3 ); }
1046 1052
 		| RETCODE intop error { $$=0; yyerror("number expected"); }
1047 1053
 		| 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 1178
 		| exp_stm			{ $$=mk_elem( NO_OP, ACTION_O, 0, ACTIONS_ST, $1);  }
1173 1179
 		| NUMBER		{$$=mk_elem( NO_OP, NUMBER_O, 0, NUMBER_ST, (void*)$1 ); }
1174 1180
 
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); }
1181
+		| attr_id_val		{$$=mk_elem( NO_OP, AVP_O, (void*)$1, 0, 0); }
1182
+		| attr_id_val strop STRING	{$$=mk_elem( $2, AVP_O, (void*)$1, STRING_ST, $3); }
1183
+		| attr_id_val strop select_id {$$=mk_elem( $2, AVP_O, (void*)$1, SELECT_ST, $3); }
1184
+		| attr_id_val intop NUMBER	{$$=mk_elem( $2, AVP_O, (void*)$1, NUMBER_ST, (void*)$3); }
1185
+		| attr_id_val binop NUMBER	{$$=mk_elem( $2, AVP_O, (void*)$1, NUMBER_ST, (void*)$3); }
1186
+                | attr_id_val strop attr_id_val {$$=mk_elem( $2, AVP_O, (void*)$1, AVP_ST, (void*)$3); }
1181 1187
 
1182 1188
                 | select_id                 { $$=mk_elem( NO_OP, SELECT_O, $1, 0, 0); }
1183 1189
 		| 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); }
1190
+		| select_id strop attr_id_val   { $$=mk_elem( $2, SELECT_O, $1, AVP_ST, (void*)$3); }
1185 1191
 		| select_id strop select_id { $$=mk_elem( $2, SELECT_O, $1, SELECT_ST, $3); }
1186 1192
 ;
1187 1193
 
... ...
@@ -1334,67 +1340,62 @@ select_id : SELECT_MARK { sel.n = 0; sel.f = 0; } select_params {
1334 1340
 }
1335 1341
 ;
1336 1342
 
1343
+attr_class_spec: ATTR_FROMUSER { s_attr->type |= AVP_TRACK_FROM | AVP_CLASS_USER; } 
1344
+		|ATTR_TOUSER { s_attr->type |= AVP_TRACK_TO | AVP_CLASS_USER; } 
1345
+		|ATTR_FROMDOMAIN { s_attr->type |= AVP_TRACK_FROM | AVP_CLASS_DOMAIN; } 
1346
+		|ATTR_TODOMAIN { s_attr->type |= AVP_TRACK_TO | AVP_CLASS_DOMAIN; } 
1347
+		|ATTR_GLOBAL { s_attr->type |= AVP_TRACK_ALL | AVP_CLASS_GLOBAL; } 
1337 1348
 
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
-//                                            }
1349
+attr_name_spec : ID { s_attr->type |= AVP_NAME_STR; s_attr->name.s.s = $1; s_attr->name.s.len = strlen ($1); }
1350
+;
1351
+	       
1352
+attr_spec : attr_name_spec |
1353
+	    attr_class_spec DOT attr_name_spec
1354
+;
1355
+
1356
+attr_mark : ATTR_MARK 
1357
+	{	s_attr = (struct avp_spec*)pkg_malloc(sizeof(struct avp_spec));
1358
+                if (!s_attr) { yyerror("No memory left"); }
1359
+                s_attr->type = 0;  
1360
+	}
1361
+;
1362
+
1363
+attr_id : attr_mark attr_spec { $$ = s_attr; }	  
1364
+;
1365
+
1366
+attr_id_num_idx : attr_mark attr_spec LBRACK NUMBER RBRACK
1367
+	       	{	s_attr->type|= (AVP_NAME_STR | ($4<0?AVP_INDEX_BACKWARD:AVP_INDEX_FORWARD)); 
1368
+			s_attr->index = ($4<0?-$4:$4);
1369
+	       		$$ = s_attr; 
1370
+	       	}	  
1371
+;
1372
+
1373
+attr_id_no_idx : attr_mark attr_spec LBRACK RBRACK
1374
+	       	{	s_attr->type|= AVP_INDEX_ALL; 
1375
+	       		$$ = s_attr;
1376
+		}	  
1377
+;
1378
+
1379
+attr_id_ass : attr_id | attr_id_no_idx
1380
+;
1381
+
1382
+attr_id_val : attr_id | attr_id_num_idx
1383
+;
1384
+
1385
+attr_id_any : attr_id | attr_id_no_idx | attr_id_num_idx
1386 1386
 ;
1387 1387
 
1388
-assign_op : ADDEQ { $$ = ADD_T; }
1389
-          | EQUAL { $$ = ASSIGN_T; }
1388
+//assign_op : ADDEQ { $$ = ADD_T; }
1389
+//          | EQUAL { $$ = ASSIGN_T; }
1390
+assign_op : EQUAL { $$ = ASSIGN_T; }
1390 1391
 ;
1391 1392
 
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); }
1393
+assign_action:   attr_id_ass assign_op STRING  { $$=mk_action($2, AVP_ST, STRING_ST, $1, $3); }
1394
+               | attr_id_ass assign_op NUMBER  { $$=mk_action($2, AVP_ST, NUMBER_ST, $1, (void*)$3); }
1395
+               | attr_id_ass assign_op fcmd    { $$=mk_action($2, AVP_ST, ACTION_ST, $1, $3); }
1396
+               | attr_id_ass assign_op attr_id_any { $$=mk_action($2, AVP_ST, AVP_ST, $1, $3); }
1397
+               | attr_id_ass assign_op select_id { $$=mk_action($2, AVP_ST, SELECT_ST, (void*)$1, (void*)$3); }
1398
+               | attr_id_ass assign_op LPAREN exp RPAREN { $$ = mk_action($2, AVP_ST, EXPR_ST, $1, $4); }
1398 1399
 ;
1399 1400
 
1400 1401
 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 315
 		/* process and optimize the element name */
315 316
 		if (ha->type==ELEM_IS_AVP) {
316 317
 			/* element is AVP */
317
-			if ( parse_avp_spec( &foo, &n, &avp_name)!=0 ) {
318
+			if ( parse_avp_spec( &foo, &n, &avp_name, &index)!=0 ) {
318 319
 				LOG(L_ERR,"ERROR:tm:parse_tw_append: bad alias spec "
319 320
 					"<%.*s>\n",foo.len, foo.s);
320 321
 				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 300
 		fr_timer_str.s = fr_timer_param;
299 301
 		fr_timer_str.len = strlen(fr_timer_str.s);
300 302
 		if (parse_avp_spec( &fr_timer_str, &fr_timer_avp_type,
301
-		&fr_timer_avp)<0) {
303
+		&fr_timer_avp, &fr_timer_index)<0) {
302 304
 			LOG(L_CRIT,"ERROR:tm:init_avp_params: invalid fr_timer "
303 305
 				"AVP specs \"%s\"\n", fr_timer_param);
304 306
 			return -1;
... ...
@@ -309,7 +311,7 @@ int init_avp_params(char *fr_timer_param, char *fr_inv_timer_param)
309 311
 		fr_inv_timer_str.s = fr_inv_timer_param;
310 312
 		fr_inv_timer_str.len = strlen(fr_inv_timer_str.s);
311 313
 		if (parse_avp_spec( &fr_inv_timer_str, &fr_inv_timer_avp_type, 
312
-		&fr_inv_timer_avp)<0) {
314
+		&fr_inv_timer_avp, &fr_inv_timer_index)<0) {
313 315
 			LOG(L_CRIT,"ERROR:tm:init_avp_params: invalid fr_inv_timer "
314 316
 				"AVP specs \"%s\"\n", fr_inv_timer_param);
315 317
 			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 132
 }
132 133
 
133 134
 
134
-int add_avp_list(avp_list_t* list, unsigned short flags, int_str name, int_str val)
135
+avp_t *create_avp (unsigned short flags, int_str name, int_str val)
135 136
 {
136 137
 	avp_t *avp;
137 138
 	str *s;
... ...
@@ -139,13 +140,11 @@ int add_avp_list(avp_list_t* list, unsigned short flags, int_str name, int_str v
139 140
 	struct str_str_data *ssd;
140 141
 	int len;
141 142
 
142
-	assert(list != 0);
143
-
144 143
 	if (name.s.s == 0 && name.s.len == 0) {
145 144
 		LOG(L_ERR,"ERROR:avp:add_avp: 0 ID or NULL NAME AVP!");
146 145
 		goto error;
147 146
 	}
148
-
147
+	
149 148
 	/* compute the required mem size */
150 149
 	len = sizeof(struct usr_avp);
151 150
 	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 167
 	avp = (struct usr_avp*)shm_malloc( len );
169 168
 	if (avp==0) {
170 169
 		LOG(L_ERR,"ERROR:avp:add_avp: no more shm mem\n");
171
-		goto error;
170
+		return 0;
172 171
 	}
173 172
 
174 173
 	avp->flags = flags;
175 174
 	avp->id = (flags&AVP_NAME_STR)? compute_ID(&name.s) : name.n ;
176
-
177
-	avp->next = *list;
178
-	*list = avp;
175
+	avp->next = NULL;
179 176
 
180 177
 	switch ( flags&(AVP_NAME_STR|AVP_VAL_STR) )
181 178
 	{
... ...
@@ -213,9 +210,23 @@ int add_avp_list(avp_list_t* list, unsigned short flags, int_str name, int_str v
213 210
 			ssd->val.s[ssd->val.len] = 0;
214 211
 			break;
215 212
 	}
216
-
217
-	return 0;
213
+	return avp;
218 214
 error:
215
+	return 0;
216
+}
217
+
218
+int add_avp_list(avp_list_t* list, unsigned short flags, int_str name, int_str val)
219
+{
220
+	avp_t *avp;
221
+
222
+	assert(list != 0);
223
+
224
+	if ((avp = create_avp(flags, name, val))) {
225
+		avp->next = *list;
226
+		*list = avp;
227
+		return 0;
228
+	}
229
+	
219 230
 	return -1;
220 231
 }
221 232
 
... ...
@@ -242,6 +253,28 @@ int add_avp(unsigned short flags, int_str name, int_str val)
242 253
 	return add_avp_list(list, flags & (~(AVP_CLASS_ALL) | avp_class), name, val);
243 254
 }
244 255
 
256
+int add_avp_before(avp_t *avp, unsigned short flags, int_str name, int_str val)
257
+{
258
+	avp_t *new_avp;
259
+	
260
+	if (!avp) {
261
+		return add_avp(flags, name, val);
262
+	}
263
+
264
+	if ((flags & AVP_CLASS_ALL) == 0) flags |= (avp->flags & AVP_CLASS_ALL);
265
+	if ((flags & AVP_TRACK_ALL) == 0) flags |= (avp->flags & AVP_TRACK_ALL);
266
+	
267
+	if ((avp->flags & (AVP_CLASS_ALL|AVP_TRACK_ALL)) != (flags & (AVP_CLASS_ALL|AVP_TRACK_ALL))) {
268
+		ERR("add_avp_before:Source and target AVPs have different CLASS/TRACK\n");
269
+		return -1;
270
+	}
271
+	if ((new_avp=create_avp(flags, name, val))) {
272
+		new_avp->next=avp->next;
273
+		avp->next=new_avp;
274
+		return 0;
275
+	}
276
+	return -1;
277
+}
245 278
 
246 279
 /* get value functions */
247 280
 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 391
 		LOG(L_ERR,"ERROR:avp:search_first_avp: 0 ID or NULL NAME AVP!");
359 392
 		return 0;
360 393
 	}
394
+	
395
+	switch (flags & AVP_INDEX_ALL) {
396
+		case AVP_INDEX_BACKWARD:
397
+		case AVP_INDEX_FORWARD:
398
+			WARN("AVP specified with index, but not used for search\n");
399
+			break;
400
+	}
361 401
 
362 402
 	if (!s) s = &st;
363 403
 
... ...
@@ -366,6 +406,17 @@ avp_t *search_first_avp(unsigned short flags, int_str name, int_str *val, struct
366 406
 		      * all of them by default
367 407
 		      */
368 408
 		flags |= AVP_CLASS_ALL;
409
+		
410
+		if ((flags & AVP_TRACK_ALL) == 0) {
411
+		    /* The caller did not specify even the track to search in, so try
412
+		     * track_from first, and if not found try track_to
413
+		     */
414
+		     	ret = search_first_avp(flags | AVP_TRACK_FROM, name, val, s);
415
+		     	if (ret) {
416
+		     		return ret;
417
+		     	}
418
+		     	flags |= AVP_TRACK_TO;
419
+		}
369 420
 	}
370 421
 
371 422
 	list = select_list(flags);
... ...
@@ -399,6 +450,13 @@ avp_t *search_next_avp(struct search_state* s, int_str *val )
399 450
 		return 0;
400 451
 	}
401 452
 
453
+	switch (s->flags & AVP_INDEX_ALL) {
454
+		case AVP_INDEX_BACKWARD:
455
+		case AVP_INDEX_FORWARD:
456
+			WARN("AVP specified with index, but not used for search\n");
457
+			break;
458
+	}
459
+
402 460
 	while(1) {
403 461
 		for( ; s->avp; s->avp = s->avp->next) {
404 462
 			if (s->flags & AVP_NAME_RE) {
... ...
@@ -431,6 +489,54 @@ avp_t *search_next_avp(struct search_state* s, int_str *val )
431 489
 	return 0;
432 490
 }
433 491
 
492
+int search_reverse( avp_t *cur, struct search_state* st,
493
+                     unsigned short index, avp_list_t *ret)
494
+{
495
+	unsigned short lvl;
496
+	
497
+	if (!cur)
498
+		return 0;
499
+	lvl = search_reverse(search_next_avp(st, NULL), st, index, ret)+1;
500
+	if (index==lvl)
501
+		*ret=cur;
502
+	return lvl;
503
+}
504
+                            
505
+avp_t *search_avp_by_index( unsigned short flags, int_str name,
506
+                            int_str *val, unsigned short index) 	
507
+{
508
+	avp_t *ret, *cur;
509
+	struct search_state st;
510
+	
511
+	if (flags & AVP_NAME_RE) {
512
+		BUG("search_by_index not supported for AVP_NAME_RE\n");
513
+		return 0;
514
+	}
515
+	switch (flags & AVP_INDEX_ALL) {
516
+		case 0:
517
+			ret = search_first_avp(flags, name, val, &st);
518
+			if (!ret || search_next_avp(&st, NULL))
519
+				return 0;
520
+			else
521
+				return ret;
522
+		case AVP_INDEX_ALL:
523
+			BUG("search_by_index not supported for anonymous index []\n");
524
+			return 0;
525
+		case AVP_INDEX_FORWARD:
526
+			ret = NULL;
527
+			cur = search_first_avp(flags & ~AVP_INDEX_ALL, name, NULL, &st);
528
+			search_reverse(cur, &st, index, &ret);
529
+			if (ret && val)
530
+				get_avp_val(ret, val);
531
+			return ret;
532
+		case AVP_INDEX_BACKWARD:
533
+			ret = search_first_avp(flags & ~AVP_INDEX_ALL, name, val, &st);
534
+			for (index--; (ret && index); ret=search_next_avp(&st, val), index--);
535
+			return ret;
536
+	}
537
+		
538
+	return 0;
539
+}                            
434 540
 
435 541
 /* FIXME */
436 542
 /********* free functions ********/
... ...
@@ -647,16 +753,28 @@ int lookup_avp_galias(str *alias, int *type, int_str *avp_name)
647 753
 
648 754
 
649 755
 /* parsing functions */
756
+#define ERR_IF_CONTAINS(name,chr) \
757
+	if (memchr(name->s,chr,name->len)) { \
758
+		ERR("Unexpected control character '%c' in AVP name\n", chr); \
759
+		goto error; \
760
+	}
650 761
 
651
-int parse_avp_name( str *name, int *type, int_str *avp_name)
762
+int parse_avp_name( str *name, int *type, int_str *avp_name, int *index)
652 763
 {
653 764
 	unsigned int id;
654 765
 	char c;
766
+	char *p;
767
+	str s;
655 768
 
656
-	if (name==0 || name->s==0 || name->len==0)
769
+	if (name==0 || name->s==0 || name->len==0) {
770
+		ERR("NULL name or name->s or name->len\n");
657 771
 		goto error;
772
+	}
658 773
 
659
-	if (name->len>=2 && name->s[1]==':') {
774
+	if (index) *index = 0;
775
+	ERR("Parsing '%.*s'\n", name->len, name->s);
776
+	if (name->len>=2 && name->s[1]==':') { // old fashion i: or s:
777
+		WARN("i: and s: avp name syntax is deprecated!\n");
660 778
 		c = name->s[0];
661 779
 		name->s += 2;
662 780
 		name->len -= 2;
... ...
@@ -670,17 +788,108 @@ int parse_avp_name( str *name, int *type, int_str *avp_name)
670 788
 			case 'i': case 'I':
671 789
 				*type = 0;
672 790
 				if (str2int( name, &id)!=0) {
673
-					LOG(L_ERR, "ERROR:parse_avp_name: invalid ID "
791
+					ERR("invalid ID "
674 792
 						"<%.*s> - not a number\n", name->len, name->s);
675 793
 					goto error;
676 794
 				}
677 795
 				avp_name->n = (int)id;
678 796
 				break;
679 797
 			default:
680
-				LOG(L_ERR, "ERROR:parse_avp_name: unsupported type "
798
+				ERR("unsupported type "
681 799
 					"[%c]\n", c);
682 800
 				goto error;
683 801
 		}
802
+	} else if ((p=memchr(name->s, '.', name->len))) {
803
+		if (p-name->s==1) {
804
+			id=name->s[0];
805
+			name->s +=2;
806
+			name->len -=2;
807
+		} else if (p-name->s==2) {
808
+			id=name->s[0]<<8 | name->s[1];
809
+			name->s +=3;
810
+			name->len -=3;
811
+		} else {
812
+			ERR("AVP unknown class prefix '%.*s'\n", p-name->s,name->s);
813
+			goto error;
814
+		}
815
+		if (name->len==0) {
816
+			ERR("AVP name not specified after the prefix separator\n");
817
+			goto error;
818
+		}
819
+		switch (id) {
820
+			case 'f':
821
+				*type = AVP_TRACK_FROM | AVP_CLASS_USER;
822
+				break;
823
+			case 't':
824
+				*type = AVP_TRACK_TO | AVP_CLASS_USER;
825
+				break;
826
+			case 0x6664: //'fd'
827
+				*type = AVP_TRACK_FROM | AVP_CLASS_DOMAIN;
828
+				break;
829
+			case 0x7464: // 'td'
830
+				*type = AVP_TRACK_TO | AVP_CLASS_DOMAIN;
831
+				break;
832
+			case 'g':
833
+				*type = AVP_TRACK_ALL | AVP_CLASS_GLOBAL;
834
+				break;
835
+			default:
836
+				if (id < 1<<8)
837
+					ERR("AVP unknown class prefix '%c'\n", id);
838
+				else
839
+					ERR("AVP unknown class prefix '%c%c'\n", id>>8,id);
840
+				goto error;
841
+		}
842
+		if (name->s[name->len-1]==']') {
843
+			p=memchr(name->s, '[', name->len);
844
+			if (!p) {
845
+				ERR("missing '[' for AVP index\n");
846
+				goto error; 
847
+			}
848
+			s.s=p+1;
849
+			s.len=name->len-(p-name->s)-2; // [ and ]
850
+			if (s.len == 0) {
851
+				*type |= AVP_INDEX_ALL;
852
+			} else {
853
+				if (s.s[0]=='-') {
854
+					*type |= AVP_INDEX_BACKWARD;
855
+					s.s++;s.len--;
856
+				} else {
857
+					*type |= AVP_INDEX_FORWARD;
858
+				}	
859
+				if ((str2int(&s, &id) != 0)||(id==0)) {
860
+					ERR("Invalid AVP index '%.*s'\n", s.len, s.s);
861
+					goto error;
862
+				}
863
+				if (index){
864
+					*index = id;
865
+				} else {
866
+					WARN("AVP index correcly specified, but called without placeholed\n");
867
+				}
868
+			}
869
+			name->len=p-name->s;
870
+		}
871
+		ERR_IF_CONTAINS(name,'.');
872
+		ERR_IF_CONTAINS(name,'[');
873
+		ERR_IF_CONTAINS(name,']');
874
+		if ((name->len > 2) && (name->s[0]=='/') && (name->s[name->len-1]=='/')) {
875
+			avp_name->re=pkg_malloc(sizeof(regex_t));
876
+			if (!avp_name->re) {
877
+				BUG("No free memory to allocate AVP_NAME_RE regex\n");
878
+				goto error;
879
+			}
880
+			c=name->s[name->len];
881
+			name->s[name->len]=0;
882
+			if (regcomp(avp_name->re, name->s, REG_EXTENDED|REG_NOSUB|REG_ICASE)) {
883
+				pkg_free(avp_name->re);
884
+				name->s[name->len] = c;
885
+				goto error;
886
+			}
887
+			*type |= AVP_NAME_RE;
888
+		} else {
889
+			ERR_IF_CONTAINS(name,'/');
890
+			*type |= AVP_NAME_STR;
891
+		}
892
+		avp_name->s = *name;
684 893
 	} else {
685 894
 		/*default is string name*/
686 895
 		*type = AVP_NAME_STR;
... ...
@@ -693,7 +902,7 @@ error:
693 902
 }
694 903
 
695 904
 
696
-int parse_avp_spec( str *name, int *type, int_str *avp_name)
905
+int parse_avp_spec( str *name, int *type, int_str *avp_name, int *index)
697 906
 {
698 907
 	str alias;
699 908
 
... ...
@@ -710,10 +919,15 @@ int parse_avp_spec( str *name, int *type, int_str *avp_name)
710 919
 		alias.len = name->len-1;
711 920
 		return lookup_avp_galias( &alias, type, avp_name);
712 921
 	} else {
713
-		return parse_avp_name( name, type, avp_name);
922
+		return parse_avp_name( name, type, avp_name, index);
714 923
 	}
715 924
 }
716 925
 
926
+void free_avp_name( int *type, int_str *avp_name)
927
+{
928
+	if ((*type & AVP_NAME_RE) && (avp_name->re))
929
+		pkg_free(avp_name->re);
930
+}
717 931
 
718 932
 int add_avp_galias_str(char *alias_definition)
719 933
 {
... ...
@@ -722,7 +936,8 @@ int add_avp_galias_str(char *alias_definition)
722 936
 	str  name;
723 937
 	str  alias;
724 938
 	int  type;
725
-
939
+	int  index;
940
+	
726 941
 	s = alias_definition;
727 942
 	while(*s && isspace((int)*s))
728 943
 		s++;
... ...
@@ -761,7 +976,7 @@ int add_avp_galias_str(char *alias_definition)
761 976
 				goto parse_error;
762 977
 		}
763 978
 
764
-		if (parse_avp_name( &name, &type, &avp_name)!=0) {
979
+		if (parse_avp_name( &name, &type, &avp_name, &index)!=0) {
765 980
 			LOG(L_ERR, "ERROR:add_avp_galias_str: <%.*s> not a valid AVP "
766 981
 				"name\n", name.len, name.s);
767 982
 			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 66
 #define AVP_FR_INV_TIMER "fr_inv_timer"  /* Value of final response invite timer */
66 67
 #define AVP_RPID         "rpid"          /* Remote-Party-ID */
67 68
 #define AVP_GFLAGS       "gflags"        /* global flags */
69
+#define AVP_FLAGS	 "flags"	 /* message flags */
68 70
 
69 71
 struct str_int_data {
70 72
 	str name;
... ...
@@ -109,6 +111,7 @@ struct search_state {
109 111
 typedef struct avp_spec {
110 112
 	int type;
111 113
 	int_str name;
114
+	int index;
112 115
 } avp_spec_t;
113 116
 
114 117
 /* AVP types */
... ...
@@ -128,6 +131,11 @@ typedef struct avp_spec {
128 131
 
129 132
 #define AVP_CLASS_ALL (AVP_CLASS_USER|AVP_CLASS_DOMAIN|AVP_CLASS_GLOBAL)
130 133
 
134
+/* AVP name index */
135
+#define AVP_INDEX_FORWARD	(1<<10)
136
+#define AVP_INDEX_BACKWARD	(1<<11)
137
+#define AVP_INDEX_ALL		(AVP_INDEX_FORWARD | AVP_INDEX_BACKWARD)
138
+
131 139
 #define GALIAS_CHAR_MARKER  '$'
132 140
 
133 141
 /* Initialize memory structures */
... ...
@@ -135,6 +143,7 @@ int init_avps(void);
135 143
 
136 144
 /* add avp to the list of avps */
137 145
 int add_avp(unsigned short flags, int_str name, int_str val);
146
+int add_avp_before(avp_t *avp, unsigned short flags, int_str name, int_str val);
138 147
 int add_avp_list(avp_list_t* list, unsigned short flags, int_str name, int_str val);
139 148
 
140 149
 /* Delete avps with given type and name */
... ...
@@ -145,6 +154,8 @@ avp_t *search_first_avp( unsigned short flags, int_str name,
145 154
 			 int_str *val, struct search_state* state);
146 155
 avp_t *search_next_avp(struct search_state* state, int_str *val);
147 156
 
157
+avp_t *search_avp_by_index( unsigned short flags, int_str name,
158
+                            int_str *val, unsigned short index);
148 159
 /* free functions */
149 160
 void reset_avps(void);
150 161
 
... ...
@@ -164,7 +175,8 @@ avp_list_t* set_avp_list(unsigned short flags, avp_list_t* list);
164 175
 int add_avp_galias_str(char *alias_definition);
165 176
 int lookup_avp_galias(str *alias, int *type, int_str *avp_name);
166 177
 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);
178
+int parse_avp_name( str *name, int *type, int_str *avp_name, int *index);
179
+int parse_avp_spec( str *name, int *type, int_str *avp_name, int *index);
180
+void free_avp_name( int *type, int_str *avp_name);
169 181
 
170 182
 #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)