nua_subnotref.c 26.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * This file is part of the Sofia-SIP package
 *
 * Copyright (C) 2006 Nokia Corporation.
 *
 * Contact: Pekka Pessi <pekka.pessi@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * 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 nua_subnotref.c
26 27
 * @brief Subscriber (event watcher)
 *
28 29 30 31
 * This file contains implementation SUBSCRIBE UAC, NOTIFY UAS, REFER UAC.
 * The implementation of SUBSCRIBE UAS, NOTIFY UAC and REFER UAS is in
 * nua_notifier.c.
 * Alternative implementation using nea is in nua_event_server.c.
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
 *
 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
 *
 * @date Created: Wed Mar  8 15:10:08 EET 2006 ppessi
 */

#include "config.h"

#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

#include <assert.h>

#include <sofia-sip/string0.h>
#include <sofia-sip/sip_protos.h>
#include <sofia-sip/sip_status.h>
#include <sofia-sip/sip_util.h>
51
#include <sofia-sip/su_uniqueid.h>
52 53 54 55

#define NTA_LEG_MAGIC_T      struct nua_handle_s
#define NTA_OUTGOING_MAGIC_T struct nua_handle_s

56
#include "nua_stack.h"
57 58

/* ---------------------------------------------------------------------- */
59
/* Subcriber event usage */
60 61 62 63

struct event_usage
{
  enum nua_substate  eu_substate;	/**< Subscription state */
64
  sip_time_t eu_expires;	        /**< Proposed expiration time */
65
  unsigned eu_notified;		        /**< Number of NOTIFYs received */
66 67
  unsigned eu_final_wait:1;	        /**< Waiting for final NOTIFY */
  unsigned eu_no_id:1;		        /**< Do not use "id" (even if we have one) */
68 69 70 71 72 73 74 75 76
};

static char const *nua_subscribe_usage_name(nua_dialog_usage_t const *du);
static int nua_subscribe_usage_add(nua_handle_t *nh, 
				   nua_dialog_state_t *ds,
				   nua_dialog_usage_t *du);
static void nua_subscribe_usage_remove(nua_handle_t *nh, 
				       nua_dialog_state_t *ds,
				       nua_dialog_usage_t *du);
77
static void nua_subscribe_usage_refresh(nua_handle_t *,
78
					nua_dialog_state_t *,
79 80 81
					nua_dialog_usage_t *,
					sip_time_t);
static int nua_subscribe_usage_shutdown(nua_handle_t *,
82
					nua_dialog_state_t *,
83
					nua_dialog_usage_t *);
84 85 86 87 88 89 90

static nua_usage_class const nua_subscribe_usage[1] = {
  {
    sizeof (struct event_usage), (sizeof nua_subscribe_usage),
    nua_subscribe_usage_add,
    nua_subscribe_usage_remove,
    nua_subscribe_usage_name,
91 92 93
    NULL,
    nua_subscribe_usage_refresh,
    nua_subscribe_usage_shutdown
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
  }};

static char const *nua_subscribe_usage_name(nua_dialog_usage_t const *du)
{
  return "subscribe";
}

static 
int nua_subscribe_usage_add(nua_handle_t *nh, 
			   nua_dialog_state_t *ds,
			   nua_dialog_usage_t *du)
{
  ds->ds_has_events++;
  ds->ds_has_subscribes++;
  return 0;
}

static 
void nua_subscribe_usage_remove(nua_handle_t *nh, 
			       nua_dialog_state_t *ds,
			       nua_dialog_usage_t *du)
{
  ds->ds_has_events--;	
  ds->ds_has_subscribes--;	
}

/* ====================================================================== */
/* SUBSCRIBE */

123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
/** Subscribe to a SIP event. 
 *
 * Subscribe a SIP event using the SIP SUBSCRIBE request. If the 
 * SUBSCRBE is successful a subscription state is established and 
 * the subscription is refreshed regularly. The refresh requests will
 * generate #nua_r_subscribe events.
 *
 * @param nh              Pointer to operation handle
 * @param tag, value, ... List of tagged parameters
 *
 * @return 
 *    nothing
 *
 * @par Related Tags:
 *    NUTAG_URL()
 *    Tags in <sip_tag.h>
 *
 * @par Events:
 *    #nua_r_subscribe \n
 *    #nua_i_notify
 *
 * @sa NUTAG_SUBSTATE(), @RFC3265
 */

