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 340
 <INITIAL>{RESETFLAG}	{ count(); yylval.strval=yytext; return RESETFLAG; }
337 341
 <INITIAL>{ISFLAGSET}	{ count(); yylval.strval=yytext; return ISFLAGSET; }
338 342
 <INITIAL>{FLAGS_DECL}	{ count(); yylval.strval=yytext; return FLAGS_DECL; }
343
+<INITIAL>{SETAVPFLAG}	{ count(); yylval.strval=yytext; return SETAVPFLAG; }
344
+<INITIAL>{RESETAVPFLAG}	{ count(); yylval.strval=yytext; return RESETAVPFLAG; }
345
+<INITIAL>{ISAVPFLAGSET}	{ count(); yylval.strval=yytext; return ISAVPFLAGSET; }
346
+<INITIAL>{AVPFLAGS_DECL}	{ count(); yylval.strval=yytext; return AVPFLAGS_DECL; }
339 347
 <INITIAL>{MSGLEN}	{ count(); yylval.strval=yytext; return MSGLEN; }
340 348
 <INITIAL>{RETCODE}	{ count(); yylval.strval=yytext; return RETCODE; }
341 349
 <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 194
 %token SETFLAG
194 195
 %token RESETFLAG
195 196
 %token ISFLAGSET
197
+%token SETAVPFLAG
198
+%token RESETAVPFLAG
199
+%token ISAVPFLAGSET
196 200
 %token METHOD
197 201
 %token URI
198 202
 %token FROM_URI
... ...
@@ -280,6 +284,7 @@ static struct socket_id* mk_listen_id(char*, int, int);
280 284
 %token TOS
281 285
 
282 286
 %token FLAGS_DECL
287
+%token AVPFLAGS_DECL
283 288
 
284 289
 %token ATTR_MARK
285 290
 %token SELECT_MARK
... ...
@@ -349,11 +354,13 @@ static struct socket_id* mk_listen_id(char*, int, int);
349 354
 %type <attr> attr_id_ass
350 355
 %type <attr> attr_id_val
351 356
 %type <attr> attr_id_any
357
+%type <attr> attr_id_any_str
352 358
 /* %type <intval> class_id */
353 359
 %type <intval> assign_op
354 360
 %type <select> select_id
355 361
 %type <strval>	flag_name;
356 362
 %type <strval>	route_name;
363
+%type <intval> avpflag_oper
357 364
 
