فهرست منبع

Merge commit 'origin/andrei/fixups'

* commit 'origin/andrei/fixups':
  avp: comments fix
  fixups: added kamailio compatible fixups
  fixups: support for PVE & PVS in get_*_fparam()
  fixups: fix param function using a param type mask
  fixups: generic fixups work now on kamailio pvars
  select: comments for parse_select()
  avp: minor fixes & comments
  sr_module: identing and whitespace
Andrei Pelinescu-Onciul 16 سال پیش
والد
کامیت
d8d8f53af2
7فایلهای تغییر یافته به همراه842 افزوده شده و 255 حذف شده
  1. 236 0
      mod_fix.c
  2. 123 0
      mod_fix.h
  3. 51 3
      select.c
  4. 369 238
      sr_module.c
  5. 23 11
      sr_module.h
  6. 39 2
      usr_avp.c
  7. 1 1
      usr_avp.h

+ 236 - 0
mod_fix.c

@@ -0,0 +1,236 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2008 iptelorg GmbH
+ *
+ * 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.
+ */
+/**
+ * @file mod_fix.c
+ * @brief kamailio compatible fixups
+ */
+/* 
+ * History:
+ * --------
+ *  2008-11-25  initial version (andrei)
+ */
+
+#include "mod_fix.h"
+#include "mem/mem.h"
+
+
+
+#if 0
+/* TODO: */
+int fixup_regexpNL_null(void** param, int param_no); /* not used */
+int fixup_regexpNL_none(void** param, int param_no); /* textops */
+#endif
+
+
+
+#define FREE_FIXUP_FP(suffix, minp, maxp) \
+	int fixup_free_##suffix(void** param, int param_no) \
+	{ \
+		if ((param_no > (maxp)) || (param_no < (minp))) \
+			return E_UNSPEC; \
+		if (*param){ \
+			fparam_free_contents((fparam_t*)*param); \
+			pkg_free(*param); \
+			*param=0; \
+		} \
+		return 0; \
+	}
+
+
+/** macro for declaring a fixup and the corresponding free_fixup
+  * for a function which fixes to fparam_t and expects 2 different types.
+  *
+  * The result (in *param) will be a fparam_t.
+  *
+  * @param suffix - function suffix (fixup_ will be pre-pended to it 
+  * @param minp - minimum parameter number acceptable
+  * @param maxp - maximum parameter number
+  * @param no1 -  number of parameters of type1
+  * @param type1 - fix_param type for the 1st param
+  * @paran type2 - fix_param type for all the other params
+  */
+#define FIXUP_F2FP(suffix, minp, maxp, no1, type1, type2) \
+	int fixup_##suffix (void** param, int param_no) \
+	{ \
+		if ((param_no > (maxp)) || (param_no <(minp))) \
+			return E_UNSPEC; \
+		if (param_no <= (no1)){ \
+			if (fix_param_types((type1), param)!=0) {\
+				ERR("Cannot convert function parameter %d to" #type1 "\n", \
+						param_no);\
+				return E_UNSPEC; \
+			} \
+		}else{ \
+			if (fix_param_types((type2), param)!=0) {\
+				ERR("Cannot convert function parameter %d to" #type2 "\n", \
+						param_no); \
+				return E_UNSPEC; \
+			} \
+		}\
+		return 0; \
+	} \
+	FREE_FIXUP_FP(suffix, minp, maxp)
+
+
+/** macro for declaring a fixup and the corresponding free_fixup
+  * for a function which fixes directly to the requested type.
+  *
+  * @see FIXUP_F2FP for the parameters
+  * Side effect: declares also some _fp_helper functions
+  */
+#define FIXUP_F2T(suffix, minp, maxp, no1, type1, type2) \
+	FIXUP_F2FP(fp_##suffix, minp, maxp, no1, type1, type2) \
+	int fixup_##suffix (void** param, int param_no) \
+	{ \
+		int ret; \
+		if ((ret=fixup_fp_##suffix (param, param_no))!=0) \
+			return ret; \
+		*param=&((fparam_t*)*param)->v; \
+		return 0; \
+	} \
+	int fixup_free_##suffix (void** param, int param_no) \
+	{ \
+		void* p; \
+		int ret; \
+		if (param && *param){ \
+			p=*param - (long)&((fparam_t*)0)->v; \
+			if ((ret=fixup_free_fp_##suffix(&p, param_no))==0) *param=p; \
+			return ret; \
+		} \
+		return 0; \
+	}
+
+
+/** macro for declaring a fixup and the corresponding free_fixup
+  * for a function expecting first no1 params as fparamt_t and the
+  * rest as direct type.
+  *
+  * @see FIXUP_F2FP for the parameters with the exception
+  * that only the first no1 parameters are converted to 
+  * fparamt_t and the rest directly to the correponding type
+  *
+  * Side effect: declares also some _fpt_helper functions
+  */
+#define FIXUP_F2FP_T(suffix, minp, maxp, no1, type1, type2) \
+	FIXUP_F2FP(fpt_##suffix, minp, maxp, no1, type1, type2) \
+	int fixup_##suffix (void** param, int param_no) \
+	{ \
+		int ret; \
+		if ((ret=fixup_fpt_##suffix(param, param_no))!=0) \
+			return ret; \
+		if (param_no>(no1)) *param=&((fparam_t*)*param)->v; \
+		return 0; \
+	} \
+	int fixup_free_##suffix (void** param, int param_no) \
+	{ \
+		void* p; \
+		int ret; \
+		if (param && *param){ \
+			p=(param_no>(no1))? *param - (long)&((fparam_t*)0)->v : *param;\
+			if ((ret=fixup_free_fpt_##suffix(&p, param_no))==0) *param=0; \
+			return ret; \
+		} \
+		return 0; \
+	}
+
+
+/** macro for declaring a fixup which fixes all the paremeters to the same
+  * type.
+  *
+  * @see FIXUP_F2T.
+  */
+#define FIXUP_F1T(suffix, minp, maxp, type) \
+	FIXUP_F2T(suffix, minp, maxp, maxp, type, 0)
+
+
+
+FIXUP_F1T(str_null, 1, 1, FPARAM_STR)
+FIXUP_F1T(str_str, 1, 2,  FPARAM_STR)
+
+/* TODO: int can be converted in place, no need for pkg_malloc'ed fparam_t*/
+FIXUP_F1T(uint_null, 1, 1, FPARAM_INT)
+FIXUP_F1T(uint_uint, 1, 2, FPARAM_INT)
+
+FIXUP_F1T(regexp_null, 1, 1, FPARAM_REGEX)
+
+FIXUP_F1T(pvar_null, 1, 1, FPARAM_PVS)
+FIXUP_F1T(pvar_pvar, 1, 2, FPARAM_PVS)
+
+FIXUP_F2T(pvar_str, 1, 2, 1, FPARAM_PVS, FPARAM_STR)
+FIXUP_F2T(pvar_str_str, 1, 3, 1, FPARAM_PVS, FPARAM_STR)
+
+FIXUP_F2FP(igp_null, 1, 1, 1, FPARAM_INT|FPARAM_PVS, 0)
+FIXUP_F2FP(igp_igp, 1, 2, 2,  FPARAM_INT|FPARAM_PVS, 0)
+
+FIXUP_F2FP_T(igp_pvar_pvar, 1, 3, 1, FPARAM_INT|FPARAM_PVS, FPARAM_PVS)
+
+/** macro for declaring a spve fixup and the corresponding free_fixup
+  * for a function expecting first no1 params as fparam converted spve 
+  * and the * rest as direct type.
+  *
+  * @see FIXUP_F2FP for the parameters with the exception
+  * that the first no1 parameters are converted to fparam_t from spve
+  * and the rest directly to the corresponding type
+  *
+  * Side effect: declares also some _spvet_helper functions
+  */
+#define FIXUP_F_SPVE_T(suffix, minp, maxp, no1, type2) \
+	FIXUP_F1T(spvet_##suffix, minp, maxp, type2) \
+	int fixup_##suffix (void** param, int param_no) \
+	{ \
+		int ret; \
+		char * bkp; \
+		fparam_t* fp; \
+		bkp=*param; \
+		if (param_no<=(no1)){ \
+			if ((ret=fix_param_types(FPARAM_PVE, param))<0){ \
+				ERR("Cannot convert function parameter %d to" #type2 "\n", \
+						param_no);\
+				return E_UNSPEC; \
+			} else{ \
+				fp=(fparam_t*)*param; \
+				if ((ret==0) && (fp->v.pve->spec.getf==0)){ \
+					fparam_free_contents(fp); \
+					pkg_free(fp); \
+					*param=bkp; \
+					return fix_param_types(FPARAM_STR, param); \
+				} else if (ret==1) \
+					return fix_param_types(FPARAM_STR, param); \
+				return ret; \
+			} \
+		} else return fixup_spvet_##suffix(param, param_no); \
+		return 0; \
+	} \
+	int fixup_free_##suffix (void** param, int param_no) \
+	{ \
+		if (param && *param){ \
+			if (param_no<=(no1)){ \
+				fparam_free_contents((fparam_t*)*param); \
+				pkg_free(*param); \
+				*param=0; \
+			} else \
+				return fixup_free_spvet_##suffix(param, param_no); \
+		} \
+		return 0; \
+	}
+
+
+FIXUP_F_SPVE_T(spve_spve, 1, 2, 2, 0)
+FIXUP_F_SPVE_T(spve_uint, 1, 2, 2, FPARAM_INT)
+FIXUP_F_SPVE_T(spve_str, 1, 2, 2, FPARAM_STR)
+

+ 123 - 0
mod_fix.h

@@ -0,0 +1,123 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2008 iptelorg GmbH
+ *
+ * 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.
+ */
+/**
+ * @file mod_fix.h
+ * @brief Generic fixup functions for module function parameter.
+ * (kamailio compatibility)
+ */
+
+#ifndef _mod_fix_h_
+#define _mod_fix_h_
+
+#include "sr_module.h"
+#include "pvar.h"
+
+#define GPARAM_TYPE_INT		FPARAM_INT
+#define GPARAM_TYPE_STR		FPARAM_STR
+#define GPARAM_TYPE_PVS		FPARAM_PVS
+#define GPARAM_TYPE_PVE		FPARAM_PVE
+
+/**
+ * generic parameter that holds a string, an int, a pseudo-variable
+ * or a ser select, avp, or subst.
+ * 
+ * Note: used only for compatibility with existing kamailio code,
+ *  please use fparam_t directly in the future.
+ *
+ * @see fparam_t
+ */
+
+/* reuse ser fparam_t */
+#define gparam_t fparam_t
+
+typedef gparam_t *gparam_p;
+
+int fixup_get_svalue(struct sip_msg* msg, gparam_p gp, str *val);
+
+/** get a string value out of a fparam_t.
+  *
+  * Note: this macro/function is  for kamailio compatibility
+  * (please use get_str_fparam() directly in the future)
+  *
+  * @param msg  - pointer to the sip message
+  * @param fp   - pointer to the fparam_t
+  * @param sval - pointer to str, used to store the result
+  * @return  0 on success, -1 on error
+  */
+#define fixup_get_svalue(msg, fp, sval) get_str_fparam(sval, msg, fp)
+
+/** get an int value out of a fparam_t.
+  *
+  * Note: this macro/function is  for kamailio compatibility
+  * (please use get_int_fparam() directly in the future)
+  *
+  * @param msg  - pointer to the sip message
+  * @param fp   - pointer to the fparam_t
+  * @param ival - pointer to str, used to store the result
+  * @return  0 on success, -1 on error
+  */
+#define fixup_get_ivalue(msg, fp, ival) get_int_fparam(ival, msg, fp)
+
+int fixup_str_null(void** param, int param_no);
+int fixup_str_str(void** param, int param_no);
+
+int fixup_free_str_null(void** param, int param_no);
+int fixup_free_str_str(void** param, int param_no);
+
+int fixup_uint_null(void** param, int param_no);
+int fixup_uint_uint(void** param, int param_no);
+
+
+int fixup_regexp_null(void** param, int param_no);
+int fixup_free_regexp_null(void** param, int param_no);
+int fixup_regexp_none(void** param, int param_no);
+int fixup_free_regexp_none(void** param, int param_no);
+#if 0
+/* not implemened yet */
+int fixup_regexpNL_null(void** param, int param_no);
+int fixup_regexpNL_none(void** param, int param_no);
+#endif
+
+int fixup_pvar_null(void **param, int param_no);
+int fixup_free_pvar_null(void** param, int param_no);
+
+int fixup_pvar_pvar(void **param, int param_no);
+int fixup_free_pvar_pvar(void** param, int param_no);
+
+int fixup_pvar_str(void** param, int param_no);
+int fixup_free_pvar_str(void** param, int param_no);
+
+int fixup_pvar_str_str(void** param, int param_no);
+int fixup_free_pvar_str_str(void** param, int param_no);
+
+int fixup_igp_igp(void** param, int param_no);
+int fixup_igp_null(void** param, int param_no);
+int fixup_get_ivalue(struct sip_msg* msg, gparam_p gp, int *val);
+
+int fixup_igp_pvar_pvar(void** param, int param_no);
+int fixup_free_igp_pvar_pvar(void** param, int param_no);
+
+int fixup_spve_spve(void** param, int param_no);
+int fixup_spve_null(void** param, int param_no);
+int fixup_spve_uint(void** param, int param_no);
+int fixup_spve_str(void** param, int param_no);
+
+
+int fixup_pvar(void **param);
+
+#endif

+ 51 - 3
select.c

@@ -60,11 +60,30 @@ static select_table_t *select_list = &select_core_table;
  */
 int select_level = 0;
 
-/*
+/** parse a select identifier (internal version)
  * Parse select string into select structure s
- * moves pointer p to the first unused char
+ * moves pointer p to the first unused char.
+ *
+ * The select identifier must be of the form:
+ *   [@] <sel_id> [ '.' <sel_id> ...]
+ *   
+ * Where 
+ *       <sel_id> = <id> |
+ *                  <id> '[' <idx> ']'
+ *       <id> = [a-zA-Z0-9_]+
+ *       <idx> = <number> | <string>
+ *       <string> = '"' <ascii> '"' | 
+ *                  '\"' <ascii> '\"'
+ *
+ * Examples:
+ *     @to.tag
+ *     @hf_value["contact"]
+ *     @msg.header["SER-Server-ID"]
+ *     @eval.pop[-1]
+ *     contact.uri.params.maddr
+ *     cfg_get.rtp_proxy.enabled 
  *
- * Returns -1 error
+ * @return -1 error
  *			  p points to the first unconsumed char
  *          0 success
  *			  p points to the first unconsumed char
@@ -148,6 +167,35 @@ error:
 	return -1;
 }
 
+
+/** parse a select identifier.
+ * Parse select string into select structure s and
+ * moves pointer p to the first unused char.
+ * 
+ * The select identifier must be of the form:
+ *   [@] <sel_id> [ '.' <sel_id> ...]
+ *   
+ * Where 
+ *       <sel_id> = <id> |
+ *                  <id> '[' <idx> ']'
+ *       <id> = [a-zA-Z0-9_]+
+ *       <idx> = <number>  | '-' <number> | <string>
+ *       <string> = '"' <ascii> '"' | 
+ *                  '\"' <ascii> '\"'
+ *
+ * Examples:
+ *     @to.tag
+ *     @hf_value["contact"]
+ *     @msg.header["SER-Server-ID"]
+ *     @eval.pop[-1]
+ *     contact.uri.params.maddr
+ *     cfg_get.rtp_proxy.enabled 
+  *
+  * @param p - double string (asciiz) pointer, *p is moved to the first char
+  *            after the select identifier
+  * @param s - the result will be stored here
+  * @return  < 0 on error, 0 on success
+  */
 int parse_select (char** p, select_t** s)
 {
 	select_t* sel;

+ 369 - 238
sr_module.c

@@ -38,6 +38,7 @@
  *  2006-02-07  added fix_flag (andrei)
  *  2008-02-29  store all the reponse callbacks in their own array (andrei)
  *  2008-11-17  support dual module interface: ser & kamailio (andrei)
+ *  2008-11-26  added fparam_free_contents() and fix_param_types (andrei)
  */
 
 
@@ -897,14 +898,17 @@ int init_modules(void)
 #endif
 
 
-action_u_t *fixup_get_param(void **cur_param, int cur_param_no, int required_param_no) {
+action_u_t *fixup_get_param(void **cur_param, int cur_param_no,
+							int required_param_no)
+{
 	action_u_t *a, a2;
 	/* cur_param points to a->u.string, get pointer to a */
 	a = (void*) ((char *)cur_param - ((char *)&a2.u.string-(char *)&a2));
 	return a + required_param_no - cur_param_no;
 }
 
-int fixup_get_param_count(void **cur_param, int cur_param_no) {
+int fixup_get_param_count(void **cur_param, int cur_param_no)
+{
 	action_u_t *a;
 	a = fixup_get_param(cur_param, cur_param_no, 0);
 	if (a)
@@ -972,125 +976,226 @@ int fix_flag( modparam_t type, void* val,
  * Common function parameter fixups
  */
 
-/*
- * Generic parameter fixup function which creates
- * fparam_t structure. type parameter contains allowed
- * parameter types
+/** Generic parameter fixup function.
+ *  Creates a fparam_t structure.
+ *  @param type  contains allowed parameter types
+ *  @param param is the parameter that will be fixed-up
  *
- * Returns:
+ * @return
  *    0 on success, 
  *    1 if the param doesn't match the specified type
  *    <0 on failure
  */
 int fix_param(int type, void** param)
 {
-    fparam_t* p;
-    str name, s;
-    unsigned int num;
-    int err;
-
-    p = (fparam_t*)pkg_malloc(sizeof(fparam_t));
-    if (!p) {
-	ERR("No memory left\n");
-	return E_OUT_OF_MEM;
-    }
-    memset(p, 0, sizeof(fparam_t));
-    p->orig = *param;
-
-    switch(type) {
-    case FPARAM_UNSPEC:
-	ERR("Invalid type value\n");
-	goto error;
-
-    case FPARAM_STRING:
-	p->v.asciiz = *param;
-	break;
-
-    case FPARAM_STR:
-	p->v.str.s = (char*)*param;
-	p->v.str.len = strlen(p->v.str.s);
-	break;
-
-    case FPARAM_INT:
-	s.s = (char*)*param;
-	s.len = strlen(s.s);
-	err = str2int(&s, &num);
-	if (err == 0) {
-	    p->v.i = (int)num;
-	} else {
-	    /* Not a number */
-	    pkg_free(p);
-	    return 1;
-	}
-	break;
+	fparam_t* p;
+	str name, s;
+	unsigned int num;
+	int err;
 
-    case FPARAM_REGEX:
-	if ((p->v.regex = pkg_malloc(sizeof(regex_t))) == 0) {
-	    ERR("No memory left\n");
-	    goto error;
-	}
-	if (regcomp(p->v.regex, *param, REG_EXTENDED|REG_ICASE|REG_NEWLINE)) {
-	    pkg_free(p->v.regex);
-	    ERR("Bad regular expression '%s'\n", (char*)*param);
-	    goto error;
+	p = (fparam_t*)pkg_malloc(sizeof(fparam_t));
+	if (!p) {
+		ERR("No memory left\n");
+		return E_OUT_OF_MEM;
 	}
-	break;
-
-    case FPARAM_AVP:
-	name.s = (char*)*param;
-	name.len = strlen(name.s);
-	trim(&name);
-	if (!name.len || name.s[0] != '$') {
-	    /* Not an AVP identifier */
-	    pkg_free(p);
-	    return 1;
+	memset(p, 0, sizeof(fparam_t));
+	p->orig = *param;
+	
+	switch(type) {
+		case FPARAM_UNSPEC:
+			ERR("Invalid type value\n");
+			goto error;
+		case FPARAM_STRING:
+			p->v.asciiz = *param;
+		
+		case FPARAM_STR:
+			p->v.str.s = (char*)*param;
+			p->v.str.len = strlen(p->v.str.s);
+			break;
+		case FPARAM_INT:
+			s.s = (char*)*param;
+			s.len = strlen(s.s);
+			err = str2int(&s, &num);
+			if (err == 0) {
+				p->v.i = (int)num;
+			} else {
+				/* Not a number */
+				pkg_free(p);
+				return 1;
+			}
+			break;
+		case FPARAM_REGEX:
+			if ((p->v.regex = pkg_malloc(sizeof(regex_t))) == 0) {
+				ERR("No memory left\n");
+			goto error;
+			}
+			if (regcomp(p->v.regex, *param,
+						REG_EXTENDED|REG_ICASE|REG_NEWLINE)) {
+				pkg_free(p->v.regex);
+				p->v.regex=0;
+				ERR("Bad regular expression '%s'\n", (char*)*param);
+				goto error;
+			}
+			break;
+		case FPARAM_AVP:
+			name.s = (char*)*param;
+			name.len = strlen(name.s);
+			trim(&name);
+			if (!name.len || name.s[0] != '$') {
+				/* Not an AVP identifier */
+				pkg_free(p);
+				return 1;
+			}
+			name.s++;
+			name.len--;
+			if (parse_avp_ident(&name, &p->v.avp) < 0) {
+				ERR("Error while parsing attribute name\n");
+				goto error;
+			}
+			break;
+		case FPARAM_SELECT:
+			name.s = (char*)*param;
+			name.len = strlen(name.s);
+			trim(&name);
+			if (!name.len || name.s[0] != '@') {
+				/* Not a select identifier */
+				pkg_free(p);
+				return 1;
+			}
+			if (parse_select(&name.s, &p->v.select) < 0) {
+				ERR("Error while parsing select identifier\n");
+				goto error;
+			}
+			break;
+		case FPARAM_SUBST:
+			s.s = *param;
+			s.len = strlen(s.s);
+			p->v.subst = subst_parser(&s);
+			if (!p->v.subst) {
+				ERR("Error while parsing regex substitution\n");
+				goto error;
+			}
+			break;
+		case FPARAM_PVS:
+			name.s = (char*)*param;
+			name.len = strlen(name.s);
+			trim(&name);
+			if (!name.len || name.s[0] != '$'){
+				/* not a pvs identifier */
+				pkg_free(p);
+				return 1;
+			}
+			p->v.pvs=pkg_malloc(sizeof(pv_spec_t));
+			if (p->v.pvs==0){
+				ERR("out of memory while parsing pv_spec_t\n");
+				goto error;
+			}
+			if (pv_parse_spec(&name, p->v.pvs)==0){
+				ERR("unsupported user field indentifier \"%.*s\"\n",
+						name.len, name.s);
+				pkg_free(p->v.pvs);
+				p->v.pvs=0;
+				goto error;
+			}
+			break;
+		case FPARAM_PVE:
+			name.s = (char*)*param;
+			name.len = strlen(name.s);
+			if (pv_parse_format(&name, &p->v.pve)<0){
+				ERR("bad PVE format: \"%.*s\"\n", name.len, name.s);
+				goto error;
+			}
+			break;
 	}
-	name.s++;
-	name.len--;
+	
+	p->type = type;
+	*param = (void*)p;
+	return 0;
+	
+error:
+	pkg_free(p);
+	return E_UNSPEC;
+}
 
-	if (parse_avp_ident(&name, &p->v.avp) < 0) {
-	    ERR("Error while parsing attribute name\n");
-	    goto error;
-	}
-	break;
-
-    case FPARAM_SELECT:
-	name.s = (char*)*param;
-	name.len = strlen(name.s);
-	trim(&name);
-	if (!name.len || name.s[0] != '@') {
-	    /* Not a select identifier */
-	    pkg_free(p);
-	    return 1;
-	}
 
-	if (parse_select(&name.s, &p->v.select) < 0) {
-	    ERR("Error while parsing select identifier\n");
-	    goto error;
-	}
-	break;
-
-    case FPARAM_SUBST:
-	s.s = *param;
-	s.len = strlen(s.s);
-	p->v.subst = subst_parser(&s);
-	if (!p->v.subst) {
-	    ERR("Error while parsing regex substitution\n");
-	    goto error;
+
+/** fparam_t free function.
+ *  Frees the "content" of a fparam, but not the fparam itself.
+ *  Assumes pkg_malloc'ed content.
+ *  @param fp -  fparam to be freed
+ *
+ */
+void fparam_free_contents(fparam_t* fp)
+{
+
+	if (fp==0)
+		return;
+	switch(fp->type) {
+		case FPARAM_UNSPEC:
+		case FPARAM_STRING: /* asciiz string, not str */
+		case FPARAM_INT:
+		case FPARAM_STR:
+			/* nothing to do */
+			return;
+		case FPARAM_REGEX:
+			if (fp->v.regex){
+				regfree(fp->v.regex);
+				pkg_free(fp->v.regex);
+				fp->v.regex=0;
+			}
+			break;
+		case FPARAM_AVP:
+			free_avp_name(&fp->v.avp.flags, &fp->v.avp.name);
+			break;
+		case FPARAM_SELECT:
+			if (fp->v.select){
+				free_select(fp->v.select);
+				fp->v.select=0;
+			}
+			break;
+		case FPARAM_SUBST:
+			if (fp->v.subst){
+				subst_expr_free(fp->v.subst);
+				fp->v.subst=0;
+			}
+			break;
+		case FPARAM_PVS:
+			if (fp->v.pvs){
+				pv_spec_free(fp->v.pvs);
+				fp->v.pvs=0;
+			}
+			break;
+		case FPARAM_PVE:
+			if (fp->v.pve){
+				pv_elem_free_all(fp->v.pve);
+				fp->v.pve=0;
+			}
+			break;
 	}
-	break;
-    }
+}
+
 
-    p->type = type;
-    *param = (void*)p;
-    return 0;
 
- error:
-    pkg_free(p);
-    return E_UNSPEC;
+/** fix a param to one of the given types (mask).
+  *
+  * @param types - bitmap of the allowed types (e.g. FPARAM_INT|FPARAM_STR)
+  * @param param - value/result
+  * @return - 0 on success, -1 on error, 1 if param doesn't
+  *           match any of the types
+  */
+int fix_param_types(int types, void** param)
+{
+	int ret;
+	int t;
+	
+	for (t=types & ~(types-1); types; types&=(types-1), t=types & ~(types-1)){
+		if ((ret=fix_param(t, param))<=0) return ret;
+	}
+	return E_UNSPEC;
 }
 
 
+
 /*
  * Fixup variable string, the parameter can be
  * AVP, SELECT, or ordinary string. AVP and select
@@ -1102,26 +1207,27 @@ int fix_param(int type, void** param)
  */
 int fixup_var_str_12(void** param, int param_no)
 {
-    int ret;
-    if ((ret = fix_param(FPARAM_AVP, param)) <= 0) return ret;
-    if ((ret = fix_param(FPARAM_SELECT, param)) <= 0) return ret;
-    if ((ret = fix_param(FPARAM_STR, param)) <= 0) return ret;
-    ERR("Error while fixing parameter, AVP, SELECT, and str conversions failed\n");
-    return -1;
+	int ret;
+	if ((ret = fix_param(FPARAM_AVP, param)) <= 0) return ret;
+	if ((ret = fix_param(FPARAM_SELECT, param)) <= 0) return ret;
+	if ((ret = fix_param(FPARAM_STR, param)) <= 0) return ret;
+	ERR("Error while fixing parameter, AVP, SELECT, and str conversions"
+			" failed\n");
+	return -1;
 }
 
 /* Same as fixup_var_str_12 but applies to the 1st parameter only */
 int fixup_var_str_1(void** param, int param_no)
 {
-    if (param_no == 1) return fixup_var_str_12(param, param_no);
-    else return 0;
+	if (param_no == 1) return fixup_var_str_12(param, param_no);
+	else return 0;
 }
 
 /* Same as fixup_var_str_12 but applies to the 2nd parameter only */
 int fixup_var_str_2(void** param, int param_no)
 {
-    if (param_no == 2) return fixup_var_str_12(param, param_no);
-    else return 0;
+	if (param_no == 2) return fixup_var_str_12(param, param_no);
+	else return 0;
 }
 
 
@@ -1136,26 +1242,27 @@ int fixup_var_str_2(void** param, int param_no)
  */
 int fixup_var_int_12(void** param, int param_no)
 {
-    int ret;
-    if ((ret = fix_param(FPARAM_AVP, param)) <= 0) return ret;
-    if ((ret = fix_param(FPARAM_SELECT, param)) <= 0) return ret;
-    if ((ret = fix_param(FPARAM_INT, param)) <= 0) return ret;
-    ERR("Error while fixing parameter, AVP, SELECT, and int conversions failed\n");
-    return -1;
+	int ret;
+	if ((ret = fix_param(FPARAM_AVP, param)) <= 0) return ret;
+	if ((ret = fix_param(FPARAM_SELECT, param)) <= 0) return ret;
+	if ((ret = fix_param(FPARAM_INT, param)) <= 0) return ret;
+	ERR("Error while fixing parameter, AVP, SELECT, and int conversions"
+			" failed\n");
+	return -1;
 }
 
 /* Same as fixup_var_int_12 but applies to the 1st parameter only */
 int fixup_var_int_1(void** param, int param_no)
 {
-    if (param_no == 1) return fixup_var_int_12(param, param_no);
-    else return 0;
+	if (param_no == 1) return fixup_var_int_12(param, param_no);
+	else return 0;
 }
 
 /* Same as fixup_var_int_12 but applies to the 2nd parameter only */
 int fixup_var_int_2(void** param, int param_no)
 {
-    if (param_no == 2) return fixup_var_int_12(param, param_no);
-    else return 0;
+	if (param_no == 2) return fixup_var_int_12(param, param_no);
+	else return 0;
 }
 
 
@@ -1165,25 +1272,25 @@ int fixup_var_int_2(void** param, int param_no)
  */
 int fixup_regex_12(void** param, int param_no)
 {
-    int ret;
+	int ret;
 
-    if ((ret = fix_param(FPARAM_REGEX, param)) <= 0) return ret;
-    ERR("Error while compiling regex in function parameter\n");
-    return -1;
+	if ((ret = fix_param(FPARAM_REGEX, param)) <= 0) return ret;
+	ERR("Error while compiling regex in function parameter\n");
+	return -1;
 }
 
 /* Same as fixup_regex_12 but applies to the 1st parameter only */
 int fixup_regex_1(void** param, int param_no)
 {
-    if (param_no == 1) return fixup_regex_12(param, param_no);
-    else return 0;
+	if (param_no == 1) return fixup_regex_12(param, param_no);
+	else return 0;
 }
 
 /* Same as fixup_regex_12 but applies to the 2nd parameter only */
 int fixup_regex_2(void** param, int param_no)
 {
-    if (param_no == 2) return fixup_regex_12(param, param_no);
-    else return 0;
+	if (param_no == 2) return fixup_regex_12(param, param_no);
+	else return 0;
 }
 
 /*
@@ -1191,26 +1298,26 @@ int fixup_regex_2(void** param, int param_no)
  */
 int fixup_int_12(void** param, int param_no)
 {
-    int ret;
+	int ret;
 
-    if ((ret = fix_param(FPARAM_INT, param)) <= 0) return ret;
-    ERR("Cannot function parameter to integer\n");
-    return -1;
+	if ((ret = fix_param(FPARAM_INT, param)) <= 0) return ret;
+	ERR("Cannot function parameter to integer\n");
+	return -1;
 
 }
 
 /* Same as fixup_int_12 but applies to the 1st parameter only */
 int fixup_int_1(void** param, int param_no)
 {
-    if (param_no == 1) return fixup_int_12(param, param_no);
-    else return 0;
+	if (param_no == 1) return fixup_int_12(param, param_no);
+	else return 0;
 }
 
 /* Same as fixup_int_12 but applies to the 2nd parameter only */
 int fixup_int_2(void** param, int param_no)
 {
-    if (param_no == 2) return fixup_int_12(param, param_no);
-    else return 0;
+	if (param_no == 2) return fixup_int_12(param, param_no);
+	else return 0;
 }
 
 /*
@@ -1219,130 +1326,155 @@ int fixup_int_2(void** param, int param_no)
  */
 int fixup_str_12(void** param, int param_no)
 {
-    int ret;
+	int ret;
 
-    if ((ret = fix_param(FPARAM_STR, param)) <= 0) return ret;
-    ERR("Cannot function parameter to string\n");
-    return -1;
+	if ((ret = fix_param(FPARAM_STR, param)) <= 0) return ret;
+	ERR("Cannot function parameter to string\n");
+	return -1;
 }
 
 /* Same as fixup_str_12 but applies to the 1st parameter only */
 int fixup_str_1(void** param, int param_no)
 {
-    if (param_no == 1) return fixup_str_12(param, param_no);
-    else return 0;
+	if (param_no == 1) return fixup_str_12(param, param_no);
+	else return 0;
 }
 
 /* Same as fixup_str_12 but applies to the 2nd parameter only */
 int fixup_str_2(void** param, int param_no)
 {
-    if (param_no == 2) return fixup_str_12(param, param_no);
-    else return 0;
+	if (param_no == 2) return fixup_str_12(param, param_no);
+	else return 0;
 }
 
 
-/*
- * Get the function parameter value as string
- * Return values:  0 - Success
- *                -1 - Cannot get value
+/** Get the function parameter value as string.
+ *  @return  0 - Success
+ *          -1 - Cannot get value
  */
 int get_str_fparam(str* dst, struct sip_msg* msg, fparam_t* param)
 {
-    int_str val;
-    int ret;
-    avp_t* avp;
-
-    switch(param->type) {
-    case FPARAM_REGEX:
-    case FPARAM_UNSPEC:
-    case FPARAM_INT:
-	return -1;
-
-    case FPARAM_STRING:
-	dst->s = param->v.asciiz;
-	dst->len = strlen(param->v.asciiz);
-	break;
-
-    case FPARAM_STR:
-	*dst = param->v.str;
-	break;
-
-    case FPARAM_AVP:
-	avp = search_first_avp(param->v.avp.flags, param->v.avp.name, &val, 0);
-	if (!avp) {
-	    DBG("Could not find AVP from function parameter '%s'\n", param->orig);
-	    return -1;
-	}
-	if (avp->flags & AVP_VAL_STR) {
-	    *dst = val.s;
-	} else {
-		 /* The caller does not know of what type the AVP will be so
-		  * convert int AVPs into string here
-		  */
-	    dst->s = int2str(val.n, &dst->len);
+	int_str val;
+	int ret;
+	avp_t* avp;
+	pv_value_t pv_val;
+	static char pve_buf[256]; /* ugly hack needed for PVE */
+	
+	switch(param->type) {
+		case FPARAM_REGEX:
+		case FPARAM_UNSPEC:
+		case FPARAM_INT:
+			return -1;
+		case FPARAM_STRING:
+			dst->s = param->v.asciiz;
+			dst->len = strlen(param->v.asciiz);
+			break;
+		case FPARAM_STR:
+			*dst = param->v.str;
+			break;
+		case FPARAM_AVP:
+			avp = search_first_avp(param->v.avp.flags, param->v.avp.name,
+									&val, 0);
+			if (unlikely(!avp)) {
+				DBG("Could not find AVP from function parameter '%s'\n",
+						param->orig);
+				return -1;
+			}
+			if (likely(avp->flags & AVP_VAL_STR)) {
+				*dst = val.s;
+			} else {
+		 		/* The caller does not know of what type the AVP will be so
+				 * convert int AVPs into string here
+				 */
+				dst->s = int2str(val.n, &dst->len);
+			}
+			break;
+		case FPARAM_SELECT:
+			ret = run_select(dst, param->v.select, msg);
+			if (unlikely(ret < 0 || ret > 0)) return -1;
+			break;
+		case FPARAM_PVS:
+			if (likely((pv_get_spec_value(msg, param->v.pvs, &pv_val)==0) &&
+					   ((pv_val.flags&(PV_VAL_NULL|PV_VAL_STR))==PV_VAL_STR))){
+					*dst=pv_val.rs;
+			}else{
+				ERR("Could not convert PV to str\n");
+				return -1;
+			}
+			break;
+		case FPARAM_PVE:
+			dst->len=sizeof(pve_buf);
+			if (unlikely(pv_printf(msg, param->v.pve, pve_buf, &dst->len)!=0)){
+				ERR("Could not convert the PV-formated string to str\n");
+				dst->len=0;
+				return -1;
+			};
+			dst->s=pve_buf;
+			break;
 	}
-	break;
-
-    case FPARAM_SELECT:
-	ret = run_select(dst, param->v.select, msg);
-	if (ret < 0 || ret > 0) return -1;
-	break;
-    }
-
-    return 0;
+	return 0;
 }
 
 
-/*
- * Get the function parameter value as integer
- * Return values:  0 - Success
- *                -1 - Cannot get value
+/** Get the function parameter value as integer.
+ *  @return  0 - Success
+ *          -1 - Cannot get value
  */
 int get_int_fparam(int* dst, struct sip_msg* msg, fparam_t* param)
 {
-    int_str val;
-    int ret;
-    avp_t* avp;
-    str tmp;
-
-    switch(param->type) {
-    case FPARAM_INT:
-	*dst = param->v.i;
-	return 0;
-
-    case FPARAM_REGEX:
-    case FPARAM_UNSPEC:
-    case FPARAM_STRING:
-    case FPARAM_STR:
-	return -1;
+	int_str val;
+	int ret;
+	avp_t* avp;
+	str tmp;
+	pv_value_t pv_val;
 
-    case FPARAM_AVP:
-	avp = search_first_avp(param->v.avp.flags, param->v.avp.name, &val, 0);
-	if (!avp) {
-	    DBG("Could not find AVP from function parameter '%s'\n", param->orig);
-	    return -1;
-	}
-	if (avp->flags & AVP_VAL_STR) {
-	    if (str2int(&val.s, (unsigned int*)dst) < 0) {
-		ERR("Could not convert AVP string value to int\n");
-		return -1;
-	    }
-	} else {
-	    *dst = val.n;
-	}
-	break;
-
-    case FPARAM_SELECT:
-	ret = run_select(&tmp, param->v.select, msg);
-	if (ret < 0 || ret > 0) return -1;
-	if (str2int(&tmp, (unsigned int*)dst) < 0) {
-	    ERR("Could not convert select result to int\n");
-	    return -1;
+	switch(param->type) {
+		case FPARAM_INT:
+			*dst = param->v.i;
+			return 0;
+		case FPARAM_REGEX:
+		case FPARAM_UNSPEC:
+		case FPARAM_STRING:
+		case FPARAM_STR:
+			return -1;
+		case FPARAM_AVP:
+			avp = search_first_avp(param->v.avp.flags, param->v.avp.name,
+									&val, 0);
+			if (unlikely(!avp)) {
+				DBG("Could not find AVP from function parameter '%s'\n",
+						param->orig);
+				return -1;
+			}
+			if (avp->flags & AVP_VAL_STR) {
+				if (str2int(&val.s, (unsigned int*)dst) < 0) {
+					ERR("Could not convert AVP string value to int\n");
+					return -1;
+				}
+			} else {
+				*dst = val.n;
+			}
+			break;
+		case FPARAM_SELECT:
+			ret = run_select(&tmp, param->v.select, msg);
+			if (unlikely(ret < 0 || ret > 0)) return -1;
+			if (unlikely(str2int(&tmp, (unsigned int*)dst) < 0)) {
+				ERR("Could not convert select result to int\n");
+				return -1;
+			}
+			break;
+		case FPARAM_PVS:
+			if (likely((pv_get_spec_value(msg, param->v.pvs, &pv_val)==0) &&
+					   ((pv_val.flags&(PV_VAL_NULL|PV_VAL_INT))==PV_VAL_INT))){
+					*dst=pv_val.ri;
+			}else{
+				ERR("Could not convert PV to int\n");
+				return -1;
+			}
+			break;
+		case FPARAM_PVE:
+			return -1;
 	}
-	break;
-    }
-
-    return 0;
+	return 0;
 }
 
 /**
@@ -1355,7 +1487,6 @@ int get_regex_fparam(regex_t *dst, struct sip_msg* msg, fparam_t* param)
 		case FPARAM_REGEX:
 			*dst = *param->v.regex;
 			return 0;
-
 		default:
 			ERR("unexpected parameter type (%d), instead of regexp.\n", 
 					param->type);

+ 23 - 11
sr_module.h

@@ -46,6 +46,7 @@
  *              dual module interface support: ser & kamailio (andrei)
  *  2008-11-18  prototypes for various fixed parameters numbers module
  *               functions (3, 4, 5 & 6) and variable parameters (andrei)
+ *  2008-11-26  added fparam_free_contents() and fix_param_types (andrei)
  */
 
 /*!
@@ -234,17 +235,23 @@ struct param_export_ {
 };
 
 
+
+/** allowed parameter types.
+  * the types that cannot be deduced from the string, should
+  * be at the end (e.g. FPARAM_STR), to allow fallback 
+  * (e.g. fix_param_types(FPARAM_AVP|FPARAM_SELECT|FPARAM_STR, param))
+  */
 enum {
 	FPARAM_UNSPEC = 0,
-	FPARAM_STRING = (1 << 0),
-	FPARAM_STR    = (1 << 1),
-	FPARAM_INT    = (1 << 2),
-	FPARAM_REGEX  = (1 << 3),
-	FPARAM_AVP    = (1 << 5),
-	FPARAM_SELECT = (1 << 6),
-	FPARAM_SUBST  = (1 << 7),
-	FPARAM_PVS    = (1 << 8),
-	FPARAM_PVE    = (1 << 9)
+	FPARAM_INT    = (1 << 0),
+	FPARAM_REGEX  = (1 << 1),
+	FPARAM_AVP    = (1 << 2),
+	FPARAM_SELECT = (1 << 3),
+	FPARAM_SUBST  = (1 << 4),
+	FPARAM_PVS    = (1 << 5),
+	FPARAM_PVE    = (1 << 6),
+	FPARAM_STRING = (1 << 7),
+	FPARAM_STR    = (1 << 8)
 };
 
 /*
@@ -261,8 +268,8 @@ typedef struct fparam {
 		avp_ident_t avp;          /* AVP identifier */
 		select_t* select;         /* select structure */ 
 		struct subst_expr* subst; /* Regex substitution */
-		struct pv_spec_t* pvs;    /* kamailo pseudo-vars */
-		struct pv_elem_t* pve;    /* kamailo pseudo-vars */
+		pv_spec_t* pvs;    /* kamailo pseudo-vars */
+		pv_elem_t* pve;    /* kamailo pseudo-vars in a string */
 	} v;
 } fparam_t;
 
@@ -417,6 +424,11 @@ int fix_flag( modparam_t type, void* val,
  * parameter types
  */
 int fix_param(int type, void** param);
+void fparam_free_contents(fparam_t* fp);
+
+/** fix a param to one of the given types (mask).
+  */
+int fix_param_types(int types, void** param);
 
 /*
  * Fixup variable string, the parameter can be

+ 39 - 2
usr_avp.c

@@ -831,6 +831,39 @@ int parse_avp_name( str *name, int *type, int_str *avp_name, int *index)
 	return ret;
 }
 
+
+/** parse an avp indentifier.
+ *
+ * Parses the following avp indentifier forms:
+ *       - "i:<number>"  - old form, deprecated  (e.g. i:42)
+ *       - "s:<string>"  - old form, deprecated  (e.g. s:foo)
+ *       - "<track>.<name>"                      (e.g.: f.bar)
+ *       - "<track>.<name>[<index>]"             (e.g.: f.bar[1])
+ *       - "<track><class>.<name>"               (e.g:  tu.bar)
+ *       - "<track><class>.<name>[<index>]"      (e.g:  fd.bar[2])
+ *       - "<string>"                            (e.g.: foo)
+ * Where:
+ *          <string> = ascii string
+ *          <id>   = ascii string w/o '[', ']', '.' and '/'
+ *          <name> = <id> | '/' regex '/'
+ *                   (Note: regex use is deprecated)
+ *          <track> = 'f' | 't'
+ *                   (from or to)
+ *          <class> = 'r' | 'u' | 'd' | 'g'
+ *                    (uri, user, domain or global)
+ *          <index> = <number> | '-' <number> | ''
+ *                    (the avp index, if missing it means AVP_INDEX_ALL, but
+ *                     it's use is deprecated)
+ * More examples:
+ *       "fr.bar[1]"  - from track, uri class, avp "bar", the value 1.
+ *       "tu./^foo/"  - to track,  user class, all avps for which the name
+ *                      starts with foo (note RE in avp names are deprecated).
+ *        "t.did"     - to track, "did" avp
+ *
+ * @param name  - avp identifier
+ * @param *attr - the result will be stored here
+ * @return 0 on success, -1 on error
+ */
 int parse_avp_ident( str *name, avp_ident_t* attr)
 {
 	unsigned int id;
@@ -960,6 +993,7 @@ int parse_avp_ident( str *name, avp_ident_t* attr)
 			name->s[name->len-1]=0;
 			if (regcomp(attr->name.re, name->s+1, REG_EXTENDED|REG_NOSUB|REG_ICASE)) {
 				pkg_free(attr->name.re);
+				attr->name.re=0;
 				name->s[name->len-1] = '/';
 				goto error;
 			}
@@ -1003,10 +1037,13 @@ int parse_avp_spec( str *name, int *type, int_str *avp_name, int *index)
 	}
 }
 
-void free_avp_name( int *type, int_str *avp_name)
+void free_avp_name(avp_flags_t *type, int_str *avp_name)
 {
-	if ((*type & AVP_NAME_RE) && (avp_name->re))
+	if ((*type & AVP_NAME_RE) && (avp_name->re)){
+		regfree(avp_name->re);
 		pkg_free(avp_name->re);
+		avp_name->re=0;
+	}
 }
 
 int add_avp_galias_str(char *alias_definition)

+ 1 - 1
usr_avp.h

@@ -203,7 +203,7 @@ int add_avp_galias(str *alias, int type, int_str avp_name);
 int parse_avp_ident( str *name, avp_ident_t* attr);
 int parse_avp_name( str *name, int *type, int_str *avp_name, int *index);
 int parse_avp_spec( str *name, int *type, int_str *avp_name, int *index);
-void free_avp_name( int *type, int_str *avp_name);
+void free_avp_name( avp_flags_t *type, int_str *avp_name);
 
 /* AVP flags functions */
 #define MAX_AVPFLAG  ((unsigned int)( sizeof(avp_flags_t) * CHAR_BIT - 1 - AVP_CUSTOM_FLAGS))