/** Unsubscribe an event. 
 *
 * Unsubscribe an active or pending subscription with SUBSCRIBE request 
 * containing Expires: header with value 0. The dialog associated with 
 * subscription will be destroyed if there is no other subscriptions or 
 * call using this dialog.
 *
 * @param nh              Pointer to operation handle
 * @param tag, value, ... List of tagged parameters
 *
 * @return 
 *    nothing
 *
 * @par Related Tags:
 *    SIPTAG_EVENT() or SIPTAG_EVENT_STR() \n
 *    Tags in <sip_tag.h> except SIPTAG_EXPIRES() or SIPTAG_EXPIRES_STR()
 *
 * @par Events:
 *    #nua_r_unsubscribe 
 *
 * @sa NUTAG_SUBSTATE(), @RFC3265
 */

170 171 172 173
static int process_response_to_subscribe(nua_handle_t *nh,
					 nta_outgoing_t *orq,
					 sip_t const *sip);

174

175
int
176 177
nua_stack_subscribe(nua_t *nua, nua_handle_t *nh, nua_event_t e,
		    tagi_t const *tags)
178
{
179
  nua_client_request_t *cr = nh->nh_ds->ds_cr;
180 181 182 183 184
  nua_dialog_usage_t *du = NULL;
  struct event_usage *eu;
  msg_t *msg;
  sip_t *sip;

185
  if (nua_stack_set_handle_special(nh, nh_has_subscribe, nua_r_subscribe) < 0)
186 187 188
    return UA_EVENT3(e, 500, "Invalid handle for SUBSCRIBE", 
		     NUTAG_SUBSTATE(nua_substate_terminated));
  else if (cr->cr_orq)
189
    return UA_EVENT2(e, 900, "Request already in progress");
190 191

  /* Initialize allow and auth */
192
  nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
193

194
  msg = nua_creq_msg(nua, nh, cr, 0,
195 196 197 198 199 200 201 202 203
		     SIP_METHOD_SUBSCRIBE,
		     NUTAG_USE_DIALOG(1),
		     NUTAG_ADD_CONTACT(1),
		     TAG_NEXT(tags));
  sip = sip_object(msg);

  if (sip) {
    sip_event_t *o = sip->sip_event;

204 205 206 207 208 209 210 211 212 213 214 215 216
    du = nua_dialog_usage_get(nh->nh_ds, nua_subscribe_usage, o);

    if (du == NULL && o == NULL)
      du = nua_dialog_usage_get(nh->nh_ds, nua_subscribe_usage, NONE);

    eu = nua_dialog_usage_private(du);

    if (du && du->du_event && (o == NULL || (o->o_id && eu->eu_no_id))) {
      if (eu->eu_no_id)		/* No id (XXX - nor other parameters) */
	sip_add_make(msg, sip, sip_event_class, du->du_event->o_type);
      else
	sip_add_dup(msg, sip, (sip_header_t *)du->du_event);
    }
217

218 219 220 221 222 223 224 225 226 227 228 229 230 231
    if (e == nua_r_subscribe) {	
      if (du == NULL)		/* Create dialog usage */
	/* We allow here SUBSCRIBE without event */
	du = nua_dialog_usage_add(nh, nh->nh_ds, nua_subscribe_usage, o);
    }
    else if (du) { /* Unsubscribe */
      /* Embryonic subscription is just a placeholder */
      if (eu->eu_substate == nua_substate_terminated ||
	  eu->eu_substate == nua_substate_embryonic) {
	nua_dialog_usage_remove(nh, nh->nh_ds, du);
	msg_destroy(msg);
	return UA_EVENT3(e, SIP_200_OK, 
			 NUTAG_SUBSTATE(nua_substate_terminated),
			 TAG_END());
232
      }
233 234 235
    }
  }

236
  /* Store message template with supported features (eventlist) */
237 238 239 240 241 242 243 244 245 246
  if (du && sip) {
    if (du->du_msg)
      msg_destroy(du->du_msg);
    du->du_msg = msg_ref_create(cr->cr_msg);
  }

  if (du)
    cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
				      process_response_to_subscribe, nh, NULL,
				      msg,
247 248
				      TAG_IF(e != nua_r_subscribe,
					     SIPTAG_EXPIRES_STR("0")),
249 250 251 252 253 254 255 256 257 258
				      SIPTAG_END(), TAG_NEXT(tags));

  eu = nua_dialog_usage_private(du);

  if (!cr->cr_orq) {
    int substate = nua_substate_terminated;

    if (du == NULL)
      ;
    else if (du->du_ready)
259
      substate = eu->eu_substate; /* No change in subscription state  */
260 261 262 263 264
    else
      nua_dialog_usage_remove(nh, nh->nh_ds, du);

    msg_destroy(msg);

265 266
    return UA_EVENT3(e, NUA_INTERNAL_ERROR, 
		     NUTAG_SUBSTATE(substate), TAG_END());
267 268
  }

