Bug Summary

File:libsofia-sip-ua/msg/msg_mime.c
Warning:line 405, column 27
Although the value stored to 'len' is used in the enclosing expression, the value is never actually read from 'len'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name msg_mime.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/llvm-11/lib/clang/11.0.1 -D HAVE_CONFIG_H -I . -I ../.. -I ../../libsofia-sip-ua/su/sofia-sip -I ./../url -I ../url -I ./../bnf -I ../bnf -I ./../su -I ../su -D SU_DEBUG=0 -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-11/lib/clang/11.0.1/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir /drone/src/libsofia-sip-ua/msg -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-output=html -faddrsig -o /drone/src/scan-build/2022-06-23-181620-12-1 -x c msg_mime.c
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/**@ingroup msg_mime
26 * @CFILE msg_mime.c
27 *
28 * MIME-related headers and MIME multipart bodies for SIP/HTTP/RTSP.
29 *
30 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
31 *
32 * @date Created: Tue Jun 13 02:57:51 2000 ppessi
33 *
34 *
35 */
36
37#include "config.h"
38
39#define _GNU_SOURCE1 1
40
41#include <sofia-sip/su_alloc.h>
42#include <sofia-sip/su_string.h>
43
44#include "msg_internal.h"
45#include "sofia-sip/msg.h"
46#include "sofia-sip/msg_mime.h"
47
48#include <sofia-sip/su_uniqueid.h>
49#include <sofia-sip/su_errno.h>
50
51#include <stddef.h>
52#include <stdlib.h>
53#include <string.h>
54#include <limits.h>
55#include <errno(*__errno_location ()).h>
56#include <assert.h>
57
58#if !HAVE_MEMMEM1
59void *memmem(const void *haystack, size_t haystacklen,
60 const void *needle, size_t needlelen);
61#endif
62
63/** Protocol version of MIME */
64char const msg_mime_version_1_0[] = "MIME/1.0";
65
66#include <sofia-sip/msg_parser.h>
67#include <sofia-sip/msg_mime_protos.h>
68
69/** Define a header class for headers without any extra data to copy */
70#define MSG_HEADER_CLASS_G(c, l, s, kind){{ msg_c_hash, msg_c_d, msg_c_e, msg_generic_dup_xtra, msg_generic_dup_one
, ((void*)0), l, sizeof(l) - 1, s, (((uintptr_t)(sizeof(msg_c_t
)) + (sizeof(void*)) - 1) & (0 - (uintptr_t)(sizeof(void*
)))), __builtin_offsetof(msg_c_t, g_common), msg_kind_kind, }
}
\
71 MSG_HEADER_CLASS(msg_, c, l, s, g_common, kind, msg_generic, msg_generic){{ msg_c_hash, msg_c_d, msg_c_e, msg_generic_dup_xtra, msg_generic_dup_one
, ((void*)0), l, sizeof(l) - 1, s, (((uintptr_t)(sizeof(msg_c_t
)) + (sizeof(void*)) - 1) & (0 - (uintptr_t)(sizeof(void*
)))), __builtin_offsetof(msg_c_t, g_common), msg_kind_kind, }
}
72
73#define msg_generic_update((void*)0) NULL((void*)0)
74
75/** Define a header class for a msg_list_t kind of header */
76#define MSG_HEADER_CLASS_LIST(c, l, s, kind){{ msg_c_hash, msg_c_d, msg_c_e, msg_list_dup_xtra, msg_list_dup_one
, ((void*)0), l, sizeof(l) - 1, s, (((uintptr_t)(sizeof(msg_c_t
)) + (sizeof(void*)) - 1) & (0 - (uintptr_t)(sizeof(void*
)))), __builtin_offsetof(msg_c_t, k_items), msg_kind_kind, }}
\
77 MSG_HEADER_CLASS(msg_, c, l, s, k_items, kind, msg_list, msg_list){{ msg_c_hash, msg_c_d, msg_c_e, msg_list_dup_xtra, msg_list_dup_one
, ((void*)0), l, sizeof(l) - 1, s, (((uintptr_t)(sizeof(msg_c_t
)) + (sizeof(void*)) - 1) & (0 - (uintptr_t)(sizeof(void*
)))), __builtin_offsetof(msg_c_t, k_items), msg_kind_kind, }}
78
79#define msg_list_update((void*)0) NULL((void*)0)
80
81/* ====================================================================== */
82
83/** Calculate length of line ending (0, 1 or 2). @internal */
84#define CRLF_TEST(b)((b)[0] == '\r' ? ((b)[1] == '\n') + 1 : (b)[0] =='\n') ((b)[0] == '\r' ? ((b)[1] == '\n') + 1 : (b)[0] =='\n')
85
86/**@ingroup msg_mime
87 * @defgroup msg_multipart MIME Multipart Body
88 *
89 * Representing MIME multipart bodies and their manipulation.
90 *
91 * The #msg_multipart_t is an object for storing MIME multipart message
92 * bodies. It includes message components used for framing and identifying
93 * message parts. Its syntax is defined in @RFC2046 as follows:
94 *
95 * @code
96 *
97 * multipart-body := [preamble CRLF]
98 * dash-boundary transport-padding CRLF
99 * body-part *encapsulation
100 * close-delimiter transport-padding
101 * [CRLF epilogue]
102 *
103 * preamble := discard-text
104 *
105 * discard-text := *(*text CRLF)
106 * ; May be ignored or discarded.
107 *
108 * dash-boundary := "--" boundary
109 * ; boundary taken from the value of boundary parameter
110 * ; of the Content-Type field.
111 *
112 * boundary := 0*69<bchars> bcharsnospace
113 *
114 * bchars := bcharsnospace / " "
115 *
116 * bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" /
117 * "+" / "_" / "," / "-" / "." /
118 * "/" / ":" / "=" / "?"
119 *
120 * transport-padding := *LWSP-char
121 * ; Composers MUST NOT generate non-zero length
122 * ; transport padding, but receivers MUST be able to
123 * ; handle padding added by message transports.
124 *
125 * body-part := <"message" as defined in @RFC822, with all header fields
126 * optional, not starting with the specified dash-boundary,
127 * and with the delimiter not occurring anywhere in the body
128 * part. Note that the semantics of a part differ from the
129 * semantics of a message, as described in the text.>
130 *
131 * encapsulation := delimiter transport-padding CRLF
132 * body-part
133 *
134 * close-delimiter := delimiter "--"
135 *
136 * delimiter := CRLF dash-boundary
137 *
138 * epilogue := discard-text
139 *
140 * @endcode
141 *
142 * @par Parsing a Multipart Message
143 *
144 * When a message body contains a multipart entity (in other words, it has a
145 * MIME media type of "multipart"), the application can split the multipart
146 * entity into body parts
147 *
148 * The parsing is relatively simple, the application just gives a memory
149 * home object, a Content-Type header object and message body object as an
150 * argument to msg_multipart_parse() function:
151 * @code
152 * if (sip->sip_content_type &&
153 * su_casenmatch(sip->sip_content_type, "multipart/", 10)) {
154 * msg_multipart_t *mp;
155 *
156 * if (sip->sip_multipart)
157 * mp = sip->sip_multipart;
158 * else
159 * mp = msg_multipart_parse(msg_home(msg),
160 * sip->sip_content_type,
161 * (sip_payload_t *)sip->sip_payload);
162 *
163 * if (mp)
164 * ... processing multipart ...
165 * else
166 * ... error handling ...
167 * }
168 * @endcode
169 *
170 * The resulting list of msg_multipart_t structures contain the parts of the
171 * multipart entity, each part represented by a separate #msg_multipart_t
172 * structure. Please note that in order to make error recovery possible, the
173 * parsing is not recursive - if multipart contains another multipart, the
174 * application is responsible for scanning for it and parsing it.
175 *
176 * @par Constructing a Multipart Message
177 *
178 * Constructing a multipart body is a bit more hairy. The application needs
179 * a message object (#msg_t), which is used to buffer the encoding of
180 * multipart components.
181 *
182 * As an example, let us create a "multipart/mixed" multipart entity with a
183 * HTML and GIF contents, and convert it into a #sip_payload_t structure:
184 * @code
185 * msg_t *msg = msg_create(sip_default_mclass, 0);
186 * su_home_t *home = msg_home(msg);
187 * sip_t *sip = sip_object(msg);
188 * sip_content_type_t *c;
189 * msg_multipart_t *mp = NULL;
190 * msg_header_t *h = NULL;
191 * char *b;
192 * size_t len, offset;
193 *
194 * mp = msg_multipart_create(home, "text/html;level=3", html, strlen(html));
195 * mp->mp_next = msg_multipart_create(home, "image/gif", gif, giflen);
196 *
197 * c = sip_content_type_make(home, "multipart/mixed");
198 *
199 * // Add delimiters to multipart, and boundary parameter to content-type
200 * if (msg_multipart_complete(home, c, mp) < 0)
201 * return -1; // Error
202 *
203 * // Combine multipart components into the chain
204 * h = NULL;
205 * if (msg_multipart_serialize(&h, mp) < 0)
206 * return -1; // Error
207 *
208 * // Encode all multipart components
209 * len = msg_multipart_prepare(msg, mp, 0);
210 * if (len < 0)
211 * return -1; // Error
212 *
213 * pl = sip_payload_create(home, NULL, len);
214 *
215 * // Copy each element from multipart to pl_data
216 * b = pl->pl_data;
217 * for (offset = 0, h = mp; offset < len; h = h->sh_succ) {
218 * memcpy(b + offset, h->sh_data, h->sh_len);
219 * offset += h->sh_len;
220 * }
221 * @endcode
222 *
223 */
224
225/**Create a part for MIME multipart entity.
226 *
227 * The function msg_multipart_create() allocates a new #msg_multipart_t
228 * object from memory home @a home. If @a content_type is non-NULL, it makes
229 * a #msg_content_type_t header object and adds the header to the
230 * #msg_multipart_t object. If @a dlen is nonzero, it allocates a
231 * msg_payload_t structure of @a dlen bytes for the payload of the newly
232 * created #msg_multipart_t object. If @a data is non-NULL, it copies the @a
233 * dlen bytes of of data to the payload of the newly created
234 * #msg_multipart_t object.
235 *
236 * @return A pointer to the newly created #msg_multipart_t object, or NULL
237 * upon an error.
238 */
239msg_multipart_t *msg_multipart_create(su_home_t *home,
240 char const *content_type,
241 void const *data,
242 isize_t dlen)
243{
244 msg_multipart_t *mp;
245
246 mp = (msg_multipart_t *)msg_header_alloc(home, msg_multipart_class((msg_hclass_t *)msg_multipart_mclass), 0);
247
248 if (mp) {
249 if (content_type)
250 mp->mp_content_type = msg_content_type_make(home, content_type);
251 if (dlen)
252 mp->mp_payload = msg_payload_create(home, data, dlen);
253
254 if ((!mp->mp_content_type && content_type) ||
255 (!mp->mp_payload && dlen)) {
256 su_free(home, mp->mp_content_type);
257 su_free(home, mp->mp_payload);
258 su_free(home, mp);
259 mp = NULL((void*)0);
260 }
261 }
262
263 return mp;
264}
265
266/** Convert boundary parameter to a search string. */
267static char *
268msg_multipart_boundary(su_home_t *home, char const *b)
269{
270 char *boundary;
271
272 if (!b || !(boundary = su_alloc(home, 2 + 2 + strlen(b) + 2 + 1)))
273 return NULL((void*)0);
274
275 strcpy(boundary, _CR"\r" LF"\n" "--");
276
277 if (b[0] == '"') /* " See http://bugzilla.gnome.org/show_bug.cgi?id=134216 */
278
279 msg_unquote(boundary + 4, b);
280 else
281 strcpy(boundary + 4, b);
282
283
284 strcat(boundary + 4, _CR"\r" LF"\n");
285
286 return boundary;
287}
288
289
290/** Boundary chars. */
291static char const bchars[] =
292"'()+_,-./:=?"
293"0123456789"
294"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
295"abcdefghijklmnopqrstuvwxyz"
296" ";
297
298#define bchars_len(sizeof(bchars) - 1) (sizeof(bchars) - 1)
299
300/** Search for a suitable boundary from MIME. */
301static char *
302msg_multipart_search_boundary(su_home_t *home, char const *p, size_t len)
303{
304 size_t m;
305 unsigned crlf;
306 char const *end = p + len;
307 char *boundary;
308
309 if (len < 2)
310 return NULL((void*)0);
311
312 /* Boundary looks like LF -- string SP* [CR] LF */
313 if (memcmp("--", p, 2) == 0) {
314 /* We can be at boundary beginning, there is no CR LF */
315 m = 2 + su_memspn(p + 2, len - 2, bchars, bchars_len(sizeof(bchars) - 1));
316 if (m + 2 >= len)
317 return NULL((void*)0);
318 crlf = p[m] == '\r' ? 1 + (p[m + 1] == '\n') : (p[m] == '\n');
319 while (p[m - 1] == ' ' || p[m - 1] == '\t')
320 m--;
321 if (m > 2 && crlf) {
322 boundary = su_alloc(home, 2 + m + 2 + 1);
323 if (boundary) {
324 memcpy(boundary, _CR"\r" LF"\n", 2);
325 memcpy(boundary + 2, p, m);
326 strcpy(boundary + m + 2, _CR"\r" LF"\n");
327 }
328 return boundary;
329 }
330 }
331
332 /* Look for LF -- */
333 for (;(p = memmem(p, end - p, LF"\n" "--", 3)); p += 3) {
334 len = end - p;
335 m = 3 + su_memspn(p + 3, len - 3, bchars, bchars_len(sizeof(bchars) - 1));
336 if (m + 2 >= len)
337 return NULL((void*)0);
338 crlf = p[m] == '\r' ? 1 + (p[m + 1] == '\n') : (p[m] == '\n');
339 while (p[m - 1] == ' ' || p[m - 1] == '\t')
340 m--;
341 m--;
342 if (m > 2 && crlf) {
343 boundary = su_alloc(home, 2 + m + 2 + 1);
344 if (boundary) {
345 memcpy(boundary, _CR"\r" LF"\n", 2);
346 memcpy(boundary + 2, p + 1, m);
347 strcpy(boundary + 2 + m, _CR"\r" LF"\n");
348 }
349 return boundary;
350 }
351 }
352
353 return NULL((void*)0);
354}
355
356/** Parse a MIME multipart.
357 *
358 * The function msg_multipart_parse() parses a MIME multipart message. The
359 * common syntax of multiparts is described in @RFC2046 (section 7).
360 *
361 * @param[in,out] home home for allocating structures
362 * @param[in] c content-type header for multipart
363 * @param[in] pl payload structure for multipart
364 *
365 * After parsing, the @a pl will contain the plain-text preamble (if any).
366 *
367 * @note If no @b Content-Type header is given, the msg_multipart_parse()
368 * tries to look for a suitable boundary. Currently, it takes first
369 * boundary-looking string and uses that, so it can be fooled with, for
370 * instance, signature @c "--Pekka".
371 */
372msg_multipart_t *msg_multipart_parse(su_home_t *home,
373 msg_content_type_t const *c,
374 msg_payload_t *pl)
375{
376 msg_multipart_t *mp = NULL((void*)0), *all = NULL((void*)0), **mmp = &all;
377 /* Dummy msg object */
378 msg_t msg[1] = {{{ SU_HOME_INIT(msg){ 0, ((void*)0), ((void*)0) } }}};
379 size_t len, m, blen;
380 char *boundary, *p, *next, save;
381 char *b, *end;
382 msg_param_t param;
383
384 if (!pl) return NULL((void*)0);
385
386 p = pl->pl_data; len = pl->pl_len; end = p + len;
387
388 su_home_init(msg_home(msg)((su_home_t*)(msg)));
389 msg->m_class = msg_multipart_mclass;
390 msg->m_tail = &msg->m_chain;
391
392 /* Get boundary from Content-Type */
393 if (c && (param = msg_header_find_param(c->c_common, "boundary=")))
394 boundary = msg_multipart_boundary(msg_home(msg)((su_home_t*)(msg)), param);
395 else
396 boundary = msg_multipart_search_boundary(msg_home(msg)((su_home_t*)(msg)), p, len);
397
398 if (!boundary)
399 return NULL((void*)0);
400
401 m = strlen(boundary) - 2, blen = m - 1;
402
403 /* Find first delimiter */
404 if (memcmp(boundary + 2, p, m - 2) == 0)
405 b = p, p = p + m - 2, len -= m - 2;
Although the value stored to 'len' is used in the enclosing expression, the value is never actually read from 'len'
406 else if ((p = memmem(p, len, boundary + 1, m - 1))) {
407 if (p != pl->pl_data && p[-1] == '\r')
408 b = --p, p = p + m, len -= m;
409 else
410 b = p, p = p + m - 1, len -= m - 1;
411 }
412 else {
413 su_home_deinit(msg_home(msg)((su_home_t*)(msg)));
414 return NULL((void*)0);
415 }
416
417 /* Split multipart into parts */
418 for (;;) {
419 while (p[0] == ' ')
420 p++;
421
422 p += p[0] == '\r' ? 1 + (p[1] == '\n') : (p[0] == '\n');
423
424 len = end - p;
425
426 if (len < blen)
427 break;
428
429 next = memmem(p, len, boundary + 1, m = blen);
430
431 if (!next)
432 break; /* error */
433
434 if (next != p && next[-1] == '\r')
435 next--, m++;
436
437 mp = (msg_multipart_t *)msg_header_alloc(msg_home(msg)((su_home_t*)(msg)), msg_multipart_class((msg_hclass_t *)msg_multipart_mclass), 0);
438 if (mp == NULL((void*)0))
439 break; /* error */
440 *mmp = mp; mmp = &mp->mp_next;
441
442 /* Put delimiter transport-padding CRLF here */
443
444 *b = '\0';
445 mp->mp_common->h_len = p - b;
446 b += strlen(boundary) - 2;
447 mp->mp_common->h_data = b;
448
449 /* .. and body-part here */
450 mp->mp_data = p;
451 mp->mp_len = next - p;
452
453 if (next[m] == '-' && next[m + 1] == '-') {
454 /* We found close-delimiter */
455 assert(mp)((void) sizeof ((mp) ? 1 : 0), __extension__ ({ if (mp) ; else
__assert_fail ("mp", "msg_mime.c", 455, __extension__ __PRETTY_FUNCTION__
); }))
;
456 if (!mp)
457 break; /* error */
458 mp->mp_close_delim = (msg_payload_t *)
459 msg_header_alloc(msg_home(msg)((su_home_t*)(msg)), msg_payload_class, 0);
460 if (!mp->mp_close_delim)
461 break; /* error */
462 /* Include also transport-padding and epilogue in the close-delimiter */
463 *next = '\0';
464 mp->mp_close_delim->pl_len = p + len - next;
465 next += strlen(boundary) - 2;
466 mp->mp_close_delim->pl_data = next;
467
468 break;
469 }
470
471 b = next; p = next + m;
472 }
473
474 if (!mp || !mp->mp_close_delim) {
475 su_home_deinit(msg_home(msg)((su_home_t*)(msg)));
476 /* Delimiter error */
477 return NULL((void*)0);
478 }
479
480 /* Parse each part */
481 for (mp = all; mp; mp = mp->mp_next) {
482 msg->m_object = (msg_pub_t *)mp; p = mp->mp_data; next = p + mp->mp_len;
483
484 if (msg->m_tail)
485 mp->mp_common->h_prev = msg->m_tail,
486 *msg->m_tail = (msg_header_t *)mp;
487
488 msg->m_chain = (msg_header_t *)mp;
489 msg->m_tail = &mp->mp_common->h_succ;
490
491 save = *next; *next = '\0'; /* NUL-terminate this part */
492
493 for (len = next - p; len > 0; len -= m, p += m) {
494 if (IS_CRLF(p[0])((p[0]) == '\r' || (p[0]) == '\n')) {
495 m = msg_extract_separator(msg, (msg_pub_t*)mp, p, len, 1);
496 assert(m > 0)((void) sizeof ((m > 0) ? 1 : 0), __extension__ ({ if (m >
0) ; else __assert_fail ("m > 0", "msg_mime.c", 496, __extension__
__PRETTY_FUNCTION__); }))
;
497
498 p += m; len -= m;
499
500 if (len > 0) {
501 m = msg_extract_payload(msg, (msg_pub_t*)mp, NULL((void*)0), len, p, len, 1);
502 assert(m > 0)((void) sizeof ((m > 0) ? 1 : 0), __extension__ ({ if (m >
0) ; else __assert_fail ("m > 0", "msg_mime.c", 502, __extension__
__PRETTY_FUNCTION__); }))
;
503 assert(len == m)((void) sizeof ((len == m) ? 1 : 0), __extension__ ({ if (len
== m) ; else __assert_fail ("len == m", "msg_mime.c", 503, __extension__
__PRETTY_FUNCTION__); }))
;
504 }
505 break;
506 }
507
508 m = msg_extract_header(msg, (msg_pub_t*)mp, p, len, 1);
509
510 if (m <= 0) {
511 assert(m > 0)((void) sizeof ((m > 0) ? 1 : 0), __extension__ ({ if (m >
0) ; else __assert_fail ("m > 0", "msg_mime.c", 511, __extension__
__PRETTY_FUNCTION__); }))
;
512 /* Xyzzy */
513 }
514 }
515
516 *next = save; /* XXX - Should we leave the payload NUL-terminated? */
517 }
518
519 /* Postprocess */
520 blen = strlen(boundary);
521
522 for (mp = all; mp; mp = mp->mp_next) {
523 mp->mp_data = boundary;
524 mp->mp_len = (unsigned)blen; /* XXX */
525
526 if (!(mp->mp_payload || mp->mp_separator)) continue;
527
528 if (mp->mp_close_delim) {
529 msg_header_t **tail;
530
531 if (mp->mp_payload)
532 tail = &mp->mp_payload->pl_common->h_succ;
533 else
534 tail = &mp->mp_separator->sep_common->h_succ;
535
536 assert(msg->m_chain == (msg_header_t *)mp)((void) sizeof ((msg->m_chain == (msg_header_t *)mp) ? 1 :
0), __extension__ ({ if (msg->m_chain == (msg_header_t *)
mp) ; else __assert_fail ("msg->m_chain == (msg_header_t *)mp"
, "msg_mime.c", 536, __extension__ __PRETTY_FUNCTION__); }))
;
537 assert(*tail == NULL)((void) sizeof ((*tail == ((void*)0)) ? 1 : 0), __extension__
({ if (*tail == ((void*)0)) ; else __assert_fail ("*tail == NULL"
, "msg_mime.c", 537, __extension__ __PRETTY_FUNCTION__); }))
;
538
539 mp->mp_close_delim->pl_common->h_prev = tail;
540 *tail = (msg_header_t *)mp->mp_close_delim;
541 }
542 }
543
544 msg_fragment_clear(pl->pl_common);
545 pl->pl_len = all->mp_data - (char *)pl->pl_data;
546
547 su_home_move(home, msg_home(msg)((su_home_t*)(msg))); su_home_deinit(msg_home(msg)((su_home_t*)(msg)));
548
549 return all;
550}
551
552/**Add all missing parts to the multipart.
553 *
554 * Add missing components such as boundaries between body parts, separators
555 * between body-part headers and data, and close-delimiter after last
556 * body-part to the multipart message.
557 *
558 * @param[in,out] home home for allocating structures
559 * @param[in,out] c content-type header for multipart
560 * @param[in,out] mp pointer to first multipart structure
561 *
562 * @retval 0 when successful
563 * @retval -1 upon an error
564 *
565 * @ERRORS
566 * @ERROR EBADMSG
567 * The @b Content-Type header @a c is malformed, or multipart message
568 * contains a malformed @b Content-Type header.
569 * @ERROR ENOMEM
570 * A memory allocation failed.
571 * @ERROR EINVAL
572 * The function msg_multipart_complete() was given invalid arguments.
573 */
574int msg_multipart_complete(su_home_t *home,
575 msg_content_type_t *c,
576 msg_multipart_t *mp)
577{
578 char *boundary;
579 char const *b;
580 size_t blen, m;
581
582 if (c == NULL((void*)0) || mp == NULL((void*)0))
583 return (errno(*__errno_location ()) = EINVAL22), -1;
584
585 if (!(b = msg_header_find_param(c->c_common, "boundary="))) {
586 /* Generate boundary */
587 enum { tlen = 16 * 4 / 3 };
588 char token[sizeof("boundary=") + tlen + 1];
589
590 if (mp->mp_data) {
591 b = mp->mp_data;
592 m = mp->mp_len;
593
594 if (strncmp(b, _CR"\r" LF"\n" "--", 4) == 0)
595 b += 4, m -= 4;
596 else if (strncmp(b, "--", 2) == 0)
597 b += 2, m -= 2;
598 else
599 return (errno(*__errno_location ()) = EBADMSG74), -1;
600 /* XXX - quoting? */
601 b = su_sprintf(home, "boundary=\"%.*s\"", (int)m, b);
602 }
603 else {
604 strcpy(token, "boundary=");
605 msg_random_token(token + strlen("boundary="), (size_t)tlen, NULL((void*)0), 0);
606 b = su_strdup(home, token);
607 }
608
609 if (!b)
610 return -1;
611
612 msg_params_replace(home, (msg_param_t **)&c->c_params, b);
613
614 b += strlen("boundary=");
615 }
616
617 if (!(boundary = msg_multipart_boundary(home, b)))
618 return -1;
619
620 blen = strlen(boundary); m = blen - 2;
621
622 for (; mp; mp = mp->mp_next) {
623 if (mp->mp_data == NULL((void*)0)) {
624 mp->mp_data = boundary;
625 mp->mp_len = (unsigned)blen; /* XXX */
626 } else {
627 if (mp->mp_len < 3)
628 return -1;
629 if (mp->mp_data[0] == '\r' && mp->mp_data[1] == '\n') {
630 if (mp->mp_len < m || memcmp(mp->mp_data + 2, boundary + 2, m - 2))
631 return -1;
632 } else if (mp->mp_data[0] == '\n') {
633 if (mp->mp_len < m - 1 || memcmp(mp->mp_data + 1, boundary + 2, m - 2))
634 return -1;
635 } else {
636 if (mp->mp_len < m - 2 || memcmp(mp->mp_data, boundary + 2, m - 2))
637 return -1;
638 }
639 }
640
641 if (mp->mp_next == NULL((void*)0)) {
642 if (!mp->mp_close_delim)
643 mp->mp_close_delim = msg_payload_format(home, "%.*s--" _CR"\r" LF"\n",
644 (int)m, boundary);
645 if (!mp->mp_close_delim)
646 return -1;
647 }
648 else if (mp->mp_close_delim) {
649 msg_payload_t *e = mp->mp_close_delim;
650
651 mp->mp_close_delim = NULL((void*)0);
652
653 if (e->pl_common->h_prev)
654 *e->pl_common->h_prev = e->pl_common->h_succ;
655 if (e->pl_common->h_succ)
656 e->pl_common->h_succ->sh_prevsh_common->h_prev = e->pl_common->h_prev;
657 }
658
659 mp->mp_common->h_data = mp->mp_data;
660 mp->mp_common->h_len = mp->mp_len;
661
662 if (!mp->mp_separator)
663 if (!(mp->mp_separator = msg_separator_make(home, _CR"\r" LF"\n")))
664 return -1;
665
666 if (mp->mp_multipart) {
667 c = mp->mp_content_type;
668 if (c == NULL((void*)0))
669 return (errno(*__errno_location ()) = EBADMSG74), -1;
670
671 if (msg_multipart_complete(home, c, mp->mp_multipart) < 0)
672 return -1;
673 }
674
675 if (!mp->mp_payload)
676 if (!(mp->mp_payload = msg_payload_create(home, NULL((void*)0), 0)))
677 return -1;
678 }
679
680 return 0;
681}
682
683/** Serialize a multipart message.
684 *
685 */
686msg_header_t *msg_multipart_serialize(msg_header_t **head0,
687 msg_multipart_t *mp)
688{
689 msg_header_t *h_succ_all = NULL((void*)0);
690 msg_header_t *h, **head, **hh, *h0, *h_succ;
691 void *hend;
692
693#define is_in_chain(h)((h) && ((msg_frg_t*)(h))->h_prev != ((void*)0)) ((h) && ((msg_frg_t*)(h))->h_prev != NULL((void*)0))
694#define insert(head, h)((h)->sh_common->h_succ = *(head), *(head) = (h), (h)->
sh_common->h_prev = (head), (head) = &(h)->sh_common
->h_succ)
\
695 ((h)->sh_succsh_common->h_succ = *(head), *(head) = (h), \
696 (h)->sh_prevsh_common->h_prev = (head), (head) = &(h)->sh_succsh_common->h_succ)
697
698 if (mp == NULL((void*)0) || head0 == NULL((void*)0))
699 return NULL((void*)0);
700
701 h_succ_all = *head0; head = head0;
702
703 for (; mp; mp = mp->mp_next) {
704 h0 = (msg_header_t *)mp;
705
706 assert(mp->mp_separator)((void) sizeof ((mp->mp_separator) ? 1 : 0), __extension__
({ if (mp->mp_separator) ; else __assert_fail ("mp->mp_separator"
, "msg_mime.c", 706, __extension__ __PRETTY_FUNCTION__); }))
; assert(mp->mp_payload)((void) sizeof ((mp->mp_payload) ? 1 : 0), __extension__ (
{ if (mp->mp_payload) ; else __assert_fail ("mp->mp_payload"
, "msg_mime.c", 706, __extension__ __PRETTY_FUNCTION__); }))
;
707 assert(mp->mp_next || mp->mp_close_delim)((void) sizeof ((mp->mp_next || mp->mp_close_delim) ? 1
: 0), __extension__ ({ if (mp->mp_next || mp->mp_close_delim
) ; else __assert_fail ("mp->mp_next || mp->mp_close_delim"
, "msg_mime.c", 707, __extension__ __PRETTY_FUNCTION__); }))
;
708
709 if (!mp->mp_separator || !mp->mp_payload ||
710 (!mp->mp_next && !mp->mp_close_delim))
711 return NULL((void*)0);
712
713 if ((void *)mp == h_succ_all)
714 h_succ_all = NULL((void*)0);
715
716 *head0 = h0; h0->sh_prevsh_common->h_prev = head;
717
718 if (is_in_chain(mp->mp_separator)((mp->mp_separator) && ((msg_frg_t*)(mp->mp_separator
))->h_prev != ((void*)0))
)
719 hend = mp->mp_separator;
720 else if (is_in_chain(mp->mp_payload)((mp->mp_payload) && ((msg_frg_t*)(mp->mp_payload
))->h_prev != ((void*)0))
)
721 hend = mp->mp_payload;
722 else if (is_in_chain(mp->mp_multipart)((mp->mp_multipart) && ((msg_frg_t*)(mp->mp_multipart
))->h_prev != ((void*)0))
)
723 hend = mp->mp_multipart;
724 else if (is_in_chain(mp->mp_close_delim)((mp->mp_close_delim) && ((msg_frg_t*)(mp->mp_close_delim
))->h_prev != ((void*)0))
)
725 hend = mp->mp_close_delim;
726 else if (is_in_chain(mp->mp_next)((mp->mp_next) && ((msg_frg_t*)(mp->mp_next))->
h_prev != ((void*)0))
)
727 hend = mp->mp_next;
728 else
729 hend = NULL((void*)0);
730
731 /* Search latest header in chain */
732 for (head = &mp->mp_common->h_succ;
733 *head && *head != hend;
734 head = &(*head)->sh_succsh_common->h_succ)
735 ;
736
737 h_succ = *head;
738
739 /* Serialize headers */
740 for (hh = &((msg_pub_t*)mp)->msg_request;
741 (char *)hh < (char *)&mp->mp_separator;
742 hh++) {
743 h = *hh; if (!h) continue;
744 for (h = *hh; h; h = h->sh_nextsh_header_next->shn_next) {
745 if (h == h_succ || !is_in_chain(h)((h) && ((msg_frg_t*)(h))->h_prev != ((void*)0))) {
746 *head = h; h->sh_prevsh_common->h_prev = head; head = &h->sh_succsh_common->h_succ;
747 while (*head && *head != hend)
748 head = &(*head)->sh_succsh_common->h_succ;
749 if (h == h_succ)
750 h_succ = *head;
751 }
752 else {
753 /* XXX Check that h is between head and hend */
754 }
755 }
756 }
757
758 if (!is_in_chain(mp->mp_separator)((mp->mp_separator) && ((msg_frg_t*)(mp->mp_separator
))->h_prev != ((void*)0))
) {
759 insert(head, (msg_header_t *)mp->mp_separator)(((msg_header_t *)mp->mp_separator)->sh_common->h_succ
= *(head), *(head) = ((msg_header_t *)mp->mp_separator), (
(msg_header_t *)mp->mp_separator)->sh_common->h_prev
= (head), (head) = &((msg_header_t *)mp->mp_separator
)->sh_common->h_succ)
;
760 } else {
761 assert(h_succ == (msg_header_t *)mp->mp_separator)((void) sizeof ((h_succ == (msg_header_t *)mp->mp_separator
) ? 1 : 0), __extension__ ({ if (h_succ == (msg_header_t *)mp
->mp_separator) ; else __assert_fail ("h_succ == (msg_header_t *)mp->mp_separator"
, "msg_mime.c", 761, __extension__ __PRETTY_FUNCTION__); }))
;
762 mp->mp_separator->sep_common->h_prev = head;
763 *head = (msg_header_t *)mp->mp_separator;
764 head = &mp->mp_separator->sep_common->h_succ;
765 h_succ = *head;
766 }
767
768 if (!is_in_chain(mp->mp_payload)((mp->mp_payload) && ((msg_frg_t*)(mp->mp_payload
))->h_prev != ((void*)0))
) {
769 insert(head, (msg_header_t *)mp->mp_payload)(((msg_header_t *)mp->mp_payload)->sh_common->h_succ
= *(head), *(head) = ((msg_header_t *)mp->mp_payload), ((
msg_header_t *)mp->mp_payload)->sh_common->h_prev = (
head), (head) = &((msg_header_t *)mp->mp_payload)->
sh_common->h_succ)
;
770 } else {
771 assert(h_succ == (msg_header_t *)mp->mp_payload)((void) sizeof ((h_succ == (msg_header_t *)mp->mp_payload)
? 1 : 0), __extension__ ({ if (h_succ == (msg_header_t *)mp->
mp_payload) ; else __assert_fail ("h_succ == (msg_header_t *)mp->mp_payload"
, "msg_mime.c", 771, __extension__ __PRETTY_FUNCTION__); }))
;
772 mp->mp_payload->pl_common->h_prev = head;
773 *head = (msg_header_t *)mp->mp_payload;
774 head = &mp->mp_payload->pl_common->h_succ;
775 h_succ = *head;
776 }
777
778 if (mp->mp_multipart) {
779 if ((*head = h_succ))
780 h_succ->sh_prevsh_common->h_prev = head;
781 if (!(h = msg_multipart_serialize(head, mp->mp_multipart)))
782 return NULL((void*)0);
783 head = &h->sh_succsh_common->h_succ; h_succ = *head;
784 }
785
786 if (mp->mp_close_delim) {
787 if (!is_in_chain(mp->mp_close_delim)((mp->mp_close_delim) && ((msg_frg_t*)(mp->mp_close_delim
))->h_prev != ((void*)0))
) {
788 insert(head, (msg_header_t*)mp->mp_close_delim)(((msg_header_t*)mp->mp_close_delim)->sh_common->h_succ
= *(head), *(head) = ((msg_header_t*)mp->mp_close_delim),
((msg_header_t*)mp->mp_close_delim)->sh_common->h_prev
= (head), (head) = &((msg_header_t*)mp->mp_close_delim
)->sh_common->h_succ)
;
789 } else {
790 assert(h_succ == (msg_header_t *)mp->mp_close_delim)((void) sizeof ((h_succ == (msg_header_t *)mp->mp_close_delim
) ? 1 : 0), __extension__ ({ if (h_succ == (msg_header_t *)mp
->mp_close_delim) ; else __assert_fail ("h_succ == (msg_header_t *)mp->mp_close_delim"
, "msg_mime.c", 790, __extension__ __PRETTY_FUNCTION__); }))
;
791 mp->mp_close_delim->pl_common->h_prev = head;
792 *head = (msg_header_t *)mp->mp_close_delim;
793 head = &mp->mp_close_delim->pl_common->h_succ;
794 }
795
796 if (h_succ_all)
797 *head = h_succ_all, h_succ_all->sh_prevsh_common->h_prev = head;
798
799 return (msg_header_t *)mp->mp_close_delim;
800 }
801
802 *head = h_succ;
803
804 head0 = head;
805 }
806
807 assert(!mp)((void) sizeof ((!mp) ? 1 : 0), __extension__ ({ if (!mp) ; else
__assert_fail ("!mp", "msg_mime.c", 807, __extension__ __PRETTY_FUNCTION__
); }))
;
808
809 return NULL((void*)0);
810}
811
812/** Encode a multipart.
813 *
814 * @return The size of multipart in bytes, or -1 upon an error.
815 */
816issize_t msg_multipart_prepare(msg_t *msg, msg_multipart_t *mp, int flags)
817{
818 if (!mp || !mp->mp_data)
819 return -1;
820
821 if (!mp->mp_common->h_data ||
822 mp->mp_common->h_len != mp->mp_len - 2 ||
823 memcmp(mp->mp_common->h_data, mp->mp_data + 2, mp->mp_len - 2)) {
824 mp->mp_common->h_data = mp->mp_data + 2;
825 mp->mp_common->h_len = mp->mp_len - 2;
826 }
827
828 return msg_headers_prepare(msg, (msg_header_t *)mp, flags);
829}
830
831/** Decode a multipart. */
832issize_t msg_multipart_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
833{
834 su_home_t tmphome[1] = { SU_HOME_INIT(tmphome){ 0, ((void*)0), ((void*)0) } };
835 msg_payload_t pl[1];
836 msg_multipart_t *mp, *result;
837
838 assert(h && msg_is_multipart(h))((void) sizeof ((h && msg_is_multipart(h)) ? 1 : 0), __extension__
({ if (h && msg_is_multipart(h)) ; else __assert_fail
("h && msg_is_multipart(h)", "msg_mime.c", 838, __extension__
__PRETTY_FUNCTION__); }))
;
839
840 msg_payload_init(pl);
841
842 result = (msg_multipart_t *)h;
843
844 pl->pl_data = s;
845 pl->pl_len = slen;
846
847 mp = msg_multipart_parse(tmphome, NULL((void*)0), pl);
848
849 if (mp) {
850 *result = *mp;
851
852 if (result->mp_common->h_succ->sh_prevsh_common->h_prev)
853 result->mp_common->h_succ->sh_prevsh_common->h_prev =
854 &result->mp_common->h_succ;
855
856 su_free(tmphome, mp);
857
858 su_home_move(home, tmphome);
859 }
860
861 su_home_deinit(tmphome);
862
863 return mp ? 0 : -1;
864}
865
866/** Encode a multipart.
867 *
868 * Please note that here we just encode a element, the msg_multipart_t
869 * itself.
870 */
871issize_t msg_multipart_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
872{
873 return msg_payload_e(b, bsiz, h, flags);
874}
875
876/** Calculate extra size of a multipart */
877isize_t msg_multipart_dup_xtra(msg_header_t const *h, isize_t offset)
878{
879 msg_multipart_t const *mp = (msg_multipart_t *)h;
880 msg_header_t const * const *hh;
881
882 offset = msg_payload_dup_xtra(h, offset);
883
884 for (hh = (msg_header_t const **)&((msg_pub_t *)mp)->msg_request;
885 (char *)hh <= (char *)&mp->mp_close_delim;
886 hh++) {
887 for (h = *hh; h; h = h->sh_nextsh_header_next->shn_next) {
888 MSG_STRUCT_SIZE_ALIGN(offset)((offset) = (((uintptr_t)(offset) + (sizeof(void *)) - 1) &
(0 - (uintptr_t)(sizeof(void *)))))
;
889 offset = h->sh_classsh_common->h_class->hc_dxtra(h, offset + h->sh_classsh_common->h_class->hc_size);
890 }
891 }
892
893 return offset;
894}
895
896/** Duplicate one msg_multipart_t object */
897char *msg_multipart_dup_one(msg_header_t *dst, msg_header_t const *src,
898 char *b, isize_t xtra)
899{
900 msg_multipart_t const *mp = (msg_multipart_t *)src;
901 msg_header_t *h, **hh;
902 char *end = b + xtra;
903
904 b = msg_payload_dup_one(dst, src, b, xtra);
905
906 for (hh = &((msg_pub_t*)mp)->msg_request;
907 (char *)hh <= (char *)&mp->mp_close_delim;
908 hh++) {
909 for (h = *hh; h; h = h->sh_nextsh_header_next->shn_next) {
910 MSG_STRUCT_ALIGN(b)((b) = (void*)(((uintptr_t)(b) + (sizeof(void *)) - 1) & (
0 - (uintptr_t)(sizeof(void *)))))
;
911 dst = (msg_header_t *)b;
912 memset(dst, 0, sizeof dst->sh_common);
913 dst->sh_classsh_common->h_class = h->sh_classsh_common->h_class;
914 b = h->sh_classsh_common->h_class->hc_dup_one(dst, h, b + h->sh_classsh_common->h_class->hc_size, end - b);
915 if (h->sh_classsh_common->h_class->hc_update)
916 msg_header_update_params(h->sh_common, 0);
917 assert(b <= end)((void) sizeof ((b <= end) ? 1 : 0), __extension__ ({ if (
b <= end) ; else __assert_fail ("b <= end", "msg_mime.c"
, 917, __extension__ __PRETTY_FUNCTION__); }))
;
918 }
919 }
920
921 return b;
922}
923
924#if 0
925msg_hclass_t msg_multipart_class((msg_hclass_t *)msg_multipart_mclass)[] =
926MSG_HEADER_CLASS(msg_, multipart, NULL, "", mp_common, append, msg_multipart);
927#endif
928
929/**Calculate Q value.
930 *
931 * The function msg_q_value() converts q-value string @a q to numeric value
932 * in range (0..1000). Q values are used, for instance, to describe
933 * relative priorities of registered contacts.
934 *
935 * @param q q-value string ("1" | "." 1,3DIGIT)
936 *
937 * @return
938 * The function msg_q_value() returns an integer in range 0 .. 1000.
939 */
940unsigned msg_q_value(char const *q)
941{
942 unsigned value = 0;
943
944 if (!q)
945 return 500;
946 if (q[0] != '0' && q[0] != '.' && q[0] != '1')
947 return 500;
948 while (q[0] == '0')
949 q++;
950 if (q[0] >= '1' && q[0] <= '9')
951 return 1000;
952 if (q[0] == '\0')
953 return 0;
954 if (q[0] != '.')
955 /* Garbage... */
956 return 500;
957
958 if (q[1] >= '0' && q[1] <= '9') {
959 value = (q[1] - '0') * 100;
960 if (q[2] >= '0' && q[2] <= '9') {
961 value += (q[2] - '0') * 10;
962 if (q[3] >= '0' && q[3] <= '9') {
963 value += (q[3] - '0');
964 if (q[4] > '5' && q[4] <= '9')
965 /* Round upwards */
966 value += 1;
967 else if (q[4] == '5')
968 value += value & 1; /* Round to even */
969 }
970 }
971 }
972
973 return value;
974}
975
976/** Parse media type (type/subtype).
977 *
978 * The function msg_mediatype_d() parses a mediatype string.
979 *
980 * @param[in,out] ss string to be parsed
981 * @param[out] type value result for media type
982 *
983 * @retval 0 when successful,
984 * @retval -1 upon an error.
985 */
986issize_t msg_mediatype_d(char **ss, char const **type)
987{
988 char *s = *ss;
989 char const *result = s;
990 size_t l1 = 0, l2 = 0, n;
991
992 /* Media type consists of two tokens, separated by / */
993
994 l1 = span_token(s);
995 for (n = l1; IS_LWS(s[n])((s[n]) == ' ' || (s[n]) == '\t' || (s[n]) == '\r' || (s[n]) ==
'\n')
; n++)
996 {}
997 if (s[n] == '/') {
998 for (n++; IS_LWS(s[n])((s[n]) == ' ' || (s[n]) == '\t' || (s[n]) == '\r' || (s[n]) ==
'\n')
; n++)
999 {}
1000 l2 = span_token(s + n);
1001 n += l2;
1002 }
1003
1004 if (l1 == 0 || l2 == 0)
1005 return -1;
1006
1007 /* If there is extra ws between tokens, compact version */
1008 if (n > l1 + 1 + l2) {
1009 s[l1] = '/';
1010 memmove(s + l1 + 1, s + n - l2, l2);
1011 s[l1 + 1 + l2] = 0;
1012 }
1013
1014 s += n;
1015
1016 while (IS_WS(*s)((*s) == ' ' || (*s) == '\t')) *s++ = '\0';
1017
1018 *ss = s;
1019
1020 if (type)
1021 *type = result;
1022
1023 return 0;
1024}
1025
1026/* ====================================================================== */
1027
1028/**@ingroup msg_mime
1029 * @defgroup msg_accept Accept Header
1030 *
1031 * The @b Accept request-header field can be used to specify certain media
1032 * types which are acceptable for the response. Its syntax is defined in
1033 * [H14.1, S20.1] as follows:
1034 *
1035 * @code
1036 * Accept = "Accept" ":" #( media-range [ accept-params ] )
1037 *
1038 * media-range = ( "*" "/" "*"
1039 * | ( type "/" "*" )
1040 * | ( type "/" subtype ) ) *( ";" parameter )
1041 *
1042 * accept-params = ";" "q" "=" qvalue *( accept-extension )
1043 *
1044 * accept-extension = ";" token [ "=" ( token | quoted-string ) ]
1045 * @endcode
1046 *
1047 */
1048
1049/**@ingroup msg_accept
1050 * @typedef typedef struct msg_accept_s msg_accept_t;
1051 *
1052 * The structure msg_accept_t contains representation of an @b Accept
1053 * header.
1054 *
1055 * The msg_accept_t is defined as follows:
1056 * @code
1057 * typedef struct msg_accept_s {
1058 * msg_common_t ac_common[1]; // Common fragment info
1059 * msg_accept_t *ac_next; // Pointer to next Accept header
1060 * char const *ac_type; // Pointer to type/subtype
1061 * char const *ac_subtype; // Points after first slash in type
1062 * msg_param_t const *ac_params; // List of parameters
1063 * msg_param_t ac_q; // Value of q parameter
1064 * } msg_accept_t;
1065 * @endcode
1066 */
1067
1068msg_hclass_t msg_accept_class[] =
1069MSG_HEADER_CLASS(msg_, accept, "Accept", "", ac_params, apndlist,{{ msg_accept_hash, msg_accept_d, msg_accept_e, msg_accept_dup_xtra
, msg_accept_dup_one, msg_accept_update, "Accept", sizeof("Accept"
) - 1, "", (((uintptr_t)(sizeof(msg_accept_t)) + (sizeof(void
*)) - 1) & (0 - (uintptr_t)(sizeof(void*)))), __builtin_offsetof
(msg_accept_t, ac_params), msg_kind_apndlist, }}
1070 msg_accept, msg_accept){{ msg_accept_hash, msg_accept_d, msg_accept_e, msg_accept_dup_xtra
, msg_accept_dup_one, msg_accept_update, "Accept", sizeof("Accept"
) - 1, "", (((uintptr_t)(sizeof(msg_accept_t)) + (sizeof(void
*)) - 1) & (0 - (uintptr_t)(sizeof(void*)))), __builtin_offsetof
(msg_accept_t, ac_params), msg_kind_apndlist, }}
;
1071
1072issize_t msg_accept_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
1073{
1074 msg_accept_t *ac;
1075
1076 for(;;) {
1077 ac = (msg_accept_t *)h;
1078
1079 while (*s == ',') /* Ignore empty entries (comma-whitespace) */
1080 *s = '\0', s += span_lws(s + 1) + 1;
1081
1082 if (*s == '\0') {
1083 /* Empty Accept list is not an error */
1084 ac->ac_type = ac->ac_subtype = "";
1085 return 0;
1086 }
1087
1088 /* "Accept:" #(type/subtyp ; *(parameters))) */
1089 if (msg_mediatype_d(&s, &ac->ac_type) == -1)
1090 return -1;
1091 if (!(ac->ac_subtype = strchr(ac->ac_type, '/')))
1092 return -1;
1093 ac->ac_subtype++;
1094
1095 if (*s == ';' && msg_params_d(home, &s, &ac->ac_params) == -1)
1096 return -1;
1097
1098 msg_parse_next_field_without_recursion(){ msg_header_t *prev = h; msg_hclass_t *hc = prev->sh_common
->h_class; char *end = s + slen; if (*s && *s != ','
) return -1; if (msg_header_update_params(prev->sh_common,
0) < 0) return -1; while (*s == ',') *s = '\0', s += span_lws
(s + 1) + 1; if (*s == 0) return 0; h = msg_header_alloc(home
, hc, 0); if (!h) return -1; prev->sh_common->h_succ = h
, h->sh_common->h_prev = &prev->sh_common->h_succ
; prev->sh_header_next->shn_next = h; slen = end - s; }
;
1099 }
1100
1101}
1102
1103issize_t msg_accept_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
1104{
1105 char *b0 = b, *end = b + bsiz;
1106 msg_accept_t const *ac = (msg_accept_t *)h;
1107
1108 assert(msg_is_accept(h))((void) sizeof ((msg_is_accept(h)) ? 1 : 0), __extension__ ({
if (msg_is_accept(h)) ; else __assert_fail ("msg_is_accept(h)"
, "msg_mime.c", 1108, __extension__ __PRETTY_FUNCTION__); }))
;
1109
1110 if (ac->ac_type) {
1111 MSG_STRING_E(b, end, ac->ac_type)do { size_t _n = strlen(ac->ac_type); if (b + _n+1 < end
) memcpy(b, ac->ac_type, _n+1); b+= _n; } while(0)
;
1112 MSG_PARAMS_E(b, end, ac->ac_params, flags)(b) += msg_params_e((b), (size_t)((b) < (end) ? (end) - (b
) : 0), (ac->ac_params))
;
1113 }
1114 MSG_TERM_E(b, end)((b) < (end) ? (b)[0] = '\0' : '\0');
1115
1116 return b - b0;
1117}
1118
1119isize_t msg_accept_dup_xtra(msg_header_t const *h, isize_t offset)
1120{
1121 msg_accept_t const *ac = (msg_accept_t *)h;
1122
1123 if (ac->ac_type) {
1124 MSG_PARAMS_SIZE(offset, ac->ac_params)(offset = msg_params_dup_xtra(ac->ac_params, offset));
1125 offset += MSG_STRING_SIZE(ac->ac_type)((ac->ac_type) ? (strlen(ac->ac_type) + 1) : 0);
1126 }
1127
1128 return offset;
1129}
1130
1131/** Duplicate one msg_accept_t object */
1132char *msg_accept_dup_one(msg_header_t *dst, msg_header_t const *src,
1133 char *b, isize_t xtra)
1134{
1135 msg_accept_t *ac = (msg_accept_t *)dst;
1136 msg_accept_t const *o = (msg_accept_t *)src;
1137 char *end = b + xtra;
1138
1139 if (o->ac_type) {
1140 b = msg_params_dup(&ac->ac_params, o->ac_params, b, xtra);
1141 MSG_STRING_DUP(b, ac->ac_type, o->ac_type)(void)((o->ac_type)?((b)=(char*)memccpy((void *)((ac->ac_type
)=(char*)b),(o->ac_type),0,2147483647)) :((ac->ac_type)
=((void*)0)))
;
1142 if ((ac->ac_subtype = strchr(ac->ac_type, '/')))
1143 ac->ac_subtype++;
1144 }
1145
1146 assert(b <= end)((void) sizeof ((b <= end) ? 1 : 0), __extension__ ({ if (
b <= end) ; else __assert_fail ("b <= end", "msg_mime.c"
, 1146, __extension__ __PRETTY_FUNCTION__); }))
; (void)end;
1147
1148 return b;
1149}
1150
1151/** Update parameter(s) for Accept header. */
1152int msg_accept_update(msg_common_t *h,
1153 char const *name, isize_t namelen,
1154 char const *value)
1155{
1156 msg_accept_t *ac = (msg_accept_t *)h;
1157
1158 if (name == NULL((void*)0)) {
1159 ac->ac_q = NULL((void*)0);
1160 }
1161 else if (namelen == 1 && su_casenmatch(name, "q", 1)) {
1162 /* XXX - check for invalid value? */
1163 ac->ac_q = value;
1164 }
1165
1166 return 0;
1167}
1168
1169/* ====================================================================== */
1170
1171/** Decode an Accept-* header. */
1172issize_t msg_accept_any_d(su_home_t *home,
1173 msg_header_t *h,
1174 char *s, isize_t slen)
1175{
1176 /** @relatesalso msg_accept_any_s */
1177 msg_accept_any_t *aa;
1178
1179 for(;;) {
1180 aa = (msg_accept_any_t *)h;
1181 while (*s == ',') /* Ignore empty entries (comma-whitespace) */
1182 *s = '\0', s += span_lws(s + 1) + 1;
1183
1184 if (*s == '\0')
1185 return -2; /* Empty list */
1186
1187 /* "Accept-*:" 1#(token *(SEMI accept-param)) */
1188 if (msg_token_d(&s, &aa->aa_value) == -1)
1189 return -1;
1190
1191 if (*s == ';' && msg_params_d(home, &s, &aa->aa_params) == -1)
1192 return -1;
1193
1194 msg_parse_next_field_without_recursion(){ msg_header_t *prev = h; msg_hclass_t *hc = prev->sh_common
->h_class; char *end = s + slen; if (*s && *s != ','
) return -1; if (msg_header_update_params(prev->sh_common,
0) < 0) return -1; while (*s == ',') *s = '\0', s += span_lws
(s + 1) + 1; if (*s == 0) return 0; h = msg_header_alloc(home
, hc, 0); if (!h) return -1; prev->sh_common->h_succ = h
, h->sh_common->h_prev = &prev->sh_common->h_succ
; prev->sh_header_next->shn_next = h; slen = end - s; }
;
1195 }
1196
1197}
1198
1199/** Encode an Accept-* header field. */
1200issize_t msg_accept_any_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
1201{
1202 /** @relatesalso msg_accept_any_s */
1203 char *b0 = b, *end = b + bsiz;
1204 msg_accept_any_t const *aa = (msg_accept_any_t *)h;
1205
1206 MSG_STRING_E(b, end, aa->aa_value)do { size_t _n = strlen(aa->aa_value); if (b + _n+1 < end
) memcpy(b, aa->aa_value, _n+1); b+= _n; } while(0)
;
1207 MSG_PARAMS_E(b, end, aa->aa_params, flags)(b) += msg_params_e((b), (size_t)((b) < (end) ? (end) - (b
) : 0), (aa->aa_params))
;
1208 MSG_TERM_E(b, end)((b) < (end) ? (b)[0] = '\0' : '\0');
1209
1210 return b - b0;
1211}
1212
1213/** Calculate extra memory used by accept-* headers. */
1214isize_t msg_accept_any_dup_xtra(msg_header_t const *h, isize_t offset)
1215{
1216 /** @relatesalso msg_accept_any_s */
1217 msg_accept_any_t const *aa = (msg_accept_any_t *)h;
1218
1219 MSG_PARAMS_SIZE(offset, aa->aa_params)(offset = msg_params_dup_xtra(aa->aa_params, offset));
1220 offset += MSG_STRING_SIZE(aa->aa_value)((aa->aa_value) ? (strlen(aa->aa_value) + 1) : 0);
1221
1222 return offset;
1223}
1224
1225/** Duplicate one msg_accept_any_t object. */
1226char *msg_accept_any_dup_one(msg_header_t *dst, msg_header_t const *src,
1227 char *b, isize_t xtra)
1228{
1229 /** @relatesalso msg_accept_any_s */
1230 msg_accept_any_t *aa = (msg_accept_any_t *)dst;
1231 msg_accept_any_t const *o = (msg_accept_any_t *)src;
1232 char *end = b + xtra;
1233
1234 b = msg_params_dup(&aa->aa_params, o->aa_params, b, xtra);
1235 MSG_STRING_DUP(b, aa->aa_value, o->aa_value)(void)((o->aa_value)?((b)=(char*)memccpy((void *)((aa->
aa_value)=(char*)b),(o->aa_value),0,2147483647)) :((aa->
aa_value)=((void*)0)))
;
1236
1237 assert(b <= end)((void) sizeof ((b <= end) ? 1 : 0), __extension__ ({ if (
b <= end) ; else __assert_fail ("b <= end", "msg_mime.c"
, 1237, __extension__ __PRETTY_FUNCTION__); }))
; (void)end;
1238
1239 return b;
1240}
1241
1242/** Update parameter(s) for Accept-* header. */
1243int msg_accept_any_update(msg_common_t *h,
1244 char const *name, isize_t namelen,
1245 char const *value)
1246{
1247 msg_accept_any_t *aa = (msg_accept_any_t *)h;
1248
1249 if (name == NULL((void*)0)) {
1250 aa->aa_q = NULL((void*)0);
1251 }
1252 else if (namelen == 1 && su_casenmatch(name, "q", 1)) {
1253 aa->aa_q = value;
1254 }
1255
1256 return 0;
1257}
1258
1259/* ====================================================================== */
1260
1261/**@ingroup msg_mime
1262 * @defgroup msg_accept_charset Accept-Charset Header
1263 *
1264 * The Accept-Charset header is similar to Accept, but restricts the
1265 * character set that are acceptable in the response. Its syntax is
1266 * defined in [H14.2] as follows:
1267 *
1268 * @code
1269 * Accept-Charset = "Accept-Charset" ":"
1270 * 1#( ( charset | "*" )[ ";" "q" "=" qvalue ] )
1271 * @endcode
1272 *
1273 */
1274
1275/**@ingroup msg_accept_charset
1276 * @typedef typedef struct msg_accept_charset_s msg_accept_charset_t;
1277 *
1278 * The structure msg_accept_encoding_t contains representation of @b
1279 * Accept-Charset header.
1280 *
1281 * The msg_accept_charset_t is defined as follows:
1282 * @code
1283 * typedef struct {
1284 * msg_common_t aa_common[1]; // Common fragment info
1285 * msg_accept_any_t *aa_next; // Pointer to next Accept-Charset
1286 * char const *aa_value; // Charset
1287 * msg_param_t const *aa_params; // Parameter list
1288 * char const *aa_q; // Q-value
1289 * } msg_accept_charset_t;
1290 * @endcode
1291 */
1292
1293msg_hclass_t msg_accept_charset_class[1] =
1294 MSG_HEADER_CLASS(msg_, accept_charset, "Accept-Charset", "",{{ msg_accept_charset_hash, msg_accept_charset_d, msg_accept_charset_e
, msg_accept_any_dup_xtra, msg_accept_any_dup_one, msg_accept_any_update
, "Accept-Charset", sizeof("Accept-Charset") - 1, "", (((uintptr_t
)(sizeof(msg_accept_charset_t)) + (sizeof(void*)) - 1) & (
0 - (uintptr_t)(sizeof(void*)))), __builtin_offsetof(msg_accept_charset_t
, aa_params), msg_kind_apndlist, }}
1295 aa_params, apndlist, msg_accept_any, msg_accept_any){{ msg_accept_charset_hash, msg_accept_charset_d, msg_accept_charset_e
, msg_accept_any_dup_xtra, msg_accept_any_dup_one, msg_accept_any_update
, "Accept-Charset", sizeof("Accept-Charset") - 1, "", (((uintptr_t
)(sizeof(msg_accept_charset_t)) + (sizeof(void*)) - 1) & (
0 - (uintptr_t)(sizeof(void*)))), __builtin_offsetof(msg_accept_charset_t
, aa_params), msg_kind_apndlist, }}
;
1296
1297issize_t msg_accept_charset_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
1298{
1299 return msg_accept_any_d(home, h, s, slen);
1300}
1301
1302issize_t msg_accept_charset_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
1303{
1304 assert(msg_is_accept_charset(h))((void) sizeof ((msg_is_accept_charset(h)) ? 1 : 0), __extension__
({ if (msg_is_accept_charset(h)) ; else __assert_fail ("msg_is_accept_charset(h)"
, "msg_mime.c", 1304, __extension__ __PRETTY_FUNCTION__); }))
;
1305 return msg_accept_any_e(b, bsiz, h, f);
1306}
1307
1308/* ====================================================================== */
1309
1310/**@ingroup msg_mime
1311 * @defgroup msg_accept_encoding Accept-Encoding Header
1312 *
1313 * The Accept-Encoding header is similar to Accept, but restricts the
1314 * content-codings that are acceptable in the response. Its syntax is
1315 * defined in [H14.3, S20.2] as follows:
1316 *
1317 * @code
1318 * Accept-Encoding = "Accept-Encoding" ":"
1319 * 1#( codings [ ";" "q" "=" qvalue ] )
1320 * codings = ( content-coding | "*" )
1321 * content-coding = token
1322 * @endcode
1323 *
1324 */
1325
1326/**@ingroup msg_accept_encoding
1327 * @typedef typedef struct msg_accept_encoding_s msg_accept_encoding_t;
1328 *
1329 * The structure msg_accept_encoding_t contains representation of @b
1330 * Accept-Encoding header.
1331 *
1332 * The msg_accept_encoding_t is defined as follows:
1333 * @code
1334 * typedef struct {
1335 * msg_common_t aa_common[1]; // Common fragment info
1336 * msg_accept_any_t *aa_next; // Pointer to next Accept-Encoding
1337 * char const *aa_value; // Content-coding
1338 * msg_param_t const *aa_params; // Parameter list
1339 * char const *aa_q; // Q-value
1340 * } msg_accept_encoding_t;
1341 * @endcode
1342 */
1343
1344msg_hclass_t msg_accept_encoding_class[1] =
1345 MSG_HEADER_CLASS(msg_, accept_encoding, "Accept-Encoding", "",{{ msg_accept_encoding_hash, msg_accept_encoding_d, msg_accept_encoding_e
, msg_accept_any_dup_xtra, msg_accept_any_dup_one, msg_accept_any_update
, "Accept-Encoding", sizeof("Accept-Encoding") - 1, "", (((uintptr_t
)(sizeof(msg_accept_encoding_t)) + (sizeof(void*)) - 1) &
(0 - (uintptr_t)(sizeof(void*)))), __builtin_offsetof(msg_accept_encoding_t
, aa_params), msg_kind_apndlist, }}
1346 aa_params, apndlist, msg_accept_any, msg_accept_any){{ msg_accept_encoding_hash, msg_accept_encoding_d, msg_accept_encoding_e
, msg_accept_any_dup_xtra, msg_accept_any_dup_one, msg_accept_any_update
, "Accept-Encoding", sizeof("Accept-Encoding") - 1, "", (((uintptr_t
)(sizeof(msg_accept_encoding_t)) + (sizeof(void*)) - 1) &
(0 - (uintptr_t)(sizeof(void*)))), __builtin_offsetof(msg_accept_encoding_t
, aa_params), msg_kind_apndlist, }}
;
1347
1348issize_t msg_accept_encoding_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
1349{
1350 return msg_accept_any_d(home, h, s, slen);
1351}
1352
1353issize_t msg_accept_encoding_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
1354{
1355 return msg_accept_any_e(b, bsiz, h, f);
1356}
1357
1358/* ====================================================================== */
1359
1360/**@ingroup msg_mime
1361 * @defgroup msg_accept_language Accept-Language Header
1362 *
1363 * The Accept-Language header allows the client to indicate to the server in
1364 * which language it would prefer to receive reason phrases, session
1365 * descriptions or status responses carried as message bodies. Its syntax is
1366 * defined in [H14.4, S20.3] as follows:
1367 *
1368 * @code
1369 * Accept-Language = "Accept-Language" ":"
1370 * 1#( language-range [ ";" "q" "=" qvalue ] )
1371 *
1372 * language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
1373 * @endcode
1374 *
1375 */
1376
1377/**@ingroup msg_accept_language
1378 * @typedef typedef struct msg_accept_language_s msg_accept_language_t;
1379 *
1380 * The structure msg_accept_language_t contains representation of @b
1381 * Accept-Language header.
1382 *
1383 * The msg_accept_language_t is defined as follows:
1384 * @code
1385 * typedef struct {
1386 * msg_common_t aa_common[1]; // Common fragment info
1387 * msg_accept_any_t *aa_next; // Pointer to next Accept-Encoding
1388 * char const *aa_value; // Language-range
1389 * msg_param_t const *aa_params; // Parameter list
1390 * char const *aa_q; // Q-value
1391 * } msg_accept_language_t;
1392 * @endcode
1393 */
1394
1395msg_hclass_t msg_accept_language_class[1] =
1396 MSG_HEADER_CLASS(msg_, accept_language, "Accept-Language", "",{{ msg_accept_language_hash, msg_accept_language_d, msg_accept_language_e
, msg_accept_any_dup_xtra, msg_accept_any_dup_one, msg_accept_any_update
, "Accept-Language", sizeof("Accept-Language") - 1, "", (((uintptr_t
)(sizeof(msg_accept_language_t)) + (sizeof(void*)) - 1) &
(0 - (uintptr_t)(sizeof(void*)))), __builtin_offsetof(msg_accept_language_t
, aa_params), msg_kind_apndlist, }}
1397 aa_params, apndlist, msg_accept_any, msg_accept_any){{ msg_accept_language_hash, msg_accept_language_d, msg_accept_language_e
, msg_accept_any_dup_xtra, msg_accept_any_dup_one, msg_accept_any_update
, "Accept-Language", sizeof("Accept-Language") - 1, "", (((uintptr_t
)(sizeof(msg_accept_language_t)) + (sizeof(void*)) - 1) &
(0 - (uintptr_t)(sizeof(void*)))), __builtin_offsetof(msg_accept_language_t
, aa_params), msg_kind_apndlist, }}
;
1398
1399issize_t msg_accept_language_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
1400{
1401 return msg_accept_any_d(home, h, s, slen);
1402}
1403
1404issize_t msg_accept_language_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
1405{
1406 assert(msg_is_accept_language(h))((void) sizeof ((msg_is_accept_language(h)) ? 1 : 0), __extension__
({ if (msg_is_accept_language(h)) ; else __assert_fail ("msg_is_accept_language(h)"
, "msg_mime.c", 1406, __extension__ __PRETTY_FUNCTION__); }))
;
1407 return msg_accept_any_e(b, bsiz, h, f);
1408}
1409
1410
1411/* ====================================================================== */
1412
1413/**@ingroup msg_mime
1414 * @defgroup msg_content_disposition Content-Disposition Header
1415 *
1416 * The Content-Disposition header field describes how the message body or,
1417 * in the case of multipart messages, a message body part is to be
1418 * interpreted by the UAC or UAS. Its syntax is defined in [S20.11]
1419 * as follows:
1420 *
1421 * @code
1422 * Content-Disposition = "Content-Disposition" ":"
1423 * disposition-type *( ";" disposition-param )
1424 * disposition-type = "render" | "session" | "icon" | "alert"
1425 * | disp-extension-token
1426 * disposition-param = "handling" "="
1427 * ( "optional" | "required" | other-handling )
1428 * | generic-param
1429 * other-handling = token
1430 * disp-extension-token = token
1431 * @endcode
1432 *
1433 * The Content-Disposition header was extended by
1434 * draft-lennox-sip-reg-payload-01.txt section 3.1 as follows:
1435 *
1436 * @code
1437 * Content-Disposition = "Content-Disposition" ":"
1438 * disposition-type *( ";" disposition-param )
1439 * disposition-type /= "script" | "sip-cgi" | token
1440 * disposition-param /= action-param
1441 * / modification-date-param
1442 * action-param = "action" "=" action-value
1443 * action-value = "store" | "remove" | token
1444 * modification-date-param = "modification-date" "=" quoted-date-time
1445 * quoted-date-time = <"> SIP-date <">
1446 * @endcode
1447 */
1448
1449/**@ingroup msg_content_disposition
1450 * @typedef struct msg_content_disposition_s msg_content_disposition_t;
1451 *
1452 * The structure msg_content_disposition_t contains representation of an @b
1453 * Content-Disposition header.
1454 *
1455 * The msg_content_disposition_t is defined as follows:
1456 * @code
1457 * typedef struct msg_content_disposition_s
1458 * {
1459 * msg_common_t cd_common[1]; // Common fragment info
1460 * msg_error_t *cd_next; // Link to next (dummy)
1461 * char const *cd_type; // Disposition type
1462 * msg_param_t const *cd_params; // List of parameters
1463 * msg_param_t cd_handling; // Value of @b handling parameter
1464 * unsigned cd_required:1; // True if handling=required
1465 * unsigned cd_optional:1; // True if handling=optional
1466 * } msg_content_disposition_t;
1467 * @endcode
1468 */
1469
1470msg_hclass_t msg_content_disposition_class[] =
1471MSG_HEADER_CLASS(msg_, content_disposition, "Content-Disposition", "",{{ msg_content_disposition_hash, msg_content_disposition_d, msg_content_disposition_e
, msg_content_disposition_dup_xtra, msg_content_disposition_dup_one
, msg_content_disposition_update, "Content-Disposition", sizeof
("Content-Disposition") - 1, "", (((uintptr_t)(sizeof(msg_content_disposition_t
)) + (sizeof(void*)) - 1) & (0 - (uintptr_t)(sizeof(void*
)))), __builtin_offsetof(msg_content_disposition_t, cd_params
), msg_kind_single, }}
1472 cd_params, single, msg_content_disposition,{{ msg_content_disposition_hash, msg_content_disposition_d, msg_content_disposition_e
, msg_content_disposition_dup_xtra, msg_content_disposition_dup_one
, msg_content_disposition_update, "Content-Disposition", sizeof
("Content-Disposition") - 1, "", (((uintptr_t)(sizeof(msg_content_disposition_t
)) + (sizeof(void*)) - 1) & (0 - (uintptr_t)(sizeof(void*
)))), __builtin_offsetof(msg_content_disposition_t, cd_params
), msg_kind_single, }}
1473 msg_content_disposition){{ msg_content_disposition_hash, msg_content_disposition_d, msg_content_disposition_e
, msg_content_disposition_dup_xtra, msg_content_disposition_dup_one
, msg_content_disposition_update, "Content-Disposition", sizeof
("Content-Disposition") - 1, "", (((uintptr_t)(sizeof(msg_content_disposition_t
)) + (sizeof(void*)) - 1) & (0 - (uintptr_t)(sizeof(void*
)))), __builtin_offsetof(msg_content_disposition_t, cd_params
), msg_kind_single, }}
;
1474
1475issize_t msg_content_disposition_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
1476{
1477 msg_content_disposition_t *cd = (msg_content_disposition_t *)h;
1478
1479 if (msg_token_d(&s, &cd->cd_type) < 0 ||
1480 (*s == ';' && msg_params_d(home, &s, &cd->cd_params) < 0))
1481 return -1;
1482
1483 if (cd->cd_params)
1484 msg_header_update_params(cd->cd_common, 0);
1485
1486 return 0;
1487}
1488
1489issize_t msg_content_disposition_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
1490{
1491 char *b0 = b, *end = b + bsiz;
1492 msg_content_disposition_t const *cd = (msg_content_disposition_t *)h;
1493
1494 assert(msg_is_content_disposition(h))((void) sizeof ((msg_is_content_disposition(h)) ? 1 : 0), __extension__
({ if (msg_is_content_disposition(h)) ; else __assert_fail (
"msg_is_content_disposition(h)", "msg_mime.c", 1494, __extension__
__PRETTY_FUNCTION__); }))
;
1495
1496 MSG_STRING_E(b, end, cd->cd_type)do { size_t _n = strlen(cd->cd_type); if (b + _n+1 < end
) memcpy(b, cd->cd_type, _n+1); b+= _n; } while(0)
;
1497 MSG_PARAMS_E(b, end, cd->cd_params, f)(b) += msg_params_e((b), (size_t)((b) < (end) ? (end) - (b
) : 0), (cd->cd_params))
;
1498
1499 MSG_TERM_E(b, end)((b) < (end) ? (b)[0] = '\0' : '\0');
1500
1501 return b - b0;
1502}
1503
1504isize_t msg_content_disposition_dup_xtra(msg_header_t const *h, isize_t offset)
1505{
1506 msg_content_disposition_t const *cd = (msg_content_disposition_t *)h;
1507
1508 MSG_PARAMS_SIZE(offset, cd->cd_params)(offset = msg_params_dup_xtra(cd->cd_params, offset));
1509 offset += MSG_STRING_SIZE(cd->cd_type)((cd->cd_type) ? (strlen(cd->cd_type) + 1) : 0);
1510
1511 return offset;
1512}
1513
1514/** Duplicate one msg_content_disposition_t object */
1515char *msg_content_disposition_dup_one(msg_header_t *dst,
1516 msg_header_t const *src,
1517 char *b, isize_t xtra)
1518{
1519 msg_content_disposition_t *cd = (msg_content_disposition_t *)dst;
1520 msg_content_disposition_t const *o = (msg_content_disposition_t *)src;
1521 char *end = b + xtra;
1522
1523 b = msg_params_dup(&cd->cd_params, o->cd_params, b, xtra);
1524 MSG_STRING_DUP(b, cd->cd_type, o->cd_type)(void)((o->cd_type)?((b)=(char*)memccpy((void *)((cd->cd_type
)=(char*)b),(o->cd_type),0,2147483647)) :((cd->cd_type)
=((void*)0)))
;
1525
1526 assert(b <= end)((void) sizeof ((b <= end) ? 1 : 0), __extension__ ({ if (
b <= end) ; else __assert_fail ("b <= end", "msg_mime.c"
, 1526, __extension__ __PRETTY_FUNCTION__); }))
; (void)end;
1527
1528 return b;
1529}
1530
1531/** Update Content-Disposition parameters */
1532int msg_content_disposition_update(msg_common_t *h,
1533 char const *name, isize_t namelen,
1534 char const *value)
1535{
1536 msg_content_disposition_t *cd = (msg_content_disposition_t *)h;
1537
1538 if (name == NULL((void*)0)) {
1539 cd->cd_handling = NULL((void*)0), cd->cd_required = 0, cd->cd_optional = 0;
1540 }
1541 else if (namelen == strlen("handling") &&
1542 su_casenmatch(name, "handling", namelen)) {
1543 cd->cd_handling = value;
1544 cd->cd_required = su_casematch(value, "required");
1545 cd->cd_optional = su_casematch(value, "optional");
1546 }
1547
1548 return 0;
1549}
1550
1551/* ====================================================================== */
1552
1553/**@ingroup msg_mime
1554 * @defgroup msg_content_encoding Content-Encoding Header
1555 *
1556 * The Content-Encoding header indicates what additional content codings
1557 * have been applied to the entity-body. Its syntax is defined in [H14.11]
1558 * and [S20.12] as follows:
1559 *
1560 * @code
1561 * Content-Encoding = ( "Content-Encoding" / "e" ) ":" 1#content-coding
1562 * content-coding = token
1563 * @endcode
1564 */
1565
1566/**@ingroup msg_content_encoding
1567 * @typedef struct msg_list_s msg_content_encoding_t;
1568 *
1569 * The structure msg_content_encoding_t contains representation of an @b
1570 * Content-Encoding header.
1571 *
1572 * The msg_content_encoding_t is defined as follows:
1573 * @code
1574 * typedef struct msg_list_s
1575 * {
1576 * msg_common_t k_common[1]; // Common fragment info
1577 * msg_list_t *k_next; // Link to next header
1578 * msg_param_t *k_items; // List of items
1579 * } msg_content_encoding_t;
1580 * @endcode
1581 */
1582
1583msg_hclass_t msg_content_encoding_class[] =
1584 MSG_HEADER_CLASS_LIST(content_encoding, "Content-Encoding", "e", list){{ msg_content_encoding_hash, msg_content_encoding_d, msg_content_encoding_e
, msg_list_dup_xtra, msg_list_dup_one, ((void*)0), "Content-Encoding"
, sizeof("Content-Encoding") - 1, "e", (((uintptr_t)(sizeof(msg_content_encoding_t
)) + (sizeof(void*)) - 1) & (0 - (uintptr_t)(sizeof(void*
)))), __builtin_offsetof(msg_content_encoding_t, k_items), msg_kind_list
, }}
;
1585
1586issize_t msg_content_encoding_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
1587{
1588 msg_content_encoding_t *e = (msg_content_encoding_t *)h;
1589 return msg_commalist_d(home, &s, &e->k_items, msg_token_scan);
1590}
1591
1592issize_t msg_content_encoding_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
1593{
1594 assert(msg_is_content_encoding(h))((void) sizeof ((msg_is_content_encoding(h)) ? 1 : 0), __extension__
({ if (msg_is_content_encoding(h)) ; else __assert_fail ("msg_is_content_encoding(h)"
, "msg_mime.c", 1594, __extension__ __PRETTY_FUNCTION__); }))
;
1595 return msg_list_e(b, bsiz, h, f);
1596}
1597
1598/* ====================================================================== */
1599
1600/**@ingroup msg_mime
1601 * @defgroup msg_content_language Content-Language Header
1602 *
1603 * The Content-Language header describes the natural language(s) of the
1604 * intended audience for the enclosed message body. Note that this might not
1605 * be equivalent to all the languages used within the message-body. Its
1606 * syntax is defined in [H14.12, S20.13] as follows:
1607 *
1608 * @code
1609 * Content-Language = "Content-Language" ":" 1#language-tag
1610 * @endcode
1611 * or
1612 * @code
1613 * Content-Language = "Content-Language" HCOLON
1614 * language-tag *(COMMA language-tag)
1615 * language-tag = primary-tag *( "-" subtag )
1616 * primary-tag = 1*8ALPHA
1617 * subtag = 1*8ALPHA
1618 * @endcode
1619 *
1620 */
1621
1622/**@ingroup msg_content_language
1623 * @typedef typedef struct msg_content_language_s msg_content_language_t;
1624 *
1625 * The structure msg_content_language_t contains representation of @b
1626 * Content-Language header.
1627 *
1628 * The msg_content_language_t is defined as follows:
1629 * @code
1630 * typedef struct {
1631 * msg_common_t k_common[1]; // Common fragment info
1632 * msg_content_language_t *k_next; // (Content-Encoding header)
1633 * msg_param_t *k_items; // List of languages
1634 * } msg_content_language_t;
1635 * @endcode
1636 */
1637
1638msg_hclass_t msg_content_language_class[] =
1639MSG_HEADER_CLASS_LIST(content_language, "Content-Language", "", list){{ msg_content_language_hash, msg_content_language_d, msg_content_language_e
, msg_list_dup_xtra, msg_list_dup_one, ((void*)0), "Content-Language"
, sizeof("Content-Language") - 1, "", (((uintptr_t)(sizeof(msg_content_language_t
)) + (sizeof(void*)) - 1) & (0 - (uintptr_t)(sizeof(void*
)))), __builtin_offsetof(msg_content_language_t, k_items), msg_kind_list
, }}
;
1640
1641issize_t msg_content_language_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
1642{
1643 msg_content_language_t *k = (msg_content_language_t *)h;
1644 return msg_commalist_d(home, &s, &k->k_items, msg_token_scan);
1645}
1646
1647issize_t msg_content_language_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
1648{
1649 assert(msg_is_content_language(h))((void) sizeof ((msg_is_content_language(h)) ? 1 : 0), __extension__
({ if (msg_is_content_language(h)) ; else __assert_fail ("msg_is_content_language(h)"
, "msg_mime.c", 1649, __extension__ __PRETTY_FUNCTION__); }))
;
1650 return msg_list_e(b, bsiz, h, f);
1651}
1652
1653/* ====================================================================== */
1654
1655/**@ingroup msg_mime
1656 * @defgroup msg_content_length Content-Length Header
1657 *
1658 * The Content-Length header indicates the size of the message-body in
1659 * decimal number of octets. Its syntax is defined in [S10.18] as
1660 * follows:
1661 *
1662 * @code
1663 * Content-Length = ( "Content-Length" / "l" ) HCOLON 1*DIGIT
1664 * @endcode
1665 *
1666 */
1667
1668/**@ingroup msg_content_length
1669 * @typedef typedef struct msg_content_length_s msg_content_length_t;
1670 *
1671 * The structure msg_content_length_t contains representation of a
1672 * Content-Length header.
1673 *
1674 * The msg_content_length_t is defined as follows:
1675 * @code
1676 * typedef struct msg_content_length_s {
1677 * msg_common_t l_common[1]; // Common fragment info
1678 * msg_error_t *l_next; // Link to next (dummy)
1679 * unsigned long l_length; // Numeric value
1680 * } msg_content_length_t;
1681 * @endcode
1682 */
1683
1684#define msg_content_length_dmsg_numeric_d msg_numeric_d
1685#define msg_content_length_emsg_numeric_e msg_numeric_e
1686
1687msg_hclass_t msg_content_length_class[] =
1688MSG_HEADER_CLASS(msg_, content_length, "Content-Length", "l",{{ msg_content_length_hash, msg_numeric_d, msg_numeric_e, msg_default_dup_xtra
, msg_default_dup_one, ((void*)0), "Content-Length", sizeof("Content-Length"
) - 1, "l", (((uintptr_t)(sizeof(msg_content_length_t)) + (sizeof
(void*)) - 1) & (0 - (uintptr_t)(sizeof(void*)))), __builtin_offsetof
(msg_content_length_t, l_common), msg_kind_single, 1, }}
1689 l_common, single_critical, msg_default, msg_generic){{ msg_content_length_hash, msg_numeric_d, msg_numeric_e, msg_default_dup_xtra
, msg_default_dup_one, ((void*)0), "Content-Length", sizeof("Content-Length"
) - 1, "l", (((uintptr_t)(sizeof(msg_content_length_t)) + (sizeof
(void*)) - 1) & (0 - (uintptr_t)(sizeof(void*)))), __builtin_offsetof
(msg_content_length_t, l_common), msg_kind_single, 1, }}
;
1690
1691/**@ingroup msg_content_length
1692 * Create a @b Content-Length header object.
1693 *
1694 * The function msg_content_length_create() creates a Content-Length
1695 * header object with the value @a n. The memory for the header is
1696 * allocated from the memory home @a home.
1697 *
1698 * @param home memory home
1699 * @param n payload size in bytes
1700 *
1701 * @return
1702 * The function msg_content_length_create() returns a pointer to newly
1703 * created @b Content-Length header object when successful or NULL upon
1704 * an error.
1705 */
1706msg_content_length_t *msg_content_length_create(su_home_t *home, uint32_t n)
1707{
1708 msg_content_length_t *l = (msg_content_length_t *)
1709 msg_header_alloc(home, msg_content_length_class, 0);
1710
1711 if (l)
1712 l->l_length = n;
1713
1714 return l;
1715}
1716
1717
1718/* ====================================================================== */
1719
1720/**@ingroup msg_mime
1721 * @defgroup msg_content_md5 Content-MD5 Header
1722 *
1723 * The Content-MD5 header is an MD5 digest of the entity-body for the
1724 * purpose of providing an end-to-end message integrity check (MIC) of the
1725 * message-body. Its syntax is defined in [@RFC1864, H14.15] as follows:
1726 *
1727 * @code
1728 * Content-MD5 = "Content-MD5" ":" md5-digest
1729 * md5-digest = <base64 of 128 bit MD5 digest as per @RFC1864>
1730 * @endcode
1731 */
1732
1733/**@ingroup msg_content_md5
1734 * @typedef struct msg_generic_s msg_content_md5_t;
1735 *
1736 * The structure msg_content_md5_t contains representation of an @b
1737 * Content-MD5 header.
1738 *
1739 * The msg_content_md5_t is defined as follows:
1740 * @code
1741 * typedef struct msg_generic_s
1742 * {
1743 * msg_common_t g_common[1]; // Common fragment info
1744 * msg_generic_t *g_next; // Link to next header
1745 * char const *g_string; // Header value
1746 * } msg_content_md5_t;
1747 * @endcode
1748 */
1749
1750#define msg_content_md5_dmsg_generic_d msg_generic_d
1751#define msg_content_md5_emsg_generic_e msg_generic_e
1752msg_hclass_t msg_content_md5_class[] =
1753MSG_HEADER_CLASS_G(content_md5, "Content-MD5", "", single){{ msg_content_md5_hash, msg_generic_d, msg_generic_e, msg_generic_dup_xtra
, msg_generic_dup_one, ((void*)0), "Content-MD5", sizeof("Content-MD5"
) - 1, "", (((uintptr_t)(sizeof(msg_content_md5_t)) + (sizeof
(void*)) - 1) & (0 - (uintptr_t)(sizeof(void*)))), __builtin_offsetof
(msg_content_md5_t, g_common), msg_kind_single, }}
;
1754
1755/* ====================================================================== */
1756
1757/**@ingroup msg_mime
1758 * @defgroup msg_content_id Content-ID Header
1759 *
1760 * The Content-ID header is an unique identifier of an entity-body. The
1761 * Content-ID value may be used for uniquely identifying MIME entities in
1762 * several contexts, particularly for caching data referenced by the
1763 * message/external-body mechanism. Its syntax is defined in [RFC2045] as
1764 * follows:
1765 *
1766 * @code
1767 * Content-ID = "Content-ID" ":" msg-id
1768 * msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS]
1769 * id-left = dot-atom-text / no-fold-quote / obs-id-left
1770 * id-right = dot-atom-text / no-fold-literal / obs-id-right
1771 * @endcode
1772 */
1773
1774/**@ingroup msg_content_id
1775 * @typedef msg_generic_t msg_content_id_t;
1776 * Content-ID Header Structure.
1777 * @code
1778 * typedef struct
1779 * {
1780 * msg_common_t g_common[1]; // Common fragment info
1781 * msg_content_id_t *g_next; // Link to next header
1782 * char const *g_string; // Header value
1783 * }
1784 * @endcode
1785 */
1786
1787#define msg_content_id_dmsg_generic_d msg_generic_d
1788#define msg_content_id_emsg_generic_e msg_generic_e
1789msg_hclass_t msg_content_id_class[] =
1790MSG_HEADER_CLASS_G(content_id, "Content-ID", "", single){{ msg_content_id_hash, msg_generic_d, msg_generic_e, msg_generic_dup_xtra
, msg_generic_dup_one, ((void*)0), "Content-ID", sizeof("Content-ID"
) - 1, "", (((uintptr_t)(sizeof(msg_content_id_t)) + (sizeof(
void*)) - 1) & (0 - (uintptr_t)(sizeof(void*)))), __builtin_offsetof
(msg_content_id_t, g_common), msg_kind_single, }}
;
1791
1792/* ====================================================================== */
1793
1794/**@ingroup msg_mime
1795 * @defgroup msg_content_type Content-Type Header
1796 *
1797 * The @b Content-Type header indicates the media type of the message-body
1798 * sent to the recipient. Its syntax is defined in [H3.7, S20.15]
1799 * as follows:
1800 *
1801 * @code
1802 * Content-Type = ( "Content-Type" | "c" ) ":" media-type
1803 * media-type = type "/" subtype *( ";" parameter )
1804 * type = token
1805 * subtype = token
1806 * @endcode
1807 */
1808
1809/**@ingroup msg_content_type
1810 * @typedef typedef struct msg_content_type_s msg_content_type_t;
1811 *
1812 * The structure msg_content_type_t contains representation of @b
1813 * Content-Type header.
1814 *
1815 * The msg_content_type_t is defined as follows:
1816 * @code
1817 * typedef struct msg_content_type_s {
1818 * msg_common_t c_common[1]; // Common fragment info
1819 * msg_unknown_t *c_next; // Dummy link to next
1820 * char const *c_type; // Pointer to type/subtype
1821 * char const *c_subtype; // Points after first slash in type
1822 * msg_param_t const *c_params; // List of parameters
1823 * } msg_content_type_t;
1824 * @endcode
1825 *
1826 * The @a c_type is always void of whitespace, that is, there is no
1827 * whitespace around the slash.
1828 */
1829
1830#define msg_content_type_update((void*)0) NULL((void*)0)
1831
1832msg_hclass_t msg_content_type_class[] =
1833MSG_HEADER_CLASS(msg_, content_type, "Content-Type", "c", c_params,{{ msg_content_type_hash, msg_content_type_d, msg_content_type_e
, msg_content_type_dup_xtra, msg_content_type_dup_one, ((void
*)0), "Content-Type", sizeof("Content-Type") - 1, "c", (((uintptr_t
)(sizeof(msg_content_type_t)) + (sizeof(void*)) - 1) & (0
- (uintptr_t)(sizeof(void*)))), __builtin_offsetof(msg_content_type_t
, c_params), msg_kind_single, }}
1834 single, msg_content_type, msg_content_type){{ msg_content_type_hash, msg_content_type_d, msg_content_type_e
, msg_content_type_dup_xtra, msg_content_type_dup_one, ((void
*)0), "Content-Type", sizeof("Content-Type") - 1, "c", (((uintptr_t
)(sizeof(msg_content_type_t)) + (sizeof(void*)) - 1) & (0
- (uintptr_t)(sizeof(void*)))), __builtin_offsetof(msg_content_type_t
, c_params), msg_kind_single, }}
;
1835
1836issize_t msg_content_type_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
1837{
1838 msg_content_type_t *c;
1839
1840 assert(h)((void) sizeof ((h) ? 1 : 0), __extension__ ({ if (h) ; else __assert_fail
("h", "msg_mime.c", 1840, __extension__ __PRETTY_FUNCTION__)
; }))
;
1841
1842 c = (msg_content_type_t *)h;
1843
1844 /* "Content-type:" type/subtyp *(; parameter))) */
1845 if (msg_mediatype_d(&s, &c->c_type) == -1 || /* compacts token / token */
1846 (c->c_subtype = strchr(c->c_type, '/')) == NULL((void*)0) ||
1847 (*s == ';' && msg_params_d(home, &s, &c->c_params) == -1) ||
1848 (*s != '\0'))
1849 return -1;
1850
1851 c->c_subtype++;
1852
1853 return 0;
1854}
1855
1856issize_t msg_content_type_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
1857{
1858 char *b0 = b, *end = b + bsiz;
1859 msg_content_type_t const *c = (msg_content_type_t *)h;
1860
1861 assert(msg_is_content_type(h))((void) sizeof ((msg_is_content_type(h)) ? 1 : 0), __extension__
({ if (msg_is_content_type(h)) ; else __assert_fail ("msg_is_content_type(h)"
, "msg_mime.c", 1861, __extension__ __PRETTY_FUNCTION__); }))
;
1862
1863 MSG_STRING_E(b, end, c->c_type)do { size_t _n = strlen(c->c_type); if (b + _n+1 < end)
memcpy(b, c->c_type, _n+1); b+= _n; } while(0)
;
1864 MSG_PARAMS_E(b, end, c->c_params, flags)(b) += msg_params_e((b), (size_t)((b) < (end) ? (end) - (b
) : 0), (c->c_params))
;
1865 MSG_TERM_E(b, end)((b) < (end) ? (b)[0] = '\0' : '\0');
1866
1867 return b - b0;
1868}
1869
1870isize_t msg_content_type_dup_xtra(msg_header_t const *h, isize_t offset)
1871{
1872 msg_content_type_t const *c = (msg_content_type_t *)h;
1873
1874 MSG_PARAMS_SIZE(offset, c->c_params)(offset = msg_params_dup_xtra(c->c_params, offset));
1875 offset += MSG_STRING_SIZE(c->c_type)((c->c_type) ? (strlen(c->c_type) + 1) : 0);
1876
1877 return offset;
1878}
1879
1880/** Duplicate one msg_content_type_t object */
1881char *msg_content_type_dup_one(msg_header_t *dst, msg_header_t const *src,
1882 char *b, isize_t xtra)
1883{
1884 msg_content_type_t *c = (msg_content_type_t *)dst;
1885 msg_content_type_t const *o = (msg_content_type_t *)src;
1886 char *end = b + xtra;
1887
1888 b = msg_params_dup(&c->c_params, o->c_params, b, xtra);
1889 MSG_STRING_DUP(b, c->c_type, o->c_type)(void)((o->c_type)?((b)=(char*)memccpy((void *)((c->c_type
)=(char*)b),(o->c_type),0,2147483647)) :((c->c_type)=((
void*)0)))
;
1890
1891 c->c_subtype = c->c_type ? strchr(c->c_type, '/') : NULL((void*)0);
1892 if (c->c_subtype)
1893 c->c_subtype++;
1894
1895 assert(b <= end)((void) sizeof ((b <= end) ? 1 : 0), __extension__ ({ if (
b <= end) ; else __assert_fail ("b <= end", "msg_mime.c"
, 1895, __extension__ __PRETTY_FUNCTION__); }))
; (void)end;
1896
1897 return b;
1898}
1899
1900/* ====================================================================== */
1901
1902/**@ingroup msg_mime
1903 * @defgroup msg_mime_version MIME-Version Header
1904 *
1905 * MIME-Version header indicates what version of the protocol was used
1906 * to construct the message. Its syntax is defined in [H19.4.1, S20.24]
1907 * as follows:
1908 *
1909 * @code
1910 * MIME-Version = "MIME-Version" ":" 1*DIGIT "." 1*DIGIT
1911 * @endcode
1912 */
1913
1914/**@ingroup msg_mime_version
1915 * @typedef struct msg_generic_s msg_mime_version_t;
1916 *
1917 * The structure msg_mime_version_t contains representation of an @b
1918 * MIME-Version header.
1919 *
1920 * The msg_mime_version_t is defined as follows:
1921 * @code
1922 * typedef struct msg_generic_s
1923 * {
1924 * msg_common_t g_common[1]; // Common fragment info
1925 * msg_generic_t *g_next; // Link to next header
1926 * char const *g_string; // Header value
1927 * } msg_mime_version_t;
1928 * @endcode
1929 */
1930
1931msg_hclass_t msg_mime_version_class[] =
1932MSG_HEADER_CLASS_G(mime_version, "MIME-Version", "", single){{ msg_mime_version_hash, msg_mime_version_d, msg_mime_version_e
, msg_generic_dup_xtra, msg_generic_dup_one, ((void*)0), "MIME-Version"
, sizeof("MIME-Version") - 1, "", (((uintptr_t)(sizeof(msg_mime_version_t
)) + (sizeof(void*)) - 1) & (0 - (uintptr_t)(sizeof(void*
)))), __builtin_offsetof(msg_mime_version_t, g_common), msg_kind_single
, }}
;
1933
1934issize_t msg_mime_version_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
1935{
1936 return msg_generic_d(home, h, s, slen);
1937}
1938
1939issize_t msg_mime_version_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
1940{
1941 assert(msg_is_mime_version(h))((void) sizeof ((msg_is_mime_version(h)) ? 1 : 0), __extension__
({ if (msg_is_mime_version(h)) ; else __assert_fail ("msg_is_mime_version(h)"
, "msg_mime.c", 1941, __extension__ __PRETTY_FUNCTION__); }))
;
1942 return msg_generic_e(b, bsiz, h, f);
1943}
1944
1945/* ====================================================================== */
1946
1947/**@ingroup msg_mime
1948 * @defgroup msg_content_location Content-Location Header
1949 *
1950 *
1951 */
1952
1953/**@ingroup msg_content_location
1954 * @typedef struct msg_generic_s msg_content_location_t;
1955 *
1956 * The structure msg_content_location_t contains representation of an @b
1957 * Content-Location header.
1958 *
1959 * The msg_content_location_t is defined as follows:
1960 * @code
1961 * typedef struct msg_generic_s
1962 * {
1963 * msg_common_t g_common[1]; // Common fragment info
1964 * msg_generic_t *g_next; // Link to next header
1965 * char const *g_string; // Header value
1966 * } msg_content_location_t;
1967 * @endcode
1968 */
1969
1970#define msg_content_location_dmsg_generic_d msg_generic_d
1971#define msg_content_location_emsg_generic_e msg_generic_e
1972msg_hclass_t msg_content_location_class[] =
1973MSG_HEADER_CLASS_G(content_location, "Content-Location", "", single){{ msg_content_location_hash, msg_generic_d, msg_generic_e, msg_generic_dup_xtra
, msg_generic_dup_one, ((void*)0), "Content-Location", sizeof
("Content-Location") - 1, "", (((uintptr_t)(sizeof(msg_content_location_t
)) + (sizeof(void*)) - 1) & (0 - (uintptr_t)(sizeof(void*
)))), __builtin_offsetof(msg_content_location_t, g_common), msg_kind_single
, }}
;
1974
1975
1976/* ====================================================================== */
1977#if 0
1978/**@ingroup msg_mime
1979 * @defgroup msg_content_base Content-Base Header
1980 *
1981 * @RFC2617:
1982 * Content-Base was deleted from the specification: it was not
1983 * implemented widely, and there is no simple, safe way to introduce it
1984 * without a robust extension mechanism. In addition, it is used in a
1985 * similar, but not identical fashion in MHTML [45].
1986 *
1987 */
1988
1989
1990/**@ingroup msg_content_base
1991 * @typedef msg_generic_t msg_content_base_t;
1992 * Content-Base Header Structure.
1993 * @code
1994 * typedef struct
1995 * {
1996 * msg_common_t g_common[1]; // Common fragment info
1997 * msg_content_base_t *g_next; // Link to next header
1998 * char const *g_string; // Header value
1999 * }
2000 * @endcode
2001 */
2002
2003#define msg_content_base_d msg_generic_d
2004#define msg_content_base_e msg_generic_e
2005msg_hclass_t msg_content_base_class[] =
2006MSG_HEADER_CLASS_G(content_base, "Content-Base", "", single){{ msg_content_base_hash, msg_content_base_d, msg_content_base_e
, msg_generic_dup_xtra, msg_generic_dup_one, ((void*)0), "Content-Base"
, sizeof("Content-Base") - 1, "", (((uintptr_t)(sizeof(msg_content_base_t
)) + (sizeof(void*)) - 1) & (0 - (uintptr_t)(sizeof(void*
)))), __builtin_offsetof(msg_content_base_t, g_common), msg_kind_single
, }}
;
2007
2008#endif
2009
2010/* ====================================================================== */
2011
2012/**@ingroup msg_mime
2013 * @defgroup msg_content_transfer_encoding Content-Transfer-Encoding Header
2014 *
2015 *
2016 */
2017
2018/**@ingroup msg_content_transfer_encoding
2019 * @typedef struct msg_generic_s msg_content_transfer_encoding_t;
2020 *
2021 * The structure msg_content_transfer_encoding_t contains representation of
2022 * an @b Content-Transfer-Encoding header.
2023 *
2024 * The msg_content_transfer_encoding_t is defined as follows:
2025 * @code
2026 * typedef struct msg_generic_s
2027 * {
2028 * msg_common_t g_common[1]; // Common fragment info
2029 * msg_generic_t *g_next; // Link to next header
2030 * char const *g_string; // Header value
2031 * } msg_content_transfer_encoding_t;
2032 * @endcode
2033 */
2034
2035
2036#define msg_content_transfer_encoding_dmsg_generic_d msg_generic_d
2037#define msg_content_transfer_encoding_emsg_generic_e msg_generic_e
2038msg_hclass_t msg_content_transfer_encoding_class[] =
2039MSG_HEADER_CLASS_G(content_transfer_encoding, "Content-Transfer-Encoding",{{ msg_content_transfer_encoding_hash, msg_generic_d, msg_generic_e
, msg_generic_dup_xtra, msg_generic_dup_one, ((void*)0), "Content-Transfer-Encoding"
, sizeof("Content-Transfer-Encoding") - 1, "", (((uintptr_t)(
sizeof(msg_content_transfer_encoding_t)) + (sizeof(void*)) - 1
) & (0 - (uintptr_t)(sizeof(void*)))), __builtin_offsetof
(msg_content_transfer_encoding_t, g_common), msg_kind_single,
}}
2040 "", single){{ msg_content_transfer_encoding_hash, msg_generic_d, msg_generic_e
, msg_generic_dup_xtra, msg_generic_dup_one, ((void*)0), "Content-Transfer-Encoding"
, sizeof("Content-Transfer-Encoding") - 1, "", (((uintptr_t)(
sizeof(msg_content_transfer_encoding_t)) + (sizeof(void*)) - 1
) & (0 - (uintptr_t)(sizeof(void*)))), __builtin_offsetof
(msg_content_transfer_encoding_t, g_common), msg_kind_single,
}}
;
2041
2042/* ====================================================================== */
2043
2044/**@ingroup msg_mime
2045 * @defgroup msg_warning Warning Header
2046 *
2047 * The Warning response-header field is used to carry additional information
2048 * about the status of a response. Its syntax is defined in [S20.43]
2049 * as follows:
2050 *
2051 * @code
2052 * Warning = "Warning" HCOLON warning-value *(COMMA warning-value)
2053 * warning-value = warn-code SP warn-agent SP warn-text
2054 * warn-code = 3DIGIT
2055 * warn-agent = hostport / pseudonym
2056 * ; the name or pseudonym of the server adding
2057 * ; the Warning header, for use in debugging
2058 * warn-text = quoted-string
2059 * pseudonym = token
2060 * @endcode
2061 */
2062
2063/**@ingroup msg_warning
2064 * @typedef struct msg_warning_s msg_warning_t;
2065 *
2066 * The structure msg_warning_t contains representation of an @b
2067 * Warning header.
2068 *
2069 * The msg_warning_t is defined as follows:
2070 * @code
2071 * typedef struct msg_warning_s
2072 * {
2073 * msg_common_t w_common[1]; // Common fragment info
2074 * msg_warning_t *w_next; // Link to next Warning header
2075 * unsigned w_code; // Warning code
2076 * char const *w_host; // Hostname or pseudonym
2077 * char const *w_port; // Port number
2078 * char const *w_text; // Warning text
2079 * } msg_warning_t;
2080 * @endcode
2081 */
2082
2083issize_t msg_warning_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
2084{
2085 msg_warning_t *w;
2086 char *text;
2087
2088 for(;;) {
2089 w = (msg_warning_t *)h;
2090 while (*s == ',') /* Ignore empty entries (comma-whitespace) */
2091 *s = '\0', s += span_lws(s + 1) + 1;
2092
2093 /* Parse protocol */
2094 if (!IS_DIGIT(*s)((*s) >= '0' && (*s) <= '9'))
2095 return -1;
2096 w->w_code = strtoul(s, &s, 10);
2097 skip_lws(&s)(*(&s) += span_lws(*(&s)));
2098
2099 /* Host (and port) */
2100 if (msg_hostport_d(&s, &w->w_host, &w->w_port) == -1)
2101 return -1;
2102 if (msg_quoted_d(&s, &text) == -1)
2103 return -1;
2104 if (msg_unquote(text, text) == NULL((void*)0))
2105 return -1;
2106
2107 w->w_text = text;
2108
2109 msg_parse_next_field_without_recursion(){ msg_header_t *prev = h; msg_hclass_t *hc = prev->sh_common
->h_class; char *end = s + slen; if (*s && *s != ','
) return -1; if (msg_header_update_params(prev->sh_common,
0) < 0) return -1; while (*s == ',') *s = '\0', s += span_lws
(s + 1) + 1; if (*s == 0) return 0; h = msg_header_alloc(home
, hc, 0); if (!h) return -1; prev->sh_common->h_succ = h
, h->sh_common->h_prev = &prev->sh_common->h_succ
; prev->sh_header_next->shn_next = h; slen = end - s; }
;
2110 }
2111
2112}
2113
2114issize_t msg_warning_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
2115{
2116 msg_warning_t const *w = (msg_warning_t *)h;
2117 char const *port = w->w_port;
2118 int n;
2119 size_t m;
2120
2121 n = snprintf(b, bsiz, "%03u %s%s%s ",
2122 w->w_code, w->w_host, port ? ":" : "", port ? port : "");
2123 if (n < 0)
2124 return n;
2125
2126 m = msg_unquoted_e((size_t)n < bsiz ? b + n : NULL((void*)0), bsiz - n, w->w_text);
2127
2128 if (b && n + m < bsiz)
2129 b[n + m] = '\0';
2130
2131 return n + m;
2132}
2133
2134isize_t msg_warning_dup_xtra(msg_header_t const *h, isize_t offset)
2135{
2136 msg_warning_t const *w = (msg_warning_t *)h;
2137
2138 offset += MSG_STRING_SIZE(w->w_host)((w->w_host) ? (strlen(w->w_host) + 1) : 0);
2139 offset += MSG_STRING_SIZE(w->w_port)((w->w_port) ? (strlen(w->w_port) + 1) : 0);
2140 offset += MSG_STRING_SIZE(w->w_text)((w->w_text) ? (strlen(w->w_text) + 1) : 0);
2141
2142 return offset;
2143}
2144
2145char *msg_warning_dup_one(msg_header_t *dst,
2146 msg_header_t const *src,
2147 char *b,
2148 isize_t xtra)
2149{
2150 msg_warning_t *w = (msg_warning_t *)dst;
2151 msg_warning_t const *o = (msg_warning_t *)src;
2152 char *end = b + xtra;
2153
2154 w->w_code = o->w_code;
2155 MSG_STRING_DUP(b, w->w_host, o->w_host)(void)((o->w_host)?((b)=(char*)memccpy((void *)((w->w_host
)=(char*)b),(o->w_host),0,2147483647)) :((w->w_host)=((
void*)0)))
;
2156 MSG_STRING_DUP(b, w->w_port, o->w_port)(void)((o->w_port)?((b)=(char*)memccpy((void *)((w->w_port
)=(char*)b),(o->w_port),0,2147483647)) :((w->w_port)=((
void*)0)))
;
2157 MSG_STRING_DUP(b, w->w_text, o->w_text)(void)((o->w_text)?((b)=(char*)memccpy((void *)((w->w_text
)=(char*)b),(o->w_text),0,2147483647)) :((w->w_text)=((
void*)0)))
;
2158
2159 assert(b <= end)((void) sizeof ((b <= end) ? 1 : 0), __extension__ ({ if (
b <= end) ; else __assert_fail ("b <= end", "msg_mime.c"
, 2159, __extension__ __PRETTY_FUNCTION__); }))
; (void)end;
2160
2161 return b;
2162}
2163
2164#define msg_warning_update((void*)0) NULL((void*)0)
2165
2166msg_hclass_t msg_warning_class[] =
2167 MSG_HEADER_CLASS(msg_, warning, "Warning", "", w_common, append,{{ msg_warning_hash, msg_warning_d, msg_warning_e, msg_warning_dup_xtra
, msg_warning_dup_one, ((void*)0), "Warning", sizeof("Warning"
) - 1, "", (((uintptr_t)(sizeof(msg_warning_t)) + (sizeof(void
*)) - 1) & (0 - (uintptr_t)(sizeof(void*)))), __builtin_offsetof
(msg_warning_t, w_common), msg_kind_append, }}
2168 msg_warning, msg_warning){{ msg_warning_hash, msg_warning_d, msg_warning_e, msg_warning_dup_xtra
, msg_warning_dup_one, ((void*)0), "Warning", sizeof("Warning"
) - 1, "", (((uintptr_t)(sizeof(msg_warning_t)) + (sizeof(void
*)) - 1) & (0 - (uintptr_t)(sizeof(void*)))), __builtin_offsetof
(msg_warning_t, w_common), msg_kind_append, }}
;