From: Victor Seva <vseva@sipwise.com>
Date: Wed, 27 May 2020 09:23:46 +0200
Subject: pv: $xavi(...) config variables implementation

same as $xavp but case insensitive for keys
---
 src/modules/pv/pv.c      | 539 ++++++++++++++++++++++++++++++++++++++++-------
 src/modules/pv/pv_xavp.c | 416 ++++++++++++++++++++++++++++++++++++
 src/modules/pv/pv_xavp.h |   7 +
 3 files changed, 891 insertions(+), 71 deletions(-)

diff --git a/src/modules/pv/pv.c b/src/modules/pv/pv.c
index b427667..be79f61 100644
--- a/src/modules/pv/pv.c
+++ b/src/modules/pv/pv.c
@@ -31,6 +31,7 @@
 #include "../../core/kemi.h"
 #include "../../core/rpc.h"
 #include "../../core/rpc_lookup.h"
+#include "../../core/strutils.h"
 
 
 #include "pv_branch.h"
@@ -93,6 +94,9 @@ static pv_export_t mod_pvs[] = {
 	{ {"xavp", sizeof("xavp")-1}, /* xavp */
 		PVT_XAVP, pv_get_xavp, pv_set_xavp,
 		pv_parse_xavp_name, 0, 0, 0 },
+	{ {"xavi", sizeof("xavi")-1}, /* xavi */
+		PVT_XAVI, pv_get_xavi, pv_set_xavi,
+		pv_parse_xavp_name, 0, 0, 0 },
 	{{"avp", (sizeof("avp")-1)}, PVT_AVP, pv_get_avp, pv_set_avp,
 		pv_parse_avp_name, pv_parse_index, 0, 0},
 	{{"hdr", (sizeof("hdr")-1)}, PVT_HDR, pv_get_hdr, 0, pv_parse_hdr_name,
@@ -543,6 +547,13 @@ static int w_sbranch_reset(sip_msg_t *msg, char p1, char *p2);
 static int w_var_to_xavp(sip_msg_t *msg, char *p1, char *p2);
 static int w_xavp_to_var(sip_msg_t *msg, char *p1);
 
+static int w_xavi_child_seti(sip_msg_t *msg, char *prname, char *pcname,
+		char *pval);
+static int w_xavi_child_sets(sip_msg_t *msg, char *prname, char *pcname,
+		char *pval);
+static int w_xavi_rm(sip_msg_t *msg, char *prname, char *p2);
+static int w_xavi_child_rm(sip_msg_t *msg, char *prname, char *pcname);
+
 int pv_evalx_fixup(void** param, int param_no);
 int w_pv_evalx(struct sip_msg *msg, char *dst, str *fmt);
 
@@ -559,6 +570,8 @@ static cmd_export_t cmds[]={
 		ANY_ROUTE },
 	{"pv_xavp_print",  (cmd_function)pv_xavp_print,  0, 0, 0,
 		ANY_ROUTE },
+	{"pv_xavi_print",  (cmd_function)pv_xavi_print,  0, 0, 0,
+		ANY_ROUTE },
 	{"pv_var_to_xavp",  (cmd_function)w_var_to_xavp, 2, fixup_spve_spve,
 		fixup_free_spve_spve, ANY_ROUTE },
 	{"pv_xavp_to_var",  (cmd_function)w_xavp_to_var, 1, fixup_spve_null,
@@ -589,6 +602,18 @@ static cmd_export_t cmds[]={
 	{"xavp_child_rm", (cmd_function)w_xavp_child_rm,
 		2, fixup_spve_spve, fixup_free_spve_spve,
 		ANY_ROUTE},
+	{"xavi_child_seti", (cmd_function)w_xavi_child_seti,
+		3, fixup_xavp_child_seti, fixup_free_xavp_child_seti,
+		ANY_ROUTE},
+	{"xavi_child_sets", (cmd_function)w_xavi_child_sets,
+		3, fixup_spve_all, fixup_free_spve_all,
+		ANY_ROUTE},
+	{"xavi_rm", (cmd_function)w_xavi_rm,
+		1, fixup_spve_null, fixup_free_spve_null,
+		ANY_ROUTE},
+	{"xavi_child_rm", (cmd_function)w_xavi_child_rm,
+		2, fixup_spve_spve, fixup_free_spve_spve,
+		ANY_ROUTE},
 	{"sbranch_set_ruri",  (cmd_function)w_sbranch_set_ruri,  0, 0, 0,
 		ANY_ROUTE },
 	{"sbranch_append",    (cmd_function)w_sbranch_append,    0, 0, 0,
@@ -805,6 +830,12 @@ static int ki_xavp_print(sip_msg_t* msg)
 	return 1;
 }
 
+static int ki_xavi_print(sip_msg_t* msg)
+{
+	xavi_print_list(NULL);
+	return 1;
+}
+
 /**
  *
  */
@@ -899,7 +930,7 @@ static int w_xavp_params_implode(sip_msg_t *msg, char *pxname, char *pvname)
 /**
  *
  */
-static int ki_xavp_seti(sip_msg_t *msg, str *rname, int ival)
+static int ki_xav_seti(sip_msg_t *msg, str *rname, int ival, int _case)
 {
 	sr_xavp_t *xavp = NULL;
 	sr_xval_t xval;
@@ -908,15 +939,28 @@ static int ki_xavp_seti(sip_msg_t *msg, str *rname, int ival)
 	xval.type = SR_XTYPE_INT;
 	xval.v.i = ival;
 
-	xavp = xavp_add_value(rname, &xval, NULL);
-
+	if(_case) {
+		xavp = xavi_add_value(rname, &xval, NULL);
+	} else {
+		xavp = xavp_add_value(rname, &xval, NULL);
+	}
 	return (xavp!=NULL)?1:-1;
 }
 
+static int ki_xavp_seti(sip_msg_t *msg, str *rname, int ival)
+{
+	return ki_xav_seti(msg, rname, ival, 0);
+}
+
+static int ki_xavi_seti(sip_msg_t *msg, str *rname, int ival)
+{
+	return ki_xav_seti(msg, rname, ival, 1);
+}
+
 /**
  *
  */
-static int ki_xavp_sets(sip_msg_t *msg, str *rname, str *sval)
+static int ki_xav_sets(sip_msg_t *msg, str *rname, str *sval, int _case)
 {
 	sr_xavp_t *xavp = NULL;
 	sr_xval_t xval;
@@ -925,29 +969,56 @@ static int ki_xavp_sets(sip_msg_t *msg, str *rname, str *sval)
 	xval.type = SR_XTYPE_STR;
 	xval.v.s = *sval;
 
-	xavp = xavp_add_value(rname, &xval, NULL);
-
+	if(_case) {
+		xavp = xavi_add_value(rname, &xval, NULL);
+	} else {
+		xavp = xavp_add_value(rname, &xval, NULL);
+	}
 	return (xavp!=NULL)?1:-1;
 }
 
+static int ki_xavp_sets(sip_msg_t *msg, str *rname, str *sval)
+{
+	return ki_xav_sets(msg, rname, sval, 0);
+}
+
+static int ki_xavi_sets(sip_msg_t *msg, str *rname, str *sval)
+{
+	return ki_xav_sets(msg, rname, sval, 1);
+}
+
 /**
  *
  */
-static int ki_xavp_child_seti(sip_msg_t *msg, str *rname, str *cname,
-		int ival)
+static int ki_xav_child_seti(sip_msg_t *msg, str *rname, str *cname,
+		int ival, int _case)
 {
 	int ret;
+	if(_case) {
+		ret = xavi_set_child_ival(rname, cname, ival);
+	} else {
+		ret = xavp_set_child_ival(rname, cname, ival);
+	}
+	return (ret<0)?ret:1;
+}
 
-	ret = xavp_set_child_ival(rname, cname, ival);
+static int ki_xavp_child_seti(sip_msg_t *msg, str *rname, str *cname,
+		int ival)
+{
+	return ki_xav_child_seti(msg, rname, cname, ival, 0);
+}
 
-	return (ret<0)?ret:1;
+static int ki_xavi_child_seti(sip_msg_t *msg, str *rname, str *cname,
+		int ival)
+{
+	return ki_xav_child_seti(msg, rname, cname, ival, 1);
 }
 
 /**
  *
  */
-static int w_xavp_child_seti(sip_msg_t *msg, char *prname, char *pcname,
-		char *pval)
+static int w_xav_child_seti(sip_msg_t *msg, char *prname, char *pcname,
+		char *pval, int _case)
 {
 	str rname = STR_NULL;
 	str cname = STR_NULL;
@@ -966,27 +1037,53 @@ static int w_xavp_child_seti(sip_msg_t *msg, char *prname, char *pcname,
 		return -1;
 	}
 
-	return ki_xavp_child_seti(msg, &rname, &cname, ival);
+ 	return ki_xav_child_seti(msg, &rname, &cname, ival, _case);
+}
+
+static int w_xavp_child_seti(sip_msg_t *msg, char *prname, char *pcname,
+		char *pval)
+{
+	return w_xav_child_seti(msg, prname, pcname, pval, 0);
+}
+
+static int w_xavi_child_seti(sip_msg_t *msg, char *prname, char *pcname,
+		char *pval)
+{
+	return w_xav_child_seti(msg, prname, pcname, pval, 1);
 }
 
 /**
  *
  */
-static int ki_xavp_child_sets(sip_msg_t *msg, str *rname, str *cname,
-		str *sval)
+static int ki_xav_child_sets(sip_msg_t *msg, str *rname, str *cname,
+		str *sval, int _case)
 {
 	int ret;
+	if(_case) {
+		ret = xavi_set_child_sval(rname, cname, sval);
+	} else {
+		ret = xavp_set_child_sval(rname, cname, sval);
+	}
+	return (ret<0)?ret:1;
+}
 
-	ret = xavp_set_child_sval(rname, cname, sval);
+static int ki_xavp_child_sets(sip_msg_t *msg, str *rname, str *cname,
+		str *sval)
+{
+	return ki_xav_child_sets(msg, rname, cname, sval, 0);
+}
 
-	return (ret<0)?ret:1;
+static int ki_xavi_child_sets(sip_msg_t *msg, str *rname, str *cname,
+		str *sval)
+{
+	return ki_xav_child_sets(msg, rname, cname, sval, 1);
 }
 
 /**
  *
  */
-static int w_xavp_child_sets(sip_msg_t *msg, char *prname, char *pcname,
-		char *pval)
+static int w_xav_child_sets(sip_msg_t *msg, char *prname, char *pcname,
+		char *pval, int _case)
 {
 	str rname;
 	str cname;
@@ -1005,7 +1102,17 @@ static int w_xavp_child_sets(sip_msg_t *msg, char *prname, char *pcname,
 		return -1;
 	}
 
-	return ki_xavp_child_sets(msg, &rname, &cname, &sval);
+	return ki_xav_child_sets(msg, &rname, &cname, &sval, _case);
+}
+
+static int w_xavp_child_sets(sip_msg_t *msg, char *prname, char *pcname,
+		char *pval) {
+	return w_xav_child_sets(msg, prname, pcname, pval, 0);
+}
+
+static int w_xavi_child_sets(sip_msg_t *msg, char *prname, char *pcname,
+		char *pval) {
+	return w_xav_child_sets(msg, prname, pcname, pval, 1);
 }
 
 /**
@@ -1036,19 +1143,32 @@ static int fixup_free_xavp_child_seti(void** param, int param_no)
 /**
  *
  */
-static int ki_xavp_rm(sip_msg_t *msg, str *rname)
+static int ki_xav_rm(sip_msg_t *msg, str *rname, int _case)
 {
 	int ret;
-
-	ret = xavp_rm_by_index(rname, 0, NULL);
+	if(_case) {
+		ret = xavi_rm_by_index(rname, 0, NULL);
+	} else {
+		ret = xavp_rm_by_index(rname, 0, NULL);
+	}
 
 	return (ret==0)?1:ret;
 }
 
+static int ki_xavp_rm(sip_msg_t *msg, str *rname)
+{
+	return ki_xav_rm(msg, rname, 0);
+}
+
+static int ki_xavi_rm(sip_msg_t *msg, str *rname)
+{
+	return ki_xav_rm(msg, rname, 1);
+}
+
 /**
  *
  */
-static int w_xavp_rm(sip_msg_t *msg, char *prname, char *p2)
+static int w_xav_rm(sip_msg_t *msg, char *prname, char *p2, int _case)
 {
 	str rname;
 
@@ -1057,25 +1177,45 @@ static int w_xavp_rm(sip_msg_t *msg, char *prname, char *p2)
 		return -1;
 	}
 
-	return ki_xavp_rm(msg, &rname);
+	return ki_xav_rm(msg, &rname, _case);
+}
+
+static int w_xavp_rm(sip_msg_t *msg, char *prname, char *p2) {
+	return w_xav_rm(msg, prname, p2, 0);
+}
+
+static int w_xavi_rm(sip_msg_t *msg, char *prname, char *p2) {
+	return w_xav_rm(msg, prname, p2, 1);
 }
 
 /**
  *
  */
-static int ki_xavp_child_rm(sip_msg_t *msg, str *rname, str *cname)
+static int ki_xav_child_rm(sip_msg_t *msg, str *rname, str *cname, int _case)
 {
 	int ret;
+	if(_case) {
+		ret = xavi_rm_child_by_index(rname, cname, 0);
+	} else {
+		ret = xavp_rm_child_by_index(rname, cname, 0);
+	}
+	return (ret==0)?1:ret;
+}
 
-	ret = xavp_rm_child_by_index(rname, cname, 0);
+static int ki_xavp_child_rm(sip_msg_t *msg, str *rname, str *cname)
+{
+	return ki_xav_child_rm(msg, rname, cname, 0);
+}
 
-	return (ret==0)?1:ret;
+static int ki_xavi_child_rm(sip_msg_t *msg, str *rname, str *cname)
+{
+	return ki_xav_child_rm(msg, rname, cname, 1);
 }
 
 /**
  *
  */
-static int w_xavp_child_rm(sip_msg_t *msg, char *prname, char *pcname)
+static int w_xav_child_rm(sip_msg_t *msg, char *prname, char *pcname, int _case)
 {
 	str rname;
 	str cname;
@@ -1089,17 +1229,28 @@ static int w_xavp_child_rm(sip_msg_t *msg, char *prname, char *pcname)
 		return -1;
 	}
 
-	return ki_xavp_child_rm(msg, &rname, &cname);
+	return ki_xav_child_rm(msg, &rname, &cname, _case);
+}
+
+static int w_xavp_child_rm(sip_msg_t *msg, char *prname, char *pcname) {
+	return w_xav_child_rm(msg, prname, pcname, 0);
+}
+
+static int w_xavi_child_rm(sip_msg_t *msg, char *prname, char *pcname) {
+	return w_xav_child_rm(msg, prname, pcname, 1);
 }
 
 /**
  *
  */
-static int ki_xavp_is_null(sip_msg_t *msg, str *rname)
+static int ki_xav_is_null(sip_msg_t *msg, str *rname, int _case)
 {
 	sr_xavp_t *xavp=NULL;
-
-	xavp = xavp_get_by_index(rname, 0, NULL);
+	if(_case) {
+		xavp = xavi_get_by_index(rname, 0, NULL);
+	} else {
+		xavp = xavp_get_by_index(rname, 0, NULL);
+	}
 	if(xavp==NULL) {
 		return 1;
 	}
@@ -1109,6 +1260,13 @@ static int ki_xavp_is_null(sip_msg_t *msg, str *rname)
 	return -1;
 }
 
+static int ki_xavp_is_null(sip_msg_t *msg, str *rname) {
+	return ki_xav_is_null(msg, rname, 0);
+}
+
+static int ki_xavi_is_null(sip_msg_t *msg, str *rname) {
+	return ki_xav_is_null(msg, rname, 1);
+}
 /**
  *
  */
@@ -1180,13 +1338,17 @@ static sr_kemi_xval_t* ki_xavp_get_xval(sr_xavp_t *xavp, int rmode)
 /**
  *
  */
-static sr_kemi_xval_t* ki_xavp_get_mode(sip_msg_t *msg, str *rname, int rmode)
+static sr_kemi_xval_t* ki_xav_get_mode(sip_msg_t *msg, str *rname, int rmode,
+		int _case)
 {
 	sr_xavp_t *xavp=NULL;
 
 	memset(&_sr_kemi_pv_xval, 0, sizeof(sr_kemi_xval_t));
-
-	xavp = xavp_get_by_index(rname, 0, NULL);
+	if(_case) {
+		xavp = xavi_get_by_index(rname, 0, NULL);
+	} else {
+		xavp = xavp_get_by_index(rname, 0, NULL);
+	}
 	if(xavp==NULL) {
 		sr_kemi_xval_null(&_sr_kemi_pv_xval, rmode);
 		return &_sr_kemi_pv_xval;
@@ -1200,7 +1362,15 @@ static sr_kemi_xval_t* ki_xavp_get_mode(sip_msg_t *msg, str *rname, int rmode)
  */
 static sr_kemi_xval_t* ki_xavp_get(sip_msg_t *msg, str *rname)
 {
-	return ki_xavp_get_mode(msg, rname, SR_KEMI_XVAL_NULL_NONE);
+	return ki_xav_get_mode(msg, rname, SR_KEMI_XVAL_NULL_NONE, 0);
+}
+
+/**
+ *
+ */
+static sr_kemi_xval_t* ki_xavi_get(sip_msg_t *msg, str *rname)
+{
+	return ki_xav_get_mode(msg, rname, SR_KEMI_XVAL_NULL_NONE, 1);
 }
 
 /**
@@ -1208,7 +1378,15 @@ static sr_kemi_xval_t* ki_xavp_get(sip_msg_t *msg, str *rname)
  */
 static sr_kemi_xval_t* ki_xavp_gete(sip_msg_t *msg, str *rname)
 {
-	return ki_xavp_get_mode(msg, rname, SR_KEMI_XVAL_NULL_EMPTY);
+	return ki_xav_get_mode(msg, rname, SR_KEMI_XVAL_NULL_EMPTY, 0);
+}
+
+/**
+ *
+ */
+static sr_kemi_xval_t* ki_xavi_gete(sip_msg_t *msg, str *rname)
+{
+	return ki_xav_get_mode(msg, rname, SR_KEMI_XVAL_NULL_EMPTY, 1);
 }
 
 /**
@@ -1216,14 +1394,22 @@ static sr_kemi_xval_t* ki_xavp_gete(sip_msg_t *msg, str *rname)
  */
 static sr_kemi_xval_t* ki_xavp_getw(sip_msg_t *msg, str *rname)
 {
-	return ki_xavp_get_mode(msg, rname, SR_KEMI_XVAL_NULL_PRINT);
+	return ki_xav_get_mode(msg, rname, SR_KEMI_XVAL_NULL_PRINT, 0);
+}
+
+/**
+ *
+ */
+static sr_kemi_xval_t* ki_xavi_getw(sip_msg_t *msg, str *rname)
+{
+	return ki_xav_get_mode(msg, rname, SR_KEMI_XVAL_NULL_PRINT, 1);
 }
 
-sr_kemi_dict_item_t* ki_xavp_dict(sr_xavp_t *xavp);
+sr_kemi_dict_item_t* ki_xav_dict(sr_xavp_t *xavp, int _case);
 /**
  * SR_KEMIP_ARRAY with values of xavp=>name
  */
-sr_kemi_dict_item_t* ki_xavp_dict_name(sr_xavp_t *xavp, str *name)
+sr_kemi_dict_item_t* ki_xav_dict_name(sr_xavp_t *xavp, str *name, int _case)
 {
 	sr_kemi_dict_item_t *ini = NULL;
 	sr_kemi_dict_item_t *val;
@@ -1237,11 +1423,17 @@ sr_kemi_dict_item_t* ki_xavp_dict_name(sr_xavp_t *xavp, str *name)
 	}
 	memset(ini, 0, sizeof(sr_kemi_xval_t));
 	ini->vtype = SR_KEMIP_ARRAY;
-	while(avp!=NULL&&!STR_EQ(avp->name,*name))
-	{
-		avp = avp->next;
+	if(_case) {
+		while(avp!=NULL&&!cmpi_str(&avp->name, name))
+		{
+			avp = avp->next;
+		}
+	} else {
+		while(avp!=NULL&&!STR_EQ(avp->name,*name))
+		{
+			avp = avp->next;
+		}
 	}
-
 	while(avp!=NULL){
 		switch(avp->val.type) {
 			case SR_XTYPE_XAVP:
@@ -1276,7 +1468,7 @@ sr_kemi_dict_item_t* ki_xavp_dict_name(sr_xavp_t *xavp, str *name)
 				LM_WARN("XAVP type:%d value not supported\n", avp->val.type);
 			break;
 			case SR_XTYPE_XAVP:
-				val = ki_xavp_dict(avp->val.v.xavp);
+				val = ki_xav_dict(avp->val.v.xavp, _case);
 			break;
 			default:
 				val->vtype = SR_KEMIP_NULL;
@@ -1290,7 +1482,11 @@ sr_kemi_dict_item_t* ki_xavp_dict_name(sr_xavp_t *xavp, str *name)
 			ini->v.dict = val;
 		}
 		last = val;
-		avp = xavp_get_next(avp);
+		if(_case) {
+			avp = xavi_get_next(avp);
+		} else {
+			avp = xavp_get_next(avp);
+		}
 	}
 	return ini;
 error:
@@ -1305,7 +1501,7 @@ error:
 /**
  * SR_KEMIP_DICT of xavp
  */
-sr_kemi_dict_item_t* ki_xavp_dict(sr_xavp_t *xavp) {
+sr_kemi_dict_item_t* ki_xav_dict(sr_xavp_t *xavp, int _case) {
 	sr_xavp_t *avp = NULL;
 	struct str_list *keys;
 	struct str_list *k;
@@ -1318,7 +1514,12 @@ sr_kemi_dict_item_t* ki_xavp_dict(sr_xavp_t *xavp) {
 		return NULL;
 	}
 	avp = xavp->val.v.xavp;
-	if((keys = xavp_get_list_key_names(xavp)) != NULL) {
+	if(_case) {
+		keys = xavi_get_list_key_names(xavp);
+	} else {
+		keys = xavp_get_list_key_names(xavp);
+	}
+	if( keys != NULL) {
 		do {
 			val = (sr_kemi_dict_item_t*)pkg_malloc(sizeof(sr_kemi_dict_item_t));
 			if(val==NULL) {
@@ -1329,7 +1530,7 @@ sr_kemi_dict_item_t* ki_xavp_dict(sr_xavp_t *xavp) {
 			val->vtype = SR_KEMIP_DICT;
 			val->name.s = keys->s.s;
 			val->name.len = keys->s.len;
-			val->v.dict = ki_xavp_dict_name(avp, &keys->s);
+			val->v.dict = ki_xav_dict_name(avp, &keys->s, _case);
 			if(last) {
 				last->next = val;
 			} else {
@@ -1360,7 +1561,7 @@ error:
  *
  */
 static sr_kemi_xval_t*
-ki_xavp_getd_helper(sip_msg_t *msg, str *rname, int *_indx)
+ki_xav_getd_helper(sip_msg_t *msg, str *rname, int *_indx, int _case)
 {
 	sr_xavp_t *xavp=NULL;
 	int xavp_size = 0;
@@ -1377,7 +1578,11 @@ ki_xavp_getd_helper(sip_msg_t *msg, str *rname, int *_indx)
 		/* we're going to retrive all */
 		_sr_kemi_pv_xval.vtype = SR_KEMIP_ARRAY;
 	}
-	xavp_size = xavp_count(rname, NULL);
+	if(_case) {
+		xavp_size = xavi_count(rname, NULL);
+	} else {
+		xavp_size = xavp_count(rname, NULL);
+	}
 	if(indx<0)
 	{
 		if((indx*-1)>xavp_size)
@@ -1388,13 +1593,17 @@ ki_xavp_getd_helper(sip_msg_t *msg, str *rname, int *_indx)
 		indx = xavp_size + indx;
 	}
 
-	xavp = xavp_get_by_index(rname, indx, NULL);
+	if(_case) {
+		xavp = xavi_get_by_index(rname, indx, NULL);
+	} else {
+		xavp = xavp_get_by_index(rname, indx, NULL);
+	}
 	if(xavp==NULL) {
 		sr_kemi_xval_null(&_sr_kemi_pv_xval, SR_KEMI_XVAL_NULL_NONE);
 		return &_sr_kemi_pv_xval;
 	}
 	do {
-		val = ki_xavp_dict(xavp);
+		val = ki_xav_dict(xavp, _case);
 		if(last) {
 			last->next = val;
 		} else {
@@ -1405,7 +1614,11 @@ ki_xavp_getd_helper(sip_msg_t *msg, str *rname, int *_indx)
 			xavp = NULL;
 		} else {
 			indx = indx + 1;
-			xavp = xavp_get_by_index(rname, indx, NULL);
+			if(_case) {
+				xavp = xavi_get_by_index(rname, indx, NULL);
+			} else {
+				xavp = xavp_get_by_index(rname, indx, NULL);
+			}
 		}
 	} while(xavp!=NULL);
 	return &_sr_kemi_pv_xval;
@@ -1417,7 +1630,15 @@ ki_xavp_getd_helper(sip_msg_t *msg, str *rname, int *_indx)
 static sr_kemi_xval_t*
 ki_xavp_getd(sip_msg_t *msg, str *rname)
 {
-	return ki_xavp_getd_helper(msg, rname, NULL);
+	return ki_xav_getd_helper(msg, rname, NULL, 0);
+}
+
+/**
+ *
+ */
+static sr_kemi_xval_t* ki_xavi_getd(sip_msg_t *msg, str *rname)
+{
+	return ki_xav_getd_helper(msg, rname, NULL, 1);
 }
 
 /**
@@ -1426,14 +1647,23 @@ ki_xavp_getd(sip_msg_t *msg, str *rname)
 static sr_kemi_xval_t*
 ki_xavp_getd_p1(sip_msg_t *msg, str *rname, int indx)
 {
-	return ki_xavp_getd_helper(msg, rname, &indx);
+	return ki_xav_getd_helper(msg, rname, &indx, 0);
 }
 
 /**
  *
  */
 static sr_kemi_xval_t*
-ki_xavp_get_keys(sip_msg_t *msg, str *rname, int indx) {
+ki_xavi_getd_p1(sip_msg_t *msg, str *rname, int indx)
+{
+	return ki_xav_getd_helper(msg, rname, &indx, 1);
+}
+
+/**
+ *
+ */
+static sr_kemi_xval_t*
+ki_xav_get_keys(sip_msg_t *msg, str *rname, int indx, int _case) {
 	sr_xavp_t *xavp=NULL;
 	struct str_list *keys, *k;
 	sr_kemi_dict_item_t *val;
@@ -1441,12 +1671,20 @@ ki_xavp_get_keys(sip_msg_t *msg, str *rname, int indx) {
 
 	memset(&_sr_kemi_pv_xval, 0, sizeof(sr_kemi_xval_t));
 
-	xavp = xavp_get_by_index(rname, indx, NULL);
+	if(_case) {
+		xavp = xavi_get_by_index(rname, indx, NULL);
+	} else {
+		xavp = xavp_get_by_index(rname, indx, NULL);
+	}
 	if(xavp==NULL) {
 		sr_kemi_xval_null(&_sr_kemi_pv_xval, SR_KEMI_XVAL_NULL_NONE);
 		return &_sr_kemi_pv_xval;
 	}
-	keys = xavp_get_list_key_names(xavp);
+	if(_case) {
+		keys = xavi_get_list_key_names(xavp);
+	} else {
+		keys = xavp_get_list_key_names(xavp);
+	}
 	_sr_kemi_pv_xval.vtype = SR_KEMIP_ARRAY;
 	while(keys!=NULL){
 		k = keys;
@@ -1488,18 +1726,41 @@ error:
 /**
  *
  */
-static int ki_xavp_child_is_null(sip_msg_t *msg, str *rname, str *cname)
+static sr_kemi_xval_t* ki_xavp_get_keys(sip_msg_t *msg, str *rname, int indx)
 {
-	sr_xavp_t *xavp=NULL;
+	return ki_xav_get_keys(msg, rname, indx, 0);
+}
 
-	xavp = xavp_get_by_index(rname, 0, NULL);
+/**
+ *
+ */
+static sr_kemi_xval_t* ki_xavi_get_keys(sip_msg_t *msg, str *rname, int indx)
+{
+	return ki_xav_get_keys(msg, rname, indx, 1);
+}
+
+/**
+ *
+ */
+static int ki_xav_child_is_null(sip_msg_t *msg, str *rname, str *cname, int _case)
+{
+	sr_xavp_t *xavp=NULL;
+	if(_case) {
+		xavp = xavi_get_by_index(rname, 0, NULL);
+	} else {
+		xavp = xavp_get_by_index(rname, 0, NULL);
+	}
 	if(xavp==NULL) {
 		return 1;
 	}
 	if(xavp->val.type != SR_XTYPE_XAVP) {
 		return 1;
 	}
-	xavp = xavp_get_by_index(cname, 0, &xavp->val.v.xavp);
+	if(_case) {
+		xavp = xavi_get_by_index(cname, 0, &xavp->val.v.xavp);
+	} else {
+		xavp = xavp_get_by_index(cname, 0, &xavp->val.v.xavp);
+	}
 	if(xavp==NULL) {
 		return 1;
 	}
@@ -1512,14 +1773,34 @@ static int ki_xavp_child_is_null(sip_msg_t *msg, str *rname, str *cname)
 /**
  *
  */
-static sr_kemi_xval_t* ki_xavp_child_get_mode(sip_msg_t *msg, str *rname,
-		str *cname, int rmode)
+static int ki_xavp_child_is_null(sip_msg_t *msg, str *rname, str *cname)
+{
+	return ki_xav_child_is_null(msg, rname, cname, 0);
+}
+
+/**
+ *
+ */
+static int ki_xavi_child_is_null(sip_msg_t *msg, str *rname, str *cname)
+{
+	return ki_xav_child_is_null(msg, rname, cname, 1);
+}
+
+/**
+ *
+ */
+static sr_kemi_xval_t* ki_xav_child_get_mode(sip_msg_t *msg, str *rname,
+		str *cname, int rmode, int _case)
 {
 	sr_xavp_t *xavp=NULL;
 
 	memset(&_sr_kemi_pv_xval, 0, sizeof(sr_kemi_xval_t));
 
-	xavp = xavp_get_by_index(rname, 0, NULL);
+	if(_case) {
+		xavp = xavi_get_by_index(rname, 0, NULL);
+	} else {
+		xavp = xavp_get_by_index(rname, 0, NULL);
+	}
 	if(xavp==NULL) {
 		sr_kemi_xval_null(&_sr_kemi_pv_xval, rmode);
 		return &_sr_kemi_pv_xval;
@@ -1530,7 +1811,11 @@ static sr_kemi_xval_t* ki_xavp_child_get_mode(sip_msg_t *msg, str *rname,
 		return &_sr_kemi_pv_xval;
 	}
 
-	xavp = xavp_get_by_index(cname, 0, &xavp->val.v.xavp);
+	if(_case) {
+		xavp = xavi_get_by_index(cname, 0, &xavp->val.v.xavp);
+	} else {
+		xavp = xavp_get_by_index(cname, 0, &xavp->val.v.xavp);
+	}
 	if(xavp==NULL) {
 		sr_kemi_xval_null(&_sr_kemi_pv_xval, rmode);
 		return &_sr_kemi_pv_xval;
@@ -1544,25 +1829,47 @@ static sr_kemi_xval_t* ki_xavp_child_get_mode(sip_msg_t *msg, str *rname,
  */
 static sr_kemi_xval_t* ki_xavp_child_get(sip_msg_t *msg, str *rname, str *cname)
 {
-	return ki_xavp_child_get_mode(msg, rname, cname, SR_KEMI_XVAL_NULL_NONE);
+	return ki_xav_child_get_mode(msg, rname, cname, SR_KEMI_XVAL_NULL_NONE, 0);
 }
 
+/**
+ *
+ */
+static sr_kemi_xval_t* ki_xavi_child_get(sip_msg_t *msg, str *rname, str *cname)
+{
+	return ki_xav_child_get_mode(msg, rname, cname, SR_KEMI_XVAL_NULL_NONE, 1);
+}
 
 /**
  *
  */
 static sr_kemi_xval_t* ki_xavp_child_gete(sip_msg_t *msg, str *rname, str *cname)
 {
-	return ki_xavp_child_get_mode(msg, rname, cname, SR_KEMI_XVAL_NULL_EMPTY);
+	return ki_xav_child_get_mode(msg, rname, cname, SR_KEMI_XVAL_NULL_EMPTY, 0);
 }
 
+/**
+ *
+ */
+static sr_kemi_xval_t* ki_xavi_child_gete(sip_msg_t *msg, str *rname, str *cname)
+{
+	return ki_xav_child_get_mode(msg, rname, cname, SR_KEMI_XVAL_NULL_EMPTY, 1);
+}
 
 /**
  *
  */
 static sr_kemi_xval_t* ki_xavp_child_getw(sip_msg_t *msg, str *rname, str *cname)
 {
-	return ki_xavp_child_get_mode(msg, rname, cname, SR_KEMI_XVAL_NULL_PRINT);
+	return ki_xav_child_get_mode(msg, rname, cname, SR_KEMI_XVAL_NULL_PRINT, 0);
+}
+
+/**
+ *
+ */
+static sr_kemi_xval_t* ki_xavi_child_getw(sip_msg_t *msg, str *rname, str *cname)
+{
+	return ki_xav_child_get_mode(msg, rname, cname, SR_KEMI_XVAL_NULL_PRINT, 1);
 }
 
 /**
@@ -1921,6 +2228,11 @@ static sr_kemi_t sr_kemi_pvx_exports[] = {
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
+	{ str_init("pvx"), str_init("pv_xavi_print"),
+		SR_KEMIP_INT, ki_xavi_print,
+		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
 	{ str_init("pvx"), str_init("xavp_params_explode"),
 		SR_KEMIP_INT, ki_xavp_params_explode,
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
@@ -2016,6 +2328,91 @@ static sr_kemi_t sr_kemi_pvx_exports[] = {
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
+	{ str_init("pvx"), str_init("xavi_seti"),
+		SR_KEMIP_INT, ki_xavi_seti,
+		{ SR_KEMIP_STR, SR_KEMIP_INT, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("pvx"), str_init("xavi_sets"),
+		SR_KEMIP_INT, ki_xavi_sets,
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("pvx"), str_init("xavi_get"),
+		SR_KEMIP_XVAL, ki_xavi_get,
+		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("pvx"), str_init("xavi_gete"),
+		SR_KEMIP_XVAL, ki_xavi_gete,
+		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("pvx"), str_init("xavi_getw"),
+		SR_KEMIP_XVAL, ki_xavi_getw,
+		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("pvx"), str_init("xavi_getd"),
+		SR_KEMIP_XVAL, ki_xavi_getd,
+		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("pvx"), str_init("xavi_getd_p1"),
+		SR_KEMIP_XVAL, ki_xavi_getd_p1,
+		{ SR_KEMIP_STR, SR_KEMIP_INT, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("pvx"), str_init("xavi_get_keys"),
+		SR_KEMIP_XVAL, ki_xavi_get_keys,
+		{ SR_KEMIP_STR, SR_KEMIP_INT, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("pvx"), str_init("xavi_rm"),
+		SR_KEMIP_INT, ki_xavi_rm,
+		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("pvx"), str_init("xavi_is_null"),
+		SR_KEMIP_INT, ki_xavi_is_null,
+		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("pvx"), str_init("xavi_child_seti"),
+		SR_KEMIP_INT, ki_xavi_child_seti,
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_INT,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("pvx"), str_init("xavi_child_sets"),
+		SR_KEMIP_INT, ki_xavi_child_sets,
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_STR,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("pvx"), str_init("xavi_child_rm"),
+		SR_KEMIP_INT, ki_xavi_child_rm,
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("pvx"), str_init("xavi_child_is_null"),
+		SR_KEMIP_INT, ki_xavi_child_is_null,
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("pvx"), str_init("xavi_child_get"),
+		SR_KEMIP_XVAL, ki_xavi_child_get,
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("pvx"), str_init("xavi_child_gete"),
+		SR_KEMIP_XVAL, ki_xavi_child_gete,
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
+	{ str_init("pvx"), str_init("xavi_child_getw"),
+		SR_KEMIP_XVAL, ki_xavi_child_getw,
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+	},
 	{ str_init("pvx"), str_init("evalx"),
 		SR_KEMIP_INT, ki_pv_evalx,
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
diff --git a/src/modules/pv/pv_xavp.c b/src/modules/pv/pv_xavp.c
index 9dca116..8db7a1c 100644
--- a/src/modules/pv/pv_xavp.c
+++ b/src/modules/pv/pv_xavp.c
@@ -567,6 +567,12 @@ int pv_xavp_print(sip_msg_t* msg, char* s1, char *s2)
 	return 1;
 }
 
+int pv_xavi_print(sip_msg_t* msg, char* s1, char *s2)
+{
+	xavi_print_list(NULL);
+	return 1;
+}
+
 /**
  *
  */
@@ -759,3 +765,413 @@ int pv_xavp_to_var(str *xname) {
 	} while(xavp);
 	return 1;
 }
+
+void pv_xavi_name_destroy(pv_xavp_name_t *xname)
+{
+	return;
+}
+
+int pv_parse_xavi_name(pv_spec_p sp, str *in)
+{
+	pv_xavp_name_t *xname=NULL;
+	char *p;
+	str s;
+
+	if(in->s==NULL || in->len<=0)
+		return -1;
+
+	xname = (pv_xavp_name_t*)pkg_malloc(sizeof(pv_xavp_name_t));
+	if(xname==NULL) {
+		PKG_MEM_ERROR;
+		return -1;
+	}
+
+	memset(xname, 0, sizeof(pv_xavp_name_t));
+
+	s = *in;
+
+	p = pv_xavp_fill_ni(&s, xname);
+	if(p==NULL)
+		goto error;
+
+	if(*p!='=')
+		goto done;
+	p++;
+	if(*p!='>')
+		goto error;
+	p++;
+
+	s.len = in->len - (int)(p - in->s);
+	s.s = p;
+	LM_DBG("xavi sublist [%.*s] - key [%.*s]\n", xname->name.len,
+			xname->name.s, s.len, s.s);
+
+	xname->next = (pv_xavp_name_t*)pkg_malloc(sizeof(pv_xavp_name_t));
+	if(xname->next==NULL) {
+		LM_ERR("not enough pkg mem\n");
+		goto error;
+	}
+	memset(xname->next, 0, sizeof(pv_xavp_name_t));
+
+	p = pv_xavp_fill_ni(&s, xname->next);
+	if(p==NULL)
+		goto error;
+
+done:
+	sp->pvp.pvn.u.dname = (void*)xname;
+	sp->pvp.pvn.type = PV_NAME_PVAR;
+	return 0;
+
+error:
+	if(xname!=NULL) {
+		pv_xavi_name_destroy(xname);
+		pkg_free(xname);
+	}
+	return -1;
+}
+
+int pv_get_xavi(struct sip_msg *msg, pv_param_t *param,
+		pv_value_t *res)
+{
+	pv_xavp_name_t *xname=NULL;
+	sr_xavp_t *avi=NULL;
+	int idxf = 0;
+	int idx = 0;
+	int count;
+	char *p, *p_ini;
+	int p_size;
+
+	if(param==NULL)
+	{
+		LM_ERR("bad parameters\n");
+		return -1;
+	}
+	xname = (pv_xavp_name_t*)param->pvn.u.dname;
+
+	if(xname->index.type==PVT_EXTRA)
+	{
+		/* get the index */
+		if(pv_get_spec_index(msg, &xname->index.pvp, &idx, &idxf)!=0)
+		{
+			LM_ERR("invalid index\n");
+			return -1;
+		}
+	}
+	/* fix the index */
+	if(idx<0)
+	{
+		count = xavi_count(&xname->name, NULL);
+		idx = count + idx;
+	}
+	avi = xavi_get_by_index(&xname->name, idx, NULL);
+	if(avi==NULL)
+		return pv_get_null(msg, param, res);
+	if(xname->next==NULL)
+		return pv_xavp_get_value(msg, param, res, avi);
+	if(avi->val.type != SR_XTYPE_XAVP)
+		return pv_get_null(msg, param, res);
+
+	idx = 0;
+	idxf = 0;
+	if(xname->next->index.type==PVT_EXTRA)
+	{
+		/* get the index */
+		if(pv_get_spec_index(msg, &xname->next->index.pvp, &idx, &idxf)!=0)
+		{
+			LM_ERR("invalid index\n");
+			return -1;
+		}
+	}
+	/* fix the index */
+	if(idx<0)
+	{
+		count = xavi_count(&xname->next->name, &avi->val.v.xavp);
+		idx = count + idx;
+	}
+	avi = xavi_get_by_index(&xname->next->name, idx, &avi->val.v.xavp);
+	if(avi==NULL)
+		return pv_get_null(msg, param, res);
+	/* get all values of second key */
+	if(idxf==PV_IDX_ALL)
+	{
+		p_ini = pv_get_buffer();
+		p = p_ini;
+		p_size = pv_get_buffer_size();
+		do {
+			if(p!=p_ini)
+			{
+				if(p-p_ini+PV_FIELD_DELIM_LEN+1>p_size)
+				{
+					LM_ERR("local buffer length exceeded\n");
+					return pv_get_null(msg, param, res);
+				}
+				memcpy(p, PV_FIELD_DELIM, PV_FIELD_DELIM_LEN);
+				p += PV_FIELD_DELIM_LEN;
+			}
+			if(pv_xavp_get_value(msg, param, res, avi)<0)
+			{
+				LM_ERR("can get value\n");
+				return pv_get_null(msg, param, res);
+			}
+			if(p-p_ini+res->rs.len+1>p_size)
+			{
+				LM_ERR("local buffer length exceeded!\n");
+				return pv_get_null(msg, param, res);
+			}
+			memcpy(p, res->rs.s, res->rs.len);
+			p += res->rs.len;
+		} while ((avi=xavi_get_next(avi))!=0);
+		res->rs.s = p_ini;
+		res->rs.len = p - p_ini;
+		return 0;
+	}
+	return pv_xavp_get_value(msg, param, res, avi);
+}
+
+/**
+ * $xavi(name1[idx1]=>name2[idx2])
+ */
+int pv_set_xavi(struct sip_msg* msg, pv_param_t *param,
+		int op, pv_value_t *val)
+{
+	pv_xavp_name_t *xname=NULL;
+	sr_xavp_t *avi=NULL;
+	sr_xavp_t *list=NULL;
+	sr_xval_t xval;
+	int idxf = 0;
+	int idx = 0;
+	int idxf1 = 0;
+	int idx1 = 0;
+	int count;
+
+	if(param==NULL)
+	{
+		LM_ERR("bad parameters\n");
+		return -1;
+	}
+	xname = (pv_xavp_name_t*)param->pvn.u.dname;
+
+	if(xname->index.type==PVT_EXTRA)
+	{
+		/* get the index */
+		if(pv_get_spec_index(msg, &xname->index.pvp, &idx, &idxf)!=0)
+		{
+			LM_ERR("invalid index\n");
+			return -1;
+		}
+	}
+
+	if((val==NULL) || (val->flags&PV_VAL_NULL))
+	{
+		if(xname->next==NULL)
+		{
+			if(xname->index.type==PVT_EXTRA) {
+				if(idxf==PV_IDX_ALL) {
+					xavi_rm_by_name(&xname->name, 1, NULL);
+					return 0;
+				}
+			}
+			if(idx==0) {
+				xavi_rm_by_name(&xname->name, 0, NULL);
+				return 0;
+			}
+			/* fix the index */
+			if(idx<0)
+			{
+				count = xavi_count(&xname->name, NULL);
+				idx = count + idx + 1;
+			}
+			xavi_rm_by_index(&xname->name, idx, NULL);
+			return 0;
+		}
+
+		if(xname->next->index.type==PVT_EXTRA)
+		{
+			/* get the index */
+			if(pv_get_spec_index(msg,&xname->next->index.pvp,&idx1,&idxf1)!=0)
+			{
+				LM_ERR("invalid index!\n");
+				return -1;
+			}
+		}
+
+		if(idxf==PV_IDX_ALL) {
+			/* iterate */
+			avi = xavi_get(&xname->name, NULL);
+			while(avi) {
+				if(avi->val.type==SR_XTYPE_XAVP) {
+					if(xname->next->index.type==PVT_EXTRA) {
+						if(idxf1==PV_IDX_ALL) {
+							xavi_rm_by_name(&xname->next->name, 1,
+									&avi->val.v.xavp);
+						} else {
+							/* fix the index */
+							idx = idx1;
+							if(idx<0)
+							{
+								count = xavi_count(&xname->next->name,
+										&avi->val.v.xavp);
+								idx = count + idx1 + 1;
+							}
+							xavi_rm_by_index(&xname->next->name, idx,
+									&avi->val.v.xavp);
+						}
+					} else {
+						xavi_rm_by_name(&xname->next->name, 0,
+								&avi->val.v.xavp);
+					}
+				}
+				avi = xavi_get_next(avi);
+			}
+			return 0;
+		}
+
+		if(idx==0) {
+			avi = xavi_get(&xname->name, NULL);
+		} else {
+			/* fix the index */
+			if(idx<0)
+			{
+				count = xavi_count(&xname->name, NULL);
+				idx = count + idx + 1;
+			}
+			avi = xavi_get_by_index(&xname->name, idx, NULL);
+		}
+		if(avi) {
+			if(avi->val.type==SR_XTYPE_XAVP) {
+				if(xname->next->index.type==PVT_EXTRA) {
+					if(idxf1==PV_IDX_ALL) {
+						xavi_rm_by_name(&xname->next->name, 1,
+								&avi->val.v.xavp);
+					} else {
+						/* fix the index */
+						idx = idx1;
+						if(idx<0)
+						{
+							count = xavi_count(&xname->next->name,
+									&avi->val.v.xavp);
+							idx = count + idx1 + 1;
+						}
+						xavi_rm_by_index(&xname->next->name, idx,
+								&avi->val.v.xavp);
+					}
+				} else {
+					xavi_rm_by_name(&xname->next->name, 0,
+							&avi->val.v.xavp);
+				}
+			}
+		}
+		return 0;
+	} /* NULL assignment */
+
+	/* build xavi value */
+	memset(&xval, 0, sizeof(sr_xval_t));
+
+	if(val->flags&PV_TYPE_INT)
+	{
+		xval.type = SR_XTYPE_INT;
+		xval.v.i = val->ri;
+	} else {
+		xval.type = SR_XTYPE_STR;
+		xval.v.s = val->rs;
+	}
+
+	/* where to add */
+	if(xname->next==NULL)
+	{
+		/* xavi with single value */
+		if(xname->index.type==PVT_EXTRA) {
+			if(idxf==PV_IDX_ALL) {
+				/* ignore: should iterate and set same value to all xavis
+				 * with same name?!?! */
+				return -1;
+			}
+			/* fix the index */
+			if(idx<0)
+			{
+				count = xavi_count(&xname->name, NULL);
+				idx = count + idx + 1;
+			}
+			/* set the value */
+			if(xavi_set_value(&xname->name, idx, &xval, NULL)==NULL)
+				return -1;
+			return 0;
+		}
+		/* add new value */
+		if(xavi_add_value(&xname->name, &xval, NULL)==NULL)
+			return -1;
+		return 0;
+	}
+
+	/* xavi with xavp list value */
+	if(xname->next->index.type==PVT_EXTRA)
+	{
+		/* get the index */
+		if(pv_get_spec_index(msg,&xname->next->index.pvp,&idx1,&idxf1)!=0)
+		{
+			LM_ERR("invalid index!\n");
+			return -1;
+		}
+	}
+
+	if(xname->index.type==PVT_EXTRA)
+	{
+		/* set the value */
+		if(idxf==PV_IDX_ALL) {
+			/* ignore: should iterate and set same value to all xavis
+			 * with same name?!?! */
+			return 0;
+		}
+
+		if(idx==0) {
+			avi = xavi_get(&xname->name, NULL);
+		} else {
+			/* fix the index */
+			if(idx<0)
+			{
+				count = xavi_count(&xname->name, NULL);
+				idx = count + idx + 1;
+			}
+			avi = xavi_get_by_index(&xname->name, idx, NULL);
+		}
+		if(avi==NULL)
+			return 0;
+
+		if(avi->val.type!=SR_XTYPE_XAVP)
+			return -1;
+
+		if(xname->next->index.type==PVT_EXTRA) {
+			if(idxf1==PV_IDX_ALL) {
+				/* ignore: should iterate and set same value to all xavis
+				 * with same name?!?! */
+				return 0;
+			}
+			/* fix the index */
+			idx = idx1;
+			if(idx<0)
+			{
+				count = xavi_count(&xname->next->name,
+						&avi->val.v.xavp);
+				idx = count + idx1 + 1;
+			}
+			/* set value */
+			xavi_set_value(&xname->next->name, idx, &xval, &avi->val.v.xavp);
+			return 0;
+		}
+		/* add new value in sublist */
+		if(xavi_add_value(&xname->next->name, &xval, &avi->val.v.xavp)==NULL)
+			return -1;
+		return 0;
+	}
+	/* add new xavi with xavp list */
+	if(xavi_add_value(&xname->next->name, &xval, &list)==NULL)
+		return -1;
+
+	/* build xavi value */
+	memset(&xval, 0, sizeof(sr_xval_t));
+	xval.type = SR_XTYPE_XAVP;
+	xval.v.xavp = list;
+	xavi_add_value(&xname->name, &xval, NULL);
+
+	return 0;
+}
diff --git a/src/modules/pv/pv_xavp.h b/src/modules/pv/pv_xavp.h
index 35c4109..b9e7de6 100644
--- a/src/modules/pv/pv_xavp.h
+++ b/src/modules/pv/pv_xavp.h
@@ -26,7 +26,14 @@ int pv_set_xavp(struct sip_msg* msg, pv_param_t *param,
 		int op, pv_value_t *val);
 int pv_parse_xavp_name(pv_spec_p sp, str *in);
 
+int pv_get_xavi(struct sip_msg *msg, pv_param_t *param,
+		pv_value_t *res);
+int pv_set_xavi(struct sip_msg* msg, pv_param_t *param,
+		int op, pv_value_t *val);
+int pv_parse_xavi_name(pv_spec_p sp, str *in);
+
 int pv_xavp_print(struct sip_msg* msg, char* s1, char *s2);
+int pv_xavi_print(struct sip_msg* msg, char* s1, char *s2);
 
 int xavp_params_explode(str *params, str *xname);
 
