[Freeswitch-svn] [commit] r7738 - in freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua: nua nua/sofia-sip sdp

Freeswitch SVN mikej at freeswitch.org
Tue Feb 26 12:00:03 EST 2008


Author: mikej
Date: Tue Feb 26 12:00:03 2008
New Revision: 7738

Modified:
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_extension.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_message.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_options.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_init.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua_params.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.h
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_simple.c
   freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_print.c

Log:
merge to sofia darcs:

Mon Feb 25 09:49:39 EST 2008  Pekka.Pessi at nokia.com
  * nua_subnotref.c: fixed problems re-calculating the subscription duration upon NOTIFY
  
  Thanks for Colin Whittaker for reporting this problem.

Wed Feb  6 12:05:13 EST 2008  Pekka.Pessi at nokia.com
  * nua_stack.c: pass events while in shutdown if NUTAG_SHUTDOWN_EVENTS(1) has been set

Wed Feb  6 12:05:46 EST 2008  Pekka.Pessi at nokia.com
  * nua: using global preferences. Added NUTAG_SHUTDOWN_EVENTS().

Mon Feb 25 12:10:31 EST 2008  Pekka.Pessi at nokia.com
  * nua: renamed crm_deinit as crm_complete, commented nua_client_methods_t initializers

Mon Feb 25 14:14:15 EST 2008  Pekka.Pessi at nokia.com
  * nua: added NUTAG_SUB_EXPIRES()

Tue Feb 26 11:09:37 EST 2008  Pekka.Pessi at nokia.com
  * nua: initial fix for sf.net bug #1827511
  
  BYE can now be challenged.

Tue Feb 26 11:19:40 EST 2008  Pekka.Pessi at nokia.com
  * nua_session.c: ensure correct call state
  
  Avoid assert() on bad input from network - crash reported by Michael Jerris.
  
  Also if calls are being terminated, reject new INVITE/UPDATE/PRACK requests
  with 481.

Tue Feb 26 11:33:19 EST 2008  Pekka.Pessi at nokia.com
  * sdp_print.c: pt 9 is, like, g722. 19 is used by nobody, so it can be used as filler?

Tue Feb 26 11:40:00 EST 2008  Pekka.Pessi at nokia.com
  * nua_session.c: fixed non-compiling fix on session state check



Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c	Tue Feb 26 12:00:03 2008
@@ -373,8 +373,12 @@
     /* Destroy saved client request */
     if (nua_client_is_bound(du->du_cr)) {
       nua_client_bind(cr = du->du_cr, NULL);
-      if (!nua_client_is_queued(cr) &&
-	  !nua_client_is_reporting(cr))
+
+      if (nua_client_is_queued(cr))
+	nua_client_request_complete(cr);
+      else if (nua_client_is_reporting(cr))
+	;
+      else
 	nua_client_request_destroy(cr);
     }
 

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h	Tue Feb 26 12:00:03 2008
@@ -253,11 +253,11 @@
 		    nta_outgoing_t *orq,
 		    tagi_t const *tags);
 
-  /** @a crm_deinit is called when a client-side request is destroyed.
+  /** @a crm_complete is called when a client-side request is destroyed.
    *
    * @return The return value should be 0. It is currently ignored.
    */
-  int (*crm_deinit)(nua_client_request_t *);
+  int (*crm_complete)(nua_client_request_t *);
 
 } nua_client_methods_t;
 
@@ -516,6 +516,8 @@
   return (void *)(cr + 1);
 }
 
+void nua_client_request_complete(nua_client_request_t *);
+
 void nua_client_request_destroy(nua_client_request_t *);
 
 int nua_client_request_queue(nua_client_request_t *cr);

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_extension.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_extension.c	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_extension.c	Tue Feb 26 12:00:03 2008
@@ -74,18 +74,21 @@
  */
 
 static nua_client_methods_t const nua_method_client_methods = {
-  SIP_METHOD_UNKNOWN,
-  0,
-  { 
+  SIP_METHOD_UNKNOWN,		/* crm_method, crm_method_name */
+  0,				/* crm_extra */
+  {				/* crm_flags */
     /* create_dialog */ 0,
     /* in_dialog */ 0,
     /* target_refresh */ 1,
   },
-  /* nua_method_client_template */ NULL,
-  /* nua_method_client_init */ NULL,
-  /* nua_method_client_request */ NULL,
-  /* nua_method_client_check_restart */ NULL,
-  /* nua_method_client_response */ NULL
+  NULL,				/* crm_template */
+  NULL,				/* crm_init */
+  NULL,				/* crm_send */
+  NULL,				/* crm_check_restart */
+  NULL,				/* crm_recv */
+  NULL,				/* crm_preliminary */
+  NULL,				/* crm_report */
+  NULL,				/* crm_complete */
 };
 
 int 

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_message.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_message.c	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_message.c	Tue Feb 26 12:00:03 2008
@@ -77,18 +77,22 @@
 				   tagi_t const *tags);
 
 static nua_client_methods_t const nua_message_client_methods = {
-  SIP_METHOD_MESSAGE,
-  0,
-  { 
+  SIP_METHOD_MESSAGE,		/* crm_method, crm_method_name */
+  0,				/* crm_extra */
+  {				/* crm_flags */
     /* create_dialog */ 0,
     /* in_dialog */ 0,
     /* target refresh */ 0
   },
-  /* nua_message_client_template */ NULL,
-  nua_message_client_init,
-  /*nua_message_client_request*/ NULL,
-  /* nua_message_client_check_restart */ NULL,
-  /*nua_message_client_response*/ NULL
+  NULL,				/* crm_template */
+  nua_message_client_init,	/* crm_init */
+  NULL,				/* crm_send */
+  NULL,				/* crm_check_restart */
+  NULL,				/* crm_recv */
+  NULL,				/* crm_preliminary */
+  NULL,				/* crm_report */
+  NULL,				/* crm_complete */
+
 };
 
 int 

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c	Tue Feb 26 12:00:03 2008
@@ -237,7 +237,8 @@
   sip_event_t *o = sip->sip_event;
   char const *event = o ? o->o_type : NULL;
   /* Maximum expiration time */
-  unsigned long expires = 3600;
+  unsigned long expires = sip->sip_expires ? sip->sip_expires->ex_delta : 3600;
+  sip_time_t now = sip_now();
 
   assert(nh && nh->nh_nua->nua_dhandle != nh);
   
@@ -259,9 +260,10 @@
 
   nu = nua_dialog_usage_private(du);
 
-  if (sip->sip_expires && sip->sip_expires->ex_delta < expires)
-    expires = sip->sip_expires->ex_delta;
-  nu->nu_requested = sip_now() + expires;
+  if (now + expires >= now)
+    nu->nu_requested = now + expires;
+  else
+    nu->nu_requested = SIP_TIME_MAX - 1;
 
 #if SU_HAVE_EXPERIMENTAL
   nu->nu_etags = 
@@ -295,9 +297,23 @@
       sip_time_t now = sip_now();
 
       if (nu->nu_requested) {
-	if (nu->nu_requested > nu->nu_expires)
+	if (sip->sip_expires) {
+	  /* Expires in response can only shorten the expiration time */
+	  if (nu->nu_requested > now + sip->sip_expires->ex_delta) 
+	    nu->nu_requested = now + sip->sip_expires->ex_delta;
+	}
+	else {
+	  unsigned sub_expires = NH_PGET(sr->sr_owner, sub_expires);
+	  if (nu->nu_requested > now + sub_expires)
+	    nu->nu_requested = now + sub_expires;
+	}
+
+	if (nu->nu_requested >= now)
 	  nu->nu_expires = nu->nu_requested;
-	else if (nu->nu_expires <= now || nu->nu_requested <= now)
+	else
+	  nu->nu_expires = now;
+
+	if (nu->nu_expires <= now)
 	  nu->nu_substate = nua_substate_terminated;
       }
 
@@ -305,7 +321,7 @@
 	ex->ex_delta = nu->nu_expires - now;
     }
     else {
-      /* Add header Expires: 0 */
+      /* Always add header Expires: 0 */
     }
 
     if (!sip->sip_expires || sip->sip_expires->ex_delta > ex->ex_delta)