269
  nua_dialog_usage_reset_refresh(du); /* during SUBSCRIBE transaction */
270
  du->du_terminating = e != nua_r_subscribe; /* Unsubscribe or destroy */
271 272 273 274 275 276 277 278 279 280 281

  if (du->du_terminating)
    eu->eu_expires = 0;
  else if (sip->sip_expires)
    eu->eu_expires = sip->sip_expires->ex_delta;
  else
    /* We just use common default value, but the default is actually
       package-specific according to the RFC 3265 section 4.4.4:
       [Event] packages MUST also define a
       default "Expires" value to be used if none is specified. */
    eu->eu_expires = 3600;
282 283

  eu->eu_final_wait = 0;
284
    
285 286 287 288 289 290 291 292 293 294 295 296
  if (sip->sip_expires && sip->sip_expires->ex_delta == 0)
    du->du_terminating = 1;

  if (eu->eu_substate == nua_substate_terminated)
    eu->eu_substate = nua_substate_embryonic;

  cr->cr_usage = du;
  return cr->cr_event = e;
}

static void restart_subscribe(nua_handle_t *nh, tagi_t *tags)
{
297
  nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_subscribe, tags);
298 299
}

300
/** @NUA_EVENT nua_r_subscribe
301
 *
302
 * Response to an outgoing SUBSCRIBE request.
303 304 305 306
 *
 * The SUBSCRIBE request may have been sent explicitly by nua_subscribe() or
 * implicitly by NUA state machine.
 *
307 308 309 310 311 312 313
 * @param status response status code
 *               (if the request is retried, @a status is 100, the @a
 *               sip->sip_status->st_status contain the real status code
 *               from the response message, e.g., 302, 401, or 407)
 * @param phrase a short textual description of @a status code
 * @param nh     operation handle associated with the subscription
 * @param hmagic application context associated with the handle
314
 * @param sip    response to SUBSCRIBE request or NULL upon an error
315 316
 *               (status code is in @a status and 
 *                descriptive message in @a phrase parameters)
317 318 319
 * @param tags   NUTAG_SUBSTATE()
 *
 * @sa nua_subscribe(), @RFC3265
320 321
 *
 * @END_NUA_EVENT
322 323
 */

324
/** @NUA_EVENT nua_r_unsubscribe
325 326 327
 *
 * Response to an outgoing un-SUBSCRIBE.
 *
328 329 330 331 332 333 334
 * @param status response status code
 *               (if the request is retried, @a status is 100, the @a
 *               sip->sip_status->st_status contain the real status code
 *               from the response message, e.g., 302, 401, or 407)
 * @param phrase a short textual description of @a status code
 * @param nh     operation handle associated with the subscription
 * @param hmagic application context associated with the handle
335
 * @param sip    response to SUBSCRIBE request or NULL upon an error
336 337
 *               (status code is in @a status and 
 *                descriptive message in @a phrase parameters)
338 339 340
 * @param tags   NUTAG_SUBSTATE()
 *
 * @sa nua_unsubscribe(), @RFC3265
341 342
 *
 * @END_NUA_EVENT
343 344
 */

