/* The oSIP library implements the Session Initiation Protocol (SIP -rfc3261-) Copyright (C) 2001,2002,2003,2004,2005 Aymeric MOIZARD jack@atosc.org This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* HISTORY: v0.5.0: created. v0.6.0: 16/07/2001 complete support for from: new structure new osip_from_parse() method */ #include #include #include #include #include #include "parser.h" /* adds the from header to message. */ /* INPUT : char *hvalue | value of header. */ /* OUTPUT: osip_message_t *sip | structure to save results. */ /* returns -1 on error. */ int osip_message_set_from (osip_message_t * sip, const char *hvalue) { int i; if (hvalue == NULL || hvalue[0] == '\0') return 0; if (sip->from != NULL) return -1; i = osip_from_init (&(sip->from)); if (i != 0) return -1; sip->message_property = 2; i = osip_from_parse (sip->from, hvalue); if (i != 0) { osip_from_free (sip->from); sip->from = NULL; return -1; } return 0; } /* returns the from header. */ /* INPUT : osip_message_t *sip | sip message. */ /* returns null on error. */ osip_from_t * osip_message_get_from (const osip_message_t * sip) { return sip->from; } int osip_from_init (osip_from_t ** from) { *from = (osip_from_t *) osip_malloc (sizeof (osip_from_t)); if (*from == NULL) return -1; (*from)->displayname = NULL; (*from)->url = NULL; osip_list_init (&(*from)->gen_params); return 0; } /* deallocates a osip_from_t structure. */ /* INPUT : osip_from_t *from | from. */ void osip_from_free (osip_from_t * from) { if (from == NULL) return; if (from->url != NULL) { osip_uri_free (from->url); } osip_free (from->displayname); osip_generic_param_freelist (&from->gen_params); osip_free (from); } /* parses the string as a from header. */ /* INPUT : const char *string | pointer to a from string.*/ /* OUTPUT: osip_from_t *from | structure to save results. */ /* returns -1 on error. */ int osip_from_parse (osip_from_t * from, const char *hvalue) { const char *displayname; const char *url; const char *url_end; const char *gen_params; /* How to parse: we'll place the pointers: displayname => beginning of displayname url => beginning of url url_end => end of url gen_params => beginning of params examples: jack ;tag=34erZ ^ ^ ^ ^ sip:jack@atosc.org;tag=34erZ ^ ^^ */ displayname = strchr (hvalue, '"'); url = strchr (hvalue, '<'); if (url != NULL) { url_end = strchr (url, '>'); if (url_end == NULL) return -1; } /* SIPit day2: this case was not supported first '"' is placed after '<' and after '>' ;description="OPEN";expires=28800 if the fisrt quote is after '<' then this is not a quote for a displayname. */ if (displayname != NULL) { if (displayname > url) displayname = NULL; } if ((displayname == NULL) && (url != NULL)) { /* displayname IS A '*token' (not a quoted-string) */ if (hvalue != url) /* displayname exists */ { if (url - hvalue + 1 < 2) return -1; from->displayname = (char *) osip_malloc (url - hvalue + 1); if (from->displayname == NULL) return -1; osip_clrncpy (from->displayname, hvalue, url - hvalue); } url++; /* place pointer on the beginning of url */ } else { if ((displayname != NULL) && (url != NULL)) { /* displayname IS A quoted-string (not a '*token') */ const char *first; const char *second=NULL; /* search for quotes */ first = __osip_quote_find (hvalue); if (first == NULL) return -1; /* missing quote */ second = __osip_quote_find (first + 1); if (second == NULL) return -1; /* missing quote */ if ((first > url)) return -1; if (second - first + 2 >= 2) { from->displayname = (char *) osip_malloc (second - first + 2); if (from->displayname == NULL) return -1; osip_strncpy (from->displayname, first, second - first + 1); /* osip_clrspace(from->displayname); *//*should we do that? */ /* special case: "" */ } /* else displayname is empty? */ url = strchr (second + 1, '<'); if (url == NULL) return -1; /* '<' MUST exist */ url++; } else url = hvalue; /* field does not contains '<' and '>' */ } /* DISPLAY-NAME SET */ /* START of URL KNOWN */ url_end = strchr (url, '>'); if (url_end == NULL) /* sip:jack@atosc.org;tag=023 */ { /* We are sure ';' is the delimiter for from-parameters */ char *host = strchr (url, '@'); if (host != NULL) gen_params = strchr (host, ';'); else gen_params = strchr (url, ';'); if (gen_params != NULL) url_end = gen_params - 1; else url_end = url + strlen (url); } else /* jack ;tag=azer */ { gen_params = strchr (url_end, ';'); url_end--; /* place pointer on the beginning of url */ } if (gen_params != NULL) /* now we are sure a param exist */ if (__osip_generic_param_parseall (&from->gen_params, gen_params) == -1) { return -1; } /* set the url */ { char *tmp; int i; if (url_end - url + 2 < 7) return -1; i = osip_uri_init (&(from->url)); if (i != 0) return -1; tmp = (char *) osip_malloc (url_end - url + 2); if (tmp == NULL) return -1; osip_strncpy (tmp, url, url_end - url + 1); i = osip_uri_parse (from->url, tmp); osip_free (tmp); if (i != 0) return -1; } return 0; } /* returns the from header as a string. */ /* INPUT : osip_from_t *from | from header. */ /* returns -1 on error. */ int osip_from_to_str (const osip_from_t * from, char **dest) { char *url; char *buf; int i; size_t len; *dest = NULL; if ((from == NULL) || (from->url == NULL)) return -1; i = osip_uri_to_str (from->url, &url); if (i != 0) return -1; if (from->displayname == NULL) len = strlen (url) + 5; else len = strlen (url) + strlen (from->displayname) + 5; buf = (char *) osip_malloc (len); if (buf == NULL) { osip_free (url); return -1; } if (from->displayname != NULL) sprintf (buf, "%s <%s>", from->displayname, url); else /* from rfc2543bis-04: for authentication related issue! "The To and From header fields always include the < and > delimiters even if the display-name is empty." */ sprintf (buf, "<%s>", url); osip_free (url); { int pos = 0; osip_generic_param_t *u_param; size_t plen; char *tmp; while (!osip_list_eol (&from->gen_params, pos)) { u_param = (osip_generic_param_t *) osip_list_get (&from->gen_params, pos); if (u_param->gvalue == NULL) plen = strlen (u_param->gname) + 2; else plen = strlen (u_param->gname) + strlen (u_param->gvalue) + 3; len = len + plen; buf = (char *) osip_realloc (buf, len); tmp = buf; tmp = tmp + strlen (tmp); if (u_param->gvalue == NULL) sprintf (tmp, ";%s", u_param->gname); else sprintf (tmp, ";%s=%s", u_param->gname, u_param->gvalue); pos++; } } *dest = buf; return 0; } char * osip_from_get_displayname (osip_from_t * from) { if (from == NULL) return NULL; return from->displayname; } void osip_from_set_displayname (osip_from_t * from, char *displayname) { from->displayname = displayname; } osip_uri_t * osip_from_get_url (osip_from_t * from) { if (from == NULL) return NULL; return from->url; } void osip_from_set_url (osip_from_t * from, osip_uri_t * url) { from->url = url; } int osip_from_param_get (osip_from_t * from, int pos, osip_generic_param_t ** fparam) { *fparam = NULL; if (from == NULL) return -1; if (osip_list_size (&from->gen_params) <= pos) return -1; /* does not exist */ *fparam = (osip_generic_param_t *) osip_list_get (&from->gen_params, pos); return pos; } int osip_from_clone (const osip_from_t * from, osip_from_t ** dest) { int i; osip_from_t *fr; *dest = NULL; if (from == NULL) return -1; i = osip_from_init (&fr); if (i != 0) /* allocation failed */ return -1; if (from->displayname != NULL) fr->displayname = osip_strdup (from->displayname); if (from->url != NULL) { i = osip_uri_clone (from->url, &(fr->url)); if (i != 0) { osip_from_free (fr); return -1; } } { int pos = 0; osip_generic_param_t *u_param; osip_generic_param_t *dest_param; while (!osip_list_eol (&from->gen_params, pos)) { u_param = (osip_generic_param_t *) osip_list_get (&from->gen_params, pos); i = osip_generic_param_clone (u_param, &dest_param); if (i != 0) { osip_from_free (fr); return -1; } osip_list_add (&fr->gen_params, dest_param, -1); pos++; } } *dest = fr; return 0; } int osip_from_compare (osip_from_t * from1, osip_from_t * from2) { char *tag1; char *tag2; if (from1 == NULL || from2 == NULL) return -1; if (from1->url == NULL || from2->url == NULL) return -1; /* we could have a sip or sips url, but if string!=NULL, host part will be NULL. */ if (from1->url->host == NULL && from2->url->host == NULL) { if (from1->url->string == NULL || from2->url->string == NULL) return -1; if (0 == strcmp (from1->url->string, from2->url->string)) return 0; } if (from1->url->host == NULL || from2->url->host == NULL) return -1; /* compare url including tag */ if (0 != strcmp (from1->url->host, from2->url->host)) return -1; if (from1->url->username != NULL && from2->url->username != NULL) if (0 != strcmp (from1->url->username, from2->url->username)) return -1; tag1 = NULL; tag2 = NULL; { int pos = 0; osip_generic_param_t *u_param; while (!osip_list_eol (&from1->gen_params, pos)) { u_param = (osip_generic_param_t *) osip_list_get (&from1->gen_params, pos); if (0 == strncmp (u_param->gname, "tag", 3)) { tag1 = u_param->gvalue; break; } pos++; } } { int pos = 0; osip_generic_param_t *u_param; while (!osip_list_eol (&from2->gen_params, pos)) { u_param = (osip_generic_param_t *) osip_list_get (&from2->gen_params, pos); if (0 == strncmp (u_param->gname, "tag", 3)) { tag2 = u_param->gvalue; break; } pos++; } } /* sounds like a BUG! if tag2 exists and tag1 does not, then it will return 0; in the first request, (INVITE) the To field does not contain any tag. The response contains one! and the response must match the request.... */ /* so we test the tags only when both exist! */ if (tag1 != NULL && tag2 != NULL) if (0 != strcmp (tag1, tag2)) return -1; /* We could return a special case, when */ /* only one tag exists?? */ return 0; /* return code changed to 0 from release 0.6.1 */ } int __osip_generic_param_parseall (osip_list_t * gen_params, const char *params) { char *pname; char *old_pname = NULL; char *pvalue; char *old_pvalue = NULL; const char *comma; const char *equal; /* find '=' wich is the separator for one param */ /* find ';' wich is the separator for multiple params */ equal = next_separator (params + 1, '=', ';'); comma = strchr (params + 1, ';'); while (comma != NULL) { if (equal == NULL) { equal = comma; pvalue = NULL; } else { const char *tmp; /* check for NULL param with an '=' character */ tmp = equal + 1; for (; *tmp == '\t' || *tmp == ' '; tmp++) { } pvalue = NULL; if (*tmp != ',' && *tmp != '\0') { if (comma - equal < 2) return -1; pvalue = (char *) osip_malloc (comma - equal); if (pvalue == NULL) return -1; osip_strncpy (pvalue, equal + 1, comma - equal - 1); } } if (equal - params < 2) { osip_free (pvalue); return -1; } pname = (char *) osip_malloc (equal - params); if (pname == NULL) { osip_free (pvalue); return -1; } osip_strncpy (pname, params + 1, equal - params - 1); if ( old_pname == NULL || osip_strcasecmp(old_pname, pname) != 0 || ( osip_strcasecmp(old_pname, pname) == 0 && pvalue && old_pvalue && strcmp(old_pvalue, pvalue) != 0)) { osip_generic_param_add (gen_params, pname, pvalue); old_pname = pname; old_pvalue = pvalue; } else { osip_free (pvalue); osip_free (pname); } params = comma; equal = next_separator (params + 1, '=', ';'); comma = strchr (params + 1, ';'); } /* this is the last header (comma==NULL) */ comma = params + strlen (params); if (equal == NULL) { equal = comma; /* at the end */ pvalue = NULL; } else { const char *tmp; /* check for NULL param with an '=' character */ tmp = equal + 1; for (; *tmp == '\t' || *tmp == ' '; tmp++) { } pvalue = NULL; if (*tmp != ',' && *tmp != '\0') { if (comma - equal < 2) return -1; pvalue = (char *) osip_malloc (comma - equal); if (pvalue == NULL) return -1; osip_strncpy (pvalue, equal + 1, comma - equal - 1); } } if (equal - params < 2) { osip_free (pvalue); return -1; } pname = (char *) osip_malloc (equal - params); if (pname == NULL) { osip_free (pvalue); return -1; } osip_strncpy (pname, params + 1, equal - params - 1); if ( old_pname == NULL || osip_strcasecmp(old_pname, pname) != 0 || ( osip_strcasecmp(old_pname, pname) == 0 && pvalue && old_pvalue && strcmp(old_pvalue, pvalue) != 0)) { osip_generic_param_add (gen_params, pname, pvalue); } else { osip_free (pvalue); osip_free (pname); } return 0; } void osip_generic_param_set_value (osip_generic_param_t * fparam, char *value) { fparam->gvalue = value; } char * osip_generic_param_get_name (const osip_generic_param_t * fparam) { if (fparam == NULL) return NULL; return fparam->gname; } void osip_generic_param_set_name (osip_generic_param_t * fparam, char *name) { fparam->gname = name; } char * osip_generic_param_get_value (const osip_generic_param_t * fparam) { if (fparam == NULL) return NULL; if (fparam->gname == NULL) return NULL; /* name is mandatory */ return fparam->gvalue; } int osip_from_tag_match (osip_from_t * from1, osip_from_t * from2) { osip_generic_param_t *tag_from1; osip_generic_param_t *tag_from2; osip_from_param_get_byname (from1, "tag", &tag_from1); osip_from_param_get_byname (from2, "tag", &tag_from2); if (tag_from1 == NULL && tag_from2 == NULL) return 0; if ((tag_from1 != NULL && tag_from2 == NULL) || (tag_from1 == NULL && tag_from2 != NULL)) return -1; if (tag_from1->gvalue == NULL || tag_from2->gvalue == NULL) return -1; if (0 != strcmp (tag_from1->gvalue, tag_from2->gvalue)) return -1; return 0; }