@@ -420,20 +436,21 @@
 				    tagi_t const *tags);
 
 static nua_client_methods_t const nua_notify_client_methods = {
-  SIP_METHOD_NOTIFY,
-  0,
-  { 
+  SIP_METHOD_NOTIFY,		/* crm_method, crm_method_name */
+  0,				/* crm_extra */
+  {				/* crm_flags */
     /* create_dialog */ 1,
     /* in_dialog */ 1,
     /* target refresh */ 1
   },
-  /* nua_notify_client_template */ NULL,
-  nua_notify_client_init,
-  nua_notify_client_request,
-  /* nua_notify_client_check_restart */ NULL,
-  /* nua_notify_client_response */ NULL,
-  /* nua_notify_client_preliminary */ NULL,
-  nua_notify_client_report
+  NULL,				/* crm_template */
+  nua_notify_client_init,	/* crm_init */
+  nua_notify_client_request,	/* crm_send */
+  NULL,				/* crm_check_restart */
+  NULL,				/* crm_recv */
+  NULL,				/* crm_preliminary */
+  nua_notify_client_report,	/* crm_report */
+  NULL,				/* crm_complete */
 };
 
 /**@internal Send NOTIFY. */

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_options.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_options.c	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_options.c	Tue Feb 26 12:00:03 2008
@@ -88,18 +88,21 @@
  */
 
 static nua_client_methods_t const nua_options_client_methods = {
-  SIP_METHOD_OPTIONS,
-  0,
-  { 
+  SIP_METHOD_OPTIONS,		/* crm_method, crm_method_name */
+  0,				/* crm_extra */
+  {				/* crm_flags */
     /* create_dialog */ 0,
     /* in_dialog */ 0,
     /* target refresh */ 0
   },
-  /*nua_options_client_template*/ NULL,
-  /*nua_options_client_init*/ NULL,
-  /*nua_options_client_request*/ NULL,
-  /* nua_options_client_check_restart */ NULL,
-  /*nua_options_client_response*/ NULL
+  NULL,				/* crm_template */
+  NULL,				/* crm_init */
+  NULL,				/* crm_send */
+  NULL,				/* crm_check_restart */
+  NULL,				/* crm_recv */
+  NULL,				/* crm_preliminary */
+  NULL,				/* crm_report */
+  NULL,				/* crm_complete */
 };
 
 int nua_stack_options(nua_t *nua,

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c	Tue Feb 26 12:00:03 2008
@@ -77,19 +77,27 @@
 su_inline void nhp_or_set(nua_handle_preferences_t *a,
 			  nua_handle_preferences_t const *b)
 {
-  unsigned *ap = a->nhp_set_.set_unsigned;
-  unsigned const *bp = b->nhp_set_.set_unsigned;
-  size_t i;
-
   memcpy(a, b, offsetof(nua_handle_preferences_t, nhp_set));
 
+  /* Bitwise or of bitfields, casted to unsigned */
+  a->nhp_set_.set_unsigned[0] |= b->nhp_set_.set_unsigned[0];
+  a->nhp_set_.set_unsigned[1] |= b->nhp_set_.set_unsigned[1];
+
+  /* 
+  unsigned *ap, const *bp;
+  size_t i;
+
+  ap = a->nhp_set_.set_unsigned;
+  bp = b->nhp_set_.set_unsigned;
   for (i = 0; i < (sizeof a->nhp_set); i += (sizeof *ap))
     *ap++ |= *bp++;
+
+  */
 }
 
 static int nhp_set_tags(su_home_t *home, 
 			nua_handle_preferences_t *nhp,
-			int global,
+			nua_global_preferences_t *ngp,
 			tagi_t const *tags);
 
 static int nhp_merge_lists(su_home_t *home,
@@ -101,11 +109,11 @@
 			   int always_merge,
 			   tag_value_t value);
 
-static
-nua_handle_preferences_t *nhp_move_params(su_home_t *home,
-					  nua_handle_preferences_t *dst,
-					  su_home_t *tmphome,
-					  nua_handle_preferences_t const *src);
+static int nhp_save_params(nua_handle_t *nh,
+		    su_home_t *tmphome, 
+		    nua_global_preferences_t *gsrc,
+		    nua_handle_preferences_t *src);
+
 
 /* ====================================================================== */
 /* Magical NUTAG_USER_AGENT() - add NHP_USER_AGENT there if it is not there */
@@ -169,6 +177,7 @@
   NHP_SET(nhp, refer_with_id, 1);
 
   NHP_SET(nhp, substate, nua_substate_active);
+  NHP_SET(nhp, sub_expires, 3600);
 
   NHP_SET(nhp, allow, sip_allow_make(home, nua_allow_str));
   NHP_SET(nhp, supported, sip_supported_make(home, "timer, 100rel"));
@@ -198,20 +207,12 @@
   sip_from_t *f = NULL,  f0[1];
   int set;
 
-  char const *uicc_name = "default";
-
   tl_gets(tags,
 	  /* By nua_stack_set_from() */
 	  SIPTAG_FROM_REF(from),
 	  SIPTAG_FROM_STR_REF(str),
-	  NUTAG_UICC_REF(uicc_name),
 	  TAG_END());
 
-#if HAVE_UICC_H
-  if (initial && uicc_name)
-    nua->nua_uicc = uicc_create(root, uicc_name);
-#endif
-
   if (!initial && from == NONE && str == NONE)
     return 0;
 
@@ -325,6 +326,7 @@
  *   NUTAG_SMIME_SIGNATURE() \n
  *   NUTAG_SOA_NAME() \n
  *   NUTAG_SUBSTATE() \n
+ *   NUTAG_SUB_EXPIRES() \n
  *   NUTAG_SUPPORTED(), SIPTAG_SUPPORTED(), and SIPTAG_SUPPORTED_STR() \n
  *   NUTAG_UPDATE_REFRESH() \n
  *   NUTAG_USER_AGENT(), SIPTAG_USER_AGENT() and SIPTAG_USER_AGENT_STR() \n
@@ -437,6 +439,7 @@
  *   NUTAG_SESSION_TIMER() \n
  *   NUTAG_SOA_NAME() \n
  *   NUTAG_SUBSTATE() \n
+ *   NUTAG_SUB_EXPIRES() \n
  *   NUTAG_SUPPORTED(), SIPTAG_SUPPORTED(), and SIPTAG_SUPPORTED_STR() \n
  *   NUTAG_UPDATE_REFRESH() \n
  *   NUTAG_USER_AGENT(), SIPTAG_USER_AGENT() and SIPTAG_USER_AGENT_STR() \n
@@ -475,146 +478,124 @@
 			 tagi_t const *tags)
 {
   nua_handle_t *dnh = nua->nua_dhandle;
-  nua_handle_preferences_t tmp[1], *nhp = nh->nh_prefs;
-  nua_handle_preferences_t const *dnhp = dnh->nh_prefs;
-
-  su_home_t tmphome[1] = { SU_HOME_INIT(tmphome) };
-
-  tagi_t const *ptags;
-
-  int error, global;
-  int status = 900;
-  char const *phrase = "Error storing parameters";
-  sip_supported_t const *supported = NULL;
-  sip_allow_t const *allow = NULL;
-  sip_allow_events_t const *allow_events = NULL;
-  sip_allow_t const *appl_method = NULL;
+  
+  int status;
+  char const *phrase;
 
   enter;
 
-  ptags = !nh->nh_used_ptags ? nh->nh_ptags : NULL;
-
-  *tmp = *nhp; NHP_UNSET_ALL(tmp);
-
-  /* Supported features, allowed methods and events are merged 
-     with previous ones */
-  if (!NHP_ISSET(nhp, supported)) 
-    supported = tmp->nhp_supported = dnhp->nhp_supported;
-  if (!NHP_ISSET(nhp, allow)) 
-    allow = tmp->nhp_allow = dnhp->nhp_allow;
-  if (!NHP_ISSET(nhp, allow_events)) 
-    allow_events = tmp->nhp_allow_events = dnhp->nhp_allow_events;
-  if (!NHP_ISSET(nhp, appl_method)) 
-    appl_method = tmp->nhp_appl_method = dnhp->nhp_appl_method;
-
-  error = 0;
-  global = nh == dnh;			/* save also stack-specific params */
+  {
+    su_home_t tmphome[1] = { SU_HOME_INIT(tmphome) };
+    nua_handle_preferences_t *nhp = nh->nh_prefs;
+    nua_handle_preferences_t const *dnhp = dnh->nh_prefs;
+    nua_handle_preferences_t tmp[1];
+    nua_global_preferences_t gtmp[1], *ngp = NULL;
+
+    *tmp = *nhp; NHP_UNSET_ALL(tmp);
+
+    /*
+     * Supported features, allowed methods and events are merged 
+     * with previous or default settings. 
+     *
+     * Here we just copy pointers from default settings. However when saving
+     * settings we have to be extra careful so that we
+     * 1) zero the pointers if the setting has not been modified
+     * 2) do not free pointer if the setting has been modified
+     * See NHP_ZAP_OVERRIDEN() below for gorier details.
+     */
+    if (!NHP_ISSET(nhp, supported)) 
+      tmp->nhp_supported = dnhp->nhp_supported;
+    if (!NHP_ISSET(nhp, allow)) 
+      tmp->nhp_allow = dnhp->nhp_allow;
+    if (!NHP_ISSET(nhp, allow_events)) 
+      tmp->nhp_allow_events = dnhp->nhp_allow_events;
+    if (!NHP_ISSET(nhp, appl_method)) 
+      tmp->nhp_appl_method = dnhp->nhp_appl_method;
     
-  /* Set and save parameters to tmp */
-  if (nhp_set_tags(tmphome, tmp, global, ptags) < 0)
-    error = 1, phrase = "Error storing default handle parameters";
-  else if (nhp_set_tags(tmphome, tmp, global, tags) < 0)
-    error = 1, phrase = "Error storing parameters";
-  else {
-    if (NHP_IS_ANY_SET(tmp)) {
-      if (tmp->nhp_supported == supported)
-	tmp->nhp_supported = NULL;
-
-      if (tmp->nhp_allow == allow)
-	tmp->nhp_allow = NULL;
-
-      if (tmp->nhp_allow_events == allow_events)
-	tmp->nhp_allow_events = NULL;
-
-      if (tmp->nhp_appl_method == appl_method)
-	tmp->nhp_appl_method = NULL;
-
-      /* Move parameters from tmp to nhp (or allocate new nhp) */
-      if (nh != dnh && nhp == dnh->nh_prefs)
-	nhp = NULL;
-      nhp = nhp_move_params(nh->nh_home, nhp, tmphome, tmp);
+    if (nh == dnh) /* nua_set_params() call, save stack-wide params, too */
+      ngp = gtmp, *gtmp = *nua->nua_prefs;
 
-      if (nhp)
-	nh->nh_prefs = nhp;
-      else
-	/* Fail miserably with ENOMEM */
-	error = 1, status = 900, phrase = su_strerror(ENOMEM);
-    }
+    /* Set and save parameters to tmp */
+    if (!nh->nh_used_ptags && 
+	nhp_set_tags(tmphome, tmp, NULL, nh->nh_ptags) < 0)
+      status = 900, phrase = "Error storing default handle parameters";
+    else if (nhp_set_tags(tmphome, tmp, ngp, tags) < 0)
+      status = 900, phrase = "Error storing parameters";
+    else if (nhp_save_params(nh, tmphome, ngp, tmp) < 0)
+      status = 900, phrase = su_strerror(ENOMEM);
+    else
+      status = 200, phrase = "OK", nh->nh_used_ptags = 1;
 
-    if (!error)
-      nh->nh_used_ptags = 1;
+    su_home_deinit(tmphome);
   }
 
-  su_home_deinit(tmphome);
-
-  if (error)
-    ;
-  else if (!nh->nh_soa && NHP_GET(nhp, dnhp, media_enable)) {
-    /* Create soa when needed */
-    char const *soa_name = NHP_GET(nhp, dnhp, soa_name);
+  if (status == 200) {
+    nua_handle_preferences_t const *nhp = nh->nh_prefs;
+    nua_handle_preferences_t const *dnhp = dnh->nh_prefs;
 
-    if (dnh->nh_soa)
-      nh->nh_soa = soa_clone(dnh->nh_soa, nua->nua_root, nh);
-    else  
-      nh->nh_soa = soa_create(soa_name, nua->nua_root, nh);
+    if (!nh->nh_soa && NHP_GET(nhp, dnhp, media_enable)) {
+      /* Create soa when needed */
+      char const *soa_name = NHP_GET(nhp, dnhp, soa_name);
 
-    ptags = nh->nh_ptags;
+      if (dnh->nh_soa)
+	nh->nh_soa = soa_clone(dnh->nh_soa, nua->nua_root, nh);
+      else  
+	nh->nh_soa = soa_create(soa_name, nua->nua_root, nh);
+      
+      if (!nh->nh_soa)
+	status = 900, phrase = "Error Creating SOA Object";
+      else if (soa_set_params(nh->nh_soa, TAG_NEXT(nh->nh_ptags)) < 0)
+	status = 900, phrase = "Error Setting SOA Parameters";
+    }
+    else if (nh->nh_soa && !NHP_GET(nhp, dnhp, media_enable)) {
+      /* ... destroy soa when not needed */
+      soa_destroy(nh->nh_soa), nh->nh_soa = NULL;
+    }
 
-    if (!nh->nh_soa)
-      error = 1, status = 900, phrase = "Error Creating SOA Object";
-  }
-  else if (nh->nh_soa && !NHP_GET(nhp, dnhp, media_enable)) {
-    /* ... destroy soa when not needed */
-    soa_destroy(nh->nh_soa), nh->nh_soa = NULL;
+    if (status == 200 && tags && nh->nh_soa &&	
+	soa_set_params(nh->nh_soa, TAG_NEXT(tags)) < 0) 
+      status = 900, phrase = "Error Setting SOA Parameters";
   }
 
-  if (!error && nh->nh_soa) {
-    if ((ptags && soa_set_params(nh->nh_soa, TAG_NEXT(ptags)) < 0) ||
-	(tags && soa_set_params(nh->nh_soa, TAG_NEXT(tags)) < 0))
-      error = 1, status = 900, phrase = "Error Setting SOA Parameters";
-  }
+  if (status == 200 && nh == dnh) {
+    /* Set stack-specific things below */
+    if (nua_stack_set_smime_params(nua, tags) < 0) {
+      status = 900, phrase = "Error setting S/MIME parameters";
+    }
+    else if (nua->nua_nta && nta_agent_set_params(nua->nua_nta, TAG_NEXT(tags)) < 0) {
+      status = 900, phrase = "Error setting NTA parameters";
+    }
+    else {
+      nua_stack_set_from(nua, 0, tags);
 
-  if (error || nh != dnh) {
-    ;
-  }
-  else if (nua_stack_set_smime_params(nua, tags) < 0) {
-    error = 1, status = 900, phrase = "Error setting S/MIME parameters";
-  }
-  else if (!nua->nua_nta) {
-  }
-  /* Set stack-specific things below */
-  else if (nta_agent_set_params(nua->nua_nta, TAG_NEXT(tags)) < 0) {
-    status = 900, phrase = "Error setting NTA parameters";
-    error = 1;
-  }
-  else {
-    nua_stack_set_from(nua, 0, tags);
-    if (NHP_ISSET(nhp, detect_network_updates))
-      nua_stack_launch_network_change_detector(nua);
+      if (nua->nua_prefs->ngp_detect_network_updates)
+	nua_stack_launch_network_change_detector(nua);
+    }
   }
 
-  if (error) {
+  if (status != 200) {
     if (e == nua_i_none)
       SU_DEBUG_1(("nua_set_params(): failed: %s\n", phrase));
     return UA_EVENT2(e, status, phrase), -1;
   }
-
-  if (e == nua_r_set_params)
-    UA_EVENT2(e, 200, "OK");
-
-  return 0;
+  else {
+    if (e == nua_r_set_params)
+      UA_EVENT2(e, status, phrase);
+    return 0;
+  }
 }
 
-/** Parse parameters from tags to @a nhp.
+
+/** Parse parameters from tags to @a nhp or @a ngp.
  *
  * @param home allocate new values from @a home
  * @param nhp  structure to store handle preferences
- * @param global  if true, save also global parameters
+ * @param ngp  structure to store global preferences
  * @param tags list of tags to parse
  */
 static int nhp_set_tags(su_home_t *home, 
 			nua_handle_preferences_t *nhp,
-			int global,
+			nua_global_preferences_t *ngp,
 			tagi_t const *tags)
 {
 
@@ -826,6 +807,10 @@
     else if (tag == nutag_substate) {
       NHP_SET(nhp, substate, (int)value);
     }
+    /* NUTAG_SUB_EXPIRES(sub_expires) */
+    else if (tag == nutag_sub_expires) {
+      NHP_SET(nhp, sub_expires, value);
+    }
     /* NUTAG_KEEPALIVE(keepalive) */
     else if (tag == nutag_keepalive) {
       NHP_SET(nhp, keepalive, (unsigned)value);
@@ -997,7 +982,7 @@
       NHP_SET_STR(nhp, outbound, value);
     }
     /* NUTAG_DETECT_NETWORK_UPDATES(detect_network_updates) */
-    else if (global && tag == nutag_detect_network_updates) {
+    else if (ngp && tag == nutag_detect_network_updates) {
       int detector = (int)value;
 
       if (detector < NUA_NW_DETECT_NOTHING)
@@ -1005,7 +990,13 @@
       else if (detector > NUA_NW_DETECT_TRY_FULL)
 	detector = NUA_NW_DETECT_TRY_FULL;
 
-      NHP_SET(nhp, detect_network_updates, detector);
+      ngp->ngp_detect_network_updates = detector;
+      ngp->ngp_set.ngp_detect_network_updates = 1;
+    }
+    /* NUTAG_SHUTDOWN_EVENTS() */
+    else if (ngp && tag == nutag_shutdown_events) {
+      ngp->ngp_shutdown_events = value != 0;
+      ngp->ngp_set.ngp_shutdown_events = 1;
     }
   }
 
@@ -1078,54 +1069,70 @@
   return 1;
 }
 
-static
-nua_handle_preferences_t *nhp_move_params(su_home_t *home,
-					  nua_handle_preferences_t *dst,
-					  su_home_t *tmphome,
-					  nua_handle_preferences_t const *src)
+/** Save parameters in @a gtmp and @a tmp.
+ */
+static 
+int nhp_save_params(nua_handle_t *nh,
+		    su_home_t *tmphome, 
+		    nua_global_preferences_t *gsrc,
+		    nua_handle_preferences_t *src)
 {
-  /* Update prefs structure */
-  nua_handle_preferences_t tbf[1];
+  su_home_t *home = nh->nh_home;
+  nua_t *nua = nh->nh_nua;
+  nua_handle_t *dnh = nua->nua_dhandle;
+  nua_handle_preferences_t *dst = nh->nh_prefs, old[1];
+
+  if (gsrc) {
+    *nua->nua_prefs = *gsrc;	/* No pointers this far */
+  }
 
-  if (dst == NULL)
-    dst = su_zalloc(home, sizeof *dst);
-  if (dst == NULL)
-    return NULL;
-  if (su_home_move(home, tmphome) < 0)
-    return NULL;
+  if (!NHP_IS_ANY_SET(src))
+    return 0;
 
-  *tbf = *dst;
+  if (nh == dnh || nh->nh_prefs != dnh->nh_prefs) {
+    dst = nh->nh_prefs, *old = *dst;
+    assert(dst);
+  }
+  else {
+    dst = su_zalloc(home, sizeof *dst), memset(old, 0, sizeof *old);
+    if (!dst)
+      return -1;
+  }
+
+  /* Move allocations from tmphome to home */
+  su_home_move(nh->nh_home, tmphome);
+  
+  /* Copy parameters that are set from src to dst */
   nhp_or_set(dst, src);
 
   /* Handle pointer items. Free changed ones and zap unset ones. */
-#define NHP_ZAP_OVERRIDEN(tbf, nhp, pref)				\
-  (((tbf)->nhp_set.nhb_##pref						\
-    && (tbf)->nhp_##pref != (nhp)->nhp_##pref				\
-    ? su_free(home, (void *)(tbf)->nhp_##pref) : (void)0),		\
-   (void)(!(nhp)->nhp_set.nhb_##pref ? (nhp)->nhp_##pref = NULL : NULL))
-
-  NHP_ZAP_OVERRIDEN(tbf, dst, soa_name);
-  NHP_ZAP_OVERRIDEN(tbf, dst, registrar);
-  NHP_ZAP_OVERRIDEN(tbf, dst, supported);
-  NHP_ZAP_OVERRIDEN(tbf, dst, allow);
-  NHP_ZAP_OVERRIDEN(tbf, dst, user_agent);
-  NHP_ZAP_OVERRIDEN(tbf, dst, organization);
-  NHP_ZAP_OVERRIDEN(tbf, dst, instance);
-  NHP_ZAP_OVERRIDEN(tbf, dst, m_display);
-  NHP_ZAP_OVERRIDEN(tbf, dst, m_username);
-  NHP_ZAP_OVERRIDEN(tbf, dst, m_params);
-  NHP_ZAP_OVERRIDEN(tbf, dst, m_features);
-  NHP_ZAP_OVERRIDEN(tbf, dst, outbound);
-
-#define NHP_ZAP_OVERRIDEN_HDR(tbf, nhp, pref)				\
-  (((tbf)->nhp_set.nhb_##pref						\
-    && (tbf)->nhp_##pref != (nhp)->nhp_##pref				\
-    ? msg_header_free(home, (void *)(tbf)->nhp_##pref) : (void)0),		\
-   (void)(!(nhp)->nhp_set.nhb_##pref ? (nhp)->nhp_##pref = NULL : NULL))
-
-  NHP_ZAP_OVERRIDEN_HDR(tbf, dst, initial_route);
+  /* Note that pointer items where !NHP_ISSET(old, pref) are not freed 
+     (because they were just on loan from the default preference set) */
+#define NHP_ZAP_OVERRIDEN(old, dst, free, pref)				\
+  (((NHP_ISSET(old, pref) &&						\
+     (old)->nhp_##pref && (old)->nhp_##pref != (dst)->nhp_##pref)	\
+    ? (free)(home, (void *)(old)->nhp_##pref) : (void)0),		\
+   (void)(!(dst)->nhp_set.nhb_##pref ? (dst)->nhp_##pref = NULL : NULL))
+
+  NHP_ZAP_OVERRIDEN(old, dst, su_free, soa_name);
+  NHP_ZAP_OVERRIDEN(old, dst, su_free, registrar);
+  NHP_ZAP_OVERRIDEN(old, dst, msg_header_free, allow);
+  NHP_ZAP_OVERRIDEN(old, dst, msg_header_free, supported);
+  NHP_ZAP_OVERRIDEN(old, dst, msg_header_free, allow_events);
+  NHP_ZAP_OVERRIDEN(old, dst, su_free, user_agent);
+  NHP_ZAP_OVERRIDEN(old, dst, su_free, organization);
+  NHP_ZAP_OVERRIDEN(old, dst, su_free, m_display);
+  NHP_ZAP_OVERRIDEN(old, dst, su_free, m_username);
+  NHP_ZAP_OVERRIDEN(old, dst, su_free, m_params);
+  NHP_ZAP_OVERRIDEN(old, dst, su_free, m_features);
+  NHP_ZAP_OVERRIDEN(old, dst, su_free, instance);
+  NHP_ZAP_OVERRIDEN(old, dst, su_free, outbound);
+  NHP_ZAP_OVERRIDEN(old, dst, msg_header_free, appl_method);
+  NHP_ZAP_OVERRIDEN(old, dst, msg_header_free, initial_route);
 
-  return dst;
+  nh->nh_prefs = dst;
+  
+  return 0;
 }
 
 static int nua_handle_tags_filter(tagi_t const *f, tagi_t const *t);
@@ -1475,6 +1482,7 @@
  *   NUTAG_SMIME_SIGNATURE() \n
  *   NUTAG_SOA_NAME() \n
  *   NUTAG_SUBSTATE() \n
+ *   NUTAG_SUB_EXPIRES() \n
  *   NUTAG_UPDATE_REFRESH() \n
  *   NUTAG_USER_AGENT() \n
  *   SIPTAG_ALLOW() \n
@@ -1515,6 +1523,7 @@
 			 tagi_t const *tags)
 {
   nua_handle_t *dnh = nua->nua_dhandle;
+  nua_global_preferences_t const *ngp = nua->nua_prefs;
   nua_handle_preferences_t const *nhp = nh->nh_prefs;
 
   tagi_t *lst;
@@ -1540,8 +1549,6 @@
 
   enter;
 
-  su_home_auto(tmphome, sizeof(tmphome));
-
   nta_agent_get_params(nua->nua_nta,
 		       NTATAG_UDP_MTU_REF(udp_mtu),
 		       NTATAG_MAX_PROCEEDING_REF(max_proceeding),
@@ -1590,6 +1597,8 @@
 	     ? sip_##pref##_make(tmphome, (char *)nhp->nhp_##pref)	\
 	     : NULL))
 
+  su_home_auto(tmphome, sizeof(tmphome));
+
   lst = tl_filtered_tlist
     (tmphome, tags,
      TAG_IF(has_from, SIPTAG_FROM(from)),
@@ -1630,6 +1639,7 @@
      TIF(NUTAG_REFER_WITH_ID, refer_with_id),
 
      TIF(NUTAG_SUBSTATE, substate),
+     TIF(NUTAG_SUB_EXPIRES, sub_expires),
 
      TIF(SIPTAG_SUPPORTED, supported),
      TIF_STR(SIPTAG_SUPPORTED_STR, supported),
@@ -1658,11 +1668,18 @@
      TIF(NUTAG_M_PARAMS, m_params),
      TIF(NUTAG_M_FEATURES, m_features),
      TIF(NUTAG_OUTBOUND, outbound),
-     TIF(NUTAG_DETECT_NETWORK_UPDATES, detect_network_updates),
 
      /* Skip user-agent-level parameters if parameters are for handle only */
      TAG_IF(nh != dnh, TAG_NEXT(media_params)),
 
+  /* Include tag in the list returned to user
+   * if it has been earlier set (by user) */
+#define GIF(TAG, pref) \
+     TAG_IF(ngp->ngp_set.ngp_##pref, TAG(ngp->ngp_##pref))
+
+     GIF(NUTAG_DETECT_NETWORK_UPDATES, detect_network_updates),
+     GIF(NUTAG_SHUTDOWN_EVENTS, shutdown_events),
+
      NTATAG_CONTACT(m),
 
 #if HAVE_SOFIA_SMIME

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h	Tue Feb 26 12:00:03 2008
@@ -107,6 +107,7 @@
 
   /* Subscriber state, i.e. nua_substate_pending */
   unsigned         nhp_substate;
+  unsigned         nhp_sub_expires;
 
   /* REGISTER keepalive intervals */
   unsigned         nhp_keepalive, nhp_keepalive_stream;
@@ -127,9 +128,6 @@
   /** Outbound OPTIONS */
   char const         *nhp_outbound; 
   
-  /** Network detection: NONE, INFORMAL, TRY_FULL */
-  int                 nhp_detect_network_updates;
-  
   sip_allow_t        *nhp_appl_method;
 
   /** Initial route set */
@@ -137,6 +135,12 @@
 
   union { struct {
     /* A bit for each feature set by application */
+    /* NOTE: 
+       Some compilers behave weird if there are bitfields
+       together with width > 32 
+       So there should be a padding field (unsigned:0;) 
+       every 32 bits. 
+    */
     unsigned nhb_retry_count:1;
     unsigned nhb_max_subscriptions:1;
 
@@ -166,13 +170,15 @@
     unsigned nhb_refer_with_id:1;
     unsigned nhb_refer_expires:1;
     unsigned nhb_substate:1;
+    unsigned nhb_sub_expires:1;
     unsigned nhb_keepalive:1;
     unsigned nhb_keepalive_stream:1;
     unsigned nhb_registrar:1;
 
     unsigned nhb_allow:1;
+    unsigned :0;		/* at most 32 bits before this point */
     unsigned nhb_supported:1;
-    unsigned :0;		/* at most 32 bits ... */
+
     unsigned nhb_allow_events:1;
     unsigned nhb_user_agent:1;
     unsigned nhb_organization:1;
@@ -183,7 +189,6 @@
     unsigned nhb_m_features:1;
     unsigned nhb_instance:1;
     unsigned nhb_outbound:1;
-    unsigned nhb_detect_network_updates:1;
     unsigned nhb_appl_method:1;
     unsigned nhb_initial_route:1;
     unsigned :0;
@@ -194,6 +199,26 @@
 
 #define nhp_set nhp_set_.set_bits
 
+/** Global preferences for nua. */
+typedef struct {
+  /** Network detection: NONE, INFORMAL, TRY_FULL */
+  signed int ngp_detect_network_updates:3;
+  /** Pass events during shutdown, too */
+  int ngp_shutdown_events:1;
+
+  unsigned :0;			/* pad */
+  union { struct {
+    /* A bit for each feature set by application */
+    unsigned ngp_detect_network_updates:1;
+    unsigned ngp_shutdown_events:1;
+    unsigned :0;
+  } set_bits; 
+    unsigned set_unsigned[2];
+  } ngp_set_;
+} nua_global_preferences_t;
+
+#define ngp_set ngp_set_.set_bits
+
 #define DNHP_GET(dnhp, pref) ((dnhp)->nhp_##pref)
 
 #define NHP_GET(nhp, dnhp, pref)					\

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c	Tue Feb 26 12:00:03 2008
@@ -244,19 +244,21 @@
 				       sip_t const *sip);
 
 static nua_client_methods_t const nua_publish_client_methods = {
-  SIP_METHOD_PUBLISH,
-  0,
-  {
+  SIP_METHOD_PUBLISH,		/* crm_method, crm_method_name */
+  0,				/* crm_extra */
+  {				/* crm_flags */
     /* create_dialog */ 0,
     /* in_dialog */ 0,
     /* target refresh */ 0
   },
-  nua_publish_client_template,
-  nua_publish_client_init,
-  nua_publish_client_request,
-  nua_publish_client_check_restart,
-  nua_publish_client_response,
-  /* nua_publish_client_preliminary */ NULL
+  nua_publish_client_template,	/* crm_template */
+  nua_publish_client_init,	/* crm_init */
+  nua_publish_client_request,	/* crm_send */
+  nua_publish_client_check_restart, /* crm_check_restart */
+  nua_publish_client_response,	/* crm_recv */
+  NULL,				/* crm_preliminary */
+  NULL,				/* crm_report */
+  NULL,				/* crm_complete */
 };
 
 /**@internal Send PUBLISH. */

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c	Tue Feb 26 12:00:03 2008
@@ -570,18 +570,21 @@
 					sip_t const *sip);
 
 static nua_client_methods_t const nua_register_client_methods = {
-  SIP_METHOD_REGISTER,
-  0,
-  {
+  SIP_METHOD_REGISTER,		/* crm_method, crm_method_name */
+  0,				/* crm_extra */
+  {				/* crm_flags */
     /* create_dialog */ 1,
     /* in_dialog */ 0,
     /* target refresh */ 0
   },
-  nua_register_client_template,
-  nua_register_client_init,
-  nua_register_client_request,
-  nua_register_client_check_restart,
-  nua_register_client_response
+  nua_register_client_template,	/* crm_template */
+  nua_register_client_init,	/* crm_init */
+  nua_register_client_request,	/* crm_send */
+  nua_register_client_check_restart, /* crm_check_restart */
+  nua_register_client_response,	/* crm_recv */
+  NULL,				/* crm_preliminary */
+  NULL,				/* crm_report */
+  NULL,				/* crm_complete */
 };
 
 /**@internal Send REGISTER. */

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c	Tue Feb 26 12:00:03 2008
@@ -191,7 +191,7 @@
 				      nua_dialog_usage_t *);
 
 static int nua_invite_client_ack(nua_client_request_t *cr, tagi_t const *tags);
-static int nua_invite_client_deinit(nua_client_request_t *cr);
+static int nua_invite_client_complete(nua_client_request_t *cr);
 
 static nua_usage_class const nua_session_usage[1] = {
   {
@@ -238,7 +238,8 @@
 
   cr = du->du_cr;
 
-  if (cr && cr->cr_orq && cr->cr_status >= 200) {
+  if (cr && cr->cr_orq && cr->cr_status >= 200 && 
+      cr->cr_method == sip_method_invite) {
     ss->ss_reporting = 1;
     nua_invite_client_ack(cr, NULL);
     ss->ss_reporting = 0;
@@ -250,14 +251,17 @@
 
     if (cr->cr_method != sip_method_invite)
       continue;
+
     if (cr == du->du_cr)
       continue;
 
-    nua_stack_event(nh->nh_nua, nh, 
-		    NULL,
-		    cr->cr_event,
-		    SIP_481_NO_TRANSACTION,
-		    NULL);
+    if (cr->cr_status < 200) {
+      nua_stack_event(nh->nh_nua, nh, 
+		      NULL,
+		      cr->cr_event,
+		      SIP_481_NO_TRANSACTION,
+		      NULL);
+    }
 
     nua_client_request_destroy(cr);
 
@@ -542,21 +546,21 @@
 				    tagi_t const *tags);
 
 nua_client_methods_t const nua_invite_client_methods = {
-  SIP_METHOD_INVITE,
-  0,
-  { 
+  SIP_METHOD_INVITE,		/* crm_method, crm_method_name */
+  0,				/* crm_extra */
+  {				/* crm_flags */
     /* create_dialog */ 1,
     /* in_dialog */ 1,
     /* target refresh */ 1
   },
-  NULL,
-  nua_invite_client_init,
-  nua_invite_client_request,
-  session_timer_check_restart,
-  nua_invite_client_response,
-  nua_invite_client_preliminary,
-  nua_invite_client_report,
-  nua_invite_client_deinit
+  NULL,				/* crm_template */
+  nua_invite_client_init,	/* crm_init */
+  nua_invite_client_request,	/* crm_send */
+  session_timer_check_restart,	/* crm_check_restart */
+  nua_invite_client_response,	/* crm_recv */
+  nua_invite_client_preliminary, /* crm_preliminary */
+  nua_invite_client_report,	/* crm_report */
+  nua_invite_client_complete,	/* crm_complete */
 };
 
 extern nua_client_methods_t const nua_bye_client_methods;
@@ -604,10 +608,15 @@
   if (!du)
     return -1;
 
+  ss = nua_dialog_usage_private(du);
+
+  if (ss->ss_state >= nua_callstate_terminating)
+    return nua_client_return(cr, 900, "Session is terminating", msg);
+
   if (nua_client_bind(cr, du) < 0)
     return nua_client_return(cr, 900, "INVITE already in progress", msg);
 
-  ss = nua_dialog_usage_private(du);
+  cr->cr_neutral = 0;
 
   session_timer_preferences(ss->ss_timer,
 			    sip,
@@ -617,8 +626,6 @@
 			    NH_PGET(nh, refresher),
 			    NH_PGET(nh, min_se));
 
-  cr->cr_neutral = 0;
-
   return 0;
 }
 
@@ -635,6 +642,9 @@
   if (du == NULL)		/* Call terminated */ 
     return nua_client_return(cr, SIP_481_NO_TRANSACTION, msg);
 
+  if (ss->ss_state >= nua_callstate_terminating)
+    return nua_client_return(cr, 900, "Session is terminating", msg);
+
   assert(ss);
 
   invite_timeout = NH_PGET(nh, invite_timeout);
@@ -1047,7 +1057,7 @@
   if (error < 0) {
     if (ss->ss_reason == NULL)
       ss->ss_reason = "SIP;cause=500;text=\"Internal Error\"";
-    ss->ss_reporting = 1;	/* We report state here if BYE fails */
+    ss->ss_reporting = 1;	/* We report terminated state here if BYE fails */
     error = nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL);
     ss->ss_reporting = 0;
     signal_call_state_change(nh, ss, 500, "Internal Error", 
@@ -1090,6 +1100,7 @@
   char const *invite_branch;
 
   assert(cr->cr_orq);
+  assert(cr->cr_method == sip_method_invite);
 
 
   if (!ds->ds_leg) {
@@ -1226,8 +1237,8 @@
   return error;
 }
 
-/** Deinitialize client request */
-static int nua_invite_client_deinit(nua_client_request_t *cr)
+/** Complete client request */
+static int nua_invite_client_complete(nua_client_request_t *cr)
 {
   if (cr->cr_orq == NULL)
     /* Xyzzy */;
@@ -1263,18 +1274,21 @@
 				     tagi_t const *tags);
 
 nua_client_methods_t const nua_cancel_client_methods = {
-  SIP_METHOD_CANCEL,
-  0,
-  { 
+  SIP_METHOD_CANCEL,		/* crm_method, crm_method_name */
+  0,				/* crm_extra */
+  {				/* crm_flags */
     /* create_dialog */ 0,
     /* in_dialog */ 1,
     /* target refresh */ 0
   },
-  NULL,
-  NULL,
-  nua_cancel_client_request,
-  /* nua_cancel_client_check_restart */ NULL,
-  /* nua_cancel_client_response */ NULL
+  NULL,				/* crm_template */
+  NULL,				/* crm_init */
+  nua_cancel_client_request,	/* crm_send */
+  NULL,				/* crm_check_restart */
+  NULL,				/* crm_recv */
+  NULL,				/* crm_preliminary */
+  NULL,				/* crm_report */
+  NULL,				/* crm_complete */
 };
 
 int nua_stack_cancel(nua_t *nua, nua_handle_t *nh, nua_event_t e,
@@ -1493,20 +1507,21 @@
 				   tagi_t const *tags);
 
 nua_client_methods_t const nua_prack_client_methods = {
-  SIP_METHOD_PRACK,
-  0,
-  { 
+  SIP_METHOD_PRACK,		/* crm_method, crm_method_name */
+  0,				/* crm_extra */
+  {				/* crm_flags */
     /* create_dialog */ 0,
     /* in_dialog */ 1,
     /* target refresh */ 0
   },
-  NULL,
-  nua_prack_client_init,
-  nua_prack_client_request,
-  /* nua_prack_client_check_restart */ NULL,
-  nua_prack_client_response,
-  NULL,
-  nua_prack_client_report
+  NULL,				/* crm_template */
+  nua_prack_client_init,	/* crm_init */
+  nua_prack_client_request,	/* crm_send */
+  NULL,				/* crm_check_restart */
+  nua_prack_client_response,	/* crm_recv */
+  NULL,				/* crm_preliminary */
+  nua_prack_client_report,	/* crm_report */
+  NULL,				/* crm_complete */
 };
 
 int nua_stack_prack(nua_t *nua, nua_handle_t *nh, nua_event_t e,
@@ -1542,6 +1557,8 @@
   if (du == NULL)		/* Call terminated */
     return nua_client_return(cr, SIP_481_NO_TRANSACTION, msg);
   assert(ss);
+  if (ss->ss_state >= nua_callstate_terminating)
+    return nua_client_return(cr, 900, "Session is terminating", msg);
 
   cri = du->du_cr;
 
@@ -1820,6 +1837,7 @@
 {
   nua_handle_t *nh = sr->sr_owner;
   nua_t *nua = nh->nh_nua;
+  nua_session_usage_t *ss;
 
   sr->sr_neutral = 1;
 
@@ -1858,6 +1876,15 @@
 	/* Glare - RFC 3261 14.2 and RFC 3311 section 5.2 */
 	return SR_STATUS1(sr, SIP_491_REQUEST_PENDING);
     }
+
+    ss = nua_dialog_usage_private(sr->sr_usage);
+
+    if (ss->ss_state < nua_callstate_completed &&
+	ss->ss_state != nua_callstate_init) {
+      /* We should never trigger this, 
+	 but better not to assert() on network input */
+      return nua_server_retry_after(sr, 500, "Overlapping Requests 2", 0, 10);
+    }
   }
 
   sr->sr_neutral = 0;
@@ -1887,6 +1914,11 @@
     /* UPDATE/PRACK sent within an existing dialog? */
     return SR_STATUS(sr, 481, "Call Does Not Exist");
   }
+  else if (sr->sr_usage) {
+    nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage);
+    if (ss->ss_state >= nua_callstate_terminating)
+      return SR_STATUS(sr, 481, "Call is being terminated");
+  }
 
   if (nh->nh_soa) {
     sip_accept_t *a = nua->nua_invite_accept;
@@ -1972,8 +2004,10 @@
 
   session_timer_store(ss->ss_timer, request);
 
-  if (!(ss->ss_state >= nua_callstate_ready || ss->ss_state == nua_callstate_init)) 
-    return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
+#if 0 /* The glare and overlap tests should take care of this. */
+  assert(ss->ss_state >= nua_callstate_completed ||
+	 ss->ss_state == nua_callstate_init);
+#endif
 
   if (NH_PGET(nh, auto_answer) ||
       /* Auto-answer to re-INVITE unless auto_answer is set to 0 on handle */
@@ -2319,7 +2353,7 @@
       nua_stack_event(nh->nh_nua, nh, NULL,
 		      nua_i_media_error, status, phrase, NULL);
 
-      ss->ss_reporting = 1;	/* We report state here if BYE fails */
+      ss->ss_reporting = 1;	/* We report terminated state here if BYE fails */
       error = nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL);
       ss->ss_reporting = 0;
 
@@ -2416,7 +2450,7 @@
   /* send BYE, too, if 200 OK (or 183 to re-INVITE) timeouts  */
   ss->ss_reason = reason;
 
-  ss->ss_reporting = 1;		/* We report state here if BYE fails */
+  ss->ss_reporting = 1;		/* We report terminated state here if BYE fails */
   error = nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL);
   ss->ss_reporting = 0;
 
@@ -2787,18 +2821,21 @@
 				   tagi_t const *tags);
 
 nua_client_methods_t const nua_info_client_methods = {
-  SIP_METHOD_INFO,
-  0,
-  { 
+  SIP_METHOD_INFO,		/* crm_method, crm_method_name */
+  0,				/* crm_extra */
+  {				/* crm_flags */
     /* create_dialog */ 0,
     /* in_dialog */ 1,
     /* target refresh */ 0
   },
-  /*nua_info_client_template*/ NULL,
-  nua_info_client_init,
-  nua_info_client_request,
-  /*nua_info_client_check_restart*/ NULL,
-  /*nua_info_client_response*/ NULL
+  NULL,				/* crm_template */
+  nua_info_client_init,		/* crm_init */
+  nua_info_client_request,	/* crm_send */
+  NULL,				/* crm_check_restart */
+  NULL,				/* crm_recv */
+  NULL,				/* crm_preliminary */
+  NULL,				/* crm_report */
+  NULL,				/* crm_complete */
 };
 
 int
@@ -2934,20 +2971,21 @@
 				    tagi_t const *tags);
 
 nua_client_methods_t const nua_update_client_methods = {
-  SIP_METHOD_UPDATE,
-  0,				/* size of private data */
-  { 
+  SIP_METHOD_UPDATE,		/* crm_method, crm_method_name */
+  0,				/* crm_extrasize of private data */
+  {				/* crm_flags */
     /* create_dialog */ 0,
     /* in_dialog */ 1,
     /* target refresh */ 1
   },
-  NULL,
-  nua_update_client_init,
-  nua_update_client_request,
-  session_timer_check_restart,
-  nua_update_client_response,
-  NULL,
-  nua_update_client_report
+  NULL,				/* crm_template */
+  nua_update_client_init,	/* crm_init */
+  nua_update_client_request,	/* crm_send */
+  session_timer_check_restart,	/* crm_check_restart */
+  nua_update_client_response,	/* crm_recv */
+  NULL,				/* crm_preliminary */
+  nua_update_client_report,	/* crm_report */
+  NULL,				/* crm_complete */
 };
 
 int nua_stack_update(nua_t *nua, nua_handle_t *nh, nua_event_t e,
@@ -2982,6 +3020,8 @@
   if (du == NULL)		/* Call terminated */
     return nua_client_return(cr, SIP_481_NO_TRANSACTION, msg);
   assert(ss);
+  if (ss->ss_state >= nua_callstate_terminating)
+    return nua_client_return(cr, 900, "Session is terminating", msg);
 
   cri = du->du_cr;
 
@@ -3397,20 +3437,21 @@
 				 tagi_t const *tags);
 
 nua_client_methods_t const nua_bye_client_methods = {
-  SIP_METHOD_BYE,
-  0,
-  { 
+  SIP_METHOD_BYE,		/* crm_method, crm_method_name */
+  0,				/* crm_extrasize */
+  {				/* crm_flags */
     /* create_dialog */ 0,
     /* in_dialog */ 1,
     /* target refresh */ 0
   },
-  NULL,
-  nua_bye_client_init,
-  nua_bye_client_request,
-  /*nua_bye_client_check_restart*/ NULL,
-  /*nua_bye_client_response*/ NULL,
-  /*nua_bye_client_preliminary*/ NULL,
-  nua_bye_client_report
+  NULL,				/* crm_template */
+  nua_bye_client_init,		/* crm_init */
+  nua_bye_client_request,	/* crm_send */
+  NULL,				/* crm_check_restart */
+  NULL,				/* crm_recv */
+  NULL,				/* crm_preliminary */
+  nua_bye_client_report,	/* crm_report */
+  NULL,				/* crm_complete */
 };
 
 int
@@ -3443,7 +3484,9 @@
 
   if (nh->nh_soa)
     soa_terminate(nh->nh_soa, 0);
-  cr->cr_usage = du;
+
+  du->du_cr = NULL;
+  nua_client_bind(cr, du);
 
   return 0;
 }
@@ -3515,17 +3558,23 @@
   else {
     nua_session_usage_t *ss = nua_dialog_usage_private(du);
 
+    if (ss->ss_reporting) {
+      return 1;			/* Somebody else's problem */
+    }
+    else if (cr->cr_waiting) {
+      return 1; /* Application problem */
+    }
+
     signal_call_state_change(nh, ss, status, "to BYE", 
 			     nua_callstate_terminated);
 
-    if (ss && !ss->ss_reporting) {
-      if (du->du_cr == NULL ||
-	  !nua_client_is_queued(du->du_cr) ||
-	  du->du_cr->cr_status >= 200) {
-	/* INVITE is completed, we can zap the session... */;
-	cr->cr_usage = NULL;
-	nua_session_usage_destroy(nh, ss);
-      }
+    if (du && 
+	(du->du_cr == NULL ||
+	 !nua_client_is_queued(du->du_cr) ||
+	 du->du_cr->cr_status >= 200)) {
+      /* INVITE is completed, we can zap the session... */;
+      cr->cr_usage = NULL;
+      nua_session_usage_destroy(nh, ss);
     }
   }
 

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c	Tue Feb 26 12:00:03 2008
@@ -209,7 +209,7 @@
   if (nua_stack_set_from(nua, 1, nua->nua_args) < 0)
     return -1;
 
-  if (NHP_ISSET(dnh->nh_prefs, detect_network_updates))
+  if (nua->nua_prefs->ngp_detect_network_updates)
     nua_stack_launch_network_change_detector(nua);
 
   nua_stack_timer(nua, nua->nua_timer, NULL);
@@ -293,7 +293,8 @@
   if ((event > nua_r_authenticate && event <= nua_r_ack)
       || event < nua_i_error
       || (nh && !nh->nh_valid)
-      ) {
+      || (nua->nua_shutdown && event != nua_r_shutdown && 
+	  !nua->nua_prefs->ngp_shutdown_events)) {
     if (msg)
       msg_destroy(msg);
     return event;
@@ -2075,6 +2076,13 @@
   return cr;
 }
 
+void nua_client_request_complete(nua_client_request_t *cr)
+{
+  nua_client_request_remove(cr);
+  if (cr && cr->cr_methods->crm_complete)
+    cr->cr_methods->crm_complete(cr);
+}
+
 void nua_client_request_destroy(nua_client_request_t *cr)
 {
   nua_handle_t *nh;
@@ -2082,14 +2090,12 @@
   if (cr == NULL)
     return;
 
-  if (cr->cr_methods->crm_deinit)
-    cr->cr_methods->crm_deinit(cr);
+  nua_client_request_complete(cr);
 
   nh = cr->cr_owner;
 
   nua_destroy_signal(cr->cr_signal);
 
-  nua_client_request_remove(cr);
   nua_client_bind(cr, NULL);
   
   if (cr->cr_msg)
@@ -2098,7 +2104,6 @@
 
   if (cr->cr_orq)
     nta_outgoing_destroy(cr->cr_orq);
-
   cr->cr_orq = NULL;
 
   if (cr->cr_timer)

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h	Tue Feb 26 12:00:03 2008
@@ -217,28 +217,31 @@
   su_clone_r   	       nua_clone;
   su_task_r            nua_client;
 
-  su_network_changed_t *nua_nw_changed;
-
   nua_callback_f       nua_callback;
   nua_magic_t         *nua_magic;
 
   nua_event_frame_t   *nua_current;
   nua_saved_event_t    nua_signal[1];
 
+  /**< Used by stop-and-wait args calls */
+  tagi_t const        *nua_args;
+
   /* Engine state flags */
+  sip_time_t           nua_shutdown;
+
   unsigned             nua_shutdown_started:1; /**< Shutdown initiated */
   unsigned             nua_shutdown_final:1; /**< Shutdown is complete */
 
   unsigned             nua_from_is_set;
   unsigned :0;
   
-  /**< Used by stop-and-wait args calls */
-  tagi_t const        *nua_args;
-
   /**< Local SIP address. Contents are kept around for ever. */
-  sip_from_t          nua_from[1];
+  sip_from_t           nua_from[1];
+
+  /* ---------------------------------------------------------------------- */
 
   /* Protocol (server) side */
+  su_network_changed_t *nua_nw_changed;
 
   nua_registration_t *nua_registrations; /**< Active registrations */
 
@@ -250,21 +253,8 @@
   nta_agent_t        *nua_nta;
   su_timer_t         *nua_timer;
 
-  void         	      *nua_sip_parser;
-
-  sip_time_t           nua_shutdown;
-
-  /* Route */
-  sip_service_route_t *nua_service_route;
-
   /* User-agent parameters */
-  unsigned             nua_media_enable:1;
-
-  unsigned     	       :0;
-
-#if HAVE_SMIME		/* Start NRC Boston */
-  sm_object_t          *sm;
-#endif                  /* End NRC Boston */
+  nua_global_preferences_t nua_prefs[1];
 
   nua_handle_t        *nua_handles;
   nua_handle_t       **nua_handles_tail;

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c	Tue Feb 26 12:00:03 2008
@@ -183,18 +183,21 @@
 					 sip_t const *sip);
 
 static nua_client_methods_t const nua_subscribe_client_methods = {
-  SIP_METHOD_SUBSCRIBE,
-  0,
-  { 
+  SIP_METHOD_SUBSCRIBE,		/* crm_method, crm_method_name */
+  0,				/* crm_extra */
+  {				/* crm_flags */
     /* create_dialog */ 1,
     /* in_dialog */ 1,
     /* target refresh */ 1
   },
-  NULL,
-  nua_subscribe_client_init,
-  nua_subscribe_client_request,
-  /* nua_subscribe_client_check_restart */ NULL,
-  nua_subscribe_client_response
+  NULL,				/* crm_template */
+  nua_subscribe_client_init,	/* crm_init */
+  nua_subscribe_client_request,	/* crm_send */
+  NULL,				/* crm_check_restart */
+  nua_subscribe_client_response, /* crm_recv */
+  NULL,				/* crm_preliminary */
+  NULL,				/* crm_report */
+  NULL,				/* crm_complete */
 };
 
 int
@@ -368,6 +371,9 @@
     else
       delta = 0;
 
+    if (delta > eu->eu_expires)
+      delta = eu->eu_expires;
+
     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, "");
@@ -647,8 +653,6 @@
     if (substate == nua_substate_active || substate == nua_substate_pending) {
       if (subs && subs->ss_expires)
 	delta = strtoul(subs->ss_expires, NULL, 10);
-      else
-	delta = eu->eu_expires;
     }
     else if (substate == nua_substate_embryonic) {
       if (subs && subs->ss_reason) {
@@ -686,7 +690,8 @@
     nua_dialog_usage_set_refresh_range(du, retry, retry + 5);
   }
   else {
-    nua_dialog_usage_set_refresh(du, delta);
+    if (delta < SIP_TIME_MAX)
+      nua_dialog_usage_set_refresh(du, delta);
   }
 
   return retval;
@@ -777,20 +782,21 @@
 				     sip_t const *sip);
 
 static nua_client_methods_t const nua_refer_client_methods = {
-  SIP_METHOD_REFER,
-  0,
-  { 
+  SIP_METHOD_REFER,		/* crm_method, crm_method_name */
+  0,				/* crm_extra */
+  {				/* crm_flags */
     /* create_dialog */ 1,
     /* in_dialog */ 1,
     /* target refresh */ 1
   },
-  /*nua_refer_client_template*/ NULL,
-  nua_refer_client_init,
-  nua_refer_client_request,
-  /* nua_refer_client_check_restart */ NULL,
-  nua_refer_client_response,
-  nua_refer_client_response,	/* Preliminary */
-  NULL
+  NULL,				/* crm_template */
+  nua_refer_client_init,	/* crm_init */
+  nua_refer_client_request,	/* crm_send */
+  NULL,				/* crm_check_restart */
+  nua_refer_client_response,	/* crm_recv */
+  nua_refer_client_response,	/* crm_preliminary */
+  NULL,				/* crm_report */
+  NULL,				/* crm_complete */
 };
 
 int

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c	Tue Feb 26 12:00:03 2008
@@ -227,21 +227,22 @@
  * - NUTAG_ALLOW_EVENTS(), SIPTAG_ALLOW_EVENTS(), and
  *                          SIPTAG_ALLOW_EVENTS_STR()
  * - NUTAG_MAX_SUBSCRIPTIONS()
- * - NUTAG_SUBSTATE()
+ * - NUTAG_SUBSTATE(), NUTAG_SUB_EXPIRES()
  * @par Specifications
  * - @RFC3265
  *
  * @par SIP Event Subscriber
  * - nua_subscribe(), #nua_r_subscribe, #nua_i_notify, NUTAG_SUBSTATE(),
- *   SIPTAG_EVENT(), SIPTAG_EXPIRES(),
+ *   SIPTAG_EVENT(), SIPTAG_EXPIRES()
  * - nua_unsubscribe(), #nua_r_unsubscribe()
  * @par Specifications
  * - @RFC3265
  *
  * @par SIP Event Notifier
  * - #nua_i_subscribe(), nua_notify(), #nua_r_notify,
- *   NUTAG_SUBSTATE(), SIPTAG_EVENT()
+ *   NUTAG_SUBSTATE(), NUTAG_SUB_EXPIRES(), SIPTAG_EVENT()
  * Settings:
+ * - NUTAG_SUB_EXPIRES()
  * - NUTAG_ALLOW_EVENTS(), SIPTAG_ALLOW_EVENTS(), and
  *                          SIPTAG_ALLOW_EVENTS_STR()
  * - NUTAG_ALLOW("SUBSCRIBE"), NUTAG_APPL_METHOD("SUBSCRIBE")
@@ -267,6 +268,8 @@
  * Settings:
  * - NUTAG_ALLOW(x), NUTAG_APPL_METHOD(x)
  *
+ * @par Server Shutdown
+ * - nua_shutdown(), NUTAG_SHUTDOWN_EVENTS(), nua_destroy().
  */
 
 /* @par S/MIME
@@ -767,14 +770,14 @@
  *
  * @par Used with
  * - with nua_create(), nua_set_params(), nua_get_params(),
- *    nua_handle(), nua_set_hparams(), nua_get_hparams(), and
- *    nua_notifier() to change the default subscription state returned by
- *    the intenal event server
+ *   nua_handle(), nua_set_hparams(), nua_get_hparams(), and
+ *   nua_notifier() to change the default subscription state returned by
+ *   the internal event server
  * - with nua_notify() and nua_respond() to SUBSCRIBE to determine the
- *    subscription state (if application include @SubscriptionState
- *    header in the tag list, the NUTAG_SUBSTATE() value is ignored)
+ *   subscription state (if application include @SubscriptionState
+ *   header in the tag list, the NUTAG_SUBSTATE() value is ignored)
  * - with #nua_r_subscribe, #nua_i_notify, #nua_i_subscribe, and #nua_r_notify
- *    to indicate the current subscription state
+ *   to indicate the current subscription state
  *
  * @par Parameter type
  *    int
@@ -806,6 +809,39 @@
  */
 
 
+/**@def NUTAG_SUB_EXPIRES()
+ *
+ * Default expiration time of subscriptions.
+ *
+ * @par Used with
+ * - with nua_create(), nua_set_params(), nua_get_params(), nua_handle(),
+ *   nua_set_hparams(), nua_get_hparams(), nua_respond(), nua_notify(), and
+ *   nua_notifier() to change the default expiration time of subscriptions
+ *
+ * @par Parameter type
+ *    unsigned int
+ *
+ * @par Values
+ *   - default expiration time in seconds
+ *
+ * Note that the expires parameter in @SubscriptionState or @Expires header
+ * in the nua_response() to the SUBSCRIBE overrides the default subscription
+ * expiration specified by NUTAG_SUB_EXPIRES().
+ *
+ * @sa @RFC3265, NUTAG_REFER_EXPIRES(), @Expires, SIPTAG_EXPIRES(),
+ * SIPTAG_EXPIRES_STR(), @SubscriptionState, nua_respond(), nua_notifier(),
+ * #nua_r_subscribe, #nua_i_subscribe, #nua_r_refer, #nua_r_notify,
+ * #nua_i_notify.
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SUB_EXPIRES_REF().
+ */
+tag_typedef_t nutag_sub_expires = UINTTAG_TYPEDEF(substate);
+
+/**@def NUTAG_SUB_EXPIRES_REF(x) 
+ * Reference tag for NUTAG_SUB_EXPIRES().
+ */
+
+
 /**@def NUTAG_NEWSUB()
  *
  * Send unsolicited NOTIFY request.
@@ -1075,17 +1111,17 @@
  * REFER.
  *
  * @par Used with
- *    nua_set_params() \n
- *    nua_get_params() \n
- *    nua_set_hparams() \n
- *    nua_get_hparams() \n
+ *    nua_handle(), nua_respond() \n
+ *    nua_set_params() or nua_set_hparams() \n
+ *    nua_get_params() or nua_get_hparams()
  *
  * @par Parameter type
  *    unsigned int
  *
  * @par Values
- *    @c 0  disable \n
- *    @c >0 interval in seconds
+ *    - default interval in seconds
+ *
+ * @sa NUTAG_SUB_EXPIRES()
  *
  * Corresponding tag taking reference parameter is NUTAG_REFER_EXPIRES_REF().
  */
@@ -1570,6 +1606,9 @@
  * NUTAG_INITIAL_ROUTE_STR() tags, the route set is constructed from them
  * all.
  *
+ * The initial route is inserted into request message before the route
+ * entries set with SIPTAG_ROUTE() or SIPTAG_ROUTE_STR().
+ *
  * @par Used with
  *    nua_set_params() \n
  *    nua_set_hparams() \n
@@ -2736,6 +2775,39 @@
  * Reference tag for NUTAG_SIP_PARSER().
  */
 
+
+/**@def NUTAG_SHUTDOWN_EVENTS(x)
+ *
+ * Allow passing of normal events when stack is being shut down.
+ *
+ * By default, only #nua_r_shutdown events are passed to application after
+ * calling nua_shutdown(). If application is interested in nua events during
+ * shutdown, it should give NUTAG_SHUTDOWN_EVENTS(1) to nua_create() or
+ * nua_set_params() called before nua_shutdown().
+ *
+ * @par Used with
+ *    nua_create(), nua_set_params().
+ *
+ * @par Parameter type
+ *    int (boolean)
+ *
+ * @par Values
+ *    @c 0   False \n
+ *    @c !=0 True
+ *
+ * Corresponding tag taking reference parameter is NUTAG_SHUTDOWN_EVENTS_REF().
+ *
+ * @sa nua_shutdown(), nua_destroy().
+ * 
+ * @NEW_1_12_9.
+ */
+tag_typedef_t nutag_shutdown_events = BOOLTAG_TYPEDEF(shutdown_events);
+
+/**@def NUTAG_SHUTDOWN_EVENTS_REF(x) 
+ * Reference tag for NUTAG_SHUTDOWN_EVENTS().
+ */
+
+
 /* ---------------------------------------------------------------------- */
 
 tag_typedef_t nutag_soa_session = PTRTAG_TYPEDEF(soa_session);

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h	Tue Feb 26 12:00:03 2008
@@ -497,12 +497,16 @@
 /** Convert string to enum nua_substate. @NEW_1_12_5. */
 SOFIAPUBFUN enum nua_substate nua_substate_make(char const *sip_substate);
 
+#define NUTAG_SUB_EXPIRES(x) nutag_sub_expires, tag_uint_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_sub_expires;
+#define NUTAG_SUB_EXPIRES_REF(x) nutag_sub_expires_ref, tag_uint_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_sub_expires_ref;
+
 #define NUTAG_NEWSUB(x)   nutag_newsub, tag_bool_v(x)
 SOFIAPUBVAR tag_typedef_t nutag_newsub;
 #define NUTAG_NEWSUB_REF(x) nutag_newsub_ref, tag_bool_vr(&(x))
 SOFIAPUBVAR tag_typedef_t nutag_newsub_ref;
 
-
 #define NUTAG_REFER_EXPIRES(x)  nutag_refer_expires, tag_uint_v((x))
 SOFIAPUBVAR tag_typedef_t nutag_refer_expires;
 #define NUTAG_REFER_EXPIRES_REF(x) nutag_refer_expires_ref, tag_uint_vr((&(x)))
@@ -569,6 +573,13 @@
           nutag_detect_network_updates_ref, tag_int_vr(&(x))
 SOFIAPUBVAR tag_typedef_t nutag_detect_network_updates_ref;
 
+#define NUTAG_SHUTDOWN_EVENTS(x) \
+  nutag_shutdown_events, tag_bool_v(x)
+SOFIAPUBVAR tag_typedef_t nutag_shutdown_events;
+#define NUTAG_SHUTDOWN_EVENTS_REF(x) \
+  nutag_shutdown_events_ref, tag_bool_vr(&(x))
+SOFIAPUBVAR tag_typedef_t nutag_shutdown_events_ref;
+
 /* Pass nua handle as tagged argument */
 #if SU_INLINE_TAG_CAST
 su_inline tag_value_t nutag_handle_v(nua_handle_t *v) { return (tag_value_t)v; }

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c	Tue Feb 26 12:00:03 2008
@@ -726,9 +726,8 @@
       if (e->data->e_event == nua_r_bye) {
 	TEST_E(e->data->e_event, nua_r_bye);
 	TEST(e->data->e_status, 200);
-	TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
-	TEST(callstate(e->data->e_tags), nua_callstate_terminated);
 	bye = 0;
+	break;
       }
       else if (e->data->e_event == nua_r_invite) {
 	TEST_E(e->data->e_event, nua_r_invite);
@@ -741,7 +740,10 @@
 	cancel = 0;
       }
     }
+    TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+    TEST(callstate(e->data->e_tags), nua_callstate_terminated);
   }
+
   TEST_1(!e->next);
 
   free_events_in_list(ctx, a->events);

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c	Tue Feb 26 12:00:03 2008
@@ -1133,7 +1133,7 @@
    Server transitions:
    INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
    RECEIVED -(S2a)-> EARLY: nua_respond(180), nua_i_state
-   EARLY -(S6b)--> TERMINATED: nua_i_cancel, nua_i_state
+   EARLY -(S6b)--> TERMINATED: nua_i_bye, nua_i_state
   */
   TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
   TEST(e->data->e_status, 100);
@@ -1423,6 +1423,79 @@
   return 0;
 }
 
+int test_bye_with_407(struct context *ctx)
+{
+  BEGIN();
+  struct endpoint *a = &ctx->a,  *c = &ctx->c;
+  struct call *a_call = a->call, *c_call = c->call;
+  struct event *e;
+
+  a_call->sdp = "m=audio 5008 RTP/AVP 8";
+  c_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+/* BYE after receiving 401
+
+   A			C
+   |-------INVITE------>|
+   |<----100 Trying-----|
+   |			|
+   |<----180 Ringing----|
+   |<-------200---------|
+   |--------ACK-------->|
+   |			|
+   |       |<----BYE----|
+   |       |-----407--->|
+   |<-------BYE---------|
+   |--------200-------->|
+   |			|
+*/
+  if (print_headings)
+    printf("TEST NUA-6.4.5: BYE with 407\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(c->to), TAG_END()));
+
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(c->contact->m_url)),
+	 SIPTAG_SUBJECT_STR("NUA-6.4.2"),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 NUTAG_AUTOANSWER(0),
+	 NUTAG_APPL_METHOD("UPDATE"),
+	 TAG_END());
+
+  run_abc_until(ctx, -1, until_ready, -1, NULL, -1, accept_call);
+
+  free_events_in_list(ctx, a->events);
+
+  TEST_1(e = c->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  free_events_in_list(ctx, c->events);
+
+  BYE(c, c_call, c_call->nh, 
+      TAG_END());
+  run_c_until(ctx, -1, save_until_final_response);
+
+  TEST_1(nua_handle_has_active_call(a_call->nh));
+  TEST_1(nua_handle_has_active_call(c_call->nh));
+
+  free_events_in_list(ctx, a->events);
+  free_events_in_list(ctx, c->events);
+
+  AUTHENTICATE(c, c_call, c_call->nh, 
+	       NUTAG_AUTH("Digest:\"test-proxy\":charlie:secret"), TAG_END());
+  
+  run_abc_until(ctx, -1, until_terminated, -1, NULL, -1, until_terminated);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  free_events_in_list(ctx, c->events);
+  nua_handle_destroy(c_call->nh), c_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-6.4.5: PASSED\n");
+
+  END();
+}
+
 int test_bye_to_invalid_contact(struct context *ctx)
 {
   BEGIN();
@@ -1576,6 +1649,7 @@
 int test_early_bye(struct context *ctx)
 {
   return 
+    test_bye_with_407(ctx) ||
     test_bye_before_200(ctx) ||
     test_bye_before_ack(ctx) ||
     test_bye_after_receiving_401(ctx) ||

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_init.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_init.c	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_init.c	Tue Feb 26 12:00:03 2008
@@ -151,8 +151,11 @@
 			      AUTHTAG_ALGORITHM("md5"),
 			      AUTHTAG_NEXT_EXPIRES(60),
 			      AUTHTAG_MAX_NCOUNT(1),
+			      AUTHTAG_ALLOW("ACK, CANCEL"),
 			      TAG_END());
 
+      test_proxy_domain_set_record_route(ctx->c.domain, 1);
+
       ctx->proxy_tests = 1;
     }
 

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua_params.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua_params.c	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua_params.c	Tue Feb 26 12:00:03 2008
@@ -203,6 +203,7 @@
 		 NUTAG_REFER_EXPIRES(333),
 		 NUTAG_REFER_WITH_ID(0),
 		 NUTAG_SUBSTATE(nua_substate_pending),
+		 NUTAG_SUB_EXPIRES(3700),
 
 		 NUTAG_KEEPALIVE(66),
 		 NUTAG_KEEPALIVE_STREAM(33),
@@ -284,6 +285,7 @@
     int auth_cache = -1;
     unsigned refer_expires = (unsigned)-1;
     int refer_with_id = -1;
+    unsigned sub_expires = (unsigned)-1;
     int substate = -1;
 
     sip_allow_t const *allow = NONE;
@@ -352,6 +354,7 @@
 	       	NUTAG_REFER_EXPIRES_REF(refer_expires),
 	       	NUTAG_REFER_WITH_ID_REF(refer_with_id),
 	       	NUTAG_SUBSTATE_REF(substate),
+		NUTAG_SUB_EXPIRES_REF(sub_expires),
 
 	       	SIPTAG_SUPPORTED_REF(supported),
 	       	SIPTAG_SUPPORTED_STR_REF(supported_str),
@@ -382,7 +385,7 @@
 		NUTAG_INSTANCE_REF(instance),
 
 		TAG_END());
-    TEST(n, 50);
+    TEST(n, 51);
 
     TEST_S(sip_header_as_string(tmphome, (void *)from), Alice);
     TEST_S(from_str, Alice);
@@ -416,6 +419,7 @@
     TEST(refer_expires, 333);
     TEST(refer_with_id, 0);
     TEST(substate, nua_substate_pending);
+    TEST(sub_expires, 3700);
 
     TEST_S(sip_header_as_string(tmphome, (void *)allow), "OPTIONS, INFO, ACK");
     TEST_S(allow_str, "OPTIONS, INFO, ACK");
@@ -492,6 +496,7 @@
     unsigned refer_expires = (unsigned)-1;
     int refer_with_id = -1;
     int substate = -1;
+    unsigned sub_expires = (unsigned)-1;
 
     sip_allow_t const *allow = NONE;
     char const   *allow_str = "NONE";
@@ -552,6 +557,7 @@
 	       	NUTAG_PATH_ENABLE_REF(path_enable),
 		NUTAG_AUTH_CACHE_REF(auth_cache),
 	       	NUTAG_SUBSTATE_REF(substate),
+	       	NUTAG_SUB_EXPIRES_REF(sub_expires),
 
 	       	SIPTAG_SUPPORTED_REF(supported),
 	       	SIPTAG_SUPPORTED_STR_REF(supported_str),
@@ -607,6 +613,7 @@
     TEST(refer_expires, (unsigned)-1);
     TEST(refer_with_id, -1);
     TEST(substate, -1);
+    TEST(sub_expires, -1);
 
     TEST_P(allow, NONE);
     TEST_S(allow_str, "NONE");

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c	Tue Feb 26 12:00:03 2008
@@ -135,6 +135,7 @@
     sip_time_t min_expires, expires, max_expires;
     int outbound_tcp;		/**< Use inbound TCP connection as outbound */
     char const *authorize;	/**< Authorization realm to use */
+    int record_route;
   } prefs;  
 
   tagi_t *tags;
@@ -478,6 +479,23 @@
   }
 }
 
+void test_proxy_domain_set_record_route(struct domain *d,
+					int use_record_route)
+{
+  if (d) {
+    d->prefs.record_route = use_record_route;
+  }
+}
+
+void test_proxy_domain_get_record_route(struct domain *d,
+					int *return_use_record_route)
+{
+  if (d) {
+    if (return_use_record_route)
+      *return_use_record_route = d->prefs.record_route;
+  }
+}
+
 int test_proxy_domain_set_authorize(struct domain *d, 
 				     char const *realm)
 {
@@ -743,6 +761,9 @@
     if (t->method != sip_method_ack && t->method != sip_method_cancel)
       nta_incoming_bind(irq, proxy_ack_cancel, t);
 
+    if (domain && domain->prefs.record_route)
+      t->rr = 1;
+
     if (process(t) < 200)
       return 0;
 
@@ -818,6 +839,9 @@
     t->use_auth = 407;
   }
 
+  if (o && o->prefs.record_route)
+    t->rr = 1;
+
   return 0;
 }
 
@@ -841,7 +865,6 @@
 	  url_cmp(t->proxy->rr_uri, t->sip->sip_route->r_url) == 0)) {
     sip_route_remove(t->msg, t->sip);
     /* add record-route also to the forwarded request  */
-    t->rr = 1;			
   }
 
   if (t->use_auth)
@@ -947,12 +970,17 @@
 
   msg_header_insert(c->msg, (msg_pub_t *)c->sip, (msg_header_t *)c->rq);
 
-  if (t->rr && 0) {
+  if (t->rr) {
     sip_record_route_t rr[1];
 
-    *sip_record_route_init(rr)->r_url = *t->proxy->rr_uri;
-
-    msg_header_add_dup(c->msg, (msg_pub_t *)c->sip, (msg_header_t *)rr);    
+    if (t->proxy->rr_uri) {
+      *sip_record_route_init(rr)->r_url = *t->proxy->rr_uri;
+      msg_header_add_dup(c->msg, (msg_pub_t *)c->sip, (msg_header_t *)rr);
+    }
+    else if (t->proxy->lr) {
+      *sip_record_route_init(rr)->r_url = *t->proxy->lr->r_url;
+      msg_header_add_dup(c->msg, (msg_pub_t *)c->sip, (msg_header_t *)rr);
+    }
   }
 
   if (c->rq)

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.h
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.h	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.h	Tue Feb 26 12:00:03 2008
@@ -73,6 +73,11 @@
 void test_proxy_domain_get_outbound(struct domain *d,
 				    int *return_use_outbound);
 
+void test_proxy_domain_set_record_route(struct domain *d,
+					int use_record_route);
+void test_proxy_domain_get_record_route(struct domain *d,
+					int *return_use_record_route);
+
 int test_proxy_close_tports(struct proxy *p);
 
 SOFIA_END_DECLS

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_simple.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_simple.c	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_simple.c	Tue Feb 26 12:00:03 2008
@@ -45,6 +45,9 @@
 
 extern int accept_request(CONDITION_PARAMS);
 
+int save_until_nth_final_response(CONDITION_PARAMS);
+int accept_n_notifys(CONDITION_PARAMS);
+
 int test_message(struct context *ctx)
 {
   BEGIN();
@@ -564,6 +567,47 @@
     "</presence>\n";
 
 
+int accept_and_notify_twice(CONDITION_PARAMS)
+{
+  msg_t *with = nua_current_request(nua);
+
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (event) {
+  case nua_i_subscribe:
+    if (status < 200) {
+      NOTIFY(ep, call, nh, 
+	     SIPTAG_EVENT(sip->sip_event),
+	     SIPTAG_CONTENT_TYPE_STR("application/pidf+xml"),
+	     SIPTAG_PAYLOAD_STR(presence_closed),
+	     NUTAG_SUBSTATE(nua_substate_pending),
+	     TAG_END());
+      NOTIFY(ep, call, nh,
+	     SIPTAG_EVENT(sip->sip_event),
+	     SIPTAG_CONTENT_TYPE_STR("application/pidf+xml"),
+	     SIPTAG_PAYLOAD_STR(presence_open),
+	     NUTAG_SUBSTATE(nua_substate_active),
+	     TAG_END());
+      RESPOND(ep, call, nh, SIP_202_ACCEPTED,
+	      NUTAG_WITH(with),
+	      SIPTAG_EXPIRES_STR("360"),
+	      TAG_END());
+    }
+    return 0;
+
+  case nua_r_notify:
+    return status >= 200 &&
+      tl_find(tags, nutag_substate)->t_value == nua_substate_active;
+
+  default:
+    return 0;
+  }
+}
+
+
 int accept_and_notify(CONDITION_PARAMS)
 {
   msg_t *with = nua_current_request(nua);
@@ -580,12 +624,14 @@
 	      NUTAG_WITH(with),
 	      SIPTAG_EXPIRES_STR("360"),
 	      TAG_END());
+
       NOTIFY(ep, call, nh, 
 	     SIPTAG_EVENT(sip->sip_event),
 	     SIPTAG_CONTENT_TYPE_STR("application/pidf+xml"),
 	     SIPTAG_PAYLOAD_STR(presence_closed),
 	     NUTAG_SUBSTATE(nua_substate_pending),
 	     TAG_END());
+
     }
     return 0;
 
@@ -597,6 +643,31 @@
   }
 }
 
+int save_and_notify(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (event) {
+  case nua_i_subscribe:
+    NOTIFY(ep, call, nh, 
+	   SIPTAG_EVENT(sip->sip_event),
+	   SIPTAG_CONTENT_TYPE_STR("application/pidf+xml"),
+	   SIPTAG_PAYLOAD_STR(presence_closed),
+	   NUTAG_SUBSTATE(nua_substate_active),
+	   TAG_END());
+    return 0;
+
+  case nua_r_notify:
+    return status >= 200;
+
+  default:
+    return 0;
+  }
+}
+
 extern int save_until_notified_and_responded(CONDITION_PARAMS);
 extern int save_until_notified(CONDITION_PARAMS);
 
@@ -606,7 +677,7 @@
 
   struct endpoint *a = &ctx->a,  *b = &ctx->b;
   struct call *a_call = a->call, *b_call = b->call;
-  struct event *e;
+  struct event *e, *en1, *en2, *es;
   sip_t const *sip;
   tagi_t const *n_tags, *r_tags;
 
@@ -620,44 +691,47 @@
 
   SUBSCRIBE(a, a_call, a_call->nh, NUTAG_URL(b->contact->m_url),
 	    SIPTAG_EVENT_STR("presence"),
+	    SIPTAG_EXPIRES_STR("333"),
 	    SIPTAG_ACCEPT_STR("application/xpidf, application/pidf+xml"),
 	    TAG_END());
 
   run_ab_until(ctx, -1, save_until_notified_and_responded,
-	       -1, accept_and_notify);
+	       -1, accept_and_notify_twice);
 
   /* Client events:
-     nua_subscribe(), nua_i_notify/nua_r_subscribe
+     nua_subscribe(), nua_i_notify/nua_r_subscribe/nua_i_notify
   */
-  TEST_1(e = a->events->head);
-  if (e->data->e_event == nua_i_notify) {
-    TEST_E(e->data->e_event, nua_i_notify);
-    TEST_1(sip = sip_object(e->data->e_msg));
-    n_tags = e->data->e_tags;
-    TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_subscribe);
-    r_tags = e->data->e_tags;
-    TEST_1(tl_find(r_tags, nutag_substate));
-    TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_pending);
-  }
-  else {
-    TEST_E(e->data->e_event, nua_r_subscribe);
-    TEST(e->data->e_status, 202);
-    r_tags = e->data->e_tags;
-    TEST_1(tl_find(r_tags, nutag_substate));
-    TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_embryonic);
-    TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
-    TEST_1(sip = sip_object(e->data->e_msg));
-    n_tags = e->data->e_tags;
+  for (en1 = en2 = es = NULL, e = a->events->head; e; e = e->next) {
+    if (en1 == NULL && e->data->e_event == nua_i_notify)
+      en1 = e;
+    else if (en2 == NULL && e->data->e_event == nua_i_notify)
+      en2 = e;
+    else if (e->data->e_event == nua_r_subscribe)
+      es = e;
+    else
+      TEST_1(!e);
   }
+
+  TEST_1(e = en1);
+  TEST_E(e->data->e_event, nua_i_notify);
+  TEST_1(tl_find(e->data->e_tags, nutag_substate));
+  TEST(tl_find(e->data->e_tags, nutag_substate)->t_value, nua_substate_pending);
+  TEST_1(sip = sip_object(e->data->e_msg));
   TEST_1(sip->sip_event); TEST_S(sip->sip_event->o_type, "presence");
   TEST_1(sip->sip_content_type);
   TEST_S(sip->sip_content_type->c_type, "application/pidf+xml");
   TEST_1(sip->sip_subscription_state);
   TEST_S(sip->sip_subscription_state->ss_substate, "pending");
   TEST_1(sip->sip_subscription_state->ss_expires);
-  TEST_1(tl_find(n_tags, nutag_substate));
-  TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_pending);
-  TEST_1(!e->next);
+
+  TEST_1(e = es); TEST_E(e->data->e_event, nua_r_subscribe);
+  TEST_1(e->data->e_status == 202 || e->data->e_status == 200);
+  TEST_1(tl_find(e->data->e_tags, nutag_substate));
+  TEST(tl_find(e->data->e_tags, nutag_substate)->t_value, nua_substate_pending);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_expires);
+  TEST_1(sip->sip_expires->ex_delta <= 333);
+
   free_events_in_list(ctx, a->events);
 
   /* Server events: nua_i_subscribe, nua_r_notify */
@@ -731,6 +805,80 @@
 
   /* ---------------------------------------------------------------------- */
 
+/* Re-SUBSCRIBE
+
+   A			B
+   |                    |
+   |<------NOTIFY-------|
+   |-------200 OK------>|
+   |                    |
+*/
+  if (print_headings)
+    printf("TEST NUA-11.4.3: re-SUBSCRIBE\n");
+
+  /* Set default expiration time */
+  nua_set_hparams(b_call->nh, NUTAG_SUB_EXPIRES(365), TAG_END());
+  run_b_until(ctx, nua_r_set_params, until_final_response);
+
+  SUBSCRIBE(a, a_call, a_call->nh, NUTAG_URL(b->contact->m_url),
+	    SIPTAG_EVENT_STR("presence"),
+	    SIPTAG_EXPIRES_STR("3600"),
+	    SIPTAG_ACCEPT_STR("application/xpidf, application/pidf+xml"),
+	    TAG_END());
+
+  run_ab_until(ctx, -1, save_until_notified_and_responded,
+	       -1, save_until_final_response);
+
+  /* Client events:
+     nua_subscribe(), nua_i_notify/nua_r_subscribe
+  */
+  for (en1 = en2 = es = NULL, e = a->events->head; e; e = e->next) {
+    if (en1 == NULL && e->data->e_event == nua_i_notify)
+      en1 = e;
+    else if (e->data->e_event == nua_r_subscribe)
+      es = e;
+    else
+      TEST_1(!e);
+  }
+  TEST_1(e = en1);
+  TEST_E(e->data->e_event, nua_i_notify);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_event); TEST_S(sip->sip_event->o_type, "presence");
+  TEST_1(sip->sip_content_type);
+  TEST_S(sip->sip_content_type->c_type, "application/pidf+xml");
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "active");
+  TEST_1(sip->sip_subscription_state->ss_expires);
+  n_tags = e->data->e_tags;
+  TEST_1(tl_find(n_tags, nutag_substate));
+  TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_active);
+
+  TEST_1(e = es); TEST_E(e->data->e_event, nua_r_subscribe);
+  TEST_1(tl_find(e->data->e_tags, nutag_substate));
+  TEST(tl_find(e->data->e_tags, nutag_substate)->t_value, nua_substate_active);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_expires);
+  TEST_1(sip->sip_expires->ex_delta <= 365);
+
+  free_events_in_list(ctx, a->events);
+
+  /* Server events: nua_i_subscribe, nua_r_notify */
+  TEST_1(e = b->events->head);
+  TEST_E(e->data->e_event, nua_i_subscribe);
+  TEST_E(e->data->e_status, 100);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
+  r_tags = e->data->e_tags;
+  TEST_1(tl_find(r_tags, nutag_substate));
+  TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_active);
+
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST NUA-11.4.3: PASSED\n");
+
+  /* ---------------------------------------------------------------------- */
+
 /* un-SUBSCRIBE
 
    A			B
@@ -742,7 +890,7 @@
    |                    |
 */
   if (print_headings)
-    printf("TEST NUA-11.4.3: un-SUBSCRIBE\n");
+    printf("TEST NUA-11.4.4: un-SUBSCRIBE\n");
 
   UNSUBSCRIBE(a, a_call, a_call->nh, TAG_END());
 
@@ -752,31 +900,35 @@
   /* Client events:
      nua_unsubscribe(), nua_i_notify/nua_r_unsubscribe
   */
-  TEST_1(e = a->events->head);
-  if (e->data->e_event == nua_i_notify) {
-    TEST_E(e->data->e_event, nua_i_notify);
-    n_tags = e->data->e_tags;
+  for (en1 = en2 = es = NULL, e = a->events->head; e; e = e->next) {
+    if (en1 == NULL && e->data->e_event == nua_i_notify)
+      en1 = e;
+    else if (e->data->e_event == nua_r_unsubscribe)
+      es = e;
+    else
+      TEST_1(!e);
+  }
+  if (en1) {
+    TEST_1(e = en1); TEST_E(e->data->e_event, nua_i_notify);
     TEST_1(sip = sip_object(e->data->e_msg));
     TEST_1(sip->sip_event);
     TEST_1(sip->sip_subscription_state);
     TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
     TEST_1(!sip->sip_subscription_state->ss_expires);
+    n_tags = e->data->e_tags;
     TEST_1(tl_find(n_tags, nutag_substate));
     TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_terminated);
-    TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_unsubscribe);
-    TEST(e->data->e_status, 200);
-    r_tags = e->data->e_tags;
-    TEST_1(tl_find(r_tags, nutag_substate));
-    TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_terminated);
-  }
-  else {
-    TEST_E(e->data->e_event, nua_r_unsubscribe);
-    TEST(e->data->e_status, 200);
-    r_tags = e->data->e_tags;
-    TEST_1(tl_find(r_tags, nutag_substate));
-    TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_terminated);
   }
-  TEST_1(!e->next);
+
+  TEST_1(e = es); TEST_E(e->data->e_event, nua_r_unsubscribe);
+  TEST(e->data->e_status, 200);
+  r_tags = e->data->e_tags;
+  TEST_1(tl_find(r_tags, nutag_substate));
+  TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_terminated);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_expires);
+  TEST_1(sip->sip_expires->ex_delta == 0);
+
   free_events_in_list(ctx, a->events);
 
   /* Notifier events: nua_r_notify */
@@ -799,7 +951,7 @@
   nua_handle_destroy(b_call->nh), b_call->nh = NULL;
 
   if (print_headings)
-    printf("TEST NUA-11.4.3: PASSED\n");
+    printf("TEST NUA-11.4.4: PASSED\n");
 
   if (print_headings)
     printf("TEST NUA-11.4: PASSED\n");
@@ -825,7 +977,7 @@
 
   struct endpoint *a = &ctx->a,  *b = &ctx->b;
   struct call *a_call = a->call, *b_call = b->call;
-  struct event *e;
+  struct event *e, *en1, *en2, *es;
   sip_t const *sip;
   tagi_t const *n_tags, *r_tags;
   struct nat_filter *f;
@@ -846,35 +998,33 @@
   /* Client events:
      nua_subscribe(), nua_i_notify/nua_r_subscribe
   */
-  TEST_1(e = a->events->head);
-  if (e->data->e_event == nua_i_notify) {
-    TEST_E(e->data->e_event, nua_i_notify);
-    TEST_1(sip = sip_object(e->data->e_msg));
-    n_tags = e->data->e_tags;
-    TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_subscribe);
-    r_tags = e->data->e_tags;
-    TEST_1(tl_find(r_tags, nutag_substate));
-    TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_pending);
-  }
-  else {
-    TEST_E(e->data->e_event, nua_r_subscribe);
-    TEST(e->data->e_status, 202);
-    r_tags = e->data->e_tags;
-    TEST_1(tl_find(r_tags, nutag_substate));
-    TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_embryonic);
-    TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
-    TEST_1(sip = sip_object(e->data->e_msg));
-    n_tags = e->data->e_tags;
+  for (en1 = en2 = es = NULL, e = a->events->head; e; e = e->next) {
+    if (en1 == NULL && e->data->e_event == nua_i_notify)
+      en1 = e;
+    else if (es == NULL && e->data->e_event == nua_r_subscribe)
+      es = e;
+    else
+      TEST_1(!e);
   }
