sip_mime.c 22.9 KB
Newer Older
Pekka Pessi's avatar
Pekka Pessi committed
1 2 3 4 5 6 7
/*
 * This file is part of the Sofia-SIP package
 *
 * Copyright (C) 2005 Nokia Corporation.
 *
 * Contact: Pekka Pessi <pekka.pessi@nokia.com>
 *
8
 * This library is free software; you can redistribute it and/or
Pekka Pessi's avatar
Pekka Pessi committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

/**@CFILE sip_mime.c 
 *
 * MIME-related SIP headers
 *
 * @author Pekka Pessi <Pekka.Pessi@nokia.com>.
 *
 * @date Created: Tue Jun 13 02:57:51 2000 ppessi
 */

#include "config.h"

36 37 38 39 40 41 42
/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
#define MSG_PUB_T       struct sip_s
#define MSG_HDR_T       union sip_header_u

#include "sofia-sip/sip_parser.h"
#include "sofia-sip/msg_mime_protos.h"

Pekka Pessi's avatar
Pekka Pessi committed
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

/* ====================================================================== */

/**@SIP_HEADER sip_accept Accept Header
 *
 * The @b Accept request-header field can be used to specify certain media
 * types which are acceptable for the response. Its syntax is defined in
 * [H14.1, S10.6] as follows:
 * 
 * @code
 *    Accept         =  "Accept" HCOLON
 *                       [ accept-range *(COMMA accept-range) ]
 *    accept-range   =  media-range *(SEMI accept-param)
 *    media-range    =  ( "*" "/" "*"
 *                      / ( m-type SLASH "*" )
 *                      / ( m-type SLASH m-subtype )
 *                      ) *( SEMI m-parameter )
 *    accept-param   =  ("q" EQUAL qvalue) / generic-param
 *    qvalue         =  ( "0" [ "." 0*3DIGIT ] )
 *                      / ( "1" [ "." 0*3("0") ] )
 *    generic-param  =  token [ EQUAL gen-value ]
 *    gen-value      =  token / host / quoted-string
 * @endcode
 *
71 72
 *
 * The parsed Accept header is stored in #sip_accept_t structure.
Pekka Pessi's avatar
Pekka Pessi committed
73 74 75 76 77
 */

/**@ingroup sip_accept
 * @typedef typedef struct sip_accept_s sip_accept_t;
 *
78 79
 * The structure #sip_accept_t contains representation of SIP
 * @Accept header.
Pekka Pessi's avatar
Pekka Pessi committed
80 81 82 83 84
 *
 * The #sip_accept_t is defined as follows:
 * @code
 * typedef struct sip_accept_s {
 *   sip_common_t        ac_common[1]; // Common fragment info
85
 *   sip_accept_t       *ac_next;      // Pointer to next @Acceptheader
Pekka Pessi's avatar
Pekka Pessi committed
86 87
 *   char const         *ac_type;      // Pointer to type/subtype
 *   char const         *ac_subtype;   // Points after first slash in type
Pekka Pessi's avatar
Pekka Pessi committed
88
 *   msg_param_t const  *ac_params;    // List of parameters
89
 *   char const         *ac_q;         // Value of q parameter
Pekka Pessi's avatar
Pekka Pessi committed
90 91 92 93 94 95
 * } sip_accept_t;
 * @endcode
 */

#define sip_accept_dup_xtra msg_accept_dup_xtra
#define sip_accept_dup_one  msg_accept_dup_one
96
#define sip_accept_update   msg_accept_update
Pekka Pessi's avatar
Pekka Pessi committed
97 98 99 100

msg_hclass_t sip_accept_class[] = 
SIP_HEADER_CLASS(accept, "Accept", "", ac_params, apndlist, accept);

101
issize_t sip_accept_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
Pekka Pessi's avatar
Pekka Pessi committed
102 103 104 105
{
  return msg_accept_d(home, h, s, slen);
}