345 346 347 348
static int process_response_to_subscribe(nua_handle_t *nh,
					 nta_outgoing_t *orq,
					 sip_t const *sip)
{
349
  nua_client_request_t *cr = nh->nh_ds->ds_cr;
350 351 352 353 354 355 356 357 358 359 360
  nua_dialog_usage_t *du = cr->cr_usage; 
  struct event_usage *eu = nua_dialog_usage_private(du);
  int status = sip ? sip->sip_status->st_status : 408;
  int gracefully = 0;
  int substate = nua_substate_embryonic;

  assert(du); assert(du->du_class == nua_subscribe_usage);

  if (status < 200)
    ;
  else if (du == NULL) {
361
    /* NOTIFY already removed du */
362
  }
363
  /* We have not received NOTIFY. */
364 365 366 367 368 369 370
  else if (status < 300) {
    int win_messenger_enable = NH_PGET(nh, win_messenger_enable);
    sip_time_t delta, now = sip_now();

    du->du_ready = 1;
    substate = eu->eu_substate;
    
371
    if (du->du_terminating)
372 373
      delta = 0;
    else
374 375
      /* If there is no expires header,
	 use default value stored in eu_expires */
376
      delta = sip_contact_expires(NULL, sip->sip_expires, sip->sip_date, 
377
				  eu->eu_expires, now);
378

379 380 381 382 383 384
    if (win_messenger_enable && !nua_dialog_is_established(nh->nh_ds)) {
      /* Notify from messanger does not match with dialog tag */ 
      nh->nh_ds->ds_remote_tag = su_strdup(nh->nh_home, "");
    }

    nua_dialog_uac_route(nh, nh->nh_ds, sip, 1);
385
    nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
386 387 388 389

    if (delta > 0) {
      nua_dialog_usage_set_refresh(du, delta);
    }
390 391 392 393 394
    else if (!eu->eu_notified) {
      /* This is a fetch: subscription was really terminated
	 but we wait 32 seconds for NOTIFY. */
      delta = 64 * NTA_SIP_T1 / 1000;

395
      if (win_messenger_enable)
396 397 398 399
	delta = 4 * 60; 	/* Wait 4 minutes for NOTIFY from Messenger */

      eu->eu_final_wait = 1;

400 401 402
      /* Do not remove usage in nua_stack_process_response  */
      cr->cr_usage = NULL;	

403
      nua_dialog_usage_refresh_range(du, delta, delta);
404
    }
405 406 407
    else {
      eu->eu_substate = substate = nua_substate_terminated;
    }
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
  }
  else /* if (status >= 300) */ {
    int terminated;

    if (nua_creq_check_restart(nh, cr, orq, sip, restart_subscribe))
      return 0;

    cr->cr_usage = NULL; /* We take care of removing/not removing usage */

    substate = eu->eu_substate;

    if (!sip || !sip->sip_retry_after)
      gracefully = 1;

    terminated = 
      sip_response_terminates_dialog(status, sip_method_subscribe, 
				     &gracefully);

    /* XXX - zap dialog if terminated < 0 ? */

    if (terminated || !du->du_ready || du->du_terminating) {
      substate = nua_substate_terminated;
      nua_dialog_usage_remove(nh, nh->nh_ds, du);
    }
    else if (gracefully && substate != nua_substate_terminated) 
      /* Post un-subscribe event */
      nua_stack_post_signal(nh, nua_r_unsubscribe, 
435 436 437
			    SIPTAG_EVENT(du->du_event), 
			    SIPTAG_EXPIRES_STR("0"),
			    TAG_END());
438 439 440 441 442 443 444 445 446
  }

  nua_stack_process_response(nh, cr, orq, sip, 
			     TAG_IF(substate >= 0, NUTAG_SUBSTATE(substate)),
			     TAG_END());
  return 0;
}

/** Refresh subscription */
447
static void nua_subscribe_usage_refresh(nua_handle_t *nh,
448
					nua_dialog_state_t *ds,
449 450
					nua_dialog_usage_t *du,
					sip_time_t now)
