--- chan_sip.c 2007-04-06 16:43:39.745369582 +0200 +++ chan_sip.new.c 2007-04-06 16:52:32.688765732 +0200 @@ -7670,6 +7670,119 @@ return TRUE; } +/*! + * Strip the options part from the uri. + * Take into account the URIs of the form: + * sip:5551234;phone-context=+1212@example.net;user=phone + * from RFC 4504, where we have semicolon before '@'. + * return pointer to the beginning of the token, replace the semicolon, + * just before the options with '\0' and advance *uri to point at the begining + * of the options + */ +static char *strip_uri_options(char **uri) +{ + char *atsign, *semi; + char *ret = *uri; + + atsign = strchr(*uri, '@'); + semi = strchr(*uri, ';'); + + if (!semi) { + *uri = 0; + return ret; + } + + if (!atsign) { + *semi = 0; + *uri = semi + 1; + return ret; + } + + if (semi < atsign) { + semi = strchr(atsign + 1, ';'); + + if (!semi) { + *uri = 0; + return ret; + } + + } + + *semi = 0; + *uri = semi + 1; + return ret; +} + +/*! + * parses a URI in its components. + * If scheme is specified, drop it from the top. + * If a component is not requested, do not split around it. + * This means that if we don't have domain, we cannot split + * name:pass and domain:port. + * It is safe to call with ret_name, pass, domain, port + * pointing all to the same place. + * Init pointers to empty string so we never get NULL dereferencing. + * Overwrites the string. + * return 0 on success, other values on error. + */ +static int parse_uri(char *uri, char *scheme, + char **ret_name, char **pass, char **domain, char **port, char **options) +{ + char *name = NULL; + int error = 0; + + /* init field as required */ + if (pass) + *pass = ""; + if (port) + *port = ""; + name = strip_uri_options(&uri); /* remove options */ + if (scheme) { + int l = strlen(scheme); + if (!strncmp(name, scheme, l)) + name += l; + else { + ast_log(LOG_NOTICE, "Missing scheme '%s' in '%s'\n", scheme, name); + error = -1; + } + } + if (!domain) { + /* if we don't want to split around domain, keep everything as a name, + * so we need to do nothing here, except remember why. + */ + } else { + /* store the result in a temp. variable to avoid it being + * overwritten if arguments point to the same place. + */ + char *c, *dom = ""; + + if ((c = strchr(name, '@')) == NULL) { + /* domain-only URI, according to the SIP RFC. */ + dom = name; + name = ""; + } else { + *c++ = '\0'; + dom = c; + } + if (port && (c = strchr(dom, ':'))) { /* Remove :port */ + *c++ = '\0'; + *port = c; + } + if (pass && (c = strchr(name, ':'))) { /* user:password */ + *c++ = '\0'; + *pass = c; + } + *domain = dom; + } + if (ret_name) /* same as for domain, store the result only at the end */ + *ret_name = name; + if (options) + *options = uri ? uri : ""; + + return error; +} + + /*! \brief Change the other partys IP address based on given contact */ static int set_address_from_contact(struct sip_pvt *pvt) { @@ -7732,6 +7845,7 @@ } + /*! \brief Parse contact header and save registration (peer registration) */ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, struct sip_peer *peer, struct sip_request *req) {