+  TEST_1(e = en1); TEST_E(e->data->e_event, nua_i_notify);
+  TEST_1(sip = sip_object(e->data->e_msg));
   TEST_1(sip->sip_event); TEST_S(sip->sip_event->o_type, "presence");
   TEST_1(sip->sip_content_type);
   TEST_S(sip->sip_content_type->c_type, "application/pidf+xml");
   TEST_1(sip->sip_subscription_state);
   TEST_S(sip->sip_subscription_state->ss_substate, "pending");
   TEST_1(sip->sip_subscription_state->ss_expires);
+  n_tags = e->data->e_tags;
   TEST_1(tl_find(n_tags, nutag_substate));
   TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_pending);
-  TEST_1(!e->next);
+
+  TEST_1(e = es); TEST_E(e->data->e_event, nua_r_subscribe);
+  r_tags = e->data->e_tags;
+  TEST_1(tl_find(r_tags, nutag_substate));
+  if (es == a->events->head)
+    TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_embryonic);
+  else
+    TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_pending);
   free_events_in_list(ctx, a->events);
 
   /* Server events: nua_i_subscribe, nua_r_notify */
@@ -1011,7 +1161,6 @@
   return ep->flags.bit0 && ep->flags.bit1;
 }
 
-
 /* ---------------------------------------------------------------------- */
 /* Unsolicited NOTIFY */
 