106
issize_t sip_accept_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
Pekka Pessi's avatar
Pekka Pessi committed
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
{
  return msg_accept_e(b, bsiz, h, flags);
}

#if SIP_HAVE_ACCEPT_DISPOSITION
/* ====================================================================== */

/**@SIP_HEADER sip_accept_disposition Accept-Disposition Header
 *
 * The Accept-Disposition header field is used to indicate what content
 * disposition types are acceptable to a client or server.  Its syntax is
 * defined in draft-lennox-sip-reg-payload-01.txt section 3.2 as follows:
 * 
 * @code
 *    Accept-Disposition = "Accept-Disposition" ":" 
 *                         #( (disposition-type | "*") *( ";" generic-param ) )
 * @endcode
 *
125 126 127
 *
 * The parsed Accept-Disposition header
 * is stored in #sip_accept_disposition_t structure.
Pekka Pessi's avatar
Pekka Pessi committed
128 129 130 131 132 133
 */

msg_hclass_t sip_accept_disposition_class[] = 
SIP_HEADER_CLASS(accept_disposition, "Accept-Disposition", "", 
		 ad_params, apndlist, accept_disposition);

134
issize_t sip_accept_disposition_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
Pekka Pessi's avatar
Pekka Pessi committed
135
{
136
  sip_accept_disposition_t *ad = (sip_accept_disposition_t *)h;
Pekka Pessi's avatar
Pekka Pessi committed
137 138 139

  assert(h);

140 141 142
  /* Ignore empty entries (comma-whitespace) */
  while (*s == ',')
    s += span_lws(s + 1) + 1;
Pekka Pessi's avatar
Pekka Pessi committed
143

144 145 146 147 148
  /* "Accept:" #(type/subtyp ; *(parameters))) */
  if (/* Parse protocol */
      sip_version_d(&s, &ad->ad_type) == -1 ||
      (ad->ad_subtype = strchr(ad->ad_type, '/')) == NULL ||
      (*s == ';' && msg_params_d(home, &s, &ad->ad_params) == -1))
Pekka Pessi's avatar
Pekka Pessi committed
149 150
    return -1;

151 152 153
  if (ad->ad_subtype) ad->ad_subtype++;

  return msg_parse_next_field(home, h, s, slen);
Pekka Pessi's avatar
Pekka Pessi committed
154 155
}

156
issize_t sip_accept_disposition_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
Pekka Pessi's avatar
Pekka Pessi committed
157 158 159 160
{
  char *b0 = b, *end = b + bsiz;
  sip_accept_disposition_t const *ad = h->sh_accept_disposition;

Pekka Pessi's avatar
Pekka Pessi committed
161 162
  MSG_STRING_E(b, end, ad->ad_type);
  MSG_PARAMS_E(b, end, ad->ad_params, flags);
Pekka Pessi's avatar
Pekka Pessi committed
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
  MSG_TERM_E(b, end);
    
  return b - b0;
}
#endif

/* ====================================================================== */

/**@SIP_HEADER sip_accept_encoding Accept-Encoding Header
 *
 * The Accept-Encoding header is similar to Accept, but restricts the
 * content-codings that are acceptable in the response.  Its syntax is
 * defined in [H14.3, S10.7] as follows:
 * 
 * @code
 *    Accept-Encoding  =  "Accept-Encoding" HCOLON
 *                         [ encoding *(COMMA encoding) ]
 *    encoding         =  codings *(SEMI accept-param)
 *    codings          =  content-coding / "*"
 *    content-coding   =  token
 * @endcode
 *
185 186 187
 *
 * The parsed Accept-Encoding header
 * is stored in #sip_accept_encoding_t structure.
Pekka Pessi's avatar
Pekka Pessi committed
188 189 190 191 192
 */

