1 /* $Id$ */
2 /*
3  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <pjsip/sip_uri.h>
21 #include <pjsip/sip_msg.h>
22 #include <pjsip/sip_parser.h>
23 #include <pjsip/print_util.h>
24 #include <pjsip/sip_errno.h>
25 #include <pjlib-util/string.h>
26 #include <pj/string.h>
27 #include <pj/pool.h>
28 #include <pj/assert.h>
29 
30 /*
31  * Generic parameter manipulation.
32  */
pjsip_param_find(const pjsip_param * param_list,const pj_str_t * name)33 PJ_DEF(pjsip_param*) pjsip_param_find(  const pjsip_param *param_list,
34 					const pj_str_t *name )
35 {
36     pjsip_param *p = (pjsip_param*)param_list->next;
37     while (p != param_list) {
38 	if (pj_stricmp(&p->name, name)==0)
39 	    return p;
40 	p = p->next;
41     }
42     return NULL;
43 }
44 
pjsip_param_cmp(const pjsip_param * param_list1,const pjsip_param * param_list2,pj_bool_t ig_nf)45 PJ_DEF(int) pjsip_param_cmp( const pjsip_param *param_list1,
46 			     const pjsip_param *param_list2,
47 			     pj_bool_t ig_nf)
48 {
49     const pjsip_param *p1;
50 
51     if ((ig_nf & 1)==0 && pj_list_size(param_list1)!=pj_list_size(param_list2))
52 	return 1;
53 
54     p1 = param_list1->next;
55     while (p1 != param_list1) {
56 	const pjsip_param *p2;
57 	p2 = pjsip_param_find(param_list2, &p1->name);
58 	if (p2 ) {
59 	    int rc = pj_stricmp(&p1->value, &p2->value);
60 	    if (rc != 0)
61 		return rc;
62 	} else if ((ig_nf & 1)==0)
63 	    return 1;
64 
65 	p1 = p1->next;
66     }
67 
68     return 0;
69 }
70 
pjsip_param_clone(pj_pool_t * pool,pjsip_param * dst_list,const pjsip_param * src_list)71 PJ_DEF(void) pjsip_param_clone( pj_pool_t *pool, pjsip_param *dst_list,
72 				const pjsip_param *src_list)
73 {
74     const pjsip_param *p = src_list->next;
75 
76     pj_list_init(dst_list);
77     while (p && p != src_list) {
78 	pjsip_param *new_param = PJ_POOL_ALLOC_T(pool, pjsip_param);
79 	pj_strdup(pool, &new_param->name, &p->name);
80 	pj_strdup(pool, &new_param->value, &p->value);
81 	pj_list_insert_before(dst_list, new_param);
82 	p = p->next;
83     }
84 }
85 
86 
pjsip_param_shallow_clone(pj_pool_t * pool,pjsip_param * dst_list,const pjsip_param * src_list)87 PJ_DEF(void) pjsip_param_shallow_clone( pj_pool_t *pool,
88 					pjsip_param *dst_list,
89 					const pjsip_param *src_list)
90 {
91     const pjsip_param *p = src_list->next;
92 
93     pj_list_init(dst_list);
94     while (p != src_list) {
95 	pjsip_param *new_param = PJ_POOL_ALLOC_T(pool, pjsip_param);
96 	new_param->name = p->name;
97 	new_param->value = p->value;
98 	pj_list_insert_before(dst_list, new_param);
99 	p = p->next;
100     }
101 }
102 
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)103 PJ_DEF(pj_ssize_t) pjsip_param_print_on( const pjsip_param *param_list,
104 					 char *buf, pj_size_t size,
105 					 const pj_cis_t *pname_spec,
106 					 const pj_cis_t *pvalue_spec,
107 					 int sep)
108 {
109     const pjsip_param *p;
110     char *startbuf;
111     char *endbuf;
112     int printed;
113 
114     p = param_list->next;
115     if (p == NULL || p == param_list)
116 	return 0;
117 
118     startbuf = buf;
119     endbuf = buf + size;
120 
121     PJ_UNUSED_ARG(pname_spec);
122 
123     do {
124 	copy_advance_char_check(buf, (char)sep);
125 	copy_advance_escape(buf, p->name, (*pname_spec));
126 	if (p->value.slen) {
127 	    copy_advance_char_check(buf, '=');
128 	    if (*p->value.ptr == '"')
129 		copy_advance(buf, p->value);
130 	    else
131 		copy_advance_escape(buf, p->value, (*pvalue_spec));
132 	}
133 	p = p->next;
134 	if (sep == '?') sep = '&';
135     } while (p != param_list);
136 
137     return buf-startbuf;
138 }
139 
140 
141 /*
142  * URI stuffs
143  */
144 #define IS_SIPS(url)	((url)->vptr==&sips_url_vptr)
145 
146 static const pj_str_t *pjsip_url_get_scheme( const pjsip_sip_uri* );
147 static const pj_str_t *pjsips_url_get_scheme( const pjsip_sip_uri* );
148 static const pj_str_t *pjsip_name_addr_get_scheme( const pjsip_name_addr * );
149 static void *pjsip_get_uri( pjsip_uri *uri );
150 static void *pjsip_name_addr_get_uri( pjsip_name_addr *name );
151 
152 static pj_str_t sip_str = { "sip", 3 };
153 static pj_str_t sips_str = { "sips", 4 };
154 
155 static pjsip_name_addr* pjsip_name_addr_clone( pj_pool_t *pool,
156 					       const pjsip_name_addr *rhs);
157 static pj_ssize_t pjsip_name_addr_print(pjsip_uri_context_e context,
158 					const pjsip_name_addr *name,
159 					char *buf, pj_size_t size);
160 static int pjsip_name_addr_compare(  pjsip_uri_context_e context,
161 				     const pjsip_name_addr *naddr1,
162 				     const pjsip_name_addr *naddr2);
163 static pj_ssize_t pjsip_url_print(  pjsip_uri_context_e context,
164 				    const pjsip_sip_uri *url,
165 				    char *buf, pj_size_t size);
166 static int pjsip_url_compare( pjsip_uri_context_e context,
167 			      const pjsip_sip_uri *url1,
168 			      const pjsip_sip_uri *url2);
169 static pjsip_sip_uri* pjsip_url_clone(pj_pool_t *pool,
170 				      const pjsip_sip_uri *rhs);
171 
172 typedef const pj_str_t* (*P_GET_SCHEME)(const void*);
173 typedef void* 		(*P_GET_URI)(void*);
174 typedef pj_ssize_t 	(*P_PRINT_URI)(pjsip_uri_context_e,const void *,
175 				       char*,pj_size_t);
176 typedef int 		(*P_CMP_URI)(pjsip_uri_context_e, const void*,
177 				     const void*);
178 typedef void* 		(*P_CLONE)(pj_pool_t*, const void*);
179 
180 
181 static pjsip_uri_vptr sip_url_vptr =
182 {
183     (P_GET_SCHEME)	&pjsip_url_get_scheme,
184     (P_GET_URI)		&pjsip_get_uri,
185     (P_PRINT_URI) 	&pjsip_url_print,
186     (P_CMP_URI) 	&pjsip_url_compare,
187     (P_CLONE) 		&pjsip_url_clone
188 };
189 
190 static pjsip_uri_vptr sips_url_vptr =
191 {
192     (P_GET_SCHEME)	&pjsips_url_get_scheme,
193     (P_GET_URI)		&pjsip_get_uri,
194     (P_PRINT_URI) 	&pjsip_url_print,
195     (P_CMP_URI) 	&pjsip_url_compare,
196     (P_CLONE) 		&pjsip_url_clone
197 };
198 
199 static pjsip_uri_vptr name_addr_vptr =
200 {
201     (P_GET_SCHEME)	&pjsip_name_addr_get_scheme,
202     (P_GET_URI)		&pjsip_name_addr_get_uri,
203     (P_PRINT_URI) 	&pjsip_name_addr_print,
204     (P_CMP_URI) 	&pjsip_name_addr_compare,
205     (P_CLONE) 		&pjsip_name_addr_clone
206 };
207 
pjsip_url_get_scheme(const pjsip_sip_uri * url)208 static const pj_str_t *pjsip_url_get_scheme(const pjsip_sip_uri *url)
209 {
210     PJ_UNUSED_ARG(url);
211     return &sip_str;
212 }
213 
pjsips_url_get_scheme(const pjsip_sip_uri * url)214 static const pj_str_t *pjsips_url_get_scheme(const pjsip_sip_uri *url)
215 {
216     PJ_UNUSED_ARG(url);
217     return &sips_str;
218 }
219 
pjsip_get_uri(pjsip_uri * uri)220 static void *pjsip_get_uri( pjsip_uri *uri )
221 {
222     return uri;
223 }
224 
pjsip_name_addr_get_uri(pjsip_name_addr * name)225 static void *pjsip_name_addr_get_uri( pjsip_name_addr *name )
226 {
227     return pjsip_uri_get_uri(name->uri);
228 }
229 
pjsip_sip_uri_set_secure(pjsip_sip_uri * url,pj_bool_t secure)230 PJ_DEF(void) pjsip_sip_uri_set_secure( pjsip_sip_uri *url,
231 				       pj_bool_t secure )
232 {
233     url->vptr = secure ? &sips_url_vptr : &sip_url_vptr;
234 }
235 
pjsip_sip_uri_init(pjsip_sip_uri * url,pj_bool_t secure)236 PJ_DEF(void) pjsip_sip_uri_init(pjsip_sip_uri *url, pj_bool_t secure)
237 {
238     pj_bzero(url, sizeof(*url));
239     url->ttl_param = -1;
240     pjsip_sip_uri_set_secure(url, secure);
241     pj_list_init(&url->other_param);
242     pj_list_init(&url->header_param);
243 }
244 
pjsip_sip_uri_create(pj_pool_t * pool,pj_bool_t secure)245 PJ_DEF(pjsip_sip_uri*) pjsip_sip_uri_create( pj_pool_t *pool,
246 					     pj_bool_t secure )
247 {
248     pjsip_sip_uri *url = PJ_POOL_ALLOC_T(pool, pjsip_sip_uri);
249     pjsip_sip_uri_init(url, secure);
250     return url;
251 }
252 
pjsip_url_print(pjsip_uri_context_e context,const pjsip_sip_uri * url,char * buf,pj_size_t size)253 static pj_ssize_t pjsip_url_print(  pjsip_uri_context_e context,
254 				    const pjsip_sip_uri *url,
255 				    char *buf, pj_size_t size)
256 {
257     int printed;
258     char *startbuf = buf;
259     char *endbuf = buf+size;
260     const pj_str_t *scheme;
261     const pjsip_parser_const_t *pc = pjsip_parser_const();
262 
263     *buf = '\0';
264 
265     /* Print scheme ("sip:" or "sips:") */
266     scheme = pjsip_uri_get_scheme(url);
267     copy_advance_check(buf, *scheme);
268     copy_advance_char_check(buf, ':');
269 
270     /* Print "user:password@", if any. */
271     if (url->user.slen) {
272 	const pj_cis_t *spec = pjsip_cfg()->endpt.allow_tx_hash_in_uri ?
273 				&pc->pjsip_USER_SPEC_LENIENT :
274 				&pc->pjsip_USER_SPEC;
275 	copy_advance_escape(buf, url->user, *spec);
276 	if (url->passwd.slen) {
277 	    copy_advance_char_check(buf, ':');
278 	    copy_advance_escape(buf, url->passwd, pc->pjsip_PASSWD_SPEC);
279 	}
280 
281 	copy_advance_char_check(buf, '@');
282     }
283 
284     /* Print host. */
285     pj_assert(url->host.slen != 0);
286     /* Detect IPv6 IP address */
287     if (pj_memchr(url->host.ptr, ':', url->host.slen)) {
288 	copy_advance_pair_quote_cond(buf, "", 0, url->host, '[', ']');
289     } else {
290 	copy_advance_check(buf, url->host);
291     }
292 
293     /* Only print port if it is explicitly specified.
294      * Port is not allowed in To and From header, see Table 1 in
295      * RFC 3261 Section 19.1.1
296      */
297     /* Note: ticket #1141 adds run-time setting to allow port number to
298      * appear in From/To header. Default is still false.
299      */
300     if (url->port &&
301 	(context != PJSIP_URI_IN_FROMTO_HDR ||
302 	 pjsip_cfg()->endpt.allow_port_in_fromto_hdr))
303     {
304 	if (endbuf - buf < 10)
305 	    return -1;
306 
307 	copy_advance_char_check(buf, ':');
308 	printed = pj_utoa(url->port, buf);
309 	buf += printed;
310     }
311 
312     /* User param is allowed in all contexes */
313     copy_advance_pair_check(buf, ";user=", 6, url->user_param);
314 
315     /* Method param is only allowed in external/other context. */
316     if (context == PJSIP_URI_IN_OTHER) {
317 	copy_advance_pair_escape(buf, ";method=", 8, url->method_param,
318 				 pc->pjsip_PARAM_CHAR_SPEC);
319     }
320 
321     /* Transport is not allowed in From/To header. */
322     if (context != PJSIP_URI_IN_FROMTO_HDR) {
323 	copy_advance_pair_escape(buf, ";transport=", 11, url->transport_param,
324 				 pc->pjsip_PARAM_CHAR_SPEC);
325     }
326 
327     /* TTL param is not allowed in From, To, Route, and Record-Route header. */
328     if (url->ttl_param >= 0 && context != PJSIP_URI_IN_FROMTO_HDR &&
329 	context != PJSIP_URI_IN_ROUTING_HDR)
330     {
331 	if (endbuf - buf < 15)
332 	    return -1;
333 	pj_memcpy(buf, ";ttl=", 5);
334 	printed = pj_utoa(url->ttl_param, buf+5);
335 	buf += printed + 5;
336     }
337 
338     /* maddr param is not allowed in From and To header. */
339     if (context != PJSIP_URI_IN_FROMTO_HDR && url->maddr_param.slen) {
340 	/* Detect IPv6 IP address */
341 	if (pj_memchr(url->maddr_param.ptr, ':', url->maddr_param.slen)) {
342 	    copy_advance_pair_quote_cond(buf, ";maddr=", 7, url->maddr_param,
343 				         '[', ']');
344 	} else {
345 	    copy_advance_pair_escape(buf, ";maddr=", 7, url->maddr_param,
346 				     pc->pjsip_PARAM_CHAR_SPEC);
347 	}
348     }
349 
350     /* lr param is not allowed in From, To, and Contact header. */
351     if (url->lr_param && context != PJSIP_URI_IN_FROMTO_HDR &&
352 	context != PJSIP_URI_IN_CONTACT_HDR)
353     {
354 	pj_str_t lr = { ";lr", 3 };
355 	if (endbuf - buf < 3)
356 	    return -1;
357 	copy_advance_check(buf, lr);
358     }
359 
360     /* Other param. */
361     printed = (int)pjsip_param_print_on(&url->other_param, buf, endbuf-buf,
362 					&pc->pjsip_PARAM_CHAR_SPEC,
363 					&pc->pjsip_PARAM_CHAR_SPEC, ';');
364     if (printed < 0)
365 	return -1;
366     buf += printed;
367 
368     /* Header param.
369      * Header param is only allowed in these contexts:
370      *	- PJSIP_URI_IN_CONTACT_HDR
371      *	- PJSIP_URI_IN_OTHER
372      */
373     if (context == PJSIP_URI_IN_CONTACT_HDR || context == PJSIP_URI_IN_OTHER) {
374 	printed = (int)pjsip_param_print_on(&url->header_param, buf, endbuf-buf,
375 					    &pc->pjsip_HDR_CHAR_SPEC,
376 					    &pc->pjsip_HDR_CHAR_SPEC, '?');
377 	if (printed < 0)
378 	    return -1;
379 	buf += printed;
380     }
381 
382     *buf = '\0';
383     return buf-startbuf;
384 }
385 
pjsip_url_compare(pjsip_uri_context_e context,const pjsip_sip_uri * url1,const pjsip_sip_uri * url2)386 static pj_status_t pjsip_url_compare( pjsip_uri_context_e context,
387 				      const pjsip_sip_uri *url1,
388 				      const pjsip_sip_uri *url2)
389 {
390     const pjsip_param *p1;
391 
392     /*
393      * Compare two SIP URL's according to Section 19.1.4 of RFC 3261.
394      */
395 
396     /* SIP and SIPS URI are never equivalent.
397      * Note: just compare the vptr to avoid string comparison.
398      *       Pretty neat huh!!
399      */
400     if (url1->vptr != url2->vptr)
401 	return PJSIP_ECMPSCHEME;
402 
403     /* Comparison of the userinfo of SIP and SIPS URIs is case-sensitive.
404      * This includes userinfo containing passwords or formatted as
405      * telephone-subscribers.
406      */
407     if (pj_strcmp(&url1->user, &url2->user) != 0)
408 	return PJSIP_ECMPUSER;
409     if (pj_strcmp(&url1->passwd, &url2->passwd) != 0)
410 	return PJSIP_ECMPPASSWD;
411 
412     /* Comparison of all other components of the URI is
413      * case-insensitive unless explicitly defined otherwise.
414      */
415 
416     /* The ordering of parameters and header fields is not significant
417      * in comparing SIP and SIPS URIs.
418      */
419 
420     /* Characters other than those in the reserved set (see RFC 2396 [5])
421      * are equivalent to their encoding.
422      */
423 
424     /* An IP address that is the result of a DNS lookup of a host name
425      * does not match that host name.
426      */
427     if (pj_stricmp(&url1->host, &url2->host) != 0)
428 	return PJSIP_ECMPHOST;
429 
430     /* A URI omitting any component with a default value will not match a URI
431      * explicitly containing that component with its default value.
432      * For instance, a URI omitting the optional port component will not match
433      * a URI explicitly declaring port 5060.
434      * The same is true for the transport-parameter, ttl-parameter,
435      * user-parameter, and method components.
436      */
437 
438     /* Port is not allowed in To and From header.
439      */
440     if (context != PJSIP_URI_IN_FROMTO_HDR) {
441 	if (url1->port != url2->port)
442 	    return PJSIP_ECMPPORT;
443     }
444     /* Transport is not allowed in From/To header. */
445     if (context != PJSIP_URI_IN_FROMTO_HDR) {
446 	if (pj_stricmp(&url1->transport_param, &url2->transport_param) != 0)
447 	    return PJSIP_ECMPTRANSPORTPRM;
448     }
449     /* TTL param is not allowed in From, To, Route, and Record-Route header. */
450     if (context != PJSIP_URI_IN_FROMTO_HDR &&
451 	context != PJSIP_URI_IN_ROUTING_HDR)
452     {
453 	if (url1->ttl_param != url2->ttl_param)
454 	    return PJSIP_ECMPTTLPARAM;
455     }
456     /* User param is allowed in all contexes */
457     if (pj_stricmp(&url1->user_param, &url2->user_param) != 0)
458 	return PJSIP_ECMPUSERPARAM;
459     /* Method param is only allowed in external/other context. */
460     if (context == PJSIP_URI_IN_OTHER) {
461 	if (pj_stricmp(&url1->method_param, &url2->method_param) != 0)
462 	    return PJSIP_ECMPMETHODPARAM;
463     }
464     /* maddr param is not allowed in From and To header. */
465     if (context != PJSIP_URI_IN_FROMTO_HDR) {
466 	if (pj_stricmp(&url1->maddr_param, &url2->maddr_param) != 0)
467 	    return PJSIP_ECMPMADDRPARAM;
468     }
469 
470     /* lr parameter is ignored (?) */
471     /* lr param is not allowed in From, To, and Contact header. */
472 
473 
474     /* All other uri-parameters appearing in only one URI are ignored when
475      * comparing the URIs.
476      */
477     if (pjsip_param_cmp(&url1->other_param, &url2->other_param, 1)!=0)
478 	return PJSIP_ECMPOTHERPARAM;
479 
480     /* URI header components are never ignored. Any present header component
481      * MUST be present in both URIs and match for the URIs to match.
482      * The matching rules are defined for each header field in Section 20.
483      */
484     p1 = url1->header_param.next;
485     while (p1 != &url1->header_param) {
486 	const pjsip_param *p2;
487 	p2 = pjsip_param_find(&url2->header_param, &p1->name);
488 	if (p2) {
489 	    /* It seems too much to compare two header params according to
490 	     * the rule of each header. We'll just compare them string to
491 	     * string..
492 	     */
493 	    if (pj_stricmp(&p1->value, &p2->value) != 0)
494 		return PJSIP_ECMPHEADERPARAM;
495 	} else {
496 	    return PJSIP_ECMPHEADERPARAM;
497 	}
498 	p1 = p1->next;
499     }
500 
501     /* Equal!! Pheuww.. */
502     return PJ_SUCCESS;
503 }
504 
505 
pjsip_sip_uri_assign(pj_pool_t * pool,pjsip_sip_uri * url,const pjsip_sip_uri * rhs)506 PJ_DEF(void) pjsip_sip_uri_assign(pj_pool_t *pool, pjsip_sip_uri *url,
507 				  const pjsip_sip_uri *rhs)
508 {
509     pj_strdup( pool, &url->user, &rhs->user);
510     pj_strdup( pool, &url->passwd, &rhs->passwd);
511     pj_strdup( pool, &url->host, &rhs->host);
512     url->port = rhs->port;
513     pj_strdup( pool, &url->user_param, &rhs->user_param);
514     pj_strdup( pool, &url->method_param, &rhs->method_param);
515     pj_strdup( pool, &url->transport_param, &rhs->transport_param);
516     url->ttl_param = rhs->ttl_param;
517     pj_strdup( pool, &url->maddr_param, &rhs->maddr_param);
518     pjsip_param_clone(pool, &url->other_param, &rhs->other_param);
519     pjsip_param_clone(pool, &url->header_param, &rhs->header_param);
520     url->lr_param = rhs->lr_param;
521 }
522 
pjsip_url_clone(pj_pool_t * pool,const pjsip_sip_uri * rhs)523 static pjsip_sip_uri* pjsip_url_clone(pj_pool_t *pool, const pjsip_sip_uri *rhs)
524 {
525     pjsip_sip_uri *url = PJ_POOL_ALLOC_T(pool, pjsip_sip_uri);
526     if (!url)
527 	return NULL;
528 
529     pjsip_sip_uri_init(url, IS_SIPS(rhs));
530     pjsip_sip_uri_assign(pool, url, rhs);
531     return url;
532 }
533 
pjsip_name_addr_get_scheme(const pjsip_name_addr * name)534 static const pj_str_t *pjsip_name_addr_get_scheme(const pjsip_name_addr *name)
535 {
536     pj_assert(name->uri != NULL);
537     return pjsip_uri_get_scheme(name->uri);
538 }
539 
pjsip_name_addr_init(pjsip_name_addr * name)540 PJ_DEF(void) pjsip_name_addr_init(pjsip_name_addr *name)
541 {
542     name->vptr = &name_addr_vptr;
543     name->uri = NULL;
544     name->display.slen = 0;
545     name->display.ptr = NULL;
546 }
547 
pjsip_name_addr_create(pj_pool_t * pool)548 PJ_DEF(pjsip_name_addr*) pjsip_name_addr_create(pj_pool_t *pool)
549 {
550     pjsip_name_addr *name_addr = PJ_POOL_ALLOC_T(pool, pjsip_name_addr);
551     pjsip_name_addr_init(name_addr);
552     return name_addr;
553 }
554 
pjsip_name_addr_print(pjsip_uri_context_e context,const pjsip_name_addr * name,char * buf,pj_size_t size)555 static pj_ssize_t pjsip_name_addr_print(pjsip_uri_context_e context,
556 					const pjsip_name_addr *name,
557 					char *buf, pj_size_t size)
558 {
559     int printed;
560     char *startbuf = buf;
561     char *endbuf = buf + size;
562     pjsip_uri *uri;
563 
564     uri = (pjsip_uri*) pjsip_uri_get_uri(name->uri);
565     pj_assert(uri != NULL);
566 
567     if (context != PJSIP_URI_IN_REQ_URI) {
568 	if (name->display.slen) {
569 	    if (endbuf-buf < name->display.slen + 3) return -1;
570 	    copy_advance_char_check(buf, '"');
571 	    copy_advance(buf, name->display);
572 	    copy_advance_char_check(buf, '"');
573 	    copy_advance_char_check(buf, ' ');
574 	}
575 	copy_advance_char_check(buf, '<');;
576     }
577 
578     printed = pjsip_uri_print(context,uri, buf, size-(buf-startbuf));
579     if (printed < 1)
580 	return -1;
581     buf += printed;
582 
583     if (context != PJSIP_URI_IN_REQ_URI) {
584 	copy_advance_char_check(buf, '>');
585     }
586 
587     *buf = '\0';
588     return buf-startbuf;
589 }
590 
pjsip_name_addr_assign(pj_pool_t * pool,pjsip_name_addr * dst,const pjsip_name_addr * src)591 PJ_DEF(void) pjsip_name_addr_assign(pj_pool_t *pool, pjsip_name_addr *dst,
592 				    const pjsip_name_addr *src)
593 {
594     pj_strdup( pool, &dst->display, &src->display);
595     dst->uri = (pjsip_uri*) pjsip_uri_clone(pool, src->uri);
596 }
597 
pjsip_name_addr_clone(pj_pool_t * pool,const pjsip_name_addr * rhs)598 static pjsip_name_addr* pjsip_name_addr_clone( pj_pool_t *pool,
599 					       const pjsip_name_addr *rhs)
600 {
601     pjsip_name_addr *addr = PJ_POOL_ALLOC_T(pool, pjsip_name_addr);
602     if (!addr)
603 	return NULL;
604 
605     pjsip_name_addr_init(addr);
606     pjsip_name_addr_assign(pool, addr, rhs);
607     return addr;
608 }
609 
pjsip_name_addr_compare(pjsip_uri_context_e context,const pjsip_name_addr * naddr1,const pjsip_name_addr * naddr2)610 static int pjsip_name_addr_compare(  pjsip_uri_context_e context,
611 				     const pjsip_name_addr *naddr1,
612 				     const pjsip_name_addr *naddr2)
613 {
614     int d;
615 
616     /* Check that naddr2 is also a name_addr */
617     if (naddr1->vptr != naddr2->vptr)
618 	return -1;
619 
620     /* I'm not sure whether display name is included in the comparison. */
621     if (pj_strcmp(&naddr1->display, &naddr2->display) != 0) {
622 	return -1;
623     }
624 
625     pj_assert( naddr1->uri != NULL );
626     pj_assert( naddr2->uri != NULL );
627 
628     /* Compare name-addr as URL */
629     d = pjsip_uri_cmp( context, naddr1->uri, naddr2->uri);
630     if (d)
631 	return d;
632 
633     return 0;
634 }
635 
636 ///////////////////////////////////////////////////////////////////////////////
637 
638 static const pj_str_t *other_uri_get_scheme( const pjsip_other_uri*);
639 static void *other_uri_get_uri( pjsip_other_uri*);
640 static pj_ssize_t other_uri_print( pjsip_uri_context_e context,
641 				   const pjsip_other_uri *url,
642 				   char *buf, pj_size_t size);
643 static int other_uri_cmp( pjsip_uri_context_e context,
644 			  const pjsip_other_uri *url1,
645 			  const pjsip_other_uri *url2);
646 static pjsip_other_uri* other_uri_clone( pj_pool_t *pool,
647 					 const pjsip_other_uri *rhs);
648 
649 static pjsip_uri_vptr other_uri_vptr =
650 {
651     (P_GET_SCHEME)  &other_uri_get_scheme,
652     (P_GET_URI)	    &other_uri_get_uri,
653     (P_PRINT_URI)   &other_uri_print,
654     (P_CMP_URI)	    &other_uri_cmp,
655     (P_CLONE) 	    &other_uri_clone
656 };
657 
658 
pjsip_other_uri_create(pj_pool_t * pool)659 PJ_DEF(pjsip_other_uri*) pjsip_other_uri_create(pj_pool_t *pool)
660 {
661     pjsip_other_uri *uri = PJ_POOL_ZALLOC_T(pool, pjsip_other_uri);
662     uri->vptr = &other_uri_vptr;
663     return uri;
664 }
665 
other_uri_get_scheme(const pjsip_other_uri * uri)666 static const pj_str_t *other_uri_get_scheme( const pjsip_other_uri *uri )
667 {
668 	return &uri->scheme;
669 }
670 
other_uri_get_uri(pjsip_other_uri * uri)671 static void *other_uri_get_uri( pjsip_other_uri *uri )
672 {
673     return uri;
674 }
675 
other_uri_print(pjsip_uri_context_e context,const pjsip_other_uri * uri,char * buf,pj_size_t size)676 static pj_ssize_t other_uri_print(pjsip_uri_context_e context,
677 				  const pjsip_other_uri *uri,
678 				  char *buf, pj_size_t size)
679 {
680     char *startbuf = buf;
681     char *endbuf = buf + size;
682 
683     PJ_UNUSED_ARG(context);
684 
685     if (uri->scheme.slen + uri->content.slen + 1 > (int)size)
686 	return -1;
687 
688     /* Print scheme. */
689     copy_advance(buf, uri->scheme);
690     *buf++ = ':';
691 
692     /* Print content. */
693     copy_advance(buf, uri->content);
694 
695     return (buf - startbuf);
696 }
697 
other_uri_cmp(pjsip_uri_context_e context,const pjsip_other_uri * uri1,const pjsip_other_uri * uri2)698 static int other_uri_cmp(pjsip_uri_context_e context,
699 			 const pjsip_other_uri *uri1,
700 			 const pjsip_other_uri *uri2)
701 {
702     PJ_UNUSED_ARG(context);
703 
704     /* Check that uri2 is also an other_uri */
705     if (uri1->vptr != uri2->vptr)
706 	return -1;
707 
708     /* Scheme must match. */
709     if (pj_stricmp(&uri1->scheme, &uri2->scheme) != 0) {
710 	return PJSIP_ECMPSCHEME;
711     }
712 
713     /* Content must match. */
714     if(pj_stricmp(&uri1->content, &uri2->content) != 0) {
715 	return -1;
716     }
717 
718     /* Equal. */
719     return 0;
720 }
721 
722 /* Clone *: URI */
other_uri_clone(pj_pool_t * pool,const pjsip_other_uri * rhs)723 static pjsip_other_uri* other_uri_clone(pj_pool_t *pool,
724 					const pjsip_other_uri *rhs)
725 {
726     pjsip_other_uri *uri = pjsip_other_uri_create(pool);
727     pj_strdup(pool, &uri->scheme, &rhs->scheme);
728     pj_strdup(pool, &uri->content, &rhs->content);
729 
730     return uri;
731 }
732 
733