summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2005-11-23 20:56:30 +0000
committerBenny Prijono <bennylp@teluu.com>2005-11-23 20:56:30 +0000
commit9894af102a5d2e61e7629b99b7746210a8fd3475 (patch)
tree261a8df5003bab4bd60a3218ce06f845386dc7b9
parent3366b25100e19ce91de500de827aed0606390f70 (diff)
Added tel: uri and user-defined uri parser
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@82 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjsip/build/pjsip_core.dsp10
-rw-r--r--pjsip/include/pjsip/print_util.h2
-rw-r--r--pjsip/include/pjsip/sip_config.h6
-rw-r--r--pjsip/include/pjsip/sip_parser.h7
-rw-r--r--pjsip/include/pjsip/sip_tel_uri.h71
-rw-r--r--pjsip/include/pjsip/sip_uri.h5
-rw-r--r--pjsip/include/pjsip_core.h1
-rw-r--r--pjsip/src/pjsip/sip_auth_msg.c9
-rw-r--r--pjsip/src/pjsip/sip_endpoint.c8
-rw-r--r--pjsip/src/pjsip/sip_msg.c17
-rw-r--r--pjsip/src/pjsip/sip_parser.c134
-rw-r--r--pjsip/src/pjsip/sip_tel_uri.c416
-rw-r--r--pjsip/src/pjsip/sip_uri.c12
-rw-r--r--pjsip/src/test-pjsip/test.c2
-rw-r--r--pjsip/src/test-pjsip/uri.c212
15 files changed, 850 insertions, 62 deletions
diff --git a/pjsip/build/pjsip_core.dsp b/pjsip/build/pjsip_core.dsp
index 92a6353f..8893fa00 100644
--- a/pjsip/build/pjsip_core.dsp
+++ b/pjsip/build/pjsip_core.dsp
@@ -41,7 +41,7 @@ RSC=rc.exe
# PROP Intermediate_Dir ".\output\pjsip-core-i386-win32-vc6-release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
-# ADD CPP /nologo /MD /W4 /Zi /O2 /Oy /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /FD /c
+# ADD CPP /nologo /MD /W4 /Zi /O2 /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
@@ -119,6 +119,10 @@ SOURCE=..\src\pjsip\sip_resolve.c
# End Source File
# Begin Source File
+SOURCE=..\src\pjsip\sip_tel_uri.c
+# End Source File
+# Begin Source File
+
SOURCE=..\src\pjsip\sip_transaction.c
# End Source File
# Begin Source File
@@ -199,6 +203,10 @@ SOURCE=..\include\pjsip\sip_resolve.h
# End Source File
# Begin Source File
+SOURCE=..\include\pjsip\sip_tel_uri.h
+# End Source File
+# Begin Source File
+
SOURCE=..\include\pjsip\sip_transaction.h
# End Source File
# Begin Source File
diff --git a/pjsip/include/pjsip/print_util.h b/pjsip/include/pjsip/print_util.h
index c72d1ab2..0951612a 100644
--- a/pjsip/include/pjsip/print_util.h
+++ b/pjsip/include/pjsip/print_util.h
@@ -55,7 +55,7 @@
if (str2.slen) { \
if (len1+str2.slen >= (endbuf-buf)) return -1; \
pj_memcpy(buf,str1,len1); \
- printed=pj_strncpy2_escape(buf,&str2,(endbuf-buf-len1),&unres);\
+ printed=pj_strncpy2_escape(buf+len1,&str2,(endbuf-buf-len1),&unres);\
if (printed < 0) return -1; \
buf += (printed+len1); \
} \
diff --git a/pjsip/include/pjsip/sip_config.h b/pjsip/include/pjsip/sip_config.h
index 98441918..972a080f 100644
--- a/pjsip/include/pjsip/sip_config.h
+++ b/pjsip/include/pjsip/sip_config.h
@@ -75,6 +75,12 @@
/* Module related constants. */
#define PJSIP_MAX_MODULE 8
+/* Maximum header types. */
+#define PJSIP_MAX_HEADER_TYPES 64
+
+/* Maximum URI types. */
+#define PJSIP_MAX_URI_TYPES 4
+
/*****************************************************************************
* Default timeout settings, in miliseconds.
*/
diff --git a/pjsip/include/pjsip/sip_parser.h b/pjsip/include/pjsip/sip_parser.h
index d6e46e5f..b2e49694 100644
--- a/pjsip/include/pjsip/sip_parser.h
+++ b/pjsip/include/pjsip/sip_parser.h
@@ -59,7 +59,7 @@ enum
/**
* Parser syntax error exception value.
*/
-#define PJSIP_SYN_ERR_EXCEPTION 1
+extern int PJSIP_SYN_ERR_EXCEPTION;
/**
* This structure is used to get error reporting from parser.
@@ -109,7 +109,8 @@ typedef pjsip_hdr* (pjsip_parse_hdr_func)(pjsip_parse_ctx *context);
* Most of the specification of header parser handler (pjsip_parse_hdr_func)
* also applies here (except the separator part).
*/
-typedef void* (pjsip_parse_uri_func)(pj_scanner *scanner, pj_pool_t *pool);
+typedef void* (pjsip_parse_uri_func)(pj_scanner *scanner, pj_pool_t *pool,
+ pj_bool_t parse_params);
/**
* Register header parser handler. The parser handler MUST follow the
@@ -148,7 +149,7 @@ PJ_DECL(pj_status_t) pjsip_unregister_hdr_parser( const char *hname,
*
* @return zero on success.
*/
-PJ_DECL(pj_status_t) pjsip_register_uri_parser( const char *scheme,
+PJ_DECL(pj_status_t) pjsip_register_uri_parser( char *scheme,
pjsip_parse_uri_func *func);
/**
diff --git a/pjsip/include/pjsip/sip_tel_uri.h b/pjsip/include/pjsip/sip_tel_uri.h
new file mode 100644
index 00000000..5ade09c6
--- /dev/null
+++ b/pjsip/include/pjsip/sip_tel_uri.h
@@ -0,0 +1,71 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __PJSIP_TEL_URI_H__
+#define __PJSIP_TEL_URI_H__
+
+/**
+ * @file sip_tel_uri.h
+ * @brief Tel: URI
+ */
+
+#include <pjsip/sip_uri.h>
+
+
+PJ_BEGIN_DECL
+
+/**
+ * tel: URI.
+ */
+typedef struct pjsip_tel_uri
+{
+ pjsip_uri_vptr *vptr; /**< Pointer to virtual function table. */
+ pj_str_t number; /**< Global or local phone number */
+ pj_str_t context; /**< Phone context (for local number). */
+ pj_str_t ext_param; /**< Extension param. */
+ pj_str_t isub_param; /**< ISDN sub-address param. */
+ pjsip_param other_param;/**< Other parameter. */
+} pjsip_tel_uri;
+
+
+/**
+ * Create a new tel: URI.
+ *
+ * @param pool The pool.
+ *
+ * @return New instance of tel: URI.
+ */
+PJ_DECL(pjsip_tel_uri*) pjsip_tel_uri_create(pj_pool_t *pool);
+
+/**
+ * This function compares two numbers for equality, according to rules as
+ * specified in RFC 3966.
+ *
+ * @param nb1 The first number.
+ * @param nb2 The second number.
+ *
+ * @return Zero if equal, -1 if nb1 is less than nb2, or +1 if
+ * nb1 is greater than nb2.
+ */
+PJ_DECL(int) pjsip_tel_nb_cmp(const pj_str_t *nb1, const pj_str_t *nb2);
+
+
+PJ_END_DECL
+
+
+#endif /* __PJSIP_TEL_URI_H__ */
diff --git a/pjsip/include/pjsip/sip_uri.h b/pjsip/include/pjsip/sip_uri.h
index 0e13b300..63f0dfe1 100644
--- a/pjsip/include/pjsip/sip_uri.h
+++ b/pjsip/include/pjsip/sip_uri.h
@@ -27,6 +27,7 @@
#include <pjsip/sip_types.h>
#include <pjsip/sip_config.h>
#include <pj/list.h>
+#include <pjlib-util/scanner.h>
PJ_BEGIN_DECL
@@ -102,12 +103,16 @@ PJ_DECL(void) pjsip_param_shallow_clone(pj_pool_t *pool,
* @param param_list The parameter list.
* @param buf Buffer.
* @param size Size of buffer.
+ * @param pname_unres Specification of allowed characters in pname.
+ * @param pvalue_unres Specification of allowed characters in pvalue.
* @param sep Separator character (either ';' or ',').
*
* @return The number of bytes printed, or -1 on errr.
*/
PJ_DECL(pj_ssize_t) pjsip_param_print_on(const pjsip_param *param_list,
char *buf, pj_size_t size,
+ const pj_cis_t *pname_unres,
+ const pj_cis_t *pvalue_unres,
int sep);
/**
diff --git a/pjsip/include/pjsip_core.h b/pjsip/include/pjsip_core.h
index 6ae1c2cf..8ae286a5 100644
--- a/pjsip/include/pjsip_core.h
+++ b/pjsip/include/pjsip_core.h
@@ -28,6 +28,7 @@
#include <pjsip/sip_msg.h>
#include <pjsip/sip_parser.h>
#include <pjsip/sip_resolve.h>
+#include <pjsip/sip_tel_uri.h>
#include <pjsip/sip_transaction.h>
#include <pjsip/sip_transport.h>
#include <pjsip/sip_uri.h>
diff --git a/pjsip/src/pjsip/sip_auth_msg.c b/pjsip/src/pjsip/sip_auth_msg.c
index 366bff0b..84c41cc9 100644
--- a/pjsip/src/pjsip/sip_auth_msg.c
+++ b/pjsip/src/pjsip/sip_auth_msg.c
@@ -18,6 +18,7 @@
*/
#include <pjsip/sip_auth_msg.h>
#include <pjsip/sip_auth_parser.h>
+#include <pjsip/sip_parser.h>
#include <pj/pool.h>
#include <pj/list.h>
#include <pj/string.h>
@@ -79,7 +80,9 @@ static int print_digest_credential(pjsip_digest_credential *cred, char *buf, pj_
copy_advance_pair(buf, ", qop=", 6, cred->qop);
copy_advance_pair(buf, ", nc=", 5, cred->nc);
- printed = pjsip_param_print_on(&cred->other_param, buf, endbuf-buf, ',');
+ printed = pjsip_param_print_on(&cred->other_param, buf, endbuf-buf,
+ &pjsip_PARAM_CHAR_SPEC,
+ &pjsip_PARAM_CHAR_SPEC, ',');
if (printed < 0)
return -1;
buf += printed;
@@ -231,7 +234,9 @@ static int print_digest_challenge( pjsip_digest_challenge *chal,
copy_advance_pair(buf, ",algorithm=", 11, chal->algorithm);
copy_advance_pair_quote_cond(buf, ",qop=", 5, chal->qop, '"', '"');
- printed = pjsip_param_print_on(&chal->other_param, buf, endbuf-buf, ',');
+ printed = pjsip_param_print_on(&chal->other_param, buf, endbuf-buf,
+ &pjsip_PARAM_CHAR_SPEC,
+ &pjsip_PARAM_CHAR_SPEC, ',');
if (printed < 0)
return -1;
buf += printed;
diff --git a/pjsip/src/pjsip/sip_endpoint.c b/pjsip/src/pjsip/sip_endpoint.c
index 011b3358..dae3d5b1 100644
--- a/pjsip/src/pjsip/sip_endpoint.c
+++ b/pjsip/src/pjsip/sip_endpoint.c
@@ -104,8 +104,13 @@ struct pjsip_endpoint
static void endpt_transport_callback(pjsip_endpoint*,
pj_status_t, pjsip_rx_data*);
+/* Defined in sip_parser.c */
void init_sip_parser(void);
+/* Defined in sip_tel_uri.c */
+pj_status_t pjsip_tel_uri_subsys_init(void);
+
+
/*
* This is the global handler for memory allocation failure, for pools that
* are created by the endpoint (by default, all pools ARE allocated by
@@ -377,6 +382,9 @@ PJ_DEF(pj_status_t) pjsip_endpt_create(pj_pool_factory *pf,
/* Init parser. */
init_sip_parser();
+ /* Init tel: uri */
+ pjsip_tel_uri_subsys_init();
+
/* Get name. */
if (name != NULL) {
pj_str_t temp;
diff --git a/pjsip/src/pjsip/sip_msg.c b/pjsip/src/pjsip/sip_msg.c
index 6f963abb..2dc83dda 100644
--- a/pjsip/src/pjsip/sip_msg.c
+++ b/pjsip/src/pjsip/sip_msg.c
@@ -17,6 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pjsip/sip_msg.h>
+#include <pjsip/sip_parser.h>
#include <pjsip/print_util.h>
#include <pj/string.h>
#include <pj/pool.h>
@@ -927,7 +928,9 @@ static int pjsip_contact_hdr_print( pjsip_contact_hdr *hdr, char *buf,
buf += printed + 9;
}
- printed = pjsip_param_print_on(&hdr->other_param, buf, endbuf-buf,';');
+ printed = pjsip_param_print_on(&hdr->other_param, buf, endbuf-buf,
+ &pjsip_PARAM_CHAR_SPEC,
+ &pjsip_PARAM_CHAR_SPEC, ';');
if (printed < 0)
return printed;
buf += printed;
@@ -1120,7 +1123,9 @@ static int pjsip_fromto_hdr_print( pjsip_fromto_hdr *hdr,
copy_advance_pair(buf, ";tag=", 5, hdr->tag);
- printed = pjsip_param_print_on(&hdr->other_param, buf, endbuf-buf, ';');
+ printed = pjsip_param_print_on(&hdr->other_param, buf, endbuf-buf,
+ &pjsip_PARAM_CHAR_SPEC,
+ &pjsip_PARAM_CHAR_SPEC, ';');
if (printed < 0)
return -1;
buf += printed;
@@ -1243,7 +1248,9 @@ static int pjsip_routing_hdr_print( pjsip_routing_hdr *hdr,
return -1;
buf += printed;
- printed = pjsip_param_print_on(&hdr->other_param, buf, endbuf-buf, ';');
+ printed = pjsip_param_print_on(&hdr->other_param, buf, endbuf-buf,
+ &pjsip_PARAM_CHAR_SPEC,
+ &pjsip_PARAM_CHAR_SPEC, ';');
if (printed < 0)
return -1;
buf += printed;
@@ -1406,7 +1413,9 @@ static int pjsip_via_hdr_print( pjsip_via_hdr *hdr,
copy_advance_pair(buf, ";received=", 10, hdr->recvd_param);
copy_advance_pair(buf, ";branch=", 8, hdr->branch_param);
- printed = pjsip_param_print_on(&hdr->other_param, buf, endbuf-buf, ';');
+ printed = pjsip_param_print_on(&hdr->other_param, buf, endbuf-buf,
+ &pjsip_PARAM_CHAR_SPEC,
+ &pjsip_PARAM_CHAR_SPEC, ';');
if (printed < 0)
return -1;
buf += printed;
diff --git a/pjsip/src/pjsip/sip_parser.c b/pjsip/src/pjsip/sip_parser.c
index 1b430de0..7b163578 100644
--- a/pjsip/src/pjsip/sip_parser.c
+++ b/pjsip/src/pjsip/sip_parser.c
@@ -49,14 +49,15 @@
#define HDR_CHAR HNV_UNRESERVED UNRESERVED ESCAPED
#define PJSIP_VERSION "SIP/2.0"
-#define PJSIP_SYN_ERR_EXCEPTION 1
#define UNREACHED(expr)
-//#define IS_NEWLINE(c) ((c)=='\r' || (c)=='\n')
-#define IS_NEWLINE(c) ((c)=='\r')
+#define IS_NEWLINE(c) ((c)=='\r' || (c)=='\n')
#define IS_SPACE(c) ((c)==' ' || (c)=='\t')
+/*
+ * Header parser records.
+ */
typedef struct handler_rec
{
char hname[PJSIP_MAX_HNAME_LEN+1];
@@ -65,13 +66,27 @@ typedef struct handler_rec
pjsip_parse_hdr_func *handler;
} handler_rec;
-static handler_rec handler[127];
+static handler_rec handler[PJSIP_MAX_HEADER_TYPES];
static unsigned handler_count;
static int parser_is_initialized;
/*
+ * URI parser records.
+ */
+typedef struct uri_parser_rec
+{
+ pj_str_t scheme;
+ pjsip_parse_uri_func *parse;
+} uri_parser_rec;
+
+static uri_parser_rec uri_handler[PJSIP_MAX_URI_TYPES];
+static unsigned uri_handler_count;
+
+/*
* Global vars (also extern).
*/
+int PJSIP_SYN_ERR_EXCEPTION;
+
const pj_str_t pjsip_USER_STR = { "user", 4};
const pj_str_t pjsip_METHOD_STR = { "method", 6};
const pj_str_t pjsip_TRANSPORT_STR = { "transport", 9};
@@ -246,6 +261,17 @@ static pj_status_t init_parser()
initialized = 1;
+ /*
+ * Syntax error exception number.
+ */
+ status = pj_exception_id_alloc("PJSIP: syntax error",
+ &PJSIP_SYN_ERR_EXCEPTION);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+
+ /*
+ * Init character input spec (cis)
+ */
+
pj_cis_buf_init(&cis_buf);
status = pj_cis_init(&cis_buf, &pjsip_DIGIT_SPEC);
@@ -309,6 +335,20 @@ static pj_status_t init_parser()
pj_cis_add_str( &pjsip_DISPLAY_SPEC, ":\r\n<");
pj_cis_invert(&pjsip_DISPLAY_SPEC);
+ /*
+ * Register URI parsers.
+ */
+
+ status = pjsip_register_uri_parser("sip", &int_parse_sip_url);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+
+ status = pjsip_register_uri_parser("sips", &int_parse_sip_url);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+
+ /*
+ * Register header parsers.
+ */
+
status = pjsip_register_hdr_parser( "Accept", NULL, &parse_hdr_accept);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
@@ -373,7 +413,10 @@ static pj_status_t init_parser()
status = pjsip_register_hdr_parser( "Via", NULL, &parse_hdr_via);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
- /* Register auth parser. */
+ /*
+ * Register auth parser.
+ */
+
status = pjsip_auth_init_parser();
return status;
@@ -382,13 +425,10 @@ static pj_status_t init_parser()
void init_sip_parser(void)
{
if (!parser_is_initialized) {
- /* Prevent race cond. */
- pj_enter_critical_section();
if (!parser_is_initialized) {
init_parser();
parser_is_initialized = 1;
}
- pj_leave_critical_section();
}
}
@@ -398,9 +438,9 @@ void init_sip_parser(void)
* - >0 if handler is 'greater' than header name.
*/
PJ_INLINE(int) compare_handler( const handler_rec *r1,
- const char *name,
- pj_size_t name_len,
- pj_uint32_t hash )
+ const char *name,
+ pj_size_t name_len,
+ pj_uint32_t hash )
{
PJ_UNUSED_ARG(name_len);
@@ -538,6 +578,31 @@ static pjsip_parse_hdr_func * find_handler(const pj_str_t *hname)
return comp==0 ? first->handler : NULL;
}
+/* Find URI handler. */
+static pjsip_parse_uri_func* find_uri_handler(const pj_str_t *scheme)
+{
+ unsigned i;
+ for (i=0; i<uri_handler_count; ++i) {
+ if (pj_stricmp_alnum(&uri_handler[i].scheme, scheme)==0)
+ return uri_handler[i].parse;
+ }
+ return NULL;
+}
+
+/* Register URI parser. */
+PJ_DEF(pj_status_t) pjsip_register_uri_parser( char *scheme,
+ pjsip_parse_uri_func *func)
+{
+ if (uri_handler_count >= PJ_ARRAY_SIZE(uri_handler))
+ return PJ_ETOOMANY;
+
+ uri_handler[uri_handler_count].scheme = pj_str((char*)scheme);
+ uri_handler[uri_handler_count].parse = func;
+ ++uri_handler_count;
+
+ return PJ_SUCCESS;
+}
+
/* Public function to parse SIP message. */
PJ_DEF(pjsip_msg*) pjsip_parse_msg( pj_pool_t *pool,
char *buf, pj_size_t size,
@@ -547,8 +612,6 @@ PJ_DEF(pjsip_msg*) pjsip_parse_msg( pj_pool_t *pool,
pj_scanner scanner;
pjsip_parse_ctx context;
- init_sip_parser();
-
pj_scan_init(&scanner, buf, size, PJ_SCAN_AUTOSKIP_WS_HEADER,
&on_syntax_error);
@@ -569,8 +632,6 @@ PJ_DEF(pjsip_msg *) pjsip_parse_rdata( char *buf, pj_size_t size,
pj_scanner scanner;
pjsip_parse_ctx context;
- init_sip_parser();
-
pj_scan_init(&scanner, buf, size, PJ_SCAN_AUTOSKIP_WS_HEADER,
&on_syntax_error);
@@ -625,8 +686,6 @@ PJ_DEF(pj_bool_t) pjsip_find_msg( const char *buf, pj_size_t size,
pj_scanner scanner;
PJ_USE_EXCEPTION;
- init_sip_parser();
-
pj_scan_init(&scanner, (char*)line, hdr_end-line,
PJ_SCAN_AUTOSKIP_WS_HEADER, &on_syntax_error);
@@ -694,8 +753,6 @@ PJ_DEF(pjsip_uri*) pjsip_parse_uri( pj_pool_t *pool,
pjsip_uri *uri = NULL;
PJ_USE_EXCEPTION;
- init_sip_parser();
-
pj_scan_init(&scanner, buf, size, 0, &on_syntax_error);
@@ -871,6 +928,10 @@ parse_headers:
} while (IS_SPACE(*scanner->curptr));
}
+ /* Restore flag. Flag may be set in int_parse_sip_url() */
+ scanner->skip_ws = PJ_SCAN_AUTOSKIP_WS_HEADER;
+
+ /* Continue parse next header, if any. */
if (!pj_scan_is_eof(scanner) && !IS_NEWLINE(*scanner->curptr)) {
goto parse_headers;
}
@@ -1018,19 +1079,17 @@ static pjsip_uri *int_parse_uri_or_name_addr( pj_scanner *scanner, pj_pool_t *po
next_ch = pj_scan_peek( scanner, &pjsip_DISPLAY_SPEC, &scheme);
- if (next_ch==':' &&
- (parser_stricmp(scheme, pjsip_SIP_STR)==0 ||
- parser_stricmp(scheme, pjsip_SIPS_STR)==0))
- {
- uri = (pjsip_uri*)
- int_parse_sip_url( scanner, pool,
- (opt & PJSIP_PARSE_URI_IN_FROM_TO_HDR)== 0);
+ if (next_ch==':') {
+ pjsip_parse_uri_func *func = find_uri_handler(&scheme);
- } else if (next_ch==':') {
+ if (func == NULL) {
+ /* Unsupported URI scheme */
+ PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
+ }
+
+ uri = (*func)( scanner, pool,
+ (opt & PJSIP_PARSE_URI_IN_FROM_TO_HDR)== 0);
- /* Not supported. */
- PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
- UNREACHED({return NULL; /* Not reached. */});
} else {
uri = (pjsip_uri*)int_parse_name_addr( scanner, pool );
@@ -1062,6 +1121,7 @@ static pjsip_uri *int_parse_uri(pj_scanner *scanner, pj_pool_t *pool,
} else {
pj_str_t scheme;
int colon;
+ pjsip_parse_uri_func *func;
/* Get scheme. */
colon = pj_scan_peek(scanner, &pjsip_TOKEN_SPEC, &scheme);
@@ -1069,16 +1129,12 @@ static pjsip_uri *int_parse_uri(pj_scanner *scanner, pj_pool_t *pool,
PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
}
- if ((parser_stricmp(scheme, pjsip_SIP_STR)==0 ||
- parser_stricmp(scheme, pjsip_SIPS_STR)==0))
- {
- return (pjsip_uri*)int_parse_sip_url( scanner, pool, parse_params);
-
- } else if (parser_stricmp(scheme, pjsip_TEL_STR)==0) {
- PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
- UNREACHED({ return NULL; /* Not reached. */ })
+ func = find_uri_handler(&scheme);
+ if (func) {
+ return (pjsip_uri*)(*func)(scanner, pool, parse_params);
} else {
+ /* Unsupported URI scheme */
PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
UNREACHED({ return NULL; /* Not reached. */ })
}
@@ -1773,8 +1829,6 @@ PJ_DEF(void*) pjsip_parse_hdr( pj_pool_t *pool, const pj_str_t *hname,
pjsip_parse_ctx context;
PJ_USE_EXCEPTION;
- init_sip_parser();
-
pj_scan_init(&scanner, buf, size, PJ_SCAN_AUTOSKIP_WS_HEADER,
&on_syntax_error);
diff --git a/pjsip/src/pjsip/sip_tel_uri.c b/pjsip/src/pjsip/sip_tel_uri.c
new file mode 100644
index 00000000..4563f6dc
--- /dev/null
+++ b/pjsip/src/pjsip/sip_tel_uri.c
@@ -0,0 +1,416 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pjsip/sip_tel_uri.h>
+#include <pjsip/sip_msg.h>
+#include <pjsip/sip_parser.h>
+#include <pjsip/print_util.h>
+#include <pj/pool.h>
+#include <pj/assert.h>
+#include <pj/string.h>
+#include <pj/ctype.h>
+#include <pj/except.h>
+#include <pjlib-util/string.h>
+#include <pjlib-util/scanner.h>
+
+#define ALPHA
+#define DIGITS "0123456789"
+#define HEX "aAbBcCdDeEfF"
+#define HEX_DIGITS DIGITS HEX
+#define VISUAL_SEP "-.()"
+#define PHONE_DIGITS DIGITS VISUAL_SEP
+#define GLOBAL_DIGITS "+" PHONE_DIGITS
+#define LOCAL_DIGITS HEX_DIGITS "*#" VISUAL_SEP
+#define NUMBER_SPEC LOCAL_DIGITS GLOBAL_DIGITS
+#define PHONE_CONTEXT ALPHA GLOBAL_DIGITS
+//#define RESERVED ";/?:@&=+$,"
+#define RESERVED "/:@&$,+"
+#define MARK "-_.!~*'()"
+#define UNRESERVED ALPHA DIGITS MARK
+#define ESCAPED "%"
+#define URIC RESERVED UNRESERVED ESCAPED "[]+"
+#define PARAM_UNRESERVED "[]/:&+$"
+#define PARAM_CHAR PARAM_UNRESERVED UNRESERVED ESCAPED
+
+static pj_cis_buf_t cis_buf;
+static pj_cis_t pjsip_TEL_NUMBER_SPEC;
+static pj_cis_t pjsip_TEL_EXT_VALUE_SPEC;
+static pj_cis_t pjsip_TEL_PHONE_CONTEXT_SPEC;
+static pj_cis_t pjsip_TEL_URIC_SPEC;
+static pj_cis_t pjsip_TEL_VISUAL_SEP_SPEC;
+static pj_cis_t pjsip_TEL_PNAME_SPEC;
+static pj_cis_t pjsip_TEL_PVALUE_SPEC;
+static pj_cis_t pjsip_TEL_PARSING_PVALUE_SPEC;
+
+static pj_str_t pjsip_ISUB_STR = { "isub", 4 };
+static pj_str_t pjsip_EXT_STR = { "ext", 3 };
+static pj_str_t pjsip_PH_CTX_STR = { "phone-context", 13 };
+
+
+static const pj_str_t *tel_uri_get_scheme( const pjsip_tel_uri* );
+static void *tel_uri_get_uri( pjsip_tel_uri* );
+static int tel_uri_print( pjsip_uri_context_e context,
+ const pjsip_tel_uri *url,
+ char *buf, pj_size_t size);
+static int tel_uri_cmp( pjsip_uri_context_e context,
+ const pjsip_tel_uri *url1, const pjsip_tel_uri *url2);
+static pjsip_tel_uri* tel_uri_clone(pj_pool_t *pool, const pjsip_tel_uri *rhs);
+static pjsip_tel_uri *tel_uri_parse( pj_scanner *scanner, pj_pool_t *pool,
+ pj_bool_t parse_params);
+
+#ifdef __GNUC__
+# define HAPPY_FLAG (void*)
+#else
+# define HAPPY_FLAG
+#endif
+
+static pjsip_uri_vptr tel_uri_vptr =
+{
+ HAPPY_FLAG &tel_uri_get_scheme,
+ HAPPY_FLAG &tel_uri_get_uri,
+ HAPPY_FLAG &tel_uri_print,
+ HAPPY_FLAG &tel_uri_cmp,
+ HAPPY_FLAG &tel_uri_clone
+};
+
+
+PJ_DEF(pjsip_tel_uri*) pjsip_tel_uri_create(pj_pool_t *pool)
+{
+ pjsip_tel_uri *uri = pj_pool_zalloc(pool, sizeof(pjsip_tel_uri));
+ uri->vptr = &tel_uri_vptr;
+ pj_list_init(&uri->other_param);
+ return uri;
+}
+
+
+static const pj_str_t *tel_uri_get_scheme( const pjsip_tel_uri *uri )
+{
+ PJ_UNUSED_ARG(uri);
+ return &pjsip_TEL_STR;
+}
+
+static void *tel_uri_get_uri( pjsip_tel_uri *uri )
+{
+ return uri;
+}
+
+
+pj_status_t pjsip_tel_uri_subsys_init(void)
+{
+ pj_status_t status;
+
+ pj_cis_buf_init(&cis_buf);
+
+ status = pj_cis_init(&cis_buf, &pjsip_TEL_EXT_VALUE_SPEC);
+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+ pj_cis_add_str(&pjsip_TEL_EXT_VALUE_SPEC, PHONE_DIGITS);
+
+ status = pj_cis_init(&cis_buf, &pjsip_TEL_NUMBER_SPEC);
+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+ pj_cis_add_str(&pjsip_TEL_NUMBER_SPEC, NUMBER_SPEC);
+
+ status = pj_cis_init(&cis_buf, &pjsip_TEL_VISUAL_SEP_SPEC);
+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+ pj_cis_add_str(&pjsip_TEL_VISUAL_SEP_SPEC, VISUAL_SEP);
+
+ status = pj_cis_init(&cis_buf, &pjsip_TEL_PHONE_CONTEXT_SPEC);
+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+ pj_cis_add_alpha(&pjsip_TEL_PHONE_CONTEXT_SPEC);
+ pj_cis_add_num(&pjsip_TEL_PHONE_CONTEXT_SPEC);
+ pj_cis_add_str(&pjsip_TEL_PHONE_CONTEXT_SPEC, PHONE_CONTEXT);
+
+ status = pj_cis_init(&cis_buf, &pjsip_TEL_URIC_SPEC);
+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+ pj_cis_add_alpha(&pjsip_TEL_URIC_SPEC);
+ pj_cis_add_num(&pjsip_TEL_URIC_SPEC);
+ pj_cis_add_str(&pjsip_TEL_URIC_SPEC, URIC);
+
+ status = pj_cis_init(&cis_buf, &pjsip_TEL_PNAME_SPEC);
+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+ pj_cis_add_alpha(&pjsip_TEL_PNAME_SPEC);
+ pj_cis_add_num(&pjsip_TEL_PNAME_SPEC);
+ pj_cis_add_str(&pjsip_TEL_PNAME_SPEC, "-");
+
+ status = pj_cis_init(&cis_buf, &pjsip_TEL_PVALUE_SPEC);
+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+ pj_cis_add_alpha(&pjsip_TEL_PVALUE_SPEC);
+ pj_cis_add_num(&pjsip_TEL_PVALUE_SPEC);
+ pj_cis_add_str(&pjsip_TEL_PVALUE_SPEC, PARAM_CHAR);
+
+ status = pj_cis_dup(&pjsip_TEL_PARSING_PVALUE_SPEC, &pjsip_TEL_URIC_SPEC);
+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+ pj_cis_add_cis(&pjsip_TEL_PARSING_PVALUE_SPEC, &pjsip_TEL_PVALUE_SPEC);
+ pj_cis_add_str(&pjsip_TEL_PARSING_PVALUE_SPEC, "=");
+
+ status = pjsip_register_uri_parser("tel", &tel_uri_parse);
+ PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+
+ return PJ_SUCCESS;
+}
+
+/* Print tel: URI */
+static int tel_uri_print( pjsip_uri_context_e context,
+ const pjsip_tel_uri *uri,
+ char *buf, pj_size_t size)
+{
+ int printed;
+ char *startbuf = buf;
+ char *endbuf = buf+size;
+
+ PJ_UNUSED_ARG(context);
+
+ /* Print scheme. */
+ copy_advance(buf, pjsip_TEL_STR);
+ *buf++ = ':';
+
+ /* Print number. */
+ copy_advance_escape(buf, uri->number, pjsip_TEL_NUMBER_SPEC);
+
+ /* ISDN sub-address or extension must appear first. */
+
+ /* Extension param. */
+ copy_advance_pair_escape(buf, ";ext=", 5, uri->ext_param,
+ pjsip_TEL_EXT_VALUE_SPEC);
+
+ /* ISDN sub-address. */
+ copy_advance_pair_escape(buf, ";isub=", 6, uri->isub_param,
+ pjsip_TEL_URIC_SPEC);
+
+ /* Followed by phone context, if present. */
+ copy_advance_pair_escape(buf, ";phone-context=", 15, uri->context,
+ pjsip_TEL_PHONE_CONTEXT_SPEC);
+
+
+ /* Print other parameters. */
+ printed = pjsip_param_print_on(&uri->other_param, buf, (endbuf-buf),
+ &pjsip_TEL_PNAME_SPEC,
+ &pjsip_TEL_PVALUE_SPEC, ';');
+ if (printed < 0)
+ return -1;
+ buf += printed;
+
+ return (buf-startbuf);
+}
+
+/* Compare two numbers, according to RFC 3966:
+ * - both must be either local or global numbers.
+ * - The 'global-number-digits' and the 'local-number-digits' must be
+ * equal, after removing all visual separators.
+ */
+PJ_DEF(int) pjsip_tel_nb_cmp(const pj_str_t *number1, const pj_str_t *number2)
+{
+ const char *s1 = number1->ptr,
+ *e1 = number1->ptr + number1->slen,
+ *s2 = number2->ptr,
+ *e2 = number2->ptr + number2->slen;
+
+ /* Compare each number, ignoreing visual separators. */
+ while (s1!=e1 && s2!=e2) {
+ int diff;
+
+ if (pj_cis_match(&pjsip_TEL_VISUAL_SEP_SPEC, *s1)) {
+ ++s1;
+ continue;
+ }
+ if (pj_cis_match(&pjsip_TEL_VISUAL_SEP_SPEC, *s2)) {
+ ++s2;
+ continue;
+ }
+
+ diff = pj_tolower(*s1) - pj_tolower(*s2);
+ if (!diff) {
+ ++s1, ++s2;
+ continue;
+ } else
+ return diff;
+ }
+
+ /* Exhaust remaining visual separators. */
+ while (s1!=e1 && pj_cis_match(&pjsip_TEL_VISUAL_SEP_SPEC, *s1))
+ ++s1;
+ while (s2!=e2 && pj_cis_match(&pjsip_TEL_VISUAL_SEP_SPEC, *s2))
+ ++s2;
+
+ if (s1==e1 && s2==e2)
+ return 0;
+ else if (s1==e1)
+ return -1;
+ else
+ return 1;
+}
+
+/* Compare two tel: URI */
+static int tel_uri_cmp( pjsip_uri_context_e context,
+ const pjsip_tel_uri *url1, const pjsip_tel_uri *url2)
+{
+ int result;
+
+ PJ_UNUSED_ARG(context);
+
+ /* Scheme must match. */
+ if (url1->vptr != url2->vptr)
+ return -1;
+
+ /* Compare number. */
+ result = pjsip_tel_nb_cmp(&url1->number, &url2->number);
+ if (result != 0)
+ return result;
+
+ /* Compare phone-context as hostname or as as global nb. */
+ if (url1->context.slen) {
+ if (*url1->context.ptr != '+')
+ result = pj_stricmp(&url1->context, &url2->context);
+ else
+ result = pjsip_tel_nb_cmp(&url1->context, &url2->context);
+
+ if (result != 0)
+ return result;
+
+ } else if (url2->context.slen)
+ return -1;
+
+ /* Compare extension. */
+ if (url1->ext_param.slen) {
+ result = pjsip_tel_nb_cmp(&url1->ext_param, &url2->ext_param);
+ if (result != 0)
+ return result;
+ }
+
+ /* Compare isub bytes by bytes. */
+ if (url1->isub_param.slen) {
+ result = pj_stricmp(&url1->isub_param, &url2->isub_param);
+ if (result != 0)
+ return result;
+ }
+
+ /* Other parameters are compared regardless of the order.
+ * If one URI has parameter not found in the other URI, the URIs are
+ * not equal.
+ */
+ if (url1->other_param.next != &url1->other_param) {
+ const pjsip_param *p1, *p2;
+ int cnt1 = 0, cnt2 = 0;
+
+ p1 = url1->other_param.next;
+ while (p1 != &url1->other_param) {
+ p2 = pjsip_param_cfind(&url2->other_param, &p1->name);
+ if (!p2 )
+ return 1;
+
+ result = pj_stricmp(&p1->value, &p2->value);
+ if (result != 0)
+ return result;
+
+ p1 = p1->next;
+ ++cnt1;
+ }
+
+ p2 = url2->other_param.next;
+ while (p2 != &url2->other_param)
+ ++cnt2, p2 = p2->next;
+
+ if (cnt1 < cnt2)
+ return -1;
+ else if (cnt1 > cnt2)
+ return 1;
+
+ } else if (url2->other_param.next != &url2->other_param)
+ return -1;
+
+ /* Equal. */
+ return 0;
+}
+
+/* Clone tel: URI */
+static pjsip_tel_uri* tel_uri_clone(pj_pool_t *pool, const pjsip_tel_uri *rhs)
+{
+ pjsip_tel_uri *uri = pjsip_tel_uri_create(pool);
+
+ pj_strdup(pool, &uri->number, &rhs->number);
+ pj_strdup(pool, &uri->context, &rhs->context);
+ pj_strdup(pool, &uri->ext_param, &rhs->ext_param);
+ pj_strdup(pool, &uri->isub_param, &rhs->isub_param);
+ pjsip_param_clone(pool, &uri->other_param, &rhs->other_param);
+
+ return uri;
+}
+
+/* Parse tel: URI */
+static pjsip_tel_uri *tel_uri_parse( pj_scanner *scanner, pj_pool_t *pool,
+ pj_bool_t parse_params)
+{
+ pjsip_tel_uri *uri;
+ pj_str_t token;
+ int skip_ws = scanner->skip_ws;
+
+ scanner->skip_ws = 0;
+
+ /* Parse scheme. */
+ pj_scan_get(scanner, &pjsip_TOKEN_SPEC, &token);
+ if (pj_scan_get_char(scanner) != ':')
+ PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
+ if (pj_stricmp_alnum(&token, &pjsip_TEL_STR) != 0)
+ PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
+
+ /* Create URI */
+ uri = pjsip_tel_uri_create(pool);
+
+ /* Get the phone number. */
+ pj_scan_get(scanner, &pjsip_TEL_NUMBER_SPEC, &uri->number);
+ uri->number = pj_str_unescape(pool, &uri->number);
+
+ /* Get all parameters. */
+ if (parse_params && *scanner->curptr==';') {
+ pj_str_t pname, pvalue;
+
+ do {
+ /* Eat the ';' separator. */
+ pj_scan_get_char(scanner);
+
+ /* Get pname. */
+ pj_scan_get(scanner, &pjsip_PARAM_CHAR_SPEC, &pname);
+
+ if (*scanner->curptr == '=') {
+ pj_scan_get_char(scanner);
+ pj_scan_get(scanner, &pjsip_TEL_PARSING_PVALUE_SPEC, &pvalue);
+ } else {
+ pvalue.slen = 0;
+ pvalue.ptr = NULL;
+ }
+
+ /* Save the parameters. */
+ if (pj_stricmp_alnum(&pname, &pjsip_ISUB_STR)==0) {
+ uri->isub_param = pvalue;
+ } else if (pj_stricmp_alnum(&pname, &pjsip_EXT_STR)==0) {
+ uri->ext_param = pvalue;
+ } else if (pj_stricmp_alnum(&pname, &pjsip_PH_CTX_STR)==0) {
+ uri->context = pvalue;
+ } else {
+ pjsip_param *param = pj_pool_alloc(pool, sizeof(pjsip_param));
+ param->name = pname;
+ param->value = pvalue;
+ pj_list_insert_before(&uri->other_param, param);
+ }
+
+ } while (*scanner->curptr==';');
+ }
+
+ scanner->skip_ws = skip_ws;
+ return uri;
+}
+
diff --git a/pjsip/src/pjsip/sip_uri.c b/pjsip/src/pjsip/sip_uri.c
index 6c4efb53..09fd8ef8 100644
--- a/pjsip/src/pjsip/sip_uri.c
+++ b/pjsip/src/pjsip/sip_uri.c
@@ -87,6 +87,8 @@ PJ_DEF(void) pjsip_param_shallow_clone( pj_pool_t *pool,
PJ_DEF(pj_ssize_t) pjsip_param_print_on( const pjsip_param *param_list,
char *buf, pj_size_t size,
+ const pj_cis_t *pname_spec,
+ const pj_cis_t *pvalue_spec,
int sep)
{
const pjsip_param *p;
@@ -103,10 +105,10 @@ PJ_DEF(pj_ssize_t) pjsip_param_print_on( const pjsip_param *param_list,
do {
*buf++ = (char)sep;
- copy_advance_escape(buf, p->name, pjsip_PARAM_CHAR_SPEC);
+ copy_advance_escape(buf, p->name, (*pname_spec));
if (p->value.slen) {
*buf++ = '=';
- copy_advance_escape(buf, p->value, pjsip_PARAM_CHAR_SPEC);
+ copy_advance_escape(buf, p->value, (*pvalue_spec));
}
p = p->next;
} while (p != param_list);
@@ -308,7 +310,9 @@ static int pjsip_url_print( pjsip_uri_context_e context,
}
/* Other param. */
- printed = pjsip_param_print_on(&url->other_param, buf, endbuf-buf, ';');
+ printed = pjsip_param_print_on(&url->other_param, buf, endbuf-buf,
+ &pjsip_PARAM_CHAR_SPEC,
+ &pjsip_PARAM_CHAR_SPEC, ';');
if (printed < 0)
return -1;
buf += printed;
@@ -448,8 +452,6 @@ static pj_status_t pjsip_url_compare( pjsip_uri_context_e context,
* the rule of each header. We'll just compare them string to
* string..
*/
- PJ_TODO(MORE_COMPLIANT_HEADER_PARAM_COMPARISON_IN_URL);
-
if (pj_stricmp(&p1->value, &p2->value) != 0)
return PJSIP_ECMPHEADERPARAM;
} else {
diff --git a/pjsip/src/test-pjsip/test.c b/pjsip/src/test-pjsip/test.c
index b940ffa1..92e0c33a 100644
--- a/pjsip/src/test-pjsip/test.c
+++ b/pjsip/src/test-pjsip/test.c
@@ -82,7 +82,7 @@ int test_main(void)
PJ_LOG(3,("",""));
DO_TEST(uri_test());
- //DO_TEST(msg_test());
+ DO_TEST(msg_test());
on_return:
diff --git a/pjsip/src/test-pjsip/uri.c b/pjsip/src/test-pjsip/uri.c
index 7afcbbef..29a16dd5 100644
--- a/pjsip/src/test-pjsip/uri.c
+++ b/pjsip/src/test-pjsip/uri.c
@@ -57,6 +57,17 @@ static pjsip_uri *create_uri14( pj_pool_t *pool );
static pjsip_uri *create_uri15( pj_pool_t *pool );
static pjsip_uri *create_uri16( pj_pool_t *pool );
static pjsip_uri *create_uri17( pj_pool_t *pool );
+static pjsip_uri *create_uri25( pj_pool_t *pool );
+static pjsip_uri *create_uri26( pj_pool_t *pool );
+static pjsip_uri *create_uri27( pj_pool_t *pool );
+static pjsip_uri *create_uri28( pj_pool_t *pool );
+static pjsip_uri *create_uri29( pj_pool_t *pool );
+static pjsip_uri *create_uri30( pj_pool_t *pool );
+static pjsip_uri *create_uri31( pj_pool_t *pool );
+static pjsip_uri *create_uri32( pj_pool_t *pool );
+static pjsip_uri *create_uri33( pj_pool_t *pool );
+static pjsip_uri *create_uri34( pj_pool_t *pool );
+static pjsip_uri *create_uri35( pj_pool_t *pool );
static pjsip_uri *create_dummy( pj_pool_t *pool );
#define ERR_NOT_EQUAL -1001
@@ -66,7 +77,8 @@ struct uri_test
{
pj_status_t status;
char str[PJSIP_MAX_URL_SIZE];
- pjsip_uri *(*creator)(pj_pool_t *pool);
+ pjsip_uri *(*creator)(pj_pool_t *pool);
+ const char *printed;
pj_size_t len;
} uri_test_array[] =
{
@@ -226,7 +238,78 @@ struct uri_test
ERR_SYNTAX_ERR,
"",
&create_dummy,
- }
+ },
+ {
+ /* 25: Simple tel: URI with global context */
+ PJ_SUCCESS,
+ "tel:+1-201-555-0123",
+ &create_uri25,
+ "tel:+1-201-555-0123"
+ },
+ {
+ /* 26: Simple tel: URI with local context */
+ PJ_SUCCESS,
+ "tel:7042;phone-context=example.com",
+ &create_uri26,
+ "tel:7042;phone-context=example.com"
+ },
+ {
+ /* 27: Simple tel: URI with local context */
+ PJ_SUCCESS,
+ "tel:863-1234;phone-context=+1-914-555",
+ &create_uri27,
+ "tel:863-1234;phone-context=+1-914-555"
+ },
+ {
+ /* 28: Comparison between local and global number */
+ ERR_NOT_EQUAL,
+ "tel:+1",
+ &create_uri28,
+ "tel:+1"
+ },
+ {
+ /* 29: tel: with some visual chars and spaces */
+ PJ_SUCCESS,
+ "tel:(44).1234-*#+Deaf",
+ &create_uri29,
+ "tel:(44).1234-*#+Deaf"
+ },
+ {
+ /* 30: isub parameters */
+ PJ_SUCCESS,
+ "tel:+1;isub=/:@&$,-_.!~*'()[]/:&$aA1%21+=",
+ &create_uri30,
+ "tel:+1;isub=/:@&$,-_.!~*'()[]/:&$aA1%21+%3d"
+ },
+ {
+ /* 31: extension number parsing and encoding */
+ PJ_SUCCESS,
+ "tel:+1;ext=+123",
+ &create_uri31,
+ "tel:+1;ext=%2b123"
+ },
+ {
+ /* 32: context parameter parsing and encoding */
+ PJ_SUCCESS,
+ "tel:911;phone-context=+1-911",
+ &create_uri32,
+ "tel:911;phone-context=+1-911"
+ },
+ {
+ /* 33: case-insensitive comparison */
+ PJ_SUCCESS,
+ "tel:911;phone-context=emergency.example.com",
+ &create_uri33,
+ "tel:911;phone-context=emergency.example.com"
+ },
+ {
+ /* 34: parameter only appears in one URL */
+ ERR_NOT_EQUAL,
+ "tel:911;p1=p1;p2=p2",
+ &create_uri34,
+ "tel:911;p1=p1;p2=p2"
+ },
+
};
static pjsip_uri *create_uri0(pj_pool_t *pool)
@@ -474,6 +557,110 @@ static pjsip_uri *create_uri17(pj_pool_t *pool)
return (pjsip_uri*)url;
}
+
+static pjsip_uri *create_uri25(pj_pool_t *pool)
+{
+ /* "tel:+1-201-555-0123" */
+ pjsip_tel_uri *uri = pjsip_tel_uri_create(pool);
+
+ uri->number = pj_str("+1-201-555-0123");
+ return (pjsip_uri*)uri;
+}
+
+static pjsip_uri *create_uri26(pj_pool_t *pool)
+{
+ /* tel:7042;phone-context=example.com */
+ pjsip_tel_uri *uri = pjsip_tel_uri_create(pool);
+
+ uri->number = pj_str("7042");
+ uri->context = pj_str("example.com");
+ return (pjsip_uri*)uri;
+}
+
+static pjsip_uri *create_uri27(pj_pool_t *pool)
+{
+ /* "tel:863-1234;phone-context=+1-914-555" */
+ pjsip_tel_uri *uri = pjsip_tel_uri_create(pool);
+
+ uri->number = pj_str("863-1234");
+ uri->context = pj_str("+1-914-555");
+ return (pjsip_uri*)uri;
+}
+
+/* "tel:1" */
+static pjsip_uri *create_uri28(pj_pool_t *pool)
+{
+ pjsip_tel_uri *uri = pjsip_tel_uri_create(pool);
+
+ uri->number = pj_str("1");
+ return (pjsip_uri*)uri;
+}
+
+/* "tel:(44).1234-*#+Deaf" */
+static pjsip_uri *create_uri29(pj_pool_t *pool)
+{
+ pjsip_tel_uri *uri = pjsip_tel_uri_create(pool);
+
+ uri->number = pj_str("(44).1234-*#+Deaf");
+ return (pjsip_uri*)uri;
+}
+
+/* "tel:+1;isub=/:@&$,-_.!~*'()[]/:&$aA1%21+=" */
+static pjsip_uri *create_uri30(pj_pool_t *pool)
+{
+ pjsip_tel_uri *uri = pjsip_tel_uri_create(pool);
+
+ uri->number = pj_str("+1");
+ uri->isub_param = pj_str("/:@&$,-_.!~*'()[]/:&$aA1%21+=");
+ return (pjsip_uri*)uri;
+}
+
+/* "tel:+1;ext=+123" */
+static pjsip_uri *create_uri31(pj_pool_t *pool)
+{
+ pjsip_tel_uri *uri = pjsip_tel_uri_create(pool);
+
+ uri->number = pj_str("+1");
+ uri->ext_param = pj_str("+123");
+ return (pjsip_uri*)uri;
+}
+
+/* "tel:911;phone-context=+1-911" */
+static pjsip_uri *create_uri32(pj_pool_t *pool)
+{
+ pjsip_tel_uri *uri = pjsip_tel_uri_create(pool);
+
+ uri->number = pj_str("911");
+ uri->context = pj_str("+1-911");
+ return (pjsip_uri*)uri;
+}
+
+/* "tel:911;phone-context=emergency.example.com" */
+static pjsip_uri *create_uri33(pj_pool_t *pool)
+{
+ pjsip_tel_uri *uri = pjsip_tel_uri_create(pool);
+
+ uri->number = pj_str("911");
+ uri->context = pj_str("EMERGENCY.EXAMPLE.COM");
+ return (pjsip_uri*)uri;
+}
+
+/* "tel:911;p1=p1;p2=p2" */
+static pjsip_uri *create_uri34(pj_pool_t *pool)
+{
+ pjsip_tel_uri *uri = pjsip_tel_uri_create(pool);
+ pjsip_param *p;
+
+ uri->number = pj_str("911");
+
+ p = pj_pool_alloc(pool, sizeof(*p));
+ p->name = p->value = pj_str("p1");
+ pj_list_insert_before(&uri->other_param, p);
+
+ return (pjsip_uri*)uri;
+}
+
+
static pjsip_uri *create_dummy(pj_pool_t *pool)
{
PJ_UNUSED_ARG(pool);
@@ -572,9 +759,24 @@ static pj_status_t do_uri_test(pj_pool_t *pool, struct uri_test *entry)
pj_add_timestamp(&cmp_time, &t2);
/* Compare text. */
- if (pj_strcmp(&s1, &s2) != 0) {
- /* Not equal. */
- status = -60;
+ if (entry->printed) {
+ if (pj_strcmp2(&s1, entry->printed) != 0) {
+ /* Not equal. */
+ PJ_LOG(3,("", " uri print mismatch:\n"
+ " printed='%s'\n"
+ " expectd='%s'",
+ s1.ptr, entry->printed));
+ status = -60;
+ }
+ } else {
+ if (pj_strcmp(&s1, &s2) != 0) {
+ /* Not equal. */
+ PJ_LOG(3,("", " uri print mismatch:\n"
+ " uri1='%s'\n"
+ " uri2='%s'",
+ s1.ptr, s2.ptr));
+ status = -70;
+ }
}
on_return: