sip_event.c 16.1 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
 * 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_event.c
 * @brief Event SIP headers.
 *
28 29
 * Implementation of header classes for event-related SIP headers @Event,
 * @AllowEvents, and @SubscriptionState.
Pekka Pessi's avatar
Pekka Pessi committed
30 31 32 33 34 35 36 37
 *
 * @author Pekka Pessi <Pekka.Pessi@nokia.com>.
 *
 * @date Created: Thu Sep 13 21:24:15 EEST 2001 ppessi
 */

#include "config.h"

38 39 40 41 42 43
/* 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"

44
#include <stdio.h>
Pekka Pessi's avatar
Pekka Pessi committed
45 46 47
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
Pekka Pessi's avatar
Pekka Pessi committed
48 49
#include <limits.h>

Pekka Pessi's avatar
Pekka Pessi committed
50 51 52 53 54 55 56
#include <assert.h>

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

/**@SIP_HEADER sip_event Event Header
 *
 * The Event header is used to indicate the which event or class of events
57 58
 * the message contains or subscribes. Its syntax is defined in @RFC3265 as
 * follows:
59
 *
Pekka Pessi's avatar
Pekka Pessi committed
60 61 62 63 64 65 66 67 68 69
 * @code
 *   Event             =  ( "Event" / "o" ) HCOLON event-type
 *                         *( SEMI event-param )
 *   event-type        =  event-package *( "." event-template )
 *   event-package     =  token-nodot
 *   event-template    =  token-nodot
 *   token-nodot       =  1*( alphanum / "-"  / "!" / "%" / "*"
 *                             / "_" / "+" / "`" / "'" / "~" )
 *   event-param      =  generic-param / ( "id" EQUAL token )
 * @endcode
70 71
 *
 * The parsed Event header is stored in #sip_event_t structure.
72 73 74
 */

/**@ingroup sip_event
75
 * @typedef struct sip_event_s sip_event_t;
76
 *
77
 * The structure #sip_event_t contains representation of an @Event header.
Pekka Pessi's avatar
Pekka Pessi committed
78
 *
79
 * The #sip_event_t is defined as follows:
80 81 82 83 84 85
 * @code
 * typedef struct sip_event_s
 * {
 *   sip_common_t        o_common;	    // Common fragment info
 *   sip_error_t        *o_next;	    // Link to next (dummy)
 *   char const *        o_type;	    // Event type
Pekka Pessi's avatar
Pekka Pessi committed
86
 *   msg_param_t const  *o_params;	    // List of parameters
87
 *   char const         *o_id;	    	    // Event ID
88 89
 * } sip_event_t;
 * @endcode
Pekka Pessi's avatar
Pekka Pessi committed
90 91 92 93
 */

static msg_xtra_f sip_event_dup_xtra;
static msg_dup_f sip_event_dup_one;
94 95
static msg_update_f sip_event_update;

96
msg_hclass_t sip_event_class[] =
Pekka Pessi's avatar
Pekka Pessi committed
97 98
SIP_HEADER_CLASS(event, "Event", "o", o_params, single, event);

99
issize_t sip_event_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
Pekka Pessi's avatar
Pekka Pessi committed
100 101
{
  sip_event_t *o = h->sh_event;
102
  size_t n;
Pekka Pessi's avatar
Pekka Pessi committed
103 104 105 106 107 108 109

  n = span_token(s); if (n == 0) return -1;
  o->o_type = s; s += n;
  while (IS_LWS(*s)) { *s++ = '\0'; }
  if (*s == ';') {
    if (msg_params_d(home, &s, &o->o_params) < 0 || *s)
      return -1;
110
    msg_header_update_params(o->o_common, 0);
Pekka Pessi's avatar
Pekka Pessi committed
111 112 113 114
  }
  return 0;
}

115
issize_t sip_event_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
Pekka Pessi's avatar
Pekka Pessi committed
116 117 118 119 120
{
  char *end = b + bsiz, *b0 = b;
  sip_event_t const *o = h->sh_event;

  assert(sip_is_event(h));
Pekka Pessi's avatar
Pekka Pessi committed
121 122
  MSG_STRING_E(b, end, o->o_type);
  MSG_PARAMS_E(b, end, o->o_params, flags);
Pekka Pessi's avatar
Pekka Pessi committed
123 124 125 126

  return b - b0;
}

127
isize_t sip_event_dup_xtra(sip_header_t const *h, isize_t offset)
Pekka Pessi's avatar
Pekka Pessi committed
128 129 130
{
  sip_event_t const *o = h->sh_event;

Pekka Pessi's avatar
Pekka Pessi committed
131 132
  MSG_PARAMS_SIZE(offset, o->o_params);
  offset += MSG_STRING_SIZE(o->o_type);
Pekka Pessi's avatar
Pekka Pessi committed
133 134 135 136

  return offset;
}

137
/** Duplicate one #sip_event_t object */
Pekka Pessi's avatar
Pekka Pessi committed
138
char *sip_event_dup_one(sip_header_t *dst, sip_header_t const *src,
139
			char *b, isize_t xtra)
Pekka Pessi's avatar
Pekka Pessi committed
140 141 142 143 144
{
  sip_event_t *o_dst = dst->sh_event;
  sip_event_t const *o_src = src->sh_event;

  char *end = b + xtra;
Pekka Pessi's avatar
Pekka Pessi committed
145 146
  b = msg_params_dup(&o_dst->o_params, o_src->o_params, b, xtra);
  MSG_STRING_DUP(b, o_dst->o_type, o_src->o_type);
147
  assert(b <= end); (void)end;
Pekka Pessi's avatar
Pekka Pessi committed
148 149 150 151

  return b;
}

152
/** Update parameters in @Event header. */
153
static int sip_event_update(msg_common_t *h,
154
			   char const *name, isize_t namelen,
155
			   char const *value)
Pekka Pessi's avatar
Pekka Pessi committed
156
{
157 158 159 160 161
  sip_event_t *o = (sip_event_t *)h;

  if (name == NULL) {
    o->o_id = NULL;
  }
162
  else if (namelen == strlen("id") && su_casenmatch(name, "id", namelen)) {
163 164
    o->o_id = value;
  }
Pekka Pessi's avatar
Pekka Pessi committed
165

166
  return 0;
Pekka Pessi's avatar
Pekka Pessi committed
167 168 169 170
}

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

171
/**@SIP_HEADER sip_allow_events Allow-Events Header
Pekka Pessi's avatar
Pekka Pessi committed
172
 *
173
 * The Allow-Events header is used to indicate which events or classes of
174 175
 * events the notifier supports. Its syntax is defined in @RFC3265 as
 * follows:
176
 *
Pekka Pessi's avatar
Pekka Pessi committed
177
 * @code
178
 *    Allow-Events = ( "Allow-Events" / "u" ) HCOLON event-type
179
 *                                           *(COMMA event-type)
Pekka Pessi's avatar
Pekka Pessi committed
180 181
 * @endcode
 *
182
 * The parsed Allow-Events header is stored in #sip_allow_events_t structure.
183 184 185 186 187 188 189
 *
 * Note that the event name is case-sensitive. The event "Presence" is
 * different from "presence". However, it is very unwise to use such event
 * names.
 *
 * @sa @Event, @RFC3265, msg_header_find_item(), msg_header_replace_item(),
 * msg_header_remove_item()
Pekka Pessi's avatar
Pekka Pessi committed
190 191
 */

192
/**@ingroup sip_allow_events
193
 * @typedef struct msg_list_s sip_allow_events_t;
194
 *
195
 * The structure #sip_allow_events_t contains representation of an
196
 * @AllowEvents header.
197
 *
198
 * The #sip_allow_events_t is defined as follows:
199 200 201 202 203 204 205 206 207 208
 * @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_allow_events_t;
 * @endcode
 */

209
msg_hclass_t sip_allow_events_class[] =
Pekka Pessi's avatar
Pekka Pessi committed
210 211
SIP_HEADER_CLASS_LIST(allow_events, "Allow-Events", "u", list);

212
issize_t sip_allow_events_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
Pekka Pessi's avatar
Pekka Pessi committed
213 214 215 216
{
  return msg_list_d(home, h, s, slen);
}

217
issize_t sip_allow_events_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
Pekka Pessi's avatar
Pekka Pessi committed
218 219 220 221 222
{
  assert(sip_is_allow_events(h));
  return msg_list_e(b, bsiz, h, f);
}

223
/** Append an event to a @AllowEvents header.
224 225 226
 *
 * @note This function @b does @b duplicate @p event.
 *
227
 * @deprecated Use msg_header_replace_item() directly.
228
 */
229 230
int sip_allow_events_add(su_home_t *home,
			 sip_allow_events_t *ae,
231
			 char const *event)
Pekka Pessi's avatar
Pekka Pessi committed
232
{
233 234
  event = su_strdup(home, event);
  if (!event)
Pekka Pessi's avatar
Pekka Pessi committed
235
    return -1;
236
  return msg_header_replace_item(home, ae->k_common, event);
Pekka Pessi's avatar
Pekka Pessi committed
237 238 239 240 241 242
}

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

/**@SIP_HEADER sip_subscription_state Subscription-State Header
 *
243 244 245
 * The Subscription-State header is used to indicate in which state a
 * subscription is. Its syntax is defined in @RFC3265 section 4.2.4 as
 * follows:
246
 *
Pekka Pessi's avatar
Pekka Pessi committed
247
 * @code
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
 *    Subscription-State   = "Subscription-State" HCOLON substate-value
 *                           *( SEMI subexp-params )
 *    substate-value       = "active" / "pending" / "terminated"
 *                           / extension-substate
 *    extension-substate   = token
 *    subexp-params        =   ("reason" EQUAL event-reason-value)
 *                           / ("expires" EQUAL delta-seconds)
 *                           / ("retry-after" EQUAL delta-seconds)
 *                           / generic-param
 *    event-reason-value   =   "deactivated"
 *                           / "probation"
 *                           / "rejected"
 *                           / "timeout"
 *                           / "giveup"
 *                           / "noresource"
 *                           / event-reason-extension
 *    event-reason-extension = token
Pekka Pessi's avatar
Pekka Pessi committed
265
 * @endcode
266 267 268
 *
 * The parsed Subscription-State header
 * is stored in #sip_subscription_state_t structure.
269 270 271 272 273
 */

/**@ingroup sip_subscription_state
 * @typedef struct sip_subscription_state_s sip_subscription_state_t;
 *
274
 * The structure #sip_subscription_state_t contains representation of an
275
 * @SubscriptionState header.
Pekka Pessi's avatar
Pekka Pessi committed
276
 *
277
 * The #sip_subscription_state_t is defined as follows:
Pekka Pessi's avatar
Pekka Pessi committed
278 279 280
 * @code
 * typedef struct sip_subscription_state_s
 * {
281 282 283
 *   sip_common_t       ss_common[1];
 *   sip_unknown_t     *ss_next;
 *   // Subscription state: "pending", "active" or "terminated"
284
 *   char const        *ss_substate;
285
 *   msg_param_t const *ss_params;      // List of parameters
286
 *   char const        *ss_reason;      // Reason of terminating
287 288
 *   char const        *ss_expires;     // Subscription lifetime in seconds
 *   char const        *ss_retry_after; // Value of retry-after parameter
Pekka Pessi's avatar
Pekka Pessi committed
289 290 291 292 293 294
 * } sip_subscription_state_t;
 * @endcode
 */

static msg_xtra_f sip_subscription_state_dup_xtra;
static msg_dup_f sip_subscription_state_dup_one;
295
static msg_update_f sip_subscription_state_update;
Pekka Pessi's avatar
Pekka Pessi committed
296

297 298 299
msg_hclass_t sip_subscription_state_class[] =
SIP_HEADER_CLASS(subscription_state, "Subscription-State", "",
		 ss_params, single,
Pekka Pessi's avatar
Pekka Pessi committed
300 301
		 subscription_state);

302
issize_t sip_subscription_state_d(su_home_t *home, sip_header_t *h,
303
				  char *s, isize_t slen)
Pekka Pessi's avatar
Pekka Pessi committed
304 305 306
{
   sip_subscription_state_t *ss = h->sh_subscription_state;
   ss->ss_substate = s;
307

308
   s += span_token(s); /* forwards the pointer to the end of substate-value */
Pekka Pessi's avatar
Pekka Pessi committed
309 310
   if (s == ss->ss_substate)
     return -1;
311
   if (IS_LWS(*s)) {
312 313
     *s = '\0'; s += span_lws(s + 1) + 1;
   }
314

Pekka Pessi's avatar
Pekka Pessi committed
315
   /* check if parameters are present and if so parse them */
316 317 318 319 320 321
   if (*s  == ';') {
     if ( msg_params_d(home, &s, &ss->ss_params) < 0)
       return -1;
     if (msg_header_update_params(ss->ss_common, 0) < 0)
       return -1;
   }
Pekka Pessi's avatar
Pekka Pessi committed
322 323 324 325

   return 0;
}

326
issize_t sip_subscription_state_e(char b[], isize_t bsiz, sip_header_t const *h, int flags)
Pekka Pessi's avatar
Pekka Pessi committed
327 328 329
{
  char *end = b + bsiz, *b0 = b;
  sip_subscription_state_t const *ss = h->sh_subscription_state;
330

Pekka Pessi's avatar
Pekka Pessi committed
331
  assert(sip_is_subscription_state(h));
332

Pekka Pessi's avatar
Pekka Pessi committed
333
  MSG_STRING_E(b, end, ss->ss_substate);
334
  MSG_PARAMS_E(b, end, ss->ss_params, flags);
Pekka Pessi's avatar
Pekka Pessi committed
335

336
  return b - b0;
Pekka Pessi's avatar
Pekka Pessi committed
337 338
}

339
isize_t sip_subscription_state_dup_xtra(sip_header_t const *h, isize_t offset)
Pekka Pessi's avatar
Pekka Pessi committed
340 341
{
   sip_subscription_state_t const *ss = h->sh_subscription_state;
342

Pekka Pessi's avatar
Pekka Pessi committed
343
   /* Calculates memory size occupied */
Pekka Pessi's avatar
Pekka Pessi committed
344 345
   MSG_PARAMS_SIZE(offset, ss->ss_params);
   offset += MSG_STRING_SIZE(ss->ss_substate);
346 347

   return offset;
Pekka Pessi's avatar
Pekka Pessi committed
348 349
}

350
/** Duplicate one #sip_subscription_state_t object */
Pekka Pessi's avatar
Pekka Pessi committed
351
char *sip_subscription_state_dup_one(sip_header_t *dst, sip_header_t const *src,
352
				     char *b, isize_t xtra)
Pekka Pessi's avatar
Pekka Pessi committed
353 354 355 356
{
  sip_subscription_state_t *ss_dst = dst->sh_subscription_state;
  sip_subscription_state_t const *ss_src = src->sh_subscription_state;
  char *end = b + xtra;
357

Pekka Pessi's avatar
Pekka Pessi committed
358 359
  b = msg_params_dup(&ss_dst->ss_params, ss_src->ss_params, b, xtra);
  MSG_STRING_DUP(b, ss_dst->ss_substate, ss_src->ss_substate);
360
  assert(b <= end); (void)end;
Pekka Pessi's avatar
Pekka Pessi committed
361

362
  return b;
Pekka Pessi's avatar
Pekka Pessi committed
363 364
}

365
static int sip_subscription_state_update(msg_common_t *h,
366
					 char const *name, isize_t namelen,
367
					 char const *value)
Pekka Pessi's avatar
Pekka Pessi committed
368
{
369
  sip_subscription_state_t *ss = (sip_subscription_state_t *)h;
Pekka Pessi's avatar
Pekka Pessi committed
370

371 372 373 374 375
  if (name == NULL) {
    ss->ss_reason = NULL;
    ss->ss_retry_after = NULL;
    ss->ss_expires = NULL;
  }
376
#define MATCH(s) (namelen == strlen(#s) && su_casenmatch(name, #s, strlen(#s)))
377 378 379 380 381 382 383 384 385 386 387 388 389 390

  else if (MATCH(reason)) {
    ss->ss_reason = value;
  }
  else if (MATCH(retry-after)) {
    ss->ss_retry_after = value;
  }
  else if (MATCH(expires)) {
    ss->ss_expires = value;
  }

#undef MATCH

  return 0;
Pekka Pessi's avatar
Pekka Pessi committed
391 392 393 394 395 396 397 398 399 400 401
}

