2 The oSIP library implements the Session Initiation Protocol (SIP -rfc3261-)
3 Copyright (C) 2001,2002,2003 Aymeric MOIZARD jack@atosc.org
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.
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.
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
20 #include <osipparser2/osip_port.h>
21 #include <osipparser2/osip_message.h>
25 /* allocate a new url structure */
26 /* OUTPUT: osip_uri_t *url | structure to save results. */
27 /* OUTPUT: err_t *err | structure to store error. */
28 /* return -1 on error */
30 osip_uri_init (osip_uri_t ** url)
32 *url = (osip_uri_t *) osip_malloc (sizeof (osip_uri_t));
35 (*url)->scheme = NULL;
36 (*url)->username = NULL;
37 (*url)->password = NULL;
41 (*url)->url_params = (osip_list_t *) osip_malloc (sizeof (osip_list_t));
42 if ((*url)->url_params == NULL)
48 osip_list_init ((*url)->url_params);
50 (*url)->url_headers = (osip_list_t *) osip_malloc (sizeof (osip_list_t));
51 if ((*url)->url_headers == NULL)
53 osip_free ((*url)->url_params);
58 osip_list_init ((*url)->url_headers);
60 (*url)->string = NULL;
65 sip:j.doe@big.com;maddr=239.255.255.1;ttl=15
67 sip:j.doe:secret@big.com;transport=tcp
68 sip:j.doe@big.com?subject=project
69 sip:+1-212-555-1212:1234@gateway.com;user=phone
73 sip:alice@registrar.com;method=REGISTER
76 SIP:JUSER@ExAmPlE.CoM;Transport=udp
77 sip:juser@ExAmPlE.CoM;Transport=UDP
80 /* this method search for the separator and */
81 /* return it only if it is located before the */
82 /* second separator. */
84 next_separator (const char *ch, int separator_osip_to_find,
90 ind = strchr (ch, separator_osip_to_find);
95 if (before_separator != 0)
96 tmp = strchr (ch, before_separator);
109 /* parse the sip url. */
110 /* INPUT : char *buf | url to be parsed.*/
111 /* OUTPUT: osip_uri_t *url | structure to save results. */
112 /* OUTPUT: err_t *err | structure to store error. */
113 /* return -1 on error */
115 osip_uri_parse (osip_uri_t * url, const char *buf)
126 if (buf == NULL || buf[0] == '\0')
129 tmp = strchr (buf, ':');
135 url->scheme = (char *) osip_malloc (tmp - buf + 1);
136 if (url->scheme == NULL)
138 osip_strncpy (url->scheme, buf, tmp - buf);
140 if (strlen (url->scheme) < 3 ||
141 (0 != osip_strncasecmp (url->scheme, "sip", 3)
142 && 0 != osip_strncasecmp (url->scheme, "sips", 4)))
143 { /* Is not a sipurl ! */
144 size_t i = strlen (tmp + 1);
148 url->string = (char *) osip_malloc (i + 1);
149 if (url->string == NULL)
151 osip_strncpy (url->string, tmp + 1, i);
156 if ('?' exists && is_located_after '@')
157 or if ('?' exists && '@' is not there -no username-)
158 =====> HEADER_PARAM EXIST
159 =====> start at index(?)
160 =====> end at the end of url
163 /* find the beginning of host */
164 username = strchr (buf, ':');
165 /* if ':' does not exist, the url is not valid */
166 if (username == NULL)
169 host = strchr (buf, '@');
174 /* username exists */
176 password = next_separator (username + 1, ':', '@');
177 if (password == NULL)
180 /* password exists */
182 if (host - password < 2)
184 url->password = (char *) osip_malloc (host - password);
185 if (url->password == NULL)
187 osip_strncpy (url->password, password + 1, host - password - 1);
188 __osip_uri_unescape (url->password);
190 if (password - username < 2)
193 url->username = (char *) osip_malloc (password - username);
194 if (url->username == NULL)
196 osip_strncpy (url->username, username + 1, password - username - 1);
197 __osip_uri_unescape (url->username);
202 /* search for header after host */
203 headers = strchr (host, '?');
206 headers = buf + strlen (buf);
209 osip_uri_parse_headers (url, headers);
212 /* search for params after host */
213 params = strchr (host, ';'); /* search for params after host */
220 if (headers - params + 1 < 2)
222 tmpbuf = osip_malloc (headers - params + 1);
225 tmpbuf = osip_strncpy (tmpbuf, params, headers - params);
226 osip_uri_parse_params (url, tmpbuf);
231 while (port > host && *port != ']' && *port != ':')
239 if ((params - port < 2) || (params - port > 8))
240 return -1; /* error cases */
241 url->port = (char *) osip_malloc (params - port);
242 if (url->port == NULL)
244 osip_strncpy (url->port, port + 1, params - port - 1);
245 osip_clrspace (url->port);
250 /* adjust port for ipv6 address */
252 while (tmp > host && *tmp != ']')
257 while (host < port && *host != '[')
265 url->host = (char *) osip_malloc (port - host);
266 if (url->host == NULL)
268 osip_strncpy (url->host, host + 1, port - host - 1);
269 osip_clrspace (url->host);
275 osip_uri_set_scheme (osip_uri_t * url, char *scheme)
277 url->scheme = scheme;
281 osip_uri_get_scheme (osip_uri_t * url)
289 osip_uri_set_username (osip_uri_t * url, char *username)
291 url->username = username;
295 osip_uri_get_username (osip_uri_t * url)
299 return url->username;
303 osip_uri_set_password (osip_uri_t * url, char *password)
305 url->password = password;
309 osip_uri_get_password (osip_uri_t * url)
313 return url->password;
317 osip_uri_set_host (osip_uri_t * url, char *host)
323 osip_uri_get_host (osip_uri_t * url)
331 osip_uri_set_port (osip_uri_t * url, char *port)
337 osip_uri_get_port (osip_uri_t * url)
346 osip_uri_parse_headers (osip_uri_t * url, const char *headers)
351 /* find '=' wich is the separator for one header */
352 /* find ';' wich is the separator for multiple headers */
354 equal = strchr (headers, '=');
355 and = strchr (headers + 1, '&');
357 if (equal == NULL) /* each header MUST have a value */
365 hname = (char *) osip_malloc (equal - headers);
368 osip_strncpy (hname, headers + 1, equal - headers - 1);
369 __osip_uri_unescape (hname);
378 hvalue = (char *) osip_malloc (and - equal);
384 osip_strncpy (hvalue, equal + 1, and - equal - 1);
385 __osip_uri_unescape (hvalue);
388 { /* this is for the last header (no and...) */
389 if (headers + strlen (headers) - equal + 1 < 2)
395 (char *) osip_malloc (headers + strlen (headers) - equal + 1);
401 osip_strncpy (hvalue, equal + 1,
402 headers + strlen (headers) - equal);
403 __osip_uri_unescape (hvalue);
406 osip_uri_uheader_add (url, hname, hvalue);
408 if (and == NULL) /* we just set the last header */
410 else /* continue on next header */
413 equal = strchr (headers, '=');
414 and = strchr (headers + 1, '&');
415 if (equal == NULL) /* each header MUST have a value */
419 while (equal != NULL);
424 osip_uri_parse_params (osip_uri_t * url, const char *params)
432 /* find '=' wich is the separator for one param */
433 /* find ';' wich is the separator for multiple params */
435 equal = next_separator (params + 1, '=', ';');
436 comma = strchr (params + 1, ';');
438 while (comma != NULL)
447 if (comma - equal < 2)
449 pvalue = (char *) osip_malloc (comma - equal);
452 osip_strncpy (pvalue, equal + 1, comma - equal - 1);
453 __osip_uri_unescape (pvalue);
456 if (equal - params < 2)
461 pname = (char *) osip_malloc (equal - params);
467 osip_strncpy (pname, params + 1, equal - params - 1);
468 __osip_uri_unescape (pname);
470 osip_uri_uparam_add (url, pname, pvalue);
473 equal = next_separator (params + 1, '=', ';');
474 comma = strchr (params + 1, ';');
477 /* this is the last header (comma==NULL) */
478 comma = params + strlen (params);
482 equal = comma; /* at the end */
487 if (comma - equal < 2)
489 pvalue = (char *) osip_malloc (comma - equal);
492 osip_strncpy (pvalue, equal + 1, comma - equal - 1);
495 if (equal - params < 2)
500 pname = (char *) osip_malloc (equal - params);
506 osip_strncpy (pname, params + 1, equal - params - 1);
508 osip_uri_uparam_add (url, pname, pvalue);
514 osip_uri_to_str (const osip_uri_t * url, char **dest)
525 if (url->host == NULL && url->string == NULL)
527 if (url->scheme == NULL && url->string != NULL)
529 if (url->string == NULL && url->scheme == NULL)
530 scheme = "sip"; /* default is sipurl */
532 scheme = url->scheme;
534 if (url->string != NULL)
536 buf = (char *) osip_malloc (strlen (scheme) + strlen (url->string) + 3);
540 sprintf (buf, "%s:", scheme);
541 buf = buf + strlen (scheme) + 1;
542 sprintf (buf, "%s", url->string);
543 buf = buf + strlen (url->string);
547 len = strlen (scheme) + 1 + strlen (url->host) + 5;
548 if (url->username != NULL)
549 len = len + (strlen (url->username) * 3) + 1; /* count escaped char */
550 if (url->password != NULL)
551 len = len + (strlen (url->password) * 3) + 1;
552 if (url->port != NULL)
553 len = len + strlen (url->port) + 3;
555 buf = (char *) osip_malloc (len);
560 sprintf (tmp, "%s:", scheme);
561 tmp = tmp + strlen (tmp);
563 if (url->username != NULL)
565 char *tmp2 = __osip_uri_escape_userinfo (url->username);
567 sprintf (tmp, "%s", tmp2);
569 tmp = tmp + strlen (tmp);
571 if ((url->password != NULL) && (url->username != NULL))
572 { /* be sure that when a password is given, a username is also given */
573 char *tmp2 = __osip_uri_escape_password (url->password);
575 sprintf (tmp, ":%s", tmp2);
577 tmp = tmp + strlen (tmp);
579 if (url->username != NULL)
580 { /* we add a '@' only when username is present... */
584 if (strchr (url->host, ':') != NULL)
586 sprintf (tmp, "[%s]", url->host);
587 tmp = tmp + strlen (tmp);
591 sprintf (tmp, "%s", url->host);
592 tmp = tmp + strlen (tmp);
594 if (url->port != NULL)
596 sprintf (tmp, ":%s", url->port);
597 tmp = tmp + strlen (tmp);
602 osip_uri_param_t *u_param;
604 while (!osip_list_eol (url->url_params, pos))
609 u_param = (osip_uri_param_t *) osip_list_get (url->url_params, pos);
611 tmp1 = __osip_uri_escape_uri_param (u_param->gname);
612 if (u_param->gvalue == NULL)
613 plen = strlen (tmp1) + 2;
616 tmp2 = __osip_uri_escape_uri_param (u_param->gvalue);
617 plen = strlen (tmp1) + strlen (tmp2) + 3;
620 buf = (char *) realloc (buf, len);
622 tmp = tmp + strlen (tmp);
623 if (u_param->gvalue == NULL)
624 sprintf (tmp, ";%s", tmp1);
627 sprintf (tmp, ";%s=%s", tmp1, tmp2);
637 osip_uri_header_t *u_header;
639 while (!osip_list_eol (url->url_headers, pos))
645 (osip_uri_header_t *) osip_list_get (url->url_headers, pos);
646 tmp1 = __osip_uri_escape_header_param (u_header->gname);
647 tmp2 = __osip_uri_escape_header_param (u_header->gvalue);
649 if (tmp1 == NULL || tmp2 == NULL)
654 plen = strlen (tmp1) + strlen (tmp2) + 4;
657 buf = (char *) realloc (buf, len);
659 tmp = tmp + strlen (tmp);
662 sprintf (tmp, "?%s=%s", u_header->gname, u_header->gvalue);
665 sprintf (tmp, "&%s=%s", u_header->gname, u_header->gvalue);
678 osip_uri_free (osip_uri_t * url)
684 osip_free (url->scheme);
685 osip_free (url->username);
686 osip_free (url->password);
687 osip_free (url->host);
688 osip_free (url->port);
690 osip_uri_param_freelist (url->url_params);
693 osip_uri_header_t *u_header;
695 while (!osip_list_eol (url->url_headers, pos))
698 (osip_uri_header_t *) osip_list_get (url->url_headers, pos);
699 osip_list_remove (url->url_headers, pos);
700 osip_uri_header_free (u_header);
702 osip_free (url->url_headers);
705 osip_free (url->string);
711 osip_uri_clone (const osip_uri_t * url, osip_uri_t ** dest)
719 if (url->host == NULL && url->string == NULL)
722 i = osip_uri_init (&ur);
723 if (i == -1) /* allocation failed */
725 if (url->scheme != NULL)
726 ur->scheme = osip_strdup (url->scheme);
727 if (url->username != NULL)
728 ur->username = osip_strdup (url->username);
729 if (url->password != NULL)
730 ur->password = osip_strdup (url->password);
731 if (url->host != NULL)
732 ur->host = osip_strdup (url->host);
733 if (url->port != NULL)
734 ur->port = osip_strdup (url->port);
735 if (url->string != NULL)
736 ur->string = osip_strdup (url->string);
740 osip_uri_param_t *u_param;
741 osip_uri_param_t *dest_param;
743 while (!osip_list_eol (url->url_params, pos))
745 u_param = (osip_uri_param_t *) osip_list_get (url->url_params, pos);
746 i = osip_uri_param_clone (u_param, &dest_param);
749 osip_list_add (ur->url_params, dest_param, -1);
755 osip_uri_param_t *u_param;
756 osip_uri_param_t *dest_param;
758 while (!osip_list_eol (url->url_headers, pos))
760 u_param = (osip_uri_param_t *) osip_list_get (url->url_headers, pos);
761 i = osip_uri_param_clone (u_param, &dest_param);
764 osip_list_add (ur->url_headers, dest_param, -1);
774 osip_uri_param_init (osip_uri_param_t ** url_param)
776 *url_param = (osip_uri_param_t *) osip_malloc (sizeof (osip_uri_param_t));
777 (*url_param)->gname = NULL;
778 (*url_param)->gvalue = NULL;
783 osip_uri_param_free (osip_uri_param_t * url_param)
785 osip_free (url_param->gname);
786 osip_free (url_param->gvalue);
787 osip_free (url_param);
791 osip_uri_param_set (osip_uri_param_t * url_param, char *pname, char *pvalue)
793 url_param->gname = pname;
794 /* not needed for url, but for all other generic params */
795 osip_clrspace (url_param->gname);
796 url_param->gvalue = pvalue;
797 if (url_param->gvalue != NULL)
798 osip_clrspace (url_param->gvalue);
803 osip_uri_param_add (osip_list_t * url_params, char *pname, char *pvalue)
806 osip_uri_param_t *url_param;
808 i = osip_uri_param_init (&url_param);
811 i = osip_uri_param_set (url_param, pname, pvalue);
814 osip_uri_param_free (url_param);
817 osip_list_add (url_params, url_param, -1);
822 osip_uri_param_freelist (osip_list_t * params)
824 osip_uri_param_t *u_param;
826 while (!osip_list_eol (params, 0))
828 u_param = (osip_uri_param_t *) osip_list_get (params, 0);
829 osip_list_remove (params, 0);
830 osip_uri_param_free (u_param);
836 osip_uri_param_get_byname (osip_list_t * params, char *pname,
837 osip_uri_param_t ** url_param)
841 osip_uri_param_t *u_param;
845 pname_len = strlen(pname);
848 while (!osip_list_eol (params, pos))
851 u_param = (osip_uri_param_t *) osip_list_get (params, pos);
852 len = strlen(u_param->gname);
853 if (pname_len == len && osip_strncasecmp (u_param->gname, pname, strlen (pname)) == 0)
855 *url_param = u_param;
864 osip_uri_param_clone (const osip_uri_param_t * uparam,
865 osip_uri_param_t ** dest)
868 osip_uri_param_t *up;
873 if (uparam->gname == NULL)
874 return -1; /* name is mandatory */
876 i = osip_uri_param_init (&up);
877 if (i != 0) /* allocation failed */
879 up->gname = osip_strdup (uparam->gname);
880 if (uparam->gvalue != NULL)
881 up->gvalue = osip_strdup (uparam->gvalue);
889 #define _ALPHANUM_ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890\0"
890 #define _RESERVED_ ";/?:@&=+$\0"
891 #define _MARK_ "-_.!~*'()\0"
893 #define _MARK__USER_UNRESERVED_ "-_.!~*'()&=+$,;?/\0"
894 #define _MARK__PWORD_UNRESERVED_ "-_.!~*'()&=+$,\0"
895 #define _MARK__URI_PARAM_UNRESERVED_ "-_.!~*'()[]/:&+$\0"
896 #define _MARK__HEADER_PARAM_UNRESERVED_ "-_.!~*'()[]/?:+$\0"
898 #define osip_is_alphanum(in) ( \
899 (in >= 'a' && in <= 'z') || \
900 (in >= 'A' && in <= 'Z') || \
901 (in >= '0' && in <= '9'))
904 __osip_uri_escape_nonascii_and_nondef (const char *string, const char *def)
906 size_t alloc = strlen (string) + 1;
908 char *ns = osip_malloc (alloc);
910 size_t newlen = alloc;
922 if (osip_is_alphanum (in))
926 for (; def[i] != '\0' && def[i] != in; i++)
935 newlen += 2; /* the size grows with two, since this'll become a %XX */
939 ns = realloc (ns, alloc);
943 sprintf (&ns[index], "%%%02X", in);
953 ns[index] = 0; /* terminate it */
957 /* user = *( unreserved / escaped / user-unreserved ) */
958 const char *userinfo_def = /* implied _ALPHANUM_ */ _MARK__USER_UNRESERVED_;
960 __osip_uri_escape_userinfo (const char *string)
962 return __osip_uri_escape_nonascii_and_nondef (string, userinfo_def);
965 /* user = *( unreserved / escaped / user-unreserved ) */
966 const char *password_def = _MARK__PWORD_UNRESERVED_;
968 __osip_uri_escape_password (const char *string)
970 return __osip_uri_escape_nonascii_and_nondef (string, password_def);
973 const char *uri_param_def = _MARK__URI_PARAM_UNRESERVED_;
975 __osip_uri_escape_uri_param (char *string)
977 return __osip_uri_escape_nonascii_and_nondef (string, uri_param_def);
980 const char *header_param_def = _MARK__HEADER_PARAM_UNRESERVED_;
982 __osip_uri_escape_header_param (char *string)
984 return __osip_uri_escape_nonascii_and_nondef (string, header_param_def);
988 __osip_uri_unescape (char *string)
990 size_t alloc = strlen (string) + 1;
1003 if (sscanf (ptr + 1, "%02X", &hex))
1005 in = (unsigned char) hex;
1011 string[index++] = in;
1014 string[index] = 0; /* terminate it */
1018 Robin Nayathodan <roooot@softhome.net>
1019 N.K Electronics INDIA
1025 osip_uri_to_str_canonical (const osip_uri_t * url, char **dest)
1029 result = osip_uri_to_str (url, dest);
1033 tmp = strchr(*dest, ";");
1035 buf=strndup(*dest, tmp-(*dest));
1040 __osip_uri_unescape (*dest);