358 365
 /*%type <route_el> rules;
359 366
   %type <route_el> rule;
... ...
@@ -373,6 +380,7 @@ statements:
373 380
 statement:
374 381
 	assign_stm
375 382
 	| flags_decl
383
+	| avpflags_decl
376 384
 	| module_stm
377 385
 	| {rt=REQUEST_ROUTE;} route_stm
378 386
 	| {rt=FAILURE_ROUTE;} failure_route_stm
... ...
@@ -460,6 +468,20 @@ flag_name:		STRING	{ $$=$1; }
460 468
 			|	ID		{ $$=$1; }
461 469
 ;
462 470
 
471
+avpflags_decl:
472
+	AVPFLAGS_DECL avpflag_list
473
+	| AVPFLAGS_DECL error { yyerror("avpflag list expected\n"); }
474
+	;
475
+avpflag_list:
476
+	avpflag_spec
477
+	| avpflag_spec COMMA avpflag_list
478
+	;
479
+avpflag_spec:
480
+	flag_name {
481
+		if (register_avpflag($1)==0)
482
+			yyerror("cannot declare avpflag");
483
+	}
484
+	;
463 485
 assign_stm:
464 486
 	DEBUG_V EQUAL NUMBER { debug=$3; }
465 487
 	| DEBUG_V EQUAL error  { yyerror("number  expected"); }
... ...
@@ -891,7 +913,7 @@ route_stm:
891 913
 	| ROUTE error { yyerror("invalid  route  statement"); }
892 914
 	;
893 915
 failure_route_stm:
894
-	ROUTE_FAILURE LBRACE actions RBRACE { 
916
+	ROUTE_FAILURE LBRACE actions RBRACE {
895 917
 									push($3, &failure_rt.rlist[DEFAULT_RT]);
896 918
 										}
897 919
 	| ROUTE_FAILURE LBRACK route_name RBRACK LBRACE actions RBRACE {
... ...
@@ -927,7 +949,7 @@ onreply_route_stm:
927 949
 	| ROUTE_ONREPLY error { yyerror("invalid onreply_route statement"); }
928 950
 	;
929 951
 branch_route_stm:
930
-	ROUTE_BRANCH LBRACE actions RBRACE { 
952
+	ROUTE_BRANCH LBRACE actions RBRACE {
931 953
 									push($3, &branch_rt.rlist[DEFAULT_RT]);
932 954
 										}
933 955
 	| ROUTE_BRANCH LBRACK route_name RBRACK LBRACE actions RBRACE {
... ...
@@ -1404,6 +1426,29 @@ attr_id_any:
1404 1426
 	| attr_id_no_idx
1405 1427
 	| attr_id_num_idx
1406 1428
 ;
1429
+attr_id_any_str:
1430
+	attr_id
1431
+	| STRING {
1432
+		avp_spec_t *avp_spec;
1433
+		str s;
1434
+		int type, idx;
1435
+		avp_spec = pkg_malloc(sizeof(*avp_spec));
1436
+		if (!avp_spec) {
1437
+			yyerror("Not enough memory");
1438
+			YYABORT;
1439
+		}
1440
+		s.s = $1+1; /* skip $ */
1441
+		s.len = strlen(s.s);
1442
+		if (parse_avp_name(&s, &type, &avp_spec->name, &idx)) {
1443
+			yyerror("error when parsing AVP");
1444
+		        pkg_free(avp_spec);
1445
+			YYABORT;
1446
+		}
1447
+		avp_spec->type = type;
1448
+		avp_spec->index = idx;
1449
+		$$ = avp_spec;
1450
+	}
1451
+	;
1407 1452
 /*
1408 1453
 assign_op:
1409 1454
 	ADDEQ { $$ = ADD_T; }
... ...
@@ -1421,6 +1466,11 @@ assign_action:
1421 1466
 	| attr_id_ass assign_op select_id { $$=mk_action($2, 2, AVP_ST, (void*)$1, SELECT_ST, (void*)$3); }
1422 1467
 	| attr_id_ass assign_op LPAREN exp RPAREN { $$ = mk_action($2, 2, AVP_ST, $1, EXPR_ST, $4); }
1423 1468
 	;
1469
+avpflag_oper:
1470
+	SETAVPFLAG { $$ = 1; }
1471
+	| RESETAVPFLAG { $$ = 0; }
1472
+	| ISAVPFLAGSET { $$ = -1; }
1473
+	;
1424 1474
 cmd:
1425 1475
 	FORWARD LPAREN host RPAREN	{ $$=mk_action(	FORWARD_T, 2, STRING_ST, $3, NUMBER_ST, 0); }
1426 1476
 	| FORWARD LPAREN STRING RPAREN	{ $$=mk_action(	FORWARD_T, 2, STRING_ST, $3, NUMBER_ST, 0); }
... ...
@@ -1568,7 +1618,7 @@ cmd:
1568 1618
 							i_tmp=get_flag_no($3, strlen($3));
1569 1619
 							if (i_tmp<0) yyerror("flag not declared");
1570 1620
 							$$=mk_action(SETFLAG_T, 1, NUMBER_ST,
1571
-										(void*)(long)i_tmp); 
1621
+										(void*)(long)i_tmp);
1572 1622
 									}
1573 1623
 	| SETFLAG error			{ $$=0; yyerror("missing '(' or ')'?"); }
1574 1624
 	| RESETFLAG LPAREN NUMBER RPAREN {
... ...
@@ -1580,7 +1630,7 @@ cmd:
1580 1630
 							i_tmp=get_flag_no($3, strlen($3));
1581 1631
 							if (i_tmp<0) yyerror("flag not declared");
1582 1632
 							$$=mk_action(RESETFLAG_T, 1, NUMBER_ST,
1583
-										(void*)(long)i_tmp); 
1633
+										(void*)(long)i_tmp);
1584 1634
 									}
1585 1635
 	| RESETFLAG error		{ $$=0; yyerror("missing '(' or ')'?"); }
1586 1636
 	| ISFLAGSET LPAREN NUMBER RPAREN {
... ...
@@ -1592,13 +1642,19 @@ cmd:
1592 1642
 							i_tmp=get_flag_no($3, strlen($3));
1593 1643
 							if (i_tmp<0) yyerror("flag not declared");
1594 1644
 							$$=mk_action(ISFLAGSET_T, 1, NUMBER_ST,
1595
-										(void*)(long)i_tmp); 
1645
+										(void*)(long)i_tmp);
1596 1646
 									}
1597 1647
 	| ISFLAGSET error { $$=0; yyerror("missing '(' or ')'?"); }
1648
+	| avpflag_oper LPAREN attr_id_any_str COMMA flag_name RPAREN {
1649
+		i_tmp=get_avpflag_no($5);
1650
+		if (i_tmp==0) yyerror("avpflag not declared");
1651
+		$$=mk_action(AVPFLAG_OPER_T, 3, AVP_ST, $3, NUMBER_ST, (void*)(long)i_tmp, NUMBER_ST, (void*)$1);
1652
+	}
1653
+	| avpflag_oper error { $$=0; yyerror("missing '(' or ')'?"); }
1598 1654
 	| ERROR LPAREN STRING COMMA STRING RPAREN {$$=mk_action(ERROR_T, 2, STRING_ST, $3, STRING_ST, $5); }
1599 1655
 	| ERROR error { $$=0; yyerror("missing '(' or ')' ?"); }
1600 1656
 	| ERROR LPAREN error RPAREN { $$=0; yyerror("bad error argument"); }
1601
-	| ROUTE LPAREN route_name RPAREN	{ 
1657
+	| ROUTE LPAREN route_name RPAREN	{
1602 1658
 						i_tmp=route_get(&main_rt, $3);
1603 1659
 						if (i_tmp==-1){
1604 1660
 							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 155
 		    function.
153 156
 		</para>
154 157
 		<para>
155
-		    The message will be sent out using 
158
+		    The message will be sent out using
156 159
 		    <function>udp_send</function> directly.
157 160
 		</para>
158 161
 	    </listitem>
... ...
@@ -221,6 +224,29 @@
221 224
 		    is set or not.
222 225
 		</para>
223 226
 	    </listitem>
227
+	    <listitem>
228
+		<para>
229
+		    <function>setavpflag(avp, flag_id)</function> - Sets a flag in the
230
+		    AVP(s). The command simply set custom flag of AVP. The flags
231
+		    may be used in script using <function>isavpflagset</function>
232
+		    or in a module to perform specific operation on marked AVPs.
233
+		    Flag identifier must be declared via <emphasis>avpflags</emphasis>
234
+		    statement.
235
+		</para>
236
+	    </listitem>
237
+	    <listitem>
238
+		<para>
239
+		    <function>resetavpflag(avp, flag_id)</function> - Same as command
240
+		    <function>setavpflag</function> - only resetavpflag will be
241
+		    called instead of setavpflag.
242
+		</para>
243
+	    </listitem>
244
+	    <listitem>
245
+		<para>
246
+		    <function>isavpflagset(avp, flag_id)</function> - Test if the avp flag
247
+		    is set or not.
248
+		</para>
249
+	    </listitem>
224 250
 	    <listitem>
225 251
 		<para>
226 252
 		    <function>error</function> - Log a message with NOTICE log
... ...
@@ -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 516
 		<title>Message Forwarding</title>
477 517
 		<listitem>
478 518
 		    <para>
479
-			<command>forward(uri, port)</command> - Forward the request to given 
480
-			destination statelessly.  The uri and port parameters may take special 
519
+			<command>forward(uri, port)</command> - Forward the request to given
520
+			destination statelessly.  The uri and port parameters may take special
481 521
 			values 'uri:host'
482 522
 			and 'uri:port' respectively, in which case SER forwards to destination
483 523
 			set in current URI. All other elements in a destination set are
... ...
@@ -489,7 +529,7 @@ sl_send_reply("300", "redirection");
489 529
 		</listitem>
490 530
 		<listitem>
491 531
 		    <para>
492
-			<command>send</command> - Send the message as is to a third party 
532
+			<command>send</command> - Send the message as is to a third party
493 533
 		    </para>
494 534
 		    <para>
495 535
 			<emphasis>Example:</emphasis> send("foo.bar.com");
... ...
@@ -498,10 +538,10 @@ sl_send_reply("300", "redirection");
498 538
 	    </itemizedlist>
499 539
 	    <itemizedlist>
500 540
 		<title>Logging</title>
501
-		
541
+
502 542
 
503 543
 		<listitem>
504
-		    
544
+
505 545
 		    <para>
506 546
 			<command>log([level], message)</command> - Log a message.
507 547
 		    </para>
... ...
@@ -530,7 +570,7 @@ sl_send_reply("300", "redirection");
530 570
 		<listitem>
531 571
 		    <para>
532 572
 			<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 
573
+			command will return 1 (indicating true). Otherwise -1 (indicating false) will be returned. It may
534 574
 			take 'max_len' as parameter, in which case message size is limited
535 575
 			to internal buffer size BUF_SIZE (3040 by default).
536 576
 		    </para>
... ...
@@ -608,25 +648,25 @@ if (len_gt(1024)) {
608 648
 		</listitem>
609 649
 		<listitem>
610 650
 		    <para>
611
-			<emphasis>-l address</emphasis> - Listens on the specified address. Multiple -l mean listening 
651
+			<emphasis>-l address</emphasis> - Listens on the specified address. Multiple -l mean listening
612 652
 			on multiple addresses. The default behavior is to listen on all the ipv4 interfaces.
613 653
 		    </para>
614 654
 		</listitem>
615 655
 		<listitem>
616 656
 		    <para>
617
-			<emphasis>-p port</emphasis> - Listens on the specified port (default 5060). It applies to the last 
657
+			<emphasis>-p port</emphasis> - Listens on the specified port (default 5060). It applies to the last
618 658
 			address specified with -l and to all the following that do not have a corresponding -p.
619 659
 		    </para>
620 660
 		</listitem>
621 661
 		<listitem>
622 662
 		    <para>
623
-			<emphasis>-n processes-no</emphasis> - Specifies the number of children processes forked per 
663
+			<emphasis>-n processes-no</emphasis> - Specifies the number of children processes forked per
624 664
 			interface (default 8).
625 665
 		    </para>
626 666
 		</listitem>
627 667
 		<listitem>
628 668
 		    <para>
629
-			<emphasis>-b max_rcv_buf_size</emphasis> - Maximum receive buffer size which will not be exceeded by 
669
+			<emphasis>-b max_rcv_buf_size</emphasis> - Maximum receive buffer size which will not be exceeded by
630 670
 			the auto-probing procedure even if the OS allows.
631 671
 		    </para>
632 672
 		</listitem>
... ...
@@ -637,7 +677,7 @@ if (len_gt(1024)) {
637 677
 		</listitem>
638 678
 		<listitem>
639 679
 		    <para>
640
-			<emphasis>-w working-dir</emphasis> - Specifies the working directory. In the very improbable event 
680
+			<emphasis>-w working-dir</emphasis> - Specifies the working directory. In the very improbable event
641 681
 			that will crash, the core file will be generated here.
642 682
 		    </para>
643 683
 		</listitem>
... ...
@@ -770,7 +810,7 @@ if (len_gt(1024)) {
770 810
 		    <listitem>
771 811
 			<para>
772 812
 			    <emphasis>
773
-					nathelper	
813
+					nathelper
774 814
 			    </emphasis>
775 815
 			    -- facilitates NAT traversal for symmetric SIP phones such as ATA.
776 816
 			    </para>
... ...
@@ -823,8 +863,8 @@ if (len_gt(1024)) {
823 863
 				<emphasis>textops</emphasis> -- textual database back-end.
824 864
 			</para>
825 865
 			</listitem>
826
-				
827
-		    <listitem>			
866
+
867
+		    <listitem>
828 868
 			<para>
829 869
 			    <emphasis>
830 870
 				tm
... ...
@@ -833,7 +873,7 @@ if (len_gt(1024)) {
833 873
 			</para>
834 874
 		    </listitem>
835 875
 
836
-		    <listitem>			
876
+		    <listitem>
837 877
 			<para>
838 878
 			    <emphasis>
839 879
 				uri, uri_radius
... ...
@@ -846,7 +886,7 @@ if (len_gt(1024)) {
846 886
 	    </para>
847 887
 	    <para>
848 888
 		The most frequently used actions exported by modules are summarized
849
-		in <xref linkend="moduleactions"/>. For a full explanation of 
889
+		in <xref linkend="moduleactions"/>. For a full explanation of
850 890
 		module actions, see documentation in respective module directories
851 891
 		in source distribution of <application>ser</application>.
852 892
 	    </para>
... ...
@@ -854,7 +894,7 @@ if (len_gt(1024)) {
854 894
 		<title>Frequently Used Module Actions</title>
855 895
 		<tgroup cols="4">
856 896
 		    <thead>
857
-			<row>			    
897
+			<row>
858 898
 			    <entry>
859 899
 				Command
860 900
 			    </entry>
... ...
@@ -1081,7 +1121,7 @@ if (len_gt(1024)) {
1081 1121
 				RegExp, Substitute
1082 1122
 			    </entry>
1083 1123
 			    <entry>
1084
-				find the first occurrence of a string matching the regular 
1124
+				find the first occurrence of a string matching the regular
1085 1125
 				expression in header or body and replace it with a substitute
1086 1126
 			    </entry>
1087 1127
 			</row>
... ...
@@ -1096,7 +1136,7 @@ if (len_gt(1024)) {
1096 1136
 				RegExp, Substitute
1097 1137
 			    </entry>
1098 1138
 			    <entry>
1099
-				find all occurrences of a string matching the regular 
1139
+				find all occurrences of a string matching the regular
1100 1140
 				expression in header or body and replace it with a substitute
1101 1141
 			    </entry>
1102 1142
 			</row>
... ...
@@ -1210,7 +1250,7 @@ if (len_gt(1024)) {
1210 1250
 		is restarted.
1211 1251
 	    </para>
1212 1252
 	    <table>
1213
-		
1253
+
1214 1254
 		<title>FIFO Commands</title>
1215 1255
 		<tgroup cols="4">
1216 1256
 		    <thead>
... ...
@@ -1223,7 +1263,7 @@ if (len_gt(1024)) {
1223 1263
 			    </entry>
1224 1264
 			    <entry>
1225 1265
 				Parameters
1226
-			    </entry>			    
1266
+			    </entry>
1227 1267
 			    <entry>
1228 1268
 				Comments
1229 1269
 			    </entry>
... ...
@@ -1255,7 +1295,7 @@ if (len_gt(1024)) {
1255 1295
 			    <entry>arg</entry>
1256 1296
 			    <entry>core</entry>
1257 1297
 			    <entry>none</entry>
1258
-			    <entry>prints list of command-line arguments with which 
1298
+			    <entry>prints list of command-line arguments with which
1259 1299
 				<application>ser</application> was started</entry>
1260 1300
 			</row>
1261 1301
 			<row>
... ...
@@ -1300,9 +1340,9 @@ if (len_gt(1024)) {
1300 1340
 			    <entry>tm</entry>
1301 1341
 			    <entry>method, request URI, outbound URI (if none, empty line with a single dot),
1302 1342
 					dot-line-terminated header fields, optionally dot-line terminated message
1303
-					body. 
1343
+					body.
1304 1344
 				</entry>
1305
-					
1345
+
1306 1346
 			    <entry>initiate a transaction.
1307 1347
 					From and To header fields must be present in header field list,
1308 1348
 					so does Content-Type if body is present. If CSeq, CallId and From-tag
... ...
@@ -1463,7 +1503,7 @@ if (len_gt(1024)) {
1463 1503
 
1464 1504
 		    <listitem>
1465 1505
 			<para>
1466
-			    server_monitoring-* -- reserved for persistent monitoring of 
1506
+			    server_monitoring-* -- reserved for persistent monitoring of
1467 1507
 				server's operation
1468 1508
 			</para>
1469 1509
 		    </listitem>
... ...
@@ -1478,7 +1518,7 @@ if (len_gt(1024)) {
1478 1518
 
1479 1519
 
1480 1520
 		</itemizedlist>
1481
-		
1521
+
1482 1522
 	    </para>
1483 1523
 	</section>
1484 1524
 </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 73
 static avp_list_t* def_glist;
72 74
 static avp_list_t** crt_glist;
73 75
 
76
+/* AVP flags */
77
+int registered_avpflags_no = 0;
78
+static char *registered_avpflags[MAX_AVPFLAG];
74 79
 
