diff --git a/debian/patches/series b/debian/patches/series
index 0feceb817..ab8e2a426 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -56,10 +56,12 @@ upstream/avpops-add-avp_subst_pv-documentation.patch
upstream/avpops-add-avp_subst_pv.patch
upstream/rtpengine-update-fix-via-branch-next-ID-generation.patch
upstream/rtpengine-t38-options.patch
+upstream/rtpengine-add-flags-field-for-every-command.patch
upstream/app_lua-add-support-for-ARRAY-and-DICT-types.patch
upstream/core-KEMI-suport-for-ARRAY-and-DICT.patch
upstream/pv-add-KEMI-functions-pvx.xavp_get_keys-and-pvx.xavp.patch
upstream/pv-fixes-for-KEMI-pvx.xavp_getd.patch
+upstream/cfgt-don-t-process-non-sip-messages.patch
## backport from kamailio trunk (5.3)
upstream/pv-do-not-set-ending-0-for-port-value-in-pv_set_ruri.patch
upstream/uac-also-set-socket-for-in-dialog-REGISTER-GH-2262.patch
@@ -73,14 +75,10 @@ upstream/utils-kamctl-fix-dbtestdb.patch
upstream/utils-kamctl-dbtextdb-remove-DeprecationWarning-on-t.patch
upstream/utils-kamctl-dbtextdb.py-close-previous-opened-file-.patch
### relevant for upstream
-sipwise/fix_error_in_cfgt_module.patch
-sipwise/pv_headers-store-To-info-in-xavp_parsed_name.r-on-re.patch
-sipwise/rtpengine-flags-for-everything.patch
-##
-sipwise/pv_headers-full-rework.patch
+#
+### active development
sipwise/pua_dialoginfo-refresh_pubruri_avps_flag.patch
sipwise/pua_dialoginfo-local_identity_dlg_var.patch
-#
### Don't just put stuff in any order
### use gbp pq import/export tooling to help maintain patches
###
diff --git a/debian/patches/sipwise/add_pv_headers_module.patch b/debian/patches/sipwise/add_pv_headers_module.patch
index 47b079ad5..da195714a 100644
--- a/debian/patches/sipwise/add_pv_headers_module.patch
+++ b/debian/patches/sipwise/add_pv_headers_module.patch
@@ -5,25 +5,25 @@ Subject: add_pv_headers_module
---
src/Makefile.groups | 3 +-
src/modules/pv_headers/Makefile | 12 +
- src/modules/pv_headers/README | 332 +++++++
+ src/modules/pv_headers/README | 337 +++++++
src/modules/pv_headers/doc/Makefile | 4 +
src/modules/pv_headers/doc/functions.xml | 131 +++
src/modules/pv_headers/doc/params.xml | 186 ++++
src/modules/pv_headers/doc/pv_headers.xml | 39 +
src/modules/pv_headers/doc/pv_headers_admin.xml | 116 +++
- src/modules/pv_headers/pv_headers.c | 351 ++++++++
- src/modules/pv_headers/pv_headers.h | 51 ++
- src/modules/pv_headers/pvh_func.c | 388 +++++++++
- src/modules/pv_headers/pvh_func.h | 38 +
- src/modules/pv_headers/pvh_hash.c | 132 +++
- src/modules/pv_headers/pvh_hash.h | 39 +
- src/modules/pv_headers/pvh_hdr.c | 235 +++++
- src/modules/pv_headers/pvh_hdr.h | 39 +
- src/modules/pv_headers/pvh_str.c | 144 ++++
- src/modules/pv_headers/pvh_str.h | 38 +
- src/modules/pv_headers/pvh_xavp.c | 1050 +++++++++++++++++++++++
- src/modules/pv_headers/pvh_xavp.h | 64 ++
- 20 files changed, 3391 insertions(+), 1 deletion(-)
+ src/modules/pv_headers/pv_headers.c | 519 +++++++++++
+ src/modules/pv_headers/pv_headers.h | 57 ++
+ src/modules/pv_headers/pvh_func.c | 360 +++++++
+ src/modules/pv_headers/pvh_func.h | 42 +
+ src/modules/pv_headers/pvh_hash.c | 134 +++
+ src/modules/pv_headers/pvh_hash.h | 41 +
+ src/modules/pv_headers/pvh_hdr.c | 295 ++++++
+ src/modules/pv_headers/pvh_hdr.h | 47 +
+ src/modules/pv_headers/pvh_str.c | 146 +++
+ src/modules/pv_headers/pvh_str.h | 40 +
+ src/modules/pv_headers/pvh_xavp.c | 1133 +++++++++++++++++++++++
+ src/modules/pv_headers/pvh_xavp.h | 66 ++
+ 20 files changed, 3707 insertions(+), 1 deletion(-)
create mode 100644 src/modules/pv_headers/Makefile
create mode 100644 src/modules/pv_headers/README
create mode 100644 src/modules/pv_headers/doc/Makefile
@@ -78,10 +78,10 @@ index 0000000..42b80dd
+include ../../Makefile.modules
diff --git a/src/modules/pv_headers/README b/src/modules/pv_headers/README
new file mode 100644
-index 0000000..b99cc42
+index 0000000..1967529
--- /dev/null
+++ b/src/modules/pv_headers/README
-@@ -0,0 +1,332 @@
+@@ -0,0 +1,337 @@
+pv_headers Module
+
+Kirill Solomko
@@ -126,7 +126,7 @@ index 0000000..b99cc42
+ 4.3. pvh_reset_headers()
+ 4.4. pvh_check_header(hname)
+ 4.5. pvh_append_header(hname, hvalue)
-+ 4.6. pvh_modify_header(hname, [idx], hvalue)
++ 4.6. pvh_modify_header(hname, hvalue, [idx])
+ 4.7. pvh_remove_header(hname, [idx])
+
+ 5. Exported Variables
@@ -168,7 +168,7 @@ index 0000000..b99cc42
+ 4.3. pvh_reset_headers()
+ 4.4. pvh_check_header(hname)
+ 4.5. pvh_append_header(hname, hvalue)
-+ 4.6. pvh_modify_header(hname, [idx], hvalue)
++ 4.6. pvh_modify_header(hname, hvalue, [idx])
+ 4.7. pvh_remove_header(hname, [idx])
+
+ 5. Exported Variables
@@ -224,7 +224,8 @@ index 0000000..b99cc42
+
+3.2. header_value_size (int)
+
-+ ??????.
++ Defines an internal maximum SIP header value size. Header values longer
++ than this setting will be stripped down when collected or applied.
+
+ Default value is 1024.
+
@@ -235,7 +236,9 @@ index 0000000..b99cc42
+
+3.3. header_collect_flag (int)
+
-+ ??????.
++ Used to mark that headers are collected for the SIP message, leading to
++ subsequent headers collection on this message to be declined with an
++ error. Should be used only in branches and replies.
+
+ Default value is 27.
+
@@ -246,7 +249,9 @@ index 0000000..b99cc42
+
+3.4. header_apply_flag (int)
+
-+ ??????.
++ Used to mark that headers are applied for the SIP message, leading to
++ subsequent headers applies on this message to be declined with an
++ error. Should be used only in branches and replies.
+
+ Default value is 28.
+
@@ -317,7 +322,7 @@ index 0000000..b99cc42
+ 4.3. pvh_reset_headers()
+ 4.4. pvh_check_header(hname)
+ 4.5. pvh_append_header(hname, hvalue)
-+ 4.6. pvh_modify_header(hname, [idx], hvalue)
++ 4.6. pvh_modify_header(hname, hvalue, [idx])
+ 4.7. pvh_remove_header(hname, [idx])
+
+ \
@@ -372,7 +377,7 @@ index 0000000..b99cc42
+ This function can be used from ANY_ROUTE but only after
+ pvh_collect_headers() or with "auto_msg" parameter enabled.
+
-+4.6. pvh_modify_header(hname, [idx], hvalue)
++4.6. pvh_modify_header(hname, hvalue, [idx])
+
+ Modifies an existing header in the XAVP "hname" with the value "hvalue"
+ into the XAVP. Index order is top to bottom. Please note that
@@ -801,7 +806,7 @@ index 0000000..a5211b9
+
diff --git a/src/modules/pv_headers/doc/pv_headers_admin.xml b/src/modules/pv_headers/doc/pv_headers_admin.xml
new file mode 100644
-index 0000000..9c5c009
+index 0000000..44e84f2
--- /dev/null
+++ b/src/modules/pv_headers/doc/pv_headers_admin.xml
@@ -0,0 +1,116 @@
@@ -871,7 +876,7 @@ index 0000000..9c5c009
+
+
+
-+
++
+
+ Exported Variables
+
@@ -923,23 +928,25 @@ index 0000000..9c5c009
+
diff --git a/src/modules/pv_headers/pv_headers.c b/src/modules/pv_headers/pv_headers.c
new file mode 100644
-index 0000000..9730847
+index 0000000..6faaf64
--- /dev/null
+++ b/src/modules/pv_headers/pv_headers.c
-@@ -0,0 +1,351 @@
+@@ -0,0 +1,519 @@
+/*
+ * pv_headers
+ *
-+ * Copyright (C) 2018 Kirill Solomko
++ * Copyright (C)
++ * 2020 Victor Seva
++ * 2018 Kirill Solomko
+ *
-+ * This file is part of SIP Router, a free SIP server.
++ * This file is part of Kamailio, a free SIP server.
+ *
-+ * SIP Router is free software; you can redistribute it and/or modify
++ * 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
+ *
-+ * SIP Router is distributed in the hope that it will be useful,
++ * 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.
@@ -951,76 +958,99 @@ index 0000000..9730847
+ */
+
+#include "../../core/sr_module.h"
-+#include "../../core/mod_fix.h"
+#include "../../core/script_cb.h"
++#include "../../core/mod_fix.h"
+#include "../../modules/tm/tm_load.h"
+#include "../../core/kemi.h"
+
+#include "pv_headers.h"
+#include "pvh_func.h"
-+#include "pvh_xavp.h"
+#include "pvh_hash.h"
++#include "pvh_xavp.h"
+
+MODULE_VERSION
+
+#define MODULE_NAME "pv_headers"
-+
+#define XAVP_NAME "headers"
+
-+#define FL_NAME_PV_HDRS_COLLECTED "pv_headers_collected"
-+#define FL_NAME_PV_HDRS_APPLIED "pv_headers_applied"
-+
-+int FL_PV_HDRS_COLLECTED = 27;
-+int FL_PV_HDRS_APPLIED = 28;
-+
+uac_api_t uac;
+static tm_api_t tmb;
+
+str xavp_name = str_init(XAVP_NAME);
-+
++str xavp_helper_xname = str_init("modparam_pv_headers");
+str xavp_parsed_xname = str_init("parsed_pv_headers");
++unsigned int header_name_size = 255;
++unsigned int header_value_size = 1024;
++int FL_PV_HDRS_COLLECTED = 27;
++int FL_PV_HDRS_APPLIED = 28;
+static str skip_headers_param =
+ str_init("Record-Route,Via,Route,Content-Length,Max-Forwards,CSeq");
+static str split_headers_param = STR_NULL;
-+static int auto_msg_param = 1;
-+
+static str single_headers_param = str_init("");
++static int auto_msg_param = 1;
+
+str _hdr_from = {"From", 4};
+str _hdr_to = {"To", 2};
-+
-+unsigned int header_name_size = 255;
-+unsigned int header_value_size = 1024;
-+
++str _hdr_reply_reason = {"@Reply-Reason", 13};
++int _branch = T_BR_UNDEFINED;
++int _reply_counter = -1;
+
+static void mod_destroy(void);
+static int mod_init(void);
+
+static void handle_tm_t(tm_cell_t *t, int type, struct tmcb_params *params);
+static int handle_msg_cb(struct sip_msg *msg, unsigned int flags, void *cb);
++static int handle_msg_branch_cb(
++ struct sip_msg *msg, unsigned int flags, void *cb);
++static int handle_msg_reply_cb(
++ struct sip_msg *msg, unsigned int flags, void *cb);
+
+static int w_pvh_collect_headers(struct sip_msg *msg, char *p1, char *p2)
+{
-+ return pvh_collect_headers(msg, 0);
++ sr_xavp_t **backup_xavps = NULL;
++
++ if(pvh_get_branch_index(msg, &_branch) < 0)
++ return -1;
++ if(msg->first_line.type == SIP_REPLY) {
++ if((_reply_counter = pvh_reply_append(backup_xavps)) < 0) {
++ return -1;
++ }
++ }
++ return pvh_collect_headers(msg);
+}
+
+static int ki_pvh_collect_headers(struct sip_msg *msg)
+{
-+ return pvh_collect_headers(msg, 0);
++ sr_xavp_t **backup_xavps = NULL;
++
++ if(pvh_get_branch_index(msg, &_branch) < 0)
++ return -1;
++ if(msg->first_line.type == SIP_REPLY) {
++ if((_reply_counter = pvh_reply_append(backup_xavps)) < 0) {
++ return -1;
++ }
++ }
++ return pvh_collect_headers(msg);
+}
+
+static int w_pvh_apply_headers(struct sip_msg *msg, char *p1, char *p2)
+{
-+ return pvh_apply_headers(msg, 0);
++ if(pvh_get_branch_index(msg, &_branch) < 0)
++ return -1;
++ return pvh_apply_headers(msg);
+}
+
+static int ki_pvh_apply_headers(struct sip_msg *msg)
+{
-+ return pvh_apply_headers(msg, 0);
++ if(pvh_get_branch_index(msg, &_branch) < 0)
++ return -1;
++ return pvh_apply_headers(msg);
+}
+
+static int w_pvh_reset_headers(struct sip_msg *msg, char *p1, char *p2)
+{
++ if(pvh_get_branch_index(msg, &_branch) < 0)
++ return -1;
+ return pvh_reset_headers(msg);
+}
+
@@ -1080,79 +1110,83 @@ index 0000000..9730847
+ return pvh_remove_header(msg, &hname, indx);
+}
+
-+/*
-+ * Exported functions
-+ */
++/* clang-format off */
+static cmd_export_t cmds[] = {
-+ {"pvh_collect_headers", (cmd_function)w_pvh_collect_headers, 0, 0, 0,
-+ ANY_ROUTE},
-+ {"pvh_apply_headers", (cmd_function)w_pvh_apply_headers, 0, 0, 0,
-+ ANY_ROUTE},
-+ {"pvh_reset_headers", (cmd_function)w_pvh_reset_headers, 0, 0, 0,
-+ ANY_ROUTE},
-+ {"pvh_check_header", (cmd_function)w_pvh_check_header, 1,
-+ fixup_spve_null, fixup_free_spve_null, ANY_ROUTE},
-+ {"pvh_append_header", (cmd_function)w_pvh_append_header, 2,
-+ fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE},
-+ {"pvh_modify_header", (cmd_function)w_pvh_modify_header, 2,
-+ fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE},
-+ {"pvh_modify_header", (cmd_function)w_pvh_modify_header, 3,
-+ fixup_spve_all, fixup_free_spve_all, ANY_ROUTE},
-+ {"pvh_remove_header", (cmd_function)w_pvh_remove_header, 1,
-+ fixup_spve_null, fixup_free_spve_null, ANY_ROUTE},
-+ {"pvh_remove_header", (cmd_function)w_pvh_remove_header, 2,
-+ fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE},
-+ {0, 0, 0, 0, 0, 0}};
++ {"pvh_collect_headers", (cmd_function)w_pvh_collect_headers, 0, 0, 0,
++ ANY_ROUTE},
++ {"pvh_apply_headers", (cmd_function)w_pvh_apply_headers, 0, 0, 0,
++ ANY_ROUTE},
++ {"pvh_reset_headers", (cmd_function)w_pvh_reset_headers, 0, 0, 0,
++ ANY_ROUTE},
++ {"pvh_check_header", (cmd_function)w_pvh_check_header, 1,
++ fixup_spve_null, fixup_free_spve_null, ANY_ROUTE},
++ {"pvh_append_header", (cmd_function)w_pvh_append_header, 2,
++ fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE},
++ {"pvh_modify_header", (cmd_function)w_pvh_modify_header, 2,
++ fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE},
++ {"pvh_modify_header", (cmd_function)w_pvh_modify_header, 3,
++ fixup_spve_all, fixup_free_spve_all, ANY_ROUTE},
++ {"pvh_remove_header", (cmd_function)w_pvh_remove_header, 1,
++ fixup_spve_null, fixup_free_spve_null, ANY_ROUTE},
++ {"pvh_remove_header", (cmd_function)w_pvh_remove_header, 2,
++ fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE},
++ {0, 0, 0, 0, 0, 0}
++};
+
+static pv_export_t mod_pvs[] = {
-+ {{"x_hdr", (sizeof("x_hdr") - 1)}, PVT_OTHER, pvh_get_header,
-+ pvh_set_header, pvh_parse_header_name, pv_parse_index, 0, 0},
-+ {{"x_fu", (sizeof("x_fu") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
-+ 0, pv_init_iname, 1},
-+ {{"x_fU", (sizeof("x_fU") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
-+ 0, pv_init_iname, 2},
-+ {{"x_fd", (sizeof("x_fd") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
-+ 0, pv_init_iname, 3},
-+ {{"x_fn", (sizeof("x_fn") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
-+ 0, pv_init_iname, 4},
-+ {{"x_ft", (sizeof("x_ft") - 1)}, PVT_OTHER, pvh_get_uri, /* ro */ 0, 0,
-+ 0, pv_init_iname, 5},
-+ {{"x_tu", (sizeof("x_tu") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
-+ 0, pv_init_iname, 6},
-+ {{"x_tU", (sizeof("x_tU") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
-+ 0, pv_init_iname, 7},
-+ {{"x_td", (sizeof("x_td") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
-+ 0, pv_init_iname, 8},
-+ {{"x_tn", (sizeof("x_tn") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
-+ 0, pv_init_iname, 9},
-+ {{"x_tt", (sizeof("x_tt") - 1)}, PVT_OTHER, pvh_get_uri, /* ro */ 0, 0,
-+ 0, pv_init_iname, 10},
-+ {{"x_rs", (sizeof("x_rs") - 1)}, PVT_OTHER, pvh_get_reply_sr,
-+ pvh_set_reply_sr, 0, 0, pv_init_iname, 1},
-+ {{"x_rr", (sizeof("x_rr") - 1)}, PVT_OTHER, pvh_get_reply_sr,
-+ pvh_set_reply_sr, 0, 0, pv_init_iname, 2},
-+ {{0, 0}, 0, 0, 0, 0, 0, 0, 0}};
-+
-+static param_export_t params[] = {{"xavp_name", PARAM_STR, &xavp_name},
-+ {"header_value_size", PARAM_INT, &header_value_size},
-+ {"header_collect_flag", PARAM_INT, &FL_PV_HDRS_COLLECTED},
-+ {"header_apply_flag", PARAM_INT, &FL_PV_HDRS_APPLIED},
-+ {"skip_headers", PARAM_STR, &skip_headers_param},
-+ {"split_headers", PARAM_STR, &split_headers_param},
-+ {"auto_msg", PARAM_INT, &auto_msg_param}, {0, 0, 0}};
++ {{"x_hdr", (sizeof("x_hdr") - 1)}, PVT_OTHER, pvh_get_header,
++ pvh_set_header, pvh_parse_header_name, pv_parse_index, 0, 0},
++ {{"x_fu", (sizeof("x_fu") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
++ 0, pv_init_iname, 1},
++ {{"x_fU", (sizeof("x_fU") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
++ 0, pv_init_iname, 2},
++ {{"x_fd", (sizeof("x_fd") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
++ 0, pv_init_iname, 3},
++ {{"x_fn", (sizeof("x_fn") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
++ 0, pv_init_iname, 4},
++ {{"x_ft", (sizeof("x_ft") - 1)}, PVT_OTHER, pvh_get_uri, /* ro */ 0, 0,
++ 0, pv_init_iname, 5},
++ {{"x_tu", (sizeof("x_tu") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
++ 0, pv_init_iname, 6},
++ {{"x_tU", (sizeof("x_tU") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
++ 0, pv_init_iname, 7},
++ {{"x_td", (sizeof("x_td") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
++ 0, pv_init_iname, 8},
++ {{"x_tn", (sizeof("x_tn") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
++ 0, pv_init_iname, 9},
++ {{"x_tt", (sizeof("x_tt") - 1)}, PVT_OTHER, pvh_get_uri, /* ro */ 0, 0,
++ 0, pv_init_iname, 10},
++ {{"x_rs", (sizeof("x_rs") - 1)}, PVT_OTHER, pvh_get_reply_sr,
++ pvh_set_reply_sr, 0, 0, pv_init_iname, 1},
++ {{"x_rr", (sizeof("x_rr") - 1)}, PVT_OTHER, pvh_get_reply_sr,
++ pvh_set_reply_sr, 0, 0, pv_init_iname, 2},
++ {{0, 0}, 0, 0, 0, 0, 0, 0, 0}
++};
++
++static param_export_t params[] = {
++ {"xavp_name", PARAM_STR, &xavp_name},
++ {"header_value_size", PARAM_INT, &header_value_size},
++ {"header_collect_flag", PARAM_INT, &FL_PV_HDRS_COLLECTED},
++ {"header_apply_flag", PARAM_INT, &FL_PV_HDRS_APPLIED},
++ {"skip_headers", PARAM_STR, &skip_headers_param},
++ {"split_headers", PARAM_STR, &split_headers_param},
++ {"auto_msg", PARAM_INT, &auto_msg_param},
++ {0, 0, 0}
++};
+
+struct module_exports exports = {
-+ MODULE_NAME, /* module name */
-+ DEFAULT_DLFLAGS, /* dlopen flags */
-+ cmds, /* exported functions */
-+ params, /* exported parameters */
-+ 0, /* RPC method exports */
-+ mod_pvs, /* exported pseudo-variables */
-+ 0, /* response handling function */
-+ mod_init, /* module initialization function */
-+ 0, /* per-child init function */
-+ mod_destroy /* module destroy function */
++ MODULE_NAME, /* module name */
++ DEFAULT_DLFLAGS, /* dlopen flags */
++ cmds, /* exported functions */
++ params, /* exported parameters */
++ 0, /* RPC method exports */
++ mod_pvs, /* exported pseudo-variables */
++ 0, /* response handling function */
++ mod_init, /* module initialization function */
++ 0, /* per-child init function */
++ mod_destroy /* module destroy function */
+};
++/* clang-format on */
+
+int mod_init(void)
+{
@@ -1167,19 +1201,25 @@ index 0000000..9730847
+ LM_NOTICE("could not bind to the 'tm' module, automatic headers "
+ "collect/apply is disabled\n");
+ auto_msg_param = 0;
-+ } else {
-+ if(auto_msg_param
-+ && register_script_cb(
-+ handle_msg_cb, PRE_SCRIPT_CB | REQUEST_CB, 0)
-+ < 0) {
-+ LM_ERR("cannot register PRE_SCRIPT_CB callbacks\n");
++ }
++ if(auto_msg_param) {
++ if(register_script_cb(handle_msg_cb, PRE_SCRIPT_CB | REQUEST_CB, 0)
++ < 0) {
++ LM_ERR("cannot register PRE_SCRIPT_CB REQUEST_CB callbacks\n");
++ return -1;
++ }
++ if(register_script_cb(
++ handle_msg_branch_cb, PRE_SCRIPT_CB | BRANCH_CB, 0)
++ < 0) {
++ LM_ERR("cannot register PRE_SCRIPT_CB BRANCH_CB callbacks\n");
++ return -1;
++ }
++ if(register_script_cb(
++ handle_msg_reply_cb, PRE_SCRIPT_CB | ONREPLY_CB, 0)
++ < 0) {
++ LM_ERR("cannot register PRE_SCRIPT_CB ONREPLY_CB callbacks\n");
+ return -1;
+ }
-+ }
-+
-+ if(header_value_size == 0) {
-+ LM_ERR("header_value_size must be >=0\n");
-+ return -1;
+ }
+
+ pvh_str_hash_init(&skip_headers, &skip_headers_param, "skip_headers");
@@ -1191,25 +1231,81 @@ index 0000000..9730847
+
+void mod_destroy(void)
+{
-+ pvh_str_hash_free(&skip_headers);
-+ pvh_str_hash_free(&split_headers);
-+ pvh_str_hash_free(&single_headers);
-+ pvh_free_xavp(&xavp_name);
-+ pvh_free_xavp(&xavp_parsed_xname);
+ LM_INFO("%s module unload...\n", MODULE_NAME);
+}
+
++/* just for debug */
++static inline char *tm_type_to_string(int type)
++{
++ switch(type) {
++ case TMCB_REQUEST_IN:
++ return "TMCB_REQUEST_IN";
++ case TMCB_RESPONSE_IN:
++ return "TMCB_RESPONSE_IN";
++ case TMCB_E2EACK_IN:
++ return "TMCB_E2EACK_IN";
++ case TMCB_REQUEST_PENDING:
++ return "TMCB_REQUEST_PENDING";
++ case TMCB_REQUEST_FWDED:
++ return "TMCB_REQUEST_FWDED";
++ case TMCB_RESPONSE_FWDED:
++ return "TMCB_RESPONSE_FWDED";
++ case TMCB_ON_FAILURE_RO:
++ return "TMCB_ON_FAILURE_RO";
++ case TMCB_ON_FAILURE:
++ return "TMCB_ON_FAILURE";
++ case TMCB_REQUEST_OUT:
++ return "TMCB_REQUEST_OUT";
++ case TMCB_RESPONSE_OUT:
++ return "TMCB_RESPONSE_OUT";
++ case TMCB_LOCAL_COMPLETED:
++ return "TMCB_LOCAL_COMPLETED";
++ case TMCB_LOCAL_RESPONSE_OUT:
++ return "TMCB_LOCAL_RESPONSE_OUT";
++ case TMCB_ACK_NEG_IN:
++ return "TMCB_ACK_NEG_IN";
++ case TMCB_REQ_RETR_IN:
++ return "TMCB_REQ_RETR_IN";
++ case TMCB_LOCAL_RESPONSE_IN:
++ return "TMCB_LOCAL_RESPONSE_IN";
++ case TMCB_LOCAL_REQUEST_IN:
++ return "TMCB_LOCAL_REQUEST_IN";
++ case TMCB_DLG:
++ return "TMCB_DLG";
++ case TMCB_DESTROY:
++ return "TMCB_DESTROY";
++ case TMCB_E2ECANCEL_IN:
++ return "TMCB_E2ECANCEL_IN";
++ case TMCB_E2EACK_RETR_IN:
++ return "TMCB_E2EACK_RETR_IN";
++ case TMCB_RESPONSE_READY:
++ return "TMCB_RESPONSE_READY";
++ case TMCB_DONT_ACK:
++ return "TMCB_DONT_ACK";
++ case TMCB_REQUEST_SENT:
++ return "TMCB_REQUEST_SENT";
++ case TMCB_RESPONSE_SENT:
++ return "TMCB_RESPONSE_SENT";
++ case TMCB_ON_BRANCH_FAILURE:
++ return "TMCB_ON_BRANCH_FAILURE";
++ case TMCB_ON_BRANCH_FAILURE_RO:
++ return "TMCB_ON_BRANCH_FAILURE_RO";
++ case TMCB_MAX:
++ return "TMCB_MAX";
++ }
++
++ return "UNKNOWN";
++}
++
+void handle_tm_t(tm_cell_t *t, int type, struct tmcb_params *params)
+{
+ struct sip_msg *msg = NULL;
+
-+ if(type & TMCB_RESPONSE_IN) {
-+ msg = params->rpl;
-+ if(msg != NULL && msg != FAKED_REPLY) {
-+ pvh_reset_headers(msg);
-+ pvh_collect_headers(msg, 1);
-+ }
-+ } else if(type & TMCB_REQUEST_FWDED) {
++ LM_DBG("T:%p params->branch:%d type:%s\n", t, params->branch,
++ tm_type_to_string(type));
++
++
++ if(type & TMCB_REQUEST_FWDED) {
+ msg = params->req;
+ } else if(type & (TMCB_ON_BRANCH_FAILURE | TMCB_RESPONSE_FWDED)) {
+ msg = params->rpl;
@@ -1218,60 +1314,137 @@ index 0000000..9730847
+ return;
+ }
+
-+ if(msg != NULL && msg != FAKED_REPLY)
-+ pvh_apply_headers(msg, 1);
+
++ LM_DBG("T:%p picked_branch:%d label:%d branches:%d\n", t,
++ tmb.t_get_picked_branch(), t->label, t->nr_of_outgoings);
++
++ if(msg != NULL && msg != FAKED_REPLY) {
++ pvh_get_branch_index(msg, &_branch);
++ LM_DBG("T:%p set branch:%d\n", t, _branch);
++ pvh_apply_headers(msg);
++ }
+ return;
+}
+
++static int msg_cbs =
++ TMCB_REQUEST_FWDED | TMCB_RESPONSE_FWDED | TMCB_ON_BRANCH_FAILURE;
++
+int handle_msg_cb(struct sip_msg *msg, unsigned int flags, void *cb)
+{
-+ int cbs = TMCB_REQUEST_FWDED | TMCB_RESPONSE_FWDED | TMCB_RESPONSE_IN
-+ | TMCB_ON_BRANCH_FAILURE;
++ if(pvh_parse_msg(msg) != 0)
++ return 1;
+
-+ if(flags & (PRE_SCRIPT_CB | REQUEST_CB)) {
-+ if(tmb.register_tmcb(msg, 0, cbs, handle_tm_t, 0, 0) <= 0) {
-+ LM_ERR("cannot register TM callbacks\n");
-+ return -1;
-+ }
-+ pvh_collect_headers(msg, 1);
++ if(tmb.register_tmcb(msg, 0, msg_cbs, handle_tm_t, 0, 0) <= 0) {
++ LM_ERR("cannot register TM callbacks\n");
++ return -1;
++ }
++
++ _branch = 0;
++ LM_DBG("msg:%p set branch:%d\n", msg, _branch);
++ pvh_collect_headers(msg);
++ return 1;
++}
++
++int handle_msg_branch_cb(struct sip_msg *msg, unsigned int flags, void *cb)
++{
++
++ LM_DBG("msg:%p previous branch:%d\n", msg, _branch);
++
++ if(flags & PRE_SCRIPT_CB) {
++ pvh_get_branch_index(msg, &_branch);
++ LM_DBG("msg:%p set branch:%d\n", msg, _branch);
++ pvh_clone_branch_xavp(msg, &xavp_name);
++ }
++
++ return 1;
++}
++
++int handle_msg_reply_cb(struct sip_msg *msg, unsigned int flags, void *cb)
++{
++ tm_cell_t *t = NULL;
++ sr_xavp_t **backup_xavps = NULL;
++ sr_xavp_t **list = NULL;
++
++ if(pvh_parse_msg(msg) != 0)
++ return 1;
++ LM_DBG("msg:%p previous branch:%d\n", msg, _branch);
++
++ if(tmb.t_check(msg, &_branch) == -1) {
++ LM_ERR("failed find UAC branch\n");
+ } else {
-+ LM_ERR("unknown callback: %d\n", flags);
++ t = tmb.t_gett();
++ if(t == NULL || t == T_UNDEFINED) {
++ LM_DBG("cannot lookup the transaction\n");
++ } else {
++ LM_DBG("T:%p t_check-branch:%d xavp_list:%p branches:%d\n", t,
++ _branch, &t->xavps_list, t->nr_of_outgoings);
++ list = &t->xavps_list;
++ backup_xavps = xavp_set_list(&t->xavps_list);
++ }
+ }
+
++ pvh_get_branch_index(msg, &_branch);
++ LM_DBG("T:%p set branch:%d picked_branch:%d\n", t, _branch,
++ tmb.t_get_picked_branch());
++
++ if((_reply_counter = pvh_reply_append(list)) < 0) {
++ return -1;
++ }
++ pvh_collect_headers(msg);
++ if(backup_xavps) {
++ xavp_set_list(backup_xavps);
++ LM_DBG("restored backup_xavps:%p\n", *backup_xavps);
++ }
++ if(t) {
++ tmb.unref_cell(t);
++ LM_DBG("T:%p unref\n", t);
++ }
++ tmb.t_sett(T_UNDEFINED, T_BR_UNDEFINED);
++ LM_DBG("reset tm\n");
++
+ return 1;
+}
+
++/* clang-format off */
+static sr_kemi_t pvh_kemi_exports[] = {
-+ {str_init("pv_headers"), str_init("pvh_collect_headers"), SR_KEMIP_INT,
-+ ki_pvh_collect_headers,
-+ {SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
-+ SR_KEMIP_NONE, SR_KEMIP_NONE}},
-+ {str_init("pv_headers"), str_init("pvh_apply_headers"), SR_KEMIP_INT,
-+ ki_pvh_apply_headers,
-+ {SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
-+ SR_KEMIP_NONE, SR_KEMIP_NONE}},
-+ {str_init("pv_headers"), str_init("pvh_reset_headers"), SR_KEMIP_INT,
-+ pvh_reset_headers,
-+ {SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
-+ SR_KEMIP_NONE, SR_KEMIP_NONE}},
-+ {str_init("pv_headers"), str_init("pvh_check_header"), SR_KEMIP_INT,
-+ pvh_check_header,
-+ {SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
-+ SR_KEMIP_NONE, SR_KEMIP_NONE}},
-+ {str_init("pv_headers"), str_init("pvh_append_header"), SR_KEMIP_INT,
-+ pvh_check_header,
-+ {SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
-+ SR_KEMIP_NONE, SR_KEMIP_NONE}},
-+ {str_init("pv_headers"), str_init("pvh_modify_header"), SR_KEMIP_INT,
-+ pvh_modify_header,
-+ {SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_INT, SR_KEMIP_NONE,
-+ SR_KEMIP_NONE, SR_KEMIP_NONE}},
-+ {str_init("pv_headers"), str_init("pvh_remove_header"), SR_KEMIP_INT,
-+ pvh_remove_header,
-+ {SR_KEMIP_STR, SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
-+ SR_KEMIP_NONE, SR_KEMIP_NONE}},
-+ {{0, 0}, {0, 0}, 0, NULL, {0, 0, 0, 0, 0, 0}}};
++ { str_init("pv_headers"), str_init("pvh_collect_headers"),
++ SR_KEMIP_INT, ki_pvh_collect_headers,
++ { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE}
++ },
++ { str_init("pv_headers"), str_init("pvh_apply_headers"),
++ SR_KEMIP_INT, ki_pvh_apply_headers,
++ { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE}
++ },
++ { str_init("pv_headers"), str_init("pvh_reset_headers"),
++ SR_KEMIP_INT, pvh_reset_headers,
++ { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE}
++ },
++ { str_init("pv_headers"), str_init("pvh_check_header"),
++ SR_KEMIP_INT, pvh_check_header,
++ { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE}
++ },
++ { str_init("pv_headers"), str_init("pvh_append_header"),
++ SR_KEMIP_INT, pvh_append_header,
++ { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE}
++ },
++ { str_init("pv_headers"), str_init("pvh_modify_header"),
++ SR_KEMIP_INT, pvh_modify_header,
++ { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_INT,
++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE}
++ },
++ { str_init("pv_headers"), str_init("pvh_remove_header"),
++ SR_KEMIP_INT, pvh_remove_header,
++ { SR_KEMIP_STR, SR_KEMIP_INT, SR_KEMIP_NONE,
++ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE}
++ },
++ {{0, 0}, {0, 0}, 0, NULL, {0, 0, 0, 0, 0, 0}}
++};
++/* clang-format on */
+
+int mod_register(char *path, int *dlflags, void *p1, void *p2)
+{
@@ -1280,23 +1453,25 @@ index 0000000..9730847
+}
diff --git a/src/modules/pv_headers/pv_headers.h b/src/modules/pv_headers/pv_headers.h
new file mode 100644
-index 0000000..556b7bf
+index 0000000..4d53318
--- /dev/null
+++ b/src/modules/pv_headers/pv_headers.h
-@@ -0,0 +1,51 @@
+@@ -0,0 +1,57 @@
+/*
-+ * PV Headers
++ * pv_headers
+ *
-+ * Copyright (C) 2018 Kirill Solomko
++ * Copyright (C)
++ * 2020 Victor Seva
++ * 2018 Kirill Solomko
+ *
-+ * This file is part of SIP Router, a free SIP server.
++ * This file is part of Kamailio, a free SIP server.
+ *
-+ * SIP Router is free software; you can redistribute it and/or modify
++ * 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
+ *
-+ * SIP Router is distributed in the hope that it will be useful,
++ * 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.
@@ -1324,12 +1499,16 @@ index 0000000..556b7bf
+
+extern str xavp_name;
+extern str xavp_parsed_xname;
++extern str xavp_helper_xname;
+
+extern unsigned int header_name_size;
+extern unsigned int header_value_size;
+
+extern str _hdr_from;
+extern str _hdr_to;
++extern str _hdr_reply_reason;
++extern int _branch;
++extern int _reply_counter;
+
+extern int FL_PV_HDRS_COLLECTED;
+extern int FL_PV_HDRS_APPLIED;
@@ -1337,23 +1516,25 @@ index 0000000..556b7bf
+#endif /* PV_HEADERS_H */
diff --git a/src/modules/pv_headers/pvh_func.c b/src/modules/pv_headers/pvh_func.c
new file mode 100644
-index 0000000..22ee74e
+index 0000000..b3749a6
--- /dev/null
+++ b/src/modules/pv_headers/pvh_func.c
-@@ -0,0 +1,388 @@
+@@ -0,0 +1,360 @@
+/*
+ * pv_headers
+ *
-+ * Copyright (C) 2018 Kirill Solomko
++ * Copyright (C)
++ * 2020 Victor Seva
++ * 2018 Kirill Solomko
+ *
-+ * This file is part of SIP Router, a free SIP server.
++ * This file is part of Kamailio, a free SIP server.
+ *
-+ * SIP Router is free software; you can redistribute it and/or modify
++ * 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
+ *
-+ * SIP Router is distributed in the hope that it will be useful,
++ * 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.
@@ -1364,18 +1545,38 @@ index 0000000..22ee74e
+ *
+ */
+
-+#include "../../core/dset.h"
++#include "../../core/strutils.h"
+
+#include "pv_headers.h"
++#include "pvh_func.h"
++#include "pvh_xavp.h"
+#include "pvh_str.h"
-+#include "pvh_hdr.h"
+#include "pvh_hash.h"
-+#include "pvh_xavp.h"
++#include "pvh_hdr.h"
+
-+static str xavp_helper_xname = str_init("modparam_pv_headers");
+static str xavp_helper_name = str_init("xavp_name");
+
-+int pvh_collect_headers(struct sip_msg *msg, int is_auto)
++int pvh_parse_msg(sip_msg_t *msg)
++{
++ if(msg->first_line.type == SIP_REQUEST) {
++ if(!IS_SIP(msg)) {
++ LM_DBG("non SIP request message\n");
++ return 1;
++ }
++ } else if(msg->first_line.type == SIP_REPLY) {
++ if(!IS_SIP_REPLY(msg)) {
++ LM_DBG("non SIP reply message\n");
++ return 1;
++ }
++ } else {
++ LM_DBG("non SIP message\n");
++ return 1;
++ }
++
++ return 0;
++}
++
++int pvh_collect_headers(struct sip_msg *msg)
+{
+ struct hdr_field *hf = NULL;
+ str name = STR_NULL;
@@ -1383,22 +1584,10 @@ index 0000000..22ee74e
+ char hvals[header_name_size][header_value_size];
+ int idx = 0, d_size = 0;
+ str val_part = STR_NULL;
-+ int br_idx;
-+
-+ pvh_get_branch_index(msg, &br_idx);
-+ LM_DBG("br_idx: %d\n", br_idx);
-+ if(!is_auto) {
-+ if(msg->first_line.type == SIP_REPLY) {
-+ if(isflagset(msg, FL_PV_HDRS_COLLECTED) == 1) {
-+ LM_ERR("headers are already collected\n");
-+ return -1;
-+ }
-+ } else {
-+ if(isbflagset(br_idx, FL_PV_HDRS_COLLECTED) == 1) {
-+ LM_ERR("headers are already collected\n");
-+ return -1;
-+ }
-+ }
++
++ if(pvh_hdrs_collected(msg)) {
++ LM_ERR("headers are already collected\n");
++ return -1;
+ }
+
+ if(parse_headers(msg, HDR_EOH_F, 0) < 0) {
@@ -1406,38 +1595,35 @@ index 0000000..22ee74e
+ return -1;
+ }
+
-+ if(pvh_str_new(&name, header_name_size) < 0)
-+ goto err;
-+ if(pvh_str_new(&val, header_value_size) < 0)
-+ goto err;
-+
-+ if(name.s == NULL || val.s == NULL)
-+ goto err;
-+
+ for(hf = msg->headers; hf; hf = hf->next) {
+ LM_DBG("collect header[%.*s]: %.*s\n", hf->name.len, hf->name.s,
+ hf->body.len, hf->body.s);
+
+ switch(hf->type) {
+ case HDR_FROM_T:
-+ pvh_str_copy(&name, &_hdr_from, header_name_size);
++ name.len = _hdr_from.len;
++ name.s = _hdr_from.s;
+ LM_DBG("force [From] as key\n");
+ break;
+ case HDR_TO_T:
-+ pvh_str_copy(&name, &_hdr_to, header_name_size);
++ name.len = _hdr_to.len;
++ name.s = _hdr_to.s;
+ LM_DBG("force [To] as key\n");
+ break;
+ default:
-+ pvh_str_copy(&name, &hf->name, header_name_size);
++ name.len = hf->name.len;
++ name.s = hf->name.s;
+ }
-+ pvh_str_copy(&val, &hf->body, header_value_size);
++ val.len = hf->body.len;
++ val.s = hf->body.s;
+
-+ if(str_hash_get(&split_headers, name.s, name.len)
-+ && strchr(val.s, ',') != NULL) {
++ if(strchr(val.s, ',') != NULL
++ && str_hash_get(&split_headers, name.s, name.len)) {
+
+ if(pvh_split_values(&val, hvals, &d_size, 1) < 0) {
-+ LM_ERR("could not parse Diversion header comma separated "
-+ "value");
++ LM_ERR("could not parse %.*s header comma separated "
++ "value",
++ name.len, name.s);
+ return -1;
+ }
+
@@ -1447,61 +1633,43 @@ index 0000000..22ee74e
+ if(pvh_set_xavp(msg, &xavp_name, &name, &val_part, SR_XTYPE_STR,
+ 0, 1)
+ < 0)
-+ goto err;
++ return -1;
+ }
+ continue;
+ }
+ if(pvh_set_xavp(msg, &xavp_name, &name, &val, SR_XTYPE_STR, 0, 1) < 0)
-+ goto err;
++ return -1;
+ }
+
+ if(pvh_set_xavp(msg, &xavp_helper_xname, &xavp_helper_name, &xavp_name,
+ SR_XTYPE_STR, 0, 0)
+ < 0)
-+ goto err;
-+
-+ pvh_str_free(&name);
-+ pvh_str_free(&val);
++ return -1;
+
-+ msg->first_line.type == SIP_REPLY ? setflag(msg, FL_PV_HDRS_COLLECTED)
-+ : setbflag(br_idx, FL_PV_HDRS_COLLECTED);
++ pvh_hdrs_set_collected(msg);
+
+ return 1;
-+
-+err:
-+ pvh_str_free(&name);
-+ pvh_str_free(&val);
-+ return -1;
+}
+
-+int pvh_apply_headers(struct sip_msg *msg, int is_auto)
++int pvh_apply_headers(struct sip_msg *msg)
+{
+ sr_xavp_t *xavp = NULL;
+ sr_xavp_t *sub = NULL;
-+ str display = STR_NULL;
-+ str uri = STR_NULL;
+ struct str_hash_table rm_hdrs;
+ int from_cnt = 0, to_cnt = 0;
-+ str br_xname = STR_NULL;
-+ int br_idx, keys_count;
++ char t[header_name_size];
++ char tv[2][header_value_size];
++ str display = {tv[0], header_value_size};
++ str uri = {tv[1], header_value_size};
++ str br_xname = {t, header_name_size};
++ int skip_from_to = 0, keys_count = 0;
+ int res = -1;
+
-+ rm_hdrs.size = 0;
-+
-+ pvh_get_branch_index(msg, &br_idx);
++ memset(&rm_hdrs, 0, sizeof(struct str_hash_table));
+
-+ if(!is_auto) {
-+ if(msg->first_line.type == SIP_REPLY) {
-+ if(isflagset(msg, FL_PV_HDRS_APPLIED) == 1) {
-+ LM_ERR("headers are already applied\n");
-+ return -1;
-+ }
-+ } else {
-+ if(isbflagset(br_idx, FL_PV_HDRS_APPLIED) == 1) {
-+ LM_ERR("headers are already applied\n");
-+ return -1;
-+ }
-+ }
++ if(pvh_hdrs_applied(msg)) {
++ LM_ERR("headers are already applied\n");
++ return -1;
+ }
+
+ if(parse_headers(msg, HDR_EOH_F, 0) < 0) {
@@ -1509,53 +1677,55 @@ index 0000000..22ee74e
+ return -1;
+ }
+
-+ if(pvh_str_new(&display, header_value_size) < 0)
-+ goto err;
-+ if(pvh_str_new(&uri, header_value_size) < 0)
-+ goto err;
-+ if(pvh_str_new(&br_xname, header_value_size) < 0)
-+ goto err;
-+
+ pvh_get_branch_xname(msg, &xavp_name, &br_xname);
+
+ if((xavp = xavp_get(&br_xname, NULL)) == NULL
+ && (xavp = xavp_get(&xavp_name, NULL)) == NULL) {
+ LM_ERR("missing xavp %s, run pv_collect_headers() first\n",
+ xavp_name.s);
-+ goto err;
++ return -1;
+ }
+ if(xavp->val.type != SR_XTYPE_XAVP) {
+ LM_ERR("not xavp child type %s\n", xavp_name.s);
-+ goto err;
++ return -1;
+ }
+
+ if((sub = xavp->val.v.xavp) == NULL) {
+ LM_ERR("invalid xavp structure: %s\n", xavp_name.s);
-+ goto err;
++ return -1;
+ }
+ keys_count = pvh_xavp_keys_count(&sub);
+ if(str_hash_alloc(&rm_hdrs, keys_count) < 0) {
+ PKG_MEM_ERROR;
-+ goto err;
++ return -1;
+ }
+ LM_DBG("xavp->name:%.*s br_xname:%.*s keys_count: %d\n", xavp->name.len,
+ xavp->name.s, br_xname.len, br_xname.s, keys_count);
+ str_hash_init(&rm_hdrs);
+
++ if(msg->first_line.type == SIP_REPLY
++ || msg->first_line.u.request.method_value == METHOD_ACK
++ || msg->first_line.u.request.method_value == METHOD_PRACK
++ || msg->first_line.u.request.method_value == METHOD_BYE) {
++ skip_from_to = 1;
++ if(msg->to == NULL) {
++ LM_DBG("no To header, can't store To info in parsed\n");
++ } else {
++ if(pvh_set_parsed(msg, &_hdr_to, &msg->to->body, NULL) == NULL)
++ LM_ERR("can't store To info in parsed\n");
++ }
++ }
++
+ do {
+ if(pvh_skip_header(&sub->name))
+ continue;
+
-+ if(strncasecmp(sub->name.s, _hdr_from.s, sub->name.len) == 0) {
-+ if(msg->first_line.type == SIP_REPLY
-+ || msg->first_line.u.request.method_value == METHOD_ACK
-+ || msg->first_line.u.request.method_value == METHOD_PRACK
-+ || msg->first_line.u.request.method_value == METHOD_BYE) {
++ if(cmpi_str(&sub->name, &_hdr_from) == 0) {
++ if(skip_from_to) {
+ LM_DBG("skip From header change in reply messages\n");
+ continue;
+ }
-+ if(strncmp(sub->val.v.s.s, msg->from->body.s, sub->val.v.s.len)
-+ == 0) {
++ if(cmp_str(&sub->val.v.s, &msg->from->body) == 0) {
+ LM_DBG("skip unchanged From header\n");
+ continue;
+ }
@@ -1582,16 +1752,12 @@ index 0000000..22ee74e
+ continue;
+ }
+
-+ if(strncasecmp(sub->name.s, _hdr_to.s, sub->name.len) == 0) {
-+ if(msg->first_line.type == SIP_REPLY
-+ || msg->first_line.u.request.method_value == METHOD_ACK
-+ || msg->first_line.u.request.method_value == METHOD_PRACK
-+ || msg->first_line.u.request.method_value == METHOD_BYE) {
++ if(cmpi_str(&sub->name, &_hdr_to) == 0) {
++ if(skip_from_to) {
+ LM_DBG("skip To header change in reply messages\n");
+ continue;
+ }
-+ if(strncmp(sub->val.v.s.s, msg->to->body.s, sub->val.v.s.len)
-+ == 0) {
++ if(cmp_str(&sub->val.v.s, &msg->to->body) == 0) {
+ LM_DBG("skip unchanged To header\n");
+ continue;
+ }
@@ -1618,7 +1784,7 @@ index 0000000..22ee74e
+ continue;
+ }
+
-+ if(strncasecmp(sub->name.s, "@Reply-Reason", sub->name.len) == 0) {
++ if(cmpi_str(&sub->name, &_hdr_reply_reason) == 0) {
+ if(str_hash_get(&rm_hdrs, sub->name.s, sub->name.len))
+ continue;
+ pvh_real_replace_reply_reason(msg, &sub->val.v.s);
@@ -1644,15 +1810,11 @@ index 0000000..22ee74e
+ }
+ } while((sub = sub->next) != NULL);
+
-+ msg->first_line.type == SIP_REPLY ? setflag(msg, FL_PV_HDRS_APPLIED)
-+ : setbflag(br_idx, FL_PV_HDRS_APPLIED);
++ pvh_hdrs_set_applied(msg);
+
+ res = 1;
+
+err:
-+ pvh_str_free(&display);
-+ pvh_str_free(&uri);
-+ pvh_str_free(&br_xname);
+ if(rm_hdrs.size)
+ pvh_str_hash_free(&rm_hdrs);
+ return res;
@@ -1660,28 +1822,17 @@ index 0000000..22ee74e
+
+int pvh_reset_headers(struct sip_msg *msg)
+{
-+ str br_xname = STR_NULL;
-+ int br_idx;
-+
-+ if(pvh_str_new(&br_xname, header_name_size) < 0)
-+ return -1;
++ char t[header_name_size];
++ str br_xname = {t, header_name_size};
+
-+ pvh_get_branch_index(msg, &br_idx);
+ pvh_get_branch_xname(msg, &xavp_name, &br_xname);
-+
++ LM_DBG("clean xavp:%.*s\n", br_xname.len, br_xname.s);
+ pvh_free_xavp(&br_xname);
+ pvh_get_branch_xname(msg, &xavp_parsed_xname, &br_xname);
++ LM_DBG("clean xavp:%.*s\n", br_xname.len, br_xname.s);
+ pvh_free_xavp(&br_xname);
+
-+ if(msg->first_line.type == SIP_REPLY) {
-+ resetflag(msg, FL_PV_HDRS_COLLECTED);
-+ resetflag(msg, FL_PV_HDRS_APPLIED);
-+ } else {
-+ resetbflag(br_idx, FL_PV_HDRS_COLLECTED);
-+ resetbflag(br_idx, FL_PV_HDRS_APPLIED);
-+ }
-+
-+ pvh_str_free(&br_xname);
++ pvh_hdrs_reset_flags(msg);
+
+ return 1;
+}
@@ -1731,23 +1882,25 @@ index 0000000..22ee74e
+}
diff --git a/src/modules/pv_headers/pvh_func.h b/src/modules/pv_headers/pvh_func.h
new file mode 100644
-index 0000000..0fe5524
+index 0000000..6aaf5aa
--- /dev/null
+++ b/src/modules/pv_headers/pvh_func.h
-@@ -0,0 +1,38 @@
+@@ -0,0 +1,42 @@
+/*
-+ * PV Headers
++ * pv_headers
+ *
-+ * Copyright (C) 2018 Kirill Solomko
++ * Copyright (C)
++ * 2020 Victor Seva
++ * 2018 Kirill Solomko
+ *
-+ * This file is part of SIP Router, a free SIP server.
++ * This file is part of Kamailio, a free SIP server.
+ *
-+ * SIP Router is free software; you can redistribute it and/or modify
++ * 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
+ *
-+ * SIP Router is distributed in the hope that it will be useful,
++ * 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.
@@ -1763,8 +1916,10 @@ index 0000000..0fe5524
+
+#include "../../core/parser/msg_parser.h"
+
-+int pvh_collect_headers(struct sip_msg *msg, int is_auto);
-+int pvh_apply_headers(struct sip_msg *msg, int is_auto);
++int pvh_parse_msg(sip_msg_t *msg);
++
++int pvh_collect_headers(struct sip_msg *msg);
++int pvh_apply_headers(struct sip_msg *msg);
+int pvh_reset_headers(struct sip_msg *msg);
+
+int pvh_check_header(struct sip_msg *msg, str *hname);
@@ -1775,23 +1930,25 @@ index 0000000..0fe5524
+#endif /* PV_FUNC_H */
diff --git a/src/modules/pv_headers/pvh_hash.c b/src/modules/pv_headers/pvh_hash.c
new file mode 100644
-index 0000000..f269868
+index 0000000..6c99c43
--- /dev/null
+++ b/src/modules/pv_headers/pvh_hash.c
-@@ -0,0 +1,132 @@
+@@ -0,0 +1,134 @@
+/*
-+ * PV Headers
++ * pv_headers
+ *
-+ * Copyright (C) 2018 Kirill Solomko
++ * Copyright (C)
++ * 2020 Victor Seva
++ * 2018 Kirill Solomko
+ *
-+ * This file is part of SIP Router, a free SIP server.
++ * This file is part of Kamailio, a free SIP server.
+ *
-+ * SIP Router is free software; you can redistribute it and/or modify
++ * 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
+ *
-+ * SIP Router is distributed in the hope that it will be useful,
++ * 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.
@@ -1913,23 +2070,25 @@ index 0000000..f269868
+}
diff --git a/src/modules/pv_headers/pvh_hash.h b/src/modules/pv_headers/pvh_hash.h
new file mode 100644
-index 0000000..8828cc6
+index 0000000..d7e25f8
--- /dev/null
+++ b/src/modules/pv_headers/pvh_hash.h
-@@ -0,0 +1,39 @@
+@@ -0,0 +1,41 @@
+/*
-+ * PV Headers
++ * pv_headers
+ *
-+ * Copyright (C) 2018 Kirill Solomko
++ * Copyright (C)
++ * 2020 Victor Seva
++ * 2018 Kirill Solomko
+ *
-+ * This file is part of SIP Router, a free SIP server.
++ * This file is part of Kamailio, a free SIP server.
+ *
-+ * SIP Router is free software; you can redistribute it and/or modify
++ * 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
+ *
-+ * SIP Router is distributed in the hope that it will be useful,
++ * 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.
@@ -1958,23 +2117,25 @@ index 0000000..8828cc6
+#endif /* PVH_HASH_H */
diff --git a/src/modules/pv_headers/pvh_hdr.c b/src/modules/pv_headers/pvh_hdr.c
new file mode 100644
-index 0000000..70be9ac
+index 0000000..d83a646
--- /dev/null
+++ b/src/modules/pv_headers/pvh_hdr.c
-@@ -0,0 +1,235 @@
+@@ -0,0 +1,295 @@
+/*
-+ * PV Headers
++ * pv_headers
+ *
-+ * Copyright (C) 2018 Kirill Solomko
++ * Copyright (C)
++ * 2020 Victor Seva
++ * 2018 Kirill Solomko
+ *
-+ * This file is part of SIP Router, a free SIP server.
++ * This file is part of Kamailio, a free SIP server.
+ *
-+ * SIP Router is free software; you can redistribute it and/or modify
++ * 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
+ *
-+ * SIP Router is distributed in the hope that it will be useful,
++ * 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.
@@ -1986,15 +2147,73 @@ index 0000000..70be9ac
+ */
+
+#include "../../core/data_lump.h"
++#include "../../core/dset.h"
+
+#include "pvh_hdr.h"
+
++int pvh_hdrs_collected(struct sip_msg *msg)
++{
++ if(msg->first_line.type == SIP_REPLY) {
++ if(isflagset(msg, FL_PV_HDRS_COLLECTED) == 1) {
++ return 1;
++ }
++ } else {
++ if(isbflagset(_branch, FL_PV_HDRS_COLLECTED) == 1) {
++ return 1;
++ }
++ }
++ return 0;
++}
++
++int pvh_hdrs_applied(struct sip_msg *msg)
++{
++ if(msg->first_line.type == SIP_REPLY) {
++ if(isflagset(msg, FL_PV_HDRS_APPLIED) == 1) {
++ return 1;
++ }
++ } else {
++ if(isbflagset(_branch, FL_PV_HDRS_APPLIED) == 1) {
++ return 1;
++ }
++ }
++ return 0;
++}
++
++void pvh_hdrs_set_applied(struct sip_msg *msg)
++{
++ if(msg->first_line.type == SIP_REPLY) {
++ setflag(msg, FL_PV_HDRS_APPLIED);
++ } else {
++ setbflag(_branch, FL_PV_HDRS_APPLIED);
++ }
++}
++
++void pvh_hdrs_set_collected(struct sip_msg *msg)
++{
++ if(msg->first_line.type == SIP_REPLY) {
++ setflag(msg, FL_PV_HDRS_COLLECTED);
++ } else {
++ setbflag(_branch, FL_PV_HDRS_COLLECTED);
++ }
++}
++
++void pvh_hdrs_reset_flags(struct sip_msg *msg)
++{
++ if(msg->first_line.type == SIP_REPLY) {
++ resetflag(msg, FL_PV_HDRS_COLLECTED);
++ resetflag(msg, FL_PV_HDRS_APPLIED);
++ } else {
++ resetbflag(_branch, FL_PV_HDRS_COLLECTED);
++ resetbflag(_branch, FL_PV_HDRS_APPLIED);
++ }
++}
++
+int pvh_real_hdr_append(struct sip_msg *msg, str *hname, str *hvalue)
+{
+ struct lump *anchor = NULL;
+ hdr_field_t *hf = NULL;
+ hdr_field_t *m_hf = NULL;
-+ str new_h;
++ str new_h = STR_NULL;
+
+ if(hname->s == NULL || hvalue->s == NULL) {
+ LM_ERR("header name/value cannot be empty");
@@ -2039,7 +2258,7 @@ index 0000000..70be9ac
+{
+ struct lump *anchor = NULL;
+ hdr_field_t *hf = NULL;
-+ str new_h;
++ str new_h = STR_NULL;
+ int new = 1;
+
+ if(hname->s == NULL || hvalue->s == NULL) {
@@ -2199,23 +2418,25 @@ index 0000000..70be9ac
+}
diff --git a/src/modules/pv_headers/pvh_hdr.h b/src/modules/pv_headers/pvh_hdr.h
new file mode 100644
-index 0000000..f05d7e4
+index 0000000..4f86953
--- /dev/null
+++ b/src/modules/pv_headers/pvh_hdr.h
-@@ -0,0 +1,39 @@
+@@ -0,0 +1,47 @@
+/*
-+ * PV Headers
++ * pv_headers
+ *
-+ * Copyright (C) 2018 Kirill Solomko
++ * Copyright (C)
++ * 2020 Victor Seva
++ * 2018 Kirill Solomko
+ *
-+ * This file is part of SIP Router, a free SIP server.
++ * This file is part of Kamailio, a free SIP server.
+ *
-+ * SIP Router is free software; you can redistribute it and/or modify
++ * 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
+ *
-+ * SIP Router is distributed in the hope that it will be useful,
++ * 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.
@@ -2234,6 +2455,12 @@ index 0000000..f05d7e4
+
+#include "pv_headers.h"
+
++int pvh_hdrs_collected(struct sip_msg *msg);
++int pvh_hdrs_applied(struct sip_msg *msg);
++void pvh_hdrs_set_collected(struct sip_msg *msg);
++void pvh_hdrs_set_applied(struct sip_msg *msg);
++void pvh_hdrs_reset_flags(struct sip_msg *msg);
++
+int pvh_real_hdr_append(struct sip_msg *msg, str *hname, str *hvalue);
+int pvh_real_hdr_replace(struct sip_msg *msg, str *hname, str *hvalue);
+int pvh_real_hdr_del_by_name(struct sip_msg *msg, str *hname);
@@ -2245,23 +2472,25 @@ index 0000000..f05d7e4
\ No newline at end of file
diff --git a/src/modules/pv_headers/pvh_str.c b/src/modules/pv_headers/pvh_str.c
new file mode 100644
-index 0000000..53e2c9c
+index 0000000..6ede032
--- /dev/null
+++ b/src/modules/pv_headers/pvh_str.c
-@@ -0,0 +1,144 @@
+@@ -0,0 +1,146 @@
+/*
-+ * PV Headers
++ * pv_headers
+ *
-+ * Copyright (C) 2018 Kirill Solomko
++ * Copyright (C)
++ * 2020 Victor Seva
++ * 2018 Kirill Solomko
+ *
-+ * This file is part of SIP Router, a free SIP server.
++ * This file is part of Kamailio, a free SIP server.
+ *
-+ * SIP Router is free software; you can redistribute it and/or modify
++ * 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
+ *
-+ * SIP Router is distributed in the hope that it will be useful,
++ * 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.
@@ -2396,23 +2625,25 @@ index 0000000..53e2c9c
\ No newline at end of file
diff --git a/src/modules/pv_headers/pvh_str.h b/src/modules/pv_headers/pvh_str.h
new file mode 100644
-index 0000000..95aa0b9
+index 0000000..10aa216
--- /dev/null
+++ b/src/modules/pv_headers/pvh_str.h
-@@ -0,0 +1,38 @@
+@@ -0,0 +1,40 @@
+/*
-+ * PV Headers
++ * pv_headers
+ *
-+ * Copyright (C) 2018 Kirill Solomko
++ * Copyright (C)
++ * 2020 Victor Seva
++ * 2018 Kirill Solomko
+ *
-+ * This file is part of SIP Router, a free SIP server.
++ * This file is part of Kamailio, a free SIP server.
+ *
-+ * SIP Router is free software; you can redistribute it and/or modify
++ * 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
+ *
-+ * SIP Router is distributed in the hope that it will be useful,
++ * 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.
@@ -2441,24 +2672,25 @@ index 0000000..95aa0b9
\ No newline at end of file
diff --git a/src/modules/pv_headers/pvh_xavp.c b/src/modules/pv_headers/pvh_xavp.c
new file mode 100644
-index 0000000..de296b4
+index 0000000..0cfd969
--- /dev/null
+++ b/src/modules/pv_headers/pvh_xavp.c
-@@ -0,0 +1,1050 @@
+@@ -0,0 +1,1133 @@
+/*
++ * pv_headers
+ *
-+ * PV Headers
-+ *
-+ * Copyright (C) 2018 Kirill Solomko
++ * Copyright (C)
++ * 2020 Victor Seva
++ * 2018 Kirill Solomko
+ *
-+ * This file is part of SIP Router, a free SIP server.
++ * This file is part of Kamailio, a free SIP server.
+ *
-+ * SIP Router is free software; you can redistribute it and/or modify
++ * 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
+ *
-+ * SIP Router is distributed in the hope that it will be useful,
++ * 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.
@@ -2469,14 +2701,75 @@ index 0000000..de296b4
+ *
+ */
+
-+#include
-+
-+#include "../../core/hashes.h"
-+#include "../../core/route_struct.h"
++#include "../../core/parser/parse_uri.h"
++#include "../../core/strutils.h"
+
+#include "pvh_xavp.h"
+#include "pvh_str.h"
+#include "pvh_hash.h"
++#include "pvh_hdr.h"
++
++static str reply_counter = str_init("reply_counter");
++
++sr_xavp_t *pvh_xavp_get_child_with_ival(
++ str *rname, str *cname, sr_xavp_t *start)
++{
++ sr_xavp_t *ravp = NULL;
++ sr_xavp_t *vavp = NULL;
++
++ ravp = xavp_get(rname, start);
++ if(ravp == NULL || ravp->val.type != SR_XTYPE_XAVP)
++ return NULL;
++
++ vavp = xavp_get(cname, ravp->val.v.xavp);
++ if(vavp == NULL || vavp->val.type != SR_XTYPE_INT)
++ return NULL;
++
++ return vavp;
++}
++
++/**
++ * We keep a $xavp(xavp_helper_xname=>reply_counter) with the number of replies
++ * so we will use $xavp(xavp_name.r.) on reply_route
++ */
++int pvh_reply_append(sr_xavp_t **start)
++{
++ sr_xavp_t *xavp = NULL;
++ sr_xval_t xval;
++
++ xavp = pvh_xavp_get_child_with_ival(
++ &xavp_helper_xname, &reply_counter, start ? *start : NULL);
++ if(xavp) {
++ xavp->val.v.i++;
++ LM_DBG("reply message: %d\n", xavp->val.v.i);
++ return xavp->val.v.i;
++ }
++
++ memset(&xval, 0, sizeof(sr_xval_t));
++ xval.type = SR_XTYPE_INT;
++ xval.v.i = 0;
++
++ xavp = xavp_get(&xavp_helper_xname, start ? *start : NULL);
++ if(xavp == NULL) {
++ if(xavp_add_xavp_value(&xavp_helper_xname, &reply_counter, &xval,
++ start ? start : NULL)
++ == NULL) {
++ LM_ERR("can't create xavp:%.*s\n", xavp_helper_xname.len,
++ xavp_helper_xname.s);
++ return -1;
++ }
++ LM_DBG("xavp_name:%.*s created\n", xavp_helper_xname.len,
++ xavp_helper_xname.s);
++ } else {
++ if(xavp_add_value(&reply_counter, &xval, &xavp->val.v.xavp) == NULL) {
++ LM_ERR("can't add reply_counter value\n");
++ return -1;
++ }
++ LM_DBG("added value\n");
++ }
++ LM_DBG("reply message: %d\n", xval.v.i);
++ return xval.v.i;
++}
+
+sr_xavp_t *pvh_xavp_new_value(str *name, sr_xval_t *val)
+{
@@ -2552,51 +2845,125 @@ index 0000000..de296b4
+ return 1;
+}
+
-+sr_xval_t *pvh_xavp_get_value(
-+ struct sip_msg *msg, str *xname, str *name, int idx)
++sr_xavp_t *pvh_xavp_get(struct sip_msg *msg, str *xname)
+{
+ sr_xavp_t *xavp = NULL;
-+ sr_xavp_t *sub = NULL;
-+ str br_xname = STR_NULL;
-+
-+ if(pvh_str_new(&br_xname, header_name_size) < 0)
-+ return NULL;
++ char t[header_name_size];
++ str br_xname = {t, header_name_size};
+
+ pvh_get_branch_xname(msg, xname, &br_xname);
-+ if((xavp = xavp_get(&br_xname, NULL)) == NULL
-+ && (xavp = xavp_get(xname, NULL)) == NULL) {
-+ goto err;
++ if((xavp = xavp_get(&br_xname, NULL)) == NULL) {
++ if(cmp_str(xname, &br_xname) == 0)
++ goto end;
++ if((xavp = xavp_get(xname, NULL)) == NULL)
++ goto end;
++ if(xname != &xavp_parsed_xname) {
++ LM_DBG("br_xname:%.*s is not there, using xname:%.*s\n",
++ br_xname.len, br_xname.s, xname->len, xname->s);
++ }
+ }
+
+ if(xavp->val.type != SR_XTYPE_XAVP) {
+ LM_ERR("not xavp child type %s\n", br_xname.s);
-+ goto err;
++ xavp = NULL;
++ goto end;
+ }
+
-+ sub = xavp_get_by_index(name, idx, &xavp->val.v.xavp);
++end:
++ return xavp;
++}
+
-+ pvh_str_free(&br_xname);
-+ return sub ? &sub->val : NULL;
++int pvh_free_xavp(str *xname)
++{
++ sr_xavp_t *xavp = NULL;
++ xavp_rm_by_name(xname, 1, NULL);
++ if((xavp = xavp_get(xname, NULL)) != NULL)
++ xavp_rm(xavp, NULL);
++ return 1;
++}
+
-+err:
-+ pvh_str_free(&br_xname);
-+ return NULL;
++void pvh_free_to_params(struct to_param *param, sr_xavp_sfree_f sfree)
++{
++ struct to_param *n = NULL;
++
++ while(param) {
++ n = param->next;
++ sfree(param);
++ param = n;
++ }
++ param = NULL;
+}
+
-+sr_xavp_t *pvh_xavp_get_child(struct sip_msg *msg, str *xname, str *name)
++int pvh_parse_header_name(pv_spec_p sp, str *hname)
++{
++ pv_spec_p psp = NULL;
++
++ if(hname->s == NULL || hname->len == 0) {
++ LM_ERR("empty header name\n");
++ return -1;
++ }
++
++ if(hname->len >= header_name_size) {
++ LM_ERR("header name is too long\n");
++ return -1;
++ }
++
++ if(*hname->s == PV_MARKER) {
++ psp = (pv_spec_p)pkg_malloc(sizeof(pv_spec_t));
++ if(psp == NULL) {
++ PKG_MEM_ERROR;
++ return -1;
++ }
++ if(pv_parse_spec(hname, psp) == NULL) {
++ LM_ERR("invalid avp name [%.*s]\n", hname->len, hname->s);
++ pv_spec_free(psp);
++ return -1;
++ }
++ sp->pvp.pvn.type = PV_NAME_PVAR;
++ sp->pvp.pvn.u.dname = (void *)psp;
++ sp->pvp.pvn.u.isname.name.s = *hname;
++ return 0;
++ }
++
++ sp->pvp.pvn.type = PV_NAME_INTSTR;
++ sp->pvp.pvn.u.isname.type = AVP_NAME_STR;
++ sp->pvp.pvn.u.isname.name.s = *hname;
++
++ return 0;
++}
++
++sr_xval_t *pvh_xavp_get_value(
++ struct sip_msg *msg, str *xname, str *name, int idx)
+{
+ sr_xavp_t *xavp = NULL;
-+ str br_xname = STR_NULL;
++ sr_xavp_t *sub = NULL;
+
-+ if(pvh_str_new(&br_xname, header_name_size) < 0)
-+ return NULL;
++ if((xavp = pvh_xavp_get(msg, xname)) != NULL) {
++ /* LM_DBG("xavp:%.*s name:%.*s idx:%d\n", xavp->name.len, xavp->name.s,
++ name->len, name->s, idx); */
++ sub = xavp_get_by_index(name, idx, &xavp->val.v.xavp);
++ }
++
++ return sub ? &sub->val : NULL;
++}
++
++sr_xavp_t *pvh_xavp_get_child(struct sip_msg *msg, str *xname, str *name)
++{
++ sr_xavp_t *xavp = NULL;
++ char t[header_name_size];
++ str br_xname = {t, header_name_size};
+
+ pvh_get_branch_xname(msg, xname, &br_xname);
+ xavp = xavp_get_child(&br_xname, name);
-+ if(xavp == NULL)
-+ xavp = xavp_get_child(xname, name);
-+
-+ pvh_str_free(&br_xname);
++ if(xavp == NULL) {
++ if(cmp_str(xname, &br_xname) != 0) {
++ xavp = xavp_get_child(xname, name);
++ if(xavp) {
++ LM_DBG("br_xname:%.*s is not there, using xname:%.*s\n",
++ br_xname.len, br_xname.s, xname->len, xname->s);
++ }
++ }
++ }
+ return xavp;
+}
+
@@ -2645,56 +3012,6 @@ index 0000000..de296b4
+ return cnt;
+}
+
-+void pvh_free_to_params(struct to_param *param, sr_xavp_sfree_f sfree)
-+{
-+ struct to_param *n = NULL;
-+
-+ while(param) {
-+ n = param->next;
-+ sfree(param);
-+ param = n;
-+ }
-+ param = NULL;
-+}
-+
-+int pvh_parse_header_name(pv_spec_p sp, str *hname)
-+{
-+ pv_spec_p psp = NULL;
-+
-+ if(hname->s == NULL || hname->len == 0) {
-+ LM_ERR("empty header name\n");
-+ return -1;
-+ }
-+
-+ if(hname->len >= header_name_size) {
-+ LM_ERR("header name is too long\n");
-+ return -1;
-+ }
-+
-+ if(*hname->s == PV_MARKER) {
-+ psp = (pv_spec_p)pkg_malloc(sizeof(pv_spec_t));
-+ if(psp == NULL) {
-+ PKG_MEM_ERROR;
-+ return -1;
-+ }
-+ if(pv_parse_spec(hname, psp) == NULL) {
-+ LM_ERR("invalid avp name [%.*s]\n", hname->len, hname->s);
-+ pv_spec_free(psp);
-+ return -1;
-+ }
-+ sp->pvp.pvn.type = PV_NAME_PVAR;
-+ sp->pvp.pvn.u.dname = (void *)psp;
-+ sp->pvp.pvn.u.isname.name.s = *hname;
-+ return 0;
-+ }
-+
-+ sp->pvp.pvn.type = PV_NAME_INTSTR;
-+ sp->pvp.pvn.u.isname.type = AVP_NAME_STR;
-+ sp->pvp.pvn.u.isname.name.s = *hname;
-+
-+ return 0;
-+}
-+
+int pvh_set_xavp(struct sip_msg *msg, str *xname, str *name, void *data,
+ sr_xtype_t type, int idx, int append)
+{
@@ -2702,17 +3019,14 @@ index 0000000..de296b4
+ sr_xavp_t *root = NULL;
+ sr_xval_t root_xval;
+ sr_xval_t xval;
-+ str br_xname = STR_NULL;
-+ int br_idx;
++ char t[header_name_size];
++ str br_xname = {t, header_name_size};
+
+ if(xname == NULL || name == NULL) {
+ LM_ERR("missing xavp/pv name\n");
+ return -1;
+ }
+
-+ pvh_get_branch_index(msg, &br_idx);
-+ if(pvh_str_new(&br_xname, header_name_size) < 0)
-+ return -1;
+ pvh_get_branch_xname(msg, xname, &br_xname);
+ LM_DBG("br_xname: %.*s name: %.*s\n", br_xname.len, br_xname.s, name->len,
+ name->s);
@@ -2727,7 +3041,7 @@ index 0000000..de296b4
+ xval.v.data = (sr_data_t *)shm_malloc(sizeof(sr_data_t));
+ if(xval.v.data == NULL) {
+ SHM_MEM_ERROR;
-+ goto err;
++ return -1;
+ }
+ memset(xval.v.data, 0, sizeof(sr_data_t));
+ xval.v.data->p = data;
@@ -2736,7 +3050,7 @@ index 0000000..de296b4
+
+ root = xavp_get(&br_xname, NULL);
+
-+ if(root == NULL && br_idx > 0) {
++ if(root == NULL && _branch > 0) {
+ pvh_clone_branch_xavp(msg, xname);
+ root = xavp_get(&br_xname, NULL);
+ }
@@ -2751,7 +3065,7 @@ index 0000000..de296b4
+
+ if((root = xavp_add_value(&br_xname, &root_xval, NULL)) == NULL) {
+ LM_ERR("error create xavp %s\n", br_xname.s);
-+ goto err;
++ return -1;
+ }
+ xavp = &root->val.v.xavp;
+ } else if(xavp_get_child(&br_xname, name) == NULL) {
@@ -2762,30 +3076,16 @@ index 0000000..de296b4
+ if(pvh_xavp_append_value(name, &xval, xavp) < 0) {
+ LM_ERR("error append xavp=>name %s=>%.*s\n", br_xname.s, name->len,
+ name->s);
-+ goto err;
++ return -1;
+ }
+ } else {
+ if(pvh_xavp_set_value(name, &xval, idx, xavp) < 0) {
+ LM_ERR("error modify xavp=>name %s=>%.*s idx=%d\n", br_xname.s,
+ name->len, name->s, idx);
-+ goto err;
++ return -1;
+ }
+ }
+
-+ pvh_str_free(&br_xname);
-+ return 1;
-+
-+err:
-+ pvh_str_free(&br_xname);
-+ return -1;
-+}
-+
-+int pvh_free_xavp(str *xname)
-+{
-+ sr_xavp_t *xavp = NULL;
-+ xavp_rm_by_name(xname, 1, NULL);
-+ if((xavp = xavp_get(xname, NULL)) != NULL)
-+ xavp_rm(xavp, NULL);
+ return 1;
+}
+
@@ -2817,7 +3117,6 @@ index 0000000..de296b4
+
+int pvh_get_branch_xname(struct sip_msg *msg, str *xname, str *dst)
+{
-+ int br_idx;
+ int os = 0;
+ char br_idx_s[32];
+ char br_idx_len = 0;
@@ -2829,9 +3128,8 @@ index 0000000..de296b4
+ memcpy(dst->s, xname->s, xname->len);
+ os += xname->len;
+
-+ pvh_get_branch_index(msg, &br_idx);
-+ if(br_idx > 0) {
-+ sprintf(br_idx_s, "%d", br_idx - 1);
++ if(_branch > 0) {
++ snprintf(br_idx_s, 32, "%d", _branch - 1);
+ br_idx_len = strlen(br_idx_s);
+ memcpy(dst->s + os, ".", 1);
+ os += 1;
@@ -2839,8 +3137,10 @@ index 0000000..de296b4
+ os += br_idx_len;
+ }
+ if(msg->first_line.type == SIP_REPLY) {
-+ memcpy(dst->s + os, ".r", 2);
-+ os += 2;
++ snprintf(br_idx_s, 32, ".r.%d", _reply_counter);
++ br_idx_len = strlen(br_idx_s);
++ memcpy(dst->s + os, br_idx_s, br_idx_len);
++ os += br_idx_len;
+ }
+ dst->len = os;
+ dst->s[dst->len] = '\0';
@@ -2854,7 +3154,9 @@ index 0000000..de296b4
+ sr_xavp_t *br_xavp = NULL;
+ sr_xavp_t *sub = NULL;
+ sr_xval_t root_xval;
-+ str br_xname = STR_NULL;
++ char t[header_name_size];
++ str br_xname = {t, header_name_size};
++ int i = 0;
+
+ if((xavp = xavp_get(xname, NULL)) == NULL) {
+ LM_ERR("cannot clone xavp from non existing %s\n", xname->s);
@@ -2871,8 +3173,6 @@ index 0000000..de296b4
+ return -1;
+ }
+
-+ if(pvh_str_new(&br_xname, header_name_size) < 0)
-+ return -1;
+ pvh_get_branch_xname(msg, xname, &br_xname);
+
+ memset(&root_xval, 0, sizeof(sr_xval_t));
@@ -2881,11 +3181,10 @@ index 0000000..de296b4
+
+ if((br_xavp = xavp_add_value(&br_xname, &root_xval, NULL)) == NULL) {
+ LM_ERR("error create xavp %s\n", br_xname.s);
-+ goto err;
++ return -1;
+ }
+
-+ if(strncmp(xname->s, xavp_parsed_xname.s, xname->len) == 0) {
-+ pvh_str_free(&br_xname);
++ if(cmp_str(xname, &xavp_parsed_xname) == 0) {
+ return 1;
+ }
+
@@ -2897,16 +3196,13 @@ index 0000000..de296b4
+ if(pvh_xavp_append_value(&sub->name, &sub->val, &br_xavp->val.v.xavp)
+ < 0) {
+ LM_ERR("cannot clone xavp %s\n", sub->name.s);
-+ goto err;
++ return -1;
+ }
++ ++i;
+ } while((sub = sub->next) != NULL);
-+
-+ pvh_str_free(&br_xname);
++ LM_DBG("cloned %.*s[%d] => %.*s\n", xname->len, xname->s, i, br_xname.len,
++ br_xname.s);
+ return 1;
-+
-+err:
-+ pvh_str_free(&br_xname);
-+ return -1;
+}
+
+int pvh_get_header(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
@@ -3059,6 +3355,34 @@ index 0000000..de296b4
+ return -1;
+}
+
++xavp_c_data_t *pvh_set_parsed(
++ struct sip_msg *msg, str *hname, str *cur, str *new)
++{
++ xavp_c_data_t *c_data = NULL;
++ str *val = new;
++
++ c_data = (xavp_c_data_t *)shm_malloc(sizeof(xavp_c_data_t));
++ if(c_data == NULL) {
++ SHM_MEM_ERROR;
++ return NULL;
++ }
++ memset(c_data, 0, sizeof(xavp_c_data_t));
++ if(val == NULL)
++ val = cur;
++ if(pvh_merge_uri(msg, SET_URI_T, cur, val, c_data) < 0)
++ goto err;
++ if(pvh_set_xavp(msg, &xavp_parsed_xname, hname, c_data, SR_XTYPE_DATA, 0, 0)
++ < 0)
++ goto err;
++ LM_DBG("c_data from pvh_merge_uri hname:%.*s\n", hname->len, hname->s);
++
++ return c_data;
++
++err:
++ // how can I call?? pvh_xavp_free_data(c_data, shm_free);
++ return NULL;
++}
++
+int pvh_get_uri(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
+{
+ sr_xval_t *xval = NULL;
@@ -3068,43 +3392,38 @@ index 0000000..de296b4
+ str sval = STR_NULL;
+ int ival = 0;
+ int is_strint = 0;
-+ str hname = STR_NULL;
++ char t[header_name_size];
++ str hname = {t, header_name_size - 1};
+
+ p_no = param->pvn.u.isname.name.n;
-+ if(pvh_str_new(&hname, header_name_size) < 0)
-+ goto err;
-+
+ if(p_no >= 1 && p_no <= 5)
+ pvh_str_copy(&hname, &_hdr_from, header_name_size);
+ else if(p_no >= 6 && p_no <= 10)
+ pvh_str_copy(&hname, &_hdr_to, header_name_size);
+
+ xval = pvh_xavp_get_value(msg, &xavp_name, &hname, 0);
-+ if(xval == NULL || !xval->v.s.s)
++ if(xval == NULL || !xval->v.s.s) {
++ /* LM_DBG("xavp:%.*s hname:%.*s is null\n", xavp_name.len, xavp_name.s,
++ hname.len, hname.s); */
+ goto err;
++ }
+
+ xval_pd = pvh_xavp_get_value(msg, &xavp_parsed_xname, &hname, 0);
+
-+ if(xval_pd)
++ if(xval_pd) {
++ /* LM_DBG("p_no:%d c_data from xavp_parsed_xname hname:%.*s\n", p_no,
++ hname.len, hname.s); */
+ c_data = (xavp_c_data_t *)xval_pd->v.data->p;
++ }
+
-+ if(c_data != NULL
-+ && strncmp(xval->v.s.s, c_data->value.s, c_data->value.len) != 0) {
++ if(c_data != NULL && cmp_str(&xval->v.s, &c_data->value) != 0) {
++ /* LM_DBG("xval:%.*s != c_data->value:%.*s\n", xval->v.s.len, xval->v.s.s,
++ c_data->value.len, c_data->value.s); */
+ c_data = NULL;
+ }
+
+ if(c_data == NULL) {
-+ c_data = (xavp_c_data_t *)shm_malloc(sizeof(xavp_c_data_t));
-+ if(c_data == NULL) {
-+ SHM_MEM_ERROR;
-+ goto err;
-+ }
-+ memset(c_data, 0, sizeof(xavp_c_data_t));
-+ if(pvh_merge_uri(msg, SET_URI_T, &xval->v.s, &xval->v.s, c_data) < 0)
-+ goto err;
-+ if(pvh_set_xavp(
-+ msg, &xavp_parsed_xname, &hname, c_data, SR_XTYPE_DATA, 0, 0)
-+ < 0)
++ if((c_data = pvh_set_parsed(msg, &hname, &xval->v.s, NULL)) == NULL)
+ goto err;
+ }
+
@@ -3132,14 +3451,12 @@ index 0000000..de296b4
+ default:
+ LM_ERR("unknown get uri op\n");
+ }
-+
-+ pvh_str_free(&hname);
++ /* LM_DBG("p_no:%d sval:%.*s\n", p_no, sval.len, sval.s); */
+ return sval.s ? is_strint ? pv_get_strintval(msg, param, res, &sval, ival)
+ : pv_get_strval(msg, param, res, &sval)
+ : pv_get_null(msg, param, res);
+
+err:
-+ pvh_str_free(&hname);
+ return pv_get_null(msg, param, res);
+}
+
@@ -3150,12 +3467,11 @@ index 0000000..de296b4
+ pv_elem_p pv_format = NULL;
+ int p_no = 0;
+ enum action_type a_type;
-+ str hname;
++ char t[header_name_size];
++ str hname = {t, header_name_size - 1};
+ str fval;
+
+ p_no = param->pvn.u.isname.name.n;
-+ if(pvh_str_new(&hname, header_name_size) < 0)
-+ goto err;
+ if(p_no >= 1 && p_no <= 5)
+ pvh_str_copy(&hname, &_hdr_from, header_name_size);
+ else if(p_no >= 6 && p_no <= 10)
@@ -3210,7 +3526,8 @@ index 0000000..de296b4
+ memset(c_data, 0, sizeof(xavp_c_data_t));
+ if(pvh_merge_uri(msg, a_type, &xval->v.s, &fval, c_data) < 0)
+ goto err;
-+
++ /* LM_DBG("xavp:%.*s hname:%.*s value:%.*s\n", xavp_name.len, xavp_name.s,
++ hname.len, hname.s, c_data->value.len, c_data->value.s); */
+ if(pvh_set_xavp(msg, &xavp_name, &hname, &c_data->value, SR_XTYPE_STR, 0, 0)
+ < 0)
+ goto err;
@@ -3220,13 +3537,11 @@ index 0000000..de296b4
+ < 0)
+ goto err;
+
-+ pvh_str_free(&hname);
+ if(pv_format)
+ pv_elem_free_all(pv_format);
+ return 1;
+
+err:
-+ pvh_str_free(&hname);
+ if(pv_format)
+ pv_elem_free_all(pv_format);
+ return -1;
@@ -3392,7 +3707,6 @@ index 0000000..de296b4
+{
+ sr_xval_t *xval = NULL;
+ int p_no = 0;
-+ str rhname = {"@Reply-Reason", 13};
+
+ p_no = param->pvn.u.isname.name.n;
+
@@ -3406,7 +3720,7 @@ index 0000000..de296b4
+ &msg->first_line.u.reply.status);
+ break;
+ case 2: // reason
-+ xval = pvh_xavp_get_value(msg, &xavp_name, &rhname, 0);
++ xval = pvh_xavp_get_value(msg, &xavp_name, &_hdr_reply_reason, 0);
+ return pv_get_strval(msg, param, res,
+ xval && xval->v.s.s ? &xval->v.s
+ : &msg->first_line.u.reply.reason);
@@ -3424,7 +3738,6 @@ index 0000000..de296b4
+ pv_elem_p pv_format = NULL;
+ int p_no = 0;
+ unsigned int code = 0;
-+ str rhname = {"@Reply-Reason", 13};
+ str fval;
+
+ p_no = param->pvn.u.isname.name.n;
@@ -3475,7 +3788,8 @@ index 0000000..de296b4
+ msg->first_line.u.reply.status.s[0] = code + '0';
+ break;
+ case 2: // reason
-+ if(pvh_set_xavp(msg, &xavp_name, &rhname, &fval, SR_XTYPE_STR, 0, 0)
++ if(pvh_set_xavp(msg, &xavp_name, &_hdr_reply_reason, &fval,
++ SR_XTYPE_STR, 0, 0)
+ < 0) {
+ LM_ERR("set reply: cannot set reply reason\n");
+ goto err;
@@ -3497,23 +3811,25 @@ index 0000000..de296b4
+}
diff --git a/src/modules/pv_headers/pvh_xavp.h b/src/modules/pv_headers/pvh_xavp.h
new file mode 100644
-index 0000000..1245a1a
+index 0000000..7d4aa30
--- /dev/null
+++ b/src/modules/pv_headers/pvh_xavp.h
-@@ -0,0 +1,64 @@
+@@ -0,0 +1,66 @@
+/*
-+ * PV Headers
++ * pv_headers
+ *
-+ * Copyright (C) 2018 Kirill Solomko
++ * Copyright (C)
++ * 2020 Victor Seva
++ * 2018 Kirill Solomko
+ *
-+ * This file is part of SIP Router, a free SIP server.
++ * This file is part of Kamailio, a free SIP server.
+ *
-+ * SIP Router is free software; you can redistribute it and/or modify
++ * 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
+ *
-+ * SIP Router is distributed in the hope that it will be useful,
++ * 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.
@@ -3527,41 +3843,41 @@ index 0000000..1245a1a
+#ifndef PV_XAVP_H
+#define PV_XAVP_H
+
-+#include "../../core/parser/parse_uri.h"
++#include "../../core/str.h"
+#include "../../core/xavp.h"
-+#include "../../core/pvar.h"
+
+#include "pv_headers.h"
+
-+sr_xavp_t *pvh_xavp_new_value(str *name, sr_xval_t *val);
-+int pvh_xavp_append_value(str *name, sr_xval_t *val, sr_xavp_t **start);
-+int pvh_xavp_set_value(str *name, sr_xval_t *val, int idx, sr_xavp_t **start);
-+sr_xval_t *pvh_xavp_get_value(
-+ struct sip_msg *msg, str *xname, str *name, int idx);
-+sr_xavp_t *pvh_xavp_get_child(struct sip_msg *msg, str *xname, str *name);
-+int pvh_xavp_is_null(sr_xavp_t *xavp);
-+void pvh_xavp_free_data(void *p, sr_xavp_sfree_f sfree);
-+int pvh_xavp_keys_count(sr_xavp_t **start);
-+void pvh_free_to_params(struct to_param *param, sr_xavp_sfree_f sfree);
++int pvh_reply_append(sr_xavp_t **start);
++
+int pvh_set_xavp(struct sip_msg *msg, str *xname, str *name, void *data,
+ sr_xtype_t type, int idx, int append);
+int pvh_free_xavp(str *xname);
-+int pvh_parse_header_name(pv_spec_p sp, str *hname);
++int pvh_xavp_is_null(sr_xavp_t *avp);
++int pvh_xavp_keys_count(sr_xavp_t **start);
++sr_xval_t *pvh_xavp_get_value(
++ struct sip_msg *msg, str *xname, str *name, int idx);
++sr_xavp_t *pvh_xavp_get_child(struct sip_msg *msg, str *xname, str *name);
+
++int pvh_get_branch_index(struct sip_msg *msg, int *br_idx);
++int pvh_get_branch_xname(struct sip_msg *msg, str *xname, str *dst);
++int pvh_clone_branch_xavp(struct sip_msg *msg, str *xname);
++
++int pvh_parse_header_name(pv_spec_p sp, str *hname);
+int pvh_get_header(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
+int pvh_set_header(
+ struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val);
-+int pvh_get_uri(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
++xavp_c_data_t *pvh_set_parsed(
++ struct sip_msg *msg, str *hname, str *cur, str *new);
++
+int pvh_set_uri(
+ struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val);
++int pvh_get_uri(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
+int pvh_merge_uri(struct sip_msg *msg, enum action_type type, str *cur,
+ str *new, xavp_c_data_t *c_data);
++
+int pvh_get_reply_sr(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
+int pvh_set_reply_sr(
+ struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val);
+
-+int pvh_get_branch_index(struct sip_msg *msg, int *br_idx);
-+int pvh_get_branch_xname(struct sip_msg *msg, str *xname, str *dst);
-+int pvh_clone_branch_xavp(struct sip_msg *msg, str *xname);
-+
+#endif /* PV_XAVP_H */
diff --git a/debian/patches/sipwise/pv_headers-full-rework.patch b/debian/patches/sipwise/pv_headers-full-rework.patch
deleted file mode 100644
index e26b207d9..000000000
--- a/debian/patches/sipwise/pv_headers-full-rework.patch
+++ /dev/null
@@ -1,2006 +0,0 @@
-From: Victor Seva
-Date: Wed, 29 Jan 2020 17:05:47 +0100
-Subject: pv_headers: full rework
-
----
- src/modules/pv_headers/README | 19 +-
- src/modules/pv_headers/doc/pv_headers_admin.xml | 2 +-
- src/modules/pv_headers/pv_headers.c | 408 ++++++++++++++++--------
- src/modules/pv_headers/pv_headers.h | 16 +-
- src/modules/pv_headers/pvh_func.c | 202 +++++-------
- src/modules/pv_headers/pvh_func.h | 18 +-
- src/modules/pv_headers/pvh_hash.c | 12 +-
- src/modules/pv_headers/pvh_hash.h | 12 +-
- src/modules/pv_headers/pvh_hdr.c | 74 ++++-
- src/modules/pv_headers/pvh_hdr.h | 18 +-
- src/modules/pv_headers/pvh_str.c | 12 +-
- src/modules/pv_headers/pvh_str.h | 12 +-
- src/modules/pv_headers/pvh_xavp.c | 306 ++++++++++--------
- src/modules/pv_headers/pvh_xavp.h | 47 ++-
- 14 files changed, 711 insertions(+), 447 deletions(-)
-
-diff --git a/src/modules/pv_headers/README b/src/modules/pv_headers/README
-index b99cc42..1967529 100644
---- a/src/modules/pv_headers/README
-+++ b/src/modules/pv_headers/README
-@@ -42,7 +42,7 @@ Victor Seva
- 4.3. pvh_reset_headers()
- 4.4. pvh_check_header(hname)
- 4.5. pvh_append_header(hname, hvalue)
-- 4.6. pvh_modify_header(hname, [idx], hvalue)
-+ 4.6. pvh_modify_header(hname, hvalue, [idx])
- 4.7. pvh_remove_header(hname, [idx])
-
- 5. Exported Variables
-@@ -84,7 +84,7 @@ Chapter 1. Admin Guide
- 4.3. pvh_reset_headers()
- 4.4. pvh_check_header(hname)
- 4.5. pvh_append_header(hname, hvalue)
-- 4.6. pvh_modify_header(hname, [idx], hvalue)
-+ 4.6. pvh_modify_header(hname, hvalue, [idx])
- 4.7. pvh_remove_header(hname, [idx])
-
- 5. Exported Variables
-@@ -140,7 +140,8 @@ modparam("pv_headers", "xavp_name", "pvh")
-
- 3.2. header_value_size (int)
-
-- ??????.
-+ Defines an internal maximum SIP header value size. Header values longer
-+ than this setting will be stripped down when collected or applied.
-
- Default value is 1024.
-
-@@ -151,7 +152,9 @@ modparam("pv_headers", "header_value_size", 512)
-
- 3.3. header_collect_flag (int)
-
-- ??????.
-+ Used to mark that headers are collected for the SIP message, leading to
-+ subsequent headers collection on this message to be declined with an
-+ error. Should be used only in branches and replies.
-
- Default value is 27.
-
-@@ -162,7 +165,9 @@ modparam("pv_headers", "header_collect_flag", 37)
-
- 3.4. header_apply_flag (int)
-
-- ??????.
-+ Used to mark that headers are applied for the SIP message, leading to
-+ subsequent headers applies on this message to be declined with an
-+ error. Should be used only in branches and replies.
-
- Default value is 28.
-
-@@ -233,7 +238,7 @@ modparam("pvh", "auto_msg", 1)
- 4.3. pvh_reset_headers()
- 4.4. pvh_check_header(hname)
- 4.5. pvh_append_header(hname, hvalue)
-- 4.6. pvh_modify_header(hname, [idx], hvalue)
-+ 4.6. pvh_modify_header(hname, hvalue, [idx])
- 4.7. pvh_remove_header(hname, [idx])
-
- \
-@@ -288,7 +293,7 @@ modparam("pvh", "auto_msg", 1)
- This function can be used from ANY_ROUTE but only after
- pvh_collect_headers() or with "auto_msg" parameter enabled.
-
--4.6. pvh_modify_header(hname, [idx], hvalue)
-+4.6. pvh_modify_header(hname, hvalue, [idx])
-
- Modifies an existing header in the XAVP "hname" with the value "hvalue"
- into the XAVP. Index order is top to bottom. Please note that
-diff --git a/src/modules/pv_headers/doc/pv_headers_admin.xml b/src/modules/pv_headers/doc/pv_headers_admin.xml
-index 9c5c009..44e84f2 100644
---- a/src/modules/pv_headers/doc/pv_headers_admin.xml
-+++ b/src/modules/pv_headers/doc/pv_headers_admin.xml
-@@ -64,7 +64,7 @@
-
-
-
--
-+
-
- Exported Variables
-
-diff --git a/src/modules/pv_headers/pv_headers.c b/src/modules/pv_headers/pv_headers.c
-index 9730847..84ac0c1 100644
---- a/src/modules/pv_headers/pv_headers.c
-+++ b/src/modules/pv_headers/pv_headers.c
-@@ -1,16 +1,18 @@
- /*
- * pv_headers
- *
-- * Copyright (C) 2018 Kirill Solomko
-+ * Copyright (C)
-+ * 2020 Victor Seva
-+ * 2018 Kirill Solomko
- *
-- * This file is part of SIP Router, a free SIP server.
-+ * This file is part of Kamailio, a free SIP server.
- *
-- * SIP Router is free software; you can redistribute it and/or modify
-+ * 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
- *
-- * SIP Router is distributed in the hope that it will be useful,
-+ * 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.
-@@ -22,76 +24,99 @@
- */
-
- #include "../../core/sr_module.h"
--#include "../../core/mod_fix.h"
- #include "../../core/script_cb.h"
-+#include "../../core/mod_fix.h"
- #include "../../modules/tm/tm_load.h"
- #include "../../core/kemi.h"
-
- #include "pv_headers.h"
- #include "pvh_func.h"
--#include "pvh_xavp.h"
- #include "pvh_hash.h"
-+#include "pvh_xavp.h"
-
- MODULE_VERSION
-
- #define MODULE_NAME "pv_headers"
--
- #define XAVP_NAME "headers"
-
--#define FL_NAME_PV_HDRS_COLLECTED "pv_headers_collected"
--#define FL_NAME_PV_HDRS_APPLIED "pv_headers_applied"
--
--int FL_PV_HDRS_COLLECTED = 27;
--int FL_PV_HDRS_APPLIED = 28;
--
- uac_api_t uac;
- static tm_api_t tmb;
-
- str xavp_name = str_init(XAVP_NAME);
--
-+str xavp_helper_xname = str_init("modparam_pv_headers");
- str xavp_parsed_xname = str_init("parsed_pv_headers");
-+unsigned int header_name_size = 255;
-+unsigned int header_value_size = 1024;
-+int FL_PV_HDRS_COLLECTED = 27;
-+int FL_PV_HDRS_APPLIED = 28;
- static str skip_headers_param =
- str_init("Record-Route,Via,Route,Content-Length,Max-Forwards,CSeq");
- static str split_headers_param = STR_NULL;
--static int auto_msg_param = 1;
--
- static str single_headers_param = str_init("");
-+static int auto_msg_param = 1;
-
- str _hdr_from = {"From", 4};
- str _hdr_to = {"To", 2};
--
--unsigned int header_name_size = 255;
--unsigned int header_value_size = 1024;
--
-+str _hdr_reply_reason = {"@Reply-Reason", 13};
-+int _branch = T_BR_UNDEFINED;
-+int _reply_counter = -1;
-
- static void mod_destroy(void);
- static int mod_init(void);
-
- static void handle_tm_t(tm_cell_t *t, int type, struct tmcb_params *params);
- static int handle_msg_cb(struct sip_msg *msg, unsigned int flags, void *cb);
-+static int handle_msg_branch_cb(
-+ struct sip_msg *msg, unsigned int flags, void *cb);
-+static int handle_msg_reply_cb(
-+ struct sip_msg *msg, unsigned int flags, void *cb);
-
- static int w_pvh_collect_headers(struct sip_msg *msg, char *p1, char *p2)
- {
-- return pvh_collect_headers(msg, 0);
-+ sr_xavp_t **backup_xavps = NULL;
-+
-+ if(pvh_get_branch_index(msg, &_branch) < 0)
-+ return -1;
-+ if(msg->first_line.type == SIP_REPLY) {
-+ if((_reply_counter = pvh_reply_append(backup_xavps)) < 0) {
-+ return -1;
-+ }
-+ }
-+ return pvh_collect_headers(msg);
- }
-
- static int ki_pvh_collect_headers(struct sip_msg *msg)
- {
-- return pvh_collect_headers(msg, 0);
-+ sr_xavp_t **backup_xavps = NULL;
-+
-+ if(pvh_get_branch_index(msg, &_branch) < 0)
-+ return -1;
-+ if(msg->first_line.type == SIP_REPLY) {
-+ if((_reply_counter = pvh_reply_append(backup_xavps)) < 0) {
-+ return -1;
-+ }
-+ }
-+ return pvh_collect_headers(msg);
- }
-
- static int w_pvh_apply_headers(struct sip_msg *msg, char *p1, char *p2)
- {
-- return pvh_apply_headers(msg, 0);
-+ if(pvh_get_branch_index(msg, &_branch) < 0)
-+ return -1;
-+ return pvh_apply_headers(msg);
- }
-
- static int ki_pvh_apply_headers(struct sip_msg *msg)
- {
-- return pvh_apply_headers(msg, 0);
-+ if(pvh_get_branch_index(msg, &_branch) < 0)
-+ return -1;
-+ return pvh_apply_headers(msg);
- }
-
- static int w_pvh_reset_headers(struct sip_msg *msg, char *p1, char *p2)
- {
-+ if(pvh_get_branch_index(msg, &_branch) < 0)
-+ return -1;
- return pvh_reset_headers(msg);
- }
-
-@@ -151,79 +176,83 @@ static int w_pvh_remove_header(
- return pvh_remove_header(msg, &hname, indx);
- }
-
--/*
-- * Exported functions
-- */
-+/* clang-format off */
- static cmd_export_t cmds[] = {
-- {"pvh_collect_headers", (cmd_function)w_pvh_collect_headers, 0, 0, 0,
-- ANY_ROUTE},
-- {"pvh_apply_headers", (cmd_function)w_pvh_apply_headers, 0, 0, 0,
-- ANY_ROUTE},
-- {"pvh_reset_headers", (cmd_function)w_pvh_reset_headers, 0, 0, 0,
-- ANY_ROUTE},
-- {"pvh_check_header", (cmd_function)w_pvh_check_header, 1,
-- fixup_spve_null, fixup_free_spve_null, ANY_ROUTE},
-- {"pvh_append_header", (cmd_function)w_pvh_append_header, 2,
-- fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE},
-- {"pvh_modify_header", (cmd_function)w_pvh_modify_header, 2,
-- fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE},
-- {"pvh_modify_header", (cmd_function)w_pvh_modify_header, 3,
-- fixup_spve_all, fixup_free_spve_all, ANY_ROUTE},
-- {"pvh_remove_header", (cmd_function)w_pvh_remove_header, 1,
-- fixup_spve_null, fixup_free_spve_null, ANY_ROUTE},
-- {"pvh_remove_header", (cmd_function)w_pvh_remove_header, 2,
-- fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE},
-- {0, 0, 0, 0, 0, 0}};
-+ {"pvh_collect_headers", (cmd_function)w_pvh_collect_headers, 0, 0, 0,
-+ ANY_ROUTE},
-+ {"pvh_apply_headers", (cmd_function)w_pvh_apply_headers, 0, 0, 0,
-+ ANY_ROUTE},
-+ {"pvh_reset_headers", (cmd_function)w_pvh_reset_headers, 0, 0, 0,
-+ ANY_ROUTE},
-+ {"pvh_check_header", (cmd_function)w_pvh_check_header, 1,
-+ fixup_spve_null, fixup_free_spve_null, ANY_ROUTE},
-+ {"pvh_append_header", (cmd_function)w_pvh_append_header, 2,
-+ fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE},
-+ {"pvh_modify_header", (cmd_function)w_pvh_modify_header, 2,
-+ fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE},
-+ {"pvh_modify_header", (cmd_function)w_pvh_modify_header, 3,
-+ fixup_spve_all, fixup_free_spve_all, ANY_ROUTE},
-+ {"pvh_remove_header", (cmd_function)w_pvh_remove_header, 1,
-+ fixup_spve_null, fixup_free_spve_null, ANY_ROUTE},
-+ {"pvh_remove_header", (cmd_function)w_pvh_remove_header, 2,
-+ fixup_spve_spve, fixup_free_spve_spve, ANY_ROUTE},
-+ {0, 0, 0, 0, 0, 0}
-+};
-
- static pv_export_t mod_pvs[] = {
-- {{"x_hdr", (sizeof("x_hdr") - 1)}, PVT_OTHER, pvh_get_header,
-- pvh_set_header, pvh_parse_header_name, pv_parse_index, 0, 0},
-- {{"x_fu", (sizeof("x_fu") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
-- 0, pv_init_iname, 1},
-- {{"x_fU", (sizeof("x_fU") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
-- 0, pv_init_iname, 2},
-- {{"x_fd", (sizeof("x_fd") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
-- 0, pv_init_iname, 3},
-- {{"x_fn", (sizeof("x_fn") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
-- 0, pv_init_iname, 4},
-- {{"x_ft", (sizeof("x_ft") - 1)}, PVT_OTHER, pvh_get_uri, /* ro */ 0, 0,
-- 0, pv_init_iname, 5},
-- {{"x_tu", (sizeof("x_tu") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
-- 0, pv_init_iname, 6},
-- {{"x_tU", (sizeof("x_tU") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
-- 0, pv_init_iname, 7},
-- {{"x_td", (sizeof("x_td") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
-- 0, pv_init_iname, 8},
-- {{"x_tn", (sizeof("x_tn") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
-- 0, pv_init_iname, 9},
-- {{"x_tt", (sizeof("x_tt") - 1)}, PVT_OTHER, pvh_get_uri, /* ro */ 0, 0,
-- 0, pv_init_iname, 10},
-- {{"x_rs", (sizeof("x_rs") - 1)}, PVT_OTHER, pvh_get_reply_sr,
-- pvh_set_reply_sr, 0, 0, pv_init_iname, 1},
-- {{"x_rr", (sizeof("x_rr") - 1)}, PVT_OTHER, pvh_get_reply_sr,
-- pvh_set_reply_sr, 0, 0, pv_init_iname, 2},
-- {{0, 0}, 0, 0, 0, 0, 0, 0, 0}};
--
--static param_export_t params[] = {{"xavp_name", PARAM_STR, &xavp_name},
-- {"header_value_size", PARAM_INT, &header_value_size},
-- {"header_collect_flag", PARAM_INT, &FL_PV_HDRS_COLLECTED},
-- {"header_apply_flag", PARAM_INT, &FL_PV_HDRS_APPLIED},
-- {"skip_headers", PARAM_STR, &skip_headers_param},
-- {"split_headers", PARAM_STR, &split_headers_param},
-- {"auto_msg", PARAM_INT, &auto_msg_param}, {0, 0, 0}};
-+ {{"x_hdr", (sizeof("x_hdr") - 1)}, PVT_OTHER, pvh_get_header,
-+ pvh_set_header, pvh_parse_header_name, pv_parse_index, 0, 0},
-+ {{"x_fu", (sizeof("x_fu") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
-+ 0, pv_init_iname, 1},
-+ {{"x_fU", (sizeof("x_fU") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
-+ 0, pv_init_iname, 2},
-+ {{"x_fd", (sizeof("x_fd") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
-+ 0, pv_init_iname, 3},
-+ {{"x_fn", (sizeof("x_fn") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
-+ 0, pv_init_iname, 4},
-+ {{"x_ft", (sizeof("x_ft") - 1)}, PVT_OTHER, pvh_get_uri, /* ro */ 0, 0,
-+ 0, pv_init_iname, 5},
-+ {{"x_tu", (sizeof("x_tu") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
-+ 0, pv_init_iname, 6},
-+ {{"x_tU", (sizeof("x_tU") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
-+ 0, pv_init_iname, 7},
-+ {{"x_td", (sizeof("x_td") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
-+ 0, pv_init_iname, 8},
-+ {{"x_tn", (sizeof("x_tn") - 1)}, PVT_OTHER, pvh_get_uri, pvh_set_uri, 0,
-+ 0, pv_init_iname, 9},
-+ {{"x_tt", (sizeof("x_tt") - 1)}, PVT_OTHER, pvh_get_uri, /* ro */ 0, 0,
-+ 0, pv_init_iname, 10},
-+ {{"x_rs", (sizeof("x_rs") - 1)}, PVT_OTHER, pvh_get_reply_sr,
-+ pvh_set_reply_sr, 0, 0, pv_init_iname, 1},
-+ {{"x_rr", (sizeof("x_rr") - 1)}, PVT_OTHER, pvh_get_reply_sr,
-+ pvh_set_reply_sr, 0, 0, pv_init_iname, 2},
-+ {{0, 0}, 0, 0, 0, 0, 0, 0, 0}
-+};
-+
-+static param_export_t params[] = {
-+ {"xavp_name", PARAM_STR, &xavp_name},
-+ {"header_value_size", PARAM_INT, &header_value_size},
-+ {"header_collect_flag", PARAM_INT, &FL_PV_HDRS_COLLECTED},
-+ {"header_apply_flag", PARAM_INT, &FL_PV_HDRS_APPLIED},
-+ {"skip_headers", PARAM_STR, &skip_headers_param},
-+ {"split_headers", PARAM_STR, &split_headers_param},
-+ {"auto_msg", PARAM_INT, &auto_msg_param},
-+ {0, 0, 0}
-+};
-
- struct module_exports exports = {
-- MODULE_NAME, /* module name */
-- DEFAULT_DLFLAGS, /* dlopen flags */
-- cmds, /* exported functions */
-- params, /* exported parameters */
-- 0, /* RPC method exports */
-- mod_pvs, /* exported pseudo-variables */
-- 0, /* response handling function */
-- mod_init, /* module initialization function */
-- 0, /* per-child init function */
-- mod_destroy /* module destroy function */
-+ MODULE_NAME, /* module name */
-+ DEFAULT_DLFLAGS, /* dlopen flags */
-+ cmds, /* exported functions */
-+ params, /* exported parameters */
-+ 0, /* RPC method exports */
-+ mod_pvs, /* exported pseudo-variables */
-+ 0, /* response handling function */
-+ mod_init, /* module initialization function */
-+ 0, /* per-child init function */
-+ mod_destroy /* module destroy function */
- };
-+/* clang-format on */
-
- int mod_init(void)
- {
-@@ -238,19 +267,25 @@ int mod_init(void)
- LM_NOTICE("could not bind to the 'tm' module, automatic headers "
- "collect/apply is disabled\n");
- auto_msg_param = 0;
-- } else {
-- if(auto_msg_param
-- && register_script_cb(
-- handle_msg_cb, PRE_SCRIPT_CB | REQUEST_CB, 0)
-- < 0) {
-- LM_ERR("cannot register PRE_SCRIPT_CB callbacks\n");
-+ }
-+ if(auto_msg_param) {
-+ if(register_script_cb(handle_msg_cb, PRE_SCRIPT_CB | REQUEST_CB, 0)
-+ < 0) {
-+ LM_ERR("cannot register PRE_SCRIPT_CB REQUEST_CB callbacks\n");
-+ return -1;
-+ }
-+ if(register_script_cb(
-+ handle_msg_branch_cb, PRE_SCRIPT_CB | BRANCH_CB, 0)
-+ < 0) {
-+ LM_ERR("cannot register PRE_SCRIPT_CB BRANCH_CB callbacks\n");
-+ return -1;
-+ }
-+ if(register_script_cb(
-+ handle_msg_reply_cb, PRE_SCRIPT_CB | ONREPLY_CB, 0)
-+ < 0) {
-+ LM_ERR("cannot register PRE_SCRIPT_CB ONREPLY_CB callbacks\n");
- return -1;
- }
-- }
--
-- if(header_value_size == 0) {
-- LM_ERR("header_value_size must be >=0\n");
-- return -1;
- }
-
- pvh_str_hash_init(&skip_headers, &skip_headers_param, "skip_headers");
-@@ -262,25 +297,81 @@ int mod_init(void)
-
- void mod_destroy(void)
- {
-- pvh_str_hash_free(&skip_headers);
-- pvh_str_hash_free(&split_headers);
-- pvh_str_hash_free(&single_headers);
-- pvh_free_xavp(&xavp_name);
-- pvh_free_xavp(&xavp_parsed_xname);
- LM_INFO("%s module unload...\n", MODULE_NAME);
- }
-
-+/* just for debug */
-+static inline char *tm_type_to_string(int type)
-+{
-+ switch(type) {
-+ case TMCB_REQUEST_IN:
-+ return "TMCB_REQUEST_IN";
-+ case TMCB_RESPONSE_IN:
-+ return "TMCB_RESPONSE_IN";
-+ case TMCB_E2EACK_IN:
-+ return "TMCB_E2EACK_IN";
-+ case TMCB_REQUEST_PENDING:
-+ return "TMCB_REQUEST_PENDING";
-+ case TMCB_REQUEST_FWDED:
-+ return "TMCB_REQUEST_FWDED";
-+ case TMCB_RESPONSE_FWDED:
-+ return "TMCB_RESPONSE_FWDED";
-+ case TMCB_ON_FAILURE_RO:
-+ return "TMCB_ON_FAILURE_RO";
-+ case TMCB_ON_FAILURE:
-+ return "TMCB_ON_FAILURE";
-+ case TMCB_REQUEST_OUT:
-+ return "TMCB_REQUEST_OUT";
-+ case TMCB_RESPONSE_OUT:
-+ return "TMCB_RESPONSE_OUT";
-+ case TMCB_LOCAL_COMPLETED:
-+ return "TMCB_LOCAL_COMPLETED";
-+ case TMCB_LOCAL_RESPONSE_OUT:
-+ return "TMCB_LOCAL_RESPONSE_OUT";
-+ case TMCB_ACK_NEG_IN:
-+ return "TMCB_ACK_NEG_IN";
-+ case TMCB_REQ_RETR_IN:
-+ return "TMCB_REQ_RETR_IN";
-+ case TMCB_LOCAL_RESPONSE_IN:
-+ return "TMCB_LOCAL_RESPONSE_IN";
-+ case TMCB_LOCAL_REQUEST_IN:
-+ return "TMCB_LOCAL_REQUEST_IN";
-+ case TMCB_DLG:
-+ return "TMCB_DLG";
-+ case TMCB_DESTROY:
-+ return "TMCB_DESTROY";
-+ case TMCB_E2ECANCEL_IN:
-+ return "TMCB_E2ECANCEL_IN";
-+ case TMCB_E2EACK_RETR_IN:
-+ return "TMCB_E2EACK_RETR_IN";
-+ case TMCB_RESPONSE_READY:
-+ return "TMCB_RESPONSE_READY";
-+ case TMCB_DONT_ACK:
-+ return "TMCB_DONT_ACK";
-+ case TMCB_REQUEST_SENT:
-+ return "TMCB_REQUEST_SENT";
-+ case TMCB_RESPONSE_SENT:
-+ return "TMCB_RESPONSE_SENT";
-+ case TMCB_ON_BRANCH_FAILURE:
-+ return "TMCB_ON_BRANCH_FAILURE";
-+ case TMCB_ON_BRANCH_FAILURE_RO:
-+ return "TMCB_ON_BRANCH_FAILURE_RO";
-+ case TMCB_MAX:
-+ return "TMCB_MAX";
-+ }
-+
-+ return "UNKNOWN";
-+}
-+
- void handle_tm_t(tm_cell_t *t, int type, struct tmcb_params *params)
- {
- struct sip_msg *msg = NULL;
-
-- if(type & TMCB_RESPONSE_IN) {
-- msg = params->rpl;
-- if(msg != NULL && msg != FAKED_REPLY) {
-- pvh_reset_headers(msg);
-- pvh_collect_headers(msg, 1);
-- }
-- } else if(type & TMCB_REQUEST_FWDED) {
-+ LM_DBG("T:%p params->branch:%d type:%s\n", t, params->branch,
-+ tm_type_to_string(type));
-+
-+
-+ if(type & TMCB_REQUEST_FWDED) {
- msg = params->req;
- } else if(type & (TMCB_ON_BRANCH_FAILURE | TMCB_RESPONSE_FWDED)) {
- msg = params->rpl;
-@@ -289,26 +380,93 @@ void handle_tm_t(tm_cell_t *t, int type, struct tmcb_params *params)
- return;
- }
-
-- if(msg != NULL && msg != FAKED_REPLY)
-- pvh_apply_headers(msg, 1);
-
-+ LM_DBG("T:%p picked_branch:%d label:%d branches:%d\n", t,
-+ tmb.t_get_picked_branch(), t->label, t->nr_of_outgoings);
-+
-+ if(msg != NULL && msg != FAKED_REPLY) {
-+ pvh_get_branch_index(msg, &_branch);
-+ LM_DBG("T:%p set branch:%d\n", t, _branch);
-+ pvh_apply_headers(msg);
-+ }
- return;
- }
-
-+static int msg_cbs =
-+ TMCB_REQUEST_FWDED | TMCB_RESPONSE_FWDED | TMCB_ON_BRANCH_FAILURE;
-+
- int handle_msg_cb(struct sip_msg *msg, unsigned int flags, void *cb)
- {
-- int cbs = TMCB_REQUEST_FWDED | TMCB_RESPONSE_FWDED | TMCB_RESPONSE_IN
-- | TMCB_ON_BRANCH_FAILURE;
-+ if(pvh_parse_msg(msg) != 0)
-+ return 1;
-
-- if(flags & (PRE_SCRIPT_CB | REQUEST_CB)) {
-- if(tmb.register_tmcb(msg, 0, cbs, handle_tm_t, 0, 0) <= 0) {
-- LM_ERR("cannot register TM callbacks\n");
-- return -1;
-- }
-- pvh_collect_headers(msg, 1);
-+ if(tmb.register_tmcb(msg, 0, msg_cbs, handle_tm_t, 0, 0) <= 0) {
-+ LM_ERR("cannot register TM callbacks\n");
-+ return -1;
-+ }
-+
-+ _branch = 0;
-+ LM_DBG("msg:%p set branch:%d\n", msg, _branch);
-+ pvh_collect_headers(msg);
-+ return 1;
-+}
-+
-+int handle_msg_branch_cb(struct sip_msg *msg, unsigned int flags, void *cb)
-+{
-+
-+ LM_DBG("msg:%p previous branch:%d\n", msg, _branch);
-+
-+ if(flags & PRE_SCRIPT_CB) {
-+ pvh_get_branch_index(msg, &_branch);
-+ LM_DBG("msg:%p set branch:%d\n", msg, _branch);
-+ pvh_clone_branch_xavp(msg, &xavp_name);
-+ }
-+
-+ return 1;
-+}
-+
-+int handle_msg_reply_cb(struct sip_msg *msg, unsigned int flags, void *cb)
-+{
-+ tm_cell_t *t = NULL;
-+ sr_xavp_t **backup_xavps = NULL;
-+ sr_xavp_t **list = NULL;
-+
-+ if(pvh_parse_msg(msg) != 0)
-+ return 1;
-+ LM_DBG("msg:%p previous branch:%d\n", msg, _branch);
-+
-+ if(tmb.t_check(msg, &_branch) == -1) {
-+ LM_ERR("failed find UAC branch\n");
- } else {
-- LM_ERR("unknown callback: %d\n", flags);
-+ t = tmb.t_gett();
-+ if(t == NULL || t == T_UNDEFINED) {
-+ LM_DBG("cannot lookup the transaction\n");
-+ } else {
-+ LM_DBG("T:%p t_check-branch:%d xavp_list:%p branches:%d\n", t,
-+ _branch, &t->xavps_list, t->nr_of_outgoings);
-+ list = &t->xavps_list;
-+ backup_xavps = xavp_set_list(&t->xavps_list);
-+ }
-+ }
-+
-+ pvh_get_branch_index(msg, &_branch);
-+ LM_DBG("T:%p set branch:%d picked_branch:%d\n", t, _branch,
-+ tmb.t_get_picked_branch());
-+
-+ if((_reply_counter = pvh_reply_append(list)) < 0) {
-+ return -1;
-+ }
-+ pvh_collect_headers(msg);
-+ if(backup_xavps) {
-+ xavp_set_list(backup_xavps);
-+ LM_DBG("restored backup_xavps:%p\n", *backup_xavps);
-+ }
-+ if(t) {
-+ tmb.unref_cell(t);
-+ LM_DBG("T:%p unref\n", t);
- }
-+ tmb.t_sett(T_UNDEFINED, T_BR_UNDEFINED);
-+ LM_DBG("reset tm\n");
-
- return 1;
- }
-diff --git a/src/modules/pv_headers/pv_headers.h b/src/modules/pv_headers/pv_headers.h
-index 556b7bf..4d53318 100644
---- a/src/modules/pv_headers/pv_headers.h
-+++ b/src/modules/pv_headers/pv_headers.h
-@@ -1,16 +1,18 @@
- /*
-- * PV Headers
-+ * pv_headers
- *
-- * Copyright (C) 2018 Kirill Solomko
-+ * Copyright (C)
-+ * 2020 Victor Seva
-+ * 2018 Kirill Solomko
- *
-- * This file is part of SIP Router, a free SIP server.
-+ * This file is part of Kamailio, a free SIP server.
- *
-- * SIP Router is free software; you can redistribute it and/or modify
-+ * 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
- *
-- * SIP Router is distributed in the hope that it will be useful,
-+ * 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.
-@@ -38,12 +40,16 @@ extern uac_api_t uac;
-
- extern str xavp_name;
- extern str xavp_parsed_xname;
-+extern str xavp_helper_xname;
-
- extern unsigned int header_name_size;
- extern unsigned int header_value_size;
-
- extern str _hdr_from;
- extern str _hdr_to;
-+extern str _hdr_reply_reason;
-+extern int _branch;
-+extern int _reply_counter;
-
- extern int FL_PV_HDRS_COLLECTED;
- extern int FL_PV_HDRS_APPLIED;
-diff --git a/src/modules/pv_headers/pvh_func.c b/src/modules/pv_headers/pvh_func.c
-index 88a6497..b3749a6 100644
---- a/src/modules/pv_headers/pvh_func.c
-+++ b/src/modules/pv_headers/pvh_func.c
-@@ -1,16 +1,18 @@
- /*
- * pv_headers
- *
-- * Copyright (C) 2018 Kirill Solomko
-+ * Copyright (C)
-+ * 2020 Victor Seva
-+ * 2018 Kirill Solomko
- *
-- * This file is part of SIP Router, a free SIP server.
-+ * This file is part of Kamailio, a free SIP server.
- *
-- * SIP Router is free software; you can redistribute it and/or modify
-+ * 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
- *
-- * SIP Router is distributed in the hope that it will be useful,
-+ * 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.
-@@ -21,18 +23,38 @@
- *
- */
-
--#include "../../core/dset.h"
-+#include "../../core/strutils.h"
-
- #include "pv_headers.h"
-+#include "pvh_func.h"
-+#include "pvh_xavp.h"
- #include "pvh_str.h"
--#include "pvh_hdr.h"
- #include "pvh_hash.h"
--#include "pvh_xavp.h"
-+#include "pvh_hdr.h"
-
--static str xavp_helper_xname = str_init("modparam_pv_headers");
- static str xavp_helper_name = str_init("xavp_name");
-
--int pvh_collect_headers(struct sip_msg *msg, int is_auto)
-+int pvh_parse_msg(sip_msg_t *msg)
-+{
-+ if(msg->first_line.type == SIP_REQUEST) {
-+ if(!IS_SIP(msg)) {
-+ LM_DBG("non SIP request message\n");
-+ return 1;
-+ }
-+ } else if(msg->first_line.type == SIP_REPLY) {
-+ if(!IS_SIP_REPLY(msg)) {
-+ LM_DBG("non SIP reply message\n");
-+ return 1;
-+ }
-+ } else {
-+ LM_DBG("non SIP message\n");
-+ return 1;
-+ }
-+
-+ return 0;
-+}
-+
-+int pvh_collect_headers(struct sip_msg *msg)
- {
- struct hdr_field *hf = NULL;
- str name = STR_NULL;
-@@ -40,22 +62,10 @@ int pvh_collect_headers(struct sip_msg *msg, int is_auto)
- char hvals[header_name_size][header_value_size];
- int idx = 0, d_size = 0;
- str val_part = STR_NULL;
-- int br_idx;
--
-- pvh_get_branch_index(msg, &br_idx);
-- LM_DBG("br_idx: %d\n", br_idx);
-- if(!is_auto) {
-- if(msg->first_line.type == SIP_REPLY) {
-- if(isflagset(msg, FL_PV_HDRS_COLLECTED) == 1) {
-- LM_ERR("headers are already collected\n");
-- return -1;
-- }
-- } else {
-- if(isbflagset(br_idx, FL_PV_HDRS_COLLECTED) == 1) {
-- LM_ERR("headers are already collected\n");
-- return -1;
-- }
-- }
-+
-+ if(pvh_hdrs_collected(msg)) {
-+ LM_ERR("headers are already collected\n");
-+ return -1;
- }
-
- if(parse_headers(msg, HDR_EOH_F, 0) < 0) {
-@@ -63,38 +73,35 @@ int pvh_collect_headers(struct sip_msg *msg, int is_auto)
- return -1;
- }
-
-- if(pvh_str_new(&name, header_name_size) < 0)
-- goto err;
-- if(pvh_str_new(&val, header_value_size) < 0)
-- goto err;
--
-- if(name.s == NULL || val.s == NULL)
-- goto err;
--
- for(hf = msg->headers; hf; hf = hf->next) {
- LM_DBG("collect header[%.*s]: %.*s\n", hf->name.len, hf->name.s,
- hf->body.len, hf->body.s);
-
- switch(hf->type) {
- case HDR_FROM_T:
-- pvh_str_copy(&name, &_hdr_from, header_name_size);
-+ name.len = _hdr_from.len;
-+ name.s = _hdr_from.s;
- LM_DBG("force [From] as key\n");
- break;
- case HDR_TO_T:
-- pvh_str_copy(&name, &_hdr_to, header_name_size);
-+ name.len = _hdr_to.len;
-+ name.s = _hdr_to.s;
- LM_DBG("force [To] as key\n");
- break;
- default:
-- pvh_str_copy(&name, &hf->name, header_name_size);
-+ name.len = hf->name.len;
-+ name.s = hf->name.s;
- }
-- pvh_str_copy(&val, &hf->body, header_value_size);
-+ val.len = hf->body.len;
-+ val.s = hf->body.s;
-
-- if(str_hash_get(&split_headers, name.s, name.len)
-- && strchr(val.s, ',') != NULL) {
-+ if(strchr(val.s, ',') != NULL
-+ && str_hash_get(&split_headers, name.s, name.len)) {
-
- if(pvh_split_values(&val, hvals, &d_size, 1) < 0) {
-- LM_ERR("could not parse Diversion header comma separated "
-- "value");
-+ LM_ERR("could not parse %.*s header comma separated "
-+ "value",
-+ name.len, name.s);
- return -1;
- }
-
-@@ -104,61 +111,43 @@ int pvh_collect_headers(struct sip_msg *msg, int is_auto)
- if(pvh_set_xavp(msg, &xavp_name, &name, &val_part, SR_XTYPE_STR,
- 0, 1)
- < 0)
-- goto err;
-+ return -1;
- }
- continue;
- }
- if(pvh_set_xavp(msg, &xavp_name, &name, &val, SR_XTYPE_STR, 0, 1) < 0)
-- goto err;
-+ return -1;
- }
-
- if(pvh_set_xavp(msg, &xavp_helper_xname, &xavp_helper_name, &xavp_name,
- SR_XTYPE_STR, 0, 0)
- < 0)
-- goto err;
--
-- pvh_str_free(&name);
-- pvh_str_free(&val);
-+ return -1;
-
-- msg->first_line.type == SIP_REPLY ? setflag(msg, FL_PV_HDRS_COLLECTED)
-- : setbflag(br_idx, FL_PV_HDRS_COLLECTED);
-+ pvh_hdrs_set_collected(msg);
-
- return 1;
--
--err:
-- pvh_str_free(&name);
-- pvh_str_free(&val);
-- return -1;
- }
-
--int pvh_apply_headers(struct sip_msg *msg, int is_auto)
-+int pvh_apply_headers(struct sip_msg *msg)
- {
- sr_xavp_t *xavp = NULL;
- sr_xavp_t *sub = NULL;
-- str display = STR_NULL;
-- str uri = STR_NULL;
- struct str_hash_table rm_hdrs;
- int from_cnt = 0, to_cnt = 0;
-- int skip_from_to = 0;
-- int br_idx, keys_count;
-+ char t[header_name_size];
-+ char tv[2][header_value_size];
-+ str display = {tv[0], header_value_size};
-+ str uri = {tv[1], header_value_size};
-+ str br_xname = {t, header_name_size};
-+ int skip_from_to = 0, keys_count = 0;
- int res = -1;
-
-- rm_hdrs.size = 0;
--
-- pvh_get_branch_index(msg, &br_idx);
-+ memset(&rm_hdrs, 0, sizeof(struct str_hash_table));
-
-- if(!is_auto) {
-- if(msg->first_line.type == SIP_REPLY) {
-- if(isflagset(msg, FL_PV_HDRS_APPLIED) == 1) {
-- LM_ERR("headers are already applied\n");
-- return -1;
-- }
-- } else {
-- if(isbflagset(br_idx, FL_PV_HDRS_APPLIED) == 1) {
-- LM_ERR("headers are already applied\n");
-- return -1;
-- }
-- }
-+ if(pvh_hdrs_applied(msg)) {
-+ LM_ERR("headers are already applied\n");
-+ return -1;
- }
-
- if(parse_headers(msg, HDR_EOH_F, 0) < 0) {
-@@ -166,28 +155,30 @@ int pvh_apply_headers(struct sip_msg *msg, int is_auto)
- return -1;
- }
-
-- if(pvh_str_new(&display, header_value_size) < 0)
-- goto err;
-- if(pvh_str_new(&uri, header_value_size) < 0)
-- goto err;
-+ pvh_get_branch_xname(msg, &xavp_name, &br_xname);
-
-- if((xavp = pvh_xavp_get(msg, &xavp_name)) == NULL) {
-- LM_ERR("missing xavp %.*s, run pv_collect_headers() first\n",
-- xavp_name.len, xavp_name.s);
-- goto err;
-+ if((xavp = xavp_get(&br_xname, NULL)) == NULL
-+ && (xavp = xavp_get(&xavp_name, NULL)) == NULL) {
-+ LM_ERR("missing xavp %s, run pv_collect_headers() first\n",
-+ xavp_name.s);
-+ return -1;
-+ }
-+ if(xavp->val.type != SR_XTYPE_XAVP) {
-+ LM_ERR("not xavp child type %s\n", xavp_name.s);
-+ return -1;
- }
-
- if((sub = xavp->val.v.xavp) == NULL) {
- LM_ERR("invalid xavp structure: %s\n", xavp_name.s);
-- goto err;
-+ return -1;
- }
- keys_count = pvh_xavp_keys_count(&sub);
- if(str_hash_alloc(&rm_hdrs, keys_count) < 0) {
- PKG_MEM_ERROR;
-- goto err;
-+ return -1;
- }
-- LM_DBG("xavp->name:%.*s keys_count: %d\n", xavp->name.len, xavp->name.s,
-- keys_count);
-+ LM_DBG("xavp->name:%.*s br_xname:%.*s keys_count: %d\n", xavp->name.len,
-+ xavp->name.s, br_xname.len, br_xname.s, keys_count);
- str_hash_init(&rm_hdrs);
-
- if(msg->first_line.type == SIP_REPLY
-@@ -207,13 +198,12 @@ int pvh_apply_headers(struct sip_msg *msg, int is_auto)
- if(pvh_skip_header(&sub->name))
- continue;
-
-- if(strncasecmp(sub->name.s, _hdr_from.s, sub->name.len) == 0) {
-+ if(cmpi_str(&sub->name, &_hdr_from) == 0) {
- if(skip_from_to) {
- LM_DBG("skip From header change in reply messages\n");
- continue;
- }
-- if(strncmp(sub->val.v.s.s, msg->from->body.s, sub->val.v.s.len)
-- == 0) {
-+ if(cmp_str(&sub->val.v.s, &msg->from->body) == 0) {
- LM_DBG("skip unchanged From header\n");
- continue;
- }
-@@ -240,13 +230,12 @@ int pvh_apply_headers(struct sip_msg *msg, int is_auto)
- continue;
- }
-
-- if(strncasecmp(sub->name.s, _hdr_to.s, sub->name.len) == 0) {
-+ if(cmpi_str(&sub->name, &_hdr_to) == 0) {
- if(skip_from_to) {
- LM_DBG("skip To header change in reply messages\n");
- continue;
- }
-- if(strncmp(sub->val.v.s.s, msg->to->body.s, sub->val.v.s.len)
-- == 0) {
-+ if(cmp_str(&sub->val.v.s, &msg->to->body) == 0) {
- LM_DBG("skip unchanged To header\n");
- continue;
- }
-@@ -273,7 +262,7 @@ int pvh_apply_headers(struct sip_msg *msg, int is_auto)
- continue;
- }
-
-- if(strncasecmp(sub->name.s, "@Reply-Reason", sub->name.len) == 0) {
-+ if(cmpi_str(&sub->name, &_hdr_reply_reason) == 0) {
- if(str_hash_get(&rm_hdrs, sub->name.s, sub->name.len))
- continue;
- pvh_real_replace_reply_reason(msg, &sub->val.v.s);
-@@ -299,14 +288,11 @@ int pvh_apply_headers(struct sip_msg *msg, int is_auto)
- }
- } while((sub = sub->next) != NULL);
-
-- msg->first_line.type == SIP_REPLY ? setflag(msg, FL_PV_HDRS_APPLIED)
-- : setbflag(br_idx, FL_PV_HDRS_APPLIED);
-+ pvh_hdrs_set_applied(msg);
-
- res = 1;
-
- err:
-- pvh_str_free(&display);
-- pvh_str_free(&uri);
- if(rm_hdrs.size)
- pvh_str_hash_free(&rm_hdrs);
- return res;
-@@ -314,29 +300,17 @@ err:
-
- int pvh_reset_headers(struct sip_msg *msg)
- {
-- str br_xname = STR_NULL;
-- int br_idx;
-+ char t[header_name_size];
-+ str br_xname = {t, header_name_size};
-
-- if(pvh_str_new(&br_xname, header_name_size) < 0)
-- return -1;
--
-- pvh_get_branch_index(msg, &br_idx);
- pvh_get_branch_xname(msg, &xavp_name, &br_xname);
-- /* LM_DBG("clean xavp:%.*s\n", br_xname.len, br_xname.s); */
-+ LM_DBG("clean xavp:%.*s\n", br_xname.len, br_xname.s);
- pvh_free_xavp(&br_xname);
- pvh_get_branch_xname(msg, &xavp_parsed_xname, &br_xname);
-- /* LM_DBG("clean xavp:%.*s\n", br_xname.len, br_xname.s); */
-+ LM_DBG("clean xavp:%.*s\n", br_xname.len, br_xname.s);
- pvh_free_xavp(&br_xname);
-
-- if(msg->first_line.type == SIP_REPLY) {
-- resetflag(msg, FL_PV_HDRS_COLLECTED);
-- resetflag(msg, FL_PV_HDRS_APPLIED);
-- } else {
-- resetbflag(br_idx, FL_PV_HDRS_COLLECTED);
-- resetbflag(br_idx, FL_PV_HDRS_APPLIED);
-- }
--
-- pvh_str_free(&br_xname);
-+ pvh_hdrs_reset_flags(msg);
-
- return 1;
- }
-diff --git a/src/modules/pv_headers/pvh_func.h b/src/modules/pv_headers/pvh_func.h
-index 0fe5524..6aaf5aa 100644
---- a/src/modules/pv_headers/pvh_func.h
-+++ b/src/modules/pv_headers/pvh_func.h
-@@ -1,16 +1,18 @@
- /*
-- * PV Headers
-+ * pv_headers
- *
-- * Copyright (C) 2018 Kirill Solomko
-+ * Copyright (C)
-+ * 2020 Victor Seva
-+ * 2018 Kirill Solomko
- *
-- * This file is part of SIP Router, a free SIP server.
-+ * This file is part of Kamailio, a free SIP server.
- *
-- * SIP Router is free software; you can redistribute it and/or modify
-+ * 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
- *
-- * SIP Router is distributed in the hope that it will be useful,
-+ * 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.
-@@ -26,8 +28,10 @@
-
- #include "../../core/parser/msg_parser.h"
-
--int pvh_collect_headers(struct sip_msg *msg, int is_auto);
--int pvh_apply_headers(struct sip_msg *msg, int is_auto);
-+int pvh_parse_msg(sip_msg_t *msg);
-+
-+int pvh_collect_headers(struct sip_msg *msg);
-+int pvh_apply_headers(struct sip_msg *msg);
- int pvh_reset_headers(struct sip_msg *msg);
-
- int pvh_check_header(struct sip_msg *msg, str *hname);
-diff --git a/src/modules/pv_headers/pvh_hash.c b/src/modules/pv_headers/pvh_hash.c
-index f269868..6c99c43 100644
---- a/src/modules/pv_headers/pvh_hash.c
-+++ b/src/modules/pv_headers/pvh_hash.c
-@@ -1,16 +1,18 @@
- /*
-- * PV Headers
-+ * pv_headers
- *
-- * Copyright (C) 2018 Kirill Solomko
-+ * Copyright (C)
-+ * 2020 Victor Seva
-+ * 2018 Kirill Solomko
- *
-- * This file is part of SIP Router, a free SIP server.
-+ * This file is part of Kamailio, a free SIP server.
- *
-- * SIP Router is free software; you can redistribute it and/or modify
-+ * 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
- *
-- * SIP Router is distributed in the hope that it will be useful,
-+ * 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.
-diff --git a/src/modules/pv_headers/pvh_hash.h b/src/modules/pv_headers/pvh_hash.h
-index 8828cc6..d7e25f8 100644
---- a/src/modules/pv_headers/pvh_hash.h
-+++ b/src/modules/pv_headers/pvh_hash.h
-@@ -1,16 +1,18 @@
- /*
-- * PV Headers
-+ * pv_headers
- *
-- * Copyright (C) 2018 Kirill Solomko
-+ * Copyright (C)
-+ * 2020 Victor Seva
-+ * 2018 Kirill Solomko
- *
-- * This file is part of SIP Router, a free SIP server.
-+ * This file is part of Kamailio, a free SIP server.
- *
-- * SIP Router is free software; you can redistribute it and/or modify
-+ * 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
- *
-- * SIP Router is distributed in the hope that it will be useful,
-+ * 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.
-diff --git a/src/modules/pv_headers/pvh_hdr.c b/src/modules/pv_headers/pvh_hdr.c
-index 70be9ac..d83a646 100644
---- a/src/modules/pv_headers/pvh_hdr.c
-+++ b/src/modules/pv_headers/pvh_hdr.c
-@@ -1,16 +1,18 @@
- /*
-- * PV Headers
-+ * pv_headers
- *
-- * Copyright (C) 2018 Kirill Solomko
-+ * Copyright (C)
-+ * 2020 Victor Seva
-+ * 2018 Kirill Solomko
- *
-- * This file is part of SIP Router, a free SIP server.
-+ * This file is part of Kamailio, a free SIP server.
- *
-- * SIP Router is free software; you can redistribute it and/or modify
-+ * 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
- *
-- * SIP Router is distributed in the hope that it will be useful,
-+ * 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.
-@@ -22,15 +24,73 @@
- */
-
- #include "../../core/data_lump.h"
-+#include "../../core/dset.h"
-
- #include "pvh_hdr.h"
-
-+int pvh_hdrs_collected(struct sip_msg *msg)
-+{
-+ if(msg->first_line.type == SIP_REPLY) {
-+ if(isflagset(msg, FL_PV_HDRS_COLLECTED) == 1) {
-+ return 1;
-+ }
-+ } else {
-+ if(isbflagset(_branch, FL_PV_HDRS_COLLECTED) == 1) {
-+ return 1;
-+ }
-+ }
-+ return 0;
-+}
-+
-+int pvh_hdrs_applied(struct sip_msg *msg)
-+{
-+ if(msg->first_line.type == SIP_REPLY) {
-+ if(isflagset(msg, FL_PV_HDRS_APPLIED) == 1) {
-+ return 1;
-+ }
-+ } else {
-+ if(isbflagset(_branch, FL_PV_HDRS_APPLIED) == 1) {
-+ return 1;
-+ }
-+ }
-+ return 0;
-+}
-+
-+void pvh_hdrs_set_applied(struct sip_msg *msg)
-+{
-+ if(msg->first_line.type == SIP_REPLY) {
-+ setflag(msg, FL_PV_HDRS_APPLIED);
-+ } else {
-+ setbflag(_branch, FL_PV_HDRS_APPLIED);
-+ }
-+}
-+
-+void pvh_hdrs_set_collected(struct sip_msg *msg)
-+{
-+ if(msg->first_line.type == SIP_REPLY) {
-+ setflag(msg, FL_PV_HDRS_COLLECTED);
-+ } else {
-+ setbflag(_branch, FL_PV_HDRS_COLLECTED);
-+ }
-+}
-+
-+void pvh_hdrs_reset_flags(struct sip_msg *msg)
-+{
-+ if(msg->first_line.type == SIP_REPLY) {
-+ resetflag(msg, FL_PV_HDRS_COLLECTED);
-+ resetflag(msg, FL_PV_HDRS_APPLIED);
-+ } else {
-+ resetbflag(_branch, FL_PV_HDRS_COLLECTED);
-+ resetbflag(_branch, FL_PV_HDRS_APPLIED);
-+ }
-+}
-+
- int pvh_real_hdr_append(struct sip_msg *msg, str *hname, str *hvalue)
- {
- struct lump *anchor = NULL;
- hdr_field_t *hf = NULL;
- hdr_field_t *m_hf = NULL;
-- str new_h;
-+ str new_h = STR_NULL;
-
- if(hname->s == NULL || hvalue->s == NULL) {
- LM_ERR("header name/value cannot be empty");
-@@ -75,7 +135,7 @@ int pvh_real_hdr_replace(struct sip_msg *msg, str *hname, str *hvalue)
- {
- struct lump *anchor = NULL;
- hdr_field_t *hf = NULL;
-- str new_h;
-+ str new_h = STR_NULL;
- int new = 1;
-
- if(hname->s == NULL || hvalue->s == NULL) {
-diff --git a/src/modules/pv_headers/pvh_hdr.h b/src/modules/pv_headers/pvh_hdr.h
-index f05d7e4..4f86953 100644
---- a/src/modules/pv_headers/pvh_hdr.h
-+++ b/src/modules/pv_headers/pvh_hdr.h
-@@ -1,16 +1,18 @@
- /*
-- * PV Headers
-+ * pv_headers
- *
-- * Copyright (C) 2018 Kirill Solomko
-+ * Copyright (C)
-+ * 2020 Victor Seva
-+ * 2018 Kirill Solomko
- *
-- * This file is part of SIP Router, a free SIP server.
-+ * This file is part of Kamailio, a free SIP server.
- *
-- * SIP Router is free software; you can redistribute it and/or modify
-+ * 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
- *
-- * SIP Router is distributed in the hope that it will be useful,
-+ * 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.
-@@ -29,6 +31,12 @@
-
- #include "pv_headers.h"
-
-+int pvh_hdrs_collected(struct sip_msg *msg);
-+int pvh_hdrs_applied(struct sip_msg *msg);
-+void pvh_hdrs_set_collected(struct sip_msg *msg);
-+void pvh_hdrs_set_applied(struct sip_msg *msg);
-+void pvh_hdrs_reset_flags(struct sip_msg *msg);
-+
- int pvh_real_hdr_append(struct sip_msg *msg, str *hname, str *hvalue);
- int pvh_real_hdr_replace(struct sip_msg *msg, str *hname, str *hvalue);
- int pvh_real_hdr_del_by_name(struct sip_msg *msg, str *hname);
-diff --git a/src/modules/pv_headers/pvh_str.c b/src/modules/pv_headers/pvh_str.c
-index 53e2c9c..6ede032 100644
---- a/src/modules/pv_headers/pvh_str.c
-+++ b/src/modules/pv_headers/pvh_str.c
-@@ -1,16 +1,18 @@
- /*
-- * PV Headers
-+ * pv_headers
- *
-- * Copyright (C) 2018 Kirill Solomko
-+ * Copyright (C)
-+ * 2020 Victor Seva
-+ * 2018 Kirill Solomko
- *
-- * This file is part of SIP Router, a free SIP server.
-+ * This file is part of Kamailio, a free SIP server.
- *
-- * SIP Router is free software; you can redistribute it and/or modify
-+ * 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
- *
-- * SIP Router is distributed in the hope that it will be useful,
-+ * 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.
-diff --git a/src/modules/pv_headers/pvh_str.h b/src/modules/pv_headers/pvh_str.h
-index 95aa0b9..10aa216 100644
---- a/src/modules/pv_headers/pvh_str.h
-+++ b/src/modules/pv_headers/pvh_str.h
-@@ -1,16 +1,18 @@
- /*
-- * PV Headers
-+ * pv_headers
- *
-- * Copyright (C) 2018 Kirill Solomko
-+ * Copyright (C)
-+ * 2020 Victor Seva
-+ * 2018 Kirill Solomko
- *
-- * This file is part of SIP Router, a free SIP server.
-+ * This file is part of Kamailio, a free SIP server.
- *
-- * SIP Router is free software; you can redistribute it and/or modify
-+ * 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
- *
-- * SIP Router is distributed in the hope that it will be useful,
-+ * 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.
-diff --git a/src/modules/pv_headers/pvh_xavp.c b/src/modules/pv_headers/pvh_xavp.c
-index db2192c..0cfd969 100644
---- a/src/modules/pv_headers/pvh_xavp.c
-+++ b/src/modules/pv_headers/pvh_xavp.c
-@@ -1,17 +1,18 @@
- /*
-+ * pv_headers
- *
-- * PV Headers
-+ * Copyright (C)
-+ * 2020 Victor Seva
-+ * 2018 Kirill Solomko
- *
-- * Copyright (C) 2018 Kirill Solomko
-+ * This file is part of Kamailio, a free SIP server.
- *
-- * This file is part of SIP Router, a free SIP server.
-- *
-- * SIP Router is free software; you can redistribute it and/or modify
-+ * 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
- *
-- * SIP Router is distributed in the hope that it will be useful,
-+ * 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.
-@@ -22,15 +23,75 @@
- *
- */
-
--#include
--
--#include "../../core/hashes.h"
--#include "../../core/route_struct.h"
-+#include "../../core/parser/parse_uri.h"
- #include "../../core/strutils.h"
-
- #include "pvh_xavp.h"
- #include "pvh_str.h"
- #include "pvh_hash.h"
-+#include "pvh_hdr.h"
-+
-+static str reply_counter = str_init("reply_counter");
-+
-+sr_xavp_t *pvh_xavp_get_child_with_ival(
-+ str *rname, str *cname, sr_xavp_t *start)
-+{
-+ sr_xavp_t *ravp = NULL;
-+ sr_xavp_t *vavp = NULL;
-+
-+ ravp = xavp_get(rname, start);
-+ if(ravp == NULL || ravp->val.type != SR_XTYPE_XAVP)
-+ return NULL;
-+
-+ vavp = xavp_get(cname, ravp->val.v.xavp);
-+ if(vavp == NULL || vavp->val.type != SR_XTYPE_INT)
-+ return NULL;
-+
-+ return vavp;
-+}
-+
-+/**
-+ * We keep a $xavp(xavp_helper_xname=>reply_counter) with the number of replies
-+ * so we will use $xavp(xavp_name.r.) on reply_route
-+ */
-+int pvh_reply_append(sr_xavp_t **start)
-+{
-+ sr_xavp_t *xavp = NULL;
-+ sr_xval_t xval;
-+
-+ xavp = pvh_xavp_get_child_with_ival(
-+ &xavp_helper_xname, &reply_counter, start ? *start : NULL);
-+ if(xavp) {
-+ xavp->val.v.i++;
-+ LM_DBG("reply message: %d\n", xavp->val.v.i);
-+ return xavp->val.v.i;
-+ }
-+
-+ memset(&xval, 0, sizeof(sr_xval_t));
-+ xval.type = SR_XTYPE_INT;
-+ xval.v.i = 0;
-+
-+ xavp = xavp_get(&xavp_helper_xname, start ? *start : NULL);
-+ if(xavp == NULL) {
-+ if(xavp_add_xavp_value(&xavp_helper_xname, &reply_counter, &xval,
-+ start ? start : NULL)
-+ == NULL) {
-+ LM_ERR("can't create xavp:%.*s\n", xavp_helper_xname.len,
-+ xavp_helper_xname.s);
-+ return -1;
-+ }
-+ LM_DBG("xavp_name:%.*s created\n", xavp_helper_xname.len,
-+ xavp_helper_xname.s);
-+ } else {
-+ if(xavp_add_value(&reply_counter, &xval, &xavp->val.v.xavp) == NULL) {
-+ LM_ERR("can't add reply_counter value\n");
-+ return -1;
-+ }
-+ LM_DBG("added value\n");
-+ }
-+ LM_DBG("reply message: %d\n", xval.v.i);
-+ return xval.v.i;
-+}
-
- sr_xavp_t *pvh_xavp_new_value(str *name, sr_xval_t *val)
- {
-@@ -109,10 +170,8 @@ int pvh_xavp_set_value(str *name, sr_xval_t *val, int idx, sr_xavp_t **start)
- sr_xavp_t *pvh_xavp_get(struct sip_msg *msg, str *xname)
- {
- sr_xavp_t *xavp = NULL;
-- str br_xname = STR_NULL;
--
-- if(pvh_str_new(&br_xname, header_name_size) < 0)
-- return NULL;
-+ char t[header_name_size];
-+ str br_xname = {t, header_name_size};
-
- pvh_get_branch_xname(msg, xname, &br_xname);
- if((xavp = xavp_get(&br_xname, NULL)) == NULL) {
-@@ -120,8 +179,10 @@ sr_xavp_t *pvh_xavp_get(struct sip_msg *msg, str *xname)
- goto end;
- if((xavp = xavp_get(xname, NULL)) == NULL)
- goto end;
-- /* LM_DBG("br_xname:%.*s is not there, using xname:%.*s\n", br_xname.len,
-- br_xname.s, xname->len, xname->s); */
-+ if(xname != &xavp_parsed_xname) {
-+ LM_DBG("br_xname:%.*s is not there, using xname:%.*s\n",
-+ br_xname.len, br_xname.s, xname->len, xname->s);
-+ }
- }
-
- if(xavp->val.type != SR_XTYPE_XAVP) {
-@@ -131,10 +192,68 @@ sr_xavp_t *pvh_xavp_get(struct sip_msg *msg, str *xname)
- }
-
- end:
-- pvh_str_free(&br_xname);
- return xavp;
- }
-
-+int pvh_free_xavp(str *xname)
-+{
-+ sr_xavp_t *xavp = NULL;
-+ xavp_rm_by_name(xname, 1, NULL);
-+ if((xavp = xavp_get(xname, NULL)) != NULL)
-+ xavp_rm(xavp, NULL);
-+ return 1;
-+}
-+
-+void pvh_free_to_params(struct to_param *param, sr_xavp_sfree_f sfree)
-+{
-+ struct to_param *n = NULL;
-+
-+ while(param) {
-+ n = param->next;
-+ sfree(param);
-+ param = n;
-+ }
-+ param = NULL;
-+}
-+
-+int pvh_parse_header_name(pv_spec_p sp, str *hname)
-+{
-+ pv_spec_p psp = NULL;
-+
-+ if(hname->s == NULL || hname->len == 0) {
-+ LM_ERR("empty header name\n");
-+ return -1;
-+ }
-+
-+ if(hname->len >= header_name_size) {
-+ LM_ERR("header name is too long\n");
-+ return -1;
-+ }
-+
-+ if(*hname->s == PV_MARKER) {
-+ psp = (pv_spec_p)pkg_malloc(sizeof(pv_spec_t));
-+ if(psp == NULL) {
-+ PKG_MEM_ERROR;
-+ return -1;
-+ }
-+ if(pv_parse_spec(hname, psp) == NULL) {
-+ LM_ERR("invalid avp name [%.*s]\n", hname->len, hname->s);
-+ pv_spec_free(psp);
-+ return -1;
-+ }
-+ sp->pvp.pvn.type = PV_NAME_PVAR;
-+ sp->pvp.pvn.u.dname = (void *)psp;
-+ sp->pvp.pvn.u.isname.name.s = *hname;
-+ return 0;
-+ }
-+
-+ sp->pvp.pvn.type = PV_NAME_INTSTR;
-+ sp->pvp.pvn.u.isname.type = AVP_NAME_STR;
-+ sp->pvp.pvn.u.isname.name.s = *hname;
-+
-+ return 0;
-+}
-+
- sr_xval_t *pvh_xavp_get_value(
- struct sip_msg *msg, str *xname, str *name, int idx)
- {
-@@ -153,25 +272,20 @@ sr_xval_t *pvh_xavp_get_value(
- sr_xavp_t *pvh_xavp_get_child(struct sip_msg *msg, str *xname, str *name)
- {
- sr_xavp_t *xavp = NULL;
-- str br_xname = STR_NULL;
--
-- if(pvh_str_new(&br_xname, header_name_size) < 0)
-- return NULL;
-+ char t[header_name_size];
-+ str br_xname = {t, header_name_size};
-
- pvh_get_branch_xname(msg, xname, &br_xname);
- xavp = xavp_get_child(&br_xname, name);
- if(xavp == NULL) {
- if(cmp_str(xname, &br_xname) != 0) {
- xavp = xavp_get_child(xname, name);
-- /*
- if(xavp) {
- LM_DBG("br_xname:%.*s is not there, using xname:%.*s\n",
-- br_xname.len, br_xname.s, xname->len, xname->s);
-- } */
-+ br_xname.len, br_xname.s, xname->len, xname->s);
-+ }
- }
- }
--
-- pvh_str_free(&br_xname);
- return xavp;
- }
-
-@@ -220,56 +334,6 @@ int pvh_xavp_keys_count(sr_xavp_t **start)
- return cnt;
- }
-
--void pvh_free_to_params(struct to_param *param, sr_xavp_sfree_f sfree)
--{
-- struct to_param *n = NULL;
--
-- while(param) {
-- n = param->next;
-- sfree(param);
-- param = n;
-- }
-- param = NULL;
--}
--
--int pvh_parse_header_name(pv_spec_p sp, str *hname)
--{
-- pv_spec_p psp = NULL;
--
-- if(hname->s == NULL || hname->len == 0) {
-- LM_ERR("empty header name\n");
-- return -1;
-- }
--
-- if(hname->len >= header_name_size) {
-- LM_ERR("header name is too long\n");
-- return -1;
-- }
--
-- if(*hname->s == PV_MARKER) {
-- psp = (pv_spec_p)pkg_malloc(sizeof(pv_spec_t));
-- if(psp == NULL) {
-- PKG_MEM_ERROR;
-- return -1;
-- }
-- if(pv_parse_spec(hname, psp) == NULL) {
-- LM_ERR("invalid avp name [%.*s]\n", hname->len, hname->s);
-- pv_spec_free(psp);
-- return -1;
-- }
-- sp->pvp.pvn.type = PV_NAME_PVAR;
-- sp->pvp.pvn.u.dname = (void *)psp;
-- sp->pvp.pvn.u.isname.name.s = *hname;
-- return 0;
-- }
--
-- sp->pvp.pvn.type = PV_NAME_INTSTR;
-- sp->pvp.pvn.u.isname.type = AVP_NAME_STR;
-- sp->pvp.pvn.u.isname.name.s = *hname;
--
-- return 0;
--}
--
- int pvh_set_xavp(struct sip_msg *msg, str *xname, str *name, void *data,
- sr_xtype_t type, int idx, int append)
- {
-@@ -277,17 +341,14 @@ int pvh_set_xavp(struct sip_msg *msg, str *xname, str *name, void *data,
- sr_xavp_t *root = NULL;
- sr_xval_t root_xval;
- sr_xval_t xval;
-- str br_xname = STR_NULL;
-- int br_idx;
-+ char t[header_name_size];
-+ str br_xname = {t, header_name_size};
-
- if(xname == NULL || name == NULL) {
- LM_ERR("missing xavp/pv name\n");
- return -1;
- }
-
-- pvh_get_branch_index(msg, &br_idx);
-- if(pvh_str_new(&br_xname, header_name_size) < 0)
-- return -1;
- pvh_get_branch_xname(msg, xname, &br_xname);
- LM_DBG("br_xname: %.*s name: %.*s\n", br_xname.len, br_xname.s, name->len,
- name->s);
-@@ -302,7 +363,7 @@ int pvh_set_xavp(struct sip_msg *msg, str *xname, str *name, void *data,
- xval.v.data = (sr_data_t *)shm_malloc(sizeof(sr_data_t));
- if(xval.v.data == NULL) {
- SHM_MEM_ERROR;
-- goto err;
-+ return -1;
- }
- memset(xval.v.data, 0, sizeof(sr_data_t));
- xval.v.data->p = data;
-@@ -311,10 +372,8 @@ int pvh_set_xavp(struct sip_msg *msg, str *xname, str *name, void *data,
-
- root = xavp_get(&br_xname, NULL);
-
-- if(root == NULL && br_idx > 0) {
-- LM_DBG("clone xavp:%.*s br_xname:%.*s\n", xname->len, xname->s,
-- br_xname.len, br_xname.s);
-- pvh_clone_branch_xavp(msg, xname, &br_xname);
-+ if(root == NULL && _branch > 0) {
-+ pvh_clone_branch_xavp(msg, xname);
- root = xavp_get(&br_xname, NULL);
- }
-
-@@ -328,7 +387,7 @@ int pvh_set_xavp(struct sip_msg *msg, str *xname, str *name, void *data,
-
- if((root = xavp_add_value(&br_xname, &root_xval, NULL)) == NULL) {
- LM_ERR("error create xavp %s\n", br_xname.s);
-- goto err;
-+ return -1;
- }
- xavp = &root->val.v.xavp;
- } else if(xavp_get_child(&br_xname, name) == NULL) {
-@@ -339,30 +398,16 @@ int pvh_set_xavp(struct sip_msg *msg, str *xname, str *name, void *data,
- if(pvh_xavp_append_value(name, &xval, xavp) < 0) {
- LM_ERR("error append xavp=>name %s=>%.*s\n", br_xname.s, name->len,
- name->s);
-- goto err;
-+ return -1;
- }
- } else {
- if(pvh_xavp_set_value(name, &xval, idx, xavp) < 0) {
- LM_ERR("error modify xavp=>name %s=>%.*s idx=%d\n", br_xname.s,
- name->len, name->s, idx);
-- goto err;
-+ return -1;
- }
- }
-
-- pvh_str_free(&br_xname);
-- return 1;
--
--err:
-- pvh_str_free(&br_xname);
-- return -1;
--}
--
--int pvh_free_xavp(str *xname)
--{
-- sr_xavp_t *xavp = NULL;
-- xavp_rm_by_name(xname, 1, NULL);
-- if((xavp = xavp_get(xname, NULL)) != NULL)
-- xavp_rm(xavp, NULL);
- return 1;
- }
-
-@@ -394,7 +439,6 @@ int pvh_get_branch_index(struct sip_msg *msg, int *br_idx)
-
- int pvh_get_branch_xname(struct sip_msg *msg, str *xname, str *dst)
- {
-- int br_idx;
- int os = 0;
- char br_idx_s[32];
- char br_idx_len = 0;
-@@ -406,9 +450,8 @@ int pvh_get_branch_xname(struct sip_msg *msg, str *xname, str *dst)
- memcpy(dst->s, xname->s, xname->len);
- os += xname->len;
-
-- pvh_get_branch_index(msg, &br_idx);
-- if(br_idx > 0) {
-- sprintf(br_idx_s, "%d", br_idx - 1);
-+ if(_branch > 0) {
-+ snprintf(br_idx_s, 32, "%d", _branch - 1);
- br_idx_len = strlen(br_idx_s);
- memcpy(dst->s + os, ".", 1);
- os += 1;
-@@ -416,8 +459,10 @@ int pvh_get_branch_xname(struct sip_msg *msg, str *xname, str *dst)
- os += br_idx_len;
- }
- if(msg->first_line.type == SIP_REPLY) {
-- memcpy(dst->s + os, ".r", 2);
-- os += 2;
-+ snprintf(br_idx_s, 32, ".r.%d", _reply_counter);
-+ br_idx_len = strlen(br_idx_s);
-+ memcpy(dst->s + os, br_idx_s, br_idx_len);
-+ os += br_idx_len;
- }
- dst->len = os;
- dst->s[dst->len] = '\0';
-@@ -425,12 +470,15 @@ int pvh_get_branch_xname(struct sip_msg *msg, str *xname, str *dst)
- return 1;
- }
-
--int pvh_clone_branch_xavp(struct sip_msg *msg, str *xname, str *br_xname)
-+int pvh_clone_branch_xavp(struct sip_msg *msg, str *xname)
- {
- sr_xavp_t *xavp = NULL;
- sr_xavp_t *br_xavp = NULL;
- sr_xavp_t *sub = NULL;
- sr_xval_t root_xval;
-+ char t[header_name_size];
-+ str br_xname = {t, header_name_size};
-+ int i = 0;
-
- if((xavp = xavp_get(xname, NULL)) == NULL) {
- LM_ERR("cannot clone xavp from non existing %s\n", xname->s);
-@@ -447,17 +495,18 @@ int pvh_clone_branch_xavp(struct sip_msg *msg, str *xname, str *br_xname)
- return -1;
- }
-
-+ pvh_get_branch_xname(msg, xname, &br_xname);
-+
- memset(&root_xval, 0, sizeof(sr_xval_t));
- root_xval.type = SR_XTYPE_XAVP;
- root_xval.v.xavp = NULL;
-
-- if((br_xavp = xavp_add_value(br_xname, &root_xval, NULL)) == NULL) {
-- LM_ERR("error create xavp %s\n", br_xname->s);
-+ if((br_xavp = xavp_add_value(&br_xname, &root_xval, NULL)) == NULL) {
-+ LM_ERR("error create xavp %s\n", br_xname.s);
- return -1;
- }
-
-- if(strncmp(xname->s, xavp_parsed_xname.s, xname->len) == 0) {
-- LM_DBG("skip clone\n");
-+ if(cmp_str(xname, &xavp_parsed_xname) == 0) {
- return 1;
- }
-
-@@ -471,8 +520,10 @@ int pvh_clone_branch_xavp(struct sip_msg *msg, str *xname, str *br_xname)
- LM_ERR("cannot clone xavp %s\n", sub->name.s);
- return -1;
- }
-+ ++i;
- } while((sub = sub->next) != NULL);
--
-+ LM_DBG("cloned %.*s[%d] => %.*s\n", xname->len, xname->s, i, br_xname.len,
-+ br_xname.s);
- return 1;
- }
-
-@@ -663,12 +714,10 @@ int pvh_get_uri(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
- str sval = STR_NULL;
- int ival = 0;
- int is_strint = 0;
-- str hname = STR_NULL;
-+ char t[header_name_size];
-+ str hname = {t, header_name_size - 1};
-
- p_no = param->pvn.u.isname.name.n;
-- if(pvh_str_new(&hname, header_name_size) < 0)
-- goto err;
--
- if(p_no >= 1 && p_no <= 5)
- pvh_str_copy(&hname, &_hdr_from, header_name_size);
- else if(p_no >= 6 && p_no <= 10)
-@@ -689,8 +738,7 @@ int pvh_get_uri(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
- c_data = (xavp_c_data_t *)xval_pd->v.data->p;
- }
-
-- if(c_data != NULL
-- && strncmp(xval->v.s.s, c_data->value.s, c_data->value.len) != 0) {
-+ if(c_data != NULL && cmp_str(&xval->v.s, &c_data->value) != 0) {
- /* LM_DBG("xval:%.*s != c_data->value:%.*s\n", xval->v.s.len, xval->v.s.s,
- c_data->value.len, c_data->value.s); */
- c_data = NULL;
-@@ -726,13 +774,11 @@ int pvh_get_uri(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
- LM_ERR("unknown get uri op\n");
- }
- /* LM_DBG("p_no:%d sval:%.*s\n", p_no, sval.len, sval.s); */
-- pvh_str_free(&hname);
- return sval.s ? is_strint ? pv_get_strintval(msg, param, res, &sval, ival)
- : pv_get_strval(msg, param, res, &sval)
- : pv_get_null(msg, param, res);
-
- err:
-- pvh_str_free(&hname);
- return pv_get_null(msg, param, res);
- }
-
-@@ -743,12 +789,11 @@ int pvh_set_uri(struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val)
- pv_elem_p pv_format = NULL;
- int p_no = 0;
- enum action_type a_type;
-- str hname;
-+ char t[header_name_size];
-+ str hname = {t, header_name_size - 1};
- str fval;
-
- p_no = param->pvn.u.isname.name.n;
-- if(pvh_str_new(&hname, header_name_size) < 0)
-- goto err;
- if(p_no >= 1 && p_no <= 5)
- pvh_str_copy(&hname, &_hdr_from, header_name_size);
- else if(p_no >= 6 && p_no <= 10)
-@@ -814,13 +859,11 @@ int pvh_set_uri(struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val)
- < 0)
- goto err;
-
-- pvh_str_free(&hname);
- if(pv_format)
- pv_elem_free_all(pv_format);
- return 1;
-
- err:
-- pvh_str_free(&hname);
- if(pv_format)
- pv_elem_free_all(pv_format);
- return -1;
-@@ -986,7 +1029,6 @@ int pvh_get_reply_sr(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
- {
- sr_xval_t *xval = NULL;
- int p_no = 0;
-- str rhname = {"@Reply-Reason", 13};
-
- p_no = param->pvn.u.isname.name.n;
-
-@@ -1000,7 +1042,7 @@ int pvh_get_reply_sr(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
- &msg->first_line.u.reply.status);
- break;
- case 2: // reason
-- xval = pvh_xavp_get_value(msg, &xavp_name, &rhname, 0);
-+ xval = pvh_xavp_get_value(msg, &xavp_name, &_hdr_reply_reason, 0);
- return pv_get_strval(msg, param, res,
- xval && xval->v.s.s ? &xval->v.s
- : &msg->first_line.u.reply.reason);
-@@ -1018,7 +1060,6 @@ int pvh_set_reply_sr(
- pv_elem_p pv_format = NULL;
- int p_no = 0;
- unsigned int code = 0;
-- str rhname = {"@Reply-Reason", 13};
- str fval;
-
- p_no = param->pvn.u.isname.name.n;
-@@ -1069,7 +1110,8 @@ int pvh_set_reply_sr(
- msg->first_line.u.reply.status.s[0] = code + '0';
- break;
- case 2: // reason
-- if(pvh_set_xavp(msg, &xavp_name, &rhname, &fval, SR_XTYPE_STR, 0, 0)
-+ if(pvh_set_xavp(msg, &xavp_name, &_hdr_reply_reason, &fval,
-+ SR_XTYPE_STR, 0, 0)
- < 0) {
- LM_ERR("set reply: cannot set reply reason\n");
- goto err;
-diff --git a/src/modules/pv_headers/pvh_xavp.h b/src/modules/pv_headers/pvh_xavp.h
-index d9e9299..7d4aa30 100644
---- a/src/modules/pv_headers/pvh_xavp.h
-+++ b/src/modules/pv_headers/pvh_xavp.h
-@@ -1,16 +1,18 @@
- /*
-- * PV Headers
-+ * pv_headers
- *
-- * Copyright (C) 2018 Kirill Solomko
-+ * Copyright (C)
-+ * 2020 Victor Seva
-+ * 2018 Kirill Solomko
- *
-- * This file is part of SIP Router, a free SIP server.
-+ * This file is part of Kamailio, a free SIP server.
- *
-- * SIP Router is free software; you can redistribute it and/or modify
-+ * 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
- *
-- * SIP Router is distributed in the hope that it will be useful,
-+ * 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.
-@@ -24,44 +26,41 @@
- #ifndef PV_XAVP_H
- #define PV_XAVP_H
-
--#include "../../core/parser/parse_uri.h"
-+#include "../../core/str.h"
- #include "../../core/xavp.h"
--#include "../../core/pvar.h"
-
- #include "pv_headers.h"
-
--sr_xavp_t *pvh_xavp_new_value(str *name, sr_xval_t *val);
--int pvh_xavp_append_value(str *name, sr_xval_t *val, sr_xavp_t **start);
--int pvh_xavp_set_value(str *name, sr_xval_t *val, int idx, sr_xavp_t **start);
--sr_xavp_t *pvh_xavp_get(struct sip_msg *msg, str *xname);
--sr_xval_t *pvh_xavp_get_value(
-- struct sip_msg *msg, str *xname, str *name, int idx);
--sr_xavp_t *pvh_xavp_get_child(struct sip_msg *msg, str *xname, str *name);
--int pvh_xavp_is_null(sr_xavp_t *xavp);
--void pvh_xavp_free_data(void *p, sr_xavp_sfree_f sfree);
--int pvh_xavp_keys_count(sr_xavp_t **start);
--void pvh_free_to_params(struct to_param *param, sr_xavp_sfree_f sfree);
-+int pvh_reply_append(sr_xavp_t **start);
-+
- int pvh_set_xavp(struct sip_msg *msg, str *xname, str *name, void *data,
- sr_xtype_t type, int idx, int append);
- int pvh_free_xavp(str *xname);
--int pvh_parse_header_name(pv_spec_p sp, str *hname);
-+int pvh_xavp_is_null(sr_xavp_t *avp);
-+int pvh_xavp_keys_count(sr_xavp_t **start);
-+sr_xval_t *pvh_xavp_get_value(
-+ struct sip_msg *msg, str *xname, str *name, int idx);
-+sr_xavp_t *pvh_xavp_get_child(struct sip_msg *msg, str *xname, str *name);
-
-+int pvh_get_branch_index(struct sip_msg *msg, int *br_idx);
-+int pvh_get_branch_xname(struct sip_msg *msg, str *xname, str *dst);
-+int pvh_clone_branch_xavp(struct sip_msg *msg, str *xname);
-+
-+int pvh_parse_header_name(pv_spec_p sp, str *hname);
- int pvh_get_header(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
- int pvh_set_header(
- struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val);
- xavp_c_data_t *pvh_set_parsed(
- struct sip_msg *msg, str *hname, str *cur, str *new);
--int pvh_get_uri(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
-+
- int pvh_set_uri(
- struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val);
-+int pvh_get_uri(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
- int pvh_merge_uri(struct sip_msg *msg, enum action_type type, str *cur,
- str *new, xavp_c_data_t *c_data);
-+
- int pvh_get_reply_sr(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
- int pvh_set_reply_sr(
- struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val);
-
--int pvh_get_branch_index(struct sip_msg *msg, int *br_idx);
--int pvh_get_branch_xname(struct sip_msg *msg, str *xname, str *dst);
--int pvh_clone_branch_xavp(struct sip_msg *msg, str *xname, str *br_xname);
--
- #endif /* PV_XAVP_H */
diff --git a/debian/patches/sipwise/pv_headers-store-To-info-in-xavp_parsed_name.r-on-re.patch b/debian/patches/sipwise/pv_headers-store-To-info-in-xavp_parsed_name.r-on-re.patch
deleted file mode 100644
index a3a725c23..000000000
--- a/debian/patches/sipwise/pv_headers-store-To-info-in-xavp_parsed_name.r-on-re.patch
+++ /dev/null
@@ -1,411 +0,0 @@
-From: Victor Seva
-Date: Tue, 17 Dec 2019 15:27:35 +0100
-Subject: pv_headers: store To info in xavp_parsed_name.r on replies
-
-pvh_get_uri was using xavp_parsed_name since xavp_parsed_name.r didn't
-exist so $x_tt was not there
-
-* some refactoring to reduce duplication
-* skip trying to get the same xavp when br_xname and xname are the same
-* add more debug, some commented just in case We needed it later
-
-Change-Id: I961d176204ddb5d4f726061c413be765187b27ac
----
- src/modules/pv_headers/pvh_func.c | 48 +++++++-------
- src/modules/pv_headers/pvh_xavp.c | 135 +++++++++++++++++++++++++-------------
- src/modules/pv_headers/pvh_xavp.h | 5 +-
- 3 files changed, 115 insertions(+), 73 deletions(-)
-
-diff --git a/src/modules/pv_headers/pvh_func.c b/src/modules/pv_headers/pvh_func.c
-index 22ee74e..88a6497 100644
---- a/src/modules/pv_headers/pvh_func.c
-+++ b/src/modules/pv_headers/pvh_func.c
-@@ -139,7 +139,7 @@ int pvh_apply_headers(struct sip_msg *msg, int is_auto)
- str uri = STR_NULL;
- struct str_hash_table rm_hdrs;
- int from_cnt = 0, to_cnt = 0;
-- str br_xname = STR_NULL;
-+ int skip_from_to = 0;
- int br_idx, keys_count;
- int res = -1;
-
-@@ -170,19 +170,10 @@ int pvh_apply_headers(struct sip_msg *msg, int is_auto)
- goto err;
- if(pvh_str_new(&uri, header_value_size) < 0)
- goto err;
-- if(pvh_str_new(&br_xname, header_value_size) < 0)
-- goto err;
--
-- pvh_get_branch_xname(msg, &xavp_name, &br_xname);
-
-- if((xavp = xavp_get(&br_xname, NULL)) == NULL
-- && (xavp = xavp_get(&xavp_name, NULL)) == NULL) {
-- LM_ERR("missing xavp %s, run pv_collect_headers() first\n",
-- xavp_name.s);
-- goto err;
-- }
-- if(xavp->val.type != SR_XTYPE_XAVP) {
-- LM_ERR("not xavp child type %s\n", xavp_name.s);
-+ if((xavp = pvh_xavp_get(msg, &xavp_name)) == NULL) {
-+ LM_ERR("missing xavp %.*s, run pv_collect_headers() first\n",
-+ xavp_name.len, xavp_name.s);
- goto err;
- }
-
-@@ -195,19 +186,29 @@ int pvh_apply_headers(struct sip_msg *msg, int is_auto)
- PKG_MEM_ERROR;
- goto err;
- }
-- LM_DBG("xavp->name:%.*s br_xname:%.*s keys_count: %d\n", xavp->name.len,
-- xavp->name.s, br_xname.len, br_xname.s, keys_count);
-+ LM_DBG("xavp->name:%.*s keys_count: %d\n", xavp->name.len, xavp->name.s,
-+ keys_count);
- str_hash_init(&rm_hdrs);
-
-+ if(msg->first_line.type == SIP_REPLY
-+ || msg->first_line.u.request.method_value == METHOD_ACK
-+ || msg->first_line.u.request.method_value == METHOD_PRACK
-+ || msg->first_line.u.request.method_value == METHOD_BYE) {
-+ skip_from_to = 1;
-+ if(msg->to == NULL) {
-+ LM_DBG("no To header, can't store To info in parsed\n");
-+ } else {
-+ if(pvh_set_parsed(msg, &_hdr_to, &msg->to->body, NULL) == NULL)
-+ LM_ERR("can't store To info in parsed\n");
-+ }
-+ }
-+
- do {
- if(pvh_skip_header(&sub->name))
- continue;
-
- if(strncasecmp(sub->name.s, _hdr_from.s, sub->name.len) == 0) {
-- if(msg->first_line.type == SIP_REPLY
-- || msg->first_line.u.request.method_value == METHOD_ACK
-- || msg->first_line.u.request.method_value == METHOD_PRACK
-- || msg->first_line.u.request.method_value == METHOD_BYE) {
-+ if(skip_from_to) {
- LM_DBG("skip From header change in reply messages\n");
- continue;
- }
-@@ -240,10 +241,7 @@ int pvh_apply_headers(struct sip_msg *msg, int is_auto)
- }
-
- if(strncasecmp(sub->name.s, _hdr_to.s, sub->name.len) == 0) {
-- if(msg->first_line.type == SIP_REPLY
-- || msg->first_line.u.request.method_value == METHOD_ACK
-- || msg->first_line.u.request.method_value == METHOD_PRACK
-- || msg->first_line.u.request.method_value == METHOD_BYE) {
-+ if(skip_from_to) {
- LM_DBG("skip To header change in reply messages\n");
- continue;
- }
-@@ -309,7 +307,6 @@ int pvh_apply_headers(struct sip_msg *msg, int is_auto)
- err:
- pvh_str_free(&display);
- pvh_str_free(&uri);
-- pvh_str_free(&br_xname);
- if(rm_hdrs.size)
- pvh_str_hash_free(&rm_hdrs);
- return res;
-@@ -325,9 +322,10 @@ int pvh_reset_headers(struct sip_msg *msg)
-
- pvh_get_branch_index(msg, &br_idx);
- pvh_get_branch_xname(msg, &xavp_name, &br_xname);
--
-+ /* LM_DBG("clean xavp:%.*s\n", br_xname.len, br_xname.s); */
- pvh_free_xavp(&br_xname);
- pvh_get_branch_xname(msg, &xavp_parsed_xname, &br_xname);
-+ /* LM_DBG("clean xavp:%.*s\n", br_xname.len, br_xname.s); */
- pvh_free_xavp(&br_xname);
-
- if(msg->first_line.type == SIP_REPLY) {
-diff --git a/src/modules/pv_headers/pvh_xavp.c b/src/modules/pv_headers/pvh_xavp.c
-index de296b4..db2192c 100644
---- a/src/modules/pv_headers/pvh_xavp.c
-+++ b/src/modules/pv_headers/pvh_xavp.c
-@@ -26,6 +26,7 @@
-
- #include "../../core/hashes.h"
- #include "../../core/route_struct.h"
-+#include "../../core/strutils.h"
-
- #include "pvh_xavp.h"
- #include "pvh_str.h"
-@@ -105,35 +106,48 @@ int pvh_xavp_set_value(str *name, sr_xval_t *val, int idx, sr_xavp_t **start)
- return 1;
- }
-
--sr_xval_t *pvh_xavp_get_value(
-- struct sip_msg *msg, str *xname, str *name, int idx)
-+sr_xavp_t *pvh_xavp_get(struct sip_msg *msg, str *xname)
- {
- sr_xavp_t *xavp = NULL;
-- sr_xavp_t *sub = NULL;
- str br_xname = STR_NULL;
-
- if(pvh_str_new(&br_xname, header_name_size) < 0)
- return NULL;
-
- pvh_get_branch_xname(msg, xname, &br_xname);
-- if((xavp = xavp_get(&br_xname, NULL)) == NULL
-- && (xavp = xavp_get(xname, NULL)) == NULL) {
-- goto err;
-+ if((xavp = xavp_get(&br_xname, NULL)) == NULL) {
-+ if(cmp_str(xname, &br_xname) == 0)
-+ goto end;
-+ if((xavp = xavp_get(xname, NULL)) == NULL)
-+ goto end;
-+ /* LM_DBG("br_xname:%.*s is not there, using xname:%.*s\n", br_xname.len,
-+ br_xname.s, xname->len, xname->s); */
- }
-
- if(xavp->val.type != SR_XTYPE_XAVP) {
- LM_ERR("not xavp child type %s\n", br_xname.s);
-- goto err;
-+ xavp = NULL;
-+ goto end;
- }
-
-- sub = xavp_get_by_index(name, idx, &xavp->val.v.xavp);
--
-+end:
- pvh_str_free(&br_xname);
-- return sub ? &sub->val : NULL;
-+ return xavp;
-+}
-
--err:
-- pvh_str_free(&br_xname);
-- return NULL;
-+sr_xval_t *pvh_xavp_get_value(
-+ struct sip_msg *msg, str *xname, str *name, int idx)
-+{
-+ sr_xavp_t *xavp = NULL;
-+ sr_xavp_t *sub = NULL;
-+
-+ if((xavp = pvh_xavp_get(msg, xname)) != NULL) {
-+ /* LM_DBG("xavp:%.*s name:%.*s idx:%d\n", xavp->name.len, xavp->name.s,
-+ name->len, name->s, idx); */
-+ sub = xavp_get_by_index(name, idx, &xavp->val.v.xavp);
-+ }
-+
-+ return sub ? &sub->val : NULL;
- }
-
- sr_xavp_t *pvh_xavp_get_child(struct sip_msg *msg, str *xname, str *name)
-@@ -146,8 +160,16 @@ sr_xavp_t *pvh_xavp_get_child(struct sip_msg *msg, str *xname, str *name)
-
- pvh_get_branch_xname(msg, xname, &br_xname);
- xavp = xavp_get_child(&br_xname, name);
-- if(xavp == NULL)
-- xavp = xavp_get_child(xname, name);
-+ if(xavp == NULL) {
-+ if(cmp_str(xname, &br_xname) != 0) {
-+ xavp = xavp_get_child(xname, name);
-+ /*
-+ if(xavp) {
-+ LM_DBG("br_xname:%.*s is not there, using xname:%.*s\n",
-+ br_xname.len, br_xname.s, xname->len, xname->s);
-+ } */
-+ }
-+ }
-
- pvh_str_free(&br_xname);
- return xavp;
-@@ -290,7 +312,9 @@ int pvh_set_xavp(struct sip_msg *msg, str *xname, str *name, void *data,
- root = xavp_get(&br_xname, NULL);
-
- if(root == NULL && br_idx > 0) {
-- pvh_clone_branch_xavp(msg, xname);
-+ LM_DBG("clone xavp:%.*s br_xname:%.*s\n", xname->len, xname->s,
-+ br_xname.len, br_xname.s);
-+ pvh_clone_branch_xavp(msg, xname, &br_xname);
- root = xavp_get(&br_xname, NULL);
- }
-
-@@ -401,13 +425,12 @@ int pvh_get_branch_xname(struct sip_msg *msg, str *xname, str *dst)
- return 1;
- }
-
--int pvh_clone_branch_xavp(struct sip_msg *msg, str *xname)
-+int pvh_clone_branch_xavp(struct sip_msg *msg, str *xname, str *br_xname)
- {
- sr_xavp_t *xavp = NULL;
- sr_xavp_t *br_xavp = NULL;
- sr_xavp_t *sub = NULL;
- sr_xval_t root_xval;
-- str br_xname = STR_NULL;
-
- if((xavp = xavp_get(xname, NULL)) == NULL) {
- LM_ERR("cannot clone xavp from non existing %s\n", xname->s);
-@@ -424,21 +447,17 @@ int pvh_clone_branch_xavp(struct sip_msg *msg, str *xname)
- return -1;
- }
-
-- if(pvh_str_new(&br_xname, header_name_size) < 0)
-- return -1;
-- pvh_get_branch_xname(msg, xname, &br_xname);
--
- memset(&root_xval, 0, sizeof(sr_xval_t));
- root_xval.type = SR_XTYPE_XAVP;
- root_xval.v.xavp = NULL;
-
-- if((br_xavp = xavp_add_value(&br_xname, &root_xval, NULL)) == NULL) {
-- LM_ERR("error create xavp %s\n", br_xname.s);
-- goto err;
-+ if((br_xavp = xavp_add_value(br_xname, &root_xval, NULL)) == NULL) {
-+ LM_ERR("error create xavp %s\n", br_xname->s);
-+ return -1;
- }
-
- if(strncmp(xname->s, xavp_parsed_xname.s, xname->len) == 0) {
-- pvh_str_free(&br_xname);
-+ LM_DBG("skip clone\n");
- return 1;
- }
-
-@@ -450,16 +469,11 @@ int pvh_clone_branch_xavp(struct sip_msg *msg, str *xname)
- if(pvh_xavp_append_value(&sub->name, &sub->val, &br_xavp->val.v.xavp)
- < 0) {
- LM_ERR("cannot clone xavp %s\n", sub->name.s);
-- goto err;
-+ return -1;
- }
- } while((sub = sub->next) != NULL);
-
-- pvh_str_free(&br_xname);
- return 1;
--
--err:
-- pvh_str_free(&br_xname);
-- return -1;
- }
-
- int pvh_get_header(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
-@@ -612,6 +626,34 @@ err:
- return -1;
- }
-
-+xavp_c_data_t *pvh_set_parsed(
-+ struct sip_msg *msg, str *hname, str *cur, str *new)
-+{
-+ xavp_c_data_t *c_data = NULL;
-+ str *val = new;
-+
-+ c_data = (xavp_c_data_t *)shm_malloc(sizeof(xavp_c_data_t));
-+ if(c_data == NULL) {
-+ SHM_MEM_ERROR;
-+ return NULL;
-+ }
-+ memset(c_data, 0, sizeof(xavp_c_data_t));
-+ if(val == NULL)
-+ val = cur;
-+ if(pvh_merge_uri(msg, SET_URI_T, cur, val, c_data) < 0)
-+ goto err;
-+ if(pvh_set_xavp(msg, &xavp_parsed_xname, hname, c_data, SR_XTYPE_DATA, 0, 0)
-+ < 0)
-+ goto err;
-+ LM_DBG("c_data from pvh_merge_uri hname:%.*s\n", hname->len, hname->s);
-+
-+ return c_data;
-+
-+err:
-+ // how can I call?? pvh_xavp_free_data(c_data, shm_free);
-+ return NULL;
-+}
-+
- int pvh_get_uri(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
- {
- sr_xval_t *xval = NULL;
-@@ -633,31 +675,29 @@ int pvh_get_uri(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
- pvh_str_copy(&hname, &_hdr_to, header_name_size);
-
- xval = pvh_xavp_get_value(msg, &xavp_name, &hname, 0);
-- if(xval == NULL || !xval->v.s.s)
-+ if(xval == NULL || !xval->v.s.s) {
-+ /* LM_DBG("xavp:%.*s hname:%.*s is null\n", xavp_name.len, xavp_name.s,
-+ hname.len, hname.s); */
- goto err;
-+ }
-
- xval_pd = pvh_xavp_get_value(msg, &xavp_parsed_xname, &hname, 0);
-
-- if(xval_pd)
-+ if(xval_pd) {
-+ /* LM_DBG("p_no:%d c_data from xavp_parsed_xname hname:%.*s\n", p_no,
-+ hname.len, hname.s); */
- c_data = (xavp_c_data_t *)xval_pd->v.data->p;
-+ }
-
- if(c_data != NULL
- && strncmp(xval->v.s.s, c_data->value.s, c_data->value.len) != 0) {
-+ /* LM_DBG("xval:%.*s != c_data->value:%.*s\n", xval->v.s.len, xval->v.s.s,
-+ c_data->value.len, c_data->value.s); */
- c_data = NULL;
- }
-
- if(c_data == NULL) {
-- c_data = (xavp_c_data_t *)shm_malloc(sizeof(xavp_c_data_t));
-- if(c_data == NULL) {
-- SHM_MEM_ERROR;
-- goto err;
-- }
-- memset(c_data, 0, sizeof(xavp_c_data_t));
-- if(pvh_merge_uri(msg, SET_URI_T, &xval->v.s, &xval->v.s, c_data) < 0)
-- goto err;
-- if(pvh_set_xavp(
-- msg, &xavp_parsed_xname, &hname, c_data, SR_XTYPE_DATA, 0, 0)
-- < 0)
-+ if((c_data = pvh_set_parsed(msg, &hname, &xval->v.s, NULL)) == NULL)
- goto err;
- }
-
-@@ -685,7 +725,7 @@ int pvh_get_uri(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
- default:
- LM_ERR("unknown get uri op\n");
- }
--
-+ /* LM_DBG("p_no:%d sval:%.*s\n", p_no, sval.len, sval.s); */
- pvh_str_free(&hname);
- return sval.s ? is_strint ? pv_get_strintval(msg, param, res, &sval, ival)
- : pv_get_strval(msg, param, res, &sval)
-@@ -763,7 +803,8 @@ int pvh_set_uri(struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val)
- memset(c_data, 0, sizeof(xavp_c_data_t));
- if(pvh_merge_uri(msg, a_type, &xval->v.s, &fval, c_data) < 0)
- goto err;
--
-+ /* LM_DBG("xavp:%.*s hname:%.*s value:%.*s\n", xavp_name.len, xavp_name.s,
-+ hname.len, hname.s, c_data->value.len, c_data->value.s); */
- if(pvh_set_xavp(msg, &xavp_name, &hname, &c_data->value, SR_XTYPE_STR, 0, 0)
- < 0)
- goto err;
-diff --git a/src/modules/pv_headers/pvh_xavp.h b/src/modules/pv_headers/pvh_xavp.h
-index 1245a1a..d9e9299 100644
---- a/src/modules/pv_headers/pvh_xavp.h
-+++ b/src/modules/pv_headers/pvh_xavp.h
-@@ -33,6 +33,7 @@
- sr_xavp_t *pvh_xavp_new_value(str *name, sr_xval_t *val);
- int pvh_xavp_append_value(str *name, sr_xval_t *val, sr_xavp_t **start);
- int pvh_xavp_set_value(str *name, sr_xval_t *val, int idx, sr_xavp_t **start);
-+sr_xavp_t *pvh_xavp_get(struct sip_msg *msg, str *xname);
- sr_xval_t *pvh_xavp_get_value(
- struct sip_msg *msg, str *xname, str *name, int idx);
- sr_xavp_t *pvh_xavp_get_child(struct sip_msg *msg, str *xname, str *name);
-@@ -48,6 +49,8 @@ int pvh_parse_header_name(pv_spec_p sp, str *hname);
- int pvh_get_header(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
- int pvh_set_header(
- struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val);
-+xavp_c_data_t *pvh_set_parsed(
-+ struct sip_msg *msg, str *hname, str *cur, str *new);
- int pvh_get_uri(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
- int pvh_set_uri(
- struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val);
-@@ -59,6 +62,6 @@ int pvh_set_reply_sr(
-
- int pvh_get_branch_index(struct sip_msg *msg, int *br_idx);
- int pvh_get_branch_xname(struct sip_msg *msg, str *xname, str *dst);
--int pvh_clone_branch_xavp(struct sip_msg *msg, str *xname);
-+int pvh_clone_branch_xavp(struct sip_msg *msg, str *xname, str *br_xname);
-
- #endif /* PV_XAVP_H */
diff --git a/debian/patches/sipwise/fix_error_in_cfgt_module.patch b/debian/patches/upstream/cfgt-don-t-process-non-sip-messages.patch
similarity index 96%
rename from debian/patches/sipwise/fix_error_in_cfgt_module.patch
rename to debian/patches/upstream/cfgt-don-t-process-non-sip-messages.patch
index 7f0723426..a4841beb2 100644
--- a/debian/patches/sipwise/fix_error_in_cfgt_module.patch
+++ b/debian/patches/upstream/cfgt-don-t-process-non-sip-messages.patch
@@ -1,14 +1,15 @@
+From 57dbfba97f03370db3ad36e1d52f85f725f12972 Mon Sep 17 00:00:00 2001
From: Sipwise Development Team
Date: Fri, 29 Nov 2019 11:23:36 +0100
-Subject: fix_error_in_cfgt_module
+Subject: [PATCH] cfgt: don't process non-sip messages
-Change-Id: I5deab153a0c17117be1d2f4de8ca84f9134a5d00
+* Skip OPTION messages internally generated
---
- src/modules/cfgt/cfgt_int.c | 103 ++++++++++++++++++++++++++++++++++++++++----
+ src/modules/cfgt/cfgt_int.c | 103 +++++++++++++++++++++++++++++++++---
1 file changed, 95 insertions(+), 8 deletions(-)
diff --git a/src/modules/cfgt/cfgt_int.c b/src/modules/cfgt/cfgt_int.c
-index 5f73a05..382d696 100644
+index 5f73a05bc8..382d696f53 100644
--- a/src/modules/cfgt/cfgt_int.c
+++ b/src/modules/cfgt/cfgt_int.c
@@ -30,6 +30,11 @@
@@ -223,3 +224,6 @@ index 5f73a05..382d696 100644
LM_ERR("node empty\n");
return -1;
}
+--
+2.20.1
+
diff --git a/debian/patches/sipwise/rtpengine-flags-for-everything.patch b/debian/patches/upstream/rtpengine-add-flags-field-for-every-command.patch
similarity index 53%
rename from debian/patches/sipwise/rtpengine-flags-for-everything.patch
rename to debian/patches/upstream/rtpengine-add-flags-field-for-every-command.patch
index 5ce4726f4..f4bce081a 100644
--- a/debian/patches/sipwise/rtpengine-flags-for-everything.patch
+++ b/debian/patches/upstream/rtpengine-add-flags-field-for-every-command.patch
@@ -1,6 +1,17 @@
+From 498d7649339edfc07f40fe3e37e66376b2817d6c Mon Sep 17 00:00:00 2001
+From: Richard Fuchs
+Date: Tue, 14 Apr 2020 13:15:21 -0400
+Subject: [PATCH] rtpengine: add `flags` field for every command
+
+---
+ src/modules/rtpengine/rtpengine.c | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+diff --git a/src/modules/rtpengine/rtpengine.c b/src/modules/rtpengine/rtpengine.c
+index 7be7968660..d56e88e003 100644
--- a/src/modules/rtpengine/rtpengine.c
+++ b/src/modules/rtpengine/rtpengine.c
-@@ -2401,8 +2401,9 @@
+@@ -2401,8 +2401,9 @@ static bencode_item_t *rtpp_function_call(bencode_buffer_t *bencbuf, struct sip_
bencode_list_add_string(item, "load limit");
body.s = NULL;
@@ -11,7 +22,7 @@
ng_flags.direction = bencode_list(bencbuf);
ng_flags.replace = bencode_list(bencbuf);
ng_flags.rtcp_mux = bencode_list(bencbuf);
-@@ -2428,11 +2429,6 @@
+@@ -2428,11 +2429,6 @@ static bencode_item_t *rtpp_function_call(bencode_buffer_t *bencbuf, struct sip_
else
bencode_dictionary_add_str(ng_flags.dict, "sdp", &body);
}
@@ -23,3 +34,6 @@
/*** parse flags & build dictionary ***/
+--
+2.20.1
+