1 /*
2 The oSIP library implements the Session Initiation Protocol (SIP -rfc3261-)
3 Copyright (C) 2001-2020 Aymeric MOIZARD amoizard@antisip.com
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #include <osipparser2/internal.h>
21
22 #include <osipparser2/osip_port.h>
23 #include <osipparser2/osip_message.h>
24
25 #define osip_is_alpha(in) ((in >= 'a' && in <= 'z') || (in >= 'A' && in <= 'Z'))
26
27 /* allocate a new url structure */
28 /* OUTPUT: osip_uri_t *url | structure to save results. */
29 /* OUTPUT: err_t *err | structure to store error. */
30 /* return -1 on error */
osip_uri_init(osip_uri_t ** url)31 int osip_uri_init(osip_uri_t **url) {
32 *url = (osip_uri_t *) osip_malloc(sizeof(osip_uri_t));
33
34 if (*url == NULL)
35 return OSIP_NOMEM;
36
37 (*url)->scheme = NULL;
38 (*url)->username = NULL;
39 (*url)->password = NULL;
40 (*url)->host = NULL;
41 (*url)->port = NULL;
42
43 osip_list_init(&(*url)->url_params);
44
45 osip_list_init(&(*url)->url_headers);
46
47 (*url)->string = NULL;
48 return OSIP_SUCCESS;
49 }
50
51 /* examples:
52 sip:j.doe@big.com;maddr=239.255.255.1;ttl=15
53 sip:j.doe@big.com
54 sip:j.doe:secret@big.com;transport=tcp
55 sip:j.doe@big.com?subject=project
56 sip:+1-212-555-1212:1234@gateway.com;user=phone
57 sip:1212@gateway.com
58 sip:alice@10.1.2.3
59 sip:alice@example.com
60 sip:alice@registrar.com;method=REGISTER
61
62 NOT EQUIVALENT:
63 SIP:JUSER@ExAmPlE.CoM;Transport=udp
64 sip:juser@ExAmPlE.CoM;Transport=UDP
65 */
66
67 /* this method search for the separator and */
68 /* return it only if it is located before the */
69 /* second separator. */
next_separator(const char * ch,int separator_osip_to_find,int before_separator)70 const char *next_separator(const char *ch, int separator_osip_to_find, int before_separator) {
71 const char *ind;
72 const char *tmp;
73
74 ind = strchr(ch, separator_osip_to_find);
75
76 if (ind == NULL)
77 return NULL;
78
79 tmp = NULL;
80
81 if (before_separator != 0)
82 tmp = strchr(ch, before_separator);
83
84 if (tmp != NULL) {
85 if (ind < tmp)
86 return ind;
87
88 } else
89 return ind;
90
91 return NULL;
92 }
93
94 /* parse the sip url. */
95 /* INPUT : char *buf | url to be parsed.*/
96 /* OUTPUT: osip_uri_t *url | structure to save results. */
97 /* OUTPUT: err_t *err | structure to store error. */
98 /* return -1 on error */
osip_uri_parse(osip_uri_t * url,const char * buf)99 int osip_uri_parse(osip_uri_t *url, const char *buf) {
100 const char *username;
101 const char *password;
102 const char *host;
103 const char *port;
104 const char *params;
105 const char *headers;
106 const char *tmp;
107 int i;
108
109 /* basic tests */
110 if (buf == NULL || buf[0] == '\0')
111 return OSIP_BADPARAMETER;
112
113 tmp = strchr(buf, ':');
114
115 if (tmp == NULL)
116 return OSIP_SYNTAXERROR;
117
118 if (tmp - buf < 2)
119 return OSIP_SYNTAXERROR;
120
121 i = 0;
122
123 while (buf + i < tmp) {
124 if (!osip_is_alpha(buf[i]))
125 return OSIP_SYNTAXERROR;
126
127 i++;
128 }
129
130 url->scheme = (char *) osip_malloc(tmp - buf + 1);
131
132 if (url->scheme == NULL)
133 return OSIP_NOMEM;
134
135 osip_strncpy(url->scheme, buf, tmp - buf);
136
137 if (strchr(url->scheme, ' ') != NULL) {
138 return OSIP_SYNTAXERROR;
139 }
140
141 if (strlen(url->scheme) < 3 || (0 != osip_strncasecmp(url->scheme, "sip", 3) && 0 != osip_strncasecmp(url->scheme, "sips", 4))) { /* Is not a sipurl ! */
142 size_t i = strlen(tmp + 1);
143
144 if (i < 2)
145 return OSIP_SYNTAXERROR;
146
147 url->string = (char *) osip_malloc(i + 1);
148
149 if (url->string == NULL)
150 return OSIP_NOMEM;
151
152 osip_strncpy(url->string, tmp + 1, i);
153 return OSIP_SUCCESS;
154 }
155
156 /* law number 1:
157 if ('?' exists && is_located_after '@')
158 or if ('?' exists && '@' is not there -no username-)
159 =====> HEADER_PARAM EXIST
160 =====> start at index(?)
161 =====> end at the end of url
162 */
163
164 /* find the beginning of host */
165 username = strchr(buf, ':');
166
167 /* if ':' does not exist, the url is not valid */
168 if (username == NULL)
169 return OSIP_SYNTAXERROR;
170
171 host = strchr(buf, '@');
172
173 if (host == NULL)
174 host = username;
175
176 else if (username[1] == '@') /* username is empty */
177 host = username + 1;
178
179 else
180 /* username exists */
181 {
182 password = next_separator(username + 1, ':', '@');
183
184 if (password == NULL)
185 password = host;
186
187 else
188 /* password exists */
189 {
190 if (host - password < 2)
191 return OSIP_SYNTAXERROR;
192
193 url->password = (char *) osip_malloc(host - password);
194
195 if (url->password == NULL)
196 return OSIP_NOMEM;
197
198 osip_strncpy(url->password, password + 1, host - password - 1);
199 __osip_uri_unescape(url->password);
200 }
201
202 if (password - username < 2)
203 return OSIP_SYNTAXERROR;
204
205 {
206 url->username = (char *) osip_malloc(password - username);
207
208 if (url->username == NULL)
209 return OSIP_NOMEM;
210
211 osip_strncpy(url->username, username + 1, password - username - 1);
212 __osip_uri_unescape(url->username);
213 }
214 }
215
216 /* search for header after host */
217 headers = strchr(host, '?');
218
219 if (headers == NULL)
220 headers = buf + strlen(buf);
221
222 else
223 /* headers exist */
224 osip_uri_parse_headers(url, headers);
225
226 /* search for params after host */
227 params = strchr(host, ';'); /* search for params after host */
228
229 if (params == NULL)
230 params = headers;
231
232 else
233 /* params exist */
234 {
235 char *tmpbuf;
236
237 if (headers - params + 1 < 2)
238 return OSIP_SYNTAXERROR;
239
240 tmpbuf = osip_malloc(headers - params + 1);
241
242 if (tmpbuf == NULL)
243 return OSIP_NOMEM;
244
245 tmpbuf = osip_strncpy(tmpbuf, params, headers - params);
246 osip_uri_parse_params(url, tmpbuf);
247 osip_free(tmpbuf);
248 }
249
250 port = params - 1;
251
252 while (port > host && *port != ']' && *port != ':')
253 port--;
254
255 if (*port == ':') {
256 if (host == port)
257 port = params;
258
259 else {
260 if ((params - port < 2) || (params - port > 8))
261 return OSIP_SYNTAXERROR; /* error cases */
262
263 url->port = (char *) osip_malloc(params - port);
264
265 if (url->port == NULL)
266 return OSIP_NOMEM;
267
268 osip_clrncpy(url->port, port + 1, params - port - 1);
269 }
270
271 } else
272 port = params;
273
274 /* adjust port for ipv6 address */
275 tmp = port;
276
277 while (tmp > host && *tmp != ']')
278 tmp--;
279
280 if (*tmp == ']') {
281 port = tmp;
282
283 while (host < port && *host != '[')
284 host++;
285
286 if (host >= port)
287 return OSIP_SYNTAXERROR;
288 }
289
290 if (port - host < 2)
291 return OSIP_SYNTAXERROR;
292
293 url->host = (char *) osip_malloc(port - host);
294
295 if (url->host == NULL)
296 return OSIP_NOMEM;
297
298 osip_clrncpy(url->host, host + 1, port - host - 1);
299
300 return OSIP_SUCCESS;
301 }
302
osip_uri_set_scheme(osip_uri_t * url,char * scheme)303 void osip_uri_set_scheme(osip_uri_t *url, char *scheme) {
304 if (url == NULL)
305 return;
306
307 url->scheme = scheme;
308 }
309
osip_uri_get_scheme(osip_uri_t * url)310 char *osip_uri_get_scheme(osip_uri_t *url) {
311 if (url == NULL)
312 return NULL;
313
314 return url->scheme;
315 }
316
osip_uri_set_username(osip_uri_t * url,char * username)317 void osip_uri_set_username(osip_uri_t *url, char *username) {
318 if (url == NULL)
319 return;
320
321 url->username = username;
322 }
323
osip_uri_get_username(osip_uri_t * url)324 char *osip_uri_get_username(osip_uri_t *url) {
325 if (url == NULL)
326 return NULL;
327
328 return url->username;
329 }
330
osip_uri_set_password(osip_uri_t * url,char * password)331 void osip_uri_set_password(osip_uri_t *url, char *password) {
332 if (url == NULL)
333 return;
334
335 url->password = password;
336 }
337
osip_uri_get_password(osip_uri_t * url)338 char *osip_uri_get_password(osip_uri_t *url) {
339 if (url == NULL)
340 return NULL;
341
342 return url->password;
343 }
344
osip_uri_set_host(osip_uri_t * url,char * host)345 void osip_uri_set_host(osip_uri_t *url, char *host) {
346 if (url == NULL)
347 return;
348
349 url->host = host;
350 }
351
osip_uri_get_host(osip_uri_t * url)352 char *osip_uri_get_host(osip_uri_t *url) {
353 if (url == NULL)
354 return NULL;
355
356 return url->host;
357 }
358
osip_uri_set_port(osip_uri_t * url,char * port)359 void osip_uri_set_port(osip_uri_t *url, char *port) {
360 if (url == NULL)
361 return;
362
363 url->port = port;
364 }
365
osip_uri_get_port(osip_uri_t * url)366 char *osip_uri_get_port(osip_uri_t *url) {
367 if (url == NULL)
368 return NULL;
369
370 return url->port;
371 }
372
osip_uri_parse_headers(osip_uri_t * url,const char * headers)373 int osip_uri_parse_headers(osip_uri_t *url, const char *headers) {
374 int i;
375 const char *_and;
376 const char *equal;
377
378 if (headers[0] != '?') /* This API can only be used with a starting '?' char */
379 return OSIP_SYNTAXERROR;
380
381 /* find '=' wich is the separator for one header */
382 /* find ';' wich is the separator for multiple headers */
383
384 equal = strchr(headers, '=');
385 _and = strchr(headers + 1, '&');
386
387 if (equal == NULL) /* each header MUST have a value */
388 return OSIP_SYNTAXERROR;
389
390 do {
391 char *hname;
392 char *hvalue;
393
394 hname = (char *) osip_malloc(equal - headers);
395
396 if (hname == NULL)
397 return OSIP_NOMEM;
398
399 osip_strncpy(hname, headers + 1, equal - headers - 1);
400 __osip_uri_unescape(hname);
401
402 if (_and != NULL) {
403 if (_and - equal < 2) {
404 osip_free(hname);
405 return OSIP_SYNTAXERROR;
406 }
407
408 hvalue = (char *) osip_malloc(_and - equal);
409
410 if (hvalue == NULL) {
411 osip_free(hname);
412 return OSIP_NOMEM;
413 }
414
415 osip_strncpy(hvalue, equal + 1, _and - equal - 1);
416 __osip_uri_unescape(hvalue);
417
418 } else { /* this is for the last header (no _and...) */
419 if (headers + strlen(headers) - equal + 1 < 2) {
420 osip_free(hname);
421 return OSIP_SYNTAXERROR;
422 }
423
424 hvalue = (char *) osip_malloc(headers + strlen(headers) - equal + 1);
425
426 if (hvalue == NULL) {
427 osip_free(hname);
428 return OSIP_NOMEM;
429 }
430
431 osip_strncpy(hvalue, equal + 1, headers + strlen(headers) - equal);
432 __osip_uri_unescape(hvalue);
433 }
434
435 i = osip_uri_uheader_add(url, hname, hvalue);
436
437 if (i != OSIP_SUCCESS) {
438 osip_free(hname);
439 osip_free(hvalue);
440 return i;
441 }
442
443 if (_and == NULL) /* we just set the last header */
444 equal = NULL;
445
446 else { /* continue on next header */
447
448 headers = _and;
449 equal = strchr(headers, '=');
450 _and = strchr(headers + 1, '&');
451
452 if (equal == NULL) /* each header MUST have a value */
453 return OSIP_SYNTAXERROR;
454 }
455 } while (equal != NULL);
456
457 return OSIP_SUCCESS;
458 }
459
osip_uri_parse_params(osip_uri_t * url,const char * params)460 int osip_uri_parse_params(osip_uri_t *url, const char *params) {
461 int i;
462 char *pname;
463 char *pvalue;
464
465 const char *comma;
466 const char *equal;
467
468 if (params[0] != ';') /* This API can only be used with a starting '?' char */
469 return OSIP_SYNTAXERROR;
470
471 /* find '=' wich is the separator for one param */
472 /* find ';' wich is the separator for multiple params */
473
474 equal = next_separator(params + 1, '=', ';');
475 comma = strchr(params + 1, ';');
476
477 while (comma != NULL) {
478 if (equal == NULL) {
479 equal = comma;
480 pvalue = NULL;
481
482 } else {
483 if (comma - equal < 2)
484 return OSIP_SYNTAXERROR;
485
486 pvalue = (char *) osip_malloc(comma - equal);
487
488 if (pvalue == NULL)
489 return OSIP_NOMEM;
490
491 osip_strncpy(pvalue, equal + 1, comma - equal - 1);
492 __osip_uri_unescape(pvalue);
493 }
494
495 if (equal - params < 2) {
496 osip_free(pvalue);
497 return OSIP_SYNTAXERROR;
498 }
499
500 pname = (char *) osip_malloc(equal - params);
501
502 if (pname == NULL) {
503 osip_free(pvalue);
504 return OSIP_NOMEM;
505 }
506
507 osip_strncpy(pname, params + 1, equal - params - 1);
508 __osip_uri_unescape(pname);
509
510 i = osip_uri_uparam_add(url, pname, pvalue);
511
512 if (i != OSIP_SUCCESS) {
513 osip_free(pname);
514 osip_free(pvalue);
515 return OSIP_NOMEM;
516 }
517
518 params = comma;
519 equal = next_separator(params + 1, '=', ';');
520 comma = strchr(params + 1, ';');
521 }
522
523 /* this is the last header (comma==NULL) */
524 comma = params + strlen(params);
525
526 if (equal == NULL) {
527 equal = comma; /* at the end */
528 pvalue = NULL;
529
530 } else {
531 if (comma - equal < 2)
532 return OSIP_SYNTAXERROR;
533
534 pvalue = (char *) osip_malloc(comma - equal);
535
536 if (pvalue == NULL)
537 return OSIP_NOMEM;
538
539 osip_strncpy(pvalue, equal + 1, comma - equal - 1);
540 __osip_uri_unescape(pvalue);
541 }
542
543 if (equal - params < 2) {
544 osip_free(pvalue);
545 return OSIP_SYNTAXERROR;
546 }
547
548 pname = (char *) osip_malloc(equal - params);
549
550 if (pname == NULL) {
551 osip_free(pvalue);
552 return OSIP_NOMEM;
553 }
554
555 osip_strncpy(pname, params + 1, equal - params - 1);
556 __osip_uri_unescape(pname);
557
558 i = osip_uri_uparam_add(url, pname, pvalue);
559
560 if (i != OSIP_SUCCESS) {
561 osip_free(pname);
562 osip_free(pvalue);
563 return OSIP_NOMEM;
564 }
565
566 return OSIP_SUCCESS;
567 }
568
osip_uri_to_str(const osip_uri_t * url,char ** dest)569 int osip_uri_to_str(const osip_uri_t *url, char **dest) {
570 char *buf;
571 size_t len;
572 size_t plen;
573 char *tmp;
574 const char *scheme;
575
576 *dest = NULL;
577
578 if (url == NULL)
579 return OSIP_BADPARAMETER;
580
581 if (url->host == NULL && url->string == NULL)
582 return OSIP_BADPARAMETER;
583
584 if (url->scheme == NULL && url->string != NULL)
585 return OSIP_BADPARAMETER;
586
587 if (url->string == NULL && url->scheme == NULL)
588 scheme = "sip"; /* default is sipurl */
589 else
590 scheme = url->scheme;
591
592 if (url->string != NULL) {
593 buf = (char *) osip_malloc(strlen(scheme) + strlen(url->string) + 3);
594
595 if (buf == NULL)
596 return OSIP_NOMEM;
597
598 *dest = buf;
599 sprintf(buf, "%s:", scheme);
600 buf = buf + strlen(scheme) + 1;
601 sprintf(buf, "%s", url->string);
602 return OSIP_SUCCESS;
603 }
604
605 len = strlen(scheme) + 1 + strlen(url->host) + 5;
606
607 if (url->username != NULL)
608 len = len + (strlen(url->username) * 3) + 1; /* count escaped char */
609
610 if (url->password != NULL)
611 len = len + (strlen(url->password) * 3) + 1;
612
613 if (url->port != NULL)
614 len = len + strlen(url->port) + 3;
615
616 buf = (char *) osip_malloc(len);
617
618 if (buf == NULL)
619 return OSIP_NOMEM;
620
621 tmp = buf;
622
623 sprintf(tmp, "%s:", scheme);
624 tmp = tmp + strlen(tmp);
625
626 if (url->username != NULL) {
627 char *tmp2 = __osip_uri_escape_userinfo(url->username);
628
629 if (tmp2 == NULL) {
630 osip_free(buf);
631 return OSIP_NOMEM;
632 }
633
634 sprintf(tmp, "%s", tmp2);
635 osip_free(tmp2);
636 tmp = tmp + strlen(tmp);
637 }
638
639 if ((url->password != NULL) && (url->username != NULL)) { /* be sure that when a password is given, a username is also given */
640 char *tmp2 = __osip_uri_escape_password(url->password);
641
642 if (tmp2 == NULL) {
643 osip_free(buf);
644 return OSIP_NOMEM;
645 }
646
647 sprintf(tmp, ":%s", tmp2);
648 osip_free(tmp2);
649 tmp = tmp + strlen(tmp);
650 }
651
652 if (url->username != NULL) { /* we add a '@' only when username is present... */
653 sprintf(tmp, "@");
654 tmp++;
655 }
656
657 if (strchr(url->host, ':') != NULL) {
658 sprintf(tmp, "[%s]", url->host);
659 tmp = tmp + strlen(tmp);
660
661 } else {
662 sprintf(tmp, "%s", url->host);
663 tmp = tmp + strlen(tmp);
664 }
665
666 if (url->port != NULL) {
667 sprintf(tmp, ":%s", url->port);
668 tmp = tmp + strlen(tmp);
669 }
670
671 {
672 osip_list_iterator_t it;
673 osip_uri_param_t *u_param = (osip_uri_param_t *) osip_list_get_first(&url->url_params, &it);
674
675 while (u_param != OSIP_SUCCESS) {
676 char *tmp1;
677 char *tmp2 = NULL;
678 char *previous_buf;
679
680 if (osip_strcasecmp(u_param->gname, "x-obr") == 0 || osip_strcasecmp(u_param->gname, "x-obp") == 0) {
681 /* x-obr and x-obp are internal params used by exosip: they must not appear in messages */
682 u_param = (osip_uri_param_t *) osip_list_get_next(&it);
683 continue;
684 }
685
686 tmp1 = __osip_uri_escape_uri_param(u_param->gname);
687
688 if (tmp1 == NULL) {
689 osip_free(buf);
690 return OSIP_SYNTAXERROR;
691 }
692
693 if (u_param->gvalue == NULL)
694 plen = strlen(tmp1) + 2;
695
696 else {
697 tmp2 = __osip_uri_escape_uri_param(u_param->gvalue);
698
699 if (tmp2 == NULL) {
700 osip_free(tmp1);
701 osip_free(buf);
702 return OSIP_SYNTAXERROR;
703 }
704
705 plen = strlen(tmp1) + strlen(tmp2) + 3;
706 }
707
708 len = len + plen;
709 previous_buf = buf;
710 buf = (char *) osip_realloc(buf, len);
711
712 if (buf == NULL) {
713 osip_free(previous_buf);
714 osip_free(tmp1);
715 osip_free(tmp2);
716 return OSIP_NOMEM;
717 }
718
719 tmp = buf;
720 tmp = tmp + strlen(tmp);
721
722 if (u_param->gvalue == NULL)
723 sprintf(tmp, ";%s", tmp1);
724
725 else {
726 sprintf(tmp, ";%s=%s", tmp1, tmp2);
727 osip_free(tmp2);
728 }
729
730 osip_free(tmp1);
731 u_param = (osip_uri_param_t *) osip_list_get_next(&it);
732 }
733 }
734
735 {
736 osip_list_iterator_t it;
737 osip_uri_header_t *u_header = (osip_uri_header_t *) osip_list_get_first(&url->url_headers, &it);
738
739 while (u_header != OSIP_SUCCESS) {
740 char *tmp1;
741 char *tmp2;
742 char *previous_buf;
743
744 tmp1 = __osip_uri_escape_header_param(u_header->gname);
745
746 if (tmp1 == NULL) {
747 osip_free(buf);
748 return OSIP_SYNTAXERROR;
749 }
750
751 tmp2 = __osip_uri_escape_header_param(u_header->gvalue);
752
753 if (tmp2 == NULL) {
754 osip_free(tmp1);
755 osip_free(buf);
756 return OSIP_SYNTAXERROR;
757 }
758
759 plen = strlen(tmp1) + strlen(tmp2) + 4;
760
761 len = len + plen;
762 previous_buf = buf;
763 buf = (char *) osip_realloc(buf, len);
764
765 if (buf == NULL) {
766 osip_free(previous_buf);
767 osip_free(tmp1);
768 osip_free(tmp2);
769 return OSIP_NOMEM;
770 }
771
772 tmp = buf;
773 tmp = tmp + strlen(tmp);
774
775 if (it.pos == 0)
776 snprintf(tmp, len - (tmp - buf), "?%s=%s", tmp1, tmp2);
777
778 else
779 snprintf(tmp, len - (tmp - buf), "&%s=%s", tmp1, tmp2);
780
781 osip_free(tmp1);
782 osip_free(tmp2);
783 u_header = (osip_uri_header_t *) osip_list_get_next(&it);
784 }
785 }
786
787 *dest = buf;
788 return OSIP_SUCCESS;
789 }
790
osip_uri_free(osip_uri_t * url)791 void osip_uri_free(osip_uri_t *url) {
792 if (url == NULL)
793 return;
794
795 osip_free(url->scheme);
796 osip_free(url->username);
797 osip_free(url->password);
798 osip_free(url->host);
799 osip_free(url->port);
800
801 osip_uri_param_freelist(&url->url_params);
802
803 {
804 osip_uri_header_t *u_header;
805
806 while (!osip_list_eol(&url->url_headers, 0)) {
807 u_header = (osip_uri_header_t *) osip_list_get(&url->url_headers, 0);
808 osip_list_remove(&url->url_headers, 0);
809 osip_uri_header_free(u_header);
810 }
811 }
812
813 osip_free(url->string);
814
815 osip_free(url);
816 }
817
osip_uri_clone(const osip_uri_t * url,osip_uri_t ** dest)818 int osip_uri_clone(const osip_uri_t *url, osip_uri_t **dest) {
819 int i;
820 osip_uri_t *ur;
821
822 *dest = NULL;
823
824 if (url == NULL)
825 return OSIP_BADPARAMETER;
826
827 if (url->host == NULL && url->string == NULL)
828 return OSIP_BADPARAMETER;
829
830 i = osip_uri_init(&ur);
831
832 if (i != 0) /* allocation failed */
833 return i;
834
835 if (url->scheme != NULL)
836 ur->scheme = osip_strdup(url->scheme);
837
838 if (url->username != NULL)
839 ur->username = osip_strdup(url->username);
840
841 if (url->password != NULL)
842 ur->password = osip_strdup(url->password);
843
844 if (url->host != NULL)
845 ur->host = osip_strdup(url->host);
846
847 if (url->port != NULL)
848 ur->port = osip_strdup(url->port);
849
850 if (url->string != NULL)
851 ur->string = osip_strdup(url->string);
852
853 i = osip_list_clone(&url->url_params, &ur->url_params, (int (*)(void *, void **)) & osip_uri_param_clone);
854
855 if (i != 0) {
856 osip_uri_free(ur);
857 return i;
858 }
859
860 i = osip_list_clone(&url->url_headers, &ur->url_headers, (int (*)(void *, void **)) & osip_uri_param_clone);
861
862 if (i != 0) {
863 osip_uri_free(ur);
864 return i;
865 }
866
867 *dest = ur;
868 return OSIP_SUCCESS;
869 }
870
osip_uri_param_init(osip_uri_param_t ** url_param)871 int osip_uri_param_init(osip_uri_param_t **url_param) {
872 *url_param = (osip_uri_param_t *) osip_malloc(sizeof(osip_uri_param_t));
873
874 if (*url_param == NULL)
875 return OSIP_NOMEM;
876
877 (*url_param)->gname = NULL;
878 (*url_param)->gvalue = NULL;
879 return OSIP_SUCCESS;
880 }
881
osip_uri_param_free(osip_uri_param_t * url_param)882 void osip_uri_param_free(osip_uri_param_t *url_param) {
883 osip_free(url_param->gname);
884 osip_free(url_param->gvalue);
885 osip_free(url_param);
886 }
887
osip_uri_param_set(osip_uri_param_t * url_param,char * pname,char * pvalue)888 int osip_uri_param_set(osip_uri_param_t *url_param, char *pname, char *pvalue) {
889 url_param->gname = pname;
890 /* not needed for url, but for all other generic params */
891 osip_clrspace(url_param->gname);
892 url_param->gvalue = pvalue;
893
894 if (url_param->gvalue != NULL)
895 osip_clrspace(url_param->gvalue);
896
897 return OSIP_SUCCESS;
898 }
899
osip_uri_param_add(osip_list_t * url_params,char * pname,char * pvalue)900 int osip_uri_param_add(osip_list_t *url_params, char *pname, char *pvalue) {
901 int i;
902 osip_uri_param_t *url_param;
903
904 i = osip_uri_param_init(&url_param);
905
906 if (i != 0)
907 return i;
908
909 i = osip_uri_param_set(url_param, pname, pvalue);
910
911 if (i != 0) {
912 osip_uri_param_free(url_param);
913 return i;
914 }
915
916 osip_list_add(url_params, url_param, -1);
917 return OSIP_SUCCESS;
918 }
919
osip_uri_param_freelist(osip_list_t * params)920 void osip_uri_param_freelist(osip_list_t *params) {
921 osip_uri_param_t *u_param;
922
923 while (!osip_list_eol(params, 0)) {
924 u_param = (osip_uri_param_t *) osip_list_get(params, 0);
925 osip_list_remove(params, 0);
926 osip_uri_param_free(u_param);
927 }
928 }
929
osip_uri_param_get_byname(osip_list_t * params,char * pname,osip_uri_param_t ** url_param)930 int osip_uri_param_get_byname(osip_list_t *params, char *pname, osip_uri_param_t **url_param) {
931 size_t pname_len;
932 osip_uri_param_t *u_param;
933 osip_list_iterator_t it;
934
935 *url_param = NULL;
936
937 if (pname == NULL)
938 return OSIP_BADPARAMETER;
939
940 pname_len = strlen(pname);
941
942 if (pname_len <= 0)
943 return OSIP_BADPARAMETER;
944
945 u_param = (osip_uri_param_t *) osip_list_get_first(params, &it);
946
947 while (u_param != OSIP_SUCCESS) {
948 size_t len;
949
950 len = strlen(u_param->gname);
951
952 if (pname_len == len && osip_strncasecmp(u_param->gname, pname, strlen(pname)) == 0) {
953 *url_param = u_param;
954 return OSIP_SUCCESS;
955 }
956
957 u_param = (osip_uri_param_t *) osip_list_get_next(&it);
958 }
959
960 return OSIP_UNDEFINED_ERROR;
961 }
962
osip_uri_param_clone(const osip_uri_param_t * uparam,osip_uri_param_t ** dest)963 int osip_uri_param_clone(const osip_uri_param_t *uparam, osip_uri_param_t **dest) {
964 int i;
965 osip_uri_param_t *up;
966
967 *dest = NULL;
968
969 if (uparam == NULL)
970 return OSIP_BADPARAMETER;
971
972 if (uparam->gname == NULL)
973 return OSIP_BADPARAMETER; /* name is mandatory */
974
975 i = osip_uri_param_init(&up);
976
977 if (i != 0) /* allocation failed */
978 return i;
979
980 up->gname = osip_strdup(uparam->gname);
981
982 if (uparam->gvalue != NULL)
983 up->gvalue = osip_strdup(uparam->gvalue);
984
985 else
986 up->gvalue = NULL;
987
988 *dest = up;
989 return OSIP_SUCCESS;
990 }
991
992 #define _ALPHANUM_ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890\0"
993 #define _RESERVED_ ";/?:@&=+$\0"
994 #define _MARK_ "-_.!~*'()\0"
995
996 #define _MARK__USER_UNRESERVED_ "-_.!~*'()&=+$,;?/\0"
997 #define _MARK__PWORD_UNRESERVED_ "-_.!~*'()&=+$,\0"
998 #define _MARK__URI_PARAM_UNRESERVED_ "-_.!~*'()[]/:&+$\0"
999 #define _MARK__HEADER_PARAM_UNRESERVED_ "-_.!~*'()[]/?:+$\0"
1000
1001 #define osip_is_alphanum(in) ((in >= 'a' && in <= 'z') || (in >= 'A' && in <= 'Z') || (in >= '0' && in <= '9'))
1002
__osip_uri_escape_nonascii_and_nondef(const char * string,const char * def)1003 char *__osip_uri_escape_nonascii_and_nondef(const char *string, const char *def) {
1004 size_t alloc = strlen(string) + 1;
1005 size_t length;
1006 char *ns = (char *) osip_malloc(alloc);
1007 unsigned char in;
1008 size_t newlen = alloc;
1009 int index = 0;
1010 const char *tmp;
1011 int i;
1012
1013 if (ns == NULL)
1014 return NULL;
1015
1016 length = alloc - 1;
1017
1018 while (length--) {
1019 in = *string;
1020
1021 i = 0;
1022 tmp = NULL;
1023
1024 if (osip_is_alphanum(in))
1025 tmp = string;
1026
1027 else {
1028 for (; def[i] != '\0' && def[i] != in; i++) {
1029 }
1030
1031 if (def[i] != '\0')
1032 tmp = string;
1033 }
1034
1035 if (tmp == NULL) {
1036 /* encode it */
1037 newlen += 2; /* the size grows with two, since this'll become a %XX */
1038
1039 if (newlen > alloc) {
1040 char *previous_ns;
1041
1042 alloc *= 2;
1043 previous_ns = ns;
1044 ns = osip_realloc(ns, alloc);
1045
1046 if (!ns) {
1047 osip_free(previous_ns);
1048 return NULL;
1049 }
1050 }
1051
1052 sprintf(&ns[index], "%%%02X", in);
1053 index += 3;
1054
1055 } else {
1056 /* just copy this */
1057 ns[index++] = in;
1058 }
1059
1060 string++;
1061 }
1062
1063 ns[index] = 0; /* terminate it */
1064 return ns;
1065 }
1066
1067 /* user = *( unreserved / escaped / user-unreserved ) */
1068 const char *userinfo_def = /* implied _ALPHANUM_ */ _MARK__USER_UNRESERVED_;
__osip_uri_escape_userinfo(const char * string)1069 char *__osip_uri_escape_userinfo(const char *string) {
1070 return __osip_uri_escape_nonascii_and_nondef(string, userinfo_def);
1071 }
1072
1073 /* user = *( unreserved / escaped / user-unreserved ) */
1074 const char *password_def = _MARK__PWORD_UNRESERVED_;
__osip_uri_escape_password(const char * string)1075 char *__osip_uri_escape_password(const char *string) {
1076 return __osip_uri_escape_nonascii_and_nondef(string, password_def);
1077 }
1078
1079 const char *uri_param_def = _MARK__URI_PARAM_UNRESERVED_;
__osip_uri_escape_uri_param(char * string)1080 char *__osip_uri_escape_uri_param(char *string) {
1081 return __osip_uri_escape_nonascii_and_nondef(string, uri_param_def);
1082 }
1083
1084 const char *header_param_def = _MARK__HEADER_PARAM_UNRESERVED_;
__osip_uri_escape_header_param(char * string)1085 char *__osip_uri_escape_header_param(char *string) {
1086 return __osip_uri_escape_nonascii_and_nondef(string, header_param_def);
1087 }
1088
__osip_uri_unescape(char * string)1089 void __osip_uri_unescape(char *string) {
1090 size_t alloc = strlen(string) + 1;
1091 unsigned char in;
1092 int index = 0;
1093 unsigned int hex;
1094 char *ptr;
1095
1096 ptr = string;
1097
1098 while (--alloc > 0) {
1099 in = *ptr;
1100
1101 if ('%' == in) {
1102 /* encoded part */
1103 if (alloc > 2 && sscanf(ptr + 1, "%02X", &hex) == 1) {
1104 in = (unsigned char) hex;
1105
1106 if (*(ptr + 2) && ((*(ptr + 2) >= '0' && *(ptr + 2) <= '9') || (*(ptr + 2) >= 'a' && *(ptr + 2) <= 'f') || (*(ptr + 2) >= 'A' && *(ptr + 2) <= 'F'))) {
1107 alloc -= 2;
1108 ptr += 2;
1109
1110 } else {
1111 alloc -= 1;
1112 ptr += 1;
1113 }
1114
1115 } else {
1116 break;
1117 }
1118 }
1119
1120 string[index++] = in;
1121 ptr++;
1122 }
1123
1124 string[index] = 0; /* terminate it */
1125 }
1126
1127 /* RFC3261 16.5
1128 */
osip_uri_to_str_canonical(const osip_uri_t * url,char ** dest)1129 int osip_uri_to_str_canonical(const osip_uri_t *url, char **dest) {
1130 int result;
1131
1132 *dest = NULL;
1133 result = osip_uri_to_str(url, dest);
1134
1135 if (result == 0) {
1136 /*
1137 tmp = strchr(*dest, ";");
1138 if (tmp !=NULL) {
1139 buf=strndup(*dest, tmp-(*dest));
1140 osip_free(*dest);
1141 *dest=buf;
1142 }
1143 */
1144 __osip_uri_unescape(*dest);
1145 }
1146
1147 return result;
1148 }
1149