|
@@ -0,0 +1,518 @@
|
|
|
+/**
|
|
|
+ * $Id$
|
|
|
+ *
|
|
|
+ * Copyright (C) 2009 Daniel-Constantin Mierla (asipto.com)
|
|
|
+ *
|
|
|
+ * Permission to use, copy, modify, and distribute this software for any
|
|
|
+ * purpose with or without fee is hereby granted, provided that the above
|
|
|
+ * copyright notice and this permission notice appear in all copies.
|
|
|
+ *
|
|
|
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
+ */
|
|
|
+
|
|
|
+#ifdef WITH_XAVP
|
|
|
+
|
|
|
+#include <stdio.h>
|
|
|
+
|
|
|
+#include "../../dprint.h"
|
|
|
+#include "../../xavp.h"
|
|
|
+
|
|
|
+#include "pv_xavp.h"
|
|
|
+
|
|
|
+int pv_xavp_get_value(struct sip_msg *msg, pv_param_t *param,
|
|
|
+ pv_value_t *res, sr_xavp_t *avp)
|
|
|
+{
|
|
|
+ static char _pv_xavp_buf[128];
|
|
|
+ str s;
|
|
|
+
|
|
|
+ switch(avp->val.type) {
|
|
|
+ case SR_XTYPE_NULL:
|
|
|
+ return pv_get_null(msg, param, res);
|
|
|
+ break;
|
|
|
+ case SR_XTYPE_INT:
|
|
|
+ return pv_get_sintval(msg, param, res, avp->val.v.i);
|
|
|
+ break;
|
|
|
+ case SR_XTYPE_STR:
|
|
|
+ return pv_get_strval(msg, param, res, &avp->val.v.s);
|
|
|
+ break;
|
|
|
+ case SR_XTYPE_TIME:
|
|
|
+ if(snprintf(_pv_xavp_buf, 128, "%lu", avp->val.v.t)<0)
|
|
|
+ return pv_get_null(msg, param, res);
|
|
|
+ break;
|
|
|
+ case SR_XTYPE_LONG:
|
|
|
+ if(snprintf(_pv_xavp_buf, 128, "%ld", avp->val.v.l)<0)
|
|
|
+ return pv_get_null(msg, param, res);
|
|
|
+ break;
|
|
|
+ case SR_XTYPE_LLONG:
|
|
|
+ if(snprintf(_pv_xavp_buf, 128, "%lld", avp->val.v.ll)<0)
|
|
|
+ return pv_get_null(msg, param, res);
|
|
|
+ break;
|
|
|
+ case SR_XTYPE_XAVP:
|
|
|
+ if(snprintf(_pv_xavp_buf, 128, "<<xavp:%p>>", avp->val.v.xavp)<0)
|
|
|
+ return pv_get_null(msg, param, res);
|
|
|
+ break;
|
|
|
+ case SR_XTYPE_DATA:
|
|
|
+ if(snprintf(_pv_xavp_buf, 128, "<<data:%p>>", avp->val.v.data)<0)
|
|
|
+ return pv_get_null(msg, param, res);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return pv_get_null(msg, param, res);
|
|
|
+ }
|
|
|
+ s.s = _pv_xavp_buf;
|
|
|
+ s.len = strlen(_pv_xavp_buf);
|
|
|
+ return pv_get_strval(msg, param, res, &s);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int pv_get_xavp(struct sip_msg *msg, pv_param_t *param,
|
|
|
+ pv_value_t *res)
|
|
|
+{
|
|
|
+ pv_xavp_name_t *xname=NULL;
|
|
|
+ sr_xavp_t *avp=NULL;
|
|
|
+ int idxf = 0;
|
|
|
+ int idx = 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /* fix the index */
|
|
|
+ if(idx<0)
|
|
|
+ {
|
|
|
+ count = xavp_count(&xname->name, NULL);
|
|
|
+ idx = count + idx + 1;
|
|
|
+ }
|
|
|
+ avp = xavp_get_by_index(&xname->name, idx, NULL);
|
|
|
+ if(avp==NULL)
|
|
|
+ return pv_get_null(msg, param, res);
|
|
|
+ if(xname->next==NULL)
|
|
|
+ return pv_xavp_get_value(msg, param, res, avp);
|
|
|
+
|
|
|
+ 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 = xavp_count(&xname->next->name, &avp->val.v.xavp);
|
|
|
+ idx = count + idx + 1;
|
|
|
+ }
|
|
|
+ avp = xavp_get_by_index(&xname->next->name, idx, &avp->val.v.xavp);
|
|
|
+ if(avp==NULL)
|
|
|
+ return pv_get_null(msg, param, res);
|
|
|
+ return pv_xavp_get_value(msg, param, res, avp);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * $xavp(name1[idx1]=>name2[idx2])
|
|
|
+ */
|
|
|
+int pv_set_xavp(struct sip_msg* msg, pv_param_t *param,
|
|
|
+ int op, pv_value_t *val)
|
|
|
+{
|
|
|
+ pv_xavp_name_t *xname=NULL;
|
|
|
+ sr_xavp_t *avp=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) {
|
|
|
+ xavp_rm_by_name(&xname->name, 1, NULL);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(idx==0) {
|
|
|
+ xavp_rm_by_name(&xname->name, 0, NULL);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ /* fix the index */
|
|
|
+ if(idx<0)
|
|
|
+ {
|
|
|
+ count = xavp_count(&xname->name, NULL);
|
|
|
+ idx = count + idx + 1;
|
|
|
+ }
|
|
|
+ xavp_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 */
|
|
|
+ avp = xavp_get(&xname->name, NULL);
|
|
|
+ while(avp) {
|
|
|
+ if(avp->val.type==SR_XTYPE_XAVP) {
|
|
|
+ if(xname->next->index.type==PVT_EXTRA) {
|
|
|
+ if(idxf1==PV_IDX_ALL) {
|
|
|
+ xavp_rm_by_name(&xname->next->name, 1,
|
|
|
+ &avp->val.v.xavp);
|
|
|
+ } else {
|
|
|
+ /* fix the index */
|
|
|
+ idx = idx1;
|
|
|
+ if(idx<0)
|
|
|
+ {
|
|
|
+ count = xavp_count(&xname->next->name,
|
|
|
+ &avp->val.v.xavp);
|
|
|
+ idx = count + idx1 + 1;
|
|
|
+ }
|
|
|
+ xavp_rm_by_index(&xname->next->name, idx,
|
|
|
+ &avp->val.v.xavp);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ xavp_rm_by_name(&xname->next->name, 0,
|
|
|
+ &avp->val.v.xavp);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ avp = xavp_get_next(avp);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(idx==0) {
|
|
|
+ avp = xavp_get(&xname->name, NULL);
|
|
|
+ } else {
|
|
|
+ /* fix the index */
|
|
|
+ if(idx<0)
|
|
|
+ {
|
|
|
+ count = xavp_count(&xname->name, NULL);
|
|
|
+ idx = count + idx + 1;
|
|
|
+ }
|
|
|
+ avp = xavp_get_by_index(&xname->name, idx, NULL);
|
|
|
+ }
|
|
|
+ if(avp) {
|
|
|
+ if(avp->val.type==SR_XTYPE_XAVP) {
|
|
|
+ if(xname->next->index.type==PVT_EXTRA) {
|
|
|
+ if(idxf1==PV_IDX_ALL) {
|
|
|
+ xavp_rm_by_name(&xname->next->name, 1,
|
|
|
+ &avp->val.v.xavp);
|
|
|
+ } else {
|
|
|
+ /* fix the index */
|
|
|
+ idx = idx1;
|
|
|
+ if(idx<0)
|
|
|
+ {
|
|
|
+ count = xavp_count(&xname->next->name,
|
|
|
+ &avp->val.v.xavp);
|
|
|
+ idx = count + idx1 + 1;
|
|
|
+ }
|
|
|
+ xavp_rm_by_index(&xname->next->name, idx,
|
|
|
+ &avp->val.v.xavp);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ xavp_rm_by_name(&xname->next->name, 0,
|
|
|
+ &avp->val.v.xavp);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ } /* NULL assignment */
|
|
|
+
|
|
|
+ /* build xavp 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)
|
|
|
+ {
|
|
|
+ /* xavp with single value */
|
|
|
+ if(xname->index.type==PVT_EXTRA) {
|
|
|
+ if(idxf==PV_IDX_ALL) {
|
|
|
+ /* ignore: should iterate and set same value to all xavps
|
|
|
+ * with same name?!?! */
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ /* fix the index */
|
|
|
+ if(idx<0)
|
|
|
+ {
|
|
|
+ count = xavp_count(&xname->name, NULL);
|
|
|
+ idx = count + idx + 1;
|
|
|
+ }
|
|
|
+ /* set the value */
|
|
|
+ if(xavp_set_value(&xname->name, idx, &xval, NULL)==NULL)
|
|
|
+ return -1;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ /* add new value */
|
|
|
+ if(xavp_add_value(&xname->name, &xval, NULL)==NULL)
|
|
|
+ return -1;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* xavp 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 xavps
|
|
|
+ * with same name?!?! */
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(idx==0) {
|
|
|
+ avp = xavp_get(&xname->name, NULL);
|
|
|
+ } else {
|
|
|
+ /* fix the index */
|
|
|
+ if(idx<0)
|
|
|
+ {
|
|
|
+ count = xavp_count(&xname->name, NULL);
|
|
|
+ idx = count + idx + 1;
|
|
|
+ }
|
|
|
+ avp = xavp_get_by_index(&xname->name, idx, NULL);
|
|
|
+ }
|
|
|
+ if(avp==NULL)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if(avp->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 xavps
|
|
|
+ * with same name?!?! */
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ /* fix the index */
|
|
|
+ idx = idx1;
|
|
|
+ if(idx<0)
|
|
|
+ {
|
|
|
+ count = xavp_count(&xname->next->name,
|
|
|
+ &avp->val.v.xavp);
|
|
|
+ idx = count + idx1 + 1;
|
|
|
+ }
|
|
|
+ /* set value */
|
|
|
+ xavp_set_value(&xname->next->name, idx, &xval, &avp->val.v.xavp);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ /* add new value in sublist */
|
|
|
+ if(xavp_add_value(&xname->next->name, &xval, &avp->val.v.xavp)==NULL)
|
|
|
+ return -1;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ /* add new xavp with xavp list */
|
|
|
+ if(xavp_add_value(&xname->next->name, &xval, &list)==NULL)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ /* build xavp value */
|
|
|
+ memset(&xval, 0, sizeof(sr_xval_t));
|
|
|
+ xval.type = SR_XTYPE_XAVP;
|
|
|
+ xval.v.xavp = list;
|
|
|
+ xavp_add_value(&xname->name, &xval, NULL);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+char* pv_xavp_fill_ni(str *in, pv_xavp_name_t *xname)
|
|
|
+{
|
|
|
+ char *p;
|
|
|
+ str idx;
|
|
|
+ int n;
|
|
|
+
|
|
|
+ if(in->s==NULL || in->len<=0 || xname==NULL)
|
|
|
+ return NULL;
|
|
|
+ p = in->s;
|
|
|
+
|
|
|
+ /* eat ws */
|
|
|
+ while(p<in->s+in->len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
|
|
|
+ p++;
|
|
|
+ if(p>in->s+in->len || *p=='\0')
|
|
|
+ goto error;
|
|
|
+ xname->name.s = p;
|
|
|
+ while(p < in->s + in->len)
|
|
|
+ {
|
|
|
+ if(*p=='=' || *p==' ' || *p=='\t' || *p=='\n' || *p=='\r' || *p=='[')
|
|
|
+ break;
|
|
|
+ p++;
|
|
|
+ }
|
|
|
+ xname->name.len = p - xname->name.s;
|
|
|
+ if(p>in->s+in->len || *p=='\0')
|
|
|
+ return p;
|
|
|
+ /* eat ws */
|
|
|
+ while(p<in->s+in->len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
|
|
|
+ p++;
|
|
|
+ if(p>in->s+in->len || *p=='\0')
|
|
|
+ return p;
|
|
|
+
|
|
|
+ if(*p!='[')
|
|
|
+ return p;
|
|
|
+ /* there is index */
|
|
|
+ p++;
|
|
|
+ idx.s = p;
|
|
|
+ n = 0;
|
|
|
+ while(p<in->s+in->len && *p!='\0')
|
|
|
+ {
|
|
|
+ if(*p==']')
|
|
|
+ {
|
|
|
+ if(n==0)
|
|
|
+ break;
|
|
|
+ n--;
|
|
|
+ }
|
|
|
+ if(*p == '[')
|
|
|
+ n++;
|
|
|
+ p++;
|
|
|
+ }
|
|
|
+ if(p>in->s+in->len || *p=='\0')
|
|
|
+ goto error;
|
|
|
+
|
|
|
+ if(p==idx.s)
|
|
|
+ {
|
|
|
+ LM_ERR("xavp [\"%.*s\"] does not get empty index param\n",
|
|
|
+ in->len, in->s);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ idx.len = p - idx.s;
|
|
|
+ if(pv_parse_index(&xname->index, &idx)!=0)
|
|
|
+ {
|
|
|
+ LM_ERR("idx \"%.*s\" has an invalid index param [%.*s]\n",
|
|
|
+ in->len, in->s, idx.len, idx.s);
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ xname->index.type = PVT_EXTRA;
|
|
|
+ p++;
|
|
|
+ return p;
|
|
|
+error:
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+void pv_xavp_name_destroy(pv_xavp_name_t *xname)
|
|
|
+{
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+int pv_parse_xavp_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)
|
|
|
+ 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("xavp 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)
|
|
|
+ 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_xavp_name_destroy(xname);
|
|
|
+ pkg_free(xname);
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+int pv_xavp_print(struct sip_msg* msg, char* s1, char *s2)
|
|
|
+{
|
|
|
+ xavp_print_list(NULL);
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|