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"

43
#include <stdio.h>
Pekka Pessi's avatar
Pekka Pessi committed
44 45 46
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
Pekka Pessi's avatar
Pekka Pessi committed
47
#include <limits.h>
Pekka Pessi's avatar
Pekka Pessi committed
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
#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
 *
73 74
 *
 * The parsed Accept header is stored in #sip_accept_t structure.
Pekka Pessi's avatar
Pekka Pessi committed
75 76 77 78 79
 */

/**@ingroup sip_accept
 * @typedef typedef struct sip_accept_s sip_accept_t;
 *
80 81
 * The structure #sip_accept_t contains representation of SIP
 * @Accept header.
Pekka Pessi's avatar
Pekka Pessi committed
82 83 84 85 86
 *
 * The #sip_accept_t is defined as follows:
 * @code
 * typedef struct sip_accept_s {
 *   sip_common_t        ac_common[1]; // Common fragment info
87
 *   sip_accept_t       *ac_next;      // Pointer to next @Acceptheader
Pekka Pessi's avatar
Pekka Pessi committed
88 89
 *   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
90
 *   msg_param_t const  *ac_params;    // List of parameters
91
 *   char const         *ac_q;         // Value of q parameter
Pekka Pessi's avatar
Pekka Pessi committed
92 93 94 95 96 97
 * } sip_accept_t;
 * @endcode
 */

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

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

103
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
104 105 106 107
{
  return msg_accept_d(home, h, s, slen);
}