@@ -1028,6 +1177,8 @@
   sip_call_id_t *i;
   tagi_t const *n_tags, *r_tags;
 
+#if 0
+
   if (print_headings)
     printf("TEST NUA-11.7.1: rejecting NOTIFY without subscription locally\n");
 
@@ -1161,6 +1312,298 @@
   nua_handle_destroy(a_call->nh), a_call->nh = NULL;
   nua_handle_destroy(b_call->nh), b_call->nh = NULL;
 
+#else
+  (void)i;
+  nua_set_params(b->nua, NUTAG_APPL_METHOD("NOTIFY"), TAG_END());
+  run_b_until(ctx, nua_r_set_params, until_final_response);
+#endif
+
+  /* ---------------------------------------------------------------------- */
+
+  if (print_headings)
+    printf("TEST NUA-11.7.4: multiple unsolicited NOTIFYs\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  NOTIFY(a, a_call, a_call->nh,
+	 NUTAG_URL(b->contact->m_url),
+	 NUTAG_NEWSUB(1),
+	 SIPTAG_EXPIRES_STR("10"),
+	 SIPTAG_SUBJECT_STR("NUA-11.7.4aa"),
+	 SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
+	 SIPTAG_PAYLOAD_STR("Messages-Waiting: no"),
+	 TAG_END());
+
+  NOTIFY(a, a_call, a_call->nh,
+	 NUTAG_URL(b->contact->m_url),
+	 NUTAG_NEWSUB(1),
+	 SIPTAG_SUBSCRIPTION_STATE_STR("active; expires=333"),
+	 SIPTAG_SUBJECT_STR("NUA-11.7.4a"),
+	 SIPTAG_EVENT_STR("message-summary"),
+	 SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
+	 SIPTAG_PAYLOAD_STR("Messages-Waiting: no"),
+	 TAG_END());
+
+  NOTIFY(a, a_call, a_call->nh,
+	 NUTAG_URL(b->contact->m_url),
+	 NUTAG_NEWSUB(1),
+	 SIPTAG_SUBSCRIPTION_STATE_STR("active; expires=3000"),
+	 SIPTAG_SUBJECT_STR("NUA-11.7.4b"),
+	 SIPTAG_EVENT_STR("message-summary"),
+	 SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
+	 SIPTAG_PAYLOAD_STR("Messages-Waiting: yes"),
+	 TAG_END());
+
+  NOTIFY(a, a_call, a_call->nh,
+	 NUTAG_URL(b->contact->m_url),
+	 NUTAG_NEWSUB(1),
+	 SIPTAG_SUBSCRIPTION_STATE_STR("terminated"),
+	 SIPTAG_SUBJECT_STR("NUA-11.7.4c"),
+	 SIPTAG_EVENT_STR("message-summary"),
+	 SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
+	 SIPTAG_PAYLOAD_STR("Messages-Waiting: yes"),
+	 TAG_END());
+
+  a->state.n = 4;
+  b->state.n = 4;
+
+  run_ab_until(ctx, -1, save_until_nth_final_response, 
+	       -1, accept_n_notifys);
+
+  /* Notifier events: nua_r_notify nua_r_notify */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_notify);
+  TEST(e->data->e_status, 200);
+  r_tags = e->data->e_tags;
+  TEST_1(tl_find(r_tags, nutag_substate));
+  TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_terminated);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
+  TEST(e->data->e_status, 200);
+  r_tags = e->data->e_tags;
+  TEST_1(tl_find(r_tags, nutag_substate));
+  TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_active);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
+  TEST(e->data->e_status, 200);
+  r_tags = e->data->e_tags;
+  TEST_1(tl_find(r_tags, nutag_substate));
+  TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_active);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
+  TEST(e->data->e_status, 200);
+  r_tags = e->data->e_tags;
+  TEST_1(tl_find(r_tags, nutag_substate));
+  TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_terminated);
+  TEST_1(!e->next);
+
+  /* subscriber events:
+     nua_i_notify
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_notify);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
+  n_tags = e->data->e_tags;
+  TEST_1(tl_find(n_tags, nutag_substate));
+  TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_terminated);
+
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "active");
+  n_tags = e->data->e_tags;
+  TEST_1(tl_find(n_tags, nutag_substate));
+  TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_active);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "active");
+  n_tags = e->data->e_tags;
+  TEST_1(tl_find(n_tags, nutag_substate));
+  TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_active);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
+  n_tags = e->data->e_tags;
+  TEST_1(tl_find(n_tags, nutag_substate));
+  TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_terminated);
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  free_events_in_list(ctx, b->events);
+
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-11.7.4: PASSED\n");
+
+  /* ---------------------------------------------------------------------- */
+
+  if (print_headings)
+    printf("TEST NUA-11.7.5: multiple unsolicited NOTIFYs\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  NOTIFY(a, a_call, a_call->nh,
+	 NUTAG_URL(b->contact->m_url),
+	 NUTAG_NEWSUB(1),
+	 SIPTAG_SUBSCRIPTION_STATE_STR("active; expires=333"),
+	 SIPTAG_SUBJECT_STR("NUA-11.7.5a"),
+	 SIPTAG_EVENT_STR("message-summary"),
+	 SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
+	 SIPTAG_PAYLOAD_STR("Messages-Waiting: no"),
+	 TAG_END());
+
+  NOTIFY(a, a_call, a_call->nh,
+	 NUTAG_URL(b->contact->m_url),
+	 NUTAG_NEWSUB(1),
+	 SIPTAG_SUBSCRIPTION_STATE_STR("active; expires=3000"),
+	 SIPTAG_SUBJECT_STR("NUA-11.7.5b"),
+	 SIPTAG_EVENT_STR("message-summary"),
+	 SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
+	 SIPTAG_PAYLOAD_STR("Messages-Waiting: yes"),
+	 TAG_END());
+
+  NOTIFY(a, a_call, a_call->nh,
+	 NUTAG_URL(b->contact->m_url),
+	 NUTAG_NEWSUB(1),
+	 SIPTAG_SUBSCRIPTION_STATE_STR("terminated"),
+	 SIPTAG_SUBJECT_STR("NUA-11.7.5c"),
+	 SIPTAG_EVENT_STR("message-summary"),
+	 SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
+	 SIPTAG_PAYLOAD_STR("Messages-Waiting: yes"),
+	 TAG_END());
+
+  a->state.n = 3;
+  b->state.n = 3;
+
+  run_ab_until(ctx, -1, save_until_nth_final_response, 
+	       -1, accept_n_notifys);
+
+  /* Notifier events: nua_r_notify nua_r_notify */
+  TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_notify);
+  TEST(e->data->e_status, 200);
+  r_tags = e->data->e_tags;
+  TEST_1(tl_find(r_tags, nutag_substate));
+  TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_active);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
+  TEST(e->data->e_status, 200);
+  r_tags = e->data->e_tags;
+  TEST_1(tl_find(r_tags, nutag_substate));
+  TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_active);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
+  TEST(e->data->e_status, 200);
+  r_tags = e->data->e_tags;
+  TEST_1(tl_find(r_tags, nutag_substate));
+  TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_terminated);
+  TEST_1(!e->next);
+
+  /* subscriber events:
+     nua_i_notify
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_notify);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "active");
+  n_tags = e->data->e_tags;
+  TEST_1(tl_find(n_tags, nutag_substate));
+  TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_active);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "active");
+  n_tags = e->data->e_tags;
+  TEST_1(tl_find(n_tags, nutag_substate));
+  TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_active);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
+  n_tags = e->data->e_tags;
+  TEST_1(tl_find(n_tags, nutag_substate));
+  TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_terminated);
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, a->events);
+  free_events_in_list(ctx, b->events);
+
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-11.7.5: PASSED\n");
+
+  /* ---------------------------------------------------------------------- */
+
+#if 0
+
+  if (print_headings)
+    printf("TEST NUA-11.7.6: unsolicited NOTIFY handle destroyed\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  NOTIFY(a, a_call, a_call->nh,
+	 NUTAG_URL(b->contact->m_url),
+	 NUTAG_NEWSUB(1),
+	 SIPTAG_SUBSCRIPTION_STATE_STR("active; expires=333"),
+	 SIPTAG_SUBJECT_STR("NUA-11.7.6a"),
+	 SIPTAG_EVENT_STR("message-summary"),
+	 SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
+	 SIPTAG_PAYLOAD_STR("Messages-Waiting: no"),
+	 TAG_END());
+
+  NOTIFY(a, a_call, a_call->nh,
+	 NUTAG_URL(b->contact->m_url),
+	 NUTAG_NEWSUB(1),
+	 SIPTAG_SUBSCRIPTION_STATE_STR("active; expires=3000"),
+	 SIPTAG_SUBJECT_STR("NUA-11.7.6b"),
+	 SIPTAG_EVENT_STR("message-summary"),
+	 SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
+	 SIPTAG_PAYLOAD_STR("Messages-Waiting: yes"),
+	 TAG_END());
+
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+
+  a->state.n = 3;
+  b->state.n = 3;
+
+  run_b_until(ctx, -1, accept_n_notifys);
+
+  /* subscriber events:
+     nua_i_notify
+  */
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_notify);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "active");
+  n_tags = e->data->e_tags;
+  TEST_1(tl_find(n_tags, nutag_substate));
+  TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_active);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "active");
+  n_tags = e->data->e_tags;
+  TEST_1(tl_find(n_tags, nutag_substate));
+  TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_active);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_subscription_state);
+  TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
+  n_tags = e->data->e_tags;
+  TEST_1(tl_find(n_tags, nutag_substate));
+  TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_terminated);
+  TEST_1(!e->next);
+
+  free_events_in_list(ctx, b->events);
+
+  if (print_headings)
+    printf("TEST NUA-11.7.6: PASSED\n");
+
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+#endif
+
   if (print_headings)
     printf("TEST NUA-11.7: PASSED\n");
 