/**@ingroup sip_accept_encoding
 * @typedef typedef struct msg_accept_any_s sip_accept_encoding_t;
 *
193 194
 * The structure #sip_accept_encoding_t contains representation of SIP
 * @AcceptEncoding header.
Pekka Pessi's avatar
Pekka Pessi committed
195 196 197 198 199
 *
 * The #sip_accept_encoding_t is defined as follows:
 * @code
 * typedef struct {
 *   msg_common_t        aa_common[1]; // Common fragment info
200
 *   sip_accept_encoding_t *aa_next;   // Pointer to next @AcceptEncoding header
Pekka Pessi's avatar
Pekka Pessi committed
201 202 203 204 205 206 207 208 209
 *   char const            *aa_value;  // Encoding token
 *   msg_param_t const     *aa_params; // List of parameters
 *   char const            *aa_q;      // Value of q parameter 
 * } sip_accept_encoding_t;
 * @endcode
 */

#define sip_accept_encoding_dup_xtra msg_accept_any_dup_xtra
#define sip_accept_encoding_dup_one  msg_accept_any_dup_one
210
#define sip_accept_encoding_update   msg_accept_any_update
Pekka Pessi's avatar
Pekka Pessi committed
211 212 213 214 215

msg_hclass_t sip_accept_encoding_class[] = 
SIP_HEADER_CLASS(accept_encoding, "Accept-Encoding", "", 
		 aa_params, apndlist, accept_encoding);

216
issize_t sip_accept_encoding_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
Pekka Pessi's avatar
Pekka Pessi committed
217
{
218
  issize_t retval = msg_accept_encoding_d(home, h, s, slen);
Pekka Pessi's avatar
Pekka Pessi committed
219 220 221

  if (retval == -2) {
    /* Empty Accept-Encoding list is not an error */
222 223
    sip_accept_encoding_t *aa = (sip_accept_encoding_t *)h;
    aa->aa_value = "";
Pekka Pessi's avatar
Pekka Pessi committed
224 225 226 227 228 229
    retval = 0;
  }

  return retval;
}

230
issize_t sip_accept_encoding_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
Pekka Pessi's avatar
Pekka Pessi committed
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
{
  return msg_accept_encoding_e(b, bsiz, h, f);
}

/* ====================================================================== */

/**@SIP_HEADER sip_accept_language Accept-Language Header
 *
 * The Accept-Language header can be used to allow the client to indicate to
 * the server in which language it would prefer to receive reason phrases,
 * session descriptions or status responses carried as message bodies.  Its
 * syntax is defined in [H14.4, S10.8] as follows:
 * 
 * @code
 *    Accept-Language  =  "Accept-Language" HCOLON
 *                         [ language *(COMMA language) ]
 *    language         =  language-range *(SEMI accept-param)
 *    language-range   =  ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) / "*" )
 * @endcode
 *
251 252 253
 *
 * The parsed Accept-Language header
 * is stored in #sip_accept_language_t structure.
Pekka Pessi's avatar
Pekka Pessi committed
254 255 256 257 258
 */

/**@ingroup sip_accept_language
 * @typedef typedef struct msg_accept_any_s sip_accept_language_t;
 *
259 260
 * The structure #sip_accept_language_t contains representation of SIP
 * @AcceptLanguage header.
Pekka Pessi's avatar
Pekka Pessi committed
261 262 263 264 265
 *
 * The #sip_accept_language_t is defined as follows:
 * @code
 * typedef struct {
 *   msg_common_t        aa_common[1]; // Common fragment info
266
 *   sip_accept_language_t *aa_next;   // Pointer to next <language>
Pekka Pessi's avatar
Pekka Pessi committed
267 268 269 270 271 272 273 274 275
 *   char const            *aa_value;  // Language-range
 *   msg_param_t const     *aa_params; // List of accept-parameters
 *   char const            *aa_q;      // Value of q parameter 
 * } sip_accept_language_t;
 * @endcode
 */

#define sip_accept_language_dup_xtra msg_accept_any_dup_xtra
#define sip_accept_language_dup_one  msg_accept_any_dup_one
276
#define sip_accept_language_update   msg_accept_any_update
Pekka Pessi's avatar
Pekka Pessi committed
277 278 279 280 281

msg_hclass_t sip_accept_language_class[] = 
SIP_HEADER_CLASS(accept_language, "Accept-Language", "", 
		 aa_params, apndlist, accept_language);

282
issize_t sip_accept_language_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
Pekka Pessi's avatar
Pekka Pessi committed
283 284 285 286 287 288 289 290 291 292 293 294
{
  int retval = msg_accept_language_d(home, h, s, slen);

  if (retval == -2) {
    /* Empty Accept-Language list is not an error */
    ((sip_accept_language_t *)h)->aa_value = "";
    retval = 0;
  }

  return retval;
}

295
issize_t sip_accept_language_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
Pekka Pessi's avatar
Pekka Pessi committed
296 297 298 299 300 301 302 303 304 305
{
  return msg_accept_language_e(b, bsiz, h, f);
}

/* ====================================================================== */

/**@SIP_HEADER sip_content_disposition Content-Disposition Header
 *
 * The Content-Disposition header field describes how the message body or,
 * in the case of multipart messages, a message body part is to be
306
 * interpreted by the UAC or UAS.  Its syntax is defined in @RFC3261
Pekka Pessi's avatar
Pekka Pessi committed
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
 * as follows:
 * 
 * @code
 *    Content-Disposition   =  "Content-Disposition" HCOLON
 *                             disp-type *( SEMI disp-param )
 *    disp-type             =  "render" / "session" / "icon" / "alert"
 *                             / disp-extension-token
 *    disp-param            =  handling-param / generic-param
 *    handling-param        =  "handling" EQUAL
 *                             ( "optional" / "required"
 *                             / other-handling )
 *    other-handling        =  token
 *    disp-extension-token  =  token
 * @endcode
 * 
 * The Content-Disposition header was extended by
 * draft-lennox-sip-reg-payload-01.txt section 3.1 as follows:
 *
 * @code
 *    Content-Disposition      =  "Content-Disposition" ":"
 *                                disposition-type *( ";" disposition-param )
 *    disposition-type         =  "script" | "sip-cgi" | token
 *    disposition-param        =  action-param
 *                             |  modification-date-param
 *                             |  generic-param
 *    action-param             =  "action" "=" action-value
 *    action-value             =  "store" | "remove" | token
 *    modification-date-param  =  "modification-date" "=" quoted-date-time
 *    quoted-date-time         =  <"> SIP-date <">
 * @endcode
337 338 339
 *
 * The parsed Content-Disposition header
 * is stored in #sip_content_disposition_t structure.
Pekka Pessi's avatar
Pekka Pessi committed
340 341
 */

342 343 344
/**@ingroup sip_content_disposition
 * @typedef struct msg_content_disposition_s sip_content_disposition_t; 
 *
345 346
 * The structure #sip_content_disposition_t contains representation of an
 * @ContentDisposition header.
347
 *
348
 * The #sip_content_disposition_t is defined as follows:
349 350 351 352 353 354 355
 * @code
 * typedef struct msg_content_disposition_s
 * {
 *   msg_common_t       cd_common[1];  // Common fragment info
 *   msg_error_t       *cd_next;       // Link to next (dummy)
 *   char const        *cd_type;       // Disposition type
 *   msg_param_t const *cd_params;     // List of parameters
356
 *   char const        *cd_handling;   // Value of @b handling parameter
357 358 359 360 361 362
 *   unsigned           cd_required:1; // True if handling=required
 *   unsigned           cd_optional:1; // True if handling=optional
 * } sip_content_disposition_t;
 * @endcode
 */

Pekka Pessi's avatar
Pekka Pessi committed
363 364
static msg_xtra_f sip_content_disposition_dup_xtra;
static msg_dup_f sip_content_disposition_dup_one;
365
#define sip_content_disposition_update msg_content_disposition_update
Pekka Pessi's avatar
Pekka Pessi committed
366 367 368 369 370

msg_hclass_t sip_content_disposition_class[] = 
SIP_HEADER_CLASS(content_disposition, "Content-Disposition", "", cd_params,
		 single, content_disposition);

371 372
issize_t sip_content_disposition_d(su_home_t *home, sip_header_t *h, 
				   char *s, isize_t slen)
Pekka Pessi's avatar
Pekka Pessi committed
373
{
374
  return msg_content_disposition_d(home, h, s, slen);
Pekka Pessi's avatar
Pekka Pessi committed
375 376
}

377 378
issize_t sip_content_disposition_e(char b[], isize_t bsiz,
				   sip_header_t const *h, int f)
Pekka Pessi's avatar
Pekka Pessi committed
379
{
380
  return msg_content_disposition_e(b, bsiz, h, f);
Pekka Pessi's avatar
Pekka Pessi committed
381 382 383
}

static
384
isize_t sip_content_disposition_dup_xtra(sip_header_t const *h, isize_t offset)
Pekka Pessi's avatar
Pekka Pessi committed
385
{
386
  return msg_content_disposition_dup_xtra(h, offset);
Pekka Pessi's avatar
Pekka Pessi committed
387 388
}

389
/** Duplicate one #sip_content_disposition_t object */ 
Pekka Pessi's avatar
Pekka Pessi committed
390 391
static
char *sip_content_disposition_dup_one(sip_header_t *dst, 
392
				      sip_header_t const *src,
393
				      char *b, isize_t xtra)
Pekka Pessi's avatar
Pekka Pessi committed
394
{
395
  return msg_content_disposition_dup_one(dst, src, b, xtra);
Pekka Pessi's avatar
Pekka Pessi committed
396 397 398 399 400 401 402 403
}


/* ====================================================================== */

/**@SIP_HEADER sip_content_encoding Content-Encoding Header
 *
 * The Content-Encoding header indicates what additional content codings
404
 * have been applied to the entity-body.  Its syntax is defined in @RFC3261
Pekka Pessi's avatar
Pekka Pessi committed
405 406 407 408 409 410 411
 * as follows:
 * 
 * @code
 * Content-Encoding  =  ( "Content-Encoding" / "e" ) HCOLON
 *                      content-coding *(COMMA content-coding)
 * content-coding    =  token
 * @endcode
412 413 414
 *
 * The parsed Content-Encoding header
 * is stored in #sip_content_encoding_t structure.
Pekka Pessi's avatar
Pekka Pessi committed
415 416
 */

417 418 419
/**@ingroup sip_content_encoding
 * @typedef struct msg_list_s sip_content_encoding_t; 
 *
420 421
 * The structure #sip_content_encoding_t contains representation of an
 * @ContentEncoding header.
422
 *
423
 * The #sip_content_encoding_t is defined as follows:
424 425 426 427 428 429 430 431 432 433
 * @code
 * typedef struct msg_list_s
 * {
 *   msg_common_t       k_common[1];  // Common fragment info
 *   msg_list_t        *k_next;	      // Link to next header
 *   msg_param_t       *k_items;      // List of items
 * } sip_content_encoding_t;
 * @endcode
 */

Pekka Pessi's avatar
Pekka Pessi committed
434
msg_hclass_t sip_content_encoding_class[] = 
435
SIP_HEADER_CLASS_LIST(content_encoding, "Content-Encoding", "e", list);
Pekka Pessi's avatar
Pekka Pessi committed
436

437
issize_t sip_content_encoding_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
Pekka Pessi's avatar
Pekka Pessi committed
438
{
439
  return msg_list_d(home, h, s, slen);
Pekka Pessi's avatar
Pekka Pessi committed
440 441
}

442
issize_t sip_content_encoding_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
Pekka Pessi's avatar
Pekka Pessi committed
443
{
444
  return msg_list_e(b, bsiz, h, f);
Pekka Pessi's avatar
Pekka Pessi committed
445 446 447 448 449 450
}

/* ====================================================================== */

