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