451 452
{
  nua_t *nua = nh->nh_nua;
453
  nua_client_request_t *cr = ds->ds_cr;
454
  struct event_usage *eu = nua_dialog_usage_private(du);
455 456
  msg_t *msg;

457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
  assert(eu);
  
  if (eu->eu_final_wait) {
    /* Did not receive NOTIFY for fetch... */
    sip_event_t const *o = du->du_event;
    char const *id = o ? o->o_id : NULL;

    SU_DEBUG_3(("nua(%p): fetch event %s%s%s timeouts\n",
		nh, o ? o->o_type : "(empty)",
		id ? "; id=" : "", id ? id : ""));

    nua_stack_event(nh->nh_nua, nh,  NULL,
		    nua_i_notify, 408, "Fetch Timeouts without NOTIFY", 
		    NUTAG_SUBSTATE(nua_substate_terminated),
		    SIPTAG_EVENT(o),
		    TAG_END());

474
    nua_dialog_usage_remove(nh, ds, du);
475

476 477 478
    return;
  }

479 480
  if (du->du_terminating)	/* No need to refresh. */
    return;
481

482 483 484 485 486
  if (cr->cr_msg) {
    /* Already doing something, delay 5..15 seconds? */
    if (cr->cr_usage != du)
      nua_dialog_usage_refresh_range(du, 5, 15);
    return;
487 488
  }

489 490
  cr->cr_msg = msg_copy(du->du_msg);

491
  msg = nua_creq_msg(nua, nh, cr, 1,
492 493 494
		     SIP_METHOD_SUBSCRIBE,
		     NUTAG_USE_DIALOG(1),
		     NUTAG_ADD_CONTACT(1),
495 496 497
		     /* If dialog is established, remove initial route */
		     TAG_IF(nua_dialog_is_established(nh->nh_ds),
			    SIPTAG_ROUTE(NONE)),
498
		     TAG_END());
499 500 501 502 503

  cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
				    process_response_to_subscribe, nh, NULL,
				    msg,
				    SIPTAG_END(), TAG_NEXT(NULL));
504 505 506
  if (cr->cr_orq) {
    cr->cr_usage = du;
    cr->cr_event = nua_r_subscribe;
507 508 509
    return;
  }

510 511 512 513 514 515 516 517 518
  if (du->du_terminating)
    nua_dialog_usage_remove(nh, nh->nh_ds, du);
  else   /* Try again later? */
    nua_dialog_usage_refresh_range(du, 5, 15);

  msg_destroy(msg);
  UA_EVENT3(nua_r_subscribe, NUA_INTERNAL_ERROR, 
	    NUTAG_SUBSTATE(eu->eu_substate),
	    TAG_END());
519 520 521
}


522 523
/** Terminate subscription */
static int nua_subscribe_usage_shutdown(nua_handle_t *nh,
524
					nua_dialog_state_t *ds,
525
					nua_dialog_usage_t *du)
526
{
527
  nua_t *nua = nh->nh_nua;
528
  nua_client_request_t *cr = ds->ds_cr;
529 530
  struct event_usage *eu = nua_dialog_usage_private(du);
  msg_t *msg;
531

532
  assert(eu); (void)eu;
533

534 535 536 537 538 539
  if (du->du_terminating)
    return 100;			/* ...in progress */
  
  if (cr->cr_msg)
    /* XXX - already doing something else? */
    return 100;
540

541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
  cr->cr_msg = msg_copy(du->du_msg);

  msg = nua_creq_msg(nua, nh, cr, 1,
		     SIP_METHOD_SUBSCRIBE,
		     NUTAG_USE_DIALOG(1),
		     NUTAG_ADD_CONTACT(1),
		     SIPTAG_EXPIRES_STR("0"),
		     /* If dialog is established, remove initial route */
		     TAG_IF(nua_dialog_is_established(nh->nh_ds),
			    SIPTAG_ROUTE(NONE)),
		     TAG_END());

  cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
				    process_response_to_subscribe, nh, NULL,
				    msg,
				    SIPTAG_END(), TAG_NEXT(NULL));
  if (cr->cr_orq) {
    cr->cr_usage = du;
    cr->cr_event = nua_r_destroy;
    return 100;
  }
562

563
  /* Too bad. */
564
  nua_dialog_usage_remove(nh, ds, du);
565 566
  msg_destroy(msg);
  return 200;
567 568 569
}

/* ======================================================================== */
570
/* NOTIFY server */
571

572
/** @NUA_EVENT nua_i_notify
573 574 575 576
 *
 * Event for incoming NOTIFY request.
 *
 * @param status statuscode of response sent automatically by stack
577 578 579
 * @param phrase a short textual description of @a status code
 * @param nh     operation handle associated with the subscription
 * @param hmagic application context associated with the handle
580 581 582 583
 * @param sip    incoming NOTIFY request
 * @param tags   NUTAG_SUBSTATE() indicating the subscription state
 *
 * @sa nua_subscribe(), nua_unsubscribe(), @RFC3265, #nua_i_subscribe
584 585
 * 
 * @END_NUA_EVENT
586 587
 */