/**@SIP_HEADER sip_content_language Content-Language Header
 *
451
 * The Content-Language header @RFC2616 section 14.12 describes the natural language(s) of
Pekka Pessi's avatar
Pekka Pessi committed
452 453
 * the intended audience for the enclosed entity. Note that this might not
 * be equivalent to all the languages used within the entity-body. Its
454
 * syntax is defined in @RFC3261 as follows:
Pekka Pessi's avatar
Pekka Pessi committed
455 456 457 458 459 460 461 462
 * 
 * @code
 *    Content-Language  =  "Content-Language" HCOLON
 *                         language-tag *(COMMA language-tag)
 *    language-tag      =  primary-tag *( "-" subtag )
 *    primary-tag       =  1*8ALPHA
 *    subtag            =  1*8ALPHA
 * @endcode
463 464 465
 *
 * The parsed Content-Language header
 * is stored in #sip_content_language_t structure.
Pekka Pessi's avatar
Pekka Pessi committed
466 467
 */

468 469 470
/**@ingroup sip_content_language
 * @typedef typedef struct msg_content_language_s sip_content_language_t;
 *
471 472
 * The structure #sip_content_language_t contains representation of
 * @ContentLanguage header.
473
 *
474
 * The #sip_content_language_t is defined as follows:
475 476 477 478 479 480 481 482 483
 * @code
 * typedef struct {
 *   msg_common_t            k_common[1]; // Common fragment info
 *   msg_content_language_t *k_next;      // (Content-Encoding header)
 *   msg_param_t            *k_items;     // List of languages
 * } sip_content_language_t;
 * @endcode
 */

Pekka Pessi's avatar
Pekka Pessi committed
484 485 486
msg_hclass_t sip_content_language_class[] = 
SIP_HEADER_CLASS_LIST(content_language, "Content-Language", "", list);

487
issize_t sip_content_language_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
Pekka Pessi's avatar
Pekka Pessi committed
488 489 490 491
{
  return msg_list_d(home, h, s, slen);
}

492
issize_t sip_content_language_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
Pekka Pessi's avatar
Pekka Pessi committed
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520
{
  return msg_list_e(b, bsiz, h, f);
}

/* ====================================================================== */

/**@SIP_HEADER sip_content_type Content-Type Header
 *
 * The Content-Type header indicates the media type of the message-body sent
 * to the recipient.  Its syntax is defined in [H3.7, S] as
 * follows:
 * 
 * @code
 * Content-Type     =  ( "Content-Type" / "c" ) HCOLON media-type
 * media-type       =  m-type SLASH m-subtype *(SEMI m-parameter)
 * m-type           =  discrete-type / composite-type
 * discrete-type    =  "text" / "image" / "audio" / "video"
 *                     / "application" / extension-token
 * composite-type   =  "message" / "multipart" / extension-token
 * extension-token  =  ietf-token / x-token
 * ietf-token       =  token
 * x-token          =  "x-" token
 * m-subtype        =  extension-token / iana-token
 * iana-token       =  token
 * m-parameter      =  m-attribute EQUAL m-value
 * m-attribute      =  token
 * m-value          =  token / quoted-string
 * @endcode
521 522
 *
 * The parsed Content-Type header is stored in #sip_content_type_t structure.
Pekka Pessi's avatar
Pekka Pessi committed
523 524 525 526 527
 */

/**@ingroup sip_content_type
 * @typedef typedef struct sip_content_type_s sip_content_type_t;
 *
528 529
 * The structure #sip_content_type_t contains representation of SIP
 * @ContentType header.
Pekka Pessi's avatar
Pekka Pessi committed
530 531 532 533 534 535 536 537
 *
 * The #sip_content_type_t is defined as follows:
 * @code
 * typedef struct sip_content_type_s {
 *   sip_common_t        c_common[1];  // Common fragment info
 *   sip_unknown_t      *c_next;       // Dummy link to next
 *   char const         *c_type;       // Pointer to type/subtype
 *   char const         *c_subtype;    // Points after first slash in type
Pekka Pessi's avatar
Pekka Pessi committed
538
 *   msg_param_t const  *c_params;     // List of parameters
Pekka Pessi's avatar
Pekka Pessi committed
539 540 541 542 543 544 545 546
 * } sip_content_type_t;
 * @endcode
 *
 * The whitespace in the @a c_type is always removed when parsing.
 */

