summaryrefslogtreecommitdiffstats
path: root/tinySIP/src/tsip_uri.c
diff options
context:
space:
mode:
Diffstat (limited to 'tinySIP/src/tsip_uri.c')
-rw-r--r--tinySIP/src/tsip_uri.c345
1 files changed, 345 insertions, 0 deletions
diff --git a/tinySIP/src/tsip_uri.c b/tinySIP/src/tsip_uri.c
new file mode 100644
index 0000000..90d9859
--- /dev/null
+++ b/tinySIP/src/tsip_uri.c
@@ -0,0 +1,345 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tsip_uri.c
+ * @brief SIP/SIPS/TEL URI.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tinysip/tsip_uri.h"
+
+#include "tinysip/parsers/tsip_parser_uri.h"
+
+#include "tsk_debug.h"
+#include "tsk_memory.h"
+#include "tsk_string.h"
+#include "tsk_params.h"
+#include "tsk_url.h"
+
+#include <string.h>
+
+/**@defgroup tsip_uri_group SIP/SIPS/TEL URI
+*/
+
+
+/**@ingroup tsip_uri_group
+* Creates new empty SIP/SIPS/TEL URI. You should use @ref tsip_uri_parse() to create an URI from a buffer.
+* @param type The type of the URI to create.
+* @retval @ref tsip_uri_t* object if succeed and Null otherwise.
+* @sa @ref tsip_uri_parse()
+*/
+tsip_uri_t* tsip_uri_create(tsip_uri_type_t type)
+{
+ return tsk_object_new(tsip_uri_def_t, type);
+}
+
+/* internal function used to serialize a SIP/SIPS/TEL URI */
+int __tsip_uri_serialize(const tsip_uri_t *uri, tsk_bool_t with_params, tsk_buffer_t *output)
+{
+ tsk_istr_t port;
+
+ if(uri->port){
+ tsk_itoa(uri->port, &port);
+ }
+
+ /* sip:alice:secretword@atlanta.com:65535 */
+ tsk_buffer_append_2(output, "%s:%s%s%s%s%s%s%s%s%s",
+
+ uri->scheme ? uri->scheme : "sip", /* default scheme is sip: */
+
+ uri->user_name ? uri->user_name : "",
+
+ uri->password ? ":" : "",
+ uri->password ? uri->password : "",
+
+ uri->host ? (uri->user_name ? "@" : "") : "",
+ uri->host_type == host_ipv6 ? "[" : "",
+ uri->host ? uri->host : "",
+ uri->host_type == host_ipv6 ? "]" : "",
+
+ uri->port ? ":" : "",
+ uri->port ? port : ""
+ );
+
+ /* Params */
+ if(with_params && !TSK_LIST_IS_EMPTY(uri->params)){
+ tsk_buffer_append(output, ";", 1);
+ tsk_params_tostring(uri->params, ';', output);
+ }
+
+ return 0;
+}
+
+/**@ingroup tsip_uri_group
+* Serializes a SIP/SIPS/TEL URI to a string buffer.
+* @param uri The URI to serialize.
+* @param with_params Whether to serialize the parameters.
+* @param quote Whether to add quotes("<" and ">").
+* @param output Destination string buffer. Should be a valid buffer created using @a tsk_buffer_create() function.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tsip_uri_serialize(const tsip_uri_t *uri, tsk_bool_t with_params, tsk_bool_t quote, tsk_buffer_t *output)
+{
+ if(uri && output){
+ int ret = 0;
+ if(quote){
+ if(uri->display_name){
+ tsk_buffer_append_2(output, "\"%s\"", uri->display_name);
+ }
+
+ tsk_buffer_append(output, "<", 1);
+ ret = __tsip_uri_serialize(uri, with_params, output);
+ tsk_buffer_append(output, ">", 1);
+ }
+ else{
+ ret = __tsip_uri_serialize(uri, with_params, output);
+ }
+ return ret;
+ }
+ else{
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+}
+
+/**@ingroup tsip_uri_group
+* Converts a SIP/SIPS/TEL URI object to a string.
+* @param uri The URI to convert.
+* @param with_params Whether to include the parameters.
+* @param quote Whether to add quotes("<" and ">").
+* @retval Pointer to a string if succeed and Null otherwise. It's up to the caller to free the returned string.
+*/
+char* tsip_uri_tostring(const tsip_uri_t *uri, tsk_bool_t with_params, tsk_bool_t quote)
+{
+ tsk_buffer_t *output = tsk_buffer_create_null();
+ char* ret = 0;
+
+ if(!tsip_uri_serialize(uri, with_params, quote, output)){
+ ret = tsk_strndup((const char*)output->data, output->size);
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to serialize URI.");
+ }
+
+ TSK_OBJECT_SAFE_FREE(output);
+ return ret;
+}
+
+/**@ingroup tsip_uri_group
+* Clones a SIP/SIPS/TEL URI object.
+* @param uri The URI to clone.
+* @param with_params Whether to include the parameters.
+* @param quote Whether to add quotes("<" and ">") and display name.
+* @retval New URI object if succeed and Null otherwise.
+*/
+tsip_uri_t *tsip_uri_clone(const tsip_uri_t *uri, tsk_bool_t with_params, tsk_bool_t quote)
+{
+ tsip_uri_t *newuri = tsk_null;
+ tsk_buffer_t *output = tsk_buffer_create_null();
+ if((tsip_uri_serialize(uri, with_params, quote, output)) == 0){
+ newuri = tsip_uri_parse(output->data, output->size);
+ }
+ TSK_OBJECT_SAFE_FREE(output);
+
+ return newuri;
+}
+
+
+
+
+
+
+
+
+//========================================================
+// SIP/SIPS/TEL URI object definition
+//
+
+static tsk_object_t* tsip_uri_ctor(tsk_object_t *self, va_list * app)
+{
+ tsip_uri_t *uri = self;
+ if(uri)
+ {
+ uri->type = va_arg(*app, tsip_uri_type_t);
+ uri->params = tsk_list_create(); /* Empty list. */
+ }
+ else
+ {
+ TSK_DEBUG_ERROR("Failed to create new SIP/SIPS/TEL.");
+ }
+ return self;
+}
+
+static tsk_object_t* tsip_uri_dtor(tsk_object_t *self)
+{
+ tsip_uri_t *uri = self;
+ if(uri)
+ {
+ TSK_FREE(uri->scheme);
+ TSK_FREE(uri->host);
+ TSK_FREE(uri->user_name);
+ TSK_FREE(uri->password);
+ TSK_FREE(uri->display_name);
+ TSK_OBJECT_SAFE_FREE(uri->params);
+ }
+ else TSK_DEBUG_ERROR("Null SIP/SIPS/TEL URI.");
+
+ return self;
+}
+
+int tsip_uri_strcmp(const char* s1, const char* s2, tsk_bool_t case_sensitive)
+{
+ if(s1 && s2){
+ tsk_bool_t s1_is_encoded = tsk_false;
+ tsk_bool_t s2_is_encoded = tsk_false;
+ char* s1_decoded = (char*)s1;
+ char* s2_decoded = (char*)s2;
+ int ret;
+
+ if(tsk_strcontains(s1, tsk_strlen(s1), "%")){
+ s1_is_encoded = 1;
+ s1_decoded = tsk_url_decode(s1);
+ }
+ if(tsk_strcontains(s2, tsk_strlen(s2), "%")){
+ s2_is_encoded = 1;
+ s2_decoded = tsk_url_decode(s2);
+ }
+
+ ret = case_sensitive ? tsk_strcmp(s1_decoded, s2_decoded) : tsk_stricmp(s1_decoded, s2_decoded);
+ if(s1_is_encoded){
+ TSK_FREE(s1_decoded);
+ }
+ if(s2_is_encoded){
+ TSK_FREE(s2_decoded);
+ }
+ return ret;
+ }
+ return case_sensitive ? tsk_strcmp(s1, s2) : tsk_stricmp(s1, s2);
+}
+#define tsip_uri_strequals(s1, s2) !tsip_uri_strcmp(s1, s2, tsk_true)
+#define tsip_uri_striequals(s1, s2) !tsip_uri_strcmp(s1, s2, tsk_false)
+
+// FIXME: tel uris are compared as per RFC 3966 section 4
+static int tsip_uri_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2)
+{
+ if(obj1 && obj2){
+ const tsip_uri_t* uri1 = obj1;
+ const tsip_uri_t* uri2 = obj2;
+ const tsk_param_t* param1;
+ const tsk_param_t* param2;
+ const tsk_list_item_t *item;
+
+ /* RFC 3261 - 19.1.4 URI Comparison
+
+ Comparison of the userinfo of SIP and SIPS URIs is case-sensitive. This includes userinfo containing passwords or
+ formatted as telephone-subscribers. Comparison of all other components of the URI is case-insensitive unless explicitly
+ defined otherwise.
+
+ An IP address that is the result of a DNS lookup of a host name does not match that host name.
+
+ For two URIs to be equal, the user, password, host, and port components must match.
+
+ A URI omitting the user component will not match a URI that includes one. A URI omitting the password component will not
+ match a URI that includes one.
+
+ userinfo = ( user / telephone-subscriber ) [ ":" password ] "@"
+ */
+ if(!tsk_strequals(uri1->scheme, uri2->scheme) ||
+ !tsip_uri_strequals(uri1->user_name, uri2->user_name) ||
+ !tsip_uri_strequals(uri1->host, uri2->host) ||
+ !tsk_strequals(uri1->password, uri2->password) ||
+ uri1->port != uri2->port){
+ return -2;
+ }
+
+ /* Is there parameters */
+ if((!uri1->params && !uri2->params) || (TSK_LIST_IS_EMPTY(uri1->params) && TSK_LIST_IS_EMPTY(uri2->params))){
+ return 0;
+ }
+
+ /* RFC 3261 - 19.1.4 URI Comparison
+
+ A URI omitting any component with a default value will not match a URI explicitly containing that component with its
+ default value. For instance, a URI omitting the optional port component will not match a URI explicitly declaring port 5060.
+ The same is true for the transport-parameter, ttl-parameter, user-parameter, and method components.
+
+ - A user, ttl, or method uri-parameter appearing in only one URI never matches, even if it contains the default value.
+ - A URI that includes an maddr parameter will not match a URI that contains no maddr parameter.
+ */
+#define TSIP_URI_CMP_PARAMETER(pname) \
+ param1 = tsk_params_get_param_by_name(uri1->params, pname);\
+ param2 = tsk_params_get_param_by_name(uri2->params, pname);\
+ if((param1 || param2) && ((param1 && !param2) || (!param1 && param2) || (!tsip_uri_striequals(param1->value, param2->value)))){\
+ return -3;\
+ }
+ TSIP_URI_CMP_PARAMETER("transport");
+ TSIP_URI_CMP_PARAMETER("ttl");
+ TSIP_URI_CMP_PARAMETER("user");
+ TSIP_URI_CMP_PARAMETER("method");
+ TSIP_URI_CMP_PARAMETER("maddr");
+
+ /* RFC 3261 - 19.1.4 URI Comparison
+
+ URI uri-parameter components are compared as follows:
+
+ 1 - Any uri-parameter appearing in both URIs must match.
+ 2 - All other uri-parameters appearing in only one URI are ignored when comparing the URIs.
+
+ o URI header components are never ignored. Any present header component MUST be present in both URIs and match for the URIs
+ to match. The matching rules are defined for each header field in Section 20.
+ */
+ tsk_list_foreach(item, uri1->params)
+ {
+ param1 = item->data;
+ if((param2 = tsk_params_get_param_by_name(uri2->params, param1->name))){
+ if(!tsip_uri_striequals(param1->value, param2->value)){
+ return -4;
+ }
+ }
+ }
+ tsk_list_foreach(item, uri2->params)
+ {
+ param2 = item->data;
+ if((param1 = tsk_params_get_param_by_name(uri1->params, param2->name))){
+ if(!tsk_striequals(param1->value, param2->value)){
+ return -4;
+ }
+ }
+ }
+
+ return 0;
+ }
+ else{
+ return (!obj1 && !obj2) ? 0 : -1;
+ }
+}
+
+static const tsk_object_def_t tsip_uri_def_s =
+{
+ sizeof(tsip_uri_t),
+ tsip_uri_ctor,
+ tsip_uri_dtor,
+ tsip_uri_cmp
+};
+const tsk_object_def_t *tsip_uri_def_t = &tsip_uri_def_s;
OpenPOWER on IntegriCloud