#if 0				/* More dead headers */

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

/**@SIP_HEADER sip_publication Publication Header
 *
 * The Publication header is used to indicate the which publication or class
 * of publications the message contains. Its syntax is defined
 * in (draft-niemi-simple-publish-00.txt) as follows:
402
 *
Pekka Pessi's avatar
Pekka Pessi committed
403 404 405 406 407 408 409 410 411 412 413
 * @code
 *   Publication          =  ( "Publication") HCOLON publish-package
 *                         *( SEMI publish-param )
 *   publish-package      =  token-nodot
 *   token-nodot          =  1*( alphanum / "-"  / "!" / "%" / "*"
 *                               / "_" / "+" / "`" / "'" / "~" )
 *   publish-param        = generic-param / pstream / ptype
 *   pstream              = "stream" EQUAL token
 *   ptype                = "type" EQUAL token
 * @endcode
 *
414 415
 *
 * The parsed Publication header is stored in #sip_publication_t structure.
Pekka Pessi's avatar
Pekka Pessi committed
416 417 418 419 420
 */

/**@ingroup sip_publication
 * @brief Structure for Publication header.
 */
421
struct sip_publication_s
Pekka Pessi's avatar
Pekka Pessi committed
422 423 424 425
{
  sip_common_t        pub_common;	    /**< Common fragment info */
  sip_error_t        *pub_next;	            /**< Link to next (dummy) */
  char const *        pub_package;          /**< Publication packaage */
Pekka Pessi's avatar
Pekka Pessi committed
426 427 428
  msg_param_t const  *pub_params;	    /**< List of parameters */
  msg_param_t         pub_type; 	    /**< Publication type */
  msg_param_t         pub_stream;	    /**< Publication stream */
Pekka Pessi's avatar
Pekka Pessi committed
429 430 431 432 433
};

static msg_xtra_f sip_publication_dup_xtra;
static msg_dup_f sip_publication_dup_one;

434 435
msg_hclass_t sip_publication_class[] =
SIP_HEADER_CLASS(publication, "Publication", "", pub_params, single,
Pekka Pessi's avatar
Pekka Pessi committed
436 437
		 publication);

438
su_inline void sip_publication_update(sip_publication_t *pub);
Pekka Pessi's avatar
Pekka Pessi committed
439

440
issize_t sip_publication_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
Pekka Pessi's avatar
Pekka Pessi committed
441 442
{
  sip_publication_t *pub = h->sh_publication;
443
  size_t n;
Pekka Pessi's avatar
Pekka Pessi committed
444 445 446 447 448 449 450 451 452 453 454 455

  n = span_token(s); if (n == 0) return -1;
  pub->pub_package = s; s += n;
  while (IS_LWS(*s)) { *s++ = '\0'; }
  if (*s == ';') {
    if (msg_params_d(home, &s, &pub->pub_params) < 0 || *s)
      return -1;
    sip_publication_update(pub);
  }
  return 0;
}

456
issize_t sip_publication_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
Pekka Pessi's avatar
Pekka Pessi committed
457 458 459 460 461
{
  char *end = b + bsiz, *b0 = b;
  sip_publication_t const *pub = h->sh_publication;

  assert(sip_is_publication(h));
Pekka Pessi's avatar
Pekka Pessi committed
462 463
  MSG_STRING_E(b, end, pub->pub_package);
  MSG_PARAMS_E(b, end, pub->pub_params, flags);
Pekka Pessi's avatar
Pekka Pessi committed
464 465 466 467

  return b - b0;
}

