Browse code

- added AVP flags feature.

Every AVP may by flaged from script via setavpflag(avpid, flag) (it's similar like message flags setflags,resetflags,isflagset). AVP flags must be declared using avpflags statement. Flags may be tested via isavpflagset(avpid, flag). Both the setting and testing may also be processed in a module. It's currently used in the "rr" module for dialog_cookies. Such module should register flag using register_avpflag(flag_id).

Example:
avpflags myflag, dialog_cookie;

$a = 123;
setavpflag($a, "myflag");

if (isavpflagset($a, "myflag")) {
....

$dlg_foo = "foo";
$dlg_bar = "bar";
setavpflag("$f./^dlg_", "dialog_cookie");

Tomas Mandys authored on 31/05/2006 23:02:46
Showing 9 changed files
... ...
@@ -365,6 +365,45 @@ int do_action(struct action* a, struct sip_msg* msg)
365 365
 			break;
366 366
 		/* jku - end : flag processing */
367 367
 
368
+		case AVPFLAG_OPER_T:  {
369
+			struct search_state st;
370
+			avp_t* avp;
371
+			int flag;
372
+			ret = 0;
373
+			flag = a->val[1].u.number;
374
+			if ((a->val[0].u.attr->type & AVP_INDEX_ALL) == AVP_INDEX_ALL || (a->val[0].u.attr->type & AVP_NAME_RE)!=0) {
375
+				for (avp=search_first_avp(a->val[0].u.attr->type, a->val[0].u.attr->name, NULL, &st); avp; avp = search_next_avp(&st, NULL)) {
376
+					switch (a->val[2].u.number) {   /* oper: 0..reset, 1..set, -1..no change */
377
+						case 0:
378
+							avp->flags &= ~(avp_flags_t)a->val[1].u.number;
379
+							break;
380
+						case 1:
381
+							avp->flags |= (avp_flags_t)a->val[1].u.number;
382
+							break;
383
+						default:;
384
+					}
385
+					ret = ret || ((avp->flags & (avp_flags_t)a->val[1].u.number) != 0);
386
+				}
387
+			}
388
+			else {
389
+				avp = search_avp_by_index(a->val[0].u.attr->type, a->val[0].u.attr->name, NULL, a->val[0].u.attr->index);
390
+				if (avp) {
391
+					switch (a->val[2].u.number) {   /* oper: 0..reset, 1..set, -1..no change */
392
+						case 0:
393
+							avp->flags &= ~(avp_flags_t)a->val[1].u.number;
394
+							break;
395
+						case 1:
396
+							avp->flags |= (avp_flags_t)a->val[1].u.number;
397
+							break;
398
+						default:;
399
+					}
400
+					ret = (avp->flags & (avp_flags_t)a->val[1].u.number) != 0;
401
+				}
402
+			}
403
+			if (ret==0)
404
+				ret = -1;
405
+			break;
406
+		}
368 407
 		case ERROR_T:
369 408
 			if ((a->val[0].type!=STRING_ST)|(a->val[1].type!=STRING_ST)){
370 409
 				LOG(L_CRIT, "BUG: do_action: bad error() types %d, %d\n",
... ...
@@ -131,6 +131,10 @@ SETFLAG		setflag
131 131
 RESETFLAG	resetflag
132 132
 ISFLAGSET	isflagset
133 133
 FLAGS_DECL	"flags"|"bool"
134
+SETAVPFLAG	setavpflag
135
+RESETAVPFLAG	resetavpflag
136
+ISAVPFLAGSET	isavpflagset
137
+AVPFLAGS_DECL	avpflags
134 138
 SET_HOST		"rewritehost"|"sethost"|"seth"
135 139
 SET_HOSTPORT	"rewritehostport"|"sethostport"|"sethp"
136 140
 SET_USER		"rewriteuser"|"setuser"|"setu"
... ...
@@ -336,6 +340,10 @@ EAT_ABLE	[\ \t\b\r]
336 336
 <INITIAL>{RESETFLAG}	{ count(); yylval.strval=yytext; return RESETFLAG; }
337 337
 <INITIAL>{ISFLAGSET}	{ count(); yylval.strval=yytext; return ISFLAGSET; }
338 338
 <INITIAL>{FLAGS_DECL}	{ count(); yylval.strval=yytext; return FLAGS_DECL; }
339
+<INITIAL>{SETAVPFLAG}	{ count(); yylval.strval=yytext; return SETAVPFLAG; }
340
+<INITIAL>{RESETAVPFLAG}	{ count(); yylval.strval=yytext; return RESETAVPFLAG; }
341
+<INITIAL>{ISAVPFLAGSET}	{ count(); yylval.strval=yytext; return ISAVPFLAGSET; }
342
+<INITIAL>{AVPFLAGS_DECL}	{ count(); yylval.strval=yytext; return AVPFLAGS_DECL; }
339 343
 <INITIAL>{MSGLEN}	{ count(); yylval.strval=yytext; return MSGLEN; }
340 344
 <INITIAL>{RETCODE}	{ count(); yylval.strval=yytext; return RETCODE; }
341 345
 <INITIAL>{ROUTE}	{ count(); yylval.strval=yytext; return ROUTE; }
... ...
@@ -71,6 +71,7 @@
71 71
  * 2005-01-07  optional semicolon in statement, PARAM_STR&PARAM_STRING
72 72
  * 2006-02-02  named flags support (andrei)
73 73
  * 2006-02-06  named routes support (andrei)
74
+ * 2006-05-30  avp flags (tma)
74 75
  */
75 76
 
76 77
 %{
... ...
@@ -193,6 +194,9 @@ static struct socket_id* mk_listen_id(char*, int, int);
193 193
 %token SETFLAG
194 194
 %token RESETFLAG
195 195
 %token ISFLAGSET
196
+%token SETAVPFLAG
197
+%token RESETAVPFLAG
198
+%token ISAVPFLAGSET
196 199
 %token METHOD
197 200
 %token URI
198 201
 %token FROM_URI
... ...
@@ -280,6 +284,7 @@ static struct socket_id* mk_listen_id(char*, int, int);
280 280
 %token TOS
281 281
 
282 282
 %token FLAGS_DECL
283
+%token AVPFLAGS_DECL
283 284
 
284 285
 %token ATTR_MARK
285 286
 %token SELECT_MARK
... ...
@@ -349,11 +354,13 @@ static struct socket_id* mk_listen_id(char*, int, int);
349 349
 %type <attr> attr_id_ass
350 350
 %type <attr> attr_id_val
351 351
 %type <attr> attr_id_any
352
+%type <attr> attr_id_any_str
352 353
 /* %type <intval> class_id */
353 354
 %type <intval> assign_op
354 355
 %type <select> select_id
355 356
 %type <strval>	flag_name;
356 357
 %type <strval>	route_name;
358
+%type <intval> avpflag_oper
357 359
 
358 360
 /*%type <route_el> rules;
359 361
   %type <route_el> rule;
... ...
@@ -373,6 +380,7 @@ statements:
373 373
 statement:
374 374
 	assign_stm
375 375
 	| flags_decl
376
+	| avpflags_decl
376 377
 	| module_stm
377 378
 	| {rt=REQUEST_ROUTE;} route_stm
378 379
 	| {rt=FAILURE_ROUTE;} failure_route_stm
... ...
@@ -460,6 +468,20 @@ flag_name:		STRING	{ $$=$1; }
460 460
 			|	ID		{ $$=$1; }
461 461
 ;
462 462
 
463
+avpflags_decl:
464
+	AVPFLAGS_DECL avpflag_list
465
+	| AVPFLAGS_DECL error { yyerror("avpflag list expected\n"); }
466
+	;
467
+avpflag_list:
468
+	avpflag_spec
469
+	| avpflag_spec COMMA avpflag_list
470
+	;
471
+avpflag_spec:
472
+	flag_name {
473
+		if (register_avpflag($1)==0)
474
+			yyerror("cannot declare avpflag");
475
+	}
476
+	;
463 477
 assign_stm:
464 478
 	DEBUG_V EQUAL NUMBER { debug=$3; }
465 479
 	| DEBUG_V EQUAL error  { yyerror("number  expected"); }
... ...
@@ -891,7 +913,7 @@ route_stm:
891 891
 	| ROUTE error { yyerror("invalid  route  statement"); }
892 892
 	;
893 893
 failure_route_stm:
894
-	ROUTE_FAILURE LBRACE actions RBRACE { 
894
+	ROUTE_FAILURE LBRACE actions RBRACE {
895 895
 									push($3, &failure_rt.rlist[DEFAULT_RT]);
896 896
 										}
897 897
 	| ROUTE_FAILURE LBRACK route_name RBRACK LBRACE actions RBRACE {
... ...
@@ -927,7 +949,7 @@ onreply_route_stm:
927 927
 	| ROUTE_ONREPLY error { yyerror("invalid onreply_route statement"); }
928 928
 	;
929 929
 branch_route_stm:
930
-	ROUTE_BRANCH LBRACE actions RBRACE { 
930
+	ROUTE_BRANCH LBRACE actions RBRACE {
931 931
 									push($3, &branch_rt.rlist[DEFAULT_RT]);
932 932
 										}
933 933
 	| ROUTE_BRANCH LBRACK route_name RBRACK LBRACE actions RBRACE {
... ...
@@ -1404,6 +1426,29 @@ attr_id_any:
1404 1404
 	| attr_id_no_idx
1405 1405
 	| attr_id_num_idx
1406 1406
 ;
1407
+attr_id_any_str:
1408
+	attr_id
1409
+	| STRING {
1410
+		avp_spec_t *avp_spec;
1411
+		str s;
1412
+		int type, idx;
1413
+		avp_spec = pkg_malloc(sizeof(*avp_spec));
1414
+		if (!avp_spec) {
1415
+			yyerror("Not enough memory");
1416
+			YYABORT;
1417
+		}
1418
+		s.s = $1+1; /* skip $ */
1419
+		s.len = strlen(s.s);
1420
+		if (parse_avp_name(&s, &type, &avp_spec->name, &idx)) {
1421
+			yyerror("error when parsing AVP");
1422
+		        pkg_free(avp_spec);
1423
+			YYABORT;
1424
+		}
1425
+		avp_spec->type = type;
1426
+		avp_spec->index = idx;
1427
+		$$ = avp_spec;
1428
+	}
1429
+	;
1407 1430
 /*
1408 1431
 assign_op:
1409 1432
 	ADDEQ { $$ = ADD_T; }
... ...
@@ -1421,6 +1466,11 @@ assign_action:
1421 1421
 	| attr_id_ass assign_op select_id { $$=mk_action($2, 2, AVP_ST, (void*)$1, SELECT_ST, (void*)$3); }
1422 1422
 	| attr_id_ass assign_op LPAREN exp RPAREN { $$ = mk_action($2, 2, AVP_ST, $1, EXPR_ST, $4); }
1423 1423
 	;
1424
+avpflag_oper:
1425
+	SETAVPFLAG { $$ = 1; }
1426
+	| RESETAVPFLAG { $$ = 0; }
1427
+	| ISAVPFLAGSET { $$ = -1; }
1428
+	;
1424 1429
 cmd:
1425 1430
 	FORWARD LPAREN host RPAREN	{ $$=mk_action(	FORWARD_T, 2, STRING_ST, $3, NUMBER_ST, 0); }
1426 1431
 	| FORWARD LPAREN STRING RPAREN	{ $$=mk_action(	FORWARD_T, 2, STRING_ST, $3, NUMBER_ST, 0); }
... ...
@@ -1568,7 +1618,7 @@ cmd:
1568 1568
 							i_tmp=get_flag_no($3, strlen($3));
1569 1569
 							if (i_tmp<0) yyerror("flag not declared");
1570 1570
 							$$=mk_action(SETFLAG_T, 1, NUMBER_ST,
1571
-										(void*)(long)i_tmp); 
1571
+										(void*)(long)i_tmp);
1572 1572
 									}
1573 1573
 	| SETFLAG error			{ $$=0; yyerror("missing '(' or ')'?"); }
1574 1574
 	| RESETFLAG LPAREN NUMBER RPAREN {
... ...
@@ -1580,7 +1630,7 @@ cmd:
1580 1580
 							i_tmp=get_flag_no($3, strlen($3));
1581 1581
 							if (i_tmp<0) yyerror("flag not declared");
1582 1582
 							$$=mk_action(RESETFLAG_T, 1, NUMBER_ST,
1583
-										(void*)(long)i_tmp); 
1583
+										(void*)(long)i_tmp);
1584 1584
 									}
1585 1585
 	| RESETFLAG error		{ $$=0; yyerror("missing '(' or ')'?"); }
1586 1586
 	| ISFLAGSET LPAREN NUMBER RPAREN {
... ...
@@ -1592,13 +1642,19 @@ cmd:
1592 1592
 							i_tmp=get_flag_no($3, strlen($3));
1593 1593
 							if (i_tmp<0) yyerror("flag not declared");
1594 1594
 							$$=mk_action(ISFLAGSET_T, 1, NUMBER_ST,
1595
-										(void*)(long)i_tmp); 
1595
+										(void*)(long)i_tmp);
1596 1596
 									}
1597 1597
 	| ISFLAGSET error { $$=0; yyerror("missing '(' or ')'?"); }
1598
+	| avpflag_oper LPAREN attr_id_any_str COMMA flag_name RPAREN {
1599
+		i_tmp=get_avpflag_no($5);
1600
+		if (i_tmp==0) yyerror("avpflag not declared");
1601
+		$$=mk_action(AVPFLAG_OPER_T, 3, AVP_ST, $3, NUMBER_ST, (void*)(long)i_tmp, NUMBER_ST, (void*)$1);
1602
+	}
1603
+	| avpflag_oper error { $$=0; yyerror("missing '(' or ')'?"); }
1598 1604
 	| ERROR LPAREN STRING COMMA STRING RPAREN {$$=mk_action(ERROR_T, 2, STRING_ST, $3, STRING_ST, $5); }
1599 1605
 	| ERROR error { $$=0; yyerror("missing '(' or ')' ?"); }
1600 1606
 	| ERROR LPAREN error RPAREN { $$=0; yyerror("bad error argument"); }
1601
-	| ROUTE LPAREN route_name RPAREN	{ 
1607
+	| ROUTE LPAREN route_name RPAREN	{
1602 1608
 						i_tmp=route_get(&main_rt, $3);
1603 1609
 						if (i_tmp==-1){
1604 1610
 							yyerror("internal error");
... ...
@@ -1,5 +1,5 @@
1 1
 <?xml version="1.0" encoding="UTF-8"?>
2
-<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" 
2
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
3 3
    "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
4 4
 
5 5
 <section id="routing_engine" xmlns:xi="http://www.w3.org/2001/XInclude">
... ...
@@ -69,7 +69,7 @@
69 69
 	</para>
70 70
 	<para>
71 71
 	    The following commands are handled by the <acronym>SER</acronym> core
72
-	    itself: 
72
+	    itself:
73 73
 	    <function>drop</function>,
74 74
 	    <function>forward</function>,
75 75
 	    <function>send</function>,
... ...
@@ -79,6 +79,9 @@
79 79
 	    <function>setflag</function>,
80 80
 	    <function>resetflag</function>,
81 81
 	    <function>isflagset</function>,
82
+	    <function>setavpflag</function>,
83
+	    <function>resetavpflag</function>,
84
+	    <function>isavpflagset</function>,
82 85
 	    <function>error</function>,
83 86
 	    <function>route</function>,
84 87
 	    <function>exec</function>,
... ...
@@ -152,7 +155,7 @@
152 152
 		    function.
153 153
 		</para>
154 154
 		<para>
155
-		    The message will be sent out using 
155
+		    The message will be sent out using
156 156
 		    <function>udp_send</function> directly.
157 157
 		</para>
158 158
 	    </listitem>
... ...
@@ -223,6 +226,29 @@
223 223
 	    </listitem>
224 224
 	    <listitem>
225 225
 		<para>
226
+		    <function>setavpflag(avp, flag_id)</function> - Sets a flag in the
227
+		    AVP(s). The command simply set custom flag of AVP. The flags
228
+		    may be used in script using <function>isavpflagset</function>
229
+		    or in a module to perform specific operation on marked AVPs.
230
+		    Flag identifier must be declared via <emphasis>avpflags</emphasis>
231
+		    statement.
232
+		</para>
233
+	    </listitem>
234
+	    <listitem>
235
+		<para>
236
+		    <function>resetavpflag(avp, flag_id)</function> - Same as command
237
+		    <function>setavpflag</function> - only resetavpflag will be
238
+		    called instead of setavpflag.
239
+		</para>
240
+	    </listitem>
241
+	    <listitem>
242
+		<para>
243
+		    <function>isavpflagset(avp, flag_id)</function> - Test if the avp flag
244
+		    is set or not.
245
+		</para>
246
+	    </listitem>
247
+	    <listitem>
248
+		<para>
226 249
 		    <function>error</function> - Log a message with NOTICE log
227 250
 		    level.
228 251
 		</para>
... ...
@@ -1,5 +1,5 @@
1 1
 <?xml version="1.0" encoding="UTF-8"?>
2
-<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" 
2
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
3 3
    "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
4 4
 
5 5
 <section id="reference" xmlns:xi="http://www.w3.org/2001/XInclude">
... ...
@@ -21,9 +21,9 @@
21 21
 	    <itemizedlist>
22 22
 		<listitem>
23 23
 		    <para>
24
-			<varname>debug</varname> - Set log level, this is number between 0 and 9. Default 
24
+			<varname>debug</varname> - Set log level, this is number between 0 and 9. Default
25 25
 			is 0.
26
-			
26
+
27 27
 		    </para>
28 28
 		</listitem>
29 29
 		<listitem>
... ...
@@ -34,10 +34,10 @@
34 34
 			    <para>
35 35
 				Disabling child spawning is useful mainly for
36 36
 				debugging. When <varname>fork</varname> is turned off,
37
-				some features are unavailable: 
37
+				some features are unavailable:
38 38
 				there is no attendant process, no pid file is generated,
39 39
 				and server listens only at one address. Make sure you
40
-				are debugging the same interface at which 
40
+				are debugging the same interface at which
41 41
 				<application>ser</application> listens.
42 42
 				The easiest way to do so is to set the interface using
43 43
 				<varname>listen</varname> option explicitly.
... ...
@@ -47,8 +47,8 @@
47 47
 		</listitem>
48 48
 		<listitem>
49 49
 		    <para>
50
-			<varname>log_stderror</varname> - If set to yes, the server will print its debugging 
51
-			information to standard error output. If set to no, <command>syslog</command> 
50
+			<varname>log_stderror</varname> - If set to yes, the server will print its debugging
51
+			information to standard error output. If set to no, <command>syslog</command>
52 52
 			will be used. Default is no (printing to syslog).
53 53
 		    </para>
54 54
 		</listitem>
... ...
@@ -60,9 +60,9 @@
60 60
 					This parameter may repeat several times, then SER will
61 61
 					listen on all addresses. For example, the following
62 62
 					command-line options (equivalent to "listen" config
63
-					option) may be used: 
63
+					option) may be used:
64 64
 					<command>
65
-						ser -l foo  -l bar -p 5061 -l x -l y 
65
+						ser -l foo  -l bar -p 5061 -l x -l y
66 66
 					</command>
67 67
 					will listen on foo:5060, bar:5061 &amp; x:5061 &amp; y:5061
68 68
 
... ...
@@ -73,7 +73,7 @@
73 73
 		<listitem>
74 74
 		    <para>
75 75
 			<varname>alias</varname> - Add IP addresses or hostnames to list of name aliases.
76
-			All requests with hostname matching an alias will satisfy the condition 
76
+			All requests with hostname matching an alias will satisfy the condition
77 77
 			"uri==myself".
78 78
 		    </para>
79 79
 		</listitem>
... ...
@@ -90,13 +90,13 @@
90 90
 		</listitem>
91 91
 		<listitem>
92 92
 		    <para>
93
-			<varname>port</varname> - Listens on the specified port (default 5060). It applies to the last 
93
+			<varname>port</varname> - Listens on the specified port (default 5060). It applies to the last
94 94
 			address specified in listen and to all the following that do not have a corresponding "port" option.
95 95
 		    </para>
96 96
 		</listitem>
97 97
 		<listitem>
98 98
 		    <para>
99
-			<varname>maxbuffer</varname> - Maximum receive buffer size which will not be exceeded by 
99
+			<varname>maxbuffer</varname> - Maximum receive buffer size which will not be exceeded by
100 100
 			the auto-probing procedure even if the OS allows. Default value is MAX_RECV_BUFFER_SIZE,
101 101
 			which is 256k.
102 102
 		    </para>
... ...
@@ -104,8 +104,8 @@
104 104
 		<listitem>
105 105
 		    <para>
106 106
 			<varname>children</varname> - Specifies how many processes should be started
107
-		        for each transport protocol. 
108
-		    Running multiple children allows a server to 
107
+		        for each transport protocol.
108
+		    Running multiple children allows a server to
109 109
 			server multiple requests in parallel when request processing block (e.g., on DNS
110 110
 			lookup). Note that <application>ser</application> typically spawns additional
111 111
 			processes, such as timer process or FIFO server. If FIFO server is turned on,
... ...
@@ -123,7 +123,7 @@
123 123
 		</listitem>
124 124
 		<listitem>
125 125
 		    <para>
126
-			<varname>syn_branch</varname> - Shall the server use stateful synonym branches? It is faster but not 
126
+			<varname>syn_branch</varname> - Shall the server use stateful synonym branches? It is faster but not
127 127
 			reboot-safe. Default is yes.
128 128
 		    </para>
129 129
 		</listitem>
... ...
@@ -165,12 +165,12 @@
165 165
 			whether they should send reply
166 166
 			to IP advertised in Via.
167 167
 			Turned off by default, which means that replies are
168
-			sent to IP address from which requests came from. 
168
+			sent to IP address from which requests came from.
169 169
 		    </para>
170 170
 		</listitem>
171 171
 		<listitem>
172 172
 		    <para>
173
-			<varname>user | uid</varname> - uid to be used by the server. 
173
+			<varname>user | uid</varname> - uid to be used by the server.
174 174
 		    </para>
175 175
 		</listitem>
176 176
 		<listitem>
... ...
@@ -180,7 +180,7 @@
180 180
 		</listitem>
181 181
 		<listitem>
182 182
 		    <para>
183
-			<varname>mhomed</varname> -- enable calculation of 
183
+			<varname>mhomed</varname> -- enable calculation of
184 184
 			outbound interface; useful on multihomed servers,
185 185
 			see <xref linkend="mhomed"/>.
186 186
 		    </para>
... ...
@@ -227,13 +227,13 @@
227 227
 		<listitem>
228 228
 		    <para>
229 229
 			<command>route[number]{...}</command> - This marks a "route block" in configuration files.
230
-			route blocks are basic building blocks of <application>ser</application> scripts. 
231
-			Each route block contains a sequence of 
230
+			route blocks are basic building blocks of <application>ser</application> scripts.
231
+			Each route block contains a sequence of
232 232
 			<application>SER</application> actions enclosed in braces. Multiple route blocks
233 233
 			can be included in a configuration file.
234
-			When script execution begins on request receipt, 
235
-			route block number 0 is entered. Other route blocks serve as a kind of sub-routines and 
236
-			may be entered by calling the action <command>route(n)</command>, 
234
+			When script execution begins on request receipt,
235
+			route block number 0 is entered. Other route blocks serve as a kind of sub-routines and
236
+			may be entered by calling the action <command>route(n)</command>,
237 237
 			where n is number of the block. The action <command>break</command>
238 238
 			exits currently executed route block. It stops script execution for
239 239
 			route block number 0 or returns to calling route block otherwise.
... ...
@@ -263,7 +263,7 @@ route[2] {
263 263
 			<command>t_relay</command>. When a negative reply
264 264
 			comes back, the desired <command>failure_route</command>
265 265
 			will be entered and processing of the original request may
266
-			continue. 
266
+			continue.
267 267
 			</para>
268 268
 		    <para>
269 269
 			The set of actions applicable from within
... ...
@@ -288,14 +288,14 @@ failure_route[1] {
288 288
 
289 289
 		<listitem>
290 290
 		    <para>
291
-		    	The action <command>break</command> exits currently executed route block. 
292
-			It stops script execution for route block number 0 or returns to calling 
291
+		    	The action <command>break</command> exits currently executed route block.
292
+			It stops script execution for route block number 0 or returns to calling
293 293
 			route block otherwise.
294 294
 			<note>
295 295
 			    <para>
296 296
 				We recommend to use <command>break</command>
297 297
 				after any request forwarding or replying. This practice
298
-				helps to avoid erroneous scripts that 
298
+				helps to avoid erroneous scripts that
299 299
 				continue execution and mistakenly send another reply or
300 300
 				forward a request to another place, resulting in
301 301
 				protocol confusion.
... ...
@@ -376,6 +376,46 @@ if (isflagset(1)) {
376 376
 </programlisting>
377 377
 		    </example>
378 378
 		</listitem>
379
+		<listitem>
380
+		    <para>
381
+			<function>setavpflag(avp, flag_id)</function> - Sets a flag in the
382
+			AVP(s). The command simply set custom flag of AVP. The flags
383
+			may be used in script using <function>isavpflagset</function>
384
+			or in a module to perform specific operation on marked AVPs.
385
+			Flag identifier must be declared via <emphasis>avpflags</emphasis>
386
+			statement.
387
+		    </para>
388
+		    <example>
389
+			<title>setavpflag</title>
390
+			<programlisting>
391
+avpflags
392
+	my_flag,
393
+	your_flag;
394
+....
395
+setavpflag($avp[1], "my_flag");
396
+....
397
+if (isavpflagset($avp2, "your_flag")) {
398
+
399
+}
400
+</programlisting>
401
+		    </example>
402
+		</listitem>
403
+		<listitem>
404
+		    <para>
405
+			<function>resetavpflag(avp, flag_id)</function> - Same as command
406
+			<function>setavpflag</function> - only resetavpflag will be
407
+			called instead of setavpflag.
408
+		    </para>
409
+		</listitem>
410
+		<listitem>
411
+		    <para>
412
+			<function>isavpflagset(avp, flag_id)</function> - Test if the avp flag
413
+			is set or not.
414
+		    </para>
415
+		</listitem>
416
+
417
+
418
+
379 419
 	    </itemizedlist>
380 420
 	    <itemizedlist>
381 421
 		<title>Manipulation of URI and Destination Set</title>
... ...
@@ -476,8 +516,8 @@ sl_send_reply("300", "redirection");
476 476
 		<title>Message Forwarding</title>
477 477
 		<listitem>
478 478
 		    <para>
479
-			<command>forward(uri, port)</command> - Forward the request to given 
480
-			destination statelessly.  The uri and port parameters may take special 
479
+			<command>forward(uri, port)</command> - Forward the request to given
480
+			destination statelessly.  The uri and port parameters may take special
481 481
 			values 'uri:host'
482 482
 			and 'uri:port' respectively, in which case SER forwards to destination
483 483
 			set in current URI. All other elements in a destination set are
... ...
@@ -489,7 +529,7 @@ sl_send_reply("300", "redirection");
489 489
 		</listitem>
490 490
 		<listitem>
491 491
 		    <para>
492
-			<command>send</command> - Send the message as is to a third party 
492
+			<command>send</command> - Send the message as is to a third party
493 493
 		    </para>
494 494
 		    <para>
495 495
 			<emphasis>Example:</emphasis> send("foo.bar.com");
... ...
@@ -498,10 +538,10 @@ sl_send_reply("300", "redirection");
498 498
 	    </itemizedlist>
499 499
 	    <itemizedlist>
500 500
 		<title>Logging</title>
501
-		
501
+
502 502
 
503 503
 		<listitem>
504
-		    
504
+
505 505
 		    <para>
506 506
 			<command>log([level], message)</command> - Log a message.
507 507
 		    </para>
... ...
@@ -530,7 +570,7 @@ sl_send_reply("300", "redirection");
530 530
 		<listitem>
531 531
 		    <para>
532 532
 			<command>len_gt</command> - If length of the message is greater than value given as parameter, the
533
-			command will return 1 (indicating true). Otherwise -1 (indicating false) will be returned. It may 
533
+			command will return 1 (indicating true). Otherwise -1 (indicating false) will be returned. It may
534 534
 			take 'max_len' as parameter, in which case message size is limited
535 535
 			to internal buffer size BUF_SIZE (3040 by default).
536 536
 		    </para>
... ...
@@ -608,25 +648,25 @@ if (len_gt(1024)) {
608 608
 		</listitem>
609 609
 		<listitem>
610 610
 		    <para>
611
-			<emphasis>-l address</emphasis> - Listens on the specified address. Multiple -l mean listening 
611
+			<emphasis>-l address</emphasis> - Listens on the specified address. Multiple -l mean listening
612 612
 			on multiple addresses. The default behavior is to listen on all the ipv4 interfaces.
613 613
 		    </para>
614 614
 		</listitem>
615 615
 		<listitem>
616 616
 		    <para>
617
-			<emphasis>-p port</emphasis> - Listens on the specified port (default 5060). It applies to the last 
617
+			<emphasis>-p port</emphasis> - Listens on the specified port (default 5060). It applies to the last
618 618
 			address specified with -l and to all the following that do not have a corresponding -p.
619 619
 		    </para>
620 620
 		</listitem>
621 621
 		<listitem>
622 622
 		    <para>
623
-			<emphasis>-n processes-no</emphasis> - Specifies the number of children processes forked per 
623
+			<emphasis>-n processes-no</emphasis> - Specifies the number of children processes forked per
624 624
 			interface (default 8).
625 625
 		    </para>
626 626
 		</listitem>
627 627
 		<listitem>
628 628
 		    <para>
629
-			<emphasis>-b max_rcv_buf_size</emphasis> - Maximum receive buffer size which will not be exceeded by 
629
+			<emphasis>-b max_rcv_buf_size</emphasis> - Maximum receive buffer size which will not be exceeded by
630 630
 			the auto-probing procedure even if the OS allows.
631 631
 		    </para>
632 632
 		</listitem>
... ...
@@ -637,7 +677,7 @@ if (len_gt(1024)) {
637 637
 		</listitem>
638 638
 		<listitem>
639 639
 		    <para>
640
-			<emphasis>-w working-dir</emphasis> - Specifies the working directory. In the very improbable event 
640
+			<emphasis>-w working-dir</emphasis> - Specifies the working directory. In the very improbable event
641 641
 			that will crash, the core file will be generated here.
642 642
 		    </para>
643 643
 		</listitem>
... ...
@@ -770,7 +810,7 @@ if (len_gt(1024)) {
770 770
 		    <listitem>
771 771
 			<para>
772 772
 			    <emphasis>
773
-					nathelper	
773
+					nathelper
774 774
 			    </emphasis>
775 775
 			    -- facilitates NAT traversal for symmetric SIP phones such as ATA.
776 776
 			    </para>
... ...
@@ -823,8 +863,8 @@ if (len_gt(1024)) {
823 823
 				<emphasis>textops</emphasis> -- textual database back-end.
824 824
 			</para>
825 825
 			</listitem>
826
-				
827
-		    <listitem>			
826
+
827
+		    <listitem>
828 828
 			<para>
829 829
 			    <emphasis>
830 830
 				tm
... ...
@@ -833,7 +873,7 @@ if (len_gt(1024)) {
833 833
 			</para>
834 834
 		    </listitem>
835 835
 
836
-		    <listitem>			
836
+		    <listitem>
837 837
 			<para>
838 838
 			    <emphasis>
839 839
 				uri, uri_radius
... ...
@@ -846,7 +886,7 @@ if (len_gt(1024)) {
846 846
 	    </para>
847 847
 	    <para>
848 848
 		The most frequently used actions exported by modules are summarized
849
-		in <xref linkend="moduleactions"/>. For a full explanation of 
849
+		in <xref linkend="moduleactions"/>. For a full explanation of
850 850
 		module actions, see documentation in respective module directories
851 851
 		in source distribution of <application>ser</application>.
852 852
 	    </para>
... ...
@@ -854,7 +894,7 @@ if (len_gt(1024)) {
854 854
 		<title>Frequently Used Module Actions</title>
855 855
 		<tgroup cols="4">
856 856
 		    <thead>
857
-			<row>			    
857
+			<row>
858 858
 			    <entry>
859 859
 				Command
860 860
 			    </entry>
... ...
@@ -1081,7 +1121,7 @@ if (len_gt(1024)) {
1081 1081
 				RegExp, Substitute
1082 1082
 			    </entry>
1083 1083
 			    <entry>
1084
-				find the first occurrence of a string matching the regular 
1084
+				find the first occurrence of a string matching the regular
1085 1085
 				expression in header or body and replace it with a substitute
1086 1086
 			    </entry>
1087 1087
 			</row>
... ...
@@ -1096,7 +1136,7 @@ if (len_gt(1024)) {
1096 1096
 				RegExp, Substitute
1097 1097
 			    </entry>
1098 1098
 			    <entry>
1099
-				find all occurrences of a string matching the regular 
1099
+				find all occurrences of a string matching the regular
1100 1100
 				expression in header or body and replace it with a substitute
1101 1101
 			    </entry>
1102 1102
 			</row>
... ...
@@ -1210,7 +1250,7 @@ if (len_gt(1024)) {
1210 1210
 		is restarted.
1211 1211
 	    </para>
1212 1212
 	    <table>
1213
-		
1213
+
1214 1214
 		<title>FIFO Commands</title>
1215 1215
 		<tgroup cols="4">
1216 1216
 		    <thead>
... ...
@@ -1223,7 +1263,7 @@ if (len_gt(1024)) {
1223 1223
 			    </entry>
1224 1224
 			    <entry>
1225 1225
 				Parameters
1226
-			    </entry>			    
1226
+			    </entry>
1227 1227
 			    <entry>
1228 1228
 				Comments
1229 1229
 			    </entry>
... ...
@@ -1255,7 +1295,7 @@ if (len_gt(1024)) {
1255 1255
 			    <entry>arg</entry>
1256 1256
 			    <entry>core</entry>
1257 1257
 			    <entry>none</entry>
1258
-			    <entry>prints list of command-line arguments with which 
1258
+			    <entry>prints list of command-line arguments with which
1259 1259
 				<application>ser</application> was started</entry>
1260 1260
 			</row>
1261 1261
 			<row>
... ...
@@ -1300,9 +1340,9 @@ if (len_gt(1024)) {
1300 1300
 			    <entry>tm</entry>
1301 1301
 			    <entry>method, request URI, outbound URI (if none, empty line with a single dot),
1302 1302
 					dot-line-terminated header fields, optionally dot-line terminated message
1303
-					body. 
1303
+					body.
1304 1304
 				</entry>
1305
-					
1305
+
1306 1306
 			    <entry>initiate a transaction.
1307 1307
 					From and To header fields must be present in header field list,
1308 1308
 					so does Content-Type if body is present. If CSeq, CallId and From-tag
... ...
@@ -1463,7 +1503,7 @@ if (len_gt(1024)) {
1463 1463
 
1464 1464
 		    <listitem>
1465 1465
 			<para>
1466
-			    server_monitoring-* -- reserved for persistent monitoring of 
1466
+			    server_monitoring-* -- reserved for persistent monitoring of
1467 1467
 				server's operation
1468 1468
 			</para>
1469 1469
 		    </listitem>
... ...
@@ -1478,7 +1518,7 @@ if (len_gt(1024)) {
1478 1478
 
1479 1479
 
1480 1480
 		</itemizedlist>
1481
-		
1481
+
1482 1482
 	    </para>
1483 1483
 	</section>
1484 1484
 </section>
... ...
@@ -322,6 +322,9 @@ void print_action(struct action* t)
322 322
 		case ISFLAGSET_T:
323 323
 			DBG("isflagset(");
324 324
 			break;
325
+		case AVPFLAG_OPER_T:
326
+			DBG("avpflagoper(");
327
+			break;
325 328
 		case SET_HOST_T:
326 329
 			DBG("sethost(");
327 330
 			break;
... ...
@@ -71,6 +71,7 @@ enum { FORWARD_T=1, SEND_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T,
71 71
 		SET_HOST_T, SET_HOSTPORT_T, SET_USER_T, SET_USERPASS_T,
72 72
 		SET_PORT_T, SET_URI_T, IF_T, MODULE_T,
73 73
 		SETFLAG_T, RESETFLAG_T, ISFLAGSET_T ,
74
+		AVPFLAG_OPER_T,
74 75
 		LEN_GT_T, PREFIX_T, STRIP_T,STRIP_TAIL_T,
75 76
 		APPEND_BRANCH_T,
76 77
 		REVERT_URI_T,
... ...
@@ -20,8 +20,8 @@
20 20
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 21
  * GNU General Public License for more details.
22 22
  *
23
- * You should have received a copy of the GNU General Public License 
24
- * along with this program; if not, write to the Free Software 
23
+ * You should have received a copy of the GNU General Public License
24
+ * along with this program; if not, write to the Free Software
25 25
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 26
  *
27 27
  * History:
... ...
@@ -39,6 +39,8 @@
39 39
 #include <string.h>
40 40
 #include <stdlib.h>
41 41
 
42
+#include <stdio.h>
43
+
42 44
 #include "sr_module.h"
43 45
 #include "dprint.h"
44 46
 #include "str.h"
... ...
@@ -71,6 +73,9 @@ static avp_list_t* crt_list[IDX_MAX];  /* Pointer to current AVP lists */
71 71
 static avp_list_t* def_glist;
72 72
 static avp_list_t** crt_glist;
73 73
 
74
+/* AVP flags */
75
+int registered_avpflags_no = 0;
76
+static char *registered_avpflags[MAX_AVPFLAG];
74 77
 
75 78
 /* Initialize AVP lists in private memory and allocate memory
76 79
  * for shared lists
... ...
@@ -80,7 +85,7 @@ int init_avps(void)
80 80
 	int i;
81 81
 	     /* Empty default lists */
82 82
 	memset(def_list, 0, sizeof(avp_list_t) * IDX_MAX);
83
-	
83
+
84 84
 	     /* Point current pointers to default lists */
85 85
 	for(i = 0; i < IDX_MAX; i++) {
86 86
 		crt_list[i] = &def_list[i];
... ...
@@ -144,7 +149,7 @@ avp_t *create_avp (avp_flags_t flags, avp_name_t name, avp_value_t val)
144 144
 		LOG(L_ERR,"ERROR:avp:add_avp: 0 ID or NULL NAME AVP!");
145 145
 		goto error;
146 146
 	}
147
-	
147
+
148 148
 	/* compute the required mem size */
149 149
 	len = sizeof(struct usr_avp);
150 150
 	if (flags&AVP_NAME_STR) {
... ...
@@ -153,11 +158,11 @@ avp_t *create_avp (avp_flags_t flags, avp_name_t name, avp_value_t val)
153 153
 			goto error;
154 154
 		}
155 155
 		if (flags&AVP_VAL_STR) {
156
-			len += sizeof(struct str_str_data)-sizeof(void*) 
156
+			len += sizeof(struct str_str_data)-sizeof(void*)
157 157
 				+ name.s.len + 1 /* Terminating zero for regex search */
158 158
 				+ val.s.len + 1; /* Value is zero terminated */
159 159
 		} else {
160
-			len += sizeof(struct str_int_data)-sizeof(void*) 
160
+			len += sizeof(struct str_int_data)-sizeof(void*)
161 161
 				+ name.s.len + 1; /* Terminating zero for regex search */
162 162
 		}
163 163
 	} else if (flags&AVP_VAL_STR) {
... ...
@@ -226,7 +231,7 @@ int add_avp_list(avp_list_t* list, avp_flags_t flags, avp_name_t name, avp_value
226 226
 		*list = avp;
227 227
 		return 0;
228 228
 	}
229
-	
229
+
230 230
 	return -1;
231 231
 }
232 232
 
... ...
@@ -256,14 +261,14 @@ int add_avp(avp_flags_t flags, avp_name_t name, avp_value_t val)
256 256
 int add_avp_before(avp_t *avp, avp_flags_t flags, avp_name_t name, avp_value_t val)
257 257
 {
258 258
 	avp_t *new_avp;
259
-	
259
+
260 260
 	if (!avp) {
261 261
 		return add_avp(flags, name, val);
262 262
 	}
263 263
 
264 264
 	if ((flags & AVP_CLASS_ALL) == 0) flags |= (avp->flags & AVP_CLASS_ALL);
265 265
 	if ((flags & AVP_TRACK_ALL) == 0) flags |= (avp->flags & AVP_TRACK_ALL);
266
-	
266
+
267 267
 	if ((avp->flags & (AVP_CLASS_ALL|AVP_TRACK_ALL)) != (flags & (AVP_CLASS_ALL|AVP_TRACK_ALL))) {
268 268
 		ERR("add_avp_before:Source and target AVPs have different CLASS/TRACK\n");
269 269
 		return -1;
... ...
@@ -400,7 +405,7 @@ avp_t *search_avp (avp_ident_t ident, avp_value_t* val, struct search_state* sta
400 400
 		LOG(L_ERR,"ERROR:avp:search_first_avp: 0 ID or NULL NAME AVP!");
401 401
 		return 0;
402 402
 	}
403
-	
403
+
404 404
 	switch (ident.flags & AVP_INDEX_ALL) {
405 405
 		case AVP_INDEX_BACKWARD:
406 406
 		case AVP_INDEX_FORWARD:
... ...
@@ -415,7 +420,7 @@ avp_t *search_avp (avp_ident_t ident, avp_value_t* val, struct search_state* sta
415 415
 		      * all of them by default
416 416
 		      */
417 417
 		ident.flags |= AVP_CLASS_ALL;
418
-		
418
+
419 419
 		if ((ident.flags & AVP_TRACK_ALL) == 0) {
420 420
 		    /* The caller did not specify even the track to search in, so search
421 421
 		     * in the track_from
... ...
@@ -496,7 +501,7 @@ int search_reverse( avp_t *cur, struct search_state* st,
496 496
                      avp_index_t index, avp_list_t *ret)
497 497
 {
498 498
 	avp_index_t lvl;
499
-	
499
+
500 500
 	if (!cur)
501 501
 		return 0;
502 502
 	lvl = search_reverse(search_next_avp(st, NULL), st, index, ret)+1;
... ...
@@ -504,13 +509,13 @@ int search_reverse( avp_t *cur, struct search_state* st,
504 504
 		*ret=cur;
505 505
 	return lvl;
506 506
 }
507
-                            
507
+
508 508
 avp_t *search_avp_by_index( avp_flags_t flags, avp_name_t name,
509
-                            avp_value_t *val, avp_index_t index) 	
509
+                            avp_value_t *val, avp_index_t index)
510 510
 {
511 511
 	avp_t *ret, *cur;
512 512
 	struct search_state st;
513
-	
513
+
514 514
 	if (flags & AVP_NAME_RE) {
515 515
 		BUG("search_by_index not supported for AVP_NAME_RE\n");
516 516
 		return 0;
... ...
@@ -537,9 +542,9 @@ avp_t *search_avp_by_index( avp_flags_t flags, avp_name_t name,
537 537
 			for (index--; (ret && index); ret=search_next_avp(&st, val), index--);
538 538
 			return ret;
539 539
 	}
540
-		
540
+
541 541
 	return 0;
542
-}                            
542
+}
543 543
 
544 544
 /* FIXME */
545 545
 /********* free functions ********/
... ...
@@ -550,7 +555,7 @@ void destroy_avp(avp_t *avp_del)
550 550
 	avp_t *avp, *avp_prev;
551 551
 
552 552
 	for (i = 0; i < IDX_MAX; i++) {
553
-		for( avp_prev=0,avp=*crt_list[i] ; avp ; 
553
+		for( avp_prev=0,avp=*crt_list[i] ; avp ;
554 554
 		     avp_prev=avp,avp=avp->next ) {
555 555
 			if (avp==avp_del) {
556 556
 				if (avp_prev) {
... ...
@@ -564,7 +569,7 @@ void destroy_avp(avp_t *avp_del)
564 564
 		}
565 565
 	}
566 566
 
567
-	for( avp_prev=0,avp=**crt_glist ; avp ; 
567
+	for( avp_prev=0,avp=**crt_glist ; avp ;
568 568
 	     avp_prev=avp,avp=avp->next ) {
569 569
 		if (avp==avp_del) {
570 570
 			if (avp_prev) {
... ...
@@ -766,7 +771,7 @@ int parse_avp_name( str *name, int *type, int_str *avp_name, int *index)
766 766
 {
767 767
 	int ret;
768 768
 	avp_ident_t attr;
769
-	
769
+
770 770
 	ret=parse_avp_ident(name, &attr);
771 771
 	if (!ret) {
772 772
 		if (type) *type = attr.flags;
... ...
@@ -866,7 +871,7 @@ int parse_avp_ident( str *name, avp_ident_t* attr)
866 866
 			p=memchr(name->s, '[', name->len);
867 867
 			if (!p) {
868 868
 				ERR("missing '[' for AVP index\n");
869
-				goto error; 
869
+				goto error;
870 870
 			}
871 871
 			s.s=p+1;
872 872
 			s.len=name->len-(p-name->s)-2; // [ and ]
... ...
@@ -878,7 +883,7 @@ int parse_avp_ident( str *name, avp_ident_t* attr)
878 878
 					s.s++;s.len--;
879 879
 				} else {
880 880
 					attr->flags |= AVP_INDEX_FORWARD;
881
-				}	
881
+				}
882 882
 				if ((str2int(&s, &id) != 0)||(id==0)) {
883 883
 					ERR("Invalid AVP index '%.*s'\n", s.len, s.s);
884 884
 					goto error;
... ...
@@ -956,7 +961,7 @@ int add_avp_galias_str(char *alias_definition)
956 956
 	str  alias;
957 957
 	int  type;
958 958
 	int  index;
959
-	
959
+
960 960
 	s = alias_definition;
961 961
 	while(*s && isspace((int)*s))
962 962
 		s++;
... ...
@@ -1027,3 +1032,26 @@ void delete_avp(avp_flags_t flags, avp_name_t name)
1027 1027
 		avp = search_next_avp(&st, 0);
1028 1028
 	}
1029 1029
 }
1030
+
1031
+/* AVP flags functions */
1032
+
1033
+/* name2id conversion is intended to use during fixup (cfg parsing and modinit) only therefore no hash is used */
1034
+avp_flags_t register_avpflag(char* name) {
1035
+	avp_flags_t ret;
1036
+	ret = get_avpflag_no(name);
1037
+	if (ret == 0) {
1038
+		if (registered_avpflags_no >= MAX_AVPFLAG) return -1;
1039
+		ret = 1<<(AVP_CUSTOM_FLAGS+registered_avpflags_no);
1040
+		registered_avpflags[registered_avpflags_no++] = name;
1041
+	}
1042
+	return ret;
1043
+}
1044
+
1045
+avp_flags_t get_avpflag_no(char* name) {
1046
+	int i;
1047
+	for (i=0; i<registered_avpflags_no; i++) {
1048
+		if (strcasecmp(name, registered_avpflags[i])==0)
1049
+			return 1<<(AVP_CUSTOM_FLAGS+i);
1050
+	}
1051
+	return 0;
1052
+}
... ...
@@ -147,10 +147,11 @@ typedef struct avp_spec {
147 147
 #define AVP_INDEX_BACKWARD	(1<<11)
148 148
 #define AVP_INDEX_ALL		(AVP_INDEX_FORWARD | AVP_INDEX_BACKWARD)
149 149
 
150
-#define AVP_FLAG_DIALOG         (1<<12)
150
+#define AVP_CUSTOM_FLAGS	12
151 151
 
152 152
 #define GALIAS_CHAR_MARKER  '$'
153 153
 
154
+#define AVP_IS_ASSIGNABLE(ident) ( ((ident).flags & AVP_NAME_RE) == 0 && (((ident).flags & AVP_NAME) == 0 || (((ident)->flags & AVP_NAME) && (ident).name.s.len)) )
154 155
 /* Initialize memory structures */
155 156
 int init_avps(void);
156 157
 
... ...
@@ -196,4 +197,10 @@ int parse_avp_name( str *name, int *type, int_str *avp_name, int *index);
196 196
 int parse_avp_spec( str *name, int *type, int_str *avp_name, int *index);
197 197
 void free_avp_name( int *type, int_str *avp_name);
198 198
 
199
+/* AVP flags functions */
200
+#define MAX_AVPFLAG  ((unsigned int)( sizeof(avp_flags_t) * CHAR_BIT - 1 - AVP_CUSTOM_FLAGS))
201
+
202
+avp_flags_t register_avpflag(char* name);
203
+avp_flags_t get_avpflag_no(char* name);
204
+
199 205
 #endif