Commit affe4a0a authored by Pekka Pessi's avatar Pekka Pessi

sip: added sip_url_query_as_taglist().

darcs-hash:20061005232546-65a35-143a9aa9b368c02b9abac9dc2139129ca6c04b2f.gz
parent 6e488292
......@@ -162,7 +162,7 @@ tagi_t *siptag_filter(tagi_t *dst,
}
}
/** Add duplicates of headers from taglist to the SIP message. */
/** Duplicate headers from taglist and add them to the SIP message. */
int sip_add_tl(msg_t *msg, sip_t *sip,
tag_type_t tag, tag_value_t value, ...)
{
......@@ -239,15 +239,33 @@ static char const *append_escaped(su_strlst_t *l,
msg_hclass_t const *hc,
char const *s);
/** Convert SIP headers to a URL-encoded headers list.
/** Convert tagged SIP headers to a URL-encoded headers list.
*
* The SIP URI can contain a query part separated with the "?", which
* specifies SIP headers that are included in the request constructed
* from the URI. For example, using URI @code <sip:example.com?subject=test>
* would include @Subject header with value "test" in the request.
*
* @param home memory home used to allocate query string (if NULL, use malloc)
* @param tag, value, ... list of tagged arguments
*
* @bug This function returns NULL if SIPTAG_REQUEST(), SIPTAG_STATUS(),
* SIPTAG_HEADER(), SIPTAG_UNKNOWN(), SIPTAG_ERROR(), SIPTAG_SEPARATOR(), or
* any corresponding string tag is included in the tag list. It ignores
* SIPTAG_SIP().
*
* @par Example
* @code
* url->url_headers =
* sip_headers_as_url_query(home, SIPTAG_REPLACES(replaces), TAG_END());
*
* @endcode
*
* @since New in @VERSION_1_12_4.
*
* @sa
* url_query_as_header_string(), sip_url_query_as_taglist(),
* nta_msg_request_complete(),
* @RFC3261 section 19.1.1 "Headers", #url_t, url_s#url_headers
*/
char *sip_headers_as_url_query(su_home_t *home,
tag_type_t tag, tag_value_t value,
......@@ -296,7 +314,11 @@ char *sip_headers_as_url_query(su_home_t *home,
return (char *)retval;
}
/** Append a string to list and url-escape it if needed */
/* "[" / "]" / "/" / "?" / ":" / "+" / "$" */
#define HNV_UNRESERVED "[]/?;+$"
#define HNV_RESERVED ":=,"
/* Append a string to list and url-escape it if needed */
static
char const *append_escaped(su_strlst_t *l,
msg_hclass_t const *hc,
......@@ -330,15 +352,120 @@ char const *append_escaped(su_strlst_t *l,
if (isupper(*n))
*n = tolower(*n);
slen = strlen(s); elen = url_esclen(s, NULL);
slen = strlen(s); elen = url_esclen(s, HNV_RESERVED);
if ((size_t)elen == slen)
return su_strlst_append(l, s);
escaped = su_alloc(lhome, elen + 1);
if (escaped)
return su_strlst_append(l, url_escape(escaped, s, NULL));
return su_strlst_append(l, url_escape(escaped, s, HNV_RESERVED));
}
return NULL;
}
/** Convert URL query to a tag list.
*
* SIP headers encoded as URL @a query is parsed returned as a tag list.
* Unknown headers are encoded as SIPTAG_HEADER_STR().
*
* @param home memory home used to alloate string (if NULL, malloc() it)
* @param query query part from SIP URL
* @param parser optional SIP parser used
*
* @sa sip_add_tl(), sip_add_tagis(), SIPTAG_HEADER_STR(),
* sip_headers_as_url_query(), url_query_as_header_string(),
* @RFC3261 section 19.1.1 "Headers", #url_t, url_s#url_headers
*
* @bug Extension headers are ignored. The @a parser parameter is not used
* at the moment.
*/
tagi_t *sip_url_query_as_taglist(su_home_t *home, char const *query,
msg_mclass_t const *parser)
{
tagi_t *retval = NULL;
char *s;
su_strlst_t *l;
isize_t N;
size_t i, j, n;
if (query == NULL || query[0] == '\0' || query[0] == '&')
return NULL;
s = su_strdup(home, query); if (!s) return NULL;
l = su_strlst_split(home, s, "&");
N = su_strlst_len(l);
if (N == 0)
goto error;
retval = su_zalloc(home, (N + 1) * sizeof (*retval));
if (retval == NULL)
goto error;
for (i = 0; i < N; i++) {
char const *hnv;
char *value;
tag_type_t t;
tag_value_t v;
msg_hclass_t const *hc = NULL;
hnv = su_strlst_item(l, i);
n = strcspn(hnv, "=");
if (n == 0)
break;
if (n == 4 && strncasecmp(hnv, "body", 4) == 0)
t = siptag_payload, hc = sip_payload_class;
else for (j = 0; (t = sip_tag_list[j]); j++) {
hc = (msg_hclass_t *)sip_tag_list[j]->tt_magic;
if (n == 1 && strncasecmp(hnv, hc->hc_short, 1) == 0)
break;
else if (n == hc->hc_len && strncasecmp(hnv, hc->hc_name, n) == 0)
break;
}
value = (char *)hnv + n + 1;
value[n] = ':';
n = url_unescape_to(value, value, SIZE_MAX);
value[n] = '\0';
if (t) {
msg_header_t *h = msg_header_make(home, hc, value);
if (!h)
break;
v = (tag_value_t)h;
}
else {
char *s;
s = su_alloc(home, n + 1);
if (!s)
break;
memcpy(s, value, n + 1);
t = siptag_header_str;
v = (tag_value_t)s;
}
retval[i].t_tag = t, retval[i].t_value = v;
}
retval[i].t_tag = NULL, retval[i].t_value = (tag_value_t)0;
if (i < N) {
for (j = 0; j < i; j++) {
if (retval[i].t_tag == siptag_header_str)
su_free(home, (void *)retval[i].t_value);
else
msg_header_free_all(home, (msg_header_t *)retval[i].t_value);
}
su_free(home, retval);
retval = NULL;
}
error:
su_free(home, s);
su_strlst_destroy(l);
return retval;
}
......@@ -109,6 +109,11 @@ SOFIAPUBFUN char *sip_headers_as_url_query(su_home_t *home,
tag_type_t tag, tag_value_t value,
...);
/** Convert URL query to a tag list. */
SOFIAPUBFUN tagi_t *sip_url_query_as_taglist(su_home_t *home,
char const *query,
msg_mclass_t const *parser);
/** Complete SIP message. */
SOFIAPUBFUN int sip_complete_message(msg_t *msg);
......
......@@ -75,10 +75,23 @@ int test_url_headers(void)
{
BEGIN();
su_home_t *home;
char *s;
char *s, *d;
tagi_t *t;
url_t *url;
sip_from_t const *f;
sip_accept_t const *ac;
sip_payload_t const *body;
TEST_1(home = su_home_new(sizeof *home));
s = sip_headers_as_url_query
(home,
SIPTAG_SUBJECT_STR(";"),
TAG_END());
TEST_1(s);
TEST_S(s, "subject=;");
s = sip_headers_as_url_query
(home,
SIPTAG_TO_STR("\"Joe\" <sip:joe@example.com>;tag=foofaa"),
......@@ -86,16 +99,47 @@ int test_url_headers(void)
TAG_END());
TEST_1(s);
TEST_S(s, "to=%22Joe%22%20%3Csip%3Ajoe%40example.com%3E%3Btag%3Dfoofaa"
TEST_S(s, "to=%22Joe%22%20%3Csip%3Ajoe@example.com%3E;tag%3Dfoofaa"
"&subject=foo");
url = url_format(home, "sip:test@example.net?%s", s); TEST_1(url);
TEST_S(url->url_headers, s);
s = sip_headers_as_url_query
(home,
SIPTAG_FROM_STR("<sip:joe@example.com>"),
SIPTAG_ACCEPT_STR(""),
SIPTAG_PAYLOAD_STR("hello"),
SIPTAG_ACCEPT_STR(""),
TAG_END());
TEST_S(s, "from=%3Csip%3Ajoe%40example.com%3E&body=hello");
TEST_S(s, "from=%3Csip%3Ajoe@example.com%3E"
"&accept="
"&body=hello"
"&accept=");
d = url_query_as_header_string(home, s);
TEST_S(d, "from:<sip:joe@example.com>\n"
"accept:\n"
"accept:\n"
"\n"
"hello");
t = sip_url_query_as_taglist(home, s, NULL); TEST_1(t);
TEST(t[0].t_tag, siptag_from); TEST_1(f = (void *)t[0].t_value);
TEST(t[1].t_tag, siptag_accept); TEST_1(ac = (void *)t[1].t_value);
TEST(t[2].t_tag, siptag_payload); TEST_1(body = (void *)t[2].t_value);
TEST(t[3].t_tag, siptag_accept);
s = "xyzzy=foo";
t = sip_url_query_as_taglist(home, s, NULL); TEST_1(t);
TEST(t[0].t_tag, siptag_header_str);
TEST_1(d = (void *)t[0].t_value);
TEST_S(d, "foo");
TEST_1(!sip_headers_as_url_query(home, SIPTAG_SEPARATOR_STR(""), TAG_END()));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment