blob: 0870186cb3ba54dae9ba9923cb2d3b253b81ae2d [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $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 */
33PJ_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
45PJ_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
71PJ_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
87PJ_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
103PJ_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 *buf++ = (char)sep;
125 copy_advance_escape(buf, p->name, (*pname_spec));
126 if (p->value.slen) {
127 *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
146static const pj_str_t *pjsip_url_get_scheme( const pjsip_sip_uri* );
147static const pj_str_t *pjsips_url_get_scheme( const pjsip_sip_uri* );
148static const pj_str_t *pjsip_name_addr_get_scheme( const pjsip_name_addr * );
149static void *pjsip_get_uri( pjsip_uri *uri );
150static void *pjsip_name_addr_get_uri( pjsip_name_addr *name );
151
152static pj_str_t sip_str = { "sip", 3 };
153static pj_str_t sips_str = { "sips", 4 };
154
155static pjsip_name_addr* pjsip_name_addr_clone( pj_pool_t *pool,
156 const pjsip_name_addr *rhs);
157static 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);
160static int pjsip_name_addr_compare( pjsip_uri_context_e context,
161 const pjsip_name_addr *naddr1,
162 const pjsip_name_addr *naddr2);
163static pj_ssize_t pjsip_url_print( pjsip_uri_context_e context,
164 const pjsip_sip_uri *url,
165 char *buf, pj_size_t size);
166static int pjsip_url_compare( pjsip_uri_context_e context,
167 const pjsip_sip_uri *url1,
168 const pjsip_sip_uri *url2);
169static pjsip_sip_uri* pjsip_url_clone(pj_pool_t *pool,
170 const pjsip_sip_uri *rhs);
171
172typedef const pj_str_t* (*P_GET_SCHEME)(const void*);
173typedef void* (*P_GET_URI)(void*);
174typedef pj_ssize_t (*P_PRINT_URI)(pjsip_uri_context_e,const void *,
175 char*,pj_size_t);
176typedef int (*P_CMP_URI)(pjsip_uri_context_e, const void*,
177 const void*);
178typedef void* (*P_CLONE)(pj_pool_t*, const void*);
179
180
181static 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
190static 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
199static 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
208static 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
214static 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
220static void *pjsip_get_uri( pjsip_uri *uri )
221{
222 return uri;
223}
224
225static void *pjsip_name_addr_get_uri( pjsip_name_addr *name )
226{
227 return pjsip_uri_get_uri(name->uri);
228}
229
230PJ_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
236PJ_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
245PJ_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
253static 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 *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 *buf++ = ':';
278 copy_advance_escape(buf, url->passwd, pc->pjsip_PASSWD_SPEC);
279 }
280
281 *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 *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
386static 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
506PJ_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
523static 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
534static 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
540PJ_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
548PJ_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
555static 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 < 8) return -1;
570 *buf++ = '"';
571 copy_advance(buf, name->display);
572 *buf++ = '"';
573 *buf++ = ' ';
574 }
575 *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 *buf++ = '>';
585 }
586
587 *buf = '\0';
588 return buf-startbuf;
589}
590
591PJ_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
598static 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
610static 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
638static const pj_str_t *other_uri_get_scheme( const pjsip_other_uri*);
639static void *other_uri_get_uri( pjsip_other_uri*);
640static pj_ssize_t other_uri_print( pjsip_uri_context_e context,
641 const pjsip_other_uri *url,
642 char *buf, pj_size_t size);
643static int other_uri_cmp( pjsip_uri_context_e context,
644 const pjsip_other_uri *url1,
645 const pjsip_other_uri *url2);
646static pjsip_other_uri* other_uri_clone( pj_pool_t *pool,
647 const pjsip_other_uri *rhs);
648
649static 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
659PJ_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
666static const pj_str_t *other_uri_get_scheme( const pjsip_other_uri *uri )
667{
668 return &uri->scheme;
669}
670
671static void *other_uri_get_uri( pjsip_other_uri *uri )
672{
673 return uri;
674}
675
676static 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
698static 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 */
723static 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