588
/** @internal Process incoming NOTIFY. */
589 590 591 592 593 594 595 596 597 598
int nua_stack_process_notify(nua_t *nua,
			     nua_handle_t *nh,
			     nta_incoming_t *irq,
			     sip_t const *sip)
{
  nua_dialog_state_t *ds = nh->nh_ds;
  nua_dialog_usage_t *du;
  struct event_usage *eu;
  sip_subscription_state_t *subs = sip ? sip->sip_subscription_state : NULL;
  sip_subscription_state_t ss0[1];
599
  msg_t *response;
600 601 602 603 604 605
  char expires[32];
  int retry = -1;
  char const *what = NULL, *why = NULL;

  enter;

606 607 608 609 610
  if (nh == NULL) {
    nta_incoming_treply(irq, 481, "Subscription Does Not Exist", 
			TAG_END());
    return 481;
  }
611
  assert(nh);
612 613

  if (/* XXX - support forking of subscriptions?... */
614 615
      ds->ds_remote_tag && ds->ds_remote_tag[0] && 
      sip && sip->sip_from->a_tag &&
616
      strcmp(ds->ds_remote_tag, sip->sip_from->a_tag)) {
617
    sip_contact_t const *m = NULL;
618 619 620 621 622 623 624 625 626
    sip_warning_t *w = NULL, w0[1];

    m = nua_stack_get_contact(nua->nua_registrations);
    if (m) {
      w = sip_warning_init(w0);
      w->w_code = 399;
      w->w_host = m->m_url->url_host;
      w->w_port = m->m_url->url_port;
      w->w_text = "Forking SUBSCRIBEs are not supported";
627
    }
628 629

    nta_incoming_treply(irq, 481, "Subscription Does Not Exist", 
630
			SIPTAG_WARNING(w),
631 632 633 634 635 636 637 638 639 640 641
			TAG_END());
    return 481;
  }

  du = nua_dialog_usage_get(nh->nh_ds, nua_subscribe_usage, sip->sip_event);

  if (du == NULL) {
    nta_incoming_treply(irq, 481, "Subscription Does Not Exist", TAG_END());
    return 481;
  }

642
  eu = nua_dialog_usage_private(du); assert(eu);
643
  eu->eu_notified++;
644

645 646 647
  if (!sip->sip_event->o_id) {
    eu->eu_no_id = 1;
  }
648

649 650
  if (subs == NULL) {
    /* Do some compatibility stuff here */
651
    unsigned long delta;
652 653 654

    sip_subscription_state_init(subs = ss0);

655
    delta = sip->sip_expires ? sip->sip_expires->ex_delta : eu->eu_expires;
656 657 658 659 660 661

    if (delta == 0)
      subs->ss_substate = "terminated";
    else
      subs->ss_substate = "active";

662
    if (delta > 0 && sip->sip_expires) {
663 664 665 666 667
      snprintf(expires, sizeof expires, "%lu", delta);
      subs->ss_expires = expires;
    }
  }

668 669
  nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
  nua_dialog_uas_route(nh, nh->nh_ds, sip, 1);
670 671 672 673 674 675

  if (strcasecmp(subs->ss_substate, what = "terminated") == 0) {
    eu->eu_substate = nua_substate_terminated;

    if (str0casecmp(subs->ss_reason, why = "deactivated") == 0) {
      eu->eu_substate = nua_substate_embryonic;
676
      retry = 0;		/* retry immediately */
677 678 679 680 681 682
    } 
    else if (str0casecmp(subs->ss_reason, why = "probation") == 0) {
      eu->eu_substate = nua_substate_embryonic;
      retry = 30;
      if (subs->ss_retry_after)
	retry = strtoul(subs->ss_retry_after, NULL, 10);
683 684
      if (retry > 3600)
	retry = 3600;
685 686 687 688 689 690 691
    }
    else
      why = subs->ss_reason;
  }
  else if (strcasecmp(subs->ss_substate, what = "pending") == 0)
    eu->eu_substate = nua_substate_pending;
  else /* if (strcasecmp(subs->ss_substate, "active") == 0) */ {
692
    /* Any extended state is considered as active */
693 694 695
    what = subs->ss_substate ? subs->ss_substate : "active";
    eu->eu_substate = nua_substate_active;
  }
696 697 698

  if (du->du_terminating)
    retry = -1;
699
  
700 701 702 703
  response = nh_make_response(nua, nh, irq, SIP_200_OK,
			      SIPTAG_ALLOW(NH_PGET(nh, allow)),
			      SIPTAG_SUPPORTED(NH_PGET(nh, supported)),
			      TAG_END());
704

705 706 707 708
  if (response && 
      nua_registration_add_contact_to_response(nh, response, NULL, 
					       sip->sip_record_route,
					       sip->sip_contact) >= 0)
709 710 711
    nta_incoming_mreply(irq, response);
  else
    nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
712

713 714 715
  if (eu->eu_substate == nua_substate_terminated && retry > 0)
    eu->eu_substate = nua_substate_embryonic;

716
  nua_stack_event(nh->nh_nua, nh, nta_incoming_getrequest(irq),
717 718 719
		  nua_i_notify, SIP_200_OK, 
		  NUTAG_SUBSTATE(eu->eu_substate),
		  TAG_END());
720 721 722 723 724 725 726

  nta_incoming_destroy(irq), irq = NULL;

  SU_DEBUG_5(("nua(%p): nua_stack_process_notify: %s (%s)\n", 
	      nh, what, why ? why : ""));

  if (eu->eu_substate == nua_substate_terminated) {
727
    if (du != nh->nh_ds->ds_cr->cr_usage)
728
      nua_dialog_usage_remove(nh, nh->nh_ds, du);
729
    else
730
      nua_dialog_usage_reset_refresh(du);
731 732
  }
  else if (eu->eu_substate == nua_substate_embryonic) {
733
    if (retry >= 0) {
734
      /* Try to subscribe again */
735 736
      nua_dialog_remove(nh, nh->nh_ds, du); /* tear down */
      nua_dialog_usage_refresh_range(du, retry, retry + 5);
737
    }
738
    else if (du != nh->nh_ds->ds_cr->cr_usage)
739
      nua_dialog_usage_remove(nh, nh->nh_ds, du);
740
    else
741
      nua_dialog_usage_reset_refresh(du);
742
  }
743
  else if (du->du_terminating) {
744
    nua_dialog_usage_reset_refresh(du);
745 746 747 748 749 750 751 752
  }
  else {
    sip_time_t delta;

    if (subs->ss_expires)
      delta = strtoul(subs->ss_expires, NULL, 10);
    else
      delta = eu->eu_expires;
753
    
754
    nua_dialog_usage_set_refresh(du, delta);
755 756 757 758 759 760 761 762
  }

  return 0;
}