468
isize_t sip_publication_dup_xtra(sip_header_t const *h, isize_t offset)
Pekka Pessi's avatar
Pekka Pessi committed
469 470 471
{
  sip_publication_t const *pub = h->sh_publication;

Pekka Pessi's avatar
Pekka Pessi committed
472 473
  MSG_PARAMS_SIZE(offset, pub->pub_params);
  offset += MSG_STRING_SIZE(pub->pub_package);
Pekka Pessi's avatar
Pekka Pessi committed
474 475 476 477

  return offset;
}

478
/** Duplicate one #sip_publication_t object */
Pekka Pessi's avatar
Pekka Pessi committed
479
char *sip_publication_dup_one(sip_header_t *dst, sip_header_t const *src,
480
			char *b, isize_t xtra)
Pekka Pessi's avatar
Pekka Pessi committed
481 482 483 484 485
{
  sip_publication_t *pub_dst = dst->sh_publication;
  sip_publication_t const *pub_src = src->sh_publication;

  char *end = b + xtra;
Pekka Pessi's avatar
Pekka Pessi committed
486 487
  b = msg_params_dup(&pub_dst->pub_params, pub_src->pub_params, b, xtra);
  MSG_STRING_DUP(b, pub_dst->pub_package, pub_src->pub_package);
Pekka Pessi's avatar
Pekka Pessi committed
488 489 490 491 492 493 494
  if (pub_dst->pub_params)
    sip_publication_update(pub_dst);
  assert(b <= end);

  return b;
}

495
su_inline void sip_publication_update(sip_publication_t *pub)
Pekka Pessi's avatar
Pekka Pessi committed
496
{
497
  size_t i;
Pekka Pessi's avatar
Pekka Pessi committed
498 499 500

  if (pub->pub_params)
    for (i = 0; pub->pub_params[i]; i++) {
501
      if (su_casenmatch(pub->pub_params[i], "stream=", strlen("stream=")))
Pekka Pessi's avatar
Pekka Pessi committed
502
	pub->pub_stream = pub->pub_params[i] + strlen("stream=");
503
      else if (su_casenmatch(pub->pub_params[i], "type=", strlen("type=")))
Pekka Pessi's avatar
Pekka Pessi committed
504 505 506 507 508 509 510 511 512 513 514
	pub->pub_type = pub->pub_params[i] + strlen("type=");
    }
}

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

/**@SIP_HEADER sip_allow_publications Allow-Publication Header
 *
 * The Allow-Publication header is used to indicate which publications or classes of
 * publications the server supports.  Its syntax is defined in [niemi]
 * (draft-niemi-simple-publish-00.txt) as follows:
515
 *
Pekka Pessi's avatar
Pekka Pessi committed
516
 * @code
517
 *   Allow-Publications   = "Allow-Publications" HCOLON publish-type
Pekka Pessi's avatar
Pekka Pessi committed
518 519 520
 *                          * ( COMMA publish-type )
 * @endcode
 *
521 522 523
 *
 * The parsed Allow-Publication Header
 * is stored in #sip_allow_publications_t structure.
Pekka Pessi's avatar
Pekka Pessi committed
524 525
 */

526
msg_hclass_t sip_allow_publications_class[] =
Pekka Pessi's avatar
Pekka Pessi committed
527 528
SIP_HEADER_CLASS_LIST(allow_publications, "Allow-Publications", "", list);

529
issize_t sip_allow_publications_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
Pekka Pessi's avatar
Pekka Pessi committed
530 531 532 533
{
  return msg_list_d(home, h, s, slen);
}

534
issize_t sip_allow_publications_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
Pekka Pessi's avatar
Pekka Pessi committed
535 536 537 538 539 540
{
  assert(sip_is_allow_publications(h));
  return msg_list_e(b, bsiz, h, f);
}

/** Append an publication to a Allow-Publications header. */
541 542
int sip_allow_publications_add(su_home_t *home,
			       sip_allow_publications_t *ae,
Pekka Pessi's avatar
Pekka Pessi committed
543 544 545 546 547
			       char const *e)
{
  e = su_strdup(home, e);
  if (!e)
    return -1;
Pekka Pessi's avatar
Pekka Pessi committed
548
  return msg_params_replace(home, (msg_param_t **)&ae->k_items, e);
Pekka Pessi's avatar
Pekka Pessi committed
549 550 551
}

#endif