static msg_xtra_f sip_content_type_dup_xtra;
static msg_dup_f sip_content_type_dup_one;
547 548
#define sip_content_type_update NULL

Pekka Pessi's avatar
Pekka Pessi committed
549 550 551 552
msg_hclass_t sip_content_type_class[] = 
SIP_HEADER_CLASS(content_type, "Content-Type", "c", c_params, 
		 single, content_type);

553
issize_t sip_content_type_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
Pekka Pessi's avatar
Pekka Pessi committed
554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573
{
  sip_content_type_t *c;

  assert(h);

  c = h->sh_content_type;

  /* "Content-type:" type/subtyp *(; parameter))) */
  if (/* Parse protocol */
      sip_version_d(&s, &c->c_type) == -1 || /* compacts token / token */
      (c->c_subtype = strchr(c->c_type, '/')) == NULL ||
      (*s == ';' && msg_params_d(home, &s, &c->c_params) == -1) ||
      (*s != '\0'))
    return -1;

  c->c_subtype++;

  return 0;
}

574
issize_t sip_content_type_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
Pekka Pessi's avatar
Pekka Pessi committed
575 576 577 578
{
  char *b0 = b, *end = b + bsiz;
  sip_content_type_t const *c = h->sh_content_type;

Pekka Pessi's avatar
Pekka Pessi committed
579 580
  MSG_STRING_E(b, end, c->c_type);
  MSG_PARAMS_E(b, end, c->c_params, flags);
Pekka Pessi's avatar
Pekka Pessi committed
581 582 583 584 585 586
  MSG_TERM_E(b, end);

  return b - b0;
}

static
587
isize_t sip_content_type_dup_xtra(sip_header_t const *h, isize_t offset)
Pekka Pessi's avatar
Pekka Pessi committed
588 589 590
{
  sip_content_type_t const *c = h->sh_content_type;

591 592
  MSG_PARAMS_SIZE(offset, c->c_params);
  offset += MSG_STRING_SIZE(c->c_type);
Pekka Pessi's avatar
Pekka Pessi committed
593

594
  return offset;
Pekka Pessi's avatar
Pekka Pessi committed
595 596
}

597
/** Duplicate one #sip_content_type_t object */ 
Pekka Pessi's avatar
Pekka Pessi committed
598 599
static
char *sip_content_type_dup_one(sip_header_t *dst, sip_header_t const *src,
600
			       char *b, isize_t xtra)
Pekka Pessi's avatar
Pekka Pessi committed
601 602 603 604 605
{
  sip_content_type_t *c = dst->sh_content_type;
  sip_content_type_t const *o = src->sh_content_type;
  char *end = b + xtra;

Pekka Pessi's avatar
Pekka Pessi committed
606 607
  b = msg_params_dup(&c->c_params, o->c_params, b, xtra);
  MSG_STRING_DUP(b, c->c_type, o->c_type);
Pekka Pessi's avatar
Pekka Pessi committed
608 609 610
  c->c_subtype = strchr(c->c_type, '/');
  c->c_subtype++;

611
  assert(b <= end); (void)end;
Pekka Pessi's avatar
Pekka Pessi committed
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626

  return b;
}

/* ====================================================================== */

/**@SIP_HEADER sip_mime_version MIME-Version Header
 *
 * MIME-Version header indicates what version of the MIME protocol was used
 * to construct the message.  Its syntax is defined in [H19.4.1, S10.28]
 * as follows:
 * 
 * @code
 *    MIME-Version  =  "MIME-Version" HCOLON 1*DIGIT "." 1*DIGIT
 * @endcode
627 628
 *
 * The parsed MIME-Version header is stored in #sip_mime_version_t structure.
Pekka Pessi's avatar
Pekka Pessi committed
629 630
 */

