Преглед изворни кода

Merge branch 'master' of ssh://git.sip-router.org/sip-router

Carsten Bock пре 14 година
родитељ
комит
905894f66f
90 измењених фајлова са 2576 додато и 679 уклоњено
  1. 9 2
      Makefile
  2. 4 1
      Makefile.defs
  3. 2 0
      cfg.lex
  4. 3 0
      cfg.y
  5. 4 1
      cfg_core.c
  6. 1 0
      cfg_core.h
  7. 51 2
      daemonize.c
  8. 1 1
      daemonize.h
  9. 36 0
      dprint.c
  10. 8 3
      dprint.h
  11. 20 1
      etc/kamailio.cfg
  12. 1 1
      forward.c
  13. 12 1
      lib/kcore/parse_sst.c
  14. 1 0
      lib/kcore/parse_sst.h
  15. 21 0
      lib/kcore/parse_supported.c
  16. 3 7
      lib/kcore/parse_supported.h
  17. 1 1
      lib/srdb1/db_id.c
  18. 3 3
      lvalue.c
  19. 3 0
      modules/dialplan/README
  20. 1 1
      modules/dialplan/dialplan.c
  21. 4 0
      modules/dialplan/doc/dialplan_admin.xml
  22. 29 15
      modules/dialplan/dp_repl.c
  23. 4 4
      modules/pipelimit/README
  24. 4 4
      modules/pipelimit/doc/pipelimit_admin.xml
  25. 14 0
      modules/sdpops/Makefile
  26. 137 0
      modules/sdpops/README
  27. 4 0
      modules/sdpops/doc/Makefile
  28. 37 0
      modules/sdpops/doc/sdpops.xml
  29. 145 0
      modules/sdpops/doc/sdpops_admin.xml
  30. 413 0
      modules/sdpops/sdpops_mod.c
  31. 1 1
      modules/tm/tm.c
  32. 2 2
      modules_k/dialog/dialog.c
  33. 6 11
      modules_k/dialog/dlg_handlers.c
  34. 1 2
      modules_k/dialog/dlg_handlers.h
  35. 10 9
      modules_k/dialog/dlg_hash.c
  36. 3 3
      modules_k/dialog/doc/dialog_admin.xml
  37. 12 3
      modules_k/dispatcher/dispatch.c
  38. 2 2
      modules_k/dispatcher/dispatcher.c
  39. 2 2
      modules_k/dispatcher/doc/dispatcher.xml
  40. 1 1
      modules_k/dispatcher/doc/dispatcher_admin.xml
  41. 2 2
      modules_k/htable/README
  42. 1 1
      modules_k/htable/doc/htable_admin.xml
  43. 38 0
      modules_k/kex/README
  44. 47 0
      modules_k/kex/doc/kex_admin.xml
  45. 23 0
      modules_k/kex/kex_mod.c
  46. 9 9
      modules_k/nathelper/nathelper.c
  47. 21 0
      modules_k/permissions/doc/permissions_admin.xml
  48. 33 23
      modules_k/permissions/hash.c
  49. 2 0
      modules_k/permissions/permissions.c
  50. 2 0
      modules_k/permissions/permissions.h
  51. 41 37
      modules_k/permissions/trusted.c
  52. 6 0
      modules_k/pv/pv.c
  53. 16 0
      modules_k/pv/pv_core.c
  54. 3 0
      modules_k/pv/pv_core.h
  55. 9 0
      modules_k/pv/pv_time.c
  56. 2 0
      modules_k/pv/pv_time.h
  57. 77 2
      modules_k/pv/pv_trans.c
  58. 1 1
      modules_k/pv/pv_trans.h
  59. 4 2
      modules_k/pv/pv_xavp.c
  60. 196 142
      modules_k/regex/README
  61. 23 9
      modules_k/regex/doc/regex_admin.xml
  62. 13 7
      modules_k/regex/regex_mod.c
  63. 41 5
      modules_k/siputils/README
  64. 27 0
      modules_k/siputils/checks.c
  65. 10 0
      modules_k/siputils/checks.h
  66. 45 5
      modules_k/siputils/doc/siputils_admin.xml
  67. 39 25
      modules_k/siputils/siputils.c
  68. 59 12
      modules_k/sqlops/README
  69. 74 5
      modules_k/sqlops/doc/sqlops_admin.xml
  70. 131 0
      modules_k/sqlops/sql_api.c
  71. 4 0
      modules_k/sqlops/sql_api.h
  72. 61 0
      modules_k/sqlops/sqlops.c
  73. 17 0
      modules_k/tmx/README
  74. 21 0
      modules_k/tmx/doc/tmx_admin.xml
  75. 21 0
      modules_k/tmx/tmx_mod.c
  76. 68 18
      modules_k/uac/README
  77. 101 3
      modules_k/uac/doc/uac_admin.xml
  78. 56 2
      modules_k/uac/uac_reg.c
  79. 80 87
      parser/hf.c
  80. 36 11
      parser/hf.h
  81. 1 1
      parser/msg_parser.c
  82. 6 0
      pkg/kamailio/deb/debian/kamailio.default
  83. 44 12
      pkg/kamailio/deb/debian/kamailio.init
  84. 2 1
      receive.c
  85. 10 143
      ser_stun.c
  86. 3 6
      ser_stun.h
  87. 2 2
      sr_module.c
  88. 4 2
      tcp_read.c
  89. 5 3
      utils/kamctl/kamdbctl.base
  90. 23 17
      xavp.c

+ 9 - 2
Makefile

@@ -772,12 +772,16 @@ utils:
 dbg: sip-router
 	gdb -command debug.gdb
 
+.PHONY: makefile_vars makefile-vars
+makefile_vars makefile-vars:
+	echo "FLAVOUR?=$(FLAVOUR)" > Makefile.vars
+
 .PHONY: tar
 .PHONY: dist
 
 dist: tar
 
-tar: $(auto_gen_keep)
+tar: makefile_vars $(auto_gen_keep)
 	$(TAR) -C .. \
 		--exclude=$(notdir $(CURDIR))/test* \
 		--exclude=$(notdir $(CURDIR))/tmp* \
@@ -1143,7 +1147,7 @@ maintainer-clean: modules=$(modules_all)
 proper realclean distclean maintainer-clean: clean_cfg
 
 # on maintainer clean, remove also the configured module list
-maintainer-clean: clean_modules_cfg
+maintainer-clean: clean_modules_cfg clean_makefile_vars
 
 .PHONY: proper-all realclean-all distclean-all
 proper-all realclean-all distclean-all: cmodules=$(all_modules_lst)
@@ -1158,6 +1162,9 @@ clean_cfg clean-cfg:
 clean_modules_cfg clean-modules-cfg:
 	rm -f modules.lst
 
+.PHONY: clean_makefile_vars clean-makefile-vars
+	rm -f Makefile.vars
+
 .PHONY: dbschema
 dbschema:
 	-@echo "Build database schemas"

+ 4 - 1
Makefile.defs

@@ -117,6 +117,8 @@ ifeq ($(quiet),verbose)
 $(info normal Makefile.defs exec)
 endif # verbose
 
+-include Makefile.vars
+
 # usage: $(call set_if_empty,VAR,value)
 set_if_empty=$(if $($(1)),,$(eval override $(1)=$(2)))
 
@@ -160,7 +162,7 @@ INSTALL_FLAVOUR=$(FLAVOUR)
 VERSION = 3
 PATCHLEVEL = 2
 SUBLEVEL =  0
-EXTRAVERSION = -dev2
+EXTRAVERSION = -dev3
 
 # memory debugger switcher
 # 0 - off (release mode)
@@ -656,6 +658,7 @@ C_DEFS= $(extra_defs) \
 	 -DUSE_DNS_FAILOVER \
 	 -DUSE_DST_BLACKLIST \
 	 -DUSE_NAPTR \
+	 -DWITH_XAVP \
 	 #-DUSE_DNS_CACHE_STATS \
 	 #-DUSE_DST_BLACKLIST_STATS \
 	 #-DDNS_WATCHDOG_SUPPORT \

+ 2 - 0
cfg.lex

@@ -386,6 +386,7 @@ SYN_BRANCH syn_branch
 MEMLOG		"memlog"|"mem_log"
 MEMDBG		"memdbg"|"mem_dbg"
 MEMSUM		"mem_summary"
+CORELOG		"corelog"|"core_log"
 SIP_WARNING sip_warning
 SERVER_SIGNATURE server_signature
 SERVER_HEADER server_header
@@ -747,6 +748,7 @@ SUBST       subst
 <INITIAL>{MEMLOG}	{ count(); yylval.strval=yytext; return MEMLOG; }
 <INITIAL>{MEMDBG}	{ count(); yylval.strval=yytext; return MEMDBG; }
 <INITIAL>{MEMSUM}	{ count(); yylval.strval=yytext; return MEMSUM; }
+<INITIAL>{CORELOG}	{ count(); yylval.strval=yytext; return CORELOG; }
 <INITIAL>{SIP_WARNING}	{ count(); yylval.strval=yytext; return SIP_WARNING; }
 <INITIAL>{USER}		{ count(); yylval.strval=yytext; return USER; }
 <INITIAL>{GROUP}	{ count(); yylval.strval=yytext; return GROUP; }

+ 3 - 0
cfg.y

@@ -434,6 +434,7 @@ extern char *finame;
 %token MEMLOG
 %token MEMDBG
 %token MEMSUM
+%token CORELOG
 %token SIP_WARNING
 %token SERVER_SIGNATURE
 %token SERVER_HEADER
@@ -918,6 +919,8 @@ assign_stm:
 	| MEMDBG EQUAL error { yyerror("int value expected"); }
 	| MEMSUM EQUAL intno { default_core_cfg.mem_summary=$3; }
 	| MEMSUM EQUAL error { yyerror("int value expected"); }
+	| CORELOG EQUAL intno { default_core_cfg.corelog=$3; }
+	| CORELOG EQUAL error { yyerror("int value expected"); }
 	| SIP_WARNING EQUAL NUMBER { sip_warning=$3; }
 	| SIP_WARNING EQUAL error { yyerror("boolean value expected"); }
 	| USER EQUAL STRING     {

+ 4 - 1
cfg_core.c

@@ -119,8 +119,9 @@ struct cfg_group_core default_core_cfg = {
 	-1,  /**< udp4_raw_ttl (auto detect by default) */
 	0,  /*!< force_rport */
 	L_DBG, /*!< memlog */
-	3 /*!< mem_summary -flags: 0 off, 1 pkg_status, 2 shm_status,
+	3, /*!< mem_summary -flags: 0 off, 1 pkg_status, 2 shm_status,
 		4 pkg_sums, 8 shm_sums */
+	L_ERR /*!< corelog */
 };
 
 void	*core_cfg = &default_core_cfg;
@@ -307,5 +308,7 @@ cfg_def_t core_cfg_def[] = {
 		" 2 - dump all the shm used blocks (status),"
 		" 4 - summary of pkg used blocks,"
 		" 8 - summary of shm used blocks" },
+	{"corelog",		CFG_VAR_INT|CFG_ATOMIC,	0, 0, 0, 0,
+		"log level for non-critical core error messages"},
 	{0, 0, 0, 0, 0, 0}
 };

+ 1 - 0
cfg_core.h

@@ -108,6 +108,7 @@ struct cfg_group_core {
 	int force_rport; /*!< if set rport will always be forced*/
 	int memlog; /*!< log level for memory status/summary info */
 	int mem_summary; /*!< display memory status/summary info on exit */
+	int corelog; /*!< log level for non-critcal core error messages */
 };
 
 extern struct cfg_group_core default_core_cfg;

+ 51 - 2
daemonize.c

@@ -58,6 +58,10 @@
 #include <pwd.h>
 #include <grp.h>
 
+#ifdef __OS_linux
+#include <sys/prctl.h>
+#endif
+
 #ifdef HAVE_SCHED_SETSCHEDULER
 #include <sched.h>
 #endif
@@ -202,6 +206,40 @@ void daemon_status_no_wait()
 }
 
 
+/**
+ * enable dumpable flag for core dumping after setuid() & friends
+ * @return 0 when no critical error occured, -1 on such error
+ */
+int enable_dumpable(void)
+{
+#ifdef __OS_linux
+	struct rlimit lim;
+	/* re-enable core dumping on linux after setuid() & friends */
+	if(disable_core_dump==0) {
+		LM_DBG("trying enable core dumping...\n");
+		if(prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)<=0) {
+			LM_DBG("core dumping is disabled now...\n");
+			if(prctl(PR_SET_DUMPABLE, 1, 0, 0, 0)<0) {
+				LM_WARN("cannot re-enable core dumping!\n");
+			} else {
+				LM_DBG("core dumping has just been enabled...\n");
+				if (getrlimit(RLIMIT_CORE, &lim)<0){
+					LOG(L_CRIT, "cannot get the maximum core size: %s\n",
+							strerror(errno));
+					return -1;
+				} else {
+					DBG("current core file limit: %lu (max: %lu)\n",
+						(unsigned long)lim.rlim_cur, (unsigned long)lim.rlim_max);
+				}
+			}
+		} else {
+			LM_DBG("core dumping is enabled now (%d)...\n",
+					prctl(PR_GET_DUMPABLE, 0, 0, 0, 0));
+		}
+	}
+#endif
+	return 0;
+}
 
 /** daemon init.
  *@param name - daemon name used for logging (used when opening syslog).
@@ -289,6 +327,10 @@ int daemonize(char*  name,  int status_wait)
 			exit(0);
 		}
 	}
+
+	if(enable_dumpable()<0)
+		goto error;
+
 	/* added by noh: create a pid file for the main process */
 	if (pid_file!=0){
 		
@@ -415,6 +457,10 @@ int do_suid()
 			goto error;
 		}
 	}
+
+	if(enable_dumpable()<0)
+		goto error;
+
 	return 0;
 error:
 	return -1;
@@ -477,7 +523,7 @@ error:
 
 
 /*! \brief enable core dumps */
-int set_core_dump(int enable, int size)
+int set_core_dump(int enable, long unsigned int size)
 {
 	struct rlimit lim;
 	struct rlimit newlim;
@@ -510,8 +556,11 @@ int set_core_dump(int enable, int size)
 						(unsigned long)lim.rlim_max);
 			}
 			goto error; /* it's an error we haven't got the size we wanted*/
+		}else{
+			newlim.rlim_cur=lim.rlim_cur;
+			newlim.rlim_max=lim.rlim_max;
+			goto done; /*nothing to do */
 		}
-		goto done; /*nothing to do */
 	}else{
 		/* disable */
 		newlim.rlim_cur=0;

+ 1 - 1
daemonize.h

@@ -30,7 +30,7 @@
 int daemonize(char* name, int daemon_status_fd_input);
 int do_suid();
 int increase_open_fds(int target);
-int set_core_dump(int enable, int size);
+int set_core_dump(int enable, long unsigned int size);
 int mem_lock_pages();
 int set_rt_prio(int prio, int policy);
 

+ 36 - 0
dprint.c

@@ -104,3 +104,39 @@ int log_facility_fixup(void *handle, str *gname, str *name, void **val)
 	*val = (void *)(long)i;
 	return 0;
 }
+
+
+/**
+ * per process debug log level (local)
+ */
+
+/* value for unset local log level  */
+#define UNSET_LOCAL_DEBUG_LEVEL	-255
+
+/* the local debug log level */
+static int _local_debug_level = UNSET_LOCAL_DEBUG_LEVEL;
+
+/**
+ * @brief return the log level - the local one if it set,
+ *   otherwise the global value
+ */
+int get_debug_level(void) {
+	return (_local_debug_level != UNSET_LOCAL_DEBUG_LEVEL) ?
+				_local_debug_level : cfg_get(core, core_cfg, debug);
+}
+
+/**
+ * @brief set the local debug log level
+ */
+void set_local_debug_level(int level)
+{
+	_local_debug_level = level;
+}
+
+/**
+ * @brief reset the local debug log level
+ */
+void reset_local_debug_level(void)
+{
+	_local_debug_level = UNSET_LOCAL_DEBUG_LEVEL;
+}

+ 8 - 3
dprint.h

@@ -118,7 +118,12 @@ struct log_level_info {
 	int syslog_level;
 };
 
-#define is_printable(level) (cfg_get(core, core_cfg, debug)>=(level))
+/** @brief per process debug level handling */
+int get_debug_level(void);
+void set_local_debug_level(int level);
+void reset_local_debug_level(void);
+
+#define is_printable(level) (get_debug_level()>=(level))
 extern struct log_level_info log_level_info[];
 extern char *log_name;
 