75 80
 /* Initialize AVP lists in private memory and allocate memory
76 81
  * for shared lists
... ...
@@ -80,7 +85,7 @@ int init_avps(void)
80 85
 	int i;
81 86
 	     /* Empty default lists */
82 87
 	memset(def_list, 0, sizeof(avp_list_t) * IDX_MAX);
83
-	
88
+
84 89
 	     /* Point current pointers to default lists */
85 90
 	for(i = 0; i < IDX_MAX; i++) {
86 91
 		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 149
 		LOG(L_ERR,"ERROR:avp:add_avp: 0 ID or NULL NAME AVP!");
145 150
 		goto error;
146 151
 	}
147
-	
152
+
148 153
 	/* compute the required mem size */
149 154
 	len = sizeof(struct usr_avp);
150 155
 	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 158
 			goto error;
154 159
 		}
155 160
 		if (flags&AVP_VAL_STR) {
156
-			len += sizeof(struct str_str_data)-sizeof(void*) 
161
+			len += sizeof(struct str_str_data)-sizeof(void*)
157 162
 				+ name.s.len + 1 /* Terminating zero for regex search */
158 163
 				+ val.s.len + 1; /* Value is zero terminated */
159 164
 		} else {
160
-			len += sizeof(struct str_int_data)-sizeof(void*) 
165
+			len += sizeof(struct str_int_data)-sizeof(void*)
161 166
 				+ name.s.len + 1; /* Terminating zero for regex search */
162 167
 		}