/* ======================================================================== */
/* REFER */

763 764
/** Transfer a call. 
 * 
765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784
 * Send a REFER request asking the recipient to transfer the call. 
 *
 * The REFER request also establishes an implied subscription to the "refer"
 * event. The "refer" event can have an "id" parameter, which has the value
 * of CSeq number in the REFER request. After initiating the REFER request,
 * the nua engine sends application a #nua_r_refer event with status 100 and
 * tag NUTAG_REFER_EVENT() containing a matching event header with id
 * parameter.
 *
 * Note that the @Event header in the locally generated #nua_r_refer event
 * contains the @a id parameter. The @a id parameter contains the @CSeq
 * number of the REFER request, and it may get incremented if the request is
 * retried because it got challenged or redirected. In that case, the
 * application gets a new #nua_r_refer event with status 100 and tag
 * NUTAG_REFER_EVENT(). Also the recipient of the REFER request may or may
 * not include the @a id parameter with the @Event header in the NOTIFY
 * requests messages which it sends to the sender of the REFER request.
 *
 * Therefore the application is not able to modify the state of the implied
 * subscription before receiving the first NOTIFY request.
785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800
 *
 * @param nh              Pointer to operation handle
 * @param tag, value, ... List of tagged parameters
 *
 * @return 
 *    nothing
 *
 * @par Related Tags:
 *    NUTAG_URL() \n
 *    Tags of nua_set_hparams() \n
 *    Tags in <sip_tag.h>
 *
 * @par Events:
 *    #nua_r_refer \n
 *    #nua_i_notify
 *
801 802
 * @sa #nua_r_refer, NUTAG_SUBSTATE(), NUTAG_REFER_EVENT(),#nua_i_refer,
 * @RFC3515, @ReferTo, @RFC3892, @ReferredBy
803 804
 */

805 806 807 808 809 810 811 812
static int process_response_to_refer(nua_handle_t *nh,
				     nta_outgoing_t *orq,
				     sip_t const *sip);

