Browse code

registrar - add registered extra parameter

adds 3rd parameter to registered to optionally restrict the contacts

adds module parameter to optionally
add contact xavp on successful match when calling registered
add contact xavp to the $ulc structure

Luis Azedo authored on 25/02/2015 10:06:35
Showing 6 changed files
... ...
@@ -103,7 +103,7 @@ int regapi_registered(struct sip_msg *msg, char *table)
103 103
 		LM_ERR("usrloc domain [%s] not found\n", table);
104 104
 		return -1;
105 105
 	}
106
-	return registered(msg, d, NULL);
106
+	return registered(msg, d, NULL, 0);
107 107
 }
108 108
 
109 109
 /**
... ...
@@ -619,13 +619,16 @@ done:
619 619
  * it is similar to lookup but registered neither rewrites
620 620
  * the Request-URI nor appends branches
621 621
  */
622
-int registered(struct sip_msg* _m, udomain_t* _d, str* _uri)
622
+int registered(struct sip_msg* _m, udomain_t* _d, str* _uri, int match_flag)
623 623
 {
624 624
 	str uri, aor;
625 625
 	urecord_t* r;
626 626
 	ucontact_t* ptr;
627 627
 	int res;
628
-	int_str match_callid=(int_str)0;
628
+	str match_callid = {0,0};
629
+	str match_received = {0,0};
630
+	str match_contact = {0,0};
631
+	sr_xavp_t *vavp = NULL;
629 632
 
630 633
 	if(_uri!=NULL)
631 634
 	{
... ...
@@ -650,26 +653,61 @@ int registered(struct sip_msg* _m, udomain_t* _d, str* _uri)
650 650
 	}
651 651
 
652 652
 	if (res == 0) {
653
-		
654
-		if (reg_callid_avp_name.n) {
655
-			struct usr_avp *avp =
656
-				search_first_avp( reg_callid_avp_type, reg_callid_avp_name, &match_callid, 0);
657
-			if (!(avp && is_avp_str_val(avp)))
658
-				match_callid.n = 0;
659
-				match_callid.s.s = NULL;
660
-		} else {
661
-			match_callid.n = 0;
662
-			match_callid.s.s = NULL;
653
+		LM_DBG("searching with match flags (%d,%d)\n", match_flag, reg_match_flag_param);
654
+		if(reg_xavp_cfg.s!=NULL) {
655
+
656
+			if((match_flag & 1)
657
+					&& (vavp = xavp_get_child_with_sval(&reg_xavp_cfg, &match_callid_name)) != NULL
658
+					&& vavp->val.v.s.len > 0) {
659
+				match_callid = vavp->val.v.s;
660
+				LM_DBG("matching with callid %.*s\n", match_callid.len, match_callid.s);
661
+			}
662
+
663
+			if((match_flag & 2)
664
+					&& (vavp = xavp_get_child_with_sval(&reg_xavp_cfg, &match_received_name)) != NULL
665
+					&& vavp->val.v.s.len > 0) {
666
+				match_received = vavp->val.v.s;
667
+				LM_DBG("matching with received %.*s\n", match_received.len, match_received.s);
668
+			}
669
+
670
+			if((match_flag & 4)
671
+					&& (vavp = xavp_get_child_with_sval(&reg_xavp_cfg, &match_contact_name)) != NULL
672
+					&& vavp->val.v.s.len > 0) {
673
+				match_contact = vavp->val.v.s;
674
+				LM_DBG("matching with contact %.*s\n", match_contact.len, match_contact.s);
675
+			}
663 676
 		}
664 677
 
665 678
 		for (ptr = r->contacts; ptr; ptr = ptr->next) {
666 679
 			if(!VALID_CONTACT(ptr, act_time)) continue;
667
-			if (match_callid.s.s && /* optionally enforce tighter matching w/ Call-ID */
668
-				memcmp(match_callid.s.s,ptr->callid.s,match_callid.s.len))
680
+			if (match_callid.s && /* optionally enforce tighter matching w/ Call-ID */
681
+				match_callid.len > 0 &&
682
+				(match_callid.len != ptr->callid.len || 
683
+				memcmp(match_callid.s, ptr->callid.s, match_callid.len)))
669 684
 				continue;
685
+			if (match_received.s && /* optionally enforce tighter matching w/ ip:port */
686
+				match_received.len > 0 &&
687
+				(match_received.len != ptr->received.len || 
688
+				memcmp(match_received.s, ptr->received.s, match_received.len)))
689
+				continue;
690
+			if (match_contact.s && /* optionally enforce tighter matching w/ Contact */
691
+				match_contact.len > 0 &&
692
+				(match_contact.len != ptr->c.len || 
693
+				memcmp(match_contact.s, ptr->c.s, match_contact.len)))
694
+				continue;
695
+
696
+			if(ptr->xavp!=NULL && reg_match_flag_param == 1) {
697
+				sr_xavp_t *xavp = xavp_clone_level_nodata(ptr->xavp);
698
+				if(xavp_add(xavp, NULL)<0) {
699
+					LM_ERR("error adding xavp for %.*s after successful match\n", aor.len, ZSW(aor.s));
700
+					xavp_destroy_list(&xavp);
701
+				}
702
+			}
703
+
670 704
 			ul.release_urecord(r);
671 705
 			ul.unlock_udomain(_d, &aor);
672 706
 			LM_DBG("'%.*s' found in usrloc\n", aor.len, ZSW(aor.s));
707
+
673 708
 			return 1;
674 709
 		}
675 710
 	}
... ...
@@ -66,7 +66,7 @@ int lookup_branches(sip_msg_t *msg, udomain_t *d);
66 66
  * it is similar to lookup but registered neither rewrites
67 67
  * the Request-URI nor appends branches
68 68
  */
69
-int registered(struct sip_msg* _m, udomain_t* _d, str* _uri);
69
+int registered(struct sip_msg* _m, udomain_t* _d, str* _uri, int match_flag);
70 70
 
71 71
 
72 72
 #endif /* LOOKUP_H */
... ...
@@ -69,6 +69,7 @@ static int w_lookup(struct sip_msg* _m, char* _d, char* _p2);
69 69
 static int w_lookup_to_dset(struct sip_msg* _m, char* _d, char* _p2);
70 70
 static int w_lookup_branches(struct sip_msg* _m, char* _d, char* _p2);
71 71
 static int w_registered(struct sip_msg* _m, char* _d, char* _uri);
72
+static int w_registered2(struct sip_msg* _m, char* _d, char* _uri, char* _flags);
72 73
 static int w_unregister(struct sip_msg* _m, char* _d, char* _uri);
73 74
 static int w_unregister2(struct sip_msg* _m, char* _d, char* _uri, char *_ruid);
74 75
 
... ...
@@ -78,6 +79,7 @@ static int domain_uri_fixup(void** param, int param_no);
78 78
 static int save_fixup(void** param, int param_no);
79 79
 static int unreg_fixup(void** param, int param_no);
80 80
 static int fetchc_fixup(void** param, int param_no);
81
+static int registered_fixup(void** param, int param_no);
81 82
 /*! \brief Functions */
82 83
 static int add_sock_hdr(struct sip_msg* msg, char *str, char *foo);
83 84
 
... ...
@@ -101,10 +103,10 @@ int reg_outbound_mode = 0;
101 101
 int reg_regid_mode = 0;
102 102
 int reg_flow_timer = 0;
103 103
 
104
-/* Populate this AVP if testing for specific registration instance. */
105
-char *reg_callid_avp_param = 0;
106
-unsigned short reg_callid_avp_type = 0;
107
-int_str reg_callid_avp_name;
104
+int reg_match_flag_param = 0;
105
+str match_callid_name = str_init("match_callid");
106
+str match_received_name = str_init("match_received");
107
+str match_contact_name = str_init("match_contact");
108 108
 
109 109
 char* rcv_avp_param = 0;
110 110
 unsigned short rcv_avp_type = 0;
... ...
@@ -164,6 +166,8 @@ static cmd_export_t cmds[] = {
164 164
 			REQUEST_ROUTE | FAILURE_ROUTE },
165 165
 	{"registered",   (cmd_function)w_registered,  2,  domain_uri_fixup, 0,
166 166
 			REQUEST_ROUTE | FAILURE_ROUTE },
167
+	{"registered",   (cmd_function)w_registered2, 3,  registered_fixup, 0,
168
+			REQUEST_ROUTE | FAILURE_ROUTE },
167 169
 	{"add_sock_hdr", (cmd_function)add_sock_hdr,  1,  fixup_str_null, 0,
168 170
 			REQUEST_ROUTE },
169 171
 	{"unregister",   (cmd_function)w_unregister,  2,  unreg_fixup, 0,
... ...
@@ -200,22 +204,22 @@ static param_export_t params[] = {
200 200
 	{"max_expires",        INT_PARAM, &default_registrar_cfg.max_expires			},
201 201
 	{"received_param",     PARAM_STR, &rcv_param           					},
202 202
 	{"received_avp",       PARAM_STRING, &rcv_avp_param       					},
203
-	{"reg_callid_avp",     PARAM_STRING, &reg_callid_avp_param					},
204 203
 	{"max_contacts",       INT_PARAM, &default_registrar_cfg.max_contacts			},
205 204
 	{"retry_after",        INT_PARAM, &default_registrar_cfg.retry_after			},
206
-	{"sock_flag",          INT_PARAM, &sock_flag           					},
207
-	{"sock_hdr_name",      PARAM_STR, &sock_hdr_name     					},
208
-	{"method_filtering",   INT_PARAM, &method_filtering    					},
209
-	{"use_path",           INT_PARAM, &path_enabled        					},
210
-	{"path_mode",          INT_PARAM, &path_mode           					},
211
-	{"path_use_received",  INT_PARAM, &path_use_params     					},
212
-        {"path_check_local",   INT_PARAM, &path_check_local                                     },
213
-	{"xavp_cfg",           PARAM_STR, &reg_xavp_cfg     					},
214
-	{"xavp_rcd",           PARAM_STR, &reg_xavp_rcd     					},
215
-	{"gruu_enabled",       INT_PARAM, &reg_gruu_enabled    					},
216
-	{"outbound_mode",      INT_PARAM, &reg_outbound_mode					},
205
+	{"sock_flag",          INT_PARAM, &sock_flag           				},
206
+	{"sock_hdr_name",      PARAM_STR, &sock_hdr_name     				},
207
+	{"method_filtering",   INT_PARAM, &method_filtering    				},
208
+	{"use_path",           INT_PARAM, &path_enabled        				},
209
+	{"path_mode",          INT_PARAM, &path_mode           				},
210
+	{"path_use_received",  INT_PARAM, &path_use_params     				},
211
+	{"path_check_local",   INT_PARAM, &path_check_local					},
212
+	{"xavp_cfg",           PARAM_STR, &reg_xavp_cfg     				},
213
+	{"xavp_rcd",           PARAM_STR, &reg_xavp_rcd     				},
214
+	{"gruu_enabled",       INT_PARAM, &reg_gruu_enabled    				},
215
+	{"outbound_mode",      INT_PARAM, &reg_outbound_mode				},
217 216
 	{"regid_mode",         INT_PARAM, &reg_regid_mode					},
218 217
 	{"flow_timer",         INT_PARAM, &reg_flow_timer					},
218
+	{"reg_on_match_flag",  INT_PARAM, &reg_match_flag_param				},
219 219
 	{0, 0, 0}
220 220
 };
221 221
 
... ...
@@ -285,8 +289,6 @@ static int mod_init(void)
285 285
 		LM_ERR("Fail to declare the configuration\n");
286 286
 	        return -1;
287 287
 	}
288
-	                                                
289
-	                                                
290 288
 
291 289
 	if (rcv_avp_param && *rcv_avp_param) {
292 290
 		s.s = rcv_avp_param; s.len = strlen(s.s);
... ...
@@ -306,24 +308,6 @@ static int mod_init(void)
306 306
 		rcv_avp_type = 0;
307 307
 	}
308 308
 
309
-	if (reg_callid_avp_param && *reg_callid_avp_param) {
310
-		s.s = reg_callid_avp_param; s.len = strlen(s.s);
311
-		if (pv_parse_spec(&s, &avp_spec)==0
312
-			|| avp_spec.type!=PVT_AVP) {
313
-			LM_ERR("malformed or non AVP %s AVP definition\n", reg_callid_avp_param);
314
-			return -1;
315
-		}
316
-
317
-		if(pv_get_avp_name(0, &avp_spec.pvp, &reg_callid_avp_name, &reg_callid_avp_type)!=0)
318
-		{
319
-			LM_ERR("[%s]- invalid AVP definition\n", reg_callid_avp_param);
320
-			return -1;
321
-		}
322
-	} else {
323
-		reg_callid_avp_name.n = 0;
324
-		reg_callid_avp_type = 0;
325
-	}
326
-
327 309
 	bind_usrloc = (bind_usrloc_t)find_export("ul_bind_usrloc", 1, 0);
328 310
 	if (!bind_usrloc) {
329 311
 		LM_ERR("can't bind usrloc\n");
... ...
@@ -485,7 +469,24 @@ static int w_registered(struct sip_msg* _m, char* _d, char* _uri)
485 485
 		LM_ERR("invalid uri parameter\n");
486 486
 		return -1;
487 487
 	}
488
-	return registered(_m, (udomain_t*)_d, (uri.len>0)?&uri:NULL);
488
+	return registered(_m, (udomain_t*)_d, (uri.len>0)?&uri:NULL, 0);
489
+}
490
+
491
+static int w_registered2(struct sip_msg* _m, char* _d, char* _uri, char* _flags)
492
+{
493
+	str uri = {0};
494
+	int flags = 0;
495
+	if(_uri!=NULL && (fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0 || uri.len<=0))
496
+	{
497
+		LM_ERR("invalid uri parameter\n");
498
+		return -1;
499
+	}
500
+	if(_flags!=NULL && (fixup_get_ivalue(_m, (fparam_t*)_flags, &flags)) < 0)
501
+	{
502
+		LM_ERR("invalid flags parameter\n");
503
+		return -1;
504
+	}
505
+	return registered(_m, (udomain_t*)_d, (uri.len>0)?&uri:NULL, flags);
489 506
 }
490 507
 
491 508
 static int w_unregister(struct sip_msg* _m, char* _d, char* _uri)
... ...
@@ -550,6 +551,18 @@ static int domain_uri_fixup(void** param, int param_no)
550 550
 	return 0;
551 551
 }