163 168
 	} 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 231
 		*list = avp;
227 232
 		return 0;
228 233
 	}
229
-	
234
+
230 235
 	return -1;
231 236
 }
232 237
 
... ...
@@ -256,14 +261,14 @@ int add_avp(avp_flags_t flags, avp_name_t name, avp_value_t val)
256 261
 int add_avp_before(avp_t *avp, avp_flags_t flags, avp_name_t name, avp_value_t val)
257 262
 {
258 263
 	avp_t *new_avp;
259
-	
264
+
260 265
 	if (!avp) {
261 266
 		return add_avp(flags, name, val);
262 267
 	}
263 268
 
264 269
 	if ((flags & AVP_CLASS_ALL) == 0) flags |= (avp->flags & AVP_CLASS_ALL);
265 270
 	if ((flags & AVP_TRACK_ALL) == 0) flags |= (avp->flags & AVP_TRACK_ALL);
266
-	
271
+
267 272
 	if ((avp->flags & (AVP_CLASS_ALL|AVP_TRACK_ALL)) != (flags & (AVP_CLASS_ALL|AVP_TRACK_ALL))) {
268 273
 		ERR("add_avp_before:Source and target AVPs have different CLASS/TRACK\n");
269 274
 		return -1;
... ...
@@ -400,7 +405,7 @@ avp_t *search_avp (avp_ident_t ident, avp_value_t* val, struct search_state* sta
400 405
 		LOG(L_ERR,"ERROR:avp:search_first_avp: 0 ID or NULL NAME AVP!");
401 406
 		return 0;
402 407
 	}
403
-	
408
+
404 409
 	switch (ident.flags & AVP_INDEX_ALL) {
405 410
 		case AVP_INDEX_BACKWARD:
406 411
 		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 420
 		      * all of them by default
416 421
 		      */
417 422
 		ident.flags |= AVP_CLASS_ALL;
418
-		
423
+
419 424
 		if ((ident.flags & AVP_TRACK_ALL) == 0) {
420 425
 		    /* The caller did not specify even the track to search in, so search
421 426
 		     * in the track_from
... ...
@@ -496,7 +501,7 @@ int search_reverse( avp_t *cur, struct search_state* st,
496 501
                      avp_index_t index, avp_list_t *ret)
497 502
 {
498 503
 	avp_index_t lvl;
499
-	
504
+
500 505
 	if (!cur)
501 506
 		return 0;
502 507
 	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 509
 		*ret=cur;
505 510
 	return lvl;
506 511
 }
507
-                            
512
+
508 513
 avp_t *search_avp_by_index( avp_flags_t flags, avp_name_t name,
509
-                            avp_value_t *val, avp_index_t index) 	
514
+                            avp_value_t *val, avp_index_t index)
510 515
 {
511 516
 	avp_t *ret, *cur;
512 517
 	struct search_state st;
513
-	
518
+
514 519
 	if (flags & AVP_NAME_RE) {
515 520
 		BUG("search_by_index not supported for AVP_NAME_RE\n");
516 521
 		return 0;
... ...
@@ -537,9 +542,9 @@ avp_t *search_avp_by_index( avp_flags_t flags, avp_name_t name,
537 542
 			for (index--; (ret && index); ret=search_next_avp(&st, val), index--);
538 543
 			return ret;
539 544
 	}
540
-		
545
+
541 546
 	return 0;
542
-}                            
547
+}
543 548
 
544 549
 /* FIXME */
545 550
 /********* free functions ********/
... ...
@@ -550,7 +555,7 @@ void destroy_avp(avp_t *avp_del)
550 555
 	avp_t *avp, *avp_prev;
551 556
 
552 557
 	for (i = 0; i < IDX_MAX; i++) {
553
-		for( avp_prev=0,avp=*crt_list[i] ; avp ; 
558
+		for( avp_prev=0,avp=*crt_list[i] ; avp ;
554 559
 		     avp_prev=avp,avp=avp->next ) {
555 560
 			if (avp==avp_del) {
556 561
 				if (avp_prev) {
... ...
@@ -564,7 +569,7 @@ void destroy_avp(avp_t *avp_del)
564 569
 		}
565 570
 	}
566 571
 
567
-	for( avp_prev=0,avp=**crt_glist ; avp ; 
572
+	for( avp_prev=0,avp=**crt_glist ; avp ;
568 573
 	     avp_prev=avp,avp=avp->next ) {
569 574
 		if (avp==avp_del) {
570 575
 			if (avp_prev) {
... ...
@@ -766,7 +771,7 @@ int parse_avp_name( str *name, int *type, int_str *avp_name, int *index)
766 771
 {
767 772
 	int ret;
768 773
 	avp_ident_t attr;
769
-	
774
+
770 775
 	ret=parse_avp_ident(name, &attr);
771 776
 	if (!ret) {
772 777
 		if (type) *type = attr.flags;
... ...
@@ -866,7 +871,7 @@ int parse_avp_ident( str *name, avp_ident_t* attr)
866 871
 			p=memchr(name->s, '[', name->len);
867 872
 			if (!p) {
868 873
 				ERR("missing '[' for AVP index\n");
869
-				goto error; 
874
+				goto error;
870 875
 			}
871 876
 			s.s=p+1;
872 877
 			s.len=name->len-(p-name->s)-2; // [ and ]
... ...
@@ -878,7 +883,7 @@ int parse_avp_ident( str *name, avp_ident_t* attr)
878 883
 					s.s++;s.len--;
879 884
 				} else {
880 885
 					attr->flags |= AVP_INDEX_FORWARD;
881
-				}	
886
+				}
882 887
 				if ((str2int(&s, &id) != 0)||(id==0)) {
883 888
 					ERR("Invalid AVP index '%.*s'\n", s.len, s.s);
884 889
 					goto error;
... ...
@@ -956,7 +961,7 @@ int add_avp_galias_str(char *alias_definition)
956 961
 	str  alias;
957 962
 	int  type;
958 963
 	int  index;
959
-	
964
+
960 965
 	s = alias_definition;
961 966
 	while(*s && isspace((int)*s))
962 967
 		s++;
... ...
@@ -1027,3 +1032,26 @@ void delete_avp(avp_flags_t flags, avp_name_t name)
1027 1032
 		avp = search_next_avp(&st, 0);
1028 1033
 	}
1029 1034
 }
1035
+
1036
+/* AVP flags functions */
1037
+
1038
+/* name2id conversion is intended to use during fixup (cfg parsing and modinit) only therefore no hash is used */
1039
+avp_flags_t register_avpflag(char* name) {
1040
+	avp_flags_t ret;
1041
+	ret = get_avpflag_no(name);
1042
+	if (ret == 0) {
1043
+		if (registered_avpflags_no >= MAX_AVPFLAG) return -1;
1044
+		ret = 1<<(AVP_CUSTOM_FLAGS+registered_avpflags_no);
1045
+		registered_avpflags[registered_avpflags_no++] = name;
1046
+	}
1047
+	return ret;
1048
+}
1049
+
1050
+avp_flags_t get_avpflag_no(char* name) {
1051
+	int i;
1052
+	for (i=0; i<registered_avpflags_no; i++) {
1053
+		if (strcasecmp(name, registered_avpflags[i])==0)
1054
+			return 1<<(AVP_CUSTOM_FLAGS+i);
1055
+	}
1056
+	return 0;
1057
+}
... ...
@@ -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 197
 int parse_avp_spec( str *name, int *type, int_str *avp_name, int *index);
197 198
 void free_avp_name( int *type, int_str *avp_name);
198 199
 
200
+/* AVP flags functions */
201
+#define MAX_AVPFLAG  ((unsigned int)( sizeof(avp_flags_t) * CHAR_BIT - 1 - AVP_CUSTOM_FLAGS))
202
+
203
+avp_flags_t register_avpflag(char* name);
204
+avp_flags_t get_avpflag_no(char* name);
205
+
199 206
 #endif