631 632 633
/**@ingroup sip_mime_version
 * @typedef struct msg_generic_s sip_mime_version_t; 
 *
634 635
 * The structure #sip_mime_version_t contains representation of an
 * @MIMEVersion header.
636
 *
637
 * The #sip_mime_version_t is defined as follows:
638 639 640 641 642 643 644 645 646 647
 * @code
 * typedef struct msg_generic_s
 * {
 *   msg_common_t   g_common[1];    // Common fragment info
 *   msg_generic_t *g_next;	    // Link to next header
 *   char const    *g_string;	    // Header value
 * } sip_mime_version_t;
 * @endcode
 */

Pekka Pessi's avatar
Pekka Pessi committed
648 649 650
msg_hclass_t sip_mime_version_class[] = 
SIP_HEADER_CLASS_G(mime_version, "MIME-Version", "", single);

651
issize_t sip_mime_version_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
Pekka Pessi's avatar
Pekka Pessi committed
652 653 654 655
{
  return sip_generic_d(home, h, s, slen);
}

656
issize_t sip_mime_version_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
Pekka Pessi's avatar
Pekka Pessi committed
657 658 659 660 661 662 663 664 665
{
  return sip_generic_e(b, bsiz, h, f);
}

/* ====================================================================== */

/**@SIP_HEADER sip_warning Warning Header
 * 
 * The Warning response-header field is used to carry additional information
666
 * about the status of a response. Its syntax is defined in @RFC3261 as
Pekka Pessi's avatar
Pekka Pessi committed
667 668 669 670 671 672 673 674 675 676 677 678
 * follows:
 * 
 * @code
 *    Warning        =  "Warning" HCOLON warning-value *(COMMA warning-value)
 *    warning-value  =  warn-code SP warn-agent SP warn-text
 *    warn-code      =  3DIGIT
 *    warn-agent     =  hostport / pseudonym
 *                      ;  the name or pseudonym of the server adding
 *                      ;  the Warning header, for use in debugging
 *    warn-text      =  quoted-string
 *    pseudonym      =  token
 * @endcode
679 680
 *
 * The parsed Warning header is stored in #sip_warning_t structure.
Pekka Pessi's avatar
Pekka Pessi committed
681 682
 */

683 684 685
/**@ingroup sip_warning
 * @typedef struct msg_warning_s sip_warning_t; 
 *
686 687
 * The structure #sip_warning_t contains representation of an
 * @Warning header.
688
 *
689
 * The #sip_warning_t is defined as follows:
690 691 692 693
 * @code
 * typedef struct msg_warning_s
 * {
 *   msg_common_t        w_common[1];  // Common fragment info
694
 *   msg_warning_t      *w_next;       // Link to next @Warning header
695 696 697 698 699 700 701 702
 *   unsigned            w_code;       // Warning code
 *   char const         *w_host;       // Hostname or pseudonym
 *   char const         *w_port;       // Port number
 *   char const         *w_text;       // Warning text
 * } sip_warning_t;
 * @endcode
 */

Pekka Pessi's avatar
Pekka Pessi committed
703 704
#define sip_warning_dup_xtra msg_warning_dup_xtra
#define sip_warning_dup_one msg_warning_dup_one
705
#define sip_warning_update NULL
Pekka Pessi's avatar
Pekka Pessi committed
706 707 708 709

msg_hclass_t sip_warning_class[] = 
SIP_HEADER_CLASS(warning, "Warning", "", w_common, append, warning);

710
issize_t sip_warning_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
Pekka Pessi's avatar
Pekka Pessi committed
711 712 713
{
  return msg_warning_d(home, h, s, slen);
}
714
issize_t sip_warning_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
Pekka Pessi's avatar
Pekka Pessi committed
715 716 717
{
  return msg_warning_e(b, bsiz, h, f);
}