@@ -1183,6 +1626,50 @@
   return event == nua_i_notify;
 }
 
+int save_until_nth_final_response(CONDITION_PARAMS)
+{
+  save_event_in_list(ctx, event, ep, call);
+
+  if (nua_r_set_params <= event && event < nua_i_network_changed
+      && status >= 200) {
+    if (ep->state.n > 0) 
+      ep->state.n--;
+    return ep->state.n == 0;
+  }
+
+  return 0;
+}
+
+int accept_n_notifys(CONDITION_PARAMS)
+{
+  tagi_t const *substate = tl_find(tags, nutag_substate);
+
+  if (event == nua_i_notify && status < 200)
+    RESPOND(ep, call, nh, SIP_200_OK, 
+	    NUTAG_WITH_THIS(ep->nua),
+	    TAG_END());
+
+  save_event_in_list(ctx, event, ep, call);
+
+  if (event != nua_i_notify)
+    return 0;
+
+  if (ep->state.n > 0) 
+    ep->state.n--;
+
+  if (ep->state.n == 0) 
+    return 1;
+
+  if (substate && substate->t_value == nua_substate_terminated) {
+    if (call && call->nh == nh) {
+      call->nh = NULL;
+      nua_handle_destroy(nh);
+    }
+  }
+
+  return 0;
+}
+
 /* ======================================================================== */
 
 int save_until_subscription_terminated(CONDITION_PARAMS);
@@ -1336,8 +1823,8 @@
 
 int test_simple(struct context *ctx)
 {
-  return
-    test_message(ctx)
+  return 0
+    || test_message(ctx)
     || test_publish(ctx)
     || test_subscribe_notify(ctx)
     || test_subscribe_notify_graceful(ctx)

Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_print.c
==============================================================================
--- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_print.c	(original)
+++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_print.c	Tue Feb 26 12:00:03 2008
@@ -613,8 +613,8 @@
 	sdp_printf(p, " %s", l->l_text);
     }
     else {
-      sdp_printf(p, " 9");      /* SDP syntax requires at least one format.
-				   9 is used by nobody, right?. */
+      sdp_printf(p, " 19");      /* SDP syntax requires at least one format.
+				    19 is used by nobody, right?. */
     }
 
 



More information about the Freeswitch-svn mailing list