| File: | libs/sofia-sip/libsofia-sip-ua/sip/sip_tag_class.c |
| Location: | line 323, column 26 |
| Description: | Access to field 'tt_magic' results in a dereference of a null pointer (loaded from field 't_tag') |
| 1 | /* | |||
| 2 | * This file is part of the Sofia-SIP package | |||
| 3 | * | |||
| 4 | * Copyright (C) 2005 Nokia Corporation. | |||
| 5 | * | |||
| 6 | * Contact: Pekka Pessi <pekka.pessi@nokia.com> | |||
| 7 | * | |||
| 8 | * This library is free software; you can redistribute it and/or | |||
| 9 | * modify it under the terms of the GNU Lesser General Public License | |||
| 10 | * as published by the Free Software Foundation; either version 2.1 of | |||
| 11 | * the License, or (at your option) any later version. | |||
| 12 | * | |||
| 13 | * This library is distributed in the hope that it will be useful, but | |||
| 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| 16 | * Lesser General Public License for more details. | |||
| 17 | * | |||
| 18 | * You should have received a copy of the GNU Lesser General Public | |||
| 19 | * License along with this library; if not, write to the Free Software | |||
| 20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | |||
| 21 | * 02110-1301 USA | |||
| 22 | * | |||
| 23 | */ | |||
| 24 | ||||
| 25 | /**@SIP_TAG | |||
| 26 | * | |||
| 27 | * @CFILE sip_tag_class.c SIP Tag classes | |||
| 28 | * | |||
| 29 | * @author Pekka Pessi <Pekka.Pessi@nokia.com>. | |||
| 30 | * | |||
| 31 | * @date Created: Fri Feb 23 12:46:42 2001 ppessi | |||
| 32 | */ | |||
| 33 | ||||
| 34 | #include "config.h" | |||
| 35 | ||||
| 36 | #include "sofia-sip/sip_parser.h" | |||
| 37 | ||||
| 38 | #include <sofia-sip/su_tag_class.h> | |||
| 39 | #include <sofia-sip/su_tag_inline.h> | |||
| 40 | #include <sofia-sip/sip_tag_class.h> | |||
| 41 | #include <sofia-sip/sip_tag.h> | |||
| 42 | #include <sofia-sip/su_tagarg.h> | |||
| 43 | #include <sofia-sip/su_strlst.h> | |||
| 44 | ||||
| 45 | #include <stdio.h> | |||
| 46 | #include <ctype.h> | |||
| 47 | #include <assert.h> | |||
| 48 | #include <stddef.h> | |||
| 49 | #include <string.h> | |||
| 50 | #include <limits.h> | |||
| 51 | ||||
| 52 | /** Tag class for tags containing SIP headers. @HIDE | |||
| 53 | * | |||
| 54 | * Tags in this class are not automatically added to the message with | |||
| 55 | * sip_add_tl() or sip_add_tagis(). | |||
| 56 | */ | |||
| 57 | tag_class_t sipexthdrtag_class[1] = | |||
| 58 | {{ | |||
| 59 | sizeof(siphdrtag_class), | |||
| 60 | /* tc_next */ NULL((void*)0), | |||
| 61 | /* tc_len */ NULL((void*)0), | |||
| 62 | /* tc_move */ NULL((void*)0), | |||
| 63 | /* tc_xtra */ msghdrtag_xtra, | |||
| 64 | /* tc_dup */ msghdrtag_dup, | |||
| 65 | /* tc_free */ NULL((void*)0), | |||
| 66 | /* tc_find */ NULL((void*)0), | |||
| 67 | /* tc_snprintf */ msghdrtag_snprintf, | |||
| 68 | /* tc_filter */ siptag_filter, | |||
| 69 | /* tc_ref_set */ t_ptr_ref_set, | |||
| 70 | /* tc_scan */ msghdrtag_scan, | |||
| 71 | }}; | |||
| 72 | ||||
| 73 | ||||
| 74 | /** Tag class for SIP header tags. @HIDE */ | |||
| 75 | tag_class_t siphdrtag_class[1] = | |||
| 76 | {{ | |||
| 77 | sizeof(siphdrtag_class), | |||
| 78 | /* tc_next */ NULL((void*)0), | |||
| 79 | /* tc_len */ NULL((void*)0), | |||
| 80 | /* tc_move */ NULL((void*)0), | |||
| 81 | /* tc_xtra */ msghdrtag_xtra, | |||
| 82 | /* tc_dup */ msghdrtag_dup, | |||
| 83 | /* tc_free */ NULL((void*)0), | |||
| 84 | /* tc_find */ NULL((void*)0), | |||
| 85 | /* tc_snprintf */ msghdrtag_snprintf, | |||
| 86 | /* tc_filter */ siptag_filter, | |||
| 87 | /* tc_ref_set */ t_ptr_ref_set, | |||
| 88 | /* tc_scan */ msghdrtag_scan, | |||
| 89 | }}; | |||
| 90 | ||||
| 91 | /** Tag class for SIP header string tags. @HIDE */ | |||
| 92 | tag_class_t sipstrtag_class[1] = | |||
| 93 | {{ | |||
| 94 | sizeof(sipstrtag_class), | |||
| 95 | /* tc_next */ NULL((void*)0), | |||
| 96 | /* tc_len */ NULL((void*)0), | |||
| 97 | /* tc_move */ NULL((void*)0), | |||
| 98 | /* tc_xtra */ t_str_xtra, | |||
| 99 | /* tc_dup */ t_str_dup, | |||
| 100 | /* tc_free */ NULL((void*)0), | |||
| 101 | /* tc_find */ NULL((void*)0), | |||
| 102 | /* tc_snprintf */ t_str_snprintf, | |||
| 103 | /* tc_filter */ NULL((void*)0) /* msgtag_str_filter */, | |||
| 104 | /* tc_ref_set */ t_ptr_ref_set, | |||
| 105 | /* tc_scan */ t_str_scan | |||
| 106 | }}; | |||
| 107 | ||||
| 108 | /** Tag class for SIP message tags. @HIDE */ | |||
| 109 | tag_class_t sipmsgtag_class[1] = | |||
| 110 | {{ | |||
| 111 | sizeof(sipmsgtag_class), | |||
| 112 | /* tc_next */ NULL((void*)0), | |||
| 113 | /* tc_len */ NULL((void*)0), | |||
| 114 | /* tc_move */ NULL((void*)0), | |||
| 115 | /* tc_xtra */ msgobjtag_xtra, | |||
| 116 | /* tc_dup */ msgobjtag_dup, | |||
| 117 | /* tc_free */ NULL((void*)0), | |||
| 118 | /* tc_find */ NULL((void*)0), | |||
| 119 | /* tc_snprintf */ msgobjtag_snprintf, | |||
| 120 | /* tc_filter */ NULL((void*)0) /* siptag_sip_filter */, | |||
| 121 | /* tc_ref_set */ t_ptr_ref_set, | |||
| 122 | }}; | |||
| 123 | ||||
| 124 | ||||
| 125 | /** Filter a for SIP header tag. | |||
| 126 | * | |||
| 127 | * @param[in] dst tag list for filtering result. May be NULL. | |||
| 128 | * @param[in] f filter tag | |||
| 129 | * @param[in] src tag item from source list. | |||
| 130 | * @param[in,out] bb pointer to pointer of mempory area used to dup | |||
| 131 | * the filtering result | |||
| 132 | * | |||
| 133 | * This function is also used to calculate size for filtering result. | |||
| 134 | */ | |||
| 135 | tagi_t *siptag_filter(tagi_t *dst, | |||
| 136 | tagi_t const f[], | |||
| 137 | tagi_t const *src, | |||
| 138 | void **bb) | |||
| 139 | { | |||
| 140 | tagi_t stub[2] = {{ NULL((void*)0) }}; | |||
| 141 | tag_type_t srctt, tt = f->t_tag; | |||
| 142 | msg_hclass_t *hc = (msg_hclass_t *)tt->tt_magic; | |||
| 143 | ||||
| 144 | assert(src)((src) ? (void) (0) : __assert_fail ("src", "sip_tag_class.c" , 144, __PRETTY_FUNCTION__)); | |||
| 145 | ||||
| 146 | srctt = src->t_tag; | |||
| 147 | ||||
| 148 | /* Match filtered header with a header from a SIP message */ | |||
| 149 | if (srctt && srctt->tt_class == sipmsgtag_class) { | |||
| 150 | sip_t const *sip = (sip_t const *)src->t_value; | |||
| 151 | sip_header_t const **hh, *h; | |||
| 152 | ||||
| 153 | if (sip == NULL((void*)0)) | |||
| 154 | return dst; | |||
| 155 | ||||
| 156 | hh = (sip_header_t const **) | |||
| 157 | msg_hclass_offset((msg_mclass_t *)sip->sip_common->h_class, | |||
| 158 | (msg_pub_t *)sip, hc); | |||
| 159 | ||||
| 160 | /* Is header present in the SIP message? */ | |||
| 161 | if (hh == NULL((void*)0) || | |||
| 162 | (char *)hh >= ((char *)sip + sip->sip_size) || | |||
| 163 | (char *)hh < (char *)&sip->sip_request) | |||
| 164 | return dst; | |||
| 165 | ||||
| 166 | h = *hh; | |||
| 167 | ||||
| 168 | if (h == NULL((void*)0)) | |||
| 169 | return dst; | |||
| 170 | ||||
| 171 | stub[0].t_tag = tt; | |||
| 172 | stub[0].t_value = (tag_value_t)h; | |||
| 173 | src = stub; srctt = tt; | |||
| 174 | } | |||
| 175 | ||||
| 176 | if (tt != srctt) | |||
| 177 | return dst; | |||
| 178 | ||||
| 179 | if (!src->t_value) | |||
| 180 | return dst; | |||
| 181 | else if (dst) { | |||
| 182 | return t_dup(dst, src, bb); | |||
| 183 | } | |||
| 184 | else { | |||
| 185 | *bb = (char *)*bb + t_xtra(src, (size_t)*bb); | |||
| 186 | return dst + 1; | |||
| 187 | } | |||
| 188 | } | |||
| 189 | ||||
| 190 | /** Duplicate headers from taglist and add them to the SIP message. */ | |||
| 191 | int sip_add_tl(msg_t *msg, sip_t *sip, | |||
| 192 | tag_type_t tag, tag_value_t value, ...) | |||
| 193 | { | |||
| 194 | tagi_t const *t; | |||
| 195 | ta_list ta; | |||
| 196 | int retval; | |||
| 197 | ||||
| 198 | ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value = (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag ) == tag_next && (ta_start__value) != 0) { ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag == tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag == tag_next) { ta_start__value = ((tagi_t *)ta_start__value) ->t_value; } else { ta_start__tag = tag_next; break; } } ( ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value ; if (ta_start__tag != ((void*)0) && ta_start__tag != tag_null && ta_start__tag != tag_next) { va_list ta_start__ap ; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag = tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap ); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0); | |||
| 199 | ||||
| 200 | t = ta_args(ta)(ta).tl; | |||
| 201 | ||||
| 202 | retval = sip_add_tagis(msg, sip, &t); | |||
| 203 | ||||
| 204 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||
| 205 | return retval; | |||
| 206 | } | |||
| 207 | ||||
| 208 | /** Add duplicates of headers from taglist to the SIP message. */ | |||
| 209 | int sip_add_tagis(msg_t *msg, sip_t *sip, tagi_t const **inout_list) | |||
| 210 | { | |||
| 211 | tagi_t const *t; | |||
| 212 | tag_type_t tag; | |||
| 213 | tag_value_t value; | |||
| 214 | ||||
| 215 | if (!msg || !inout_list) | |||
| 216 | return -1; | |||
| 217 | ||||
| 218 | if (sip == NULL((void*)0)) | |||
| 219 | sip = sip_object(msg); | |||
| 220 | ||||
| 221 | for (t = *inout_list; t; t = t_next(t)) { | |||
| 222 | tag = t->t_tag, value = t->t_value; | |||
| 223 | ||||
| 224 | if (tag == NULL((void*)0) || tag == siptag_end) { | |||
| 225 | t = t_next(t); | |||
| 226 | break; | |||
| 227 | } | |||
| 228 | ||||
| 229 | if (!value) | |||
| 230 | continue; | |||
| 231 | ||||
| 232 | if (SIPTAG_P(tag)((tag)->tt_class == siphdrtag_class)) { | |||
| 233 | msg_hclass_t *hc = (msg_hclass_t *)tag->tt_magic; | |||
| 234 | msg_header_t *h = (msg_header_t *)value, **hh; | |||
| 235 | ||||
| 236 | if (h == SIP_NONE((void const *)-1L)) { /* Remove header */ | |||
| 237 | hh = msg_hclass_offset(msg_mclass(msg), (msg_pub_t *)sip, hc); | |||
| 238 | if (hh != NULL((void*)0) && | |||
| 239 | (char *)hh < ((char *)sip + sip->sip_size) && | |||
| 240 | (char *)hh >= (char *)&sip->sip_request) { | |||
| 241 | while (*hh) | |||
| 242 | msg_header_remove(msg, (msg_pub_t *)sip, *hh); | |||
| 243 | } | |||
| 244 | continue; | |||
| 245 | } | |||
| 246 | ||||
| 247 | if (tag == siptag_header) | |||
| 248 | hc = h->sh_classsh_common->h_class; | |||
| 249 | ||||
| 250 | if (msg_header_add_dup_as(msg, (msg_pub_t *)sip, hc, h) < 0) | |||
| 251 | break; | |||
| 252 | } | |||
| 253 | else if (SIPTAG_STR_P(tag)((tag)->tt_class == sipstrtag_class)) { | |||
| 254 | msg_hclass_t *hc = (msg_hclass_t *)tag->tt_magic; | |||
| 255 | char const *s = (char const *)value; | |||
| 256 | if (s && msg_header_add_make(msg, (msg_pub_t *)sip, hc, s) < 0) | |||
| 257 | return -1; | |||
| 258 | } | |||
| 259 | else if (tag == siptag_header_str) { | |||
| 260 | if (msg_header_add_str(msg, (msg_pub_t *)sip, (char const *)value) < 0) | |||
| 261 | return -1; | |||
| 262 | } | |||
| 263 | } | |||
| 264 | ||||
| 265 | *inout_list = t; | |||
| 266 | ||||
| 267 | return 0; | |||
| 268 | } | |||
| 269 | ||||
| 270 | static char const *append_escaped(su_strlst_t *l, | |||
| 271 | msg_hclass_t *hc, | |||
| 272 | char const *s); | |||
| 273 | ||||
| 274 | /** Convert tagged SIP headers to a URL-encoded headers list. | |||
| 275 | * | |||
| 276 | * The SIP URI can contain a query part separated with the "?", which | |||
| 277 | * specifies SIP headers that are included in the request constructed | |||
| 278 | * from the URI. For example, using URI @code <sip:example.com?subject=test> | |||
| 279 | * would include @Subject header with value "test" in the request. | |||
| 280 | * | |||
| 281 | * @param home memory home used to allocate query string (if NULL, use malloc) | |||
| 282 | * @param tag, value, ... list of tagged arguments | |||
| 283 | * | |||
| 284 | * @bug This function returns NULL if SIPTAG_REQUEST(), SIPTAG_STATUS(), | |||
| 285 | * SIPTAG_HEADER(), SIPTAG_UNKNOWN(), SIPTAG_ERROR(), SIPTAG_SEPARATOR(), or | |||
| 286 | * any corresponding string tag is included in the tag list. It ignores | |||
| 287 | * SIPTAG_SIP(). | |||
| 288 | * | |||
| 289 | * @par Example | |||
| 290 | * @code | |||
| 291 | * url->url_headers = | |||
| 292 | * sip_headers_as_url_query(home, SIPTAG_REPLACES(replaces), TAG_END()); | |||
| 293 | * @endcode | |||
| 294 | * | |||
| 295 | * @since New in @VERSION_1_12_4. | |||
| 296 | * | |||
| 297 | * @sa | |||
| 298 | * url_query_as_header_string(), sip_url_query_as_taglist(), | |||
| 299 | * nta_msg_request_complete(), | |||
| 300 | * @RFC3261 section 19.1.1 "Headers", #url_t, url_s#url_headers | |||
| 301 | */ | |||
| 302 | char *sip_headers_as_url_query(su_home_t *home, | |||
| 303 | tag_type_t tag, tag_value_t value, | |||
| 304 | ...) | |||
| 305 | { | |||
| 306 | ta_list ta; | |||
| 307 | tagi_t const *t; | |||
| 308 | su_strlst_t *l = su_strlst_create(home); | |||
| 309 | su_home_t *lhome = su_strlst_home(l); | |||
| 310 | char const *retval = ""; | |||
| 311 | ||||
| 312 | if (!l) | |||
| ||||
| 313 | return NULL((void*)0); | |||
| 314 | ||||
| 315 | ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value = (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag ) == tag_next && (ta_start__value) != 0) { ta_start__tag = ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag == tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag == tag_next) { ta_start__value = ((tagi_t *)ta_start__value) ->t_value; } else { ta_start__tag = tag_next; break; } } ( ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value ; if (ta_start__tag != ((void*)0) && ta_start__tag != tag_null && ta_start__tag != tag_next) { va_list ta_start__ap ; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag = tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap ); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value = 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0); | |||
| 316 | ||||
| 317 | for (t = ta_args(ta)(ta).tl; t && retval; t = t_next(t)) { | |||
| 318 | msg_hclass_t *hc; | |||
| 319 | ||||
| 320 | if (t->t_value == 0 || t->t_value == -1) | |||
| 321 | continue; | |||
| 322 | ||||
| 323 | hc = (msg_hclass_t *)t->t_tag->tt_magic; | |||
| ||||
| 324 | ||||
| 325 | if (SIPTAG_P(t->t_tag)((t->t_tag)->tt_class == siphdrtag_class)) { | |||
| 326 | sip_header_t const *h = (sip_header_t const *)t->t_value; | |||
| 327 | char *s = sip_header_as_string(lhome, h); | |||
| 328 | ||||
| 329 | retval = append_escaped(l, hc, s); | |||
| 330 | ||||
| 331 | if (retval != s) | |||
| 332 | su_free(lhome, s); | |||
| 333 | } | |||
| 334 | else if (SIPTAG_STR_P(t->t_tag)((t->t_tag)->tt_class == sipstrtag_class)) { | |||
| 335 | retval = append_escaped(l, hc, (char const *)t->t_value); | |||
| 336 | } | |||
| 337 | } | |||
| 338 | ||||
| 339 | ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value ))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta) .ap)); | |||
| 340 | ||||
| 341 | if (retval) | |||
| 342 | retval = su_strlst_join(l, home, ""); | |||
| 343 | ||||
| 344 | su_strlst_destroy(l); | |||
| 345 | ||||
| 346 | return (char *)retval; | |||
| 347 | } | |||
| 348 | ||||
| 349 | /* "[" / "]" / "/" / "?" / ":" / "+" / "$" */ | |||
| 350 | #define HNV_UNRESERVED"[]/?+$" "[]/?+$" | |||
| 351 | #define HNV_RESERVED":=,;" ":=,;" | |||
| 352 | ||||
| 353 | /* Append a string to list and url-escape it if needed */ | |||
| 354 | static | |||
| 355 | char const *append_escaped(su_strlst_t *l, | |||
| 356 | msg_hclass_t *hc, | |||
| 357 | char const *s) | |||
| 358 | { | |||
| 359 | char const *name; | |||
| 360 | ||||
| 361 | if (hc == NULL((void*)0)) | |||
| 362 | return NULL((void*)0); | |||
| 363 | ||||
| 364 | if (hc->hc_hash == sip_payload_hash) | |||
| 365 | name = "body"; | |||
| 366 | else /* XXX - could we use short form? */ | |||
| 367 | name = hc->hc_name; | |||
| 368 | ||||
| 369 | if (name == NULL((void*)0)) | |||
| 370 | return NULL((void*)0); | |||
| 371 | ||||
| 372 | if (s) { | |||
| 373 | su_home_t *lhome = su_strlst_home(l); | |||
| 374 | size_t slen; | |||
| 375 | isize_t elen; | |||
| 376 | char *n, *escaped; | |||
| 377 | char *sep = su_strlst_len(l) > 0 ? "&" : ""; | |||
| 378 | ||||
| 379 | n = su_sprintf(lhome, "%s%s=", sep, name); | |||
| 380 | if (!su_strlst_append(l, n)) | |||
| 381 | return NULL((void*)0); | |||
| 382 | ||||
| 383 | for (;*n; n++) | |||
| 384 | if (isupper(*(const unsigned char *)n)((*__ctype_b_loc ())[(int) ((*(const unsigned char *)n))] & (unsigned short int) _ISupper)) | |||
| 385 | *n = tolower(*(const unsigned char *)n)(__extension__ ({ int __res; if (sizeof (*(const unsigned char *)n) > 1) { if (__builtin_constant_p (*(const unsigned char *)n)) { int __c = (*(const unsigned char *)n); __res = __c < -128 || __c > 255 ? __c : (*__ctype_tolower_loc ())[__c]; } else __res = tolower (*(const unsigned char *)n); } else __res = (*__ctype_tolower_loc ())[(int) (*(const unsigned char *)n )]; __res; })); | |||
| 386 | ||||
| 387 | slen = strlen(s); elen = url_esclen(s, HNV_RESERVED":=,;"); | |||
| 388 | ||||
| 389 | if ((size_t)elen == slen) | |||
| 390 | return su_strlst_append(l, s); | |||
| 391 | ||||
| 392 | escaped = su_alloc(lhome, elen + 1); | |||
| 393 | if (escaped) | |||
| 394 | return su_strlst_append(l, url_escape(escaped, s, HNV_RESERVED":=,;")); | |||
| 395 | } | |||
| 396 | ||||
| 397 | return NULL((void*)0); | |||
| 398 | } | |||
| 399 | ||||
| 400 | /** Convert URL query to a tag list. | |||
| 401 | * | |||
| 402 | * SIP headers encoded as URL @a query is parsed returned as a tag list. | |||
| 403 | * Unknown headers are encoded as SIPTAG_HEADER_STR(). | |||
| 404 | * | |||
| 405 | * @param home memory home used to alloate string (if NULL, malloc() it) | |||
| 406 | * @param query query part from SIP URL | |||
| 407 | * @param parser optional SIP parser used | |||
| 408 | * | |||
| 409 | * @sa sip_add_tl(), sip_add_tagis(), SIPTAG_HEADER_STR(), | |||
| 410 | * sip_headers_as_url_query(), url_query_as_header_string(), | |||
| 411 | * @RFC3261 section 19.1.1 "Headers", #url_t, url_s#url_headers | |||
| 412 | * | |||
| 413 | * @NEW_1_12_4. | |||
| 414 | * | |||
| 415 | * @bug Extension headers are ignored. The @a parser parameter is not used | |||
| 416 | * at the moment. | |||
| 417 | */ | |||
| 418 | tagi_t *sip_url_query_as_taglist(su_home_t *home, char const *query, | |||
| 419 | msg_mclass_t const *parser) | |||
| 420 | { | |||
| 421 | tagi_t *retval = NULL((void*)0); | |||
| 422 | char *s; | |||
| 423 | su_strlst_t *l; | |||
| 424 | isize_t N; | |||
| 425 | size_t i, j, n; | |||
| 426 | ||||
| 427 | if (query == NULL((void*)0) || query[0] == '\0' || query[0] == '&') | |||
| 428 | return NULL((void*)0); | |||
| 429 | ||||
| 430 | s = su_strdup(home, query); if (!s) return NULL((void*)0); | |||
| 431 | l = su_strlst_split(home, s, "&"); | |||
| 432 | N = su_strlst_len(l); | |||
| 433 | ||||
| 434 | if (N == 0) | |||
| 435 | goto error; | |||
| 436 | ||||
| 437 | retval = su_zalloc(home, (N + 1) * sizeof (*retval)); | |||
| 438 | if (retval == NULL((void*)0)) | |||
| 439 | goto error; | |||
| 440 | ||||
| 441 | for (i = 0; i < N; i++) { | |||
| 442 | char const *hnv; | |||
| 443 | char *value; | |||
| 444 | tag_type_t t; | |||
| 445 | tag_value_t v; | |||
| 446 | msg_hclass_t *hc = NULL((void*)0); | |||
| 447 | ||||
| 448 | hnv = su_strlst_item(l, i); | |||
| 449 | n = hnv ? strcspn(hnv, "=")__extension__ ({ char __r0, __r1, __r2; (__builtin_constant_p ("=") && ((size_t)(const void *)(("=") + 1) - (size_t )(const void *)("=") == 1) ? ((__builtin_constant_p (hnv) && ((size_t)(const void *)((hnv) + 1) - (size_t)(const void *)( hnv) == 1)) ? __builtin_strcspn (hnv, "=") : ((__r0 = ((const char *) ("="))[0], __r0 == '\0') ? strlen (hnv) : ((__r1 = ( (const char *) ("="))[1], __r1 == '\0') ? __strcspn_c1 (hnv, __r0 ) : ((__r2 = ((const char *) ("="))[2], __r2 == '\0') ? __strcspn_c2 (hnv, __r0, __r1) : (((const char *) ("="))[3] == '\0' ? __strcspn_c3 (hnv, __r0, __r1, __r2) : __builtin_strcspn (hnv, "=")))))) : __builtin_strcspn (hnv, "=")); }) : 0; | |||
| 450 | if (n == 0) | |||
| 451 | break; | |||
| 452 | ||||
| 453 | if (n == 4 && su_casenmatch(hnv, "body", 4)) | |||
| 454 | t = siptag_payload, hc = sip_payload_class; | |||
| 455 | else { | |||
| 456 | for (j = 0; (t = sip_tag_list[j]); j++) { | |||
| 457 | hc = (msg_hclass_t *)sip_tag_list[j]->tt_magic; | |||
| 458 | if (n == 1 && su_casenmatch(hnv, hc->hc_short, 1)) | |||
| 459 | break; | |||
| 460 | else if (n == (size_t)hc->hc_len && | |||
| 461 | su_casenmatch(hnv, hc->hc_name, n)) | |||
| 462 | break; | |||
| 463 | } | |||
| 464 | } | |||
| 465 | ||||
| 466 | value = (char *)hnv + n; | |||
| 467 | *value++ = ':'; | |||
| 468 | n = url_unescape_to(value, value, SIZE_MAX(18446744073709551615UL)); | |||
| 469 | value[n] = '\0'; | |||
| 470 | ||||
| 471 | if (t) { | |||
| 472 | msg_header_t *h = msg_header_make(home, hc, value); | |||
| 473 | if (!h) | |||
| 474 | break; | |||
| 475 | v = (tag_value_t)h; | |||
| 476 | } | |||
| 477 | else { | |||
| 478 | char *s; | |||
| 479 | s = su_alloc(home, n + 1); | |||
| 480 | if (!s) | |||
| 481 | break; | |||
| 482 | memcpy(s, value, n + 1); | |||
| 483 | t = siptag_header_str; | |||
| 484 | v = (tag_value_t)s; | |||
| 485 | } | |||
| 486 | retval[i].t_tag = t, retval[i].t_value = v; | |||
| 487 | } | |||
| 488 | ||||
| 489 | retval[i].t_tag = NULL((void*)0), retval[i].t_value = (tag_value_t)0; | |||
| 490 | ||||
| 491 | if (i < N) { | |||
| 492 | for (j = 0; j < i; j++) { | |||
| 493 | if (retval[i].t_tag == siptag_header_str) | |||
| 494 | su_free(home, (void *)retval[i].t_value); | |||
| 495 | else | |||
| 496 | msg_header_free_all(home, (msg_header_t *)retval[i].t_value); | |||
| 497 | } | |||
| 498 | su_free(home, retval); | |||
| 499 | retval = NULL((void*)0); | |||
| 500 | } | |||
| 501 | ||||
| 502 | error: | |||
| 503 | su_free(home, s); | |||
| 504 | su_strlst_destroy(l); | |||
| 505 | ||||
| 506 | return retval; | |||
| 507 | } | |||
| 508 |