552 552
 
553
+static int registered_fixup(void** param, int param_no)
554
+{
555
+	if (param_no == 1) {
556
+		return domain_fixup(param, 1);
557
+	} else if (param_no == 2) {
558
+		return fixup_spve_null(param, 1);
559
+	} else if (param_no == 3) {
560
+		return fixup_igp_null(param, 1);
561
+	}
562
+	return 0;
563
+}
564
+
553 565
 
554 566
 /*! \brief
555 567
  * Convert char* parameter to udomain_t* pointer
... ...
@@ -616,7 +629,6 @@ static int fetchc_fixup(void** param, int param_no)
616 616
 	return 0;
617 617
 }
618 618
 
619
-
620 619
 static void mod_destroy(void)
621 620
 {
622 621
 	free_contact_buf();
... ...
@@ -74,8 +74,12 @@ extern float def_q;
74 74
 
75 75
 extern unsigned short rcv_avp_type;
76 76
 extern int_str rcv_avp_name;
77
-extern unsigned short reg_callid_avp_type;
78
-extern int_str reg_callid_avp_name;
77
+
78
+extern int reg_match_flag_param;
79
+extern str match_callid_name;
80
+extern str match_received_name;
81
+extern str match_contact_name;
82
+
79 83
 
80 84
 extern str rcv_param;
81 85
 extern int method_filtering;
... ...
@@ -35,10 +35,15 @@
35 35
 #include "../../action.h"
36 36
 #include "../../lib/kcore/faked_msg.h"
37 37
 #include "../usrloc/usrloc.h"
38
+#include "../../pvapi.h"
39
+#include "../../xavp.h"
38 40
 #include "reg_mod.h"
39 41
 #include "common.h"
40 42
 #include "regpv.h"
41 43
 
44
+#define REGPV_FIELD_DELIM ", "
45
+#define REGPV_FIELD_DELIM_LEN (sizeof(REGPV_FIELD_DELIM) - 1)
46
+
42 47
 typedef struct _regpv_profile {
43 48
 	str pname;
44 49
 	str domain;
... ...
@@ -53,6 +58,7 @@ typedef struct _regpv_profile {
53 53
 typedef struct _regpv_name {
54 54
 	regpv_profile_t *rp;
55 55
 	int attr;
56
+	pv_xavp_name_t* xname;
56 57
 } regpv_name_t;
57 58
 
58 59
 static regpv_profile_t *_regpv_profile_list = NULL;
... ...
@@ -110,6 +116,9 @@ static void regpv_free_profile(regpv_profile_t *rpp)
110 110
 	ptr = rpp->contacts;
111 111
 	while(ptr)
112 112
 	{
113
+		if(ptr->xavp) {
114
+			xavp_destroy_list(&ptr->xavp);
115
+		}
113 116
 		ptr0 = ptr;
114 117
 		ptr = ptr->next;
115 118
 		pkg_free(ptr0);
... ...
@@ -151,6 +160,285 @@ void regpv_free_profiles(void)
151 151
 	_regpv_profile_list = 0;
152 152
 }
153 153
 
154
+char* regpv_xavp_fill_ni(str *in, pv_xavp_name_t *xname)
155
+{
156
+	char *p;
157
+	str idx;
158
+	int n;
159
+
160
+	if(in->s==NULL || in->len<=0 || xname==NULL)
161
+		return NULL;
162
+	p = in->s;
163
+
164
+	/* eat ws */
165
+	while(p<in->s+in->len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
166
+		p++;
167
+	if(p>in->s+in->len || *p=='\0')
168
+		goto error;
169
+	xname->name.s = p;
170
+	while(p < in->s + in->len)
171
+	{
172
+		if(*p=='=' || *p==' ' || *p=='\t' || *p=='\n' || *p=='\r' || *p=='[')
173
+			break;
174
+		p++;
175
+	}
176
+	xname->name.len = p - xname->name.s;
177
+	if(p>in->s+in->len || *p=='\0')
178
+		return p;
179
+	/* eat ws */
180
+	while(p<in->s+in->len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
181
+		p++;
182
+	if(p>in->s+in->len || *p=='\0')
183
+		return p;
184
+
185
+	if(*p!='[')
186
+		return p;
187
+	/* there is index */
188
+	p++;
189
+	idx.s = p;
190
+	n = 0;
191
+	while(p<in->s+in->len && *p!='\0')
192
+	{
193
+		if(*p==']')
194
+		{
195
+			if(n==0)
196
+				break;
197
+			n--;
198
+		}
199
+		if(*p == '[')
200
+			n++;
201
+		p++;
202
+	}
203
+	if(p>in->s+in->len || *p=='\0')
204
+		goto error;
205
+
206
+	if(p==idx.s)
207
+	{
208
+		LM_ERR("xavp [\"%.*s\"] does not get empty index param\n",
209
+				in->len, in->s);
210
+		goto error;
211
+	}
212
+	idx.len = p - idx.s;
213
+	if(pv_parse_index(&xname->index, &idx)!=0)
214
+	{
215
+		LM_ERR("idx \"%.*s\" has an invalid index param [%.*s]\n",
216
+					in->len, in->s, idx.len, idx.s);
217
+		goto error;
218
+	}
219
+	xname->index.type = PVT_EXTRA;
220
+	p++;
221
+	return p;
222
+error:
223
+	return NULL;
224
+}
225
+
226
+int regpv_parse_xavp_name(pv_spec_p sp, str *in)
227
+{
228
+	pv_xavp_name_t *xname=NULL;
229
+	char *p;
230
+	str s;
231
+
232
+	if(in->s==NULL || in->len<=0)
233
+		return -1;
234
+
235
+	xname = (pv_xavp_name_t*)shm_malloc(sizeof(pv_xavp_name_t));
236
+	if(xname==NULL)
237
+		return -1;
238
+
239
+	memset(xname, 0, sizeof(pv_xavp_name_t));
240
+
241
+	s = *in;
242
+
243
+	p = regpv_xavp_fill_ni(&s, xname);
244
+	if(p==NULL) {
245
+		goto error;
246
+	}
247
+
248
+	if(*p!='=') {
249
+		goto done;
250
+	}
251
+	p++;
252
+	if(*p!='>') {
253
+		goto error;
254
+	}
255
+	p++;
256
+
257
+	s.len = in->len - (int)(p - in->s);
258
+	s.s = p;
259
+	LM_INFO("xavp sublist [%.*s] - key [%.*s]\n", xname->name.len,
260
+			xname->name.s, s.len, s.s);
261
+
262
+	xname->next = (pv_xavp_name_t*)pkg_malloc(sizeof(pv_xavp_name_t));
263
+	if(xname->next==NULL) {
264
+		goto error;
265
+	}
266
+
267
+	memset(xname->next, 0, sizeof(pv_xavp_name_t));
268
+
269
+	p = regpv_xavp_fill_ni(&s, xname->next);
270
+	if(p==NULL) {
271
+		goto error;
272
+	}
273
+
274
+done:
275
+	sp->pvp.pvn.u.dname = (void*)xname;
276
+	sp->pvp.pvn.type = PV_NAME_PVAR;
277
+	return 0;
278
+
279
+error:
280
+	if(xname!=NULL) {
281
+		pkg_free(xname);
282
+	}
283
+	return -1;
284
+}
285
+
286
+int regpv_xavp_get_value(struct sip_msg *msg, pv_param_t *param,
287
+		pv_value_t *res, sr_xavp_t *avp)
288
+{
289
+	static char _pv_xavp_buf[128];
290
+	str s;
291
+
292
+	switch(avp->val.type) {
293
+		case SR_XTYPE_NULL:
294
+			return pv_get_null(msg, param, res);
295
+		break;
296
+		case SR_XTYPE_INT:
297
+			return pv_get_sintval(msg, param, res, avp->val.v.i);
298
+		break;
299
+		case SR_XTYPE_STR:
300
+			return pv_get_strval(msg, param, res, &avp->val.v.s);
301
+		break;
302
+		case SR_XTYPE_TIME:
303
+			if(snprintf(_pv_xavp_buf, 128, "%lu", (long unsigned)avp->val.v.t)<0)
304
+				return pv_get_null(msg, param, res);
305
+		break;
306
+		case SR_XTYPE_LONG:
307
+			if(snprintf(_pv_xavp_buf, 128, "%ld", (long unsigned)avp->val.v.l)<0)
308
+				return pv_get_null(msg, param, res);
309
+		break;
310
+		case SR_XTYPE_LLONG:
311
+			if(snprintf(_pv_xavp_buf, 128, "%lld", avp->val.v.ll)<0)
312
+				return pv_get_null(msg, param, res);
313
+		break;
314
+		case SR_XTYPE_XAVP:
315
+			if(snprintf(_pv_xavp_buf, 128, "<<xavp:%p>>", avp->val.v.xavp)<0)
316
+				return pv_get_null(msg, param, res);
317
+		break;
318
+		case SR_XTYPE_DATA:
319
+			if(snprintf(_pv_xavp_buf, 128, "<<data:%p>>", avp->val.v.data)<0)
320
+				return pv_get_null(msg, param, res);
321
+		break;
322
+		default:
323
+			return pv_get_null(msg, param, res);
324
+	}
325
+	s.s = _pv_xavp_buf;
326
+	s.len = strlen(_pv_xavp_buf);
327
+	return pv_get_strval(msg, param, res, &s);
328
+}
329
+
330
+int regpv_get_xavp_from_start(struct sip_msg *msg, pv_param_t *param,
331
+		pv_value_t *res, sr_xavp_t **start)
332
+{
333
+	pv_xavp_name_t *xname=NULL;
334
+	sr_xavp_t *avp=NULL;
335
+	int idxf = 0;
336
+	int idx = 0;
337
+	int count;
338
+	char *p, *p_ini;
339
+	int p_size;
340
+
341
+	if(param==NULL)
342
+	{
343
+		LM_ERR("bad parameters\n");
344
+		return -1;
345
+	}
346
+	xname = ((regpv_name_t*)param->pvn.u.dname)->xname;
347
+
348
+	if(xname->index.type==PVT_EXTRA)
349
+	{
350
+		/* get the index */
351
+		if(pv_get_spec_index(msg, &xname->index.pvp, &idx, &idxf)!=0)
352
+		{
353
+			LM_ERR("invalid index\n");
354
+			return -1;
355
+		}
356
+	}
357
+	/* fix the index */
358
+	if(idx<0)
359
+	{
360
+		count = xavp_count(&xname->name, start);
361
+		idx = count + idx;
362
+	}
363
+	avp = xavp_get_by_index(&xname->name, idx, start);
364
+	if(avp==NULL) {
365
+		LM_DBG("GET XAVP AVP = NULL\n");
366
+		return pv_get_null(msg, param, res);
367
+	}
368
+	if(xname->next==NULL) {
369
+		LM_DBG("GET XAVP XNAME NEXT = NULL\n");
370
+		return regpv_xavp_get_value(msg, param, res, avp);
371
+	}
372
+
373
+	idx = 0;
374
+	idxf = 0;
375
+	if(xname->next->index.type==PVT_EXTRA)
376
+	{
377
+		/* get the index */
378
+		if(pv_get_spec_index(msg, &xname->next->index.pvp, &idx, &idxf)!=0)
379
+		{
380
+			LM_ERR("invalid index\n");
381
+			return -1;
382
+		}
383
+	}
384
+	/* fix the index */
385
+	if(idx<0)
386
+	{
387
+		count = xavp_count(&xname->next->name, &avp->val.v.xavp);
388
+		idx = count + idx;
389
+	}
390
+	avp = xavp_get_by_index(&xname->next->name, idx, &avp->val.v.xavp);
391
+	if(avp==NULL) {
392
+		LM_DBG("GET XAVP AVP BY INDEX = NULL\n");
393
+		return pv_get_null(msg, param, res);
394
+	}
395
+	/* get all values of second key */
396
+	if(idxf==PV_IDX_ALL)
397
+	{
398
+		p_ini = pv_get_buffer();
399
+		p = p_ini;
400
+		p_size = pv_get_buffer_size();
401
+		do {
402
+			if(p!=p_ini)
403
+			{
404
+				if(p-p_ini+REGPV_FIELD_DELIM_LEN+1>p_size)
405
+				{
406
+					LM_ERR("local buffer length exceeded\n");
407
+					return pv_get_null(msg, param, res);
408
+				}
409
+				memcpy(p, REGPV_FIELD_DELIM, REGPV_FIELD_DELIM_LEN);
410
+				p += REGPV_FIELD_DELIM_LEN;
411
+			}
412
+			if(regpv_xavp_get_value(msg, param, res, avp)<0)
413
+			{
414
+				LM_ERR("can get value\n");
415
+				return pv_get_null(msg, param, res);
416
+			}
417
+			if(p-p_ini+res->rs.len+1>p_size)
418
+			{
419
+				LM_ERR("local buffer length exceeded!\n");
420
+				return pv_get_null(msg, param, res);
421
+			}
422
+			memcpy(p, res->rs.s, res->rs.len);
423
+			p += res->rs.len;
424
+		} while ((avp=xavp_get_next(avp))!=0);
425
+		res->rs.s = p_ini;
426
+		res->rs.len = p - p_ini;
427
+		return 0;
428
+	}
429
+	return regpv_xavp_get_value(msg, param, res, avp);
430
+}
431
+
432
+
154 433
 int pv_get_ulc(struct sip_msg *msg,  pv_param_t *param,
155 434
 		pv_value_t *res)
156 435
 {
... ...
@@ -192,7 +480,7 @@ int pv_get_ulc(struct sip_msg *msg,  pv_param_t *param,
192 192
 	/* get contact */
193 193
 	i = 0;
194 194
 	c = rpp->contacts;
195
-	while(rpp)
195
+	while(c)
196 196
 	{
197 197
 		if(i == idx)
198 198
 			break;
... ...
@@ -269,6 +557,10 @@ int pv_get_ulc(struct sip_msg *msg,  pv_param_t *param,
269 269
 			if(c->instance.len>0)
270 270
 				return  pv_get_strval(msg, param, res, &c->instance);
271 271
 		break;
272
+		case 21: /* xavp */
273
+			if(c->xavp)
274
+				return regpv_get_xavp_from_start(msg, param, res, &c->xavp);
275
+		break;
272 276
 	}
273 277
 
274 278
 	return pv_get_null(msg, param, res);
... ...
@@ -333,6 +625,15 @@ int pv_parse_ulc_name(pv_spec_p sp, str *in)
333 333
 	memset(rp, 0, sizeof(regpv_name_t));
334 334
 	rp->rp = rpp;
335 335
 
336
+	if(strstr(pa.s, "=>")) {
337
+		regpv_parse_xavp_name(sp, &pa);
338
+		pv_xavp_name_t* xname = (pv_xavp_name_t*)sp->pvp.pvn.u.dname;
339
+		LM_DBG("ulc parse xavp name [%.*s] \n", xname->name.len, xname->name.s);
340
+		rp->xname = xname;
341
+		rp->attr = 21;
342
+		goto done;
343
+	}
344
+
336 345
 	switch(pa.len)
337 346
 	{
338 347
 		case 1: 
... ...
@@ -402,6 +703,7 @@ int pv_parse_ulc_name(pv_spec_p sp, str *in)
402 402
 		default:
403 403
 			goto error;
404 404
 	}
405
+done:
405 406
 	sp->pvp.pvn.u.dname = (void*)rp;
406 407
 	sp->pvp.pvn.type = PV_NAME_PVAR;
407 408
 
... ...
@@ -538,7 +840,10 @@ int pv_fetch_contacts(struct sip_msg* msg, char* table, char* uri,
538 538
 			c0->instance.len = ptr->instance.len;
539 539
 			p += c0->instance.len;
540 540
 		}
541
-
541
+		if(ptr->xavp != NULL && reg_match_flag_param == 1)
542
+		{
543
+			c0->xavp = xavp_clone_level_nodata(ptr->xavp);
544
+		}
542 545
 		if(ptr0==NULL)
543 546
 		{
544 547
 			rpp->contacts = c0;
... ...
@@ -679,6 +984,10 @@ void reg_ul_expired_contact(ucontact_t* ptr, int type, void* param)
679 679
 		c0->instance.len = ptr->instance.len;
680 680
 		p += c0->instance.len;
681 681
 	}
682
+	if(ptr->xavp != NULL && reg_match_flag_param == 1)
683
+	{
684
+		c0->xavp = xavp_clone_level_nodata(ptr->xavp);
685
+	}		
682 686
 
683 687
 	rpp->contacts = c0;
684 688
 	rpp->nrc = 1;