int
nua_stack_refer(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
{
  nua_dialog_usage_t *du = NULL;
813
  nua_client_request_t *cr = nh->nh_ds->ds_cr;
814 815 816 817 818
  msg_t *msg;
  sip_t *sip;
  sip_referred_by_t by[1];
  sip_event_t *event = NULL;

819
  if (nua_stack_set_handle_special(nh, nh_has_subscribe, nua_r_subscribe) < 0)
820
    return UA_EVENT2(e, 900, "Invalid handle for REFER");
821
  else if (cr->cr_orq)
822
    return UA_EVENT2(e, 900, "Request already in progress");
823

824
  nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857

  sip_referred_by_init(by);
  by->b_display = nua->nua_from->a_display;
  *by->b_url = *nua->nua_from->a_url;

  /* Now we create a REFER request message */
  msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count,
			 SIP_METHOD_REFER,
			 NUTAG_USE_DIALOG(1),
			 SIPTAG_EVENT(SIP_NONE), /* remove event */
			 SIPTAG_REFERRED_BY(by), /* Overriden by user tags */
			 NUTAG_ADD_CONTACT(1),
			 TAG_NEXT(tags));
  sip = sip_object(msg);

  if (sip && sip->sip_cseq)
    event = sip_event_format(nh->nh_home, "refer;id=%u", 
			     sip->sip_cseq->cs_seq);

  if (event)
    du = nua_dialog_usage_add(nh, nh->nh_ds, nua_subscribe_usage, event);
  
  if (du)
    cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
				      process_response_to_refer, nh, NULL,
				      msg,
				      SIPTAG_END(), TAG_NEXT(tags));
  
  if (!cr->cr_orq) {
    if (du)
      nua_dialog_usage_remove(nh, nh->nh_ds, du);
    su_free(nh->nh_home, event);
    msg_destroy(msg);
858
    return UA_EVENT1(e, NUA_INTERNAL_ERROR);
859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876
  }

  /*
   * We send a 100 trying event so that application gets a event 
   * it can use to match NOTIFYs with its REFER
   */
  nua_stack_event(nua, nh, NULL, e, SIP_100_TRYING, 
	   NUTAG_REFER_EVENT(event),
	   TAG_END());
  su_free(nh->nh_home, event);

  cr->cr_usage = du;

  return cr->cr_event = e;
}

void restart_refer(nua_handle_t *nh, tagi_t *tags)
{
877
  nua_stack_refer(nh->nh_nua, nh, nh->nh_ds->ds_cr->cr_event, tags);
878 879
}

880
/**@NUA_EVENT nua_r_refer
881
 *
882
 * @brief Response to outgoing REFER.
883
 *
884 885 886 887 888 889 890
 * @param status response status code
 *               (if the request is retried, @a status is 100, the @a
 *               sip->sip_status->st_status contain the real status code
 *               from the response message, e.g., 302, 401, or 407)
 * @param phrase a short textual description of @a status code
 * @param nh     operation handle associated with the REFER request
 * @param hmagic application context associated with the handle
891
 * @param sip    response to REFER request or NULL upon an error
892 893 894 895 896 897 898 899 900
 *               (status code is in @a status and 
 *                descriptive message in @a phrase parameters)
 * @param tags    NUTAG_REFER_EVENT() \n
 *                NUTAG_SUBSTATE()
 *
 * @sa nua_refer(), NUTAG_SUBSTATE(), #nua_i_refer,
 * @RFC3515, @ReferTo, @RFC3892, @ReferredBy
 *
 * @END_NUA_EVENT
901 902
 */

903 904 905 906
static int process_response_to_refer(nua_handle_t *nh,
				     nta_outgoing_t *orq,
				     sip_t const *sip)
{
907
  nua_client_request_t *cr = nh->nh_ds->ds_cr;
908 909 910 911 912 913 914
  int status = sip ? sip->sip_status->st_status : 408;

  if (status < 200)
    ;
  else if (status < 300) {
    if (cr->cr_usage)
      cr->cr_usage->du_ready = 1;
915 916
    nua_dialog_uac_route(nh, nh->nh_ds, sip, 1);
    nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
917 918 919 920 921 922 923 924 925 926
  }
  else /* if (status >= 300) */ {
    if (cr->cr_usage)
      nua_dialog_usage_remove(nh, nh->nh_ds, cr->cr_usage), cr->cr_usage = NULL;
    if (nua_creq_check_restart(nh, cr, orq, sip, restart_refer))
      return 0;
  }

  return nua_stack_process_response(nh, cr, orq, sip, TAG_END());
}