@@ -167,7 +172,7 @@ int log_facility_fixup(void *handle, str *gname, str *name, void **val);
 #	ifdef __SUNPRO_C
 #		define LOG_(facility, level, prefix, fmt, ...) \
 			do { \
-				if (unlikely(cfg_get(core, core_cfg, debug) >= (level) && \
+				if (unlikely(get_debuglevel() >= (level) && \
 						DPRINT_NON_CRIT)) { \
 					DPRINT_CRIT_ENTER; \
 					if (likely(((level) >= L_ALERT) && ((level) <= L_DBG))){ \
@@ -229,7 +234,7 @@ int log_facility_fixup(void *handle, str *gname, str *name, void **val);
 #	else /* ! __SUNPRO_C */
 #		define LOG_(facility, level, prefix, fmt, args...) \
 			do { \
-				if (cfg_get(core, core_cfg, debug) >= (level) && \
+				if (get_debug_level() >= (level) && \
 						DPRINT_NON_CRIT) { \
 					DPRINT_CRIT_ENTER; \
 					if (likely(((level) >= L_ALERT) && ((level) <= L_DBG))){ \

+ 20 - 1
etc/kamailio.cfg

@@ -241,6 +241,10 @@ loadmodule "pike.so"
 loadmodule "xmlrpc.so"
 #!endif
 
+#!ifdef WITH_DEBUG
+loadmodule "debugger.so"
+#!endif
+
 # ----------------- setting module-specific parameters ---------------
 
 
@@ -388,6 +392,11 @@ modparam("xmlrpc", "route", "XMLRPC");
 modparam("xmlrpc", "url_match", "^/RPC")
 #!endif
 
+#!ifdef WITH_DEBUG
+# ----- debugger params -----
+modparam("debugger", "cfgtrace", 1)
+#!endif
+
 ####### Routing Logic ########
 
 
@@ -668,10 +677,20 @@ route[AUTH] {
 			}
 			if (is_method("PUBLISH"))
 			{
-				if ($au!=$tU) {
+				if ($au!=$fU || $au!=$tU) {
 					sl_send_reply("403","Forbidden auth ID");
 					exit;
 				}
+				if ($au!=$rU) {
+					sl_send_reply("403","Forbidden R-URI");
+					exit;
+				}
+#!ifdef WITH_MULTIDOMAIN
+				if ($fd!=$rd) {
+					sl_send_reply("403","Forbidden R-URI domain");
+					exit;
+				}
+#!endif
 			} else {
 				if ($au!=$fU) {
 					sl_send_reply("403","Forbidden auth ID");

+ 1 - 1
forward.c

@@ -783,7 +783,7 @@ int forward_reply(struct sip_msg* msg)
 		|| (msg->via2==0) || (msg->via2->error!=PARSE_OK))
 	{
 		/* no second via => error */
-		LOG(L_INFO, "broken reply to forward - no 2nd via\n");
+		LOG(L_DBG, "broken reply to forward - no 2nd via\n");
 		goto error;
 	}
 

+ 12 - 1
lib/kcore/parse_sst.c

@@ -68,6 +68,16 @@ malloc_session_expires( void )
 	return se;
 }
 
+/**
+ * wrapper to free the content of parsed session-expires header
+ */
+void hf_free_session_expires(void *parsed)
+{
+	struct session_expires *se;
+	se = (struct session_expires*)parsed;
+	free_session_expires(se);
+}
+
 
 void
 free_session_expires( struct session_expires *se )
@@ -84,7 +94,7 @@ parse_session_expires_body( struct hdr_field *hf )
 	int pos = 0;
 	int len = hf->body.len;
 	char *q;
-	struct session_expires se = { 0, sst_refresher_unspecified };
+	struct session_expires se = { 0, 0, sst_refresher_unspecified };
 	unsigned tok;
 
 	if ( !p || len <= 0 ) {
@@ -165,6 +175,7 @@ parse_session_expires_body( struct hdr_field *hf )
 		LM_ERR(" out of pkg memory\n" );
 		return parse_sst_out_of_mem;
 	}
+	se.hfree = hf_free_session_expires;
 	*((struct session_expires *)hf->parsed) = se;
 
 	return parse_sst_success;

+ 1 - 0
lib/kcore/parse_sst.h

@@ -53,6 +53,7 @@ enum sst_refresher {
  * a pointer to a struct session_expires.
  */
 struct session_expires {
+	hf_parsed_free_f hfree;       /* function to free the content */
 	unsigned            interval; /* in seconds */
 	enum sst_refresher  refresher;
 };

+ 21 - 0
lib/kcore/parse_supported.c

@@ -112,6 +112,17 @@ static inline int parse_supported_body(str *body, unsigned int *sup)
 	return 0;
 }
 
+
+/**
+ * wrapper to free the content of parsed supported header
+ */
+void hf_free_supported(void *parsed)
+{
+	struct supported_body *sb;
+	sb = (struct supported_body*)parsed;
+	free_supported(&sb);
+}
+
 /*!
  * Parse all Supported headers
  */
@@ -144,6 +155,7 @@ int parse_supported( struct sip_msg *msg)
 		}
 
 		parse_supported_body(&(hdr->body), &(sb->supported));
+		sb->hfree = hf_free_supported;
 		sb->supported_all = 0;
 		hdr->parsed = (void*)sb;
 		supported |= sb->supported;
@@ -153,3 +165,12 @@ int parse_supported( struct sip_msg *msg)
 		supported;
 	return 0;
 }
+
+/* free supported header structure */
+void free_supported(struct supported_body **sb)
+{
+	if (sb && *sb) {
+		pkg_free(*sb);
+		*sb = 0;
+	}
+}

+ 3 - 7
lib/kcore/parse_supported.h

@@ -36,6 +36,7 @@
 #define PARSE_SUPPORTED_H
 
 #include "../../parser/msg_parser.h"
+#include "../../parser/hf.h"
 #include "../../mem/mem.h"
 
 
@@ -64,6 +65,7 @@
 
 
 struct supported_body {
+	hf_parsed_free_f hfree;        /* function to free the content */
 	unsigned int supported;        /* supported mask for the current hdr */
 	unsigned int supported_all;    /* suppoted mask for the all "supported" hdr
 	                                *  - it's set only for the first hdr in 
@@ -77,12 +79,6 @@ struct supported_body {
 int parse_supported( struct sip_msg *msg);
 
 
-static inline void free_supported(struct supported_body **sb)
-{
-	if (sb && *sb) {
-		pkg_free(*sb);
-		*sb = 0;
-	}
-}
+void free_supported(struct supported_body **sb);
 
 #endif /* PARSE_SUPPORTED_H */

+ 1 - 1
lib/srdb1/db_id.c

@@ -279,7 +279,7 @@ unsigned char cmp_db_id(const struct db_id* id1, const struct db_id* id2)
 	if (strcasecmp(id1->host, id2->host)) return 0;
 	if (strcmp(id1->database, id2->database)) return 0;
 	if(id1->pid!=id2->pid) {
-		LM_WARN("identical DB URLs, but different DB connection pid [%d/%d]\n",
+		LM_DBG("identical DB URLs, but different DB connection pid [%d/%d]\n",
 				id1->pid, id2->pid);
 		return 0;
 	}

+ 3 - 3
lvalue.c

@@ -290,7 +290,7 @@ inline static int lval_pvar_assign(struct run_act_ctx* h, struct sip_msg* msg,
 														    break in expr*/
 			} else
 				pval.ri=0;
-			ret=pval.ri;
+			ret=!(!pval.ri);
 			break;
 		case RV_BEXPR: /* logic/boolean expr. */
 			pval.flags=PV_TYPE_INT|PV_VAL_INT;
@@ -301,7 +301,7 @@ inline static int lval_pvar_assign(struct run_act_ctx* h, struct sip_msg* msg,
 				WARN("error in expression\n");
 				pval.ri=0; /* expr. is treated as false */
 			}
-			ret=pval.ri;
+			ret=!(!pval.ri);
 			break;
 		case RV_SEL:
 			pval.flags=PV_VAL_STR;
@@ -315,7 +315,7 @@ inline static int lval_pvar_assign(struct run_act_ctx* h, struct sip_msg* msg,
 					break;
 				}
 			}
-			ret=(pval.rs.len)>0;
+			ret=(pval.rs.len>0);
 			break;
 		case RV_AVP:
 				r_avp = search_avp_by_index(rv->v.avps.type, rv->v.avps.name,

+ 3 - 0
modules/dialplan/README

@@ -334,6 +334,9 @@ modparam("dialplan", "fetch_rows", 4000)
    with dialplan ID equal to id. If dest is missing, only matching and
    storing of matching rule's attributes is done.
 
+   Returns 1, if translation succeeded, -1 in case of some error occurred,
+   and -2 if dialplan with ID equal to id does not exist.
+
    Meaning of the parameters is as follows:
      * id -the dialplan id of the possible matching rules. This parameter
        can have the following types:

+ 1 - 1
modules/dialplan/dialplan.c

@@ -326,7 +326,7 @@ static int dp_translate_f(struct sip_msg* msg, char* str1, char* str2)
 
 	if ((idp = select_dpid(dpid)) ==0 ){
 		LM_DBG("no information available for dpid %i\n", dpid);
-		return -1;
+		return -2;
 	}
 
 	repl_par = (str2!=NULL)? ((dp_param_p)str2):default_par2;

+ 4 - 0
modules/dialplan/doc/dialplan_admin.xml

@@ -365,6 +365,10 @@ modparam("dialplan", "fetch_rows", 4000)
 	missing, only matching and storing of matching rule's
 	attributes is done.
 	</para>
+	<para>
+	  Returns 1, if translation succeeded, -1 in case of some error
+	  occurred, and -2 if dialplan with ID equal to id does not exist.
+	</para>
 	<para>Meaning of the parameters is as follows:</para>
 	<itemizedlist>
 	<listitem>

+ 29 - 15
modules/dialplan/dp_repl.c

@@ -72,7 +72,7 @@ struct subst_expr* repl_exp_parse(str subst)
 	repl = p;
 	if((rw_no = parse_repl(rw, &p, end, &max_pmatch, WITHOUT_SEP))< 0)
 		goto error;
-	
+
 	repl_end=p;
 
     /* construct the subst_expr structure */
@@ -183,8 +183,9 @@ int rule_translate(struct sip_msg *msg, str string, dpl_node_t * rule,
 	/* offset- offset in the replacement string */
 	result->len = repl_nb = offset = 0;
 	p=repl_comp->replacement.s;
-	
+
 	while( repl_nb < repl_comp->n_escapes){
+
 		token = repl_comp->replace[repl_nb];
 		
 		if(offset< token.offset){
@@ -194,12 +195,12 @@ int rule_translate(struct sip_msg *msg, str string, dpl_node_t * rule,
 				goto error;
 			}
 			/*copy from the replacing string*/
-			size=repl_comp->replacement.s+repl_comp->replace[repl_nb].offset-p;
-			memcpy(result->s + result->len, p, size);
+			size = token.offset - offset;
+			memcpy(result->s + result->len, p + offset, size);
+			LM_DBG("copying <%.*s> from replacing string\n",
+			       size, p + offset);
 			result->len += size;
-			p+=size+repl_comp->replace[repl_nb].size;
-
-			offset += token.offset-offset; /*update the offset*/
+			offset = token.offset;
 		}
 
 		switch(token.type) {
@@ -214,16 +215,21 @@ int rule_translate(struct sip_msg *msg, str string, dpl_node_t * rule,
 				}
 
 				memcpy(result->s + result->len, match.s, match.len);
+				LM_DBG("copying match <%.*s> token size %d\n",
+				       match.len, match.s, token.size);
 				result->len += match.len;
-				offset += token.size; /*update the offset*/
+				offset += token.size;
 			break;
 			case REPLACE_CHAR:
 				if(result->len + 1>= MAX_PHONE_NB_DIGITS){
 					LM_ERR("overflow\n");
 					goto error;
 				}
-				*result->s=repl_comp->replace[repl_nb].u.c;
+				*(result->s + result->len) = token.u.c;
+				LM_DBG("copying char <%c> token size %d\n",
+					token.u.c, token.size);
 				result->len++;
+				offset += token.size;
 			break;
 			case REPLACE_URI:	
 				if ( msg== NULL || msg->first_line.type!=SIP_REQUEST){
@@ -238,15 +244,17 @@ int rule_translate(struct sip_msg *msg, str string, dpl_node_t * rule,
 					goto error;
 				}
 				memcpy(result->s + result->len, uri->s, uri->len);
+				LM_DBG("copying uri <%.*s> token size %d\n",
+					uri->len, uri->s, token.size);
 				result->len+=uri->len;
+				offset += token.size;
 			break;
 			case REPLACE_SPEC:
 				if (msg== NULL) {
 					LM_DBG("replace spec attempted on no message\n");
 					break;
 				}
-				if(pv_get_spec_value(msg, 
-						&repl_comp->replace[repl_nb].u.spec, &sv)!=0){
+				if (pv_get_spec_value(msg, &token.u.spec, &sv) != 0) {
 					LM_CRIT("item substitution returned error\n");
 					break; /* ignore, we can continue */
 				}
@@ -254,8 +262,12 @@ int rule_translate(struct sip_msg *msg, str string, dpl_node_t * rule,
 					LM_ERR("rule_translate: overflow\n");
 					goto error;
 				}
-				memcpy(result->s + result->len, sv.rs.s, sv.rs.len);
+				memcpy(result->s + result->len, sv.rs.s,
+				       sv.rs.len);
+				LM_DBG("copying pvar value <%.*s> token size %d\n",
+					sv.rs.len, sv.rs.s, token.size);
 				result->len+=sv.rs.len;
+				offset += token.size;
 			break;
 			default:
 				LM_CRIT("unknown type %d\n", repl_comp->replace[repl_nb].type);
@@ -264,10 +276,12 @@ int rule_translate(struct sip_msg *msg, str string, dpl_node_t * rule,
 		repl_nb++;
 	}
 	/* anything left? */
-	if( repl_nb && token.offset+token.size < repl_comp->replacement.len){
+	if( repl_nb && offset < repl_comp->replacement.len){
 		/*copy from the replacing string*/
-		size = repl_comp->replacement.s+repl_comp->replacement.len-p;
-		memcpy(result->s + result->len, p, size);
+		size = repl_comp->replacement.len - offset;
+		memcpy(result->s + result->len, p + offset, size);
+		LM_DBG("copying leftover <%.*s> from replacing string\n",
+		       size, p + offset);
 		result->len += size;
 	}
 

+ 4 - 4
modules/pipelimit/README

@@ -154,7 +154,7 @@ modparam("pipelimit", "db_url", "dbdriver://username:password@dbhost/dbname")
 
 3.2. plp_table_name (string)
 
-   Name of DB table where data definitio for pipes is stores.
+   Name of DB table where data definition for pipes is stores.
 
    Default value is “pl_pipes”.
 
@@ -223,7 +223,7 @@ modparam("ratelimit", "timer_interval", 5)
 modparam("ratelimit", "reply_code", 505)
 ...
 
-   This value cant be modified at runtime using sercmd
+   This value can be modified at runtime using sercmd
 
    Example 1.8.  Set reply_code parameter at runtime
 sercmd cfg.set_now_int ratelimit reply_code 505
@@ -239,7 +239,7 @@ sercmd cfg.set_now_int ratelimit reply_code 505
 modparam("ratelimit", "reply_reason", "Limiting")
 ...
 
-   This value cant be modified at runtime using sercmd
+   This value can be modified at runtime using sercmd
 
    Example 1.10.  Set reply_reason parameter at runtime
 sercmd cfg.set_now_string ratelimit reply_reason "Limiting"
@@ -387,7 +387,7 @@ sercmd cfg.set_now_string ratelimit reply_reason "Limiting"
 
 5.6.  pl_push_load
 
-   Force the value of the load parameter. This methos is usefull for
+   Force the value of the load parameter. This command is useful for
    testing the Feedback algorithm.
 
    Name: pl_push_load

+ 4 - 4
modules/pipelimit/doc/pipelimit_admin.xml

@@ -88,7 +88,7 @@ modparam("pipelimit", "db_url", "&exampledb;")
 	<section>
 	    <title><varname>plp_table_name</varname> (string)</title>
 	    <para>
-			Name of DB table where data definitio for pipes is stores.
+			Name of DB table where data definition for pipes is stores.
 	    </para>
 	    <para>
 		<emphasis>
@@ -210,7 +210,7 @@ modparam("ratelimit", "reply_code", 505)
 </programlisting>
 		</example>
 		<para>
-		This value cant be modified at runtime using sercmd
+		This value can be modified at runtime using sercmd
 		</para>
 		<example>
 		<title> Set <varname>reply_code</varname> parameter at runtime </title>
@@ -240,7 +240,7 @@ modparam("ratelimit", "reply_reason", "Limiting")
 </programlisting>
 		</example>
 		<para>
-		This value cant be modified at runtime using sercmd
+		This value can be modified at runtime using sercmd
 		</para>
 		<example>
 		<title> Set <varname>reply_reason</varname> parameter at runtime </title>
@@ -471,7 +471,7 @@ sercmd cfg.set_now_string ratelimit reply_reason "Limiting"
 		<function moreinfo="none">pl_push_load</function>
 		</title>
 		<para>
-		Force the value of the load parameter.  This methos is usefull
+		Force the value of the load parameter.  This command is useful
 		for testing the Feedback algorithm.
 		</para>
 		<para>

+ 14 - 0
modules/sdpops/Makefile

@@ -0,0 +1,14 @@
+# $Id$
+#
+# 
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=sdpops.so
+DEFS +=
+LIBS +=
+
+DEFS+=-DOPENSER_MOD_INTERFACE
+
+include ../../Makefile.modules

+ 137 - 0
modules/sdpops/README

@@ -0,0 +1,137 @@
+SDPOPS Module
+
+Daniel-Constantin Mierla
+
+   <[email protected]>
+
+Edited by
+
+Daniel-Constantin Mierla
+
+   <[email protected]>
+
+   Copyright © 2011 asipto.com
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
+
+        3. Exported Parameters
+        4. Exported Functions
+
+              4.1. sdp_remove_codecs_by_id(list)
+              4.2. sdp_with_media(type)
+              4.3. sdp_print(level)
+
+   List of Examples
+
+   1.1. sdp_remove_codecs_by_id usage
+   1.2. sdp_with_media usage
+   1.3. sdp_print usage
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Exported Parameters
+   4. Exported Functions
+
+        4.1. sdp_remove_codecs_by_id(list)
+        4.2. sdp_with_media(type)
+        4.3. sdp_print(level)
+
+1. Overview
+
+   This module provides function for checking and managing the SDP
+   payloads of SIP messages.
+
+   Examples of what this module offers: remove codecs from SDP, check the
+   media stream types, return attributes of SDP document. For the full
+   least of the features provided by this module and the implementation
+   state, read further to the list of exported functions.
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+
+2.1. Kamailio Modules
+
+   The following modules must be loaded before this module:
+     * none.
+
+2.2. External Libraries or Applications
+
+   The following libraries or applications must be installed before
+   running Kamailio with this module loaded:
+     * None
+
+3. Exported Parameters
+
+   The module does not export any config parameter yet.
+
+4. Exported Functions
+
+   4.1. sdp_remove_codecs_by_id(list)
+   4.2. sdp_with_media(type)
+   4.3. sdp_print(level)
+
+4.1.  sdp_remove_codecs_by_id(list)
+
+   Remove the codecs provided in the parameter 'list' from all media
+   streams found in SDP payload. The parameter 'list' must be one or a
+   comma separated list of numeric codec IDs. The parameter can be a
+   static string or a variable holding the list of numeric codec IDs.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.1. sdp_remove_codecs_by_id usage
+...
+# remove PCMU
+sdp_remove_codecs_by_id("0");
+# remove PCMU, PCMA and GSM
+sdp_remove_codecs_by_id("0,8,3");
+...
+
+4.2.  sdp_with_media(type)
+
+   Return true of the SDP has 'media=type ...' line. Useful to check the
+   content of the RTP sessions, such as 'audio' or 'video'. The parameter
+   can be static string or variable holding the media type.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.2. sdp_with_media usage
+...
+# check for video stream
+if(sdp_with_media("video"))
+{
+    # the session has a video stream
+}
+...
+
+4.3.  sdp_print(level)
+
+   Print the SDP internal structure to log 'level'. The parameter can be
+   static integer or variable holding the integer value of the log level.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.3. sdp_print usage
+...
+# print the SDP
+sdp_print("1");
+...

+ 4 - 0
modules/sdpops/doc/Makefile

@@ -0,0 +1,4 @@
+docs = sdpops.xml
+
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module

+ 37 - 0
modules/sdpops/doc/sdpops.xml

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+    <bookinfo>
+	<title>SDPOPS Module</title>
+	<productname class="trade">sip-router.org</productname>
+	<authorgroup>
+	    <author>
+		<firstname>Daniel-Constantin</firstname>
+		<surname>Mierla</surname>
+		<email>[email protected]</email>
+	    </author>
+	    <editor>
+		<firstname>Daniel-Constantin</firstname>
+		<surname>Mierla</surname>
+		<email>[email protected]</email>
+	    </editor>
+	</authorgroup>
+	<copyright>
+	    <year>2011</year>
+	    <holder>asipto.com</holder>
+	</copyright>
+    </bookinfo>
+    <toc></toc>
+    
+    <xi:include href="sdpops_admin.xml"/>
+    
+    
+</book>

+ 145 - 0
modules/sdpops/doc/sdpops_admin.xml

@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+<!-- Module User's Guide -->
+
+<chapter>
+	
+	<title>&adminguide;</title>
+	
+	<section>
+	<title>Overview</title>
+	<para>
+		This module provides function for checking and managing the SDP
+		payloads of SIP messages.
+	</para>
+	<para>
+		Examples of what this module offers: remove codecs from SDP,
+		check the media stream types, return attributes of SDP document.
+		For the full least of the features provided by this module and
+		the implementation state, read further to the list of exported
+		functions.
+	</para>
+	</section>
+
+	<section>
+	<title>Dependencies</title>
+	<section>
+		<title>&kamailio; Modules</title>
+		<para>
+		The following modules must be loaded before this module:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>none</emphasis>.
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	<section>
+		<title>External Libraries or Applications</title>
+		<para>
+		The following libraries or applications must be installed before running
+		&kamailio; with this module loaded:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>None</emphasis>
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	</section>
+	<section>
+	<title>Exported Parameters</title>
+		<para>
+		The module does not export any config parameter yet.
+		</para>
+	</section>
+
+	<section>
+	<title>Exported Functions</title>
+	<section>
+	    <title>
+		<function moreinfo="none">sdp_remove_codecs_by_id(list)</function>
+	    </title>
+	    <para>
+			Remove the codecs provided in the parameter 'list' from all
+			media streams found in SDP payload. The parameter 'list' must
+			be one or a comma separated list of numeric codec IDs. The
+			parameter can be a static string or a variable holding the
+			list of numeric codec IDs.
+	    </para>
+		<para>
+			This function can be used from ANY_ROUTE.
+	    </para>
+		<example>
+		<title><function>sdp_remove_codecs_by_id</function> usage</title>
+		<programlisting format="linespecific">
+...
+# remove PCMU
+sdp_remove_codecs_by_id("0");
+# remove PCMU, PCMA and GSM
+sdp_remove_codecs_by_id("0,8,3");
+...
+</programlisting>
+	    </example>
+	</section>
+	<section>
+	    <title>
+		<function moreinfo="none">sdp_with_media(type)</function>
+	    </title>
+	    <para>
+		Return true of the SDP has 'media=type ...' line. Useful to check
+		the content of the RTP sessions, such as 'audio' or 'video'. The
+		parameter can be static string or variable holding the media type.
+	    </para>
+		<para>
+			This function can be used from ANY_ROUTE.
+	    </para>
+		<example>
+		<title><function>sdp_with_media</function> usage</title>
+		<programlisting format="linespecific">
+...
+# check for video stream
+if(sdp_with_media("video"))
+{
+    # the session has a video stream
+}
+...
+</programlisting>
+	    </example>
+	</section>
+	<section>
+	    <title>
+		<function moreinfo="none">sdp_print(level)</function>
+	    </title>
+	    <para>
+		Print the SDP internal structure to log 'level'. The
+		parameter can be static integer or variable holding the integer
+		value of the log level.
+	    </para>
+		<para>
+			This function can be used from ANY_ROUTE.
+	    </para>
+		<example>
+		<title><function>sdp_print</function> usage</title>
+		<programlisting format="linespecific">
+...
+# print the SDP
+sdp_print("1");
+...
+</programlisting>
+	    </example>
+	</section>
+	</section>
+</chapter>
+

+ 413 - 0
modules/sdpops/sdpops_mod.c

@@ -0,0 +1,413 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2011 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "../../sr_module.h"
+#include "../../dprint.h"
+#include "../../mod_fix.h"
+#include "../../pvar.h"
+#include "../../trim.h"
+#include "../../parser/sdp/sdp.h"
+#include "../../data_lump.h"
+
+
+MODULE_VERSION
+
+static int w_sdp_remove_codecs_by_id(sip_msg_t* msg, char* codecs, char *bar);
+static int w_sdp_with_media(sip_msg_t* msg, char* media, char *bar);
+static int w_sdp_print(sip_msg_t* msg, char* level, char *bar);
+
+static int mod_init(void);
+
+static cmd_export_t cmds[] = {
+	{"sdp_remove_codecs_by_id",    (cmd_function)w_sdp_remove_codecs_by_id,
+		1, fixup_spve_null,  0, ANY_ROUTE},
+	{"sdp_with_media",             (cmd_function)w_sdp_with_media,
+		1, fixup_spve_null,  0, ANY_ROUTE},
+	{"sdp_print",                  (cmd_function)w_sdp_print,
+		1, fixup_igp_null,  0, ANY_ROUTE},
+	{0, 0, 0, 0, 0}
+};
+
+static pv_export_t mod_pvs[] = {
+#if 0
+	{{"sdp", (sizeof("sdp")-1)}, /* */
+		PVT_OTHER, pv_get_sdp, 0,
+		0, 0, 0, 0},
+#endif
+
+	{ {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+static param_export_t params[] = {
+	{0, 0, 0}
+};
+
+/** module exports */
+struct module_exports exports= {
+	"sdpops",
+	DEFAULT_DLFLAGS, /* dlopen flags */
+	cmds,
+	params,
+	0,          /* exported statistics */
+	0  ,        /* exported MI functions */
+	mod_pvs,    /* exported pseudo-variables */
+	0,          /* extra processes */
+	mod_init,   /* module initialization function */
+	0,
+	0,
+	0           /* per-child init function */
+};
+
+/** 
+ * 
+ */
+static int mod_init(void)
+{
+	LM_DBG("sdpops module loaded\n");
+	return 0;
+}
+
+
+/**
+ *
+ */
+int str_find_token(str *text, str *result, char delim)
+{
+	int i;
+	if(text==NULL || result==NULL)
+		return -1;
+	if(text->s[0] == delim)
+	{
+		 text->s += 1;
+		 text->len -= 1;
+	}
+	trim_leading(text);
+	result->s = text->s;
+	result->len = 0;
+	for (i=0; i<text->len; i++)
+	{
+		if(result->s[i]==delim || result->s[i]=='\0'
+				|| result->s[i]=='\r' || result->s[i]=='\n')
+			return 0;
+		result->len++;
+	}
+	return 0;
+}
+
+/**
+ *
+ */
+int sdp_locate_line(sip_msg_t* msg, char *pos, str *aline)
+{
+	char *p;
+	p = pos;
+	while(*p!='\n') p--;
+	aline->s = p + 1;
+	p = pos;
+	while(*p!='\n') p++;
+	aline->len = p - aline->s + 1;
+	return 0;
+}
+
+/**
+ *
+ */
+int sdp_remove_str_codec_id_attrs(sip_msg_t* msg,
+		sdp_stream_cell_t* sdp_stream, str *rm_codec)
+{
+	str aline = {0, 0};
+	sdp_payload_attr_t *payload;
+	struct lump *anchor;
+
+	payload = sdp_stream->payload_attr;
+	while (payload) {
+		LM_DBG("a= ... for codec %.*s/%.*s\n",
+			payload->rtp_payload.len, payload->rtp_payload.s,
+			payload->rtp_enc.len, payload->rtp_enc.s);
+		if(rm_codec->len==payload->rtp_payload.len
+				&& strncmp(payload->rtp_payload.s, rm_codec->s,
+					rm_codec->len)==0) {
+			if(payload->rtp_enc.s!=NULL) {
+				if(sdp_locate_line(msg, payload->rtp_enc.s, &aline)==0)
+				{
+					anchor = del_lump(msg, aline.s - msg->buf,
+							aline.len, 0);
+					if (anchor == NULL) {
+						LM_ERR("failed to remove [%.*s] inside [%.*s]\n",
+							rm_codec->len, rm_codec->s,
+							aline.len, aline.s);
+						return -1;
+					}
+				}
+			}
+			if(payload->fmtp_string.s!=NULL) {
+				if(sdp_locate_line(msg, payload->fmtp_string.s, &aline)==0)
+				{
+					anchor = del_lump(msg, aline.s - msg->buf,
+							aline.len, 0);
+					if (anchor == NULL) {
+						LM_ERR("failed to remove [%.*s] inside [%.*s]\n",
+							rm_codec->len, rm_codec->s,
+							aline.len, aline.s);
+						return -1;
+					}
+				}
+			}
+		}
+		payload=payload->next;
+	}
+
+	return 0;
+}
+
+/**
+ *
+ */
+int sdp_remove_str_codec_id(sip_msg_t* msg, str *allcodecs, str* rmcodec)
+{
+	int i;
+	int cmp;
+	struct lump *anchor;
+
+	if(msg==NULL || allcodecs==NULL || rmcodec==NULL
+			|| allcodecs->len<=0 || rmcodec->len<=0)
+		return -1;
+
+	cmp = 1;
+	for(i=0; i<allcodecs->len; i++) {
+		if(cmp==1) {
+			if(rmcodec->len <= allcodecs->len-i) {
+				if(strncmp(&allcodecs->s[i], rmcodec->s, rmcodec->len)==0) {
+					if(&allcodecs->s[i+rmcodec->len]
+									== &allcodecs->s[allcodecs->len]
+							|| allcodecs->s[i+rmcodec->len] == ' ') {
+						/* match - remove also the space before codec id */
+						LM_DBG("found codec [%.*s] inside [%.*s]\n",
+									rmcodec->len, rmcodec->s,
+									allcodecs->len, allcodecs->s);
+						anchor = del_lump(msg, &allcodecs->s[i-1] - msg->buf,
+								rmcodec->len+1, 0);
+						if (anchor == NULL) {
+							LM_ERR("failed to remove [%.*s] inside [%.*s]\n",
+									rmcodec->len, rmcodec->s,
+									allcodecs->len, allcodecs->s);
+							return -1;
+						}
+						return 0;
+					}
+				}
+			}
+		}
+		if(allcodecs->s[i]==' ')
+			cmp = 1;
+		else
+			cmp = 0;
+	}
+
+	return 0;
+}
+
+/**
+ *
+ */
+int sdp_remove_codecs_by_id(sip_msg_t* msg, str* codecs)
+{
+	sdp_info_t *sdp = NULL;
+	int sdp_session_num;
+	int sdp_stream_num;
+	sdp_session_cell_t* sdp_session;
+	sdp_stream_cell_t* sdp_stream;
+	str sdp_codecs;
+	str tmp_codecs;
+	str rm_codec;
+
+	if(parse_sdp(msg) < 0) {
+		LM_ERR("Unable to parse sdp\n");
+		return -1;
+	}
+
+	LM_ERR("attempting to remove codecs from sdp: [%.*s]\n",
+			codecs->len, codecs->s);
+
+	sdp = (sdp_info_t*)msg->body;
+
+	sdp_session_num = 0;
+	for(;;)
+	{
+		sdp_session = get_sdp_session(msg, sdp_session_num);
+		if(!sdp_session) break;
+		sdp_stream_num = 0;
+		for(;;)
+		{
+			sdp_stream = get_sdp_stream(msg, sdp_session_num, sdp_stream_num);
+			if(!sdp_stream) break;
+
+			LM_DBG("stream %d of %d - payloads [%.*s]\n",
+				sdp_stream_num, sdp_session_num, 
+				sdp_stream->payloads.len, sdp_stream->payloads.s);
+			sdp_codecs = sdp_stream->payloads;
+			tmp_codecs = *codecs;
+			while(str_find_token(&tmp_codecs, &rm_codec, ',')==0
+					&& rm_codec.len>0)
+			{
+				tmp_codecs.len -=(int)(&rm_codec.s[rm_codec.len]-tmp_codecs.s);
+				tmp_codecs.s = rm_codec.s + rm_codec.len;
+
+				LM_DBG("codecs [%.*s] - remove [%.*s]\n",
+						sdp_codecs.len, sdp_codecs.s,
+						rm_codec.len, rm_codec.s);
+				sdp_remove_str_codec_id(msg, &sdp_codecs, &rm_codec);
+				sdp_remove_str_codec_id_attrs(msg, sdp_stream, &rm_codec);
+			}
+			sdp_stream_num++;
+		}
+		sdp_session_num++;
+	}
+
+	return 0;
+}
+
+/**
+ *
+ */
+static int w_sdp_remove_codecs_by_id(sip_msg_t* msg, char* codecs, char* bar)
+{
+	str lcodecs = {0, 0};
+
+	if(codecs==0)
+	{
+		LM_ERR("invalid parameters\n");
+		return -1;
+	}
+
+	if(fixup_get_svalue(msg, (gparam_p)codecs, &lcodecs)!=0)
+	{
+		LM_ERR("unable to get the list of codecs\n");
+		return -1;
+	}
+
+	if(sdp_remove_codecs_by_id(msg, &lcodecs)<0)
+		return -1;
+	return 1;
+}
+
+
+/** 
+ * @brief check 'media' matches the value of any 'm=value ...' lines
+ * @return -1 - error; 0 - not found; 1 - found
+ */
+static int sdp_with_media(sip_msg_t *msg, str *media)
+{
+	sdp_info_t *sdp = NULL;
+	int sdp_session_num;
+	int sdp_stream_num;
+	sdp_session_cell_t* sdp_session;
+	sdp_stream_cell_t* sdp_stream;
+
+	if(parse_sdp(msg) < 0) {
+		LM_ERR("Unable to parse sdp\n");
+		return -1;
+	}
+
+	LM_ERR("attempting to search for media type: [%.*s]\n",
+			media->len, media->s);
+
+	sdp = (sdp_info_t*)msg->body;
+
+	sdp_session_num = 0;
+	for(;;)
+	{
+		sdp_session = get_sdp_session(msg, sdp_session_num);
+		if(!sdp_session) break;
+		sdp_stream_num = 0;
+		for(;;)
+		{
+			sdp_stream = get_sdp_stream(msg, sdp_session_num, sdp_stream_num);
+			if(!sdp_stream) break;
+
+			LM_DBG("stream %d of %d - media [%.*s]\n",
+				sdp_stream_num, sdp_session_num,
+				sdp_stream->media.len, sdp_stream->media.s);
+			if(media->len==sdp_stream->media.len
+					&& strncasecmp(sdp_stream->media.s, media->s,
+							media->len)==0)
+				return 1;
+			sdp_stream_num++;
+		}
+		sdp_session_num++;
+	}
+
+	return 0;
+}
+
+/**
+ *
+ */
+static int w_sdp_with_media(sip_msg_t* msg, char* media, char *bar)
+{
+	str lmedia = {0, 0};
+
+	if(media==0)
+	{
+		LM_ERR("invalid parameters\n");
+		return -1;
+	}
+
+	if(fixup_get_svalue(msg, (gparam_p)media, &lmedia)!=0)
+	{
+		LM_ERR("unable to get the media value\n");
+		return -1;
+	}
+
+	if(sdp_with_media(msg, &lmedia)<=0)
+		return -1;
+	return 1;
+}
+
+
+static int w_sdp_print(sip_msg_t* msg, char* level, char *bar)
+{
+	sdp_info_t *sdp = NULL;
+	int llevel = L_DBG;
+
+	if(parse_sdp(msg) < 0) {
+		LM_ERR("Unable to parse sdp\n");
+		return -1;
+	}
+
+	if(fixup_get_ivalue(msg, (gparam_p)level, &llevel)!=0)
+	{
+		LM_ERR("unable to get the debug level value\n");
+		return -1;
+	}
+
+	sdp = (sdp_info_t*)msg->body;
+
+	print_sdp(sdp, llevel);
+	return 1;
+}

+ 1 - 1
modules/tm/tm.c

@@ -461,7 +461,7 @@ static cmd_export_t cmds[]={
 	{"t_save_lumps",      w_t_save_lumps,           0, 0,
 			REQUEST_ROUTE},
 	{"t_check_trans",	  w_t_check_trans,			0, 0,
-			REQUEST_ROUTE|TM_ONREPLY_ROUTE|BRANCH_ROUTE },
+			REQUEST_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE },
 
 	{"t_load_contacts", t_load_contacts,            0, 0,
 			REQUEST_ROUTE | FAILURE_ROUTE},

+ 2 - 2
modules_k/dialog/dialog.c

@@ -85,12 +85,12 @@ static char* rr_param = "did";
 static int dlg_flag = -1;
 static str timeout_spec = {NULL, 0};
 static int default_timeout = 60 * 60 * 12;  /* 12 hours */
-static int seq_match_mode = SEQ_MATCH_STRICT_ID;
 static char* profiles_wv_s = NULL;
 static char* profiles_nv_s = NULL;
 str dlg_extra_hdrs = {NULL,0};
 static int db_fetch_rows = 200;
 
+int seq_match_mode = SEQ_MATCH_STRICT_ID;
 str dlg_bridge_controller = {"sip:[email protected]", 27};
 
 str ruri_pvar_param = {"$ru", 3};
@@ -551,7 +551,7 @@ static int mod_init(void)
 
 	/* init handlers */
 	init_dlg_handlers( rr_param, dlg_flag,
-		timeout_spec.s?&timeout_avp:0, default_timeout, seq_match_mode);
+		timeout_spec.s?&timeout_avp:0, default_timeout);
 
 	/* init timer */
 	if (init_dlg_timer(dlg_ontimeout)!=0) {

+ 6 - 11
modules_k/dialog/dlg_handlers.c

@@ -82,8 +82,8 @@ static str       rr_param;		/*!< record-route parameter for matching */
 static int       dlg_flag;		/*!< flag for dialog tracking */
 static pv_spec_t *timeout_avp;		/*!< AVP for timeout setting */
 static int       default_timeout;	/*!< default dialog timeout */
-static int       seq_match_mode;	/*!< dlg_match mode */ 
 static int       shutdown_done = 0;	/*!< 1 when destroy_dlg_handlers was called */
+extern int       seq_match_mode;	/*!< dlg_match mode */ 
 extern int       detect_spirals;
 
 extern struct rr_binds d_rrb;		/*!< binding to record-routing module */
@@ -113,11 +113,9 @@ static unsigned int CURR_DLG_ID  = 0xffffffff;	/*!< current dialog id */
  * \param dlg_flag_p dialog flag
  * \param timeout_avp_p AVP for timeout setting
  * \param default_timeout_p default timeout
- * \param seq_match_mode_p matching mode
  */
 void init_dlg_handlers(char *rr_param_p, int dlg_flag_p,
-		pv_spec_t *timeout_avp_p ,int default_timeout_p,
-		int seq_match_mode_p)
+		pv_spec_t *timeout_avp_p ,int default_timeout_p)
 {
 	rr_param.s = rr_param_p;
 	rr_param.len = strlen(rr_param.s);
@@ -126,7 +124,6 @@ void init_dlg_handlers(char *rr_param_p, int dlg_flag_p,
 
 	timeout_avp = timeout_avp_p;
 	default_timeout = default_timeout_p;
-	seq_match_mode = seq_match_mode_p;
 }
 
 
@@ -716,12 +713,10 @@ int dlg_new_dialog(struct sip_msg *msg, struct cell *t)
 	if (_dlg_ctx.to_bye!=0)
 		dlg->dflags |= DLG_FLAG_TOBYE;
 
-	if (t) {
-		if ( d_tmb.register_tmcb( msg, t, TMCB_MAX,
-					dlg_tmcb_dummy, (void*)dlg, 0)<0 ) {
-			LM_ERR("failed cache in T the shortcut to dlg\n");
-			goto error;
-		}
+	if ( d_tmb.register_tmcb( msg, t, TMCB_MAX,
+				dlg_tmcb_dummy, (void*)dlg, 0)<0 ) {
+		LM_ERR("failed cache in T the shortcut to dlg\n");
+		goto error;
 	}
 #if 0
 		t->dialog_ctx = (void*) dlg;

+ 1 - 2
modules_k/dialog/dlg_handlers.h

@@ -60,8 +60,7 @@
  * \param seq_match_mode_p matching mode
  */
 void init_dlg_handlers(char *rr_param, int dlg_flag,
-		pv_spec_t *timeout_avp, int default_timeout,
-		int seq_match_mode);
+		pv_spec_t *timeout_avp, int default_timeout);
 
 
 /*!

+ 10 - 9
modules_k/dialog/dlg_hash.c

@@ -543,11 +543,10 @@ void link_dlg(struct dlg_cell *dlg, int n)
  */
 #define unref_dlg_unsafe(_dlg,_cnt,_d_entry)   \
 	do { \
-		(_dlg)->ref -= (_cnt); \
-		LM_DBG("unref dlg %p with %d -> %d\n",\
+		LM_DBG("unref dlg %p with %d, crt ref count: %d\n",\
 			(_dlg),(_cnt),(_dlg)->ref);\
-		if ((_dlg)->ref<0) {\
-			LM_CRIT("bogus ref %d with cnt %d for dlg %p [%u:%u] "\
+		if ((_dlg)->ref<=0) {\
+			LM_CRIT("bogus op: ref %d with cnt %d for dlg %p [%u:%u] "\
 				"with clid '%.*s' and tags '%.*s' '%.*s'\n",\
 				(_dlg)->ref, _cnt, _dlg,\
 				(_dlg)->h_entry, (_dlg)->h_id,\
@@ -556,11 +555,13 @@ void link_dlg(struct dlg_cell *dlg, int n)
 				(_dlg)->tag[DLG_CALLER_LEG].s,\
 				(_dlg)->tag[DLG_CALLEE_LEG].len,\
 				(_dlg)->tag[DLG_CALLEE_LEG].s); \
-		}\
-		if ((_dlg)->ref<=0) { \
-			unlink_unsafe_dlg( _d_entry, _dlg);\
-			LM_DBG("ref <=0 for dialog %p\n",_dlg);\
-			destroy_dlg(_dlg);\
+		} else { \
+			(_dlg)->ref -= (_cnt); \
+			if ((_dlg)->ref<=0) { \
+				unlink_unsafe_dlg( _d_entry, _dlg);\
+				LM_DBG("ref <=0 for dialog %p\n",_dlg);\
+				destroy_dlg(_dlg);\
+			}\
 		}\
 	}while(0)
 

+ 3 - 3
modules_k/dialog/doc/dialog_admin.xml

@@ -341,9 +341,9 @@ modparam("dialog", "dlg_match_mode", 1)
 		<example>
 			<title>Set <varname>detect_spirals</varname> parameter</title>
 			<programlisting format="linespecific">
-				...
-				modparam("dialog", "detect_spirals", 1)
-				...
+...
+modparam("dialog", "detect_spirals", 1)
+...
 			</programlisting>
 		</example>
 	</section>

+ 12 - 3
modules_k/dispatcher/dispatch.c

@@ -1995,7 +1995,7 @@ int ds_mark_dst(struct sip_msg *msg, int mode)
 	
 	if(mode==1) {
 		ret = ds_set_state(group, &avp_value.s,
-				DS_INACTIVE_DST|DS_PROBING_DST, 0);
+				DS_INACTIVE_DST|DS_PROBING_DST|DS_RESET_FAIL_DST, 0);
 	} else if(mode==2) {
 		ret = ds_set_state(group, &avp_value.s, DS_PROBING_DST, 1);
 		if (ret == 0) ret = ds_set_state(group, &avp_value.s,
@@ -2039,7 +2039,6 @@ int ds_set_state(int group, str *address, int state, int type)
 				&& strncasecmp(idx->dlist[i].uri.s, address->s,
 					address->len)==0)
 		{
-			
 			/* remove the Probing/Inactive-State? Set the fail-count to 0. */
 			if (state == DS_PROBING_DST) {
 				if (type) {
@@ -2064,6 +2063,16 @@ int ds_set_state(int group, str *address, int state, int type)
 				idx->dlist[i].failure_count = 0;
 				state &= ~DS_RESET_FAIL_DST;
 			}
+	
+			/*  Type 2 means reply from OPTIONS-Ping */
+			if (type == 2) {
+				if (idx->dlist[i].flags & DS_INACTIVE_DST) {
+					LM_INFO("Ignoring the request to set this destination"
+							" to active: It is already administratively deactivated!\n");
+					return 0;
+				}
+				type = 0;
+			}
 			
 			if(type)
 				idx->dlist[i].flags |= state;
@@ -2307,7 +2316,7 @@ static void ds_options_callback( struct cell *t, int type,
 		/* Set the according entry back to "Active":
 		 *  remove the Probing/Inactive Flag and reset the failure counter. */
 		if (ds_set_state(group, &uri,
-					DS_INACTIVE_DST|DS_PROBING_DST|DS_RESET_FAIL_DST, 0) != 0)
+					DS_INACTIVE_DST|DS_PROBING_DST|DS_RESET_FAIL_DST, 2) != 0)
 		{
 			LM_ERR("Setting the state failed (%.*s, group %d)\n", uri.len,
 					uri.s, group);

+ 2 - 2
modules_k/dispatcher/dispatcher.c

@@ -170,9 +170,9 @@ static cmd_export_t cmds[]={
 	{"ds_next_domain",   (cmd_function)w_ds_next_domain,   0,
 		ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE},
 	{"ds_mark_dst",      (cmd_function)w_ds_mark_dst0,     0,
-		ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE},
+		ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE},
 	{"ds_mark_dst",      (cmd_function)w_ds_mark_dst1,     1,
-		ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE},
+		ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE},
 	{"ds_is_from_list",  (cmd_function)w_ds_is_from_list0, 0,
 		0, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE},
 	{"ds_is_from_list",  (cmd_function)w_ds_is_from_list1, 1,

+ 2 - 2
modules_k/dispatcher/doc/dispatcher.xml

@@ -26,9 +26,9 @@
             <editor>
                 <firstname>Carsten</firstname>
                 <surname>Bock</surname>
-                <affiliation><orgname>BASIS AudioNet GmbH</orgname></affiliation>
+                <affiliation><orgname>ng-voice.com</orgname></affiliation>
                 <address>
-                <email>[email protected]</email>
+                <email>[email protected]</email>
                 </address>
             </editor>
 	</authorgroup>

+ 1 - 1
modules_k/dispatcher/doc/dispatcher_admin.xml

@@ -905,7 +905,7 @@ ds_select_dst("1", "$var(a)");
 		</listitem>
 		<listitem>
 			<para><emphasis>"a", "A" or "1"</emphasis> - the last destination
-				should be set to active.</para>
+				should be set to active and the error-counter should set to "0".</para>
 		</listitem>
 		<listitem>
 			<para><emphasis>"p", "P" or "2"</emphasis> - the last destination

+ 2 - 2
modules_k/htable/README

@@ -11,7 +11,7 @@ Elena-Ramona Modroiu
 
    <[email protected]>
 
-   Copyright © 2008 http://www.asipto.com
+   Copyright © 2008-2011 http://www.asipto.com
      __________________________________________________________________
 
    Table of Contents
@@ -179,7 +179,7 @@ if(is_present_hf("Authorization"))
                 sl_send_reply("403", "Forbidden");
             exit;
             case -2:
-                if($sht(a=>$au::auth_count) == null)
+                if($sht(a=>$au::auth_count) == $null)
                     $sht(a=>$au::auth_count) = 0;
                 $sht(a=>$au::auth_count) = $sht(a=>$au::auth_count) + 1;
                 if($sht(a=>$au::auth_count) == 3)

+ 1 - 1
modules_k/htable/doc/htable_admin.xml

@@ -91,7 +91,7 @@ if(is_present_hf("Authorization"))
                 sl_send_reply("403", "Forbidden");
             exit;
             case -2:
-                if($sht(a=&gt;$au::auth_count) == null)
+                if($sht(a=&gt;$au::auth_count) == $null)
                     $sht(a=&gt;$au::auth_count) = 0;
                 $sht(a=&gt;$au::auth_count) = $sht(a=&gt;$au::auth_count) + 1;
                 if($sht(a=&gt;$au::auth_count) == 3)

+ 38 - 0
modules_k/kex/README

@@ -38,6 +38,8 @@ Daniel-Constantin Mierla
               3.10. isdsturiset()
               3.11. pv_printf(var, str)
               3.12. is_myself(uri)
+              3.13. setdebug(level)
+              3.14. resetdebug()
 
         4. Exported MI Functions
 
@@ -66,6 +68,8 @@ Daniel-Constantin Mierla
    1.10. >isdsturiset usage
    1.11. >pv_printf usage
    1.12. >is_myself usage
+   1.13. setdebug usage
+   1.14. >resetdebug usage
 
 Chapter 1. Admin Guide
 
@@ -91,6 +95,8 @@ Chapter 1. Admin Guide
         3.10. isdsturiset()
         3.11. pv_printf(var, str)
         3.12. is_myself(uri)
+        3.13. setdebug(level)
+        3.14. resetdebug()
 
    4. Exported MI Functions
 
@@ -141,6 +147,8 @@ Chapter 1. Admin Guide
    3.10. isdsturiset()
    3.11. pv_printf(var, str)
    3.12. is_myself(uri)
+   3.13. setdebug(level)
+   3.14. resetdebug()
 
 3.1. setsflag(flag)
 
@@ -351,6 +359,36 @@ if(is_myself("$fu")) {
 }
 ...
 
+3.13. setdebug(level)
+
+   Set the debug log level per process.
+
+   Meaning of the parameters is as follows:
+     * level - the debug log level to be set. Can be integer or
+       pseudo-variable with integer value.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.13. setdebug usage
+...
+setdebug("1");
+...
+$var(level) = 2;
+setdebug("$var(level)");
+...
+
+3.14. resetdebug()
+
+   Reset the local debug log level back to the value of core parameter
+   'debug'.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.14. >resetdebug usage
+...
+resetdebug();
+...
+
 4. Exported MI Functions
 
    4.1. arg

+ 47 - 0
modules_k/kex/doc/kex_admin.xml

@@ -404,6 +404,53 @@ if(is_myself("$fu")) {
     ...
 }
 ...
+</programlisting>
+		</example>
+		</section>
+		<section>
+		<title><function moreinfo="none">setdebug(level)</function></title>
+		<para>
+			Set the debug log level per process.
+		</para>
+		<para>Meaning of the parameters is as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para>
+				<emphasis>level</emphasis> - the debug log level to
+				be set. Can be integer or pseudo-variable with integer value.
+			</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+		This function can be used from ANY_ROUTE.
+		</para>
+		<example>
+		<title><function>setdebug</function> usage</title>
+		<programlisting format="linespecific">
+...
+setdebug("1");
+...
+$var(level) = 2;
+setdebug("$var(level)");
+...
+</programlisting>
+		</example>
+		</section>
+		<section>
+		<title><function moreinfo="none">resetdebug()</function></title>
+		<para>
+		Reset the local debug log level back to the value of core parameter
+		'debug'.
+		</para>
+		<para>
+		This function can be used from ANY_ROUTE.
+		</para>
+		<example>
+		<title><function>>resetdebug</function> usage</title>
+		<programlisting format="linespecific">
+...
+resetdebug();
+...
 </programlisting>
 		</example>
 		</section>

+ 23 - 0
modules_k/kex/kex_mod.c

@@ -46,6 +46,8 @@ MODULE_VERSION
 
 /** module functions */
 int w_is_myself(struct sip_msg *msg, char *uri, str *s2);
+int w_setdebug(struct sip_msg *msg, char *level, str *s2);
+int w_resetdebug(struct sip_msg *msg, char *uri, str *s2);
 
 static int mod_init(void);
 static int child_init(int rank);
@@ -86,6 +88,10 @@ static cmd_export_t cmds[]={
 			0, ANY_ROUTE },
 	{"is_myself", (cmd_function)w_is_myself,    1, fixup_spve_null,
 			0, ANY_ROUTE },
+	{"setdebug", (cmd_function)w_setdebug,      1, fixup_igp_null,
+			0, ANY_ROUTE },
+	{"resetdebug", (cmd_function)w_resetdebug,  0, 0,
+			0, ANY_ROUTE },
 
 	{0,0,0,0,0,0}
 };
@@ -182,3 +188,20 @@ int w_is_myself(struct sip_msg *msg, char *uri, str *s2)
 	return 1;
 }
 
+int w_setdebug(struct sip_msg *msg, char *level, str *s2)
+{
+	int lval=0;
+	if(fixup_get_ivalue(msg, (gparam_p)level, &lval)!=0)
+	{
+		LM_ERR("no debug level value\n");
+		return -1;
+	}
+	set_local_debug_level(lval);
+	return 1;
+}
+
+int w_resetdebug(struct sip_msg *msg, char *uri, str *s2)
+{
+	reset_local_debug_level();
+	return 1;
+}

+ 9 - 9
modules_k/nathelper/nathelper.c

@@ -775,7 +775,7 @@ fix_nated_contact_f(struct sip_msg* msg, char* str1, char* str2)
 #define SALIAS_LEN (sizeof(SALIAS) - 1)
 
 /*
- * Adds ;alias=ip:port param to cotact uri containing received ip:port
+ * Adds ;alias=ip:port param to contact uri containing received ip:port
  * if contact uri ip:port does not match received ip:port.
  */
 static int
@@ -806,14 +806,14 @@ add_contact_alias_f(struct sip_msg* msg, char* str1, char* str2)
 
     /* Compare source ip and port against contact uri */
     if ((ip = str2ip(&(uri.host))) == NULL) {
-	LM_ERR("contact uri host is not an ip address\n");
-	return -1;
-    }
-    if (ip_addr_cmp(ip, &(msg->rcv.src_ip)) &&
-	((msg->rcv.src_port == uri.port_no) ||
-	 ((uri.port.len == 0) && (msg->rcv.src_port == 5060)))) {
-	LM_DBG("no need to add alias param\n");
-	return 2;
+	LM_DBG("contact uri host is not an ip address\n");
+    } else {
+	if (ip_addr_cmp(ip, &(msg->rcv.src_ip)) &&
+	    ((msg->rcv.src_port == uri.port_no) ||
+	     ((uri.port.len == 0) && (msg->rcv.src_port == 5060)))) {
+	    LM_DBG("no need to add alias param\n");
+	    return 2;
+	}
     }
 	
     /* Check if function has been called already */

+ 21 - 0
modules_k/permissions/doc/permissions_admin.xml

@@ -669,6 +669,27 @@ modparam("permissions", "tag_col", "peer_tag")
 ...
 modparam("permissions", "peer_tag_avp", "$avp(i:707)")
 ...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title><varname>peer_tag_mode</varname> (integer)</title>
+		<para>
+		Tag mode for allow_trusted(). 0 sets only the tag of the
+		first match. 1 adds the tags of all matches to the avp. In addition
+		the return value of allow_trusted() is the number of matches.
+		</para>
+		<para>
+		<emphasis>
+		Default value is <quote>0</quote>.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>peer_tag_mode</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("permissions", "peer_tag_mode", "1")
+...
 </programlisting>
 		</example>
 	</section>

+ 33 - 23
modules_k/permissions/hash.c

@@ -40,6 +40,9 @@
 static int     tag_avp_type;
 static int_str tag_avp;
 
+extern int peer_tag_mode;
+
+
 
 /*
  * Parse and set tag AVP specs
@@ -199,6 +202,7 @@ int hash_table_insert(struct trusted_list** table, char* src_ip,
  * Check if an entry exists in hash table that has given src_ip and protocol
  * value and pattern that matches to From URI.  If an entry exists and tag_avp
  * has been defined, tag of the entry is added as a value to tag_avp.
+ * Returns number of matches or -1 if none matched.
  */
 int match_hash_table(struct trusted_list** table, struct sip_msg* msg,
 		     char *src_ip_c_str, int proto)
@@ -209,6 +213,7 @@ int match_hash_table(struct trusted_list** table, struct sip_msg* msg,
 	struct trusted_list *np;
 	str src_ip;
 	int_str val;
+	int count = 0;
 
 	src_ip.s = src_ip_c_str;
 	src_ip.len = strlen(src_ip.s);
@@ -223,32 +228,37 @@ int match_hash_table(struct trusted_list** table, struct sip_msg* msg,
 	uri_string[uri.len] = (char)0;
 
 	for (np = table[perm_hash(src_ip)]; np != NULL; np = np->next) {
-	    if ((np->src_ip.len == src_ip.len) && 
-		(strncmp(np->src_ip.s, src_ip.s, src_ip.len) == 0) &&
-		((np->proto == PROTO_NONE) || (np->proto == proto))) {
-		if (!(np->pattern)) goto found;
-		if (regcomp(&preg, np->pattern, REG_NOSUB)) {
-		    LM_ERR("invalid regular expression\n");
-		    return -1;
-		}
-		if (regexec(&preg, uri_string, 0, (regmatch_t *)0, 0)) {
-		    regfree(&preg);
-		} else {
-		    regfree(&preg);
-		    goto found;
+		if ((np->src_ip.len == src_ip.len) && 
+		   (strncmp(np->src_ip.s, src_ip.s, src_ip.len) == 0) &&
+		   ((np->proto == PROTO_NONE) || (np->proto == proto))) {
+			if (np->pattern) {
+				if (regcomp(&preg, np->pattern, REG_NOSUB)) {
+					LM_ERR("invalid regular expression\n");
+					continue;
+				}
+				if (regexec(&preg, uri_string, 0, (regmatch_t *)0, 0)) {
+					regfree(&preg);
+					continue;
+				}
+				regfree(&preg);
+			}
+			/* Found a match */
+			if (tag_avp.n && np->tag.s) {
+				val.s = np->tag;
+				if (add_avp(tag_avp_type|AVP_VAL_STR, tag_avp, val) != 0) {
+					LM_ERR("setting of tag_avp failed\n");
+					return -1;
+				}
+			}
+			if (!peer_tag_mode)
+				return 1;
+			count++;
 		}
-	    }
 	}
-	return -1;
-found:
-	if (tag_avp.n && np->tag.s) {
-	    val.s = np->tag;
-	    if (add_avp(tag_avp_type|AVP_VAL_STR, tag_avp, val) != 0) {
-		LM_ERR("setting of tag_avp failed\n");
+	if (!count)
 		return -1;
-	    }
-	}
-	return 1;
+	else 
+		return count;
 }
 
 

+ 2 - 0
modules_k/permissions/permissions.c

@@ -68,6 +68,7 @@ str proto_col = str_init("proto");         /* Name of protocol column */
 str from_col = str_init("from_pattern");   /* Name of from pattern column */
 str tag_col = str_init("tag");             /* Name of tag column */
 str tag_avp_param = {NULL, 0};             /* Peer tag AVP spec */
+int peer_tag_mode = 0;                     /* Add tags form all mathcing peers to avp */
 
 /* for allow_address function */
 str address_table = str_init("address");   /* Name of address table */
@@ -159,6 +160,7 @@ static param_export_t params[] = {
 	{"from_col",           STR_PARAM, &from_col.s        },
 	{"tag_col",            STR_PARAM, &tag_col.s         },
 	{"peer_tag_avp",       STR_PARAM, &tag_avp_param.s   },
+	{"peer_tag_mode",      INT_PARAM, &peer_tag_mode     },
 	{"address_table",      STR_PARAM, &address_table.s   },
 	{"grp_col",            STR_PARAM, &grp_col.s         },
 	{"ip_addr_col",        STR_PARAM, &ip_addr_col.s     },

+ 2 - 0
modules_k/permissions/permissions.h

@@ -61,6 +61,8 @@ extern str grp_col;       /* Name of address group column */
 extern str ip_addr_col;   /* Name of ip address column */
 extern str mask_col;      /* Name of mask column */
 extern str port_col;      /* Name of port column */
+extern int peer_tag_mode; /* Matching mode */
+
 
 typedef struct int_or_pvar {
     unsigned int i;

+ 41 - 37
modules_k/permissions/trusted.c

@@ -328,18 +328,19 @@ static inline int match_proto(const char *proto_string, int proto_int)
 }
 
 /*
- * Matches from uri against patterns returned from database.  Returns 1 when
- * first pattern matches and 0 if none of the patterns match.
+ * Matches from uri against patterns returned from database.  Returns number
+ * of matches or -1 if none of the patterns match.
  */
 static int match_res(struct sip_msg* msg, int proto, db1_res_t* _r)
 {
-        int i, tag_avp_type;
+	int i, tag_avp_type;
 	str uri;
 	char uri_string[MAX_URI_SIZE+1];
 	db_row_t* row;
 	db_val_t* val;
 	regex_t preg;
 	int_str tag_avp, avp_val;
+	int count = 0;
 
 	if (parse_from_header(msg) < 0) return -1;
 	uri = get_from(msg)->uri;
@@ -349,46 +350,49 @@ static int match_res(struct sip_msg* msg, int proto, db1_res_t* _r)
 	}
 	memcpy(uri_string, uri.s, uri.len);
 	uri_string[uri.len] = (char)0;
+	get_tag_avp(&tag_avp, &tag_avp_type);
 
 	row = RES_ROWS(_r);
-		
+
 	for(i = 0; i < RES_ROW_N(_r); i++) {
-	    val = ROW_VALUES(row + i);
-	    if ((ROW_N(row + i) == 3) &&
-		(VAL_TYPE(val) == DB1_STRING) && !VAL_NULL(val) &&
-		match_proto(VAL_STRING(val), proto) &&
-		(VAL_NULL(val + 1) ||
-		 ((VAL_TYPE(val + 1) == DB1_STRING) && !VAL_NULL(val + 1))) &&
-		(VAL_NULL(val + 2) ||
-		 ((VAL_TYPE(val + 2) == DB1_STRING) && !VAL_NULL(val + 2))))
-	    {
-		if (VAL_NULL(val + 1)) goto found;
-		if (regcomp(&preg, (char *)VAL_STRING(val + 1), REG_NOSUB)) {
-		    LM_ERR("invalid regular expression\n");
-		    continue;
-		}
-		if (regexec(&preg, uri_string, 0, (regmatch_t *)0, 0)) {
-		    regfree(&preg);
-		    continue;
-		} else {
-		    regfree(&preg);
-		    goto found;
+		val = ROW_VALUES(row + i);
+		if ((ROW_N(row + i) == 3) &&
+		    (VAL_TYPE(val) == DB1_STRING) && !VAL_NULL(val) &&
+		    match_proto(VAL_STRING(val), proto) &&
+		    (VAL_NULL(val + 1) ||
+		      ((VAL_TYPE(val + 1) == DB1_STRING) && !VAL_NULL(val + 1))) &&
+		    (VAL_NULL(val + 2) ||
+		      ((VAL_TYPE(val + 2) == DB1_STRING) && !VAL_NULL(val + 2))))
+		{
+			if (!VAL_NULL(val + 1)) {
+				if (regcomp(&preg, (char *)VAL_STRING(val + 1), REG_NOSUB)) {
+					LM_ERR("invalid regular expression\n");
+					continue;
+				}
+				if (regexec(&preg, uri_string, 0, (regmatch_t *)0, 0)) {
+					regfree(&preg);
+					continue;
+				}
+			    regfree(&preg);
+			}
+			/* Found a match */
+			if (tag_avp.n && !VAL_NULL(val + 2)) {
+				avp_val.s.s = (char *)VAL_STRING(val + 2);
+				avp_val.s.len = strlen(avp_val.s.s);
+				if (add_avp(tag_avp_type|AVP_VAL_STR, tag_avp, avp_val) != 0) {
+					LM_ERR("failed to set of tag_avp failed\n");
+					return -1;
+				}
+			}
+			if (!peer_tag_mode) 
+				return 1;
+			count++;
 		}
-	    }
 	}
-	return -1;
-
-found:
-	get_tag_avp(&tag_avp, &tag_avp_type);
-	if (tag_avp.n && !VAL_NULL(val + 2)) {
-	    avp_val.s.s = (char *)VAL_STRING(val + 2);
-	    avp_val.s.len = strlen(avp_val.s.s);
-	    if (add_avp(tag_avp_type|AVP_VAL_STR, tag_avp, avp_val) != 0) {
-		LM_ERR("failed to set of tag_avp failed\n");
+	if (!count)
 		return -1;
-	    }
-	}
-	return 1;
+	else 
+		return count;
 }
 
 

+ 6 - 0
modules_k/pv/pv.c

@@ -220,6 +220,9 @@ static pv_export_t mod_pvs[] = {
 	{{"ml", (sizeof("ml")-1)}, /* */
 		PVT_OTHER, pv_get_msg_len, 0,
 		0, 0, 0, 0},
+	{{"mt", (sizeof("mt")-1)}, /* */
+		PVT_OTHER, pv_get_msgtype, 0,
+		0, 0, 0, 0},
 	{{"od", (sizeof("od")-1)}, /* */
 		PVT_OTHER, pv_get_ouri_attr, 0,
 		0, 0, pv_init_iname, 2},
@@ -361,6 +364,9 @@ static pv_export_t mod_pvs[] = {
 	{{"true", (sizeof("true")-1)}, /* */
 		PVT_OTHER, pv_get_true, 0,
 		0, 0, 0, 0},
+	{{"Tb", (sizeof("Tb")-1)}, /* */
+		PVT_OTHER, pv_get_timeb, 0,
+		0, 0, 0, 0},
 	{{"Tf", (sizeof("Tf")-1)}, /* */
 		PVT_CONTEXT, pv_get_timef, 0,
 		0, 0, 0, 0},

+ 16 - 0
modules_k/pv/pv_core.c

@@ -152,6 +152,22 @@ int pv_get_methodid(struct sip_msg *msg, pv_param_t *param,
 			(unsigned int)(get_cseq(msg)->method_id));
 }
 
+int pv_get_msgtype(struct sip_msg *msg, pv_param_t *param,
+		pv_value_t *res)
+{
+	unsigned int type = 0;
+
+	if(msg==NULL)
+		return -1;
+
+	if(msg->first_line.type == SIP_REQUEST)
+		type = 1;
+	else if(msg->first_line.type == SIP_REPLY)
+		type = 2;
+
+	return pv_get_uintval(msg, param, res, type);
+}
+
 int pv_get_version(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res)
 {

+ 3 - 0
modules_k/pv/pv_core.h

@@ -48,6 +48,9 @@ int pv_get_method(struct sip_msg *msg, pv_param_t *param,
 int pv_get_methodid(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res);
 
+int pv_get_msgtype(struct sip_msg *msg, pv_param_t *param,
+		pv_value_t *res);
+
 int pv_get_status(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res);
 

+ 9 - 0
modules_k/pv/pv_time.c

@@ -30,6 +30,7 @@
 #include <sys/time.h>
 
 #include "../../dprint.h"
+#include "../../globals.h"
 #include "../../pvar.h"
 
 #include "pv_time.h"
@@ -254,6 +255,14 @@ int pv_get_timef(struct sip_msg *msg, pv_param_t *param,
 	return pv_get_strintval(msg, param, res, &s, (int)t);
 }
 
+int pv_get_timeb(struct sip_msg *msg, pv_param_t *param,
+		pv_value_t *res)
+{
+	if(msg==NULL)
+		return -1;
+	return pv_get_uintval(msg, param, res, (unsigned int)up_since);
+}
+
 static struct timeval _timeval_ts;
 static unsigned int _timeval_msg_id = 0;
 static char _timeval_ts_buf[32];

+ 2 - 0
modules_k/pv/pv_time.h

@@ -40,6 +40,8 @@ int pv_get_times(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res);
 int pv_get_timef(struct sip_msg *msg, pv_param_t *param,
 		pv_value_t *res);
+int pv_get_timeb(struct sip_msg *msg, pv_param_t *param,
+		pv_value_t *res);
 
 int pv_parse_timeval_name(pv_spec_p sp, str *in);
 int pv_get_timeval(struct sip_msg *msg, pv_param_t *param,

+ 77 - 2
modules_k/pv/pv_trans.c

@@ -67,7 +67,7 @@ static char _tr_buffer[TR_BUFFER_SIZE];
 int tr_eval_string(struct sip_msg *msg, tr_param_t *tp, int subtype,
 		pv_value_t *val)
 {
-	int i, j;
+	int i, j, max;
 	char *p, *s;
 	str st;
 	pv_value_t v;
@@ -452,6 +452,50 @@ int tr_eval_string(struct sip_msg *msg, tr_param_t *tp, int subtype,
 			val->rs.len -= i;
 			break;
 
+		case TR_S_PREFIXES:
+		case TR_S_PREFIXES_QUOT:
+			if(!(val->flags&PV_VAL_STR))
+				val->rs.s = int2str(val->ri, &val->rs.len);
+
+			/* Set maximum prefix length */
+			max = val->rs.len;
+			if(tp!=NULL) {
+				if(tp->type==TR_PARAM_NUMBER) {
+					if (tp->v.n > 0 && tp->v.n < max)
+						max = tp->v.n;
+				} else {
+					if(pv_get_spec_value(msg, (pv_spec_p)tp->v.data, &v)!=0
+							|| (!(v.flags&PV_VAL_INT)))
+					{
+						LM_ERR("prefixes cannot get max\n");
+						return -1;
+					}
+					if (v.ri > 0 && v.ri < max)
+						max  = v.ri;
+				}
+			}
+
+			if(max * (max/2 + (subtype==TR_S_PREFIXES_QUOT ? 1 : 3)) > TR_BUFFER_SIZE-1) {
+				LM_ERR("prefixes buffer too short\n");
+				return -1;
+			}
+
+			j = 0;
+			for (i=1; i <= max; i++) {
+				if (subtype==TR_S_PREFIXES_QUOT)
+					_tr_buffer[j++] = '\'';
+				memcpy(&(_tr_buffer[j]), val->rs.s, i);
+				j += i;
+				if (subtype==TR_S_PREFIXES_QUOT)
+					_tr_buffer[j++] = '\'';
+				_tr_buffer[j++] = ',';
+			}
+			memset(val, 0, sizeof(pv_value_t));
+			val->flags = PV_VAL_STR;
+			val->rs.s = _tr_buffer;
+			val->rs.len = j-1;
+			break;
+
 		default:
 			LM_ERR("unknown subtype %d\n",
 					subtype);
@@ -1236,6 +1280,38 @@ char* tr_parse_string(str* in, trans_t *t)
 	} else if(name.len==14 && strncasecmp(name.s, "unescape.param", 14)==0) {
 		t->subtype = TR_S_UNESCAPEPARAM;
 		goto done;
+	} else if(name.len==8 && strncasecmp(name.s, "prefixes", 8)==0) {
+		t->subtype = TR_S_PREFIXES;
+		if(*p!=TR_PARAM_MARKER)
+			goto done;
+		p++;
+		_tr_parse_nparam(p, p0, tp, spec, n, sign, in, s);
+		t->params = tp;
+		tp = 0;
+		while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++;
+		if(*p!=TR_RBRACKET)
+		{
+			LM_ERR("invalid prefixes transformation: %.*s!!\n",
+				in->len, in->s);
+			goto error;
+		}
+		goto done;
+	} else if(name.len==15 && strncasecmp(name.s, "prefixes.quoted", 15)==0) {
+		t->subtype = TR_S_PREFIXES_QUOT;
+		if(*p!=TR_PARAM_MARKER)
+			goto done;
+		p++;
+		_tr_parse_nparam(p, p0, tp, spec, n, sign, in, s);
+		t->params = tp;
+		tp = 0;
+		while(*p && (*p==' ' || *p=='\t' || *p=='\n')) p++;
+		if(*p!=TR_RBRACKET)
+		{
+			LM_ERR("invalid prefixes transformation: %.*s!!\n",
+				in->len, in->s);
+			goto error;
+		}
+		goto done;
 	} else if(name.len==6 && strncasecmp(name.s, "substr", 6)==0) {
 		t->subtype = TR_S_SUBSTR;
 		if(*p!=TR_PARAM_MARKER)
@@ -1706,4 +1782,3 @@ done:
 	t->name = name;
 	return p;
 }
-

+ 1 - 1
modules_k/pv/pv_trans.h

@@ -39,7 +39,7 @@ enum _tr_s_subtype {
 	TR_S_SELECT, TR_S_ENCODEHEXA, TR_S_DECODEHEXA,
 	TR_S_ESCAPECOMMON, TR_S_UNESCAPECOMMON, TR_S_ESCAPEUSER, TR_S_UNESCAPEUSER,
 	TR_S_ESCAPEPARAM, TR_S_UNESCAPEPARAM, TR_S_TOLOWER, TR_S_TOUPPER,
-	TR_S_STRIP, TR_S_STRIPTAIL
+	TR_S_STRIP, TR_S_STRIPTAIL, TR_S_PREFIXES, TR_S_PREFIXES_QUOT
 };
 enum _tr_uri_subtype {
 	TR_URI_NONE=0, TR_URI_USER, TR_URI_HOST, TR_URI_PASSWD, TR_URI_PORT,

+ 4 - 2
modules_k/pv/pv_xavp.c

@@ -99,7 +99,7 @@ int pv_get_xavp(struct sip_msg *msg, pv_param_t *param,
 	if(idx<0)
 	{
 		count = xavp_count(&xname->name, NULL);
-		idx = count + idx + 1;
+		idx = count + idx;
 	}
 	avp = xavp_get_by_index(&xname->name, idx, NULL);
 	if(avp==NULL)
@@ -107,6 +107,8 @@ int pv_get_xavp(struct sip_msg *msg, pv_param_t *param,
 	if(xname->next==NULL)
 		return pv_xavp_get_value(msg, param, res, avp);
 
+	idx = 0;
+	idxf = 0;
 	if(xname->next->index.type==PVT_EXTRA)
 	{
 		/* get the index */
@@ -120,7 +122,7 @@ int pv_get_xavp(struct sip_msg *msg, pv_param_t *param,
 	if(idx<0)
 	{
 		count = xavp_count(&xname->next->name, &avp->val.v.xavp);
-		idx = count + idx + 1;
+		idx = count + idx;
 	}
 	avp = xavp_get_by_index(&xname->next->name, idx, &avp->val.v.xavp);
 	if(avp==NULL)

+ 196 - 142
modules_k/regex/README

@@ -1,53 +1,52 @@
 Regex Module
 
-Iñaki Baz Castillo
+Iñaki Baz Castillo
 
    <[email protected]>
 
 Edited by
 
-Iñaki Baz Castillo
+Iñaki Baz Castillo
 
    <[email protected]>
 
-   Copyright © 2009 Iñaki Baz Castillo
+   Copyright © 2009 Iñaki Baz Castillo
    Revision History
-   Revision $Revision: 5462 $ $Date: 2009-01-14 17:05:51 +0100
-                              (Mi, 14 Jan 2009) $
-     __________________________________________________________
+   Revision $Revision$ $Date$
+     __________________________________________________________________
 
    Table of Contents
 
    1. Admin Guide
 
-        1.1. Overview
-        1.2. Dependencies
+        1. Overview
+        2. Dependencies
 
-              1.2.1. Kamailio Modules
-              1.2.2. External Libraries or Applications
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
 
-        1.3. Exported Parameters
+        3. Exported Parameters
 
-              1.3.1. file (string)
-              1.3.2. max_groups (int)
-              1.3.3. group_max_size (int)
-              1.3.4. pcre_caseless (int)
-              1.3.5. pcre_multiline (int)
-              1.3.6. pcre_dotall (int)
-              1.3.7. pcre_extended (int)
+              3.1. file (string)
+              3.2. max_groups (int)
+              3.3. group_max_size (int)
+              3.4. pcre_caseless (int)
+              3.5. pcre_multiline (int)
+              3.6. pcre_dotall (int)
+              3.7. pcre_extended (int)
 
-        1.4. Exported Functions
+        4. Exported Functions
 
-              1.4.1. pcre_match (string, pcre_regex)
-              1.4.2. pcre_match_group (string [, group])
+              4.1. pcre_match (string, pcre_regex)
+              4.2. pcre_match_group (string [, group])
 
-        1.5. Exported MI Functions
+        5. Exported MI Functions
 
-              1.5.1. regex_reload
+              5.1. regex_reload
 
-        1.6. Installation and Running
+        6. Installation and Running
 
-              1.6.1. File format
+              6.1. File format
 
    List of Examples
 
@@ -61,165 +60,205 @@ I
    1.8. pcre_match usage (forcing case insensitive)
    1.9. pcre_match usage (using "end of line" symbol)
    1.10. pcre_match_group usage
-   1.11. regex file
-   1.12. Using with pua_usrloc
-   1.13. Incorrect groups file
+   1.11. pcre_match_group usage (using a pseudo-variable as group)
+   1.12. regex file
+   1.13. Using with pua_usrloc
+   1.14. Incorrect groups file
 
 Chapter 1. Admin Guide
 
-1.1. Overview
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Exported Parameters
+
+        3.1. file (string)
+        3.2. max_groups (int)
+        3.3. group_max_size (int)
+        3.4. pcre_caseless (int)
+        3.5. pcre_multiline (int)
+        3.6. pcre_dotall (int)
+        3.7. pcre_extended (int)
+
+   4. Exported Functions
+
+        4.1. pcre_match (string, pcre_regex)
+        4.2. pcre_match_group (string [, group])
+
+   5. Exported MI Functions
+
+        5.1. regex_reload
+
+   6. Installation and Running
 
-   This module offers matching operations against regular
-   expressions using the powerful PCRE library.
+        6.1. File format
 
-   A text file containing regular expressions categorized in
-   groups is compiled when the module is loaded, storing the
-   compiled PCRE objects in an array. A function to match a string
-   or pseudo-variable against any of these groups is provided. The
-   text file can be modified and reloaded at any time via a MI
-   command. The module also offers a function to perform a PCRE
-   matching operation against a regular expression provided as
-   function parameter.
+1. Overview
 
-   For a detailed list of PCRE features read the man page of the
-   library.
+   This module offers matching operations against regular expressions
+   using the powerful PCRE library.
 
-1.2. Dependencies
+   A text file containing regular expressions categorized in groups is
+   compiled when the module is loaded, storing the compiled PCRE objects
+   in an array. A function to match a string or pseudo-variable against
+   any of these groups is provided. The text file can be modified and
+   reloaded at any time via a MI command. The module also offers a
+   function to perform a PCRE matching operation against a regular
+   expression provided as function parameter.
 
-1.2.1. Kamailio Modules
+   For a detailed list of PCRE features read the man page of the library.
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+
+2.1. Kamailio Modules
 
    The following modules must be loaded before this module:
      * No dependencies on other Kamailio modules.
 
-1.2.2. External Libraries or Applications
+2.2. External Libraries or Applications
 
-   The following libraries or applications must be installed
-   before running Kamailio with this module loaded:
+   The following libraries or applications must be installed before
+   running Kamailio with this module loaded:
      * libpcre - the libraries of PCRE.
 
-1.3. Exported Parameters
+3. Exported Parameters
 
-1.3.1. file (string)
+   3.1. file (string)
+   3.2. max_groups (int)
+   3.3. group_max_size (int)
+   3.4. pcre_caseless (int)
+   3.5. pcre_multiline (int)
+   3.6. pcre_dotall (int)
+   3.7. pcre_extended (int)
 
-   Text file containing the regular expression groups. It must be
-   set in order to enable the group matching function.
+3.1. file (string)
 
-   Default value is "NULL".
+   Text file containing the regular expression groups. It must be set in
+   order to enable the group matching function.
+
+   Default value is “NULL�.
 
    Example 1.1. Set file parameter
 ...
 modparam("regex", "file", "/etc/kamailio/regex_groups")
 ...
 
-1.3.2. max_groups (int)
+3.2. max_groups (int)
 
    Max number of regular expression groups in the text file.
 
-   Default value is "20".
+   Default value is “20�.
 
    Example 1.2. Set max_groups parameter
 ...
 modparam("regex", "max_groups", 40)
 ...
 
-1.3.3. group_max_size (int)
+3.3. group_max_size (int)
 
    Max content size of a group in the text file.
 
-   Default value is "8192".
+   Default value is “8192�.
 
    Example 1.3. Set group_max_size parameter
 ...
 modparam("regex", "group_max_size", 16384)
 ...
 
-1.3.4. pcre_caseless (int)
+3.4. pcre_caseless (int)
 
-   If this options is set, matching is done caseless. It is
-   equivalent to Perl's /i option, and it can be changed within a
-   pattern by a (?i) or (?-i) option setting.
+   If this options is set, matching is done caseless. It is equivalent to
+   Perl's /i option, and it can be changed within a pattern by a (?i) or
+   (?-i) option setting.
 
-   Default value is "0".
+   Default value is “0�.
 
    Example 1.4. Set pcre_caseless parameter
 ...
 modparam("regex", "pcre_caseless", 1)
 ...
 
-1.3.5. pcre_multiline (int)
+3.5. pcre_multiline (int)
 
-   By default, PCRE treats the subject string as consisting of a
-   single line of characters (even if it actually contains
-   newlines). The "start of line" metacharacter (^) matches only
-   at the start of the string, while the "end of line"
-   metacharacter ($) matches only at the end of the string, or
-   before a terminating newline.
+   By default, PCRE treats the subject string as consisting of a single
+   line of characters (even if it actually contains newlines). The "start
+   of line" metacharacter (^) matches only at the start of the string,
+   while the "end of line" metacharacter ($) matches only at the end of
+   the string, or before a terminating newline.
 
    When this option is set, the "start of line" and "end of line"
-   constructs match immediately following or immediately before
-   internal newlines in the subject string, respectively, as well
-   as at the very start and end. This is equivalent to Perl's /m
-   option, and it can be changed within a pattern by a (?m) or
-   (?-m) option setting. If there are no newlines in a subject
-   string, or no occurrences of ^ or $ in a pattern, setting this
-   option has no effect.
+   constructs match immediately following or immediately before internal
+   newlines in the subject string, respectively, as well as at the very
+   start and end. This is equivalent to Perl's /m option, and it can be
+   changed within a pattern by a (?m) or (?-m) option setting. If there
+   are no newlines in a subject string, or no occurrences of ^ or $ in a
+   pattern, setting this option has no effect.
 
-   Default value is "0".
+   Default value is “0�.
 
    Example 1.5. Set pcre_multiline parameter
 ...
 modparam("regex", "pcre_multiline", 1)
 ...
 
-1.3.6. pcre_dotall (int)
+3.6. pcre_dotall (int)
 
-   If this option is set, a dot metacharater in the pattern
-   matches all characters, including those that indicate newline.
-   Without it, a dot does not match when the current position is
-   at a newline. This option is equivalent to Perl's /s option,
-   and it can be changed within a pattern by a (?s) or (?-s)
-   option setting.
+   If this option is set, a dot metacharater in the pattern matches all
+   characters, including those that indicate newline. Without it, a dot
+   does not match when the current position is at a newline. This option
+   is equivalent to Perl's /s option, and it can be changed within a
+   pattern by a (?s) or (?-s) option setting.
 
-   Default value is "0".
+   Default value is “0�.
 
    Example 1.6. Set pcre_dotall parameter
 ...
 modparam("regex", "pcre_dotall", 1)
 ...
 
-1.3.7. pcre_extended (int)
+3.7. pcre_extended (int)
 
-   If this option is set, whitespace data characters in the
-   pattern are totally ignored except when escaped or inside a
-   character class. Whitespace does not include the VT character
-   (code 11). In addition, characters between an unescaped #
-   outside a character class and the next newline, inclusive, are
-   also ignored. This is equivalent to Perl's /x option, and it
-   can be changed within a pattern by a (?x) or (?-x) option
-   setting.
+   If this option is set, whitespace data characters in the pattern are
+   totally ignored except when escaped or inside a character class.
+   Whitespace does not include the VT character (code 11). In addition,
+   characters between an unescaped # outside a character class and the
+   next newline, inclusive, are also ignored. This is equivalent to Perl's
+   /x option, and it can be changed within a pattern by a (?x) or (?-x)
+   option setting.
 
-   Default value is "0".
+   Default value is “0�.
 
    Example 1.7. Set pcre_extended parameter
 ...
 modparam("regex", "pcre_extended", 1)
 ...
 
-1.4. Exported Functions
+4. Exported Functions
+
+   4.1. pcre_match (string, pcre_regex)
+   4.2. pcre_match_group (string [, group])
 
-1.4.1.  pcre_match (string, pcre_regex)
+4.1.  pcre_match (string, pcre_regex)
 
-   Matches the given string parameter against the regular
-   expression pcre_regex, which is compiled into a PCRE object.
-   Returns TRUE if it matches, FALSE otherwise.
+   Matches the given string parameter against the regular expression
+   pcre_regex, which is compiled in runtime into a PCRE object. Returns
+   TRUE if it matches, FALSE otherwise.
 
    Meaning of the parameters is as follows:
      * string - String or pseudo-variable to compare.
-     * pcre_regex - Regular expression to be compiled in a PCRE
-       object. It can be a string or pseudo-variable.
+     * pcre_regex - Regular expression to be compiled in a PCRE object. It
+       can be a string or pseudo-variable.
 
-   NOTE: To use the "end of line" symbol '$' in the pcre_regex
-   parameter use '$$'.
+   NOTE: To use the "end of line" symbol '$' in the pcre_regex parameter
+   use '$$'.
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
@@ -233,41 +272,54 @@ if (pcre_match("$ua", "(?i)^twinkle")) {
 
    Example 1.9.  pcre_match usage (using "end of line" symbol)
 ...
-if (pcre_match("$rU", "^user[1234]$$")) {  # Will be converted to "^user
-[1234]$"
+if (pcre_match("$rU", "^user[1234]$$")) {  # Will be converted to "^user[1234]$"
     xlog("L_INFO", "RURI username matches\n");
 }
 ...
 
-1.4.2.  pcre_match_group (string [, group])
+4.2.  pcre_match_group (string [, group])
 
-   It uses the groups readed from the text file (see
-   Section 1.6.1, "File format") to match the given string
-   parameter against the compiled regular expression in group
-   number group. Returns TRUE if it matches, FALSE otherwise.
+   Tries to match the given string against a specific group in the text
+   file (see Section 6.1, “File format�). Returns TRUE if it matches,
+   FALSE otherwise.
 
    Meaning of the parameters is as follows:
      * string - String or pseudo-variable to compare.
-     * group - Number of group to use in the operation. If not
-       specified then 0 (the first group) is used.
+     * group - Number of group to use in the operation. If not specified
+       then 0 (the first group) is used. A pseudo-variable containing an
+       integer can also be used.
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    ONREPLY_ROUTE, BRANCH_ROUTE and LOCAL_ROUTE.
 
    Example 1.10.  pcre_match_group usage
 ...
-if (pcre_match_group("$rU", 2)) {
+if (pcre_match_group("$rU", "2")) {
     xlog("L_INFO", "RURI username matches group 2\n");
 }
 ...
 
-1.5. Exported MI Functions
+   Example 1.11.  pcre_match_group usage (using a pseudo-variable as
+   group)
+                                        ...
+                                        $avp(i:10) = 5;  # Maybe got from a DB q
+uery.
+                                        if (pcre_match_group("$ua", "$avp(i:10)"
+)) {
+                                        xlog("L_INFO", "User-Agent matches group
+ 5\n");
+                                        }
+                                        ...
+
+5. Exported MI Functions
 
-1.5.1.  regex_reload
+   5.1. regex_reload
+
+5.1.  regex_reload
 
    Causes regex module to re-read the content of the text file and
-   re-compile the regular expressions. The number of groups in the
-   file can be modified safely.
+   re-compile the regular expressions. The number of groups in the file
+   can be modified safely.
 
    Name: regex_reload
 
@@ -277,19 +329,21 @@ if (pcre_match_group("$rU", 2)) {
 :regex_reload:_reply_fifo_file_
 _empty_line_
 
-1.6. Installation and Running
+6. Installation and Running
+
+   6.1. File format
 
-1.6.1. File format
+6.1. File format
 
-   The file contains regular expressions categorized in groups.
-   Each group starts with "[number]" line. Lines starting by
-   space, tab, CR, LF or # (comments) are ignored. Each regular
-   expression must take up just one line, this means that a
-   regular expression can't be splitted in various lines.
+   The file contains regular expressions categorized in groups. Each group
+   starts with "[number]" line. Lines starting by space, tab, CR, LF or #
+   (comments) are ignored. Each regular expression must take up just one
+   line, this means that a regular expression can't be splitted in various
+   lines.
 
    An example of the file format would be the following:
 
-   Example 1.11. regex file
+   Example 1.12. regex file
 ### List of User-Agents publishing presence status
 [0]
 
@@ -330,12 +384,12 @@ group 0: ((^Twinkle/1)|(^X-Lite)|(^eyeBeam)|(^Bria)|(^SIP Communicator)|
 group 1: ((^190\.232\.250\.226$)|(^122\.5\.27\.125$)|(^86\.92\.112\.))
 group 2: ((^1\d{3}$)|(^((\+|00)34)?900\d{6}$))
 
-   The first group can be used to avoid auto-generated PUBLISH
-   (pua_usrloc module) for UA's already supporting presence:
+   The first group can be used to avoid auto-generated PUBLISH (pua_usrloc
+   module) for UA's already supporting presence:
 
-   Example 1.12. Using with pua_usrloc
+   Example 1.13. Using with pua_usrloc
 route[REGISTER] {
-    if (! pcre_match_group("$ua", 0)) {
+    if (! pcre_match_group("$ua", "0")) {
         xlog("L_INFO", "Auto-generated PUBLISH for $fu ($ua)\n");
         pua_set_publish();
     }
@@ -343,12 +397,12 @@ route[REGISTER] {
     exit;
 }
 
-   NOTE: It's important to understand that the numbers in each
-   group header ([number]) must start by 0. If not, the real group
-   number will not match the number appearing in the file. For
-   example, the following text file:
+   NOTE: It's important to understand that the numbers in each group
+   header ([number]) must start by 0. If not, the real group number will
+   not match the number appearing in the file. For example, the following
+   text file:
 
-   Example 1.13. Incorrect groups file
+   Example 1.14. Incorrect groups file
 [1]
 ^aaa
 ^bbb
@@ -361,16 +415,16 @@ route[REGISTER] {
 group 0: ((^aaa)|(^bbb))
 group 1: ((^ccc)|(^ddd))
 
-   Note that the real index doesn't match the group number in the
-   file. This is, compiled group 0 always points to the first
-   group in the file, regardless of its number in the file. In
-   fact, the group number appearing in the file is used for
-   nothing but for delimiting different groups.
+   Note that the real index doesn't match the group number in the file.
+   This is, compiled group 0 always points to the first group in the file,
+   regardless of its number in the file. In fact, the group number
+   appearing in the file is used for nothing but for delimiting different
+   groups.
 
-   NOTE: A line containing a regular expression cannot start by
-   '[' since it would be treated as a new group. The same for
-   lines starting by space, tab, or '#' (they would be ignored by
-   the parser). As a workaround, using brackets would work:
+   NOTE: A line containing a regular expression cannot start by '[' since
+   it would be treated as a new group. The same for lines starting by
+   space, tab, or '#' (they would be ignored by the parser). As a
+   workaround, using brackets would work:
 [0]
 ([0-9]{9})
 ( #abcde)

+ 23 - 9
modules_k/regex/doc/regex_admin.xml

@@ -237,8 +237,8 @@ modparam("regex", "pcre_extended", 1)
 
 			<para>
 				Matches the given string parameter against the regular expression pcre_regex,
-				which is compiled into a PCRE object. Returns TRUE if it matches, FALSE
-				otherwise.
+				which is compiled in runtime into a PCRE object. Returns TRUE if it matches,
+				FALSE otherwise.
 			</para>
 
 			<para>Meaning of the parameters is as follows:</para>
@@ -300,10 +300,9 @@ if (pcre_match("$rU", "^user[1234]$$")) {  # Will be converted to "^user[1234]$"
 			</title>
 
 			<para>
-				It uses the groups readed from the text file
-				(see <xref linkend="file-format-id"/>) to match the given string
-				parameter against the compiled regular expression in group number group.
-				Returns TRUE if it matches, FALSE otherwise.
+				Tries to match the given string against a specific group in the text
+				file (see <xref linkend="file-format-id"/>). Returns TRUE if it matches,
+				FALSE otherwise.
 			</para>
 
 			<para>Meaning of the parameters is as follows:</para>
@@ -317,7 +316,8 @@ if (pcre_match("$rU", "^user[1234]$$")) {  # Will be converted to "^user[1234]$"
 				<listitem>
 					<para>
 						<emphasis>group</emphasis> - Number of group to use in the operation.
-						If not specified then 0 (the first group) is used.
+						If not specified then 0 (the first group) is used. A pseudo-variable
+						containing an integer can also be used.
 					</para>
 				</listitem>
 			</itemizedlist>
@@ -333,13 +333,27 @@ if (pcre_match("$rU", "^user[1234]$$")) {  # Will be converted to "^user[1234]$"
 				</title>
 <programlisting format="linespecific">
 ...
-if (pcre_match_group("$rU", 2)) {
+if (pcre_match_group("$rU", "2")) {
     xlog("L_INFO", "RURI username matches group 2\n");
 }
 ...
 </programlisting>
 			</example>
 
+			<example>
+				<title>
+					<function>pcre_match_group</function> usage (using a pseudo-variable as group)
+				</title>
+				<programlisting format="linespecific">
+...
+$avp(i:10) = 5;  # Maybe got from a DB query.
+if (pcre_match_group("$ua", "$avp(i:10)")) {
+    xlog("L_INFO", "User-Agent matches group 5\n");
+}
+...
+				</programlisting>
+			</example>
+ 
 		</section>
 
 	</section>
@@ -455,7 +469,7 @@ group 2: ((^1\d{3}$)|(^((\+|00)34)?900\d{6}$))
 				<title>Using with pua_usrloc</title>
 <programlisting  format="linespecific">
 route[REGISTER] {
-    if (! pcre_match_group("$ua", 0)) {
+    if (! pcre_match_group("$ua", "0")) {
         xlog("L_INFO", "Auto-generated PUBLISH for $fu ($ua)\n");
         pua_set_publish();
     }

+ 13 - 7
modules_k/regex/regex_mod.c

@@ -23,7 +23,8 @@
  *
  * History:
  * --------
- *  2009-01-14  initial version (Iñaki Baz Castillo)
+ *  2011-02-22  pcre_match_group() allows now pseudo-variable as group argument.
+ *  2009-01-14  initial version (Iñaki Baz Castillo).
  */
 
 
@@ -119,7 +120,7 @@ static cmd_export_t cmds[] =
 {
 	{ "pcre_match", (cmd_function)w_pcre_match, 2, fixup_spve_spve, 0,
 		REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
-	{ "pcre_match_group", (cmd_function)w_pcre_match_group, 2, fixup_spve_uint, 0,
+	{ "pcre_match_group", (cmd_function)w_pcre_match_group, 2, fixup_spve_spve, 0,
 		REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
 	{ "pcre_match_group", (cmd_function)w_pcre_match_group, 1, fixup_spve_null, 0,
 		REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
@@ -383,7 +384,7 @@ static int load_pcres(int action)
 	}
 	
 	/* Log the group patterns */
-	LM_NOTICE("num groups = %d\n\n", num_pcres_tmp);
+	LM_NOTICE("num groups = %d\n", num_pcres_tmp);
 	for (i=0; i < num_pcres_tmp; i++) {
 		LM_NOTICE("<group[%d]>%s</group[%d]> (size = %i)\n", i, patterns[i], i, (int)strlen(patterns[i]));
 	}
@@ -587,8 +588,8 @@ static int w_pcre_match(struct sip_msg* _msg, char* _s1, char* _s2)
 /*! \brief Return true if the string argument matches the pattern group parameter */
 static int w_pcre_match_group(struct sip_msg* _msg, char* _s1, char* _s2)
 {
-	str string;
-	int num_pcre;
+	str string, group;
+	unsigned int num_pcre;
 	int pcre_rc;
 	
 	/* Check if group matching feature is enabled */
@@ -605,7 +606,12 @@ static int w_pcre_match_group(struct sip_msg* _msg, char* _s1, char* _s2)
 	if (_s2 == NULL) {
 		num_pcre = 0;
 	} else {
-		num_pcre = (uint)(long)_s2;
+		if (fixup_get_svalue(_msg, (gparam_p)_s2, &group))
+		{
+			LM_ERR("cannot print the format for second param\n");
+			return -5;
+		}
+		str2int(&group, &num_pcre);
 	}
 	
 	if (num_pcre >= *num_pcres) {
@@ -615,7 +621,7 @@ static int w_pcre_match_group(struct sip_msg* _msg, char* _s1, char* _s2)
 	
 	if (fixup_get_svalue(_msg, (gparam_p)_s1, &string))
 	{
-		LM_ERR("cannot print the format\n");
+		LM_ERR("cannot print the format for first param\n");
 		return -5;
 	}
 	

+ 41 - 5
modules_k/siputils/README

@@ -24,6 +24,10 @@ Gabriel Vasile
 
    FhG FOKUS
 
+Juha Heinanen
+
+   TutPro Inc.
+
 Edited by
 
 Jan Janak
@@ -87,6 +91,8 @@ Gabriel Vasile
               4.18. append_rpid_hf(prefix, suffix)
               4.19. is_rpid_user_e164()
               4.20. set_uri_user(uri, user)
+              4.21. is_request()
+              4.22. is_reply()
 
    List of Examples
 
@@ -119,6 +125,8 @@ Gabriel Vasile
    1.27. append_rpid_hf(prefix, suffix) usage
    1.28. is_rpid_user_e164 usage
    1.29. set_uri_user usage
+   1.30. is_request usage
+   1.31. is_reply usage
 
 Chapter 1. Admin Guide
 
@@ -164,6 +172,8 @@ Chapter 1. Admin Guide
         4.18. append_rpid_hf(prefix, suffix)
         4.19. is_rpid_user_e164()
         4.20. set_uri_user(uri, user)
+        4.21. is_request()
+        4.22. is_reply()
 
 1. Overview
 
@@ -358,6 +368,8 @@ modparam("auth", "rpid_avp", "$avp(myrpid)")
    4.18. append_rpid_hf(prefix, suffix)
    4.19. is_rpid_user_e164()
    4.20. set_uri_user(uri, user)
+   4.21. is_request()
+   4.22. is_reply()
 
 4.1.  ring_insert_callid()
 
@@ -424,7 +436,7 @@ if (is_user("john")) {
 
    Check if To header field uri contains tag parameter.
 
-   This function can be used from REQUEST_ROUTE.
+   This function can be used from ANY_ROUTE.
 
    Example 1.13. has_totag usage
 ...
@@ -613,8 +625,7 @@ reply_route[2] {
 
    The function returns true if the two parameters matches as SIP URI.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
-   FAILURE_ROUTE and BRANCH_ROUTE.
+   This function can be used from ANY_ROUTE.
 
    Example 1.23. cmp_uri usage
 ...
@@ -629,8 +640,7 @@ if(cmp_uri("$ru", "sip:[email protected]"))
    The function returns true if the two parameters matches as AoR. The
    parameters have to be SIP URIs.
 
-   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
-   FAILURE_ROUTE and BRANCH_ROUTE.
+   This function can be used from ANY_ROUTE.
 
    Example 1.24. cmp_aor usage
 ...
@@ -729,3 +739,29 @@ $var(uri) = "sip:user@host";
 $var(user) = "new_user";
 set_uri_user("$var(uri)", "$var(user)");
 ...
+
+4.21.  is_request()
+
+   Return true if the SIP message is a request.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.30. is_request usage
+...
+if (is_request()) {
+        ...
+}
+...
+
+4.22.  is_reply()
+
+   Return true if the SIP message is a reply.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.31. is_reply usage
+...
+if (is_reply()) {
+        ...
+}
+...

+ 27 - 0
modules_k/siputils/checks.c

@@ -54,6 +54,33 @@
 #include "../../lvalue.h"
 #include "checks.h"
 
+/**
+ * return 1 (true) if the SIP message type is request
+ */
+int w_is_request(struct sip_msg* msg, char *foo, char *bar)
+{
+	if(msg==NULL)
+		return -1;
+
+	if(msg->first_line.type == SIP_REQUEST)
+		return 1;
+
+	return -1;
+}
+
+/**
+ * return 1 (true) if the SIP message type is reply
+ */
+int w_is_reply(struct sip_msg* msg, char *foo, char *bar)
+{
+	if(msg==NULL)
+		return -1;
+
+	if(msg->first_line.type == SIP_REPLY)
+		return 1;
+
+	return -1;
+}
 
 /*
  * Checks if From includes a To-tag -- good to identify

+ 10 - 0
modules_k/siputils/checks.h

@@ -95,4 +95,14 @@ int is_e164(struct sip_msg* _m, char* _sp, char* _s2);
  */
 int set_uri_user(struct sip_msg* _m, char* _uri, char* _value);
 
+/*
+ * Return true (1) if SIP message is request, otherwise false (-1)
+ */
+int w_is_request(struct sip_msg* msg, char *foo, char *bar);
+
+/*
+ * Return true (1) if SIP message is reply, otherwise false (-1)
+ */
+int w_is_reply(struct sip_msg* msg, char *foo, char *bar);
+
 #endif /* CHECKS_H */

+ 45 - 5
modules_k/siputils/doc/siputils_admin.xml

@@ -375,7 +375,7 @@ if (is_user("john")) {
 		Check if To header field uri contains tag parameter.
 		</para>
 		<para>
-		This function can be used from REQUEST_ROUTE.
+		This function can be used from ANY_ROUTE.
 		</para>
 		<example>
 		<title><function>has_totag</function> usage</title>
@@ -684,8 +684,7 @@ reply_route[2] {
 		the two parameters matches as SIP URI.
 		</para>
    		<para>
-		This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, 
-		FAILURE_ROUTE and BRANCH_ROUTE.
+		This function can be used from ANY_ROUTE.
 		</para>
 		<example>
 		<title><function>cmp_uri</function> usage</title>
@@ -710,8 +709,7 @@ if(cmp_uri("$ru", "sip:[email protected]"))
 		URIs.
 		</para>
    		<para>
-		This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, 
-		FAILURE_ROUTE and BRANCH_ROUTE.
+		This function can be used from ANY_ROUTE.
 		</para>
 		<example>
 		<title><function>cmp_aor</function> usage</title>
@@ -859,6 +857,48 @@ $var(uri) = "sip:user@host";
 $var(user) = "new_user";
 set_uri_user("$var(uri)", "$var(user)");
 ...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title>
+		<function moreinfo="none">is_request()</function>
+		</title>
+		<para>
+		Return true if the SIP message is a request.
+		</para>
+		<para>
+		This function can be used from ANY_ROUTE.
+		</para>
+		<example>
+		<title><function>is_request</function> usage</title>
+		<programlisting format="linespecific">
+...
+if (is_request()) {
+	...
+}
+...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title>
+		<function moreinfo="none">is_reply()</function>
+		</title>
+		<para>
+		Return true if the SIP message is a reply.
+		</para>
+		<para>
+		This function can be used from ANY_ROUTE.
+		</para>
+		<example>
+		<title><function>is_reply</function> usage</title>
+		<programlisting format="linespecific">
+...
+if (is_reply()) {
+	...
+}
+...
 </programlisting>
 		</example>
 	</section>

+ 39 - 25
modules_k/siputils/siputils.c

@@ -113,36 +113,50 @@ static int fixup_free_set_uri(void** param, int param_no);
 char *contact_flds_separator = DEFAULT_SEPARATOR;
 
 static cmd_export_t cmds[]={
-	{"ring_insert_callid", (cmd_function)ring_insert_callid, 0, ring_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE},
-	{"options_reply",      (cmd_function)opt_reply, 0, 0, 0, REQUEST_ROUTE},
-	{"is_user",            (cmd_function)is_user,        1, fixup_str_null, 0, REQUEST_ROUTE|LOCAL_ROUTE},
-	{"has_totag", 	       (cmd_function)has_totag,      0, 0, 0, REQUEST_ROUTE|LOCAL_ROUTE},
-	{"uri_param",          (cmd_function)uri_param_1,    1, fixup_str_null, 0, REQUEST_ROUTE|LOCAL_ROUTE},
-	{"uri_param",          (cmd_function)uri_param_2,    2, fixup_str_str, 0, REQUEST_ROUTE|LOCAL_ROUTE},
-	{"add_uri_param",      (cmd_function)add_uri_param,  1, fixup_str_null, 0, REQUEST_ROUTE},
-	{"tel2sip",            (cmd_function)tel2sip,        0, 0,         0, REQUEST_ROUTE},
-	{"is_e164",            (cmd_function)is_e164, 1, fixup_pvar_null, fixup_free_pvar_null, REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE},
-	{"is_uri_user_e164",   (cmd_function)is_uri_user_e164, 1, fixup_pvar_null, fixup_free_pvar_null, REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE},
-	{"encode_contact",     (cmd_function)encode_contact,2,0, 0, REQUEST_ROUTE|ONREPLY_ROUTE},
-	{"decode_contact",     (cmd_function)decode_contact,0,0, 0, REQUEST_ROUTE},
-	{"decode_contact_header", (cmd_function)decode_contact_header,0,0,0,REQUEST_ROUTE|ONREPLY_ROUTE},
-	{"cmp_uri",  (cmd_function)w_cmp_uri, 2,
-		fixup_spve_spve, 0,
-		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
-	{"cmp_aor",  (cmd_function)w_cmp_aor, 2,
-		fixup_spve_spve, 0,
-		REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE},
-	{"is_rpid_user_e164",   (cmd_function)is_rpid_user_e164,       0, 0,
+	{"ring_insert_callid", (cmd_function)ring_insert_callid, 0, ring_fixup,
+		0, REQUEST_ROUTE|FAILURE_ROUTE},
+	{"options_reply",      (cmd_function)opt_reply,         0, 0,
+		0, REQUEST_ROUTE},
+	{"is_user",            (cmd_function)is_user,           1, fixup_str_null,
+		0, REQUEST_ROUTE|LOCAL_ROUTE},
+	{"has_totag", 	       (cmd_function)has_totag,         0, 0,
+		0, ANY_ROUTE},
+	{"uri_param",          (cmd_function)uri_param_1,       1, fixup_str_null,
+		0, REQUEST_ROUTE|LOCAL_ROUTE},
+	{"uri_param",          (cmd_function)uri_param_2,       2, fixup_str_str,
+		0, REQUEST_ROUTE|LOCAL_ROUTE},
+	{"add_uri_param",      (cmd_function)add_uri_param,     1, fixup_str_null,
+		0, REQUEST_ROUTE},
+	{"tel2sip",            (cmd_function)tel2sip,           0, 0,
+		0, REQUEST_ROUTE},
+	{"is_e164",            (cmd_function)is_e164,           1, fixup_pvar_null,
+		fixup_free_pvar_null, REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE},
+	{"is_uri_user_e164",   (cmd_function)is_uri_user_e164,  1, fixup_pvar_null,
+		fixup_free_pvar_null, REQUEST_ROUTE|FAILURE_ROUTE|LOCAL_ROUTE},
+	{"encode_contact",     (cmd_function)encode_contact,    2, 0,
+		0, REQUEST_ROUTE|ONREPLY_ROUTE},
+	{"decode_contact",     (cmd_function)decode_contact,    0, 0,
+		0, REQUEST_ROUTE},
+	{"decode_contact_header", (cmd_function)decode_contact_header, 0, 0,
+		0,REQUEST_ROUTE|ONREPLY_ROUTE},
+	{"cmp_uri",  (cmd_function)w_cmp_uri,                   2, fixup_spve_spve,
+		0, ANY_ROUTE},
+	{"cmp_aor",  (cmd_function)w_cmp_aor,                   2, fixup_spve_spve,
+		0, ANY_ROUTE},
+	{"is_rpid_user_e164",   (cmd_function)is_rpid_user_e164, 0, 0,
 			0, REQUEST_ROUTE},
-	{"append_rpid_hf",      (cmd_function)append_rpid_hf,          0, 0,
+	{"append_rpid_hf",      (cmd_function)append_rpid_hf,    0, 0,
 			0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE},
-	{"append_rpid_hf",      (cmd_function)append_rpid_hf_p,        2, fixup_str_str,
+	{"append_rpid_hf",      (cmd_function)append_rpid_hf_p,  2, fixup_str_str,
 			0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE},
-	{"set_uri_user", (cmd_function)set_uri_user, 2, fixup_set_uri,
-	 fixup_free_set_uri,	
-	 REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE},
+	{"set_uri_user", (cmd_function)set_uri_user,             2, fixup_set_uri,
+		    fixup_free_set_uri,	ANY_ROUTE},
 	{"bind_siputils",       (cmd_function)bind_siputils,           0, 0,
 			0, 0},
+	{"is_request",          (cmd_function)w_is_request,            0, 0,
+			0, ANY_ROUTE},
+	{"is_reply",            (cmd_function)w_is_reply,              0, 0,
+			0, ANY_ROUTE},
 	{0,0,0,0,0,0}
 };
 

+ 59 - 12
modules_k/sqlops/README

@@ -32,7 +32,8 @@ Daniel-Constantin Mierla
         4. Exported Functions
 
               4.1. sql_query(connection, query, result)
-              4.2. sql_result_free(result)
+              4.2. sql_xquery(connection, query, result)
+              4.3. sql_result_free(result)
 
         5. Exported pseudo-variables
 
@@ -43,8 +44,9 @@ Daniel-Constantin Mierla
    1.1. Set sqlcon parameter
    1.2. Set sqlres parameter
    1.3. sql_query() usage
-   1.4. sql_result_free() usage
-   1.5. $dbr(result=>key) usage
+   1.4. sql_xquery() usage
+   1.5. sql_result_free() usage
+   1.6. $dbr(result=>key) usage
 
 Chapter 1. Admin Guide
 
@@ -64,7 +66,8 @@ Chapter 1. Admin Guide
    4. Exported Functions
 
         4.1. sql_query(connection, query, result)
-        4.2. sql_result_free(result)
+        4.2. sql_xquery(connection, query, result)
+        4.3. sql_result_free(result)
 
    5. Exported pseudo-variables
 
@@ -91,6 +94,10 @@ Chapter 1. Admin Guide
        [row,column].
      * persistence in process space - a result can be used many times in
        the same worker process. Query once, use many times.
+     * alternatively, results can be stored in xavps - columns are
+       accessed by their names, rows by xavp index. Xavp's are available
+       during the transactions lifetime and don't need to be destroyed
+       manually.
 
 2. Dependencies
 
@@ -153,7 +160,8 @@ modparam("sqlops", "sqlres", "ra")
 4. Exported Functions
 
    4.1. sql_query(connection, query, result)
-   4.2. sql_result_free(result)
+   4.2. sql_xquery(connection, query, result)
+   4.3. sql_result_free(result)
 
 4.1.  sql_query(connection, query, result)
 
@@ -164,8 +172,7 @@ modparam("sqlops", "sqlres", "ra")
      * result - string name to identify the result. Will be used by
        $dbr(...) pseudo-variable to access result attributes.
 
-   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
-   ONREPLY_ROUTE, BRANCH_ROUTE.
+   This function can be used from ANY_ROUTE.
 
    Example 1.3. sql_query() usage
 ...
@@ -176,14 +183,32 @@ xlog("number of rows in table domain: $dbr(ra=>rows)\n");
 sql_result_free("ra");
 ...
 
-4.2.  sql_result_free(result)
+4.2.  sql_xquery(connection, query, result)
+
+   Make a SQL query using 'connection' and store data in 'result' xavp.
+     * connection - the name of the connection to be used for query
+       (defined via the “sqlcon” parameter).
+     * query - SQL query string or pseudo-variables containing SQL query.
+     * result - string name to identify the result xavp. Each row will be
+       added to this xavp, each column can be accessed by its name.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.4. sql_xquery() usage
+...
+modparam("sqlops","sqlcon","ca=>dbdriver://username:password@dbhost/dbname")
+...
+sql_xquery("ca", "select * from domain", "ra");
+  xlog("first domain: $xavp(ra=>domain) with id: $xavp(ra=>domain_id)\n");
+...
+
+4.3.  sql_result_free(result)
 
    Free data in SQL 'result'.
 
-   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
-   ONREPLY_ROUTE, BRANCH_ROUTE.
+   This function can be used from ANY_ROUTE.
 
-   Example 1.4. sql_result_free() usage
+   Example 1.5. sql_result_free() usage
 ...
 modparam("sqlops","sqlcon","ca=>dbdriver://username:password@dbhost/dbname")
 ...
@@ -212,7 +237,7 @@ sql_result_free("ra");
        integer.
      * colname[N] - return the name of the N-th column in the result set.
 
-   Example 1.5. $dbr(result=>key) usage
+   Example 1.6. $dbr(result=>key) usage
 ...
 modparam("sqlops","sqlcon","ca=>dbdriver://username:password@dbhost/dbname")
 ...
@@ -240,3 +265,25 @@ if($dbr(ra=>rows)>0)
 }
 sql_result_free("ra");
 ...
+
+
+...
+if (sql_xquery("ca", "select * from domain", "ra") == 1)
+{
+# non-destructive iteration
+    $var(i) = 0;
+    while($xavp(ra[$var(i)]) != $null)
+    {
+        xlog("[id, domain] = [$xavp(ra[$var(i)]=>id), $xavp(ra[$var(i)]=>domain)
+]\n");
+        $var(i) = $var(i) + 1;
+    }
+
+# destructive iteration
+    while($xavp(ra) != $null)
+    {
+        xlog("[id, domain] = [$xavp(ra=>id), $xavp(ra=>domain)]\n");
+        pv_unset("$xavp(ra)");
+    }
+}
+...

+ 74 - 5
modules_k/sqlops/doc/sqlops_admin.xml

@@ -60,6 +60,14 @@
 			times.
 		</para>
 		</listitem>
+		<listitem>
+		<para>
+			<emphasis>alternatively, results can be stored in xavps</emphasis>
+			- columns are accessed by their names, rows by xavp index. Xavp's
+			are available during the transactions lifetime and don't need to
+			be destroyed manually.
+		</para>
+		</listitem>
 
 	</itemizedlist>
 	</section>
@@ -197,8 +205,7 @@ modparam("sqlops", "sqlres", "ra")
 		</listitem>
 		</itemizedlist>
 		<para>
-			This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
-			ONREPLY_ROUTE, BRANCH_ROUTE.
+			This function can be used from ANY_ROUTE.
 		</para>
 		<example>
 		<title><function>sql_query()</function> usage</title>
@@ -210,6 +217,48 @@ sql_query("ca", "select * from domain", "ra");
 xlog("number of rows in table domain: $dbr(ra=&gt;rows)\n");
 sql_result_free("ra");
 ...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title>
+		<function moreinfo="none">sql_xquery(connection, query, result)</function>
+		</title>
+		<para>
+			Make a SQL query using 'connection' and store data in 'result' xavp.
+		</para>
+		<itemizedlist>
+		<listitem>
+			<para>
+				<emphasis>connection</emphasis> - the name of the connection
+				to be used for query (defined via the <quote>sqlcon</quote> parameter).
+			</para>
+		</listitem>
+		<listitem>
+			<para>
+				<emphasis>query</emphasis> - SQL query string or pseudo-variables containing SQL query.
+			</para>
+		</listitem>
+		<listitem>
+			<para>
+				<emphasis>result</emphasis> - string name to identify the
+				result xavp. Each row will be added to this xavp, each column can 
+				be accessed by its name.
+			</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+			This function can be used from ANY_ROUTE.
+		</para>
+		<example>
+		<title><function>sql_xquery()</function> usage</title>
+		<programlisting format="linespecific">
+...
+modparam("sqlops","sqlcon","ca=&gt;&exampledb;")
+...
+sql_xquery("ca", "select * from domain", "ra");
+  xlog("first domain: $xavp(ra=>domain) with id: $xavp(ra=>domain_id)\n");
+...
 </programlisting>
 		</example>
 	</section>
@@ -221,8 +270,7 @@ sql_result_free("ra");
 			Free data in SQL 'result'.
 		</para>
 		<para>
-			This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
-			ONREPLY_ROUTE, BRANCH_ROUTE.
+			This function can be used from ANY_ROUTE.
 		</para>
 		<example>
 		<title><function>sql_result_free()</function> usage</title>
@@ -306,7 +354,28 @@ if($dbr(ra=>rows)>0)
 }
 sql_result_free("ra");
 ...
-				 </programlisting>
+
+
+...
+if (sql_xquery("ca", "select * from domain", "ra") == 1)
+{
+# non-destructive iteration
+    $var(i) = 0;
+    while($xavp(ra[$var(i)]) != $null)
+    {
+        xlog("[id, domain] = [$xavp(ra[$var(i)]=&gt;id), $xavp(ra[$var(i)]=&gt;domain)]\n");
+        $var(i) = $var(i) + 1;
+    }
+
+# destructive iteration
+    while($xavp(ra) != $null)
+    {
+        xlog("[id, domain] = [$xavp(ra=&gt;id), $xavp(ra=&gt;domain)]\n");
+        pv_unset("$xavp(ra)");
+    }
+}
+...
+				</programlisting>
 			</example>
 	</section>
 	</section>

+ 131 - 0
modules_k/sqlops/sql_api.c

@@ -32,6 +32,9 @@
 #include "../../dprint.h"
 #include "../../lib/kcore/hash_func.h"
 #include "../../ut.h"
+#ifdef WITH_XAVP
+#include "../../xavp.h"
+#endif
 
 #include "sql_api.h"
 
@@ -341,6 +344,134 @@ error:
 	return -1;
 }
 
+#ifdef WITH_XAVP
+int sql_do_xquery(struct sip_msg *msg, sql_con_t *con, pv_elem_t *query,
+		pv_elem_t *res)
+{
+	db1_res_t* db_res = NULL;
+	sr_xavp_t *row = NULL;
+	sr_xval_t val;
+	int i, j;
+	str sv, xavp;
+
+	if(msg==NULL || query==NULL || res==NULL)
+	{
+		LM_ERR("bad parameters\n");
+		return -1;
+	}
+	if(pv_printf_s(msg, query, &sv)!=0)
+	{
+		LM_ERR("cannot print the sql query\n");
+		return -1;
+	}
+
+	if(pv_printf_s(msg, res, &xavp)!=0)
+	{
+		LM_ERR("cannot print the result parameter\n");
+		return -1;
+	}
+
+	if(con->dbf.raw_query(con->dbh, &sv, &db_res)!=0)
+	{
+		LM_ERR("cannot do the query\n");
+		return -1;
+	}
+
+	if(db_res==NULL || RES_ROW_N(db_res)<=0 || RES_COL_N(db_res)<=0)
+	{
+		LM_DBG("no result after query\n");
+		con->dbf.free_result(con->dbh, db_res);
+		return 2;
+	}
+
+	for(i=RES_ROW_N(db_res)-1; i>=0; i--)
+	{
+		row = NULL;
+		for(j=RES_COL_N(db_res)-1; j>=0; j--)
+		{
+			if(RES_ROWS(db_res)[i].values[j].nul)
+			{
+				val.type = SR_XTYPE_NULL;
+			} else
+			{
+				switch(RES_ROWS(db_res)[i].values[j].type)
+				{
+					case DB1_STRING:
+						val.type = SR_XTYPE_STR;
+						sv.s=
+							(char*)RES_ROWS(db_res)[i].values[j].val.string_val;
+						sv.len=strlen(sv.s);
+					break;
+					case DB1_STR:
+						val.type = SR_XTYPE_STR;
+						sv.len=
+							RES_ROWS(db_res)[i].values[j].val.str_val.len;
+						sv.s=
+							(char*)RES_ROWS(db_res)[i].values[j].val.str_val.s;
+					break;
+					case DB1_BLOB:
+						val.type = SR_XTYPE_STR;
+						sv.len=
+							RES_ROWS(db_res)[i].values[j].val.blob_val.len;
+						sv.s=
+							(char*)RES_ROWS(db_res)[i].values[j].val.blob_val.s;
+					break;
+					case DB1_INT:
+						val.type = SR_XTYPE_INT;
+						val.v.i
+							= (int)RES_ROWS(db_res)[i].values[j].val.int_val;
+					break;
+					case DB1_DATETIME:
+						val.type = SR_XTYPE_INT;
+						val.v.i
+							= (int)RES_ROWS(db_res)[i].values[j].val.time_val;
+					break;
+					case DB1_BITMAP:
+						val.type = SR_XTYPE_INT;
+						val.v.i
+							= (int)RES_ROWS(db_res)[i].values[j].val.bitmap_val;
+					break;
+					default:
+						val.type = SR_XTYPE_NULL;
+				}
+				if(val.type == SR_XTYPE_STR)
+				{
+					if(sv.len==0)
+					{
+						val.v.s = _sql_empty_str;
+					} else {
+						val.v.s.s = (char*)pkg_malloc(sv.len*sizeof(char));
+						if(val.v.s.s == NULL)
+						{
+							LM_ERR("no more memory\n");
+							goto error;
+						}
+						memcpy(val.v.s.s, sv.s, sv.len);
+						val.v.s.len = sv.len;
+					}
+				}
+			}
+			/* Add column to current row, under the column's name */
+			LM_DBG("Adding column: %.*s\n", RES_NAMES(db_res)[j]->len, RES_NAMES(db_res)[j]->s);
+			xavp_add_value(RES_NAMES(db_res)[j], &val, &row);
+		}
+		/* Add row to result xavp */
+		val.type = SR_XTYPE_XAVP;
+		val.v.xavp = row;
+		LM_DBG("Adding row\n");
+		xavp_add_value(&xavp, &val, NULL);
+	}
+
+	con->dbf.free_result(con->dbh, db_res);
+	return 1;
+
+error:
+	con->dbf.free_result(con->dbh, db_res);
+	return -1;
+
+}
+#endif
+
 int sql_parse_param(char *val)
 {
 	str name;

+ 4 - 0
modules_k/sqlops/sql_api.h

@@ -73,6 +73,10 @@ void sql_destroy(void);
 int sql_connect(void);
 
 int sql_do_query(sql_con_t *con, str *query, sql_result_t *res);
+#ifdef WITH_XAVP
+int sql_do_xquery(struct sip_msg *msg, sql_con_t *con, pv_elem_t *query,
+		pv_elem_t *res);
+#endif
 sql_con_t* sql_get_connection(str *name);
 sql_result_t* sql_get_result(str *name);
 

+ 61 - 0
modules_k/sqlops/sqlops.c

@@ -60,11 +60,17 @@ static int bind_sqlops(sqlops_api_t* api);
 
 /** module functions */
 static int sql_query(struct sip_msg*, char*, char*, char*);
+#ifdef WITH_XAVP
+static int sql_xquery(struct sip_msg *msg, char *dbl, char *query, char *res);
+#endif
 static int sql_rfree(struct sip_msg*, char*, char*);
 static int child_init(int rank);
 static void destroy(void);
 
 static int fixup_sql_query(void** param, int param_no);
+#ifdef WITH_XAVP
+static int fixup_sql_xquery(void** param, int param_no);
+#endif
 static int fixup_sql_rfree(void** param, int param_no);
 
 static int sql_con_param(modparam_t type, void* val);
@@ -80,6 +86,11 @@ static cmd_export_t cmds[]={
 	{"sql_query",  (cmd_function)sql_query, 3, fixup_sql_query, 0, 
 		REQUEST_ROUTE | FAILURE_ROUTE |
 		ONREPLY_ROUTE | BRANCH_ROUTE | LOCAL_ROUTE},
+#ifdef WITH_XAVP
+	{"sql_xquery",  (cmd_function)sql_xquery, 3, fixup_sql_xquery, 0, 
+		REQUEST_ROUTE | FAILURE_ROUTE |
+		ONREPLY_ROUTE | BRANCH_ROUTE | LOCAL_ROUTE},
+#endif
 	{"sql_result_free",  (cmd_function)sql_rfree,  1, fixup_sql_rfree, 0, 
 		REQUEST_ROUTE | FAILURE_ROUTE |
 		ONREPLY_ROUTE | BRANCH_ROUTE | LOCAL_ROUTE},
@@ -181,6 +192,16 @@ static int sql_query(struct sip_msg *msg, char *dbl, char *query, char *res)
 	return sql_do_query((sql_con_t*)dbl, &sq, (sql_result_t*)res);
 }
 
+#ifdef WITH_XAVP
+/**
+ *
+ */
+static int sql_xquery(struct sip_msg *msg, char *dbl, char *query, char *res)
+{
+	return sql_do_xquery(msg, (sql_con_t*)dbl, query, (pv_elem_t*)res);
+}
+#endif
+
 /**
  *
  */
@@ -230,6 +251,46 @@ static int fixup_sql_query(void** param, int param_no)
 	return 0;
 }
 
+#ifdef WITH_XAVP
+/**
+ *
+ */
+static int fixup_sql_xquery(void** param, int param_no)
+{
+	sql_con_t *con = NULL;
+	pv_elem_t *pv = NULL;
+	str s;
+
+	s.s = (char*)(*param);
+	s.len = strlen(s.s);
+
+	if (param_no==1) {
+		con = sql_get_connection(&s);
+		if(con==NULL)
+		{
+			LM_ERR("invalid connection [%s]\n", s.s);
+			return E_UNSPEC;
+		}
+		*param = (void*)con;
+	} else if (param_no==2) {
+		if(pv_parse_format(&s, &pv)<0)
+		{
+			LM_ERR("invalid query string [%s]\n", s.s);
+			return E_UNSPEC;
+		}
+		*param = (void*)pv;
+	} else if (param_no==3) {
+		if(pv_parse_format(&s, &pv)<0)
+		{
+			LM_ERR("invalid result [%s]\n", s.s);
+			return E_UNSPEC;
+		}
+		*param = (void*)pv;
+	}
+	return 0;
+}
+#endif
+
 /**
  *
  */

+ 17 - 0
modules_k/tmx/README

@@ -29,6 +29,7 @@ Daniel-Constantin Mierla
               3.1. t_cancel_branches(which)
               3.2. t_cancel_callid(callid, cseq, flag)
               3.3. t_reply_callid(callid, cseq, code, reason)
+              3.4. t_flush_flags()
 
         4. Exported pseudo-variables
         5. Exported MI Functions
@@ -57,6 +58,7 @@ Daniel-Constantin Mierla
    1.1. t_cancel_branches usage
    1.2. t_cancel_callid usage
    1.3. t_reply_callid usage
+   1.4. t_flush_flags usage
 
 Chapter 1. Admin Guide
 
@@ -73,6 +75,7 @@ Chapter 1. Admin Guide
         3.1. t_cancel_branches(which)
         3.2. t_cancel_callid(callid, cseq, flag)
         3.3. t_reply_callid(callid, cseq, code, reason)
+        3.4. t_flush_flags()
 
    4. Exported pseudo-variables
    5. Exported MI Functions
@@ -124,6 +127,7 @@ Chapter 1. Admin Guide
    3.1. t_cancel_branches(which)
    3.2. t_cancel_callid(callid, cseq, flag)
    3.3. t_reply_callid(callid, cseq, code, reason)
+   3.4. t_flush_flags()
 
 3.1.  t_cancel_branches(which)
 
@@ -182,6 +186,19 @@ if (t_reply_callid("123qaz", "5", "458", "Replied remotely")) {
 }
 ...
 
+3.4.  t_flush_flags()
+
+   Flush the flags from current SIP message into the already created
+   transaction. It make sense only in routing block if the transaction was
+   created via t_newtran() and the flags have been altered since.
+
+   This function can be used from ANY_ROUTE .
+
+   Example 1.4. t_flush_flags usage
+...
+t_flush_flags();
+...
+
 4. Exported pseudo-variables
 
      * $T_branch_idx

+ 21 - 0
modules_k/tmx/doc/tmx_admin.xml

@@ -168,6 +168,27 @@ if (t_reply_callid("123qaz", "5", "458", "Replied remotely")) {
 	xlog("transaction replied\n");
 }
 ...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title>
+		<function moreinfo="none">t_flush_flags()</function>
+		</title>
+		<para>
+		Flush the flags from current SIP message into the already created 
+		transaction. It make sense only in routing block if the transaction was
+		created via t_newtran() and the flags have been altered since.
+		</para>
+		<para>
+		This function can be used from ANY_ROUTE .
+		</para>
+		<example>
+		<title><function>t_flush_flags</function> usage</title>
+		<programlisting format="linespecific">
+...
+t_flush_flags();
+...
 </programlisting>
 		</example>
 	</section>

+ 21 - 0
modules_k/tmx/tmx_mod.c

@@ -53,6 +53,8 @@ static int t_reply_callid(struct sip_msg* msg, char *cid, char *cseq,
 				char *rc, char *rs);
 static int fixup_reply_callid(void** param, int param_no);
 
+static int t_flush_flags(struct sip_msg* msg, char*, char* );
+
 /* statistic variables */
 stat_var *tm_rcv_rpls;
 stat_var *tm_rld_rpls;
@@ -135,6 +137,8 @@ static cmd_export_t cmds[]={
 		fixup_cancel_callid, 0, ANY_ROUTE },
 	{"t_reply_callid", (cmd_function)t_reply_callid,  4,
 		fixup_reply_callid, 0, ANY_ROUTE },
+	{"t_flush_flags",   (cmd_function)t_flush_flags,    0, 0,
+			0, ANY_ROUTE  },
 	{0,0,0,0,0,0}
 };
 
@@ -398,6 +402,23 @@ static int t_reply_callid(struct sip_msg* msg, char *cid, char *cseq,
 	return -1;
 }
 
+/**
+ *
+ */
+static int t_flush_flags(struct sip_msg* msg, char *foo, char *bar)
+{
+	struct cell *t;
+
+	t=_tmx_tmb.t_gett();
+	if ( t==0 || t==T_UNDEFINED) {
+		LM_ERR("failed to flush flags - no transaction found\n");
+		return -1;
+	}
+
+	t->uas.request->flags = msg->flags;
+	return 1;
+}
+
 #ifdef STATISTICS
 
 /*** tm stats ***/

+ 68 - 18
modules_k/uac/README

@@ -14,9 +14,9 @@ Ramona-Elena Modroiu
 
    <[email protected]>
 
-   Copyright © 2009-2010 asipto.com
+   Copyright © 2009-2010 asipto.com
 
-   Copyright © 2005 Voice Sistem
+   Copyright © 2005 Voice Sistem
      __________________________________________________________________
 
    Table of Contents
@@ -51,6 +51,7 @@ Ramona-Elena Modroiu
               4.6. uac_reg_lookup(uuid, dst)
 
         5. Exported pseudo-variables
+        6. Remote Registration
 
    List of Examples
 
@@ -69,6 +70,7 @@ Ramona-Elena Modroiu
    1.13. uac_auth usage
    1.14. uac_req_send usage
    1.15. uac_reg_lookup usage
+   1.16. lookup remote registrations usage
 
 Chapter 1. Admin Guide
 
@@ -102,13 +104,20 @@ Chapter 1. Admin Guide
         4.6. uac_reg_lookup(uuid, dst)
 
    5. Exported pseudo-variables
+   6. Remote Registration
 
 1. Overview
 
    UAC (User Agent Client) module provides some basic UAC functionalities
    like FROM header manipulation (anonymization) or client authentication.
+
    From version 1.5.0 it has function to send SIP message from
-   configuration file. Version 3.1.0 adds user registration functionality.
+   configuration file. See variable $uac_req(name) and the function
+   uac_req_send().
+
+   Version 3.1.0 adds user registration functionality. See
+   uac_reg_lookup() function and dedicated section for remote registration
+   configuration.
 
    Known limitations in this version:
      * authentication does not support qop auth-int, just qop auth;
@@ -125,7 +134,7 @@ Chapter 1. Admin Guide
    The following modules must be loaded before this module:
      * TM - Transaction Module
      * RR - Record-Route Module, but only if restore mode for FROM URI is
-       set to "auto".
+       set to “auto�.
 
 2.2. External Libraries or Applications
 
@@ -150,7 +159,7 @@ Chapter 1. Admin Guide
    Name of Record-Route header parameter that will be used to store
    (encoded) the original FROM URI.
 
-   This parameter is optional, it's default value being "vsf".
+   This parameter is optional, it's default value being “vsf�.
 
    Example 1.1. Set rr_store_param parameter
 ...
@@ -160,15 +169,15 @@ modparam("uac","rr_store_param","my_param")
 3.2. from_restore_mode (string)
 
    There are 3 mode of restoring the original FROM URI:
-     * "none" - no information about original URI is stored; restoration
+     * “none� - no information about original URI is stored; restoration
        is not possible.
-     * "manual" - all following replies will be restored, but not also the
+     * “manual� - all following replies will be restored, but not also the
        sequential requests - this must be manually updated based on
        original URI.
-     * "auto" - all sequential requests and replies will be automatically
+     * “auto� - all sequential requests and replies will be automatically
        updated based on stored original URI.
 
-   This parameter is optional, it's default value being "auto".
+   This parameter is optional, it's default value being “auto�.
 
    Example 1.2. Set from_restore_mode parameter
 ...
@@ -204,9 +213,9 @@ modparam("uac","credential","username:domain:password")
    The definition of an AVP that might contain the realm to be used to
    perform authentication.
 
-   If you define it, you also need to define "auth_username_avp"
-   (Section 3.6, "auth_username_avp (string)") and "auth_username_avp"
-   (Section 3.7, "auth_password_avp (string)").
+   If you define it, you also need to define “auth_username_avp�
+   (Section 3.6, “auth_username_avp (string)�) and “auth_username_avp�
+   (Section 3.7, “auth_password_avp (string)�).
 
    Example 1.5. Set auth_realm_avp parameter
 ...
@@ -218,9 +227,9 @@ modparam("uac","auth_realm_avp","$avp(i:10)")
    The definition of an AVP that might contain the username to be used to
    perform authentication.
 
-   If you define it, you also need to define "auth_realm_avp"
-   (Section 3.5, "auth_realm_avp (string)") and "auth_username_avp"
-   (Section 3.7, "auth_password_avp (string)").
+   If you define it, you also need to define “auth_realm_avp�
+   (Section 3.5, “auth_realm_avp (string)�) and “auth_username_avp�
+   (Section 3.7, “auth_password_avp (string)�).
 
    Example 1.6. Set auth_username_avp parameter
 ...
@@ -232,9 +241,9 @@ modparam("uac","auth_username_avp","$avp(i:11)")
    The definition of an AVP that might contain the password to be used to
    perform authentication.
 
-   If you define it, you also need to define "auth_password_avp"
-   (Section 3.7, "auth_password_avp (string)") and "auth_username_avp"
-   (Section 3.7, "auth_password_avp (string)").
+   If you define it, you also need to define “auth_password_avp�
+   (Section 3.7, “auth_password_avp (string)�) and “auth_username_avp�
+   (Section 3.7, “auth_password_avp (string)�).
 
    Example 1.7. Set auth_password_avp parameter
 ...
@@ -368,3 +377,44 @@ if(uac_reg_lookup("$rU", "$ru"))
 
    Exported pseudo-variables are documented at
    http://www.kamailio.org/dokuwiki/.
+
+6. Remote Registration
+
+   The module can register contact addresses to remote REGISTRAR servers.
+   You have to add records to uacreg table. The table stores following
+   attributes:
+     * l_uuid - local unique user id, e.g.,: 12345678
+
+     * l_username - local user name, e.g.,: test
+
+     * l_domain - local domain, e.g.,: mysipserver.com
+
+     * r_username - remote username, e.g.,: test123
+
+     * r_domain - remote domain, e.g.,: sipprovider.com
+
+     * realm - remote relam, e.g.,: sipprovider.com
+
+     * auth_username - authentication username, e.g.,: test123
+
+     * auth_password - authentication password, e.g.,: xxxxxx
+
+     * auth_proxy - SIP address of authentication proxy, e.g.,:
+       sip:sipprovider.com
+
+     * expires - expiration time for registration, in seconds, e.g.,: 360
+
+   The module takes care of sending REGISTER and refresh registrations
+   before they expire.
+
+   When calls come in, you have to run uac_reg_lookup() that will detect
+   if the call is coming from a remote SIP provider and can change the
+   R-URI to local username@domain. Afterwards you can run location lookup.
+
+   Example 1.16. lookup remote registrations usage
+...
+    if(uac_reg_lookup("$rU", "$ru")) {
+        xlog("request from a remote SIP provider [$ou => $ru]\n");
+    }
+    lookup("location");
+...

+ 101 - 3
modules_k/uac/doc/uac_admin.xml

@@ -19,9 +19,17 @@
 		<para>
 		UAC (User Agent Client) module provides some basic UAC
 		functionalities like FROM header manipulation (anonymization)
-		or client authentication. From version 1.5.0 it has function to
-		send SIP message from configuration file. Version 3.1.0 adds user
-		registration functionality.
+		or client authentication.
+		</para>
+		<para>
+		From version 1.5.0 it has function to send SIP message from
+		configuration file. See variable $uac_req(name) and the function
+		uac_req_send().
+		</para>
+		<para>
+		Version 3.1.0 adds user registration functionality. See
+		uac_reg_lookup() function and dedicated section for remote
+		registration configuration.
 		</para>
 		<para>
 		Known limitations in this version:
@@ -441,5 +449,95 @@ if(uac_reg_lookup("$rU", "$ru"))
 		Exported pseudo-variables are documented at &kamwikilink;.
 		</para>
 	</section>
+	<section>
+		<title>Remote Registration</title>
+		<para>
+		The module can register contact addresses to remote REGISTRAR servers.
+		You have to add records to uacreg table. The table stores following
+		attributes:
+		</para>
+
+		<itemizedlist>
+			<listitem><para>
+			<emphasis>l_uuid</emphasis> - local unique user id, e.g.,:
+			12345678
+			</para></listitem>
+		</itemizedlist>
+		<itemizedlist>
+			<listitem><para>
+			<emphasis>l_username</emphasis> - local user name, e.g.,: test
+			</para></listitem>
+		</itemizedlist>
+		<itemizedlist>
+			<listitem><para>
+			<emphasis>l_domain</emphasis> - local domain, e.g.,:
+			mysipserver.com
+			</para></listitem>
+		</itemizedlist>
+		<itemizedlist>
+			<listitem><para>
+			<emphasis>r_username</emphasis> - remote username, e.g.,:
+			test123
+			</para></listitem>
+		</itemizedlist>
+		<itemizedlist>
+			<listitem><para>
+			<emphasis>r_domain</emphasis> - remote domain, e.g.,:
+			sipprovider.com
+			</para></listitem>
+		</itemizedlist>
+		<itemizedlist>
+			<listitem><para>
+			<emphasis>realm</emphasis> - remote relam, e.g.,:
+			sipprovider.com
+			</para></listitem>
+		</itemizedlist>
+		<itemizedlist>
+			<listitem><para>
+			<emphasis>auth_username</emphasis> - authentication username,
+			e.g.,: test123
+			</para></listitem>
+		</itemizedlist>
+		<itemizedlist>
+			<listitem><para>
+			<emphasis>auth_password</emphasis> - authentication password,
+			e.g.,: xxxxxx
+			</para></listitem>
+		</itemizedlist>
+		<itemizedlist>
+			<listitem><para>
+			<emphasis>auth_proxy</emphasis> - SIP address of authentication
+			proxy, e.g.,: sip:sipprovider.com
+			</para></listitem>
+		</itemizedlist>
+		<itemizedlist>
+			<listitem><para>
+			<emphasis>expires</emphasis> - expiration time for registration,
+			in seconds, e.g.,: 360
+			</para></listitem>
+		</itemizedlist>
+
+		<para>
+		The module takes care of sending REGISTER and refresh registrations
+		before they expire.
+		</para>
+		<para>
+		When calls come in, you have to run uac_reg_lookup() that will detect
+		if the call is coming from a remote SIP provider and can change the
+		R-URI to local username@domain. Afterwards you can run location lookup.
+		</para>
+
+		<example>
+		<title><function>lookup remote registrations</function> usage</title>
+			<programlisting format="linespecific">
+...
+    if(uac_reg_lookup("$rU", "$ru")) {
+        xlog("request from a remote SIP provider [$ou => $ru]\n");
+    }
+    lookup("location");
+...
+			</programlisting>
+		</example>
+	</section>
 </chapter>
 

+ 56 - 2
modules_k/uac/uac_reg.c

@@ -28,8 +28,11 @@
 #include "../../mem/shm_mem.h"
 #include "../../lib/srdb1/db.h"
 #include "../../ut.h"
+#include "../../trim.h"
 #include "../../hashes.h"
 #include "../../parser/parse_uri.h"
+#include "../../parser/parse_from.h"
+#include "../../parser/parse_to.h"
 #include "../../parser/contact/parse_contact.h"
 #include "../../rpc.h"
 #include "../../rpc_lookup.h"
@@ -385,6 +388,41 @@ reg_uac_t *reg_ht_get_byuser(str *user, str *domain)
 	return NULL;
 }
 
+int uac_reg_tmdlg(dlg_t *tmdlg, sip_msg_t *rpl)
+{
+	if(tmdlg==NULL || rpl==NULL)
+		return -1;
+
+	if (parse_headers(rpl, HDR_EOH_F, 0) < 0) {
+		LM_ERR("error while parsing all headers in the reply\n");
+		return -1;
+	}
+	if(parse_to_header(rpl)<0 || parse_from_header(rpl)<0) {
+		LM_ERR("error while parsing From/To headers in the reply\n");
+		return -1;
+	}
+	memset(tmdlg, 0, sizeof(dlg_t));
+
+	str2int(&(get_cseq(rpl)->number), &tmdlg->loc_seq.value);
+	tmdlg->loc_seq.is_set = 1;
+
+	tmdlg->id.call_id = rpl->callid->body;
+	trim(&tmdlg->id.call_id);
+
+	if (get_from(rpl)->tag_value.len) {
+		tmdlg->id.loc_tag = get_from(rpl)->tag_value;
+	}
+#if 0
+	if (get_to(rpl)->tag_value.len) {
+		tmdlg->id.rem_tag = get_to(rpl)->tag_value;
+	}
+#endif
+	tmdlg->loc_uri = get_from(rpl)->uri;
+	tmdlg->rem_uri = get_to(rpl)->uri;
+	tmdlg->state= DLG_CONFIRMED;
+	return 0;
+}
+
 void uac_reg_tm_callback( struct cell *t, int type, struct tmcb_params *ps)
 {
 	char *uuid;
@@ -400,13 +438,16 @@ void uac_reg_tm_callback( struct cell *t, int type, struct tmcb_params *ps)
 	struct uac_credential cred;
 	char  b_ruri[MAX_URI_SIZE];
 	str   s_ruri;
+#ifdef UAC_OLD_AUTH
 	char  b_turi[MAX_URI_SIZE];
 	str   s_turi;
+#endif
 	char  b_hdrs[MAX_UACH_SIZE];
 	str   s_hdrs;
 	uac_req_t uac_r;
 	str method = {"REGISTER", 8};
 	int ret;
+	dlg_t tmdlg;
 
 	if(ps->param==NULL || *ps->param==0)
 	{
@@ -531,11 +572,12 @@ void uac_reg_tm_callback( struct cell *t, int type, struct tmcb_params *ps)
 			goto done;
 		}
 		
+#ifdef UAC_OLD_AUTH
 		snprintf(b_turi, MAX_URI_SIZE, "sip:%.*s@%.*s",
 				ri->r_username.len, ri->r_username.s,
 				ri->r_domain.len, ri->r_domain.s);
 		s_turi.s = b_turi; s_turi.len = strlen(s_turi.s);
-
+#endif
 		snprintf(b_hdrs, MAX_UACH_SIZE,
 				"Contact: <sip:%.*s@%.*s>\r\n"
 				"Expires: %d\r\n"
@@ -547,20 +589,32 @@ void uac_reg_tm_callback( struct cell *t, int type, struct tmcb_params *ps)
 		s_hdrs.s = b_hdrs; s_hdrs.len = strlen(s_hdrs.s);
 		pkg_free(new_auth_hdr->s);
 
-		memset(&uac_r, '\0', sizeof(uac_r));
+		memset(&uac_r, 0, sizeof(uac_r));
+		if(uac_reg_tmdlg(&tmdlg, ps->rpl)<0)
+		{
+			LM_ERR("failed to build tm dialog\n");
+			goto done;
+		}
+		tmdlg.rem_target = s_ruri;
+		if(ri->auth_proxy.len)
+			tmdlg.dst_uri = ri->auth_proxy;
 		uac_r.method = &method;
 		uac_r.headers = &s_hdrs;
+		uac_r.dialog = &tmdlg;
 		uac_r.cb_flags = TMCB_LOCAL_COMPLETED;
 		/* Callback function */
 		uac_r.cb  = uac_reg_tm_callback;
 		/* Callback parameter */
 		uac_r.cbp = (void*)uuid;
+#ifdef UAC_OLD_AUTH
 		ret = uac_tmb.t_request(&uac_r,  /* UAC Req */
 				&s_ruri, /* Request-URI */
 				&s_turi, /* To */
 				&s_turi, /* From */
 				(ri->auth_proxy.len)?&ri->auth_proxy:NULL /* outbound uri */
 			);
+#endif
+		ret = uac_tmb.t_request_within(&uac_r);
 		ri->flags |= UAC_REG_AUTHSENT;
 
 		if(ret<0)

+ 80 - 87
parser/hf.c

@@ -68,145 +68,129 @@ void clean_hdr_field(struct hdr_field* hf)
 	void** h_parsed;
 
 	if (hf->parsed){
-		h_parsed=&hf->parsed; /*strict aliasing warnings workarround */
+		h_parsed=&hf->parsed; /* strict aliasing warnings workarround */
 		switch(hf->type){
-		case HDR_VIA_T:
-			free_via_list(hf->parsed);
-			break;
-
-		case HDR_TO_T:
-			free_to(hf->parsed);
-			break;
-
-		case HDR_FROM_T:
-			free_to(hf->parsed);
-			break;
-
-		case HDR_CSEQ_T:
-			free_cseq(hf->parsed);
+		/* headers with pkg alloc for parsed structure (alphabetic order) */
+		case HDR_ACCEPT_T:
+			pkg_free(hf->parsed);
 			break;
 
-		case HDR_CALLID_T:
+		case HDR_ALLOW_T:
+			free_allow_header(hf);
 			break;
 
-		case HDR_SIPIFMATCH_T:
-			free_sipifmatch((str **)h_parsed);
+		case HDR_AUTHORIZATION_T:
+			free_credentials((auth_body_t**)h_parsed);
 			break;
 
 		case HDR_CONTACT_T:
 			free_contact((contact_body_t**)h_parsed);
 			break;
 
-		case HDR_MAXFORWARDS_T:
-			break;
-
-		case HDR_ROUTE_T:
-			free_rr((rr_t**)h_parsed);
-			break;
-
-		case HDR_RECORDROUTE_T:
-			free_rr((rr_t**)h_parsed);
+		case HDR_CONTENTDISPOSITION_T:
+			free_disposition( ((struct disposition**)h_parsed));
 			break;
 
-		case HDR_CONTENTTYPE_T:
+		case HDR_CSEQ_T:
+			free_cseq(hf->parsed);
 			break;
 
-		case HDR_CONTENTLENGTH_T:
+		case HDR_DATE_T:
+			free_date(hf->parsed);
 			break;
 
-		case HDR_RETRY_AFTER_T:
+		case HDR_DIVERSION_T:
+			free_to(hf->parsed);
 			break;
 
-		case HDR_AUTHORIZATION_T:
-			free_credentials((auth_body_t**)h_parsed);
+		case HDR_EVENT_T:
+			free_event((event_t**)h_parsed);
 			break;
 
 		case HDR_EXPIRES_T:
 			free_expires((exp_body_t**)h_parsed);
 			break;
 
-		case HDR_PROXYAUTH_T:
-			free_credentials((auth_body_t**)h_parsed);
-			break;
-
-		case HDR_SUPPORTED_T:
-			break;
-
-		case HDR_REQUIRE_T:
-			break;
-
-		case HDR_PROXYREQUIRE_T:
-			break;
-
-		case HDR_UNSUPPORTED_T:
-			break;
-
-		case HDR_ALLOW_T:
-			free_allow_header(hf);
-			break;
-
-		case HDR_EVENT_T:
-			free_event((event_t**)h_parsed);
-			break;
-
-		case HDR_ACCEPT_T:
-			pkg_free(hf->parsed);
+		case HDR_FROM_T:
+			free_to(hf->parsed);
 			break;
 
-		case HDR_ACCEPTLANGUAGE_T:
+		case HDR_IDENTITY_INFO_T:
+			free_identityinfo(hf->parsed);
 			break;
 
-		case HDR_ORGANIZATION_T:
+		case HDR_IDENTITY_T:
+			free_identity(hf->parsed);
 			break;
 
-		case HDR_PRIORITY_T:
+		case HDR_PAI_T:
+			free_to(hf->parsed);
 			break;
 
-		case HDR_SUBJECT_T:
+		case HDR_PPI_T:
+			free_to(hf->parsed);
 			break;
 
-		case HDR_USERAGENT_T:
+		case HDR_PROXYAUTH_T:
+			free_credentials((auth_body_t**)h_parsed);
 			break;
 
-		case HDR_SERVER_T:
+		case HDR_RECORDROUTE_T:
+			free_rr((rr_t**)h_parsed);
 			break;
 
-		case HDR_ACCEPTDISPOSITION_T:
+		case HDR_REFER_TO_T:
+			free_to(hf->parsed);
 			break;
 
-		case HDR_CONTENTDISPOSITION_T:
-			free_disposition( ((struct disposition**)h_parsed));
+		case HDR_ROUTE_T:
+			free_rr((rr_t**)h_parsed);
 			break;
 
-		case HDR_DIVERSION_T:
+		case HDR_RPID_T:
 			free_to(hf->parsed);
 			break;
 
-		case HDR_RPID_T:
-			free_to(hf->parsed);
+		case HDR_SESSIONEXPIRES_T:
+			hdr_free_parsed(h_parsed);
 			break;
 
-		case HDR_REFER_TO_T:
-			free_to(hf->parsed);
+		case HDR_SIPIFMATCH_T:
+			free_sipifmatch((str **)h_parsed);
 			break;
 
 		case HDR_SUBSCRIPTION_STATE_T:
 			free_subscription_state((subscription_state_t**)h_parsed);
 			break;
 
-		case HDR_DATE_T:
-			free_date(hf->parsed);
+		case HDR_SUPPORTED_T:
+			hdr_free_parsed(h_parsed);
 			break;
 
-		case HDR_IDENTITY_INFO_T:
-			free_identityinfo(hf->parsed);
+		case HDR_TO_T:
+			free_to(hf->parsed);
 			break;
 
-		case HDR_IDENTITY_T:
-			free_identity(hf->parsed);
+		case HDR_VIA_T:
+			free_via_list(hf->parsed);
 			break;
 
-		case HDR_SESSIONEXPIRES_T:
+		/* headers with no alloc for parsed structure */
+		case HDR_CALLID_T:
+		case HDR_MAXFORWARDS_T:
+		case HDR_CONTENTTYPE_T:
+		case HDR_CONTENTLENGTH_T:
+		case HDR_RETRY_AFTER_T:
+		case HDR_REQUIRE_T:
+		case HDR_PROXYREQUIRE_T:
+		case HDR_UNSUPPORTED_T:
+		case HDR_ACCEPTLANGUAGE_T:
+		case HDR_ORGANIZATION_T:
+		case HDR_PRIORITY_T:
+		case HDR_SUBJECT_T:
+		case HDR_USERAGENT_T:
+		case HDR_SERVER_T:
+		case HDR_ACCEPTDISPOSITION_T:
 		case HDR_MIN_SE_T:
 		case HDR_ACCEPTCONTACT_T:
 		case HDR_ALLOWEVENTS_T:
@@ -221,14 +205,6 @@ void clean_hdr_field(struct hdr_field* hf)
 		case HDR_REASON_T:
 			break;
 
-		case HDR_PPI_T:
-			free_to(hf->parsed);
-			break;
-
-		case HDR_PAI_T:
-			free_to(hf->parsed);
-			break;
-
 		default:
 			LOG(L_CRIT, "BUG: clean_hdr_field: unknown header type %d\n",
 			    hf->type);
@@ -252,6 +228,7 @@ void free_hdr_field_lst(struct hdr_field* hf)
 	}
 }
 
+/* print the content of hdr_field */
 void dump_hdr_field( struct hdr_field* hf )
 {
 	LOG(L_ERR, "DEBUG: dump_hdr_field: type=%d, name=%.*s, "
@@ -260,3 +237,19 @@ void dump_hdr_field( struct hdr_field* hf )
 		hf->body.len, ZSW(hf->body.s),
 		hf->parsed, hf->next );
 }
+
+/**
+ * free hdr parsed structure using inner free function
+ * - hdr parsed struct must have as first file a free function,
+ *   so it can be caseted to hf_parsed_t
+ */
+void hdr_free_parsed(void **h_parsed)
+{
+	if(h_parsed==NULL || *h_parsed==NULL)
+		return;
+
+	if(((hf_parsed_t*)(*h_parsed))->hfree) {
+		((hf_parsed_t*)(*h_parsed))->hfree(*h_parsed);
+	}
+	*h_parsed = 0;
+}

+ 36 - 11
parser/hf.h

@@ -213,27 +213,44 @@ typedef struct hdr_field {
 } hdr_field_t;
 
 
+/* type of the function to free the structure of parsed header field */
+typedef void (*hf_parsed_free_f)(void *parsed);
+
+/* structure to hold the function to free the parsed header field */
+typedef struct hdr_parsed {
+	hf_parsed_free_f hfree;
+} hf_parsed_t;
 
 /** returns true if the header links allocated memory on parse field. */
 static inline int hdr_allocs_parse(struct hdr_field* hdr)
 {
 	switch(hdr->type){
-		case HDR_VIA_T:
-		case HDR_TO_T:
-		case HDR_FROM_T:
-		case HDR_CONTACT_T:
-		case HDR_ROUTE_T:
-		case HDR_RECORDROUTE_T:
-		case HDR_AUTHORIZATION_T:
-		case HDR_EXPIRES_T:
-		case HDR_PROXYAUTH_T:
-		case HDR_EVENT_T:
 		case HDR_ACCEPT_T:
+		case HDR_ALLOW_T:
+		case HDR_AUTHORIZATION_T:
+		case HDR_CONTACT_T:
 		case HDR_CONTENTDISPOSITION_T:
+		case HDR_CSEQ_T:
+		case HDR_DATE_T:
 		case HDR_DIVERSION_T:
-		case HDR_RPID_T:
+		case HDR_EVENT_T:
+		case HDR_EXPIRES_T:
+		case HDR_FROM_T:
+		case HDR_IDENTITY_INFO_T:
+		case HDR_IDENTITY_T:
+		case HDR_PAI_T:
+		case HDR_PPI_T:
+		case HDR_PROXYAUTH_T:
+		case HDR_RECORDROUTE_T:
 		case HDR_REFER_TO_T:
+		case HDR_ROUTE_T:
+		case HDR_RPID_T:
+		case HDR_SESSIONEXPIRES_T:
+		case HDR_SIPIFMATCH_T:
 		case HDR_SUBSCRIPTION_STATE_T:
+		case HDR_SUPPORTED_T:
+		case HDR_TO_T:
+		case HDR_VIA_T:
 			return 1;
 		default:
 			return 0;
@@ -251,6 +268,14 @@ void clean_hdr_field(struct hdr_field* hf);
  */
 void free_hdr_field_lst(struct hdr_field* hf);
 
+/* print content of hdr_field */
 void dump_hdr_field( struct hdr_field* hf );
 
+/**
+ * free hdr parsed structure using inner free function
+ * - hdr parsed struct must have as first file a free function,
+ *   so it can be caseted to hf_parsed_t
+ */
+void hdr_free_parsed(void **h_parsed);
+
 #endif /* HF_H */

+ 1 - 1
parser/msg_parser.c

@@ -710,7 +710,7 @@ int parse_msg(char* buf, unsigned int len, struct sip_msg* msg)
 
 error:
 	/* more debugging, msg->orig is/should be null terminated*/
-	LOG(L_ERR, "ERROR: parse_msg: message=<%.*s>\n",
+	LOG(cfg_get(core, core_cfg, corelog), "ERROR: parse_msg: message=<%.*s>\n",
 			(int)msg->len, ZSW(msg->buf));
 	return -1;
 }

+ 6 - 0
pkg/kamailio/deb/debian/kamailio.default

@@ -14,6 +14,12 @@ GROUP=kamailio
 # Amount of memory to allocate for the running Kamailio server (in Mb)
 MEMORY=64
 
+# Switch to USER and GROUP by start-stop-daemon or by kamailio itself
+# - with recent kernels, changing user ID inside applicaton prevents
+#   dumping core files. If the value is 'yes', the suid is done by
+#   start-stop-daemon, otherwise it is done by kamailio itself
+SSD_SUID=no
+
 # Enable the server to leave a core file when it crashes.
 # Set this to 'yes' to enable Kamailio to leave a core file when it crashes
 # or 'no' to disable this feature. This option is case sensitive and only

+ 44 - 12
pkg/kamailio/deb/debian/kamailio.init

@@ -22,13 +22,14 @@ DESC=kamailio
 HOMEDIR=/var/run/kamailio
 PIDFILE=$HOMEDIR/$NAME.pid
 DEFAULTS=/etc/default/kamailio
+CFGFILE=/etc/kamailio/kamailio.cfg
 RUN_KAMAILIO=no
 
 # Do not start kamailio if fork=no is set in the config file
 # otherwise the boot process will just stop
 check_fork ()
 {
-    if grep -q "^[[:space:]]*fork[[:space:]]*=[[:space:]]*no.*" /etc/kamailio/kamailio.cfg; then
+    if grep -q "^[[:space:]]*fork[[:space:]]*=[[:space:]]*no.*" $CFGFILE; then
 	echo "Not starting $DESC: fork=no specified in config file; run /etc/init.d/kamailio debug instead"
 	exit 1
     fi
@@ -80,7 +81,10 @@ create_radius_seqfile ()
     chmod 660 $RADIUS_SEQ_FILE
 }
 
-test -f $DAEMON || exit 0
+if [ ! -f $DAEMON ]; then
+	echo "No Kamailio daemon at: $DAEMON"
+	exit 0
+fi
 
 # Load startup options if available
 if [ -f $DEFAULTS ]; then
@@ -89,7 +93,16 @@ fi
 
 if [ "$RUN_KAMAILIO" != "yes" ]; then
     echo "Kamailio not yet configured. Edit /etc/default/kamailio first."
-    exit 0
+    case "$1" in
+    status)
+        # 4 program or service status is unknown
+        exit 4
+       ;;
+    *)
+        # 6 program is not configured
+        exit 6
+       ;;
+    esac
 fi
 
 set -e
@@ -104,13 +117,34 @@ if test "$DUMP_CORE" = "yes" ; then
     ulimit -c unlimited
     
     # directory for the core dump files
-    # COREDIR=/home/corefiles
+    # COREDIR=/tmp/corefiles
     # [ -d $COREDIR ] || mkdir $COREDIR
     # chmod 777 $COREDIR
     # echo "$COREDIR/core.%e.sig%s.%p" > /proc/sys/kernel/core_pattern
 fi
 
-OPTIONS="-P $PIDFILE -m $MEMORY -u $USER -g $GROUP"
+if [ "$SSD_SUID" != "yes" ]; then
+	OPTIONS="-f $CFGFILE -P $PIDFILE -m $MEMORY -u $USER -g $GROUP"
+	SSDOPTS=""
+else
+	OPTIONS="-f $CFGFILE -P $PIDFILE -m $MEMORY"
+	SSDOPTS="--chuid $USER:$GROUP"
+fi
+
+start_kamailio_daemon ()
+{
+	start-stop-daemon --start --quiet --pidfile $PIDFILE $SSDOPTS \
+		--exec $DAEMON -- $OPTIONS || if [ ! -r "$PIDFILE" ]; then
+			echo " error, failed to start."
+			exit 1
+		elif read pid < "$PIDFILE" && ps -p "$pid" > /dev/null 2>&1; then
+			echo -n " already running"
+			echo "."
+		else
+			echo " error, failed to start ($PIDFILE exists)."
+			exit 1
+		fi
+}
 
 case "$1" in
   start|debug)
@@ -122,13 +156,12 @@ case "$1" in
 	    check_fork
 	fi
 
-	echo -n "Starting $DESC: $NAME"
-	start-stop-daemon --start --quiet --pidfile $PIDFILE \
-		--exec $DAEMON -- $OPTIONS || echo -n " already running"
+	echo -n "Starting $DESC: $NAME "
+	start_kamailio_daemon
 	echo "."
 	;;
   stop)
-	echo -n "Stopping $DESC: $NAME"
+	echo -n "Stopping $DESC: $NAME "
 	start-stop-daemon --oknodo --stop --quiet --pidfile $PIDFILE \
 		--exec $DAEMON
 	echo "."
@@ -138,12 +171,11 @@ case "$1" in
 	check_homedir
 	create_radius_seqfile
 
-	echo -n "Restarting $DESC: $NAME"
+	echo -n "Restarting $DESC: $NAME "
 	start-stop-daemon --oknodo --stop --quiet --pidfile \
 		$PIDFILE --exec $DAEMON
 	sleep 1
-	start-stop-daemon --start --quiet --pidfile \
-		$PIDFILE --exec $DAEMON  -- $OPTIONS
+	start_kamailio_daemon
 	echo "."
 	;;
   status)

+ 2 - 1
receive.c

@@ -139,7 +139,8 @@ int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info)
 	msg->set_global_port=default_global_port;
 	
 	if (parse_msg(buf,len, msg)!=0){
-		LOG(L_ERR, "ERROR: receive_msg: parse_msg failed\n");
+		LOG(cfg_get(core, core_cfg, corelog),
+				"ERROR: receive_msg: parse_msg failed\n");
 		goto error02;
 	}
 	DBG("After parse_msg...\n");

+ 10 - 143
ser_stun.c

@@ -64,9 +64,7 @@ int stun_add_address_attr(struct stun_msg* res,
 						int do_xor);
 int add_unknown_attr(struct stun_msg* res, struct stun_unknown_att* unknown);
 int add_error_code(struct stun_msg* res, USHORT_T error_code);
-int add_fingerprint(struct stun_buffer* msg);
 int copy_str_to_buffer(struct stun_msg* res, const char* data, UINT_T pad);
-int validate_fingerprint(struct stun_msg* req, USHORT_T* error_code);
 int reallock_buffer(struct stun_buffer* buffer, UINT_T len);
 int buf_copy(struct stun_buffer* msg, void* source, UINT_T len);
 void clean_memory(struct stun_msg* req,
@@ -231,11 +229,9 @@ int stun_parse_body(
 	struct stun_unknown_att*	tmp_unknown;
 	struct stun_unknown_att*	body;
 	char*	buf;
-	int		fp_present;
 	
 	attr_size = sizeof(struct stun_attr);
 	buf = &req->msg.buf.s[sizeof(struct stun_hdr)];
-	fp_present = 0;
 	
 	/* 
 	 * Mark the body lenght as unparsed.
@@ -286,7 +282,6 @@ int stun_parse_body(
 			case MAPPED_ADDRESS_ATTR:
 			case XOR_MAPPED_ADDRESS_ATTR:
 			case ALTERNATE_SERVER_ATTR:
-			case REFRESH_INTERVAL_ATTR:
 			case RESPONSE_ADDRESS_ATTR:
 			case SOURCE_ADDRESS_ATTR:
 			case REFLECTED_FROM_ATTR:		
@@ -300,10 +295,9 @@ int stun_parse_body(
 			
 			/* following attributes must be padded to 4 bytes */
 			case USERNAME_ATTR:
-			case PASSWORD_ATTR:
 			case ERROR_CODE_ATTR:
 			case UNKNOWN_ATTRIBUTES_ATTR:
-			case SERVER_ATTR:
+			case SOFTWARE_ATTR:
 				padded_len = PADDED_TO_FOUR(ntohs(attr.len));
 #ifdef EXTRA_DEBUG
 				LOG(L_DBG, "DEBUG: stun_parse_body: padded to four\n");
@@ -322,25 +316,8 @@ int stun_parse_body(
 #ifdef EXTRA_DEBUG
 				LOG(L_DBG, "DEBUG: stun_parse_body: fingerprint attribute found\n");
 #endif
-				fp_present = 1;
-				if (ntohs(attr.len) != SHA_DIGEST_LENGTH) {
-					LOG(L_WARN, 
-						"WARNING: STUN: Incorrect fingerprint of request.\n");
-					*error_code = BAD_REQUEST_ERR;
-					continue;
-				}
-
-				memcpy(req->fp, buf, SHA_DIGEST_LENGTH);
-				if(stun_allow_fp) {
-					if (validate_fingerprint(req, error_code) != 0) {
-						LOG(L_WARN, 
-							"WARNING: STUN: Incorrect fingerprint of request.\n");
-						*error_code = BAD_REQUEST_ERR;
-						continue;
-					}
-				} 
-
 				padded_len = SHA_DIGEST_LENGTH;
+
 				if (not_parsed > SHA_DIGEST_LENGTH) {
 #ifdef EXTRA_DEBUG
 					LOG(L_DBG, "DEBUG: stun_parse_body: fingerprint is not the last attribute\n");
@@ -396,14 +373,6 @@ int stun_parse_body(
 		*error_code = UNKNOWN_ATTRIBUTE_ERR;
 	} 
 	
-	if (fp_present == 0 && req->old == 0) {
-#ifdef EXTRA_DEBUG
-		LOG(L_DBG, "DEBUG: stun_parse_body: fingerprint is missing is this new request\n");
-#endif
-		/* missing mandatory attribute fingerprint */
-		*error_code = BAD_REQUEST_ERR;
-	}
-	
 	return 0;
 }
 
@@ -431,7 +400,6 @@ int stun_create_response(
 						struct stun_unknown_att* unknown, 
 						UINT_T error_code)
 {
-	UINT_T msg_len;
 	/*
 	 * Alloc some space for response.
 	 * Optimalization? - maybe it would be better to use biggish static array.
@@ -477,14 +445,6 @@ int stun_create_response(
 						  XOR) != 0) {
 #ifdef EXTRA_DEBUG
 				LOG(L_DBG, "DEBUG: stun_create_response: failed to add address\n");
-#endif
-				return FATAL_ERROR;
-			}
-			
-			if (stun_add_common_integer_attr(res, REFRESH_INTERVAL_ATTR, 
-						stun_refresh_interval) != 0) {
-#ifdef EXTRA_DEBUG
-				LOG(L_DBG, "DEBUG: stun_create_response: failed to common attributes\n");
 #endif
 				return FATAL_ERROR;
 			}
@@ -532,10 +492,10 @@ int stun_create_response(
 	
 	if (req->old == 0) {
 		/* 
-		 * add optional information about server; attribute SERVER is not a part of 
-		 * rfc3489.txt 
+		 * add optional information about server; attribute SOFTWARE is part of 
+		 * rfc5389.txt
 		 * */
-		if (stun_add_common_text_attr(res, SERVER_ATTR, SERVER_HDR, PAD4)!=0) {
+		if (stun_add_common_text_attr(res, SOFTWARE_ATTR, SERVER_HDR, PAD4)!=0) {
 #ifdef EXTRA_DEBUG
 			LOG(L_DBG, "DEBUG: stun_create_response: failed to add common text attribute\n");
 #endif
@@ -543,28 +503,9 @@ int stun_create_response(
 		}
 	}	
 	
-	if (req->old == 0 && stun_allow_fp) {
-		/* count length of body except header and fingerprint
-	 	 * and copy message length at the beginning of buffer
-	   */
-	  msg_len = res->msg.buf.len - sizeof(struct stun_hdr);
-	  msg_len += SHA_DIGEST_LENGTH + sizeof(struct stun_attr);
-		res->hdr.len = htons(msg_len);
-		memcpy(&res->msg.buf.s[sizeof(USHORT_T)], (void *) &res->hdr.len,
-	  	sizeof(USHORT_T));
-	  		
-		if (add_fingerprint(&res->msg) != 0) {
-#ifdef EXTRA_DEBUG
-			LOG(L_DBG, "DEBUG: stun_create_response: failed to add fingerprint\n");
-#endif
-			return FATAL_ERROR;
-		}
-	}
-	else {
-		res->hdr.len = htons(res->msg.buf.len - sizeof(struct stun_hdr));
-		memcpy(&res->msg.buf.s[sizeof(USHORT_T)], (void *) &res->hdr.len,
-	  	sizeof(USHORT_T));
-	}
+	res->hdr.len = htons(res->msg.buf.len - sizeof(struct stun_hdr));
+	memcpy(&res->msg.buf.s[sizeof(USHORT_T)], (void *) &res->hdr.len,
+	       sizeof(USHORT_T));
 	
 	return 0;
 }
@@ -824,14 +765,14 @@ int stun_add_address_attr(struct stun_msg* res,
 	
 	ip_struct_len = 0;
 	attr.type = htons(type);
-	res->ip_addr.port = (do_xor) ? htons(port) ^ MAGIC_COOKIE_2B : htons(port);
+	res->ip_addr.port = htons((do_xor) ? (port ^ MAGIC_COOKIE_2B) : port);
 	switch(af) {
 		case AF_INET:
 			ip_struct_len = sizeof(struct stun_ip_addr) - 3*sizeof(UINT_T);
 			res->ip_addr.family = htons(IPV4_FAMILY);
 			memcpy(res->ip_addr.ip, ip_addr, IPV4_LEN);
 			res->ip_addr.ip[0] = (do_xor) ? 
-					res->ip_addr.ip[0] ^ MAGIC_COOKIE : res->ip_addr.ip[0];		
+				res->ip_addr.ip[0] ^ htonl(MAGIC_COOKIE) : res->ip_addr.ip[0];
 			break;
 #ifdef USE_IPV6
 		case AF_INET6:
@@ -864,48 +805,6 @@ int stun_add_address_attr(struct stun_msg* res,
 	return 0;
 }
 
-/*
- * add_fingerprint()
- * 			- msg: response buffer
- * 
- * The function add_fingerprint ensures adding fingerprint attribute into
- * response buffer.
- * 
- * Return value:	0	if there is no environment error
- * 					-1	if there is some enviroment error such as insufficiency
- * 						of memory
- */
-int add_fingerprint(struct stun_buffer* msg)
-{
-	struct stun_attr attr;
-	USHORT_T attr_type_size;
-	
-	attr_type_size = sizeof(struct stun_attr);
-	attr.type = htons(FINGERPRINT_ATTR);
-	attr.len = htons(SHA_DIGEST_LENGTH);
-	
-	if (msg->empty < (SHA_DIGEST_LENGTH + attr_type_size)) {
-		if (reallock_buffer(msg, SHA_DIGEST_LENGTH + attr_type_size) != 0) {
-			return FATAL_ERROR;
-		}
-	}
-	
-	memcpy(&msg->buf.s[msg->buf.len], (void *) &attr, attr_type_size);	
-	msg->buf.len += attr_type_size;
-	msg->empty -= attr_type_size;
-	
-	if (SHA1((UCHAR_T *)msg->buf.s, msg->buf.len-attr_type_size, 
-			 (UCHAR_T *) &msg->buf.s[msg->buf.len]) == 0) {
-		LOG(L_ERR, "ERROR: STUN: SHA-1 algorithm failed.\n");
-		return FATAL_ERROR;
-	}
-	
-	msg->buf.len += SHA_DIGEST_LENGTH;
-	msg->empty -= SHA_DIGEST_LENGTH;
-	
-	return 0;
-}
-
 /*
  * stun_alloc_unknown_attr()
  * 			- type: type of unknown attribute
@@ -957,38 +856,6 @@ void stun_delete_unknown_attrs(struct stun_unknown_att* unknown)
 	pkg_free(unknown);
 }
 
-/*
- * validate_fingerprint()
- * 			- req: structure representing request message
- * 			- error_code: indication of any protocol error
- * 
- * The function validate_fingerprint ensures validation of FINGERPRINT
- * attribute.
- * 
- * Return value:	0	if there is no environment error
- * 					-1	if there is some enviroment error such as insufficiency
- * 						of memory
- */
-int validate_fingerprint(struct stun_msg* req, USHORT_T* error_code)
-{
-	UCHAR_T	msg_digest[SHA_DIGEST_LENGTH];
-	UINT_T	buf_len; 
-	
-	buf_len = req->hdr.len + sizeof(struct stun_hdr);
-	buf_len -= SHA_DIGEST_LENGTH + sizeof(struct stun_attr);
-	
-	if (SHA1((UCHAR_T *) req->msg.buf.s, buf_len, msg_digest) == 0) {
-		LOG(L_ERR, "ERROR: STUN: SHA-1 algorithm failed.\n");
-		return FATAL_ERROR;
-	} 
-	
-	if (memcmp((void *)req->fp, (void *)&msg_digest, SHA_DIGEST_LENGTH) != 0) {
-		*error_code = BAD_REQUEST_ERR;
-	}
-	
-	return 0;	
-}
-
 /*
  * buf_copy()
  * 			- msg: buffer where the data will be copy to

+ 3 - 6
ser_stun.h

@@ -56,19 +56,17 @@ typedef unsigned long	ULONG_T;
 /* common STUN attributes */
 #define MAPPED_ADDRESS_ATTR		0x0001
 #define USERNAME_ATTR			0x0006
-#define PASSWORD_ATTR			0x0007
 #define MESSAGE_INTEGRITY_ATTR	0x0008
 #define ERROR_CODE_ATTR			0x0009
 #define UNKNOWN_ATTRIBUTES_ATTR	0x000A
 
-/* STUN attributes defined by rfc3489bis */
+/* STUN attributes defined by rfc5389 */
 #define REALM_ATTR				0x0014
 #define NONCE_ATTR				0x0015
 #define XOR_MAPPED_ADDRESS_ATTR	0x0020 
-#define FINGERPRINT_ATTR		0x0023
-#define SERVER_ATTR				0x8022
+#define FINGERPRINT_ATTR		0x8028
+#define SOFTWARE_ATTR				0x8022
 #define ALTERNATE_SERVER_ATTR	0x8023
-#define REFRESH_INTERVAL_ATTR	0x8024
 
 /* STUN attributes defined by rfc3489 */
 #define RESPONSE_ADDRESS_ATTR	0x0002
@@ -167,7 +165,6 @@ struct stun_msg {
 	struct stun_hdr			hdr;
 	struct stun_ip_addr		ip_addr;		/* XOR values for rfc3489bis, 
 											normal values for rfc3489 */
-	char					fp[SHA_DIGEST_LENGTH];		/* fingerprint value */
 	struct stun_buffer		msg;
 	UCHAR_T					old;		/* true: the format of message is in 
 										accordance with rfc3489 */ 

+ 2 - 2
sr_module.c

@@ -1038,7 +1038,7 @@ int fix_param(int type, void** param)
 {
 	fparam_t* p;
 	str name, s;
-	unsigned int num;
+	int num;
 	int err;
 
 	p = (fparam_t*)pkg_malloc(sizeof(fparam_t));
@@ -1064,7 +1064,7 @@ int fix_param(int type, void** param)
 		case FPARAM_INT:
 			s.s = (char*)*param;
 			s.len = strlen(s.s);
-			err = str2int(&s, &num);
+			err = str2sint(&s, &num);
 			if (err == 0) {
 				p->v.i = (int)num;
 			} else {

+ 4 - 2
tcp_read.c

@@ -266,7 +266,8 @@ again:
 								break;
 						}
 				}
-				LOG(L_ERR, "error reading: %s (%d)\n", strerror(errno), errno);
+				LOG(cfg_get(core, core_cfg, corelog),
+						"error reading: %s (%d)\n", strerror(errno), errno);
 				return -1;
 			}
 		}else if (unlikely((bytes_read==0) || 
@@ -879,7 +880,8 @@ again:
 					req->start);
 #endif
 			if (unlikely(bytes==-1)){
-				LOG(L_ERR, "ERROR: tcp_read_req: error reading \n");
+				LOG(cfg_get(core, core_cfg, corelog),
+						"ERROR: tcp_read_req: error reading \n");
 				resp=CONN_ERROR;
 				goto end_req;
 			}

+ 5 - 3
utils/kamctl/kamdbctl.base

@@ -36,8 +36,9 @@ STANDARD_TABLES=${STANDARD_TABLES:-version acc dbaliases domain grp
 		uri speed_dial lcr_gw lcr_rule lcr_rule_target pdt subscriber
 		location re_grp trusted address missed_calls usr_preferences
 		aliases silo dialog dispatcher dialplan}
-EXTRA_TABLES=${EXTRA_TABLES:-imc_members imc_rooms cpl sip_trace domainpolicy carrierroute
-		carrier_name domain_name carrierfailureroute userblacklist globalblacklist htable purplemap}
+EXTRA_TABLES=${EXTRA_TABLES:-imc_members imc_rooms cpl sip_trace domainpolicy
+		carrierroute carrier_name domain_name carrierfailureroute userblacklist
+		globalblacklist htable purplemap uacreg}
 PRESENCE_TABLES=${PRESENCE_TABLES:-presentity active_watchers watchers xcap 
 		pua rls_presentity rls_watchers}
 
@@ -65,7 +66,8 @@ STANDARD_MODULES=${STANDARD_MODULES:-standard acc lcr domain group permissions
 				     registrar usrloc msilo alias_db uri_db
 				     speeddial avpops auth_db pdt dialog dispatcher
 				     dialplan}
-EXTRA_MODULES=${EXTRA_MODULES:-imc cpl siptrace domainpolicy carrierroute userblacklist htable purple}
+EXTRA_MODULES=${EXTRA_MODULES:-imc cpl siptrace domainpolicy carrierroute
+    userblacklist htable purple uac}
 
 ############################################################
 

+ 23 - 17
xavp.c

@@ -459,50 +459,56 @@ sr_xavp_t **xavp_get_crt_list(void)
 	return _xavp_list_crt;
 }
 
-void xavp_print_list(sr_xavp_t **head)
+void xavp_print_list_content(sr_xavp_t **head, int level)
 {
 	sr_xavp_t *avp=0;
+	sr_xavp_t *start=0;
 
 	if(head!=NULL)
-		avp = *head;
+		start = *head;
 	else
-		avp=*_xavp_list_crt;
-	LM_DBG("+++++ XAVP list: %p\n", avp);
+		start=*_xavp_list_crt;
+	LM_INFO("+++++ start XAVP list: %p (level=%d)\n", start, level);
+	avp = start;
 	while(avp)
 	{
-		LM_DBG("     *** XAVP name: %s\n", avp->name.s);
-		LM_DBG("     XAVP id: %u\n", avp->id);
-		LM_DBG("     XAVP value type: %d\n", avp->val.type);
+		LM_INFO("     *** XAVP name: %s\n", avp->name.s);
+		LM_INFO("     XAVP id: %u\n", avp->id);
+		LM_INFO("     XAVP value type: %d\n", avp->val.type);
 		switch(avp->val.type) {
 			case SR_XTYPE_NULL:
-				LM_DBG("     XAVP value: <null>\n");
+				LM_INFO("     XAVP value: <null>\n");
 			break;
 			case SR_XTYPE_INT:
-				LM_DBG("     XAVP value: %d\n", avp->val.v.i);
+				LM_INFO("     XAVP value: %d\n", avp->val.v.i);
 			break;
 			case SR_XTYPE_STR:
-				LM_DBG("     XAVP value: %s\n", avp->val.v.s.s);
+				LM_INFO("     XAVP value: %s\n", avp->val.v.s.s);
 			break;
 			case SR_XTYPE_TIME:
-				LM_DBG("     XAVP value: %lu\n", avp->val.v.t);
+				LM_INFO("     XAVP value: %lu\n", avp->val.v.t);
 			break;
 			case SR_XTYPE_LONG:
-				LM_DBG("     XAVP value: %ld\n", avp->val.v.l);
+				LM_INFO("     XAVP value: %ld\n", avp->val.v.l);
 			break;
 			case SR_XTYPE_LLONG:
-				LM_DBG("     XAVP value: %lld\n", avp->val.v.ll);
+				LM_INFO("     XAVP value: %lld\n", avp->val.v.ll);
 			break;
 			case SR_XTYPE_XAVP:
-				LM_DBG("     XAVP value: <xavp:%p>\n", avp->val.v.xavp);
-				xavp_print_list(&avp->val.v.xavp);
+				LM_INFO("     XAVP value: <xavp:%p>\n", avp->val.v.xavp);
+				xavp_print_list_content(&avp->val.v.xavp, level+1);
 			break;
 			case SR_XTYPE_DATA:
-				LM_DBG("     XAVP value: <data:%p>\n", avp->val.v.data);
+				LM_INFO("     XAVP value: <data:%p>\n", avp->val.v.data);
 			break;
 		}
 		avp = avp->next;
 	}
-	LM_DBG("----- XAVP list\n");
+	LM_INFO("----- end XAVP list: %p (level=%d)\n", start, level);
 }
 
+void xavp_print_list(sr_xavp_t **head)
+{
+	xavp_print_list_content(head, 0);
+}
 #endif