git: d9dbd960873e - main - net/belle-sip: Update version 5.2.94=>5.4.2

From: Muhammad Moinur Rahman <bofh_at_FreeBSD.org>
Date: Thu, 27 Mar 2025 09:18:02 UTC
The branch main has been updated by bofh:

URL: https://cgit.FreeBSD.org/ports/commit/?id=d9dbd960873e847818a0d965d4ce10631e38f793

commit d9dbd960873e847818a0d965d4ce10631e38f793
Author:     Muhammad Moinur Rahman <bofh@FreeBSD.org>
AuthorDate: 2025-03-26 21:05:49 +0000
Commit:     Muhammad Moinur Rahman <bofh@FreeBSD.org>
CommitDate: 2025-03-27 09:17:04 +0000

    net/belle-sip: Update version 5.2.94=>5.4.2
    
    Changelog: https://gitlab.linphone.org/BC/public/belle-sip/-/tags/5.4.2
    
    Sponsored by:   Cybermancer Infosec
---
 net/belle-sip/Makefile                             |   17 +-
 net/belle-sip/distinfo                             |    8 +-
 net/belle-sip/files/belle_sip_headers_impl.cc      | 2516 ++++++++++++++++++++
 net/belle-sip/files/patch-CMakeLists.txt           |   18 +
 ...pl.c => patch-src_belle__sip__headers__impl.cc} |   24 +-
 .../files/patch-src_belle__sip__internal.h         |   14 +-
 net/belle-sip/files/patch-src_dns_dns.c            |   29 -
 net/belle-sip/pkg-plist                            |    8 +-
 8 files changed, 2571 insertions(+), 63 deletions(-)

diff --git a/net/belle-sip/Makefile b/net/belle-sip/Makefile
index ea30799b20e7..0e6a2dfd65e9 100644
--- a/net/belle-sip/Makefile
+++ b/net/belle-sip/Makefile
@@ -1,5 +1,5 @@
 PORTNAME=	belle-sip
-DISTVERSION=	5.2.94
+DISTVERSION=	5.4.2
 CATEGORIES=	net java
 
 MAINTAINER=	bofh@FreeBSD.org
@@ -9,23 +9,24 @@ WWW=		https://www.linphone.org/technical-corner/belle-sip.html
 LICENSE=	GPLv2+
 LICENSE_FILE=	${WRKSRC}/LICENSE.txt
 
-LIB_DEPENDS=	libantlr3c.so:devel/libantlr3c \
-		libbctoolbox.so:net/bctoolbox \
-		libbelr.so:textproc/belr
+BUILD_DEPENDS=	${LOCALBASE}/lib/libbctoolbox.a:net/bctoolbox \
+		${LOCALBASE}/lib/libbcunit.a:devel/bcunit \
+		${LOCALBASE}/lib/libbelr.a:textproc/belr
+LIB_DEPENDS=	libantlr3c.so:devel/libantlr3c
 
 USES=		cmake cpe java:build tar:bz2
 CPE_VENDOR=	linphone
 USE_GITLAB=	yes
 GL_SITE=	https://gitlab.linphone.org/BC
 GL_ACCOUNT=	public
+GL_TUPLE=	https://gitlab.linphone.org/BC/public:external:cpp-httplib:a2ed0d11c134b6c23da275103b5183b423cea8a8:httplib/tester/cpp-httplib
 USE_LDCONFIG=	yes
 
 CMAKE_ARGS=	-DCMAKE_PREFIX_PATH=${LOCALBASE} \
-		-DENABLE_STATIC=NO \
 		-DENABLE_STRICT=NO \
-		-DENABLE_TESTS=NO
+		-DENABLE_TESTS=NO \
+		-DENABLE_UNIT_TESTS=NO
 
-post-patch:
-	@${REINPLACE_CMD} '/clock_gettime/d' ${WRKSRC}/CMakeLists.txt
+LDFLAGS+=	-lpthread
 
 .include <bsd.port.mk>