108
issize_t sip_accept_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
Pekka Pessi's avatar
Pekka Pessi committed
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
{
  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
 *
127 128 129
 *
 * The parsed Accept-Disposition header
 * is stored in #sip_accept_disposition_t structure.
Pekka Pessi's avatar
Pekka Pessi committed
130 131 132 133 134 135
 */

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

136
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
137
{
138
  sip_accept_disposition_t *ad = (sip_accept_disposition_t *)h;
Pekka Pessi's avatar
Pekka Pessi committed
139 140 141

  assert(h);

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

146 147 148 149 150
  /* "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
151 152
    return -1;

153 154 155
  if (ad->ad_subtype) ad->ad_subtype++;

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

158
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
159 160 161 162
{
  char *b0 = b, *end = b + bsiz;
  sip_accept_disposition_t const *ad = h->sh_accept_disposition;

Pekka Pessi's avatar
Pekka Pessi committed
163 164
  MSG_STRING_E(b, end, ad->ad_type);
  MSG_PARAMS_E(b, end, ad->ad_params, flags);
Pekka Pessi's avatar
Pekka Pessi committed
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
  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
 *
187 188 189
 *
 * The parsed Accept-Encoding header
 * is stored in #sip_accept_encoding_t structure.
Pekka Pessi's avatar
Pekka Pessi committed
190 191 192 193 194
 */

/**@ingroup sip_accept_encoding
 * @typedef typedef struct msg_accept_any_s sip_accept_encoding_t;
 *
195 196
 * The structure #sip_accept_encoding_t contains representation of SIP
 * @AcceptEncoding header.
Pekka Pessi's avatar
Pekka Pessi committed
197 198 199 200 201
 *
 * The #sip_accept_encoding_t is defined as follows:
 * @code
 * typedef struct {
 *   msg_common_t        aa_common[1]; // Common fragment info
202
 *   sip_accept_encoding_t *aa_next;   // Pointer to next @AcceptEncoding header
Pekka Pessi's avatar
Pekka Pessi committed
203 204 205 206 207 208 209 210 211
 *   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
212
#define sip_accept_encoding_update   msg_accept_any_update
Pekka Pessi's avatar
Pekka Pessi committed
213 214 215 216 217

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

218
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
219
{
220
  issize_t retval = msg_accept_encoding_d(home, h, s, slen);
Pekka Pessi's avatar
Pekka Pessi committed
221 222 223

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

  return retval;
}

232
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
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
{
  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
 *
253 254 255
 *
 * The parsed Accept-Language header
 * is stored in #sip_accept_language_t structure.
Pekka Pessi's avatar
Pekka Pessi committed
256 257 258 259 260
 */

/**@ingroup sip_accept_language
 * @typedef typedef struct msg_accept_any_s sip_accept_language_t;
 *
261 262
 * The structure #sip_accept_language_t contains representation of SIP
 * @AcceptLanguage header.
Pekka Pessi's avatar
Pekka Pessi committed
263 264 265 266 267
 *
 * The #sip_accept_language_t is defined as follows:
 * @code
 * typedef struct {
 *   msg_common_t        aa_common[1]; // Common fragment info
268
 *   sip_accept_language_t *aa_next;   // Pointer to next <language>
Pekka Pessi's avatar
Pekka Pessi committed
269 270 271 272 273 274 275 276 277
 *   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
278
#define sip_accept_language_update   msg_accept_any_update
Pekka Pessi's avatar
Pekka Pessi committed
279 280 281 282 283

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

284
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
285 286 287 288 289 290 291 292 293 294 295 296
{
  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;
}

297
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
298 299 300 301 302 303 304 305 306 307
{
  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
308
 * interpreted by the UAC or UAS.  Its syntax is defined in @RFC3261
Pekka Pessi's avatar
Pekka Pessi committed
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 337 338
 * 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
339 340 341
 *
 * The parsed Content-Disposition header
 * is stored in #sip_content_disposition_t structure.
Pekka Pessi's avatar
Pekka Pessi committed
342 343
 */

344 345 346
/**@ingroup sip_content_disposition
 * @typedef struct msg_content_disposition_s sip_content_disposition_t; 
 *
347 348
 * The structure #sip_content_disposition_t contains representation of an
 * @ContentDisposition header.
349
 *
350
 * The #sip_content_disposition_t is defined as follows:
351 352 353 354 355 356 357
 * @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
358
 *   char const        *cd_handling;   // Value of @b handling parameter
359 360 361 362 363 364
 *   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
365 366
static msg_xtra_f sip_content_disposition_dup_xtra;
static msg_dup_f sip_content_disposition_dup_one;
367
#define sip_content_disposition_update msg_content_disposition_update
Pekka Pessi's avatar
Pekka Pessi committed
368 369 370 371 372

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

373 374
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
375
{
376
  return msg_content_disposition_d(home, h, s, slen);
Pekka Pessi's avatar
Pekka Pessi committed
377 378
}

379 380
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
381
{
382
  return msg_content_disposition_e(b, bsiz, h, f);
Pekka Pessi's avatar
Pekka Pessi committed
383 384 385
}

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

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


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

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

419 420 421
/**@ingroup sip_content_encoding
 * @typedef struct msg_list_s sip_content_encoding_t; 
 *
422 423
 * The structure #sip_content_encoding_t contains representation of an
 * @ContentEncoding header.
424
 *
425
 * The #sip_content_encoding_t is defined as follows:
426 427 428 429 430 431 432 433 434 435
 * @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
436
msg_hclass_t sip_content_encoding_class[] = 
437
SIP_HEADER_CLASS_LIST(content_encoding, "Content-Encoding", "e", list);
Pekka Pessi's avatar
Pekka Pessi committed
438

439
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
440
{
441
  return msg_list_d(home, h, s, slen);
Pekka Pessi's avatar
Pekka Pessi committed
442 443
}

444
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
445
{
446
  return msg_list_e(b, bsiz, h, f);
Pekka Pessi's avatar
Pekka Pessi committed
447 448 449 450 451 452
}

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

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

470 471 472
/**@ingroup sip_content_language
 * @typedef typedef struct msg_content_language_s sip_content_language_t;
 *
473 474
 * The structure #sip_content_language_t contains representation of
 * @ContentLanguage header.
475
 *
476
 * The #sip_content_language_t is defined as follows:
477 478 479 480 481 482 483 484 485
 * @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
486 487 488
msg_hclass_t sip_content_language_class[] = 
SIP_HEADER_CLASS_LIST(content_language, "Content-Language", "", list);

489
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
490 491 492 493
{
  return msg_list_d(home, h, s, slen);
}

494
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
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 521 522
{
  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
523 524
 *
 * The parsed Content-Type header is stored in #sip_content_type_t structure.
Pekka Pessi's avatar
Pekka Pessi committed
525 526 527 528 529
 */

/**@ingroup sip_content_type
 * @typedef typedef struct sip_content_type_s sip_content_type_t;
 *
530 531
 * The structure #sip_content_type_t contains representation of SIP
 * @ContentType header.
Pekka Pessi's avatar
Pekka Pessi committed
532 533 534 535 536 537 538 539
 *
 * 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
540
 *   msg_param_t const  *c_params;     // List of parameters
Pekka Pessi's avatar
Pekka Pessi committed
541 542 543 544 545 546 547 548
 * } 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;
549 550
#define sip_content_type_update NULL

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

555
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
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
{
  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;
}

576
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
577 578 579 580
{
  char *b0 = b, *end = b + bsiz;
  sip_content_type_t const *c = h->sh_content_type;

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

  return b - b0;
}

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

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

596
  return offset;
Pekka Pessi's avatar
Pekka Pessi committed
597 598
}

599
/** Duplicate one #sip_content_type_t object */ 
Pekka Pessi's avatar
Pekka Pessi committed
600 601
static
char *sip_content_type_dup_one(sip_header_t *dst, sip_header_t const *src,
602
			       char *b, isize_t xtra)
Pekka Pessi's avatar
Pekka Pessi committed
603 604 605 606 607
{
  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
608 609
  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
610 611 612
  c->c_subtype = strchr(c->c_type, '/');
  c->c_subtype++;

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

  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
629 630
 *
 * The parsed MIME-Version header is stored in #sip_mime_version_t structure.
Pekka Pessi's avatar
Pekka Pessi committed
631 632
 */

633 634 635
/**@ingroup sip_mime_version
 * @typedef struct msg_generic_s sip_mime_version_t; 
 *
636 637
 * The structure #sip_mime_version_t contains representation of an
 * @MIMEVersion header.
638
 *
639
 * The #sip_mime_version_t is defined as follows:
640 641 642 643 644 645 646 647 648 649
 * @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
650 651 652
msg_hclass_t sip_mime_version_class[] = 
SIP_HEADER_CLASS_G(mime_version, "MIME-Version", "", single);

653
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
654 655 656 657
{
  return sip_generic_d(home, h, s, slen);
}

658
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
659 660 661 662 663 664 665 666 667
{
  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
668
 * about the status of a response. Its syntax is defined in @RFC3261 as
Pekka Pessi's avatar
Pekka Pessi committed
669 670 671 672 673 674 675 676 677 678 679 680
 * 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
681 682
 *
 * The parsed Warning header is stored in #sip_warning_t structure.
Pekka Pessi's avatar
Pekka Pessi committed
683 684
 */

685 686 687
/**@ingroup sip_warning
 * @typedef struct msg_warning_s sip_warning_t; 
 *
688 689
 * The structure #sip_warning_t contains representation of an
 * @Warning header.
690
 *
691
 * The #sip_warning_t is defined as follows:
692 693 694 695
 * @code
 * typedef struct msg_warning_s
 * {
 *   msg_common_t        w_common[1];  // Common fragment info
696
 *   msg_warning_t      *w_next;       // Link to next @Warning header
697 698 699 700 701 702 703 704
 *   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
705 706
#define sip_warning_dup_xtra msg_warning_dup_xtra
#define sip_warning_dup_one msg_warning_dup_one
707
#define sip_warning_update NULL
Pekka Pessi's avatar
Pekka Pessi committed
708 709 710 711

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

712
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
713 714 715
{
  return msg_warning_d(home, h, s, slen);
}
716
issize_t sip_warning_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
Pekka Pessi's avatar
Pekka Pessi committed
717 718 719
{
  return msg_warning_e(b, bsiz, h, f);
}