Tristan Matthews | 0a329cc | 2013-07-17 13:20:14 -0400 | [diff] [blame] | 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 | */ |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | *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 | |
| 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 | |
| 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 | |
| 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 | |
| 220 | static void *pjsip_get_uri( pjsip_uri *uri ) |
| 221 | { |
| 222 | return uri; |
| 223 | } |
| 224 | |
| 225 | static void *pjsip_name_addr_get_uri( pjsip_name_addr *name ) |
| 226 | { |
| 227 | return pjsip_uri_get_uri(name->uri); |
| 228 | } |
| 229 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | *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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 < 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 666 | static const pj_str_t *other_uri_get_scheme( const pjsip_other_uri *uri ) |
| 667 | { |
| 668 | return &uri->scheme; |
| 669 | } |
| 670 | |
| 671 | static void *other_uri_get_uri( pjsip_other_uri *uri ) |
| 672 | { |
| 673 | return uri; |
| 674 | } |
| 675 | |
| 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 | |
| 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 */ |
| 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 | |