diff --git a/net/belle-sip/distinfo b/net/belle-sip/distinfo
index f204584637eb..22350636883a 100644
--- a/net/belle-sip/distinfo
+++ b/net/belle-sip/distinfo
@@ -1,3 +1,5 @@
-TIMESTAMP = 1690557657
-SHA256 (belle-sip-5.2.94.tar.bz2) = d94d4310a48162f480d60076867f325e99ac256d4a871d8e1062810c63e90f80
-SIZE (belle-sip-5.2.94.tar.bz2) = 3436258
+TIMESTAMP = 1743022710
+SHA256 (belle-sip-5.4.2.tar.bz2) = a8d74d193a3ac71c338c69b4047e91e59c1af9eb9640a2882aee4be8a6c5a889
+SIZE (belle-sip-5.4.2.tar.bz2) = 655526
+SHA256 (external-cpp-httplib-a2ed0d11c134b6c23da275103b5183b423cea8a8_GL0.tar.gz) = 9b4db463ede003979bd5ea9ec97c7b80e06b1d6da3f05ce39c43670c6807a0f0
+SIZE (external-cpp-httplib-a2ed0d11c134b6c23da275103b5183b423cea8a8_GL0.tar.gz) = 1153181
diff --git a/net/belle-sip/files/belle_sip_headers_impl.cc b/net/belle-sip/files/belle_sip_headers_impl.cc
new file mode 100644
index 000000000000..a660aa132a41
--- /dev/null
+++ b/net/belle-sip/files/belle_sip_headers_impl.cc
@@ -0,0 +1,2516 @@
+/*
+ * Copyright (c) 2012-2024 Belledonne Communications SARL.
+ *
+ * This file is part of belle-sip.
+ *
+ * This program 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "belle-sip/headers.h"
+#include "belle-sip/parameters.h"
+#include "sip/sip_parser.hh"
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "belle_sip_internal.h"
+#include "listeningpoint_internal.h"
+
+/************************
+ * header
+ ***********************/
+
+GET_SET_STRING(belle_sip_header, name);
+#define PROTO_SIP 0x1
+#define PROTO_HTTP 0x1 << 1
+typedef belle_sip_header_t *(*header_parse_func)(const char *);
+
+struct header_name_func_pair {
+	int protocol;
+	const char *name;
+	header_parse_func func;
+};
+
+static struct header_name_func_pair header_table[] = {
+    {PROTO_SIP, "m", (header_parse_func)belle_sip_header_contact_parse},
+    {PROTO_SIP, BELLE_SIP_CONTACT, (header_parse_func)belle_sip_header_contact_parse},
+    {PROTO_SIP, "f", (header_parse_func)belle_sip_header_from_parse},
+    {PROTO_SIP, BELLE_SIP_FROM, (header_parse_func)belle_sip_header_from_parse},
+    {PROTO_SIP, "t", (header_parse_func)belle_sip_header_to_parse},
+    {PROTO_SIP, BELLE_SIP_TO, (header_parse_func)belle_sip_header_to_parse},
+    {PROTO_SIP, "d", (header_parse_func)belle_sip_header_diversion_parse},
+    {PROTO_SIP, BELLE_SIP_DIVERSION, (header_parse_func)belle_sip_header_diversion_parse},
+    {PROTO_SIP, "i", (header_parse_func)belle_sip_header_call_id_parse},
+    {PROTO_SIP, BELLE_SIP_CALL_ID, (header_parse_func)belle_sip_header_call_id_parse},
+    {PROTO_SIP, "r", (header_parse_func)belle_sip_header_retry_after_parse},
+    {PROTO_SIP, BELLE_SIP_RETRY_AFTER, (header_parse_func)belle_sip_header_retry_after_parse},
+    {PROTO_SIP, "l", (header_parse_func)belle_sip_header_content_length_parse},
+    {PROTO_SIP | PROTO_HTTP, BELLE_SIP_CONTENT_LENGTH, (header_parse_func)belle_sip_header_content_length_parse},
+    {PROTO_SIP, "c", (header_parse_func)belle_sip_header_content_type_parse},
+    {PROTO_SIP | PROTO_HTTP, BELLE_SIP_CONTENT_TYPE, (header_parse_func)belle_sip_header_content_type_parse},
+    {PROTO_SIP, BELLE_SIP_CSEQ, (header_parse_func)belle_sip_header_cseq_parse},
+    {PROTO_SIP, BELLE_SIP_ROUTE, (header_parse_func)belle_sip_header_route_parse},
+    {PROTO_SIP, BELLE_SIP_RECORD_ROUTE, (header_parse_func)belle_sip_header_record_route_parse},
+    {PROTO_SIP, "v", (header_parse_func)belle_sip_header_via_parse},
+    {PROTO_SIP, BELLE_SIP_VIA, (header_parse_func)belle_sip_header_via_parse},
+    {PROTO_SIP, "x", (header_parse_func)belle_sip_header_session_expires_parse},
+    {PROTO_SIP, BELLE_SIP_SESSION_EXPIRES, (header_parse_func)belle_sip_header_session_expires_parse},
+    {PROTO_SIP, BELLE_SIP_AUTHORIZATION, (header_parse_func)belle_sip_header_authorization_parse},
+    {PROTO_SIP, BELLE_SIP_PROXY_AUTHORIZATION, (header_parse_func)belle_sip_header_proxy_authorization_parse},
+    {PROTO_SIP | PROTO_HTTP, BELLE_SIP_WWW_AUTHENTICATE, (header_parse_func)belle_sip_header_www_authenticate_parse},
+    {PROTO_SIP | PROTO_HTTP, BELLE_SIP_PROXY_AUTHENTICATE,
+     (header_parse_func)belle_sip_header_proxy_authenticate_parse},
+    {PROTO_SIP, BELLE_SIP_MAX_FORWARDS, (header_parse_func)belle_sip_header_max_forwards_parse},
+    {PROTO_SIP | PROTO_HTTP, BELLE_SIP_USER_AGENT, (header_parse_func)belle_sip_header_user_agent_parse},
+    {PROTO_SIP, BELLE_SIP_EXPIRES, (header_parse_func)belle_sip_header_expires_parse},
+    {PROTO_SIP | PROTO_HTTP, BELLE_SIP_ALLOW, (header_parse_func)belle_sip_header_allow_parse},
+    {PROTO_SIP, BELLE_SIP_SUBSCRIPTION_STATE, (header_parse_func)belle_sip_header_subscription_state_parse},
+    {PROTO_SIP, BELLE_SIP_SERVICE_ROUTE, (header_parse_func)belle_sip_header_service_route_parse},
+    {PROTO_SIP, BELLE_SIP_REFER_TO, (header_parse_func)belle_sip_header_refer_to_parse},
+    {PROTO_SIP, BELLE_SIP_REFERRED_BY, (header_parse_func)belle_sip_header_referred_by_parse},
+    {PROTO_SIP, BELLE_SIP_REPLACES, (header_parse_func)belle_sip_header_replaces_parse},
+    {PROTO_SIP | PROTO_HTTP, BELLE_SIP_DATE, (header_parse_func)belle_sip_header_date_parse},
+    {PROTO_SIP, BELLE_SIP_P_PREFERRED_IDENTITY, (header_parse_func)belle_sip_header_p_preferred_identity_parse},
+    {PROTO_SIP, BELLE_SIP_PRIVACY, (header_parse_func)belle_sip_header_privacy_parse},
+    {PROTO_SIP, BELLE_SIP_EVENT, (header_parse_func)belle_sip_header_event_parse},
+    {PROTO_SIP, "o", (header_parse_func)belle_sip_header_event_parse},
+    {PROTO_SIP, BELLE_SIP_SUPPORTED, (header_parse_func)belle_sip_header_supported_parse},
+    {PROTO_SIP, "k", (header_parse_func)belle_sip_header_supported_parse},
+    {PROTO_SIP, BELLE_SIP_REQUIRE, (header_parse_func)belle_sip_header_require_parse},
+    {PROTO_SIP, BELLE_SIP_CONTENT_DISPOSITION, (header_parse_func)belle_sip_header_content_disposition_parse},
+    {PROTO_SIP | PROTO_HTTP, BELLE_SIP_ACCEPT, (header_parse_func)belle_sip_header_accept_parse},
+    {PROTO_SIP, BELLE_SIP_REASON, (header_parse_func)belle_sip_header_reason_parse},
+    {PROTO_SIP, BELLE_SIP_AUTHENTICATION_INFO, (header_parse_func)belle_sip_header_authentication_info_parse}};
+
+static belle_sip_header_t *belle_header_create(const char *name, const char *value, int protocol) {
+	size_t i;
+	belle_sip_header_t *ret;
+	size_t elements = sizeof(header_table) / sizeof(struct header_name_func_pair);
+
+	if (!name || name[0] == '\0') {
+		belle_sip_error("Cannot create header without name");
+		return NULL;
+	}
+
+	for (i = 0; i < elements; i++) {
+		if ((header_table[i].protocol & protocol) && strcasecmp(header_table[i].name, name) == 0) {
+			char *raw = belle_sip_strdup_printf("%s:%s", name, value);
+			ret = header_table[i].func(raw);
+			belle_sip_free(raw);
+			return ret;
+		}
+	}
+	/*not a known header*/
+	return BELLE_SIP_HEADER(belle_sip_header_extension_create(name, value));
+}
+
+belle_sip_header_t *belle_sip_header_create(const char *name, const char *value) {
+	return belle_header_create(name, value, PROTO_SIP);
+}
+
+belle_sip_header_t *belle_http_header_create(const char *name, const char *value) {
+	return belle_header_create(name, value, PROTO_HTTP);
+}
+
+void belle_sip_header_init(belle_sip_header_t *header) {
+}
+
+static void belle_sip_header_clone(belle_sip_header_t *header, const belle_sip_header_t *orig) {
+	CLONE_STRING(belle_sip_header, name, header, orig)
+	if (belle_sip_header_get_next(orig)) {
+		belle_sip_header_set_next(
+		    header, BELLE_SIP_HEADER(belle_sip_object_clone(BELLE_SIP_OBJECT(belle_sip_header_get_next(orig)))));
+	}
+}
+
+static void belle_sip_header_destroy(belle_sip_header_t *header) {
+	if (header->name) belle_sip_free(header->name);
+	if (header->unparsed_value) belle_sip_free(header->unparsed_value);
+	if (header->next) belle_sip_object_unref(BELLE_SIP_OBJECT(header->next));
+}
+
+void belle_sip_header_set_next(belle_sip_header_t *header, belle_sip_header_t *next) {
+	if (next) belle_sip_object_ref(next);
+	if (header->next) belle_sip_object_unref(header->next);
+	header->next = next;
+}
+
+void belle_sip_header_append(belle_sip_header_t *header, belle_sip_header_t *next) {
+	auto current = header;
+	while (current->next)
+		current = current->next;
+	belle_sip_header_set_next(current, next);
+}
+
+belle_sip_header_t *belle_sip_header_get_next(const belle_sip_header_t *header) {
+	return header->next;
+}
+
+const char *belle_sip_header_get_unparsed_value(belle_sip_header_t *obj) {
+	if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(obj, belle_sip_header_extension_t)) {
+		return belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(obj));
+	} else {
+		char *tmp = belle_sip_object_to_string(obj);
+		char *ret;
+		if (obj->unparsed_value) {
+			belle_sip_free(obj->unparsed_value);
+			obj->unparsed_value = NULL;
+		}
+		obj->unparsed_value = tmp;
+		ret = tmp;
+		ret += strlen(obj->name) + 1; /* name + semicolon*/
+		for (; *ret == ' '; ret++) {
+		}; /*skip spaces*/
+		return ret;
+	}
+}
+
+belle_sip_error_code
+belle_sip_header_marshal(belle_sip_header_t *header, char *buff, size_t buff_size, size_t *offset) {
+	if (header->name) {
+		return belle_sip_snprintf(buff, buff_size, offset, "%s: ", header->name);
+	} else {
+		belle_sip_warning("no header name found");
+		return BELLE_SIP_OK;
+	}
+}
+
+BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_header_t);
+
+BELLE_SIP_INSTANCIATE_VPTR(belle_sip_header_t,
+                           belle_sip_object_t,
+                           belle_sip_header_destroy,
+                           belle_sip_header_clone,
+                           belle_sip_header_marshal,
+                           TRUE);
+
+BELLE_SIP_PARSE_WITH_CONTEXT_AND_RULE(header, message_header);
+
+belle_sip_header_t *belle_sip_header_new_dummy(void) {
+	return belle_sip_header_create("dummy", "dummy");
+}
+
+void belle_sip_header_set_unparsed_value(belle_sip_header_t *obj, const char *value) {
+	if (obj->unparsed_value) belle_sip_free(obj->unparsed_value);
+	if (value) {
+		obj->unparsed_value = belle_sip_strdup(value);
+	} else {
+		obj->unparsed_value = nullptr;
+	}
+}
+
+/************************
+ * header_address
+ ***********************/
+struct _belle_sip_header_address {
+	belle_sip_parameters_t base;
+	char *displayname;
+	belle_sip_uri_t *uri;
+	belle_generic_uri_t *absolute_uri;
+	unsigned char automatic;
+};
+
+static void belle_sip_header_address_init(belle_sip_header_address_t *object) {
+	belle_sip_parameters_init((belle_sip_parameters_t *)object); /*super*/
+}
+
+static void belle_sip_header_address_destroy(belle_sip_header_address_t *address) {
+	if (address->displayname) belle_sip_free(address->displayname);
+	if (address->uri) belle_sip_object_unref(address->uri);
+	if (address->absolute_uri) belle_sip_object_unref(address->absolute_uri);
+}
+
+static void _belle_sip_header_address_clone(belle_sip_header_address_t *addr, const belle_sip_header_address_t *orig) {
+	CLONE_STRING(belle_sip_header_address, displayname, addr, orig)
+	if (belle_sip_header_address_get_uri(orig)) {
+		belle_sip_header_address_set_uri(
+		    addr, BELLE_SIP_URI(belle_sip_object_clone(BELLE_SIP_OBJECT(belle_sip_header_address_get_uri(orig)))));
+	}
+	if (belle_sip_header_address_get_absolute_uri(orig)) {
+		belle_sip_header_address_set_absolute_uri(addr, BELLE_GENERIC_URI(belle_sip_object_clone(BELLE_SIP_OBJECT(
+		                                                    belle_sip_header_address_get_absolute_uri(orig)))));
+	}
+	if (belle_sip_header_address_get_automatic(orig)) {
+		belle_sip_header_address_set_automatic(addr, belle_sip_header_address_get_automatic(orig));
+	}
+	belle_sip_parameters_copy_parameters_from(&addr->base, &orig->base);
+}
+belle_sip_header_address_t *belle_sip_header_address_clone(const belle_sip_header_address_t *orig) {
+	belle_sip_header_address_t *new_address = belle_sip_header_address_new();
+	_belle_sip_header_address_clone(new_address, orig);
+	return new_address;
+}
+
+static belle_sip_error_code _belle_sip_header_address_marshal(
+    belle_sip_header_address_t *header, char *buff, size_t buff_size, size_t *offset, int force_angle_quote) {
+	belle_sip_error_code error = BELLE_SIP_OK;
+	bool has_display_name = header->displayname != nullptr;
+
+	if (belle_sip_stack_name_addr_forced) force_angle_quote = TRUE;
+
+	/*1 display name*/
+	if (has_display_name) {
+		char *escaped_display_name = belle_sip_display_name_to_backslashed_escaped_string(header->displayname);
+		error = belle_sip_snprintf(buff, buff_size, offset, "\"%s\" ", escaped_display_name);
+		belle_sip_free(escaped_display_name);
+		if (error != BELLE_SIP_OK) return error;
+	}
+	if (header->uri || header->absolute_uri) {
+		bool has_parameters = belle_sip_parameters_get_parameter_names(&header->base);
+		bool is_sip_uri_with_headers_or_parameters =
+		    (header->uri != nullptr) &&
+		    (belle_sip_parameters_get_parameter_names((belle_sip_parameters_t *)header->uri) ||
+		     belle_sip_uri_get_header_names(header->uri));
+		bool angle_quote_required =
+		    force_angle_quote || has_display_name || is_sip_uri_with_headers_or_parameters || has_parameters;
+		/*cases where < is required*/
+		if (angle_quote_required) {
+			error = belle_sip_snprintf(buff, buff_size, offset, "%s", "<");
+			if (error != BELLE_SIP_OK) return error;
+		}
+		if (header->uri) {
+			error = belle_sip_uri_marshal(header->uri, buff, buff_size, offset);
+		} else {
+			error = belle_generic_uri_marshal(header->absolute_uri, buff, buff_size, offset);
+		}
+		if (error != BELLE_SIP_OK) return error;
+		if (angle_quote_required) {
+			error = belle_sip_snprintf(buff, buff_size, offset, "%s", ">");
+			if (error != BELLE_SIP_OK) return error;
+		}
+	}
+	error = belle_sip_parameters_marshal(&header->base, buff, buff_size, offset);
+	if (error != BELLE_SIP_OK) return error;
+	return error;
+}
+
+belle_sip_error_code
+belle_sip_header_address_marshal(belle_sip_header_address_t *header, char *buff, size_t buff_size, size_t *offset) {
+	return _belle_sip_header_address_marshal(header, buff, buff_size, offset, FALSE);
+}
+#define belle_sip_header_address_clone                                                                                 \
+	_belle_sip_header_address_clone /*because public clone function is not the one to be used internally*/
+BELLE_SIP_NEW_HEADER(header_address, parameters, "header_address");
+BELLE_SIP_ADDRESS_PARSE(header_address);
+GET_SET_STRING(belle_sip_header_address, displayname);
+SET_QUOTED_STRING(belle_sip_header_address, displayname);
+
+void belle_sip_header_address_set_quoted_displayname_with_slashes(belle_sip_header_address_t *address,
+                                                                  const char *value) {
+	char *unescaped_value = belle_sip_string_to_backslash_less_unescaped_string(value);
+	belle_sip_header_address_set_quoted_displayname(address, unescaped_value);
+	belle_sip_free(unescaped_value);
+}
+
+belle_sip_uri_t *belle_sip_header_address_get_uri(const belle_sip_header_address_t *address) {
+	return address->uri;
+}
+
+void belle_sip_header_address_set_uri(belle_sip_header_address_t *address, belle_sip_uri_t *uri) {
+	if (uri) belle_sip_object_ref(uri);
+	if (address->uri) {
+		belle_sip_object_unref(address->uri);
+	}
+	address->uri = uri;
+	if (address->absolute_uri && uri) {
+		belle_sip_warning("sip absolute uri [%p] already set for header_address [%p], cleaning it",
+		                  address->absolute_uri, address);
+		belle_sip_header_address_set_absolute_uri(address, NULL);
+	}
+}
+
+void belle_sip_header_address_set_automatic(belle_sip_header_address_t *address, int automatic) {
+	address->automatic = (unsigned char)automatic;
+}
+
+int belle_sip_header_address_get_automatic(const belle_sip_header_address_t *address) {
+	return address->automatic;
+}
+
+belle_generic_uri_t *belle_sip_header_address_get_absolute_uri(const belle_sip_header_address_t *address) {
+	return address->absolute_uri;
+}
+
+void belle_sip_header_address_set_absolute_uri(belle_sip_header_address_t *address, belle_generic_uri_t *absolute_uri) {
+	belle_sip_object_ref(absolute_uri);
+	if (address->absolute_uri) {
+		belle_sip_object_unref(address->absolute_uri);
+	}
+	address->absolute_uri = absolute_uri;
+	if (address->uri && absolute_uri) {
+		belle_sip_warning("sip uri [%p] already set for header_address [%p], cleaning it", address->uri, address);
+		belle_sip_header_address_set_uri(address, NULL);
+	}
+}
+
+void belle_sip_header_address_set_generic_uri(belle_sip_header_address_t *obj, belle_generic_uri_t *generic_uri) {
+	const char *scheme = belle_generic_uri_get_scheme(generic_uri);
+	if (scheme && (strcasecmp(scheme, "sip") != 0) && (strcasecmp(scheme, "sips") != 0)) {
+		belle_sip_header_address_set_absolute_uri(obj, generic_uri);
+	} else {
+		belle_sip_error("Cannot parse a sip/sips uri as a generic uri");
+		belle_sip_object_unref(generic_uri);
+	}
+}
+
+belle_sip_header_address_t *belle_sip_header_address_create(const char *display, belle_sip_uri_t *uri) {
+	belle_sip_header_address_t *address = belle_sip_header_address_new();
+	belle_sip_header_address_set_displayname(address, display);
+	belle_sip_header_address_set_uri(address, uri);
+	return address;
+}
+
+belle_sip_header_address_t *belle_sip_header_address_create2(const char *display, belle_generic_uri_t *uri) {
+	belle_sip_header_address_t *address = belle_sip_header_address_new();
+	belle_sip_header_address_set_displayname(address, display);
+	belle_sip_header_address_set_absolute_uri(address, uri);
+	return address;
+}
+
+int belle_sip_header_address_equals(const belle_sip_header_address_t *addr_a,
+                                    const belle_sip_header_address_t *addr_b) {
+	// Addresses are not identical if either is NULL
+	if (!addr_a | !addr_b) return -1;
+	belle_sip_uri_t *uri_a = belle_sip_header_address_get_uri(addr_a);
+	belle_sip_uri_t *uri_b = belle_sip_header_address_get_uri(addr_b);
+	// URIs are not identical if either is NULL
+	if (!uri_a | !uri_b) return -1;
+	const bool_t uri_equal = (belle_sip_uri_equals(uri_a, uri_b) != 0);
+
+	const char *displayname_a = belle_sip_header_address_get_displayname(addr_a);
+	const char *displayname_b = belle_sip_header_address_get_displayname(addr_b);
+	bool_t displayname_equal = FALSE;
+	if (displayname_a && displayname_b) {
+		displayname_equal = (strcmp(displayname_a, displayname_b) == 0);
+	} else if (!displayname_a & !displayname_b) {
+		displayname_equal = TRUE;
+	}
+	return ((uri_equal && displayname_equal) ? 0 : -1);
+}
+
+/*fast header address implementation*/
+
+belle_sip_header_address_t *belle_sip_header_address_fast_parse(const char *address) {
+	return belle_sip_header_address_parse(address);
+}
+
+/*
+ same as belle_sip_header_address_fast_parse but with no error log.
+ */
+belle_sip_header_address_t *belle_sip_header_address_try_fast_parse(const char *address) {
+	return belle_sip_try_header_address_parse(address);
+}
+
+belle_sip_header_address_t *belle_sip_header_address_try_parse(const char *address) {
+	return belle_sip_try_header_address_parse(address);
+}
+
+/******************************
+ * Allow header inherits from header
+ ******************************/
+struct _belle_sip_header_allow {
+	belle_sip_header_t header;
+	const char *method;
+};
+static void belle_sip_header_allow_clone(belle_sip_header_allow_t *allow, const belle_sip_header_allow_t *orig) {
+	CLONE_STRING(belle_sip_header_allow, method, allow, orig)
+}
+static void belle_sip_header_allow_destroy(belle_sip_header_allow_t *allow) {
+	if (allow->method) belle_sip_free((void *)allow->method);
+}
+
+belle_sip_error_code
+belle_sip_header_allow_marshal(belle_sip_header_allow_t *allow, char *buff, size_t buff_size, size_t *offset) {
+	belle_sip_error_code error = belle_sip_header_marshal(BELLE_SIP_HEADER(allow), buff, buff_size, offset);
+	if (error != BELLE_SIP_OK) return error;
+	error = belle_sip_snprintf(buff, buff_size, offset, "%s", allow->method);
+	if (error != BELLE_SIP_OK) return error;
+	return error;
+}
+
+BELLE_SIP_NEW_HEADER(header_allow, header, "Allow");
+BELLE_SIP_PARSE_FULL(header_allow);
+belle_sip_header_allow_t *belle_sip_header_allow_create(const char *methods) {
+	belle_sip_header_allow_t *allow = belle_sip_header_allow_new();
+	belle_sip_header_allow_set_method(allow, methods);
+	return allow;
+}
+GET_SET_STRING(belle_sip_header_allow, method);
+
+/************************
+ * Contact header object inherits from header_address
+ ***********************/
+struct _belle_sip_header_contact {
+	belle_sip_header_address_t address;
+	unsigned char wildcard;
+	unsigned char unknown;
+	unsigned char pad[2];
+};
+
+void belle_sip_header_contact_destroy(belle_sip_header_contact_t *contact) {
+}
+
+void belle_sip_header_contact_clone(belle_sip_header_contact_t *contact, const belle_sip_header_contact_t *orig) {
+	contact->wildcard = orig->wildcard;
+}
+
+belle_sip_error_code
+belle_sip_header_contact_marshal(belle_sip_header_contact_t *contact, char *buff, size_t buff_size, size_t *offset) {
+	belle_sip_error_code error = belle_sip_header_marshal(BELLE_SIP_HEADER(contact), buff, buff_size, offset);
+	if (error != BELLE_SIP_OK) return error;
+	if (contact->wildcard) {
+		error = belle_sip_snprintf(buff, buff_size, offset, "%s", "*");
+	} else {
+		error = belle_sip_header_address_marshal(&contact->address, buff, buff_size, offset);
+	}
+	return error;
+}
+
+BELLE_SIP_NEW_HEADER(header_contact, header_address, BELLE_SIP_CONTACT);
+BELLE_SIP_PARSE_WITH_CONTEXT(header_contact);
+belle_sip_header_contact_t *belle_sip_header_contact_create(const belle_sip_header_address_t *contact) {
+	belle_sip_header_contact_t *header = belle_sip_header_contact_new();
+	_belle_sip_object_copy(BELLE_SIP_OBJECT(header), BELLE_SIP_OBJECT(contact));
+	belle_sip_header_set_next(BELLE_SIP_HEADER(header), NULL);              /*make sure only one header is kept*/
+	belle_sip_header_set_name(BELLE_SIP_HEADER(header), BELLE_SIP_CONTACT); /*restaure header name*/
+	return header;
+}
+GET_SET_INT_PARAM_PRIVATE(belle_sip_header_contact, expires, int, _);
+GET_SET_INT_PARAM_PRIVATE(belle_sip_header_contact, q, float, _);
+GET_SET_BOOL(belle_sip_header_contact, wildcard, is);
+
+void belle_sip_header_contact_set_string_wildcard(belle_sip_header_contact_t *contact, const char *wildcard) {
+	if (strcmp("*", wildcard) == 0) {
+		belle_sip_header_contact_set_wildcard(contact, 1);
+	}
+}
+
+int belle_sip_header_contact_set_expires(belle_sip_header_contact_t *contact, int expires) {
+	if (expires < 0) {
+		belle_sip_error("bad expires value [%i] for contact", expires);
+		return -1;
+	}
+	_belle_sip_header_contact_set_expires(contact, expires);
+	return 0;
+}
+int belle_sip_header_contact_set_qvalue(belle_sip_header_contact_t *contact, float qValue) {
+	if (qValue != -1 && qValue < 0 && qValue > 1) {
+		belle_sip_error("bad q value [%f] for contact", qValue);
+		return -1;
+	}
+	_belle_sip_header_contact_set_q(contact, qValue);
+	return 0;
+}
+float belle_sip_header_contact_get_qvalue(const belle_sip_header_contact_t *contact) {
+	return belle_sip_header_contact_get_q(contact);
+}
+
+unsigned int belle_sip_header_contact_equals(const belle_sip_header_contact_t *a, const belle_sip_header_contact_t *b) {
+	if (!a | !b) return 0;
+	return belle_sip_uri_equals(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(a)),
+	                            belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(b)));
+}
+unsigned int belle_sip_header_contact_not_equals(const belle_sip_header_contact_t *a,
+                                                 const belle_sip_header_contact_t *b) {
+	return !belle_sip_header_contact_equals(a, b);
+}
+
+unsigned int belle_sip_header_contact_equals_with_uri_omitting(const belle_sip_header_contact_t *a,
+                                                               const belle_sip_header_contact_t *b) {
+	if (!a | !b) return 0;
+	return belle_sip_uri_equals_with_uri_omitting(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(a)),
+	                                              belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(b)));
+}
+unsigned int belle_sip_header_contact_not_equals_with_uri_omitting(const belle_sip_header_contact_t *a,
+                                                                   const belle_sip_header_contact_t *b) {
+	return !belle_sip_header_contact_equals_with_uri_omitting(a, b);
+}
+
+void belle_sip_header_contact_set_automatic(belle_sip_header_contact_t *a, int enabled) {
+	belle_sip_header_address_set_automatic((belle_sip_header_address_t *)a, enabled);
+}
+
+int belle_sip_header_contact_get_automatic(const belle_sip_header_contact_t *a) {
+	return belle_sip_header_address_get_automatic((belle_sip_header_address_t *)a);
+}
+
+void belle_sip_header_contact_set_unknown(belle_sip_header_contact_t *a, int value) {
+	a->unknown = value;
+}
+
+int belle_sip_header_contact_is_unknown(const belle_sip_header_contact_t *a) {
+	return a->unknown;
+}
+
+/**************************
+ * From header object inherits from header_address
+ ***************************/
+#define BELLE_SIP_FROM_LIKE_MARSHAL(header, force_angle_quote)                                                         \
+	belle_sip_error_code error = belle_sip_header_marshal(BELLE_SIP_HEADER(header), buff, buff_size, offset);          \
+	if (error != BELLE_SIP_OK) return error;                                                                           \
+	error = _belle_sip_header_address_marshal(&header->address, buff, buff_size, offset, force_angle_quote);           \
+	if (error != BELLE_SIP_OK) return error;                                                                           \
+	return error;
+
+struct _belle_sip_header_from {
+	belle_sip_header_address_t address;
+};
+
+static void belle_sip_header_from_destroy(belle_sip_header_from_t *from) {
+}
+
+static void belle_sip_header_from_clone(belle_sip_header_from_t *from, const belle_sip_header_from_t *cloned) {
+}
+
+belle_sip_error_code
+belle_sip_header_from_marshal(belle_sip_header_from_t *from, char *buff, size_t buff_size, size_t *offset) {
+	BELLE_SIP_FROM_LIKE_MARSHAL(from, FALSE);
+}
+
+belle_sip_header_from_t *belle_sip_header_from_create2(const char *uri, const char *tag) {
+	belle_sip_header_address_t *address = belle_sip_header_address_parse(uri);
+	if (address) {
+		belle_sip_header_from_t *from = belle_sip_header_from_create(address, tag);
+		belle_sip_object_unref(address);
+		return from;
+	} else return NULL;
+}
+belle_sip_header_from_t *belle_sip_header_from_create(const belle_sip_header_address_t *address, const char *tag) {
+	belle_sip_header_from_t *header = belle_sip_header_from_new();
+	belle_sip_uri_t *uri;
+	_belle_sip_object_copy((belle_sip_object_t *)header, (belle_sip_object_t *)address);
+	/*clear unwanted uri components*/
+	if ((uri = belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(header)))) {
+		belle_sip_parameters_t *params = BELLE_SIP_PARAMETERS(uri);
+		belle_sip_parameters_remove_parameter(params, "lr");
+		belle_sip_parameters_remove_parameter(params, "ttl");
+		belle_sip_parameters_remove_parameter(params, "method");
+		belle_sip_parameters_remove_parameter(params, "maddr");
+		belle_sip_parameters_remove_parameter(params, "transport");
+		belle_sip_uri_set_port(uri, 0);
+		belle_sip_uri_headers_clean(uri);
+	}
+	belle_sip_header_set_next(BELLE_SIP_HEADER(header), NULL);           /*make sure only one header is kept*/
+	belle_sip_header_set_name(BELLE_SIP_HEADER(header), BELLE_SIP_FROM); /*restore header name*/
+	if (tag) belle_sip_header_from_set_tag(header, tag);
+	return header;
+}
+BELLE_SIP_NEW_HEADER(header_from, header_address, BELLE_SIP_FROM);
+BELLE_SIP_PARSE_HEADER_WITH_URI_CHECK(header_from);
+GET_SET_STRING_PARAM2(belle_sip_header_from, tag, raw_tag);
+
+void belle_sip_header_from_set_random_tag(belle_sip_header_from_t *obj) {
+	char tmp[BELLE_SIP_TAG_LENGTH];
+	belle_sip_header_from_set_raw_tag(obj, belle_sip_random_token(tmp, sizeof(tmp)));
+}
+
+void belle_sip_header_from_set_tag(belle_sip_header_from_t *obj, const char *tag) {
+	if (tag == BELLE_SIP_RANDOM_TAG) belle_sip_header_from_set_random_tag(obj);
+	else belle_sip_header_from_set_raw_tag(obj, tag);
+}
+
+const char *belle_sip_header_from_get_tag(const belle_sip_header_from_t *obj) {
+	return belle_sip_header_from_get_raw_tag(obj);
+}
+
+/**************************
+ * To header object inherits from header_address
+ ***************************/
+struct _belle_sip_header_to {
+	belle_sip_header_address_t address;
+};
+
+static void belle_sip_header_to_destroy(belle_sip_header_to_t *to) {
+}
+
+void belle_sip_header_to_clone(belle_sip_header_to_t *contact, const belle_sip_header_to_t *orig) {
+}
+
+belle_sip_error_code belle_sip_header_to_marshal(belle_sip_header_to_t *to,
+                                                 char *buff,
+                                                 size_t buff_size,
+                                                 size_t *offset){BELLE_SIP_FROM_LIKE_MARSHAL(to, FALSE)}
+
+BELLE_SIP_NEW_HEADER(header_to, header_address, BELLE_SIP_TO);
+BELLE_SIP_PARSE_HEADER_WITH_URI_CHECK(header_to);
+GET_SET_STRING_PARAM2(belle_sip_header_to, tag, raw_tag);
+
+belle_sip_header_to_t *belle_sip_header_to_create2(const char *uri, const char *tag) {
+	belle_sip_header_address_t *address = belle_sip_header_address_parse(uri);
+	if (address) {
+		belle_sip_header_to_t *to = belle_sip_header_to_create(address, tag);
+		belle_sip_object_unref(address);
+		return to;
+	} else return NULL;
+}
+belle_sip_header_to_t *belle_sip_header_to_create(const belle_sip_header_address_t *address, const char *tag) {
+	belle_sip_header_to_t *header = belle_sip_header_to_new();
+	belle_sip_uri_t *uri;
+	_belle_sip_object_copy((belle_sip_object_t *)header, (belle_sip_object_t *)address);
+	/*clear unwanted uri components*/
+	if ((uri = belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(header)))) {
+		belle_sip_parameters_t *params = BELLE_SIP_PARAMETERS(uri);
+		belle_sip_parameters_remove_parameter(params, "lr");
+		belle_sip_parameters_remove_parameter(params, "ttl");
+		belle_sip_parameters_remove_parameter(params, "method");
+		belle_sip_parameters_remove_parameter(params, "maddr");
+		belle_sip_parameters_remove_parameter(params, "transport");
+		belle_sip_uri_set_port(uri, 0);
+		belle_sip_uri_headers_clean(uri);
+	}
+	belle_sip_header_set_next(BELLE_SIP_HEADER(header), NULL);         /*make sure only one header is kept*/
+	belle_sip_header_set_name(BELLE_SIP_HEADER(header), BELLE_SIP_TO); /*restaure header name*/
+	if (tag) belle_sip_header_to_set_tag(header, tag);
+	return header;
+}
+void belle_sip_header_to_set_random_tag(belle_sip_header_to_t *obj) {
+	char tmp[8];
+	/*not less than 32bit */
+	belle_sip_header_to_set_tag(obj, belle_sip_random_token(tmp, sizeof(tmp)));
+}
+
+void belle_sip_header_to_set_tag(belle_sip_header_to_t *obj, const char *tag) {
+	if (tag == BELLE_SIP_RANDOM_TAG) belle_sip_header_to_set_random_tag(obj);
+	else belle_sip_header_to_set_raw_tag(obj, tag);
+}
+
+const char *belle_sip_header_to_get_tag(const belle_sip_header_to_t *obj) {
+	return belle_sip_header_to_get_raw_tag(obj);
+}
+
+/**************************
+ * Diversion header object inherits from header_address
+ ***************************/
+struct _belle_sip_header_diversion {
+	belle_sip_header_address_t address;
+};
+
+static void belle_sip_header_diversion_destroy(belle_sip_header_diversion_t *diversion) {
+}
+
+void belle_sip_header_diversion_clone(belle_sip_header_diversion_t *contact, const belle_sip_header_diversion_t *orig) {
+}
+
+belle_sip_error_code belle_sip_header_diversion_marshal(belle_sip_header_diversion_t *diversion,
+                                                        char *buff,
+                                                        size_t buff_size,
+                                                        size_t *offset){BELLE_SIP_FROM_LIKE_MARSHAL(diversion, FALSE)}
+
+BELLE_SIP_NEW_HEADER(header_diversion, header_address, BELLE_SIP_DIVERSION) BELLE_SIP_PARSE_FULL(header_diversion);
+GET_SET_STRING_PARAM2(belle_sip_header_diversion, tag, raw_tag);
+
+belle_sip_header_diversion_t *belle_sip_header_diversion_create2(const char *uri, const char *tag) {
+	belle_sip_header_address_t *address = belle_sip_header_address_parse(uri);
+	if (address) {
+		belle_sip_header_diversion_t *diversion = belle_sip_header_diversion_create(address, tag);
+		belle_sip_object_unref(address);
+		return diversion;
+	} else return NULL;
+}
+belle_sip_header_diversion_t *belle_sip_header_diversion_create(const belle_sip_header_address_t *address,
+                                                                const char *tag) {
+	belle_sip_header_diversion_t *header = belle_sip_header_diversion_new();
+	belle_sip_uri_t *uri;
+	_belle_sip_object_copy((belle_sip_object_t *)header, (belle_sip_object_t *)address);
+	/*clear unwanted uri components*/
+	if ((uri = belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(header)))) {
+		belle_sip_parameters_t *params = BELLE_SIP_PARAMETERS(uri);
+		belle_sip_parameters_remove_parameter(params, "lr");
+		belle_sip_parameters_remove_parameter(params, "ttl");
+		belle_sip_parameters_remove_parameter(params, "method");
+		belle_sip_parameters_remove_parameter(params, "maddr");
+		belle_sip_parameters_remove_parameter(params, "transport");
+		belle_sip_uri_set_port(uri, 0);
+		belle_sip_uri_headers_clean(uri);
+	}
+	belle_sip_header_set_name(BELLE_SIP_HEADER(header), BELLE_SIP_DIVERSION); /*restaure header name*/
+	if (tag) belle_sip_header_diversion_set_tag(header, tag);
+	return header;
+}
+void belle_sip_header_diversion_set_random_tag(belle_sip_header_diversion_t *obj) {
+	char tmp[8];
+	/*not less than 32bit */
+	belle_sip_header_diversion_set_tag(obj, belle_sip_random_token(tmp, sizeof(tmp)));
+}
+
+void belle_sip_header_diversion_set_tag(belle_sip_header_diversion_t *obj, const char *tag) {
+	if (tag == BELLE_SIP_RANDOM_TAG) belle_sip_header_diversion_set_random_tag(obj);
+	else belle_sip_header_diversion_set_raw_tag(obj, tag);
+}
+
+const char *belle_sip_header_diversion_get_tag(const belle_sip_header_diversion_t *obj) {
+	return belle_sip_header_diversion_get_raw_tag(obj);
+}
+
+/******************************
+ * Session-Expires inherits from parameters
+ ******************************/
+struct _belle_sip_header_session_expires {
+	belle_sip_parameters_t params_list;
+	int delta;
+};
+
+static void belle_sip_header_session_expires_destroy(belle_sip_header_session_expires_t *session_expires) {
+}
+
+static void belle_sip_header_session_expires_clone(belle_sip_header_session_expires_t *session_expires,
+                                                   const belle_sip_header_session_expires_t *orig) {
+	session_expires->delta = orig->delta;
+	belle_sip_header_session_expires_set_refresher_value(session_expires,
+	                                                     belle_sip_header_session_expires_get_refresher_value(orig));
+}
+
+belle_sip_error_code belle_sip_header_session_expires_marshal(belle_sip_header_session_expires_t *session_expires,
+                                                              char *buff,
+                                                              size_t buff_size,
+                                                              size_t *offset) {
+	belle_sip_error_code error = belle_sip_header_marshal(BELLE_SIP_HEADER(session_expires), buff, buff_size, offset);
+
+	if (session_expires->delta) {
+		error = belle_sip_snprintf(buff, buff_size, offset, "%i", session_expires->delta);
+		if (error != BELLE_SIP_OK) return error;
+	}
+
+	error = belle_sip_parameters_marshal(&session_expires->params_list, buff, buff_size, offset);
+	if (error != BELLE_SIP_OK) return error;
+
+	return error;
+}
+
+belle_sip_header_session_expires_t *
+belle_sip_header_session_expires_create(int delta, belle_sip_header_session_expires_refresher_t refresher) {
+	belle_sip_header_session_expires_t *session_expires = belle_sip_header_session_expires_new();
+
+	belle_sip_header_session_expires_set_delta(session_expires, delta);
+	if (refresher != BELLE_SIP_HEADER_SESSION_EXPIRES_UNSPECIFIED) {
+		belle_sip_header_session_expires_set_refresher_value(session_expires, refresher);
+	}
+
+	return session_expires;
+}
+
+BELLE_SIP_PARSE_FULL(header_session_expires);
+BELLE_SIP_NEW_HEADER(header_session_expires, parameters, BELLE_SIP_SESSION_EXPIRES);
+GET_SET_STRING_PARAM(belle_sip_header_session_expires, refresher);
+GET_SET_INT(belle_sip_header_session_expires, delta, int);
+
+belle_sip_header_session_expires_refresher_t
+belle_sip_header_session_expires_get_refresher_value(const belle_sip_header_session_expires_t *session_expires) {
+	const char *refresher_value = belle_sip_header_session_expires_get_refresher(session_expires);
+
+	if (refresher_value == NULL) {
+		return BELLE_SIP_HEADER_SESSION_EXPIRES_UNSPECIFIED;
+	} else if (strcmp("uac", refresher_value) == 0) {
+		return BELLE_SIP_HEADER_SESSION_EXPIRES_UAC;
+	} else if (strcmp("uas", refresher_value) == 0) {
+		return BELLE_SIP_HEADER_SESSION_EXPIRES_UAS;
+	}
+
+	return BELLE_SIP_HEADER_SESSION_EXPIRES_UNSPECIFIED;
+}
+
+void belle_sip_header_session_expires_set_refresher_value(
+    belle_sip_header_session_expires_t *session_expires, belle_sip_header_session_expires_refresher_t refresher_value) {
+	switch (refresher_value) {
+		case BELLE_SIP_HEADER_SESSION_EXPIRES_UNSPECIFIED:
+			belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(session_expires), "refresher");
+			break;
+		case BELLE_SIP_HEADER_SESSION_EXPIRES_UAC:
+			belle_sip_header_session_expires_set_refresher(session_expires, "uac");
+			break;
+		case BELLE_SIP_HEADER_SESSION_EXPIRES_UAS:
+			belle_sip_header_session_expires_set_refresher(session_expires, "uas");
+			break;
+	}
+}
+
+/******************************
+ * User-Agent header inherits from header
+ ******************************/
+struct _belle_sip_header_user_agent {
+	belle_sip_header_t header;
+	belle_sip_list_t *products;
+};
+
+static void belle_sip_header_user_agent_destroy(belle_sip_header_user_agent_t *user_agent) {
+	belle_sip_header_user_agent_set_products(user_agent, NULL);
+}
+
+static void belle_sip_header_user_agent_clone(belle_sip_header_user_agent_t *user_agent,
+                                              const belle_sip_header_user_agent_t *orig) {
+	belle_sip_list_t *list = orig->products;
+	for (; list != NULL; list = list->next) {
+		belle_sip_header_user_agent_add_product(user_agent, (const char *)list->data);
+	}
+}
+
+belle_sip_error_code belle_sip_header_user_agent_marshal(belle_sip_header_user_agent_t *user_agent,
+                                                         char *buff,
+                                                         size_t buff_size,
+                                                         size_t *offset) {
+	belle_sip_error_code error = BELLE_SIP_OK;
+	belle_sip_list_t *list = user_agent->products;
+	error = belle_sip_header_marshal(BELLE_SIP_HEADER(user_agent), buff, buff_size, offset);
+	if (error != BELLE_SIP_OK) return error;
+	for (; list != NULL; list = list->next) {
+		error = belle_sip_snprintf(buff, buff_size, offset, list == user_agent->products ? "%s" : " %s",
+		                           (const char *)list->data);
+		if (error != BELLE_SIP_OK) return error;
+	}
+	return error;
+}
+
+BELLE_SIP_NEW_HEADER(header_user_agent, header, "User-Agent");
+BELLE_SIP_PARSE_FULL(header_user_agent);
+
+belle_sip_list_t *belle_sip_header_user_agent_get_products(const belle_sip_header_user_agent_t *user_agent) {
+	return user_agent->products;
+}
+void belle_sip_header_user_agent_set_products(belle_sip_header_user_agent_t *user_agent, belle_sip_list_t *products) {
+	belle_sip_list_t *list;
+	if (user_agent->products) {
+		for (list = user_agent->products; list != NULL; list = list->next) {
+			belle_sip_free((void *)list->data);
+		}
+		belle_sip_list_free(user_agent->products);
+	}
+	user_agent->products = products;
+}
+void belle_sip_header_user_agent_add_product(belle_sip_header_user_agent_t *user_agent, const char *product) {
+	user_agent->products = belle_sip_list_append(user_agent->products, belle_sip_strdup(product));
+}
+
+int belle_sip_header_user_agent_get_products_as_string(const belle_sip_header_user_agent_t *user_agent,
+                                                       char *value,
+                                                       unsigned int value_size) {
+	size_t result = 0;
+	belle_sip_error_code error = BELLE_SIP_OK;
*** 1782 LINES SKIPPED ***