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 |