[Freeswitch-branches] [commit] r4923 - in freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua: iptsec iptsec/sofia-sip nta nua nua/sofia-sip sdp sip

Freeswitch SVN mikej at freeswitch.org
Fri Apr 13 10:33:31 EDT 2007


Author: mikej
Date: Fri Apr 13 10:33:30 2007
New Revision: 4923

Modified:
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/iptsec/Doxyfile
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client_plugin.h
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nta/nta.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_common.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_extension.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_registrar.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua.h
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_basic_call.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_call_reject.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_offer_answer.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.h
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_register.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_session_timer.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_simple.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/sdp/run_test_sdp
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/sip/sip_feature.c
   freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c

Log:
sync with current darcs tree

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/iptsec/Doxyfile
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/iptsec/Doxyfile	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/iptsec/Doxyfile	Fri Apr 13 10:33:30 2007
@@ -19,3 +19,6 @@
 GENERATE_TAGFILE    = ../docs/iptsec.doxytags
 
 ALIASES 	   += 
+
+PREDEFINED         += SOFIA_EXTEND_AUTH_CLIENT=1
+

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client.c	Fri Apr 13 10:33:30 2007
@@ -31,6 +31,8 @@
 
 #include "config.h"
 
+#define SOFIA_EXTEND_AUTH_CLIENT 1
+
 #include <sofia-sip/su.h>
 #include <sofia-sip/su_md5.h>
 
@@ -77,9 +79,7 @@
 			  char const *user,
 			  char const *pass);
 
-static int ca_clear_credentials(auth_client_t *ca, 
-				char const *scheme,
-				char const *realm);
+static int ca_clear_credentials(auth_client_t *ca);
 
 
 /** Initialize authenticators.
@@ -340,8 +340,8 @@
  * @param[in] user          username 
  * @param[in] pass          password
  * 
- * @retval number of matching clients
- * @retval 0 when no matching client was found
+ * @retval number of updated clients
+ * @retval 0 when no client was updated
  * @retval -1 upon an error
  */
 int auc_all_credentials(auth_client_t **auc_list, 
@@ -375,6 +375,9 @@
 		   char const *user,
 		   char const *pass)
 {
+  char *new_user, *new_pass;
+  char *old_user, *old_pass;
+
   assert(ca);
 
   if (!ca || !ca->ca_scheme || !ca->ca_realm)
@@ -384,12 +387,24 @@
       (realm != NULL && strcmp(realm, ca->ca_realm)))
     return -1;
 
-  ca->ca_user = su_strdup(ca->ca_home, user);
-  ca->ca_pass = su_strdup(ca->ca_home, pass);
+  old_user = ca->ca_user, old_pass = ca->ca_pass;
+
+  if (str0cmp(user, old_user) == 0 && str0cmp(pass, old_pass) == 0)
+    return 0;
+
+  new_user = su_strdup(ca->ca_home, user);
+  new_pass = su_strdup(ca->ca_home, pass);
 
-  if (!ca->ca_user || !ca->ca_pass)
+  if (!new_user || !new_pass)
     return -1;
 
+  ca->ca_user = new_user, ca->ca_pass = new_pass;
+  if (AUTH_CLIENT_IS_EXTENDED(ca))
+    ca->ca_clear = 0;
+
+  su_free(ca->ca_home, old_user);
+  su_free(ca->ca_home, old_pass);
+
   return 1;
 }
 
@@ -416,12 +431,15 @@
       char *u, *p;
       if (!ca->ca_user || !ca->ca_pass)
 	continue;
+      if (AUTH_CLIENT_IS_EXTENDED(ca) && ca->ca_clear)
+	continue;
       if (!ca->ca_scheme[0] || strcmp(ca->ca_scheme, d->ca_scheme))
 	continue;
       if (!ca->ca_realm[0] || strcmp(ca->ca_realm, d->ca_realm))
 	continue;
 
-      if (d->ca_user && strcmp(d->ca_user, ca->ca_user) == 0 &&
+      if (!(AUTH_CLIENT_IS_EXTENDED(d) && d->ca_clear) &&
+	  d->ca_user && strcmp(d->ca_user, ca->ca_user) == 0 &&
 	  d->ca_pass && strcmp(d->ca_pass, ca->ca_pass) == 0) {
 	retval++;
 	break;
@@ -435,6 +453,9 @@
       if (d->ca_user) su_free(d->ca_home, (void *)d->ca_user);
       if (d->ca_pass) su_free(d->ca_home, (void *)d->ca_pass);
       d->ca_user = u, d->ca_pass = p;
+      if (AUTH_CLIENT_IS_EXTENDED(d))
+	d->ca_clear = 0;
+
       retval++;
       break;
     }
@@ -457,13 +478,24 @@
  * @retval -1 upon an error
  */
 int auc_clear_credentials(auth_client_t **auc_list, 
-			 char const *scheme,
-			 char const *realm)
+			  char const *scheme,
+			  char const *realm)
 {
   int retval = 0;
+  int match;
 
   for (; *auc_list; auc_list = &(*auc_list)->ca_next) {
-    int match = ca_clear_credentials(*auc_list, scheme, realm);
+    auth_client_t *ca = *auc_list;
+
+    if (!AUTH_CLIENT_IS_EXTENDED(ca))
+      continue;
+
+    if ((scheme != NULL && strcasecmp(scheme, ca->ca_scheme)) ||
+	(realm != NULL && strcmp(realm, ca->ca_realm)))
+      continue;
+
+    match = ca->ca_auc->auc_clear(*auc_list);
+
     if (match < 0) {
       retval = -1;
       break;
@@ -476,21 +508,14 @@
 }
 
 static
-int ca_clear_credentials(auth_client_t *ca, 
-			 char const *scheme,
-			 char const *realm)
+int ca_clear_credentials(auth_client_t *ca)
 {
-  assert(ca);
-
-  if (!ca || !ca->ca_scheme || !ca->ca_realm)
-    return -1;
+  assert(ca); assert(ca->ca_home->suh_size >= (int)(sizeof *ca));
 
-  if ((scheme != NULL && strcasecmp(scheme, ca->ca_scheme)) ||
-      (realm != NULL && strcmp(realm, ca->ca_realm)))
+  if (!ca)
     return -1;
 
-  su_free(ca->ca_home, (void *)ca->ca_user), ca->ca_user = NULL;
-  su_free(ca->ca_home, (void *)ca->ca_pass), ca->ca_pass = NULL;
+  ca->ca_clear = 1;
 
   return 1;
 }
@@ -513,6 +538,8 @@
   for (ca = *auc_list; ca; ca = ca->ca_next) {
     if (!ca->ca_user || !ca->ca_pass || !ca->ca_credential_class)
       return 0;
+    if (AUTH_CLIENT_IS_EXTENDED(ca) && ca->ca_clear)
+      return 0;
   }
 
   return 1;
@@ -570,8 +597,11 @@
     if (!ca->ca_auc)
       continue;
 
-    if (ca->ca_auc->auc_authorize(ca, home, method, url, body, &h) < 0
-	|| msg_header_insert(msg, pub, h) < 0)
+    if (ca->ca_auc->auc_authorize(ca, home, method, url, body, &h) < 0)
+      return -1;
+    if (h == NULL)
+      continue;
+    if (msg_header_insert(msg, pub, h) < 0)
       return -1;
   }
 
@@ -639,14 +669,15 @@
 				   msg_payload_t const *body,
 				   msg_header_t **);
 
-const auth_client_plugin_t ca_basic_plugin = 
+static const auth_client_plugin_t ca_basic_plugin = 
 { 
   /* auc_plugin_size: */ sizeof ca_basic_plugin,
   /* auc_size: */        sizeof (auth_client_t),
   /* auc_name: */       "Basic",
   /* auc_challenge: */   NULL,
   /* auc_authorize: */   auc_basic_authorization,
-  /* auc_info: */        NULL
+  /* auc_info: */        NULL,
+  /* auc_clear: */       ca_clear_credentials
 };
 
 /**Create a basic authorization header.
@@ -683,6 +714,9 @@
   if (user == NULL || pass == NULL)
     return -1;
 
+  if (AUTH_CLIENT_IS_EXTENDED(ca) && ca->ca_clear)
+    return 0;
+
   ulen = strlen(user), plen = strlen(pass), uplen = ulen + 1 + plen;
   b64len = BASE64_SIZE(uplen);
   basiclen = strlen("Basic ") + b64len;
@@ -746,7 +780,8 @@
   /* auc_name: */       "Digest", 
   /* auc_challenge: */   auc_digest_challenge,
   /* auc_authorize: */   auc_digest_authorization,
-  /* auc_info: */        auc_digest_info
+  /* auc_info: */        auc_digest_info,
+  /* auc_clear: */       ca_clear_credentials
 };
 
 /** Store a digest authorization challenge.
@@ -826,9 +861,9 @@
  * sip_authorization_class or sip_proxy_authorization_class, as well as
  * http_authorization_class or http_proxy_authorization_class.
  *
- * @return
- * Returns a pointer to newly created authorization header, or NULL upon an
- * error.
+ * @retval 1 when authorization headers has been created  
+ * @retval 0 when there is no credentials
+ * @retval -1 upon an error
  */
 static
 int auc_digest_authorization(auth_client_t *ca, 
@@ -854,6 +889,9 @@
   auth_response_t ar[1] = {{ 0 }};
   char ncount[17];
 
+  if (!user || !pass || (AUTH_CLIENT_IS_EXTENDED(ca) && ca->ca_clear))
+    return 0;
+
   ar->ar_size = sizeof(ar);
   ar->ar_username = user;
   ar->ar_realm = ac->ac_realm;

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client_plugin.h
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client_plugin.h	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client_plugin.h	Fri Apr 13 10:33:30 2007
@@ -29,6 +29,9 @@
 /**@file sofia-sip/auth_client_plugin.h
  * @brief Client-side plugin interface for authentication
  * 
+ * @note For extensions in 1.12.6 or later, 
+ * you have to #define SOFIA_EXTEND_AUTH_CLIENT to 1.
+ *
  * @author Pekka Pessi <Pekka.Pessi at nokia.com>
  * 
  * @date Created: Fri May 19 16:18:21 EEST 2006
@@ -58,6 +61,10 @@
   char         *ca_pass;
 
   msg_hclass_t *ca_credential_class;
+
+#if SOFIA_EXTEND_AUTH_CLIENT
+  int           ca_clear;
+#endif
 };
 
 struct auth_client_plugin
@@ -81,8 +88,19 @@
 
   /** Store nextnonce from Authentication-Info or Proxy-Authentication-Info. */
   int (*auc_info)(auth_client_t *ca, msg_auth_info_t const *ai);
+
+#if SOFIA_EXTEND_AUTH_CLIENT
+  /** Clear credentials (user/pass). @NEW_1_12_6 */
+  int (*auc_clear)(auth_client_t *ca);
+#endif
 };
 
+/** Check if authentication client has been extended. @NEW_1_12_6 */
+#define AUTH_CLIENT_IS_EXTENDED(ca)					\
+  ((ca)->ca_auc->auc_plugin_size >					\
+   offsetof(auth_client_plugin_t, auc_clear)				\
+   && (ca)->ca_auc->auc_clear != NULL)
+
 SOFIA_END_DECLS
 
 #endif /* !defined AUTH_CLIENT_PLUGIN_H */

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nta/nta.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nta/nta.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nta/nta.c	Fri Apr 13 10:33:30 2007
@@ -8016,7 +8016,7 @@
 {
   nta_agent_t *sa = orq->orq_agent;
   short orq_status = orq->orq_status;
-  int internal = sip == NULL || (sip->sip_flags & NTA_INTERNAL_MSG) == 0;
+  int internal = sip == NULL || (sip->sip_flags & NTA_INTERNAL_MSG) != 0;
 
   if (status < 100) status = 100;
 

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_common.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_common.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_common.c	Fri Apr 13 10:33:30 2007
@@ -216,6 +216,50 @@
   return su_strdup(home, str);
 }
 
+/** Check if event is a request that can be responded with nua_respond().
+ *
+ * Note that if event status is 200 or greater, it already has been
+ * responded. This function is provided for compatibility with future
+ * versions of nua. An unknown event can always be handled in the event
+ * callback like this:
+ * @code
+ * switch (event) {
+ *   ...
+ *   default:
+ *     if (status < 200 && nua_event_is_incoming_request(event))
+ *       nua_respond(nh, SIP_501_NOT_IMPLEMENTED,
+ *                   NUTAG_WITH_THIS(nua), TAG_END());
+ *     if (hmagic == NULL)
+ *       nua_handle_destroy(nh);
+ *     return;
+ *   ...
+ * @endcode
+ *
+ * @sa #nua_event_t, nua_respond()
+ *
+ * @NEW_1_12_6
+ */
+int nua_event_is_incoming_request(nua_event_t event)
+{
+  switch (event) {
+  case nua_i_invite: return 1;
+  case nua_i_cancel: return 1;
+  case nua_i_register: return 1;
+  case nua_i_bye: return 1;
+  case nua_i_options: return 1;
+  case nua_i_refer: return 1;
+  case nua_i_publish: return 1;
+  case nua_i_prack: return 1;
+  case nua_i_info: return 1;
+  case nua_i_update: return 1;
+  case nua_i_message: return 1;
+  case nua_i_subscribe: return 1;
+  case nua_i_notify: return 1;
+  case nua_i_method: return 1;
+  default: return 0;
+  }
+}
+
 /** Get name for a NUA event. */
 char const *nua_event_name(nua_event_t event)
 {

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c	Fri Apr 13 10:33:30 2007
@@ -443,24 +443,6 @@
   ds->ds_terminating = 0;
 }
 
-
-/**@internal
- * Set expiration time. 
- */
-void nua_dialog_usage_set_expires(nua_dialog_usage_t *du,
-				  unsigned delta)
-{
-  if (delta) {
-    sip_time_t now = sip_now(), expires = now + delta;
-    if (expires < now)
-      expires = SIP_TIME_MAX;
-    du->du_expires = expires;
-    nua_dialog_usage_set_refresh(du, delta);
-  }
-  else
-    du->du_expires = 0, du->du_refresh = 0;
-}
-
 /**@internal
  * Set refresh value suitably. 
  *
@@ -514,6 +496,15 @@
   du->du_refresh = target;
 }
 
+/** Set absolute refresh time */
+void nua_dialog_usage_refresh_at(nua_dialog_usage_t *du,
+				 sip_time_t target)
+{
+  SU_DEBUG_7(("nua(): refresh %s after %lu seconds\n",
+	      nua_dialog_usage_name(du), target - sip_now()));
+  du->du_refresh = target;
+} 
+
 /**@internal Do not refresh. */
 void nua_dialog_usage_reset_refresh(nua_dialog_usage_t *du)
 {
@@ -561,8 +552,13 @@
   return 1;
 }
 
-/** (Gracefully) terminate usage */
-void nua_dialog_usage_shutdown(nua_owner_t *owner,
+/** (Gracefully) terminate usage.
+ *
+ * @retval >0  shutdown done
+ * @retval 0   shutdown in progress
+ * @retval <0  try again later
+ */
+int nua_dialog_usage_shutdown(nua_owner_t *owner,
 			       nua_dialog_state_t *ds,
 			       nua_dialog_usage_t *du)
 {
@@ -570,6 +566,8 @@
     du->du_refresh = 0;
     du->du_shutdown = 1;
     assert(du->du_class->usage_shutdown);
-    du->du_class->usage_shutdown(owner, ds, du);
+    return du->du_class->usage_shutdown(owner, ds, du);
   }
+  else
+    return 200;
 }

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h	Fri Apr 13 10:33:30 2007
@@ -112,6 +112,7 @@
   unsigned sr_event:1;		/**< Reported to application */
   unsigned sr_initial:1;	/**< Handle was created by this request */
   unsigned sr_add_contact:1;	/**< Add Contact header to the response */
+  unsigned sr_target_refresh:1;	/**< Refresh target */
   unsigned sr_terminating:1;	/**< Terminate usage after final response */
   unsigned sr_gracefully:1;	/**< Terminate usage gracefully */
 
@@ -299,6 +300,7 @@
   unsigned cr_auto:1;		/**< Request was generated by stack */
   unsigned cr_has_contact:1;	/**< Request has user Contact */
   unsigned cr_contactize:1;	/**< Request needs Contact */
+  unsigned cr_dialog:1;		/**< Request can initiate dialog */
 
   /* Current state */
   unsigned cr_challenged:1;	/**< Request was challenged */
@@ -396,7 +398,6 @@
    * Non-zero if the usage is established, SIP_TIME_MAX if there no
    * expiration time.
    */
-  sip_time_t      du_expires;		
 
   sip_time_t      du_refresh;		/**< When to refresh */
 
@@ -439,13 +440,14 @@
 
 int nua_dialog_shutdown(nua_owner_t *owner, nua_dialog_state_t *ds);
 
-void nua_dialog_usage_set_expires(nua_dialog_usage_t *du, unsigned delta);
-
 void nua_dialog_usage_set_refresh(nua_dialog_usage_t *du, unsigned delta);
 
 void nua_dialog_usage_refresh_range(nua_dialog_usage_t *du, 
 				    unsigned min, unsigned max);
 
+void nua_dialog_usage_refresh_at(nua_dialog_usage_t *du, 
+				 sip_time_t target);
+
 void nua_dialog_usage_reset_refresh(nua_dialog_usage_t *du);
 
 void nua_dialog_usage_refresh(nua_owner_t *owner,
@@ -453,9 +455,9 @@
 			      nua_dialog_usage_t *du, 
 			      sip_time_t now);
 
-void nua_dialog_usage_shutdown(nua_owner_t *owner,
-				nua_dialog_state_t *ds,
-				nua_dialog_usage_t *du);
+int nua_dialog_usage_shutdown(nua_owner_t *owner,
+			      nua_dialog_state_t *ds,
+			      nua_dialog_usage_t *du);
 
 static inline
 int nua_dialog_is_established(nua_dialog_state_t const *ds)

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_extension.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_extension.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_extension.c	Fri Apr 13 10:33:30 2007
@@ -75,7 +75,7 @@
   { 
     /* create_dialog */ 0,
     /* in_dialog */ 0,
-    /* target_refresh */ 0
+    /* target_refresh */ 1,
   },
   /* nua_method_client_template */ NULL,
   /* nua_method_client_init */ NULL,
@@ -146,7 +146,7 @@
     SIP_METHOD_UNKNOWN,
     nua_i_method,		/* Event */
     { 
-      0,			/* Do not create dialog */
+      1,			/* Do create dialog */
       0,			/* Can be an initial request */
       1,			/* Perhaps a target refresh request? */
       1,			/* Add a contact? */

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c	Fri Apr 13 10:33:30 2007
@@ -135,7 +135,7 @@
  * (or SIPTAG_ALLOW_EVENTS() or SIPTAG_ALLOW_EVENTS_STR()). The application
  * can decide whether to accept the SUBSCRIBE request or reject it. The
  * nua_response() call responding to a SUBSCRIBE request must have
- * NUTAG_WITH() (or NUTAG_WITH_CURRENT()/NUTAG_WITH_SAVED()) tag.
+ * NUTAG_WITH() (or NUTAG_WITH_THIS()/NUTAG_WITH_SAVED()) tag.
  *
  * If the application accepts the SUBSCRIBE request, it must immediately
  * send an initial NOTIFY establishing the dialog. This is because the
@@ -690,9 +690,15 @@
 		   SIPTAG_EVENT(du ? du->du_event : NULL),
 		   TAG_NEXT(tags));
 
-  if (nu && nu->nu_requested && du->du_cr == cr)
-    /* Re-SUBSCRIBEd while NOTIFY was in progress, resend NOTIFY */
-    nua_client_resend_request(cr, 0);
+  if (du && du->du_cr == cr && !cr->cr_terminated) {
+    if (nu->nu_requested) {
+      /* Re-SUBSCRIBEd while NOTIFY was in progress, resend NOTIFY */
+      nua_client_resend_request(cr, 0);
+    }
+    else if (nu->nu_expires) {
+      nua_dialog_usage_refresh_at(du, nu->nu_expires);
+    }
+  }
 
   return 0;
 }
@@ -710,7 +716,7 @@
   if (cr) {
     int terminating = 0;
 
-    if (du->du_expires && du->du_expires <= now)
+    if (nu->nu_expires && nu->nu_expires <= now)
       terminating = 1;
     else if (nu->nu_requested && nu->nu_requested <= now)
       terminating = 1;

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c	Fri Apr 13 10:33:30 2007
@@ -149,9 +149,10 @@
   NHP_SET(nhp, auto_ack, 1);
   NHP_SET(nhp, invite_timeout, 120);
 
-  NHP_SET(nhp, session_timer, 1800);
+  nhp->nhp_session_timer = 1800;
+  nhp->nhp_refresher = nua_no_refresher;
+
   NHP_SET(nhp, min_se, 120);
-  NHP_SET(nhp, refresher, nua_no_refresher);
   NHP_SET(nhp, update_refresh, 0);
 
   NHP_SET(nhp, message_enable, 1);
@@ -1503,6 +1504,11 @@
 #define TIF(TAG, pref) \
   TAG_IF(nhp->nhp_set.nhb_##pref, TAG(nhp->nhp_##pref))
 
+  /* Include tag in the list returned to user
+   * if it has been earlier set (by user) returning default parameters */
+#define TIFD(TAG, pref) \
+  TAG_IF(nh == dnh || nhp->nhp_set.nhb_##pref, TAG(nhp->nhp_##pref))
+
   /* Include string tag made out of SIP header
    * if it has been earlier set (by user) */
 #define TIF_STR(TAG, pref)						\
@@ -1540,9 +1546,9 @@
      TIF(NUTAG_AUTOACK, auto_ack),
      TIF(NUTAG_INVITE_TIMER, invite_timeout),
 
-     TIF(NUTAG_SESSION_TIMER, session_timer),
+     TIFD(NUTAG_SESSION_TIMER, session_timer),
      TIF(NUTAG_MIN_SE, min_se),
-     TIF(NUTAG_SESSION_REFRESHER, refresher),
+     TIFD(NUTAG_SESSION_REFRESHER, refresher),
      TIF(NUTAG_UPDATE_REFRESH, update_refresh),
 
      TIF(NUTAG_ENABLEMESSAGE, message_enable),

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h	Fri Apr 13 10:33:30 2007
@@ -169,8 +169,8 @@
 
     unsigned nhb_allow:1;
     unsigned nhb_supported:1;
-    unsigned nhb_allow_events:1;
     unsigned :0;		/* at most 32 bits ... */
+    unsigned nhb_allow_events:1;
     unsigned nhb_user_agent:1;
     unsigned nhb_organization:1;
 
@@ -226,4 +226,9 @@
   (NHP_ISSET((nh)->nh_prefs, pref) &&					\
    (nh)->nh_nua->nua_dhandle->nh_prefs != (nh)->nh_prefs)
 
+/* Check if preference has been set by applicationx */
+#define NUA_PISSET(nua, nh, pref)					\
+  (NHP_ISSET((nua)->nua_dhandle->nh_prefs, pref) ||			\
+   ((nh) && NHP_ISSET((nh)->nh_prefs, pref)))
+
 #endif /* NUA_PARAMS_H */

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c	Fri Apr 13 10:33:30 2007
@@ -443,7 +443,7 @@
  * events with nua_set_params() tag NUTAG_ALLOW_EVENTS(). 
  *
  * The nua_response() call responding to a PUBLISH request must have
- * NUTAG_WITH() (or NUTAG_WITH_CURRENT()/NUTAG_WITH_SAVED()) tag. Note that
+ * NUTAG_WITH() (or NUTAG_WITH_THIS()/NUTAG_WITH_SAVED()) tag. Note that
  * a successful response to PUBLISH @b MUST include @Expires and @SIPETag
  * headers.
  *

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c	Fri Apr 13 10:33:30 2007
@@ -881,7 +881,7 @@
     if (mindelta == SIP_TIME_MAX)
       mindelta = 3600;
 
-    nua_dialog_usage_set_expires(du, mindelta);
+    nua_dialog_usage_set_refresh(du, mindelta);
 
   /*  RFC 3608 Section 6.1 Procedures at the UA
 
@@ -935,7 +935,7 @@
     nua_registration_set_ready(nr, 1);
   }
   else if (du) {
-    nua_dialog_usage_set_expires(du, 0);
+    nua_dialog_usage_set_refresh(du, 0);
 
     su_free(nh->nh_home, nr->nr_route);
     nr->nr_route = NULL;

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_registrar.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_registrar.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_registrar.c	Fri Apr 13 10:33:30 2007
@@ -60,7 +60,7 @@
  * the REGISTER method with NUTAG_ALLOW() tag.
  *
  * The nua_response() call responding to a REGISTER request must have
- * NUTAG_WITH() (or NUTAG_WITH_CURRENT()/NUTAG_WITH_SAVED()) tag. Note that
+ * NUTAG_WITH() (or NUTAG_WITH_THIS()/NUTAG_WITH_SAVED()) tag. Note that
  * a successful response to REGISTER @b MUST include the @Contact header
  * bound to the the AoR URI (in @To header).
  *

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c	Fri Apr 13 10:33:30 2007
@@ -149,14 +149,23 @@
 
   unsigned        ss_precondition:1;	/**< Precondition required */
 
-  unsigned        ss_timer_set:1;       /**< We have active session timer. */
-
   unsigned        ss_reporting:1;       /**< True if reporting state */
   unsigned        : 0;
-  
-  unsigned        ss_session_timer;	/**< Value of Session-Expires (delta) */
-  unsigned        ss_min_se;		/**< Minimum session expires */
-  enum nua_session_refresher ss_refresher; /**< none, local or remote */
+
+  struct session_timer {
+    unsigned  interval;		/**< Negotiated expiration time */
+    enum nua_session_refresher refresher; /**< Our Negotiated role */
+
+    struct {
+      unsigned expires, defaults; /**< Value of Session-Expires (delta) */
+      unsigned min_se;	/**< Minimum session expires */
+      /** none, local or remote */
+      enum nua_session_refresher refresher;
+      unsigned    supported:1, require:1, :0;
+    } local, remote;
+
+    unsigned      timer_set:1;  /**< We have active session timer. */
+  } ss_timer[1];
 
   char const     *ss_reason;	        /**< Reason for termination. */
 
@@ -204,11 +213,16 @@
 			   nua_dialog_state_t *ds,
 			   nua_dialog_usage_t *du)
 {
+  nua_session_usage_t *ss = nua_dialog_usage_private(du);  
+
   if (ds->ds_has_session)
     return -1;
   ds->ds_has_session = 1;
   ds->ds_got_session = 1;
 
+  ss->ss_timer->local.refresher = nua_any_refresher;
+  ss->ss_timer->remote.refresher = nua_any_refresher;
+
   return 0;
 }
 
@@ -297,19 +311,29 @@
 int nua_stack_prack(nua_t *nua, nua_handle_t *nh, nua_event_t e,
 		    tagi_t const *tags);
 
-static void session_timer_preferences(nua_session_usage_t *ss,
-				      unsigned expires,
-				      unsigned min_se,
-				      enum nua_session_refresher refresher);
-
-static int session_timer_is_supported(nua_handle_t const *nh);
-
-static int prefer_session_timer(nua_handle_t const *nh);
-
-static int use_session_timer(nua_session_usage_t *ss, int uas, int always,
-			     msg_t *msg, sip_t *);
-static int init_session_timer(nua_session_usage_t *ss, sip_t const *, int refresher);
-static void set_session_timer(nua_session_usage_t *ss);
+static int session_timer_is_supported(struct session_timer const *t);
+
+static void session_timer_preferences(struct session_timer *t,
+				      sip_t const *sip,
+				      sip_supported_t const *supported,
+				      unsigned expires, int isset,
+				      enum nua_session_refresher refresher,
+				      unsigned min_se);
+
+static void session_timer_store(struct session_timer *t,
+				sip_t const *sip);
+
+static int session_timer_check_min_se(msg_t *msg, sip_t *sip,
+				      sip_t const *request,
+				      unsigned long min_se);
+
+static int session_timer_add_headers(struct session_timer *t,
+				     int initial,
+				     msg_t *msg, sip_t *sip);
+
+static void session_timer_negotiate(struct session_timer *t);
+
+static void session_timer_set(nua_session_usage_t *ss);
 
 static int session_timer_check_restart(nua_client_request_t *cr,
 				       int status, char const *phrase,
@@ -551,6 +575,7 @@
 {
   nua_handle_t *nh = cr->cr_owner;
   nua_dialog_usage_t *du;
+  nua_session_usage_t *ss;
 
   cr->cr_usage = du = nua_dialog_usage_for_session(nh->nh_ds);
   /* Errors returned by nua_invite_client_init() 
@@ -573,16 +598,22 @@
   }
   else
     du = nua_dialog_usage_add(nh, nh->nh_ds, nua_session_usage, NULL);
+
   if (!du)
     return -1;
 
   if (nua_client_bind(cr, du) < 0)
     return nua_client_return(cr, 900, "INVITE already in progress", msg);
 
-  session_timer_preferences(nua_dialog_usage_private(du), 
+  ss = nua_dialog_usage_private(du);
+
+  session_timer_preferences(ss->ss_timer,
+			    sip,
+			    NH_PGET(nh, supported),		     
 			    NH_PGET(nh, session_timer),
-			    NH_PGET(nh, min_se),
-			    NH_PGET(nh, refresher));
+			    NUA_PISSET(nh->nh_nua, nh, session_timer),
+			    NH_PGET(nh, refresher),
+			    NH_PGET(nh, min_se));
 
   cr->cr_neutral = 0;
 
@@ -608,12 +639,13 @@
   if (invite_timeout == 0)
     invite_timeout = UINT_MAX;
   /* Send CANCEL if we don't get response within timeout*/
-  nua_dialog_usage_set_expires(du, invite_timeout);
+  /* nua_dialog_usage_set_expires(du, invite_timeout); Xyzzy */
   nua_dialog_usage_set_refresh(du, 0);
 
   /* Add session timer headers */
-  if (session_timer_is_supported(nh))
-    use_session_timer(ss, 0, prefer_session_timer(nh), msg, sip);
+  if (session_timer_is_supported(ss->ss_timer))
+    session_timer_add_headers(ss->ss_timer, ss->ss_state == nua_callstate_init,
+			      msg, sip);
 
   ss->ss_100rel = NH_PGET(nh, early_media);
   ss->ss_precondition = sip_has_feature(sip->sip_require, "precondition");
@@ -672,7 +704,6 @@
 				      int status, char const *phrase,
 				      sip_t const *sip)
 {
-  nua_handle_t *nh = cr->cr_owner;
   nua_dialog_usage_t *du = cr->cr_usage;
   nua_session_usage_t *ss = nua_dialog_usage_private(du);
 
@@ -682,8 +713,10 @@
   else if (status < 300) {
     du->du_ready = 1;
 
-    init_session_timer(ss, sip, NH_PGET(nh, refresher));
-    set_session_timer(ss);
+    if (session_timer_is_supported(ss->ss_timer))
+      session_timer_store(ss->ss_timer, sip);
+
+    session_timer_set(ss);
   }
   
   return nua_session_client_response(cr, status, phrase, sip);
@@ -1263,42 +1296,37 @@
   nua_client_request_t const *cr = du->du_cr;
   nua_server_request_t const *sr;
 
-  assert(cr);
-
   if (ss->ss_state >= nua_callstate_terminating || 
-      /* No INVITE template */
-      cr == NULL || 
       /* INVITE is in progress or being authenticated */
-      cr->cr_orq || cr->cr_wait_for_cred)
+      (cr && (cr->cr_orq || cr->cr_wait_for_cred)))
     return;
 
-  /* UPDATE in progress or being authenticated */
+  /* UPDATE has been queued */
   for (cr = ds->ds_cr; cr; cr = cr->cr_next) 
     if (cr->cr_method == sip_method_update)
       return;
 
-  /* INVITE or UPDATE in progress */
+  /* INVITE or UPDATE in progress on server side */
   for (sr = ds->ds_sr; sr; sr = sr->sr_next)
     if (sr->sr_usage == du && 
 	(sr->sr_method == sip_method_invite || 
 	 sr->sr_method == sip_method_update))
       return;
 
-  if (!ss->ss_refresher) {
-    if (du->du_expires == 0 || now < du->du_expires)
-      /* Refresh contact & route set using re-INVITE */
-      nua_client_resend_request(du->du_cr, 0);
-    else {
-      ss->ss_reason = "SIP;cause=408;text=\"Session timeout\""; 
-      nua_stack_bye(nh->nh_nua, nh, nua_r_bye, NULL);
-    }
+  if (ss->ss_timer->refresher == nua_remote_refresher) {
+    ss->ss_reason = "SIP;cause=408;text=\"Session timeout\""; 
+    nua_stack_bye(nh->nh_nua, nh, nua_r_bye, NULL);
+    return;
   }
   else if (NH_PGET(nh, update_refresh)) {
     nua_stack_update(nh->nh_nua, nh, nua_r_update, NULL);
   }
-  else {
+  else if (du->du_cr) {
     nua_client_resend_request(du->du_cr, 0);
   }
+  else {
+    nua_stack_invite(nh->nh_nua, nh, nua_r_invite, NULL);
+  }
 }
 
 /** @interal Shut down session usage. 
@@ -1787,8 +1815,6 @@
 
   sip_t const *request = sr->sr_request.sip;
 
-  unsigned min = NH_PGET(nh, min_se);
-
   if (!sr->sr_initial)
     sr->sr_usage = nua_dialog_usage_get(nh->nh_ds, nua_session_usage, NULL);
 
@@ -1817,21 +1843,15 @@
   }
 
   if (request->sip_session_expires &&
-      nta_check_session_expires(NULL, request, min, TAG_END())) {
-    sip_min_se_t *min_se, min_se0[1];
-
-    min_se = sip_min_se_init(min_se0);
-    min_se->min_delta = min;
-    
-    if (request->sip_min_se && request->sip_min_se->min_delta > min)
-      min_se = request->sip_min_se;
-
-    sip_add_dup(msg, sip, (sip_header_t *)min_se);
-    
-    return SR_STATUS1(sr, SIP_422_SESSION_TIMER_TOO_SMALL);
+      sip_has_feature(NH_PGET(nh, supported), "timer") &&
+      session_timer_check_min_se(msg, sip, request, NH_PGET(nh, min_se))) {
+    if (sip->sip_min_se)
+      return SR_STATUS1(sr, SIP_422_SESSION_TIMER_TOO_SMALL);
+    else
+      return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
   }
 
-  session_get_description(sr->sr_request.sip, &sr->sr_sdp, &sr->sr_sdp_len);
+  session_get_description(request, &sr->sr_sdp, &sr->sr_sdp_len);
 
   return 0;
 }
@@ -1885,14 +1905,7 @@
   if (ss->ss_precondition)
     ss->ss_100rel = 1;
 
-  session_timer_preferences(ss, 
-			    NH_PGET(nh, session_timer),
-			    NH_PGET(nh, min_se),
-			    NH_PGET(nh, refresher));
-
-  /* Session Timer negotiation */
-  if (sip_has_supported(NH_PGET(nh, supported), "timer"))
-    init_session_timer(ss, request, ss->ss_refresher);
+  session_timer_store(ss->ss_timer, request);
 
   assert(ss->ss_state >= nua_callstate_ready ||
 	 ss->ss_state == nua_callstate_init);
@@ -2043,9 +2056,18 @@
     return 0;
   }
 
-  if (ss->ss_refresher && 200 <= sr->sr_status && sr->sr_status < 300)
-    if (session_timer_is_supported(nh))
-      use_session_timer(ss, 1, 1, msg, sip);
+  if (200 <= sr->sr_status && sr->sr_status < 300) {
+    session_timer_preferences(ss->ss_timer,
+			      sip,
+			      NH_PGET(nh, supported),		     
+			      NH_PGET(nh, session_timer),
+			      NUA_PISSET(nh->nh_nua, nh, session_timer),
+			      NH_PGET(nh, refresher),
+			      NH_PGET(nh, min_se));
+
+    if (session_timer_is_supported(ss->ss_timer))
+      session_timer_add_headers(ss->ss_timer, 0, msg, sip);
+  }
 
   return nua_base_server_respond(sr, tags);  
 }
@@ -2249,7 +2271,7 @@
 
   nua_stack_event(nh->nh_nua, nh, msg, nua_i_ack, SIP_200_OK, NULL);
   signal_call_state_change(nh, ss, 200, "OK", nua_callstate_ready);
-  set_session_timer(ss);
+  session_timer_set(ss);
 
   nua_server_request_destroy(sr);
 
@@ -2560,171 +2582,6 @@
 }
 
 /* ---------------------------------------------------------------------- */
-/* Session timer - RFC 4028 */
-
-static int session_timer_is_supported(nua_handle_t const *nh)
-{
-  /* Is timer feature supported? */
-  return sip_has_supported(NH_PGET(nh, supported), "timer");
-}
-
-static int prefer_session_timer(nua_handle_t const *nh)
-{
-  return 
-    NH_PGET(nh, refresher) != nua_no_refresher || 
-    NH_PGET(nh, session_timer) != 0;
-}
-
-/* Initialize session timer */ 
-static
-void session_timer_preferences(nua_session_usage_t *ss,
-			       unsigned expires,
-			       unsigned min_se,
-			       enum nua_session_refresher refresher)
-{
-  if (expires < min_se)
-    expires = min_se;
-  if (refresher && expires == 0)
-    expires = 3600;
-
-  ss->ss_min_se = min_se;
-  ss->ss_session_timer = expires;
-  ss->ss_refresher = refresher;
-}
-
-
-/** Add timer featuretag and Session-Expires/Min-SE headers */
-static int
-use_session_timer(nua_session_usage_t *ss, int uas, int always,
-		  msg_t *msg, sip_t *sip)
-{
-  sip_min_se_t min_se[1];
-  sip_session_expires_t session_expires[1];
-
-  static sip_param_t const x_params_uac[] = {"refresher=uac", NULL};
-  static sip_param_t const x_params_uas[] = {"refresher=uas", NULL};
-
-  /* Session-Expires timer */
-  if (ss->ss_refresher == nua_no_refresher && !always)
-    return 0;
-
-  sip_min_se_init(min_se)->min_delta = ss->ss_min_se;
-  sip_session_expires_init(session_expires)->x_delta = ss->ss_session_timer;
-
-  if (ss->ss_refresher == nua_remote_refresher)
-    session_expires->x_params = uas ? x_params_uac : x_params_uas;
-  else if (ss->ss_refresher == nua_local_refresher)
-    session_expires->x_params = uas ? x_params_uas : x_params_uac;
-
-  sip_add_tl(msg, sip,
-	     TAG_IF(ss->ss_session_timer,
-		    SIPTAG_SESSION_EXPIRES(session_expires)),
-	     TAG_IF(ss->ss_min_se != 0
-		    /* Min-SE: 0 is optional with initial INVITE */
-		    || ss->ss_state != nua_callstate_init,
-		    SIPTAG_MIN_SE(min_se)),
-	     TAG_IF(ss->ss_refresher == nua_remote_refresher,
-		    SIPTAG_REQUIRE_STR("timer")),
-	     TAG_END());
-
-  return 1;
-}
-
-static int
-init_session_timer(nua_session_usage_t *ss,
-		   sip_t const *sip,
-		   int refresher)
-{
-  int server;
-
-  /* Session timer is not needed */
-  if (!sip->sip_session_expires) {
-    if (!sip_has_supported(sip->sip_supported, "timer"))
-      ss->ss_refresher = nua_local_refresher;
-    return 0;
-  }
-
-  ss->ss_refresher = nua_no_refresher;
-  ss->ss_session_timer = sip->sip_session_expires->x_delta;
-
-  if (sip->sip_min_se != NULL
-      && sip->sip_min_se->min_delta > ss->ss_min_se)
-    ss->ss_min_se = sip->sip_min_se->min_delta;
-
-  server = sip->sip_request != NULL;
-
-  if (!sip_has_supported(sip->sip_supported, "timer"))
-    ss->ss_refresher = nua_local_refresher;
-  else if (!str0casecmp("uac", sip->sip_session_expires->x_refresher))
-    ss->ss_refresher = server ? nua_remote_refresher : nua_local_refresher;
-  else if (!str0casecmp("uas", sip->sip_session_expires->x_refresher))
-    ss->ss_refresher = server ? nua_local_refresher : nua_remote_refresher;
-  else if (!server)
-    return 0;			/* XXX */
-  /* User preferences */
-  else if (refresher == nua_local_refresher)
-    ss->ss_refresher = nua_local_refresher;
-  else
-    ss->ss_refresher = nua_remote_refresher;
-
-  SU_DEBUG_7(("nua session: session expires in %u refreshed by %s (%s %s)\n",
-	      ss->ss_session_timer,
-	      ss->ss_refresher == nua_local_refresher ? "local" : "remote",
-	      server ? sip->sip_request->rq_method_name : "response to",
-	      server ? "request" : sip->sip_cseq->cs_method_name));
-
-  return 1;
-}
-
-static int session_timer_check_restart(nua_client_request_t *cr,
-				       int status, char const *phrase,
-				       sip_t const *sip)
-{
-  if (cr->cr_usage && status == 422) {
-    nua_session_usage_t *ss = nua_dialog_usage_private(cr->cr_usage);
-
-    if (sip->sip_min_se && ss->ss_min_se < sip->sip_min_se->min_delta)
-      ss->ss_min_se = sip->sip_min_se->min_delta;
-    if (ss->ss_min_se > ss->ss_session_timer)
-      ss->ss_session_timer = ss->ss_min_se;
-  
-    return nua_client_restart(cr, 100, "Re-Negotiating Session Timer");
-  }
-
-  return nua_base_client_check_restart(cr, status, phrase, sip);
-}
-
-static void
-set_session_timer(nua_session_usage_t *ss)
-{
-  nua_dialog_usage_t *du = nua_dialog_usage_public(ss);
-
-  if (ss == NULL)
-    return;
-
-  if (ss->ss_refresher == nua_local_refresher) {
-    ss->ss_timer_set = 1;
-    nua_dialog_usage_set_expires(du, ss->ss_session_timer);
-  }
-  else if (ss->ss_refresher == nua_remote_refresher) {
-    ss->ss_timer_set = 1;
-    nua_dialog_usage_set_expires(du, ss->ss_session_timer + 32);
-    nua_dialog_usage_reset_refresh(du);
-  }
-  else {
-    ss->ss_timer_set = 0;
-    nua_dialog_usage_set_expires(du, UINT_MAX);
-    nua_dialog_usage_reset_refresh(du);
-  }
-}
-
-static inline int
-is_session_timer_set(nua_session_usage_t *ss)
-{
-  return ss->ss_timer_set;
-}
-
-/* ---------------------------------------------------------------------- */
 /* Automatic notifications from a referral */
 
 static int
@@ -2787,7 +2644,6 @@
   return 0;
 }
 
-
 static void
 nh_referral_respond(nua_handle_t *nh, int status, char const *phrase)
 {
@@ -3099,8 +2955,17 @@
   }
 
   /* Add session timer headers */
-  if (session_timer_is_supported(nh))
-    use_session_timer(ss, 0, prefer_session_timer(nh), msg, sip);
+  session_timer_preferences(ss->ss_timer,
+			    sip,
+			    NH_PGET(nh, supported),		     
+			    NH_PGET(nh, session_timer),
+			    NUA_PISSET(nh->nh_nua, nh, session_timer),
+			    NH_PGET(nh, refresher),
+			    NH_PGET(nh, min_se));
+
+  if (session_timer_is_supported(ss->ss_timer))
+    session_timer_add_headers(ss->ss_timer, ss->ss_state < nua_callstate_ready,
+			      msg, sip);
 
   retval = nua_base_client_request(cr, msg, sip, NULL);
 
@@ -3109,9 +2974,15 @@
     ss->ss_update_needed = 0;
 
     if (!cr->cr_restarting) {
+      enum nua_callstate state = ss->ss_state;
+
+      if (state == nua_callstate_ready)
+	state = nua_callstate_calling;
+
       if (offer_sent)
 	ss->ss_oa_sent = "offer";
-      signal_call_state_change(nh, ss, 0, "UPDATE sent", ss->ss_state);
+
+      signal_call_state_change(nh, ss, 0, "UPDATE sent", state);
     }
   }
 
@@ -3129,9 +3000,18 @@
   assert(200 <= status);
 
   if (ss && sip && status < 300) {
-    if (is_session_timer_set(ss)) {
-      init_session_timer(ss, sip, NH_PGET(nh, refresher));
-      set_session_timer(ss);
+    if (session_timer_is_supported(ss->ss_timer)) {
+      nua_server_request_t *sr;
+
+      for (sr = nh->nh_ds->ds_sr; sr; sr = sr->sr_next)
+	if (sr->sr_method == sip_method_invite ||
+	    sr->sr_method == sip_method_update)
+	  break;
+
+      if (!sr && (!du->du_cr || !du->du_cr->cr_orq)) {
+	session_timer_store(ss->ss_timer, sip);
+	session_timer_set(ss);
+      }
     }
   }
 
@@ -3225,7 +3105,7 @@
 
   /* Do session timer negotiation */
   if (request->sip_session_expires)
-    init_session_timer(ss, request, NH_PGET(nh, refresher));
+    session_timer_store(ss->ss_timer, request);
 
   if (sr->sr_sdp) {		/* Check for overlap */
     nua_client_request_t *cr;
@@ -3306,11 +3186,28 @@
     }
   }
 
-  if (ss->ss_refresher && 200 <= sr->sr_status && sr->sr_status < 300)
-    if (session_timer_is_supported(nh)) {
-      use_session_timer(ss, 1, 1, msg, sip);
-      set_session_timer(ss);	/* XXX */
+  if (200 <= sr->sr_status && sr->sr_status < 300) {
+    session_timer_preferences(ss->ss_timer,
+			      sip,
+			      NH_PGET(nh, supported),		     
+			      NH_PGET(nh, session_timer),
+			      NUA_PISSET(nh->nh_nua, nh, session_timer),
+			      NH_PGET(nh, refresher),
+			      NH_PGET(nh, min_se));
+
+    if (ss && session_timer_is_supported(ss->ss_timer)) {
+      nua_server_request_t *sr0;
+
+      session_timer_add_headers(ss->ss_timer, 0, msg, sip);
+
+      for (sr0 = nh->nh_ds->ds_sr; sr0; sr0 = sr0->sr_next)
+	if (sr0->sr_method == sip_method_invite)
+	  break;
+
+      if (!sr0 && (!sr->sr_usage->du_cr || !sr->sr_usage->du_cr->cr_orq))
+	session_timer_set(ss);
     }
+  }
 
   return nua_base_server_respond(sr, tags);
 }
@@ -3348,9 +3245,15 @@
     return retval;
   }
 
-  if (offer_recv_or_answer_sent)
+  if (offer_recv_or_answer_sent) {
     /* signal offer received, answer sent */
-    signal_call_state_change(nh, ss, status, phrase, ss->ss_state);
+    enum nua_callstate state = ss->ss_state;
+    
+    if (state == nua_callstate_ready && status < 200)
+      state = nua_callstate_received;
+
+    signal_call_state_change(nh, ss, status, phrase, state);
+  }
 
   if (200 <= status && status < 300
       && ss->ss_state < nua_callstate_ready
@@ -3900,6 +3803,287 @@
 }
 
 /* ======================================================================== */
+/* Session timer - RFC 4028 */
+
+static int session_timer_is_supported(struct session_timer const *t)
+{
+  return t->local.supported;
+}
+
+/** Set session timer preferences  */ 
+static
+void session_timer_preferences(struct session_timer *t,
+			       sip_t const *sip,
+			       sip_supported_t const *supported,
+			       unsigned expires,
+			       int isset,
+			       enum nua_session_refresher refresher,
+			       unsigned min_se)
+{
+  memset(&t->local, 0, sizeof t->local);
+
+  t->local.require = sip_has_feature(sip->sip_require, "timer");
+  t->local.supported =
+    sip_has_feature(supported, "timer") ||
+    sip_has_feature(sip->sip_supported, "timer");
+  if (isset || refresher != nua_no_refresher)
+    t->local.expires = expires;
+  else
+    t->local.defaults = expires;
+  t->local.min_se = min_se;
+  t->local.refresher = refresher;
+}
+
+static int session_timer_check_restart(nua_client_request_t *cr,
+				       int status, char const *phrase,
+				       sip_t const *sip)
+{
+  if (status == 422) {
+    nua_session_usage_t *ss = nua_dialog_usage_private(cr->cr_usage);
+
+    if (ss && session_timer_is_supported(ss->ss_timer)) {
+      struct session_timer *t = ss->ss_timer;
+
+      if (sip->sip_min_se && t->local.min_se < sip->sip_min_se->min_delta)
+	t->local.min_se = sip->sip_min_se->min_delta;
+      if (t->local.expires != 0 && t->local.min_se > t->local.expires)
+	t->local.expires = t->local.min_se;
+  
+      return nua_client_restart(cr, 100, "Re-Negotiating Session Timer");
+    }
+  }
+
+  return nua_base_client_check_restart(cr, status, phrase, sip);
+}
+
+/** Check that received Session-Expires is longer than Min-SE */
+static
+int session_timer_check_min_se(msg_t *msg,
+			       sip_t *sip,
+			       sip_t const *request,
+			       unsigned long min)
+{
+  if (min == 0)
+    min = 1;
+
+  /*
+   If an incoming request contains a Supported header field with a value
+   'timer' and a Session Expires header field, the UAS MAY reject the
+   INVITE request with a 422 (Session Interval Too Small) response if
+   the session interval in the Session-Expires header field is smaller
+   than the minimum interval defined by the UAS' local policy.  When
+   sending the 422 response, the UAS MUST include a Min-SE header field
+   with the value of its minimum interval.  This minimum interval MUST
+   NOT be lower than 90 seconds.
+  */
+  if (request->sip_session_expires &&
+      sip_has_feature(request->sip_supported, "timer") &&
+      request->sip_session_expires->x_delta < min) {
+    sip_min_se_t min_se[1];
+
+    if (min < 90)
+      min = 90;
+
+    sip_min_se_init(min_se)->min_delta = min;
+
+    /* Include extension parameters, if any */
+    if (request->sip_min_se)
+      min_se->min_params = request->sip_min_se->min_params;
+    
+    sip_add_dup(msg, sip, (sip_header_t *)min_se);
+
+    return 422;
+  }
+
+  return 0;
+}
+
+/** Store session timer parameters in request from uac / response from uas */ 
+static
+void session_timer_store(struct session_timer *t,
+			 sip_t const *sip)
+{
+  sip_require_t const *require = sip->sip_require;
+  sip_supported_t const *supported = sip->sip_supported;
+  sip_session_expires_t const *x = sip->sip_session_expires;
+
+  t->remote.require = require && sip_has_feature(require, "timer");
+  t->remote.supported =
+    t->remote.supported || (supported && sip_has_feature(supported, "timer"));
+
+  t->remote.expires = 0;
+  t->remote.refresher = nua_any_refresher;
+  t->remote.min_se = 0;
+
+  if (x) {
+    t->remote.expires = x->x_delta;
+
+    if (x->x_refresher) {
+      int uas = sip->sip_request != NULL;
+
+      if (strcasecmp(x->x_refresher, "uac") == 0)
+	t->remote.refresher = uas ? nua_remote_refresher : nua_local_refresher;
+      else if (strcasecmp(x->x_refresher, "uas") == 0)
+	t->remote.refresher = uas ? nua_local_refresher : nua_remote_refresher;
+    }
+  }
+
+  if (sip->sip_min_se)
+    t->remote.min_se = sip->sip_min_se->min_delta;
+}
+
+/** Add timer feature and Session-Expires/Min-SE headers to request/response
+ * 
+ */
+static int
+session_timer_add_headers(struct session_timer *t,
+			  int initial,
+			  msg_t *msg, sip_t *sip)
+{
+  unsigned long expires, min;
+  sip_min_se_t min_se[1];
+  sip_session_expires_t x[1];
+  int uas;
+
+  enum nua_session_refresher refresher = nua_any_refresher;
+
+  static sip_param_t const x_params_uac[] = {"refresher=uac", NULL};
+  static sip_param_t const x_params_uas[] = {"refresher=uas", NULL};
+
+  if (!t->local.supported)
+    return 0;
+
+  uas = sip->sip_status != NULL;
+
+  min = t->local.min_se;
+  if (min < t->remote.min_se)
+    min = t->remote.min_se;
+
+  if (uas) {
+    session_timer_negotiate(t);
+    
+    refresher = t->refresher;
+    expires = t->interval;
+  }
+  else {
+    /* RFC 4028:
+     * The UAC MAY include the refresher parameter with value 'uac' if it
+     * wants to perform the refreshes.  However, it is RECOMMENDED that the
+     * parameter be omitted so that it can be selected by the negotiation
+     * mechanisms described below.
+     */
+    if (t->local.refresher == nua_local_refresher)
+      refresher = nua_local_refresher;
+
+    expires = t->local.expires;
+    if (expires != 0 && expires < min)
+      expires = min;
+  }
+
+  sip_min_se_init(min_se)->min_delta = min;
+
+  sip_session_expires_init(x)->x_delta = expires;
+  if (refresher == nua_remote_refresher)
+    x->x_params = uas ? x_params_uac : x_params_uas;
+  else if (refresher == nua_local_refresher)
+    x->x_params = uas ? x_params_uas : x_params_uac;
+
+  sip_add_tl(msg, sip,
+	     TAG_IF(expires != 0, SIPTAG_SESSION_EXPIRES(x)),
+	     TAG_IF(min != 0
+		    /* Min-SE: 0 is optional with initial INVITE */
+		    || !initial,
+		    SIPTAG_MIN_SE(min_se)),
+	     TAG_IF(refresher == nua_remote_refresher && expires != 0,
+		    SIPTAG_REQUIRE_STR("timer")),
+	     TAG_END());
+
+  return 1;
+}
+
+static
+void session_timer_negotiate(struct session_timer *t)
+{
+  if (!t->local.supported)
+    t->refresher = nua_no_refresher;
+  else if (!t->remote.supported)
+    t->refresher = nua_local_refresher;
+  else if (t->remote.refresher == nua_local_refresher)
+    t->refresher = nua_local_refresher;
+  else if (t->remote.refresher == nua_remote_refresher)
+    t->refresher = nua_remote_refresher;
+  else if (t->local.refresher == nua_local_refresher)
+    t->refresher = nua_local_refresher;
+  else
+    t->refresher = nua_remote_refresher;
+
+  t->interval = t->remote.expires;
+  if (t->interval == 0)
+    t->interval = t->local.expires;
+  if (t->local.expires != 0 && t->interval > t->local.expires)
+    t->interval = t->local.expires;
+  if (t->local.defaults != 0 && t->interval > t->local.defaults)
+    t->interval = t->local.defaults;
+    
+  if (t->interval != 0) {
+    if (t->interval < t->local.min_se)
+      t->interval = t->local.min_se;
+    if (t->interval < t->remote.min_se)
+      t->interval = t->remote.min_se;
+  }
+
+  if (t->interval == 0)
+    t->refresher = nua_no_refresher;
+}
+
+static void
+session_timer_set(nua_session_usage_t *ss)
+{
+  nua_dialog_usage_t *du = nua_dialog_usage_public(ss);
+  struct session_timer *t;
+
+  if (ss == NULL)
+    return;
+
+  t = ss->ss_timer;
+
+  session_timer_negotiate(t);
+
+  if (t->refresher == nua_local_refresher) {
+    unsigned low = t->interval / 2, high = t->interval / 2;
+
+    if (t->interval >= 90)
+      low -=5, high += 5;
+
+    nua_dialog_usage_refresh_range(du, low, high);
+    t->timer_set = 1;
+  }
+  else if (t->refresher == nua_remote_refresher) {
+    /* if the side not performing refreshes does not receive a
+       session refresh request before the session expiration, it SHOULD send
+       a BYE to terminate the session, slightly before the session
+       expiration.  The minimum of 32 seconds and one third of the session
+       interval is RECOMMENDED. */
+    unsigned interval = t->interval;
+
+    interval -= 32 > interval / 6 ? interval / 3 : 32 + interval / 3;
+
+    nua_dialog_usage_refresh_range(du, interval, interval);
+    t->timer_set = 1;
+  }
+  else {
+    nua_dialog_usage_reset_refresh(du);
+    t->timer_set = 0;
+  }
+}
+
+static inline int
+session_timer_has_been_set(struct session_timer const *t)
+{
+  return t->timer_set;
+}
+
+/* ======================================================================== */
 
 /** Get SDP from a SIP message.
  *
@@ -4020,6 +4204,8 @@
   return retval;
 }
 
+/* ====================================================================== */
+
 /** @NUA_EVENT nua_i_options
  *
  * Incoming OPTIONS request. The user-agent should respond to an OPTIONS
@@ -4093,4 +4279,3 @@
 
   return nua_base_server_respond(sr, tags);
 }
-

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c	Fri Apr 13 10:33:30 2007
@@ -989,11 +989,10 @@
 nua_stack_authenticate(nua_t *nua, nua_handle_t *nh, nua_event_t e,
 		       tagi_t const *tags)
 {
+  nua_client_request_t *cr = nh->nh_ds->ds_cr;
   int status = nh_authorize(nh, TAG_NEXT(tags));
 
   if (status > 0) {
-    nua_client_request_t *cr = nh->nh_ds->ds_cr;
-
     if (cr && cr->cr_wait_for_cred) {
       nua_client_restart_request(cr, cr->cr_terminating, tags);
     }
@@ -1003,6 +1002,14 @@
 		      NULL);
     }
   }
+  else if (cr && cr->cr_wait_for_cred) {
+    cr->cr_wait_for_cred = 0;
+
+    if (status < 0)
+      nua_client_response(cr, 900, "Cannot add credentials", NULL);
+    else
+      nua_client_response(cr, 904, "No matching challenge", NULL);
+  }
   else if (status < 0) {
     nua_stack_event(nua, nh, NULL, e, 900, "Cannot add credentials", NULL);
   }
@@ -1049,6 +1056,7 @@
   nua_server_methods_t const *sm;
   nua_server_request_t *sr, sr0[1];
   int status, initial = 1;
+  int create_dialog;
 
   char const *user_agent = NH_PGET(nh, user_agent);
   sip_supported_t const *supported = NH_PGET(nh, supported);
@@ -1135,11 +1143,15 @@
     return 481;
   }
 
+  create_dialog = sm->sm_flags.create_dialog;
+  if (method == sip_method_message && NH_PGET(nh, win_messenger_enable))
+    create_dialog = 1;
   sr = memset(sr0, 0, (sizeof sr0));
 
   sr->sr_methods = sm;
   sr->sr_method = method = sip->sip_request->rq_method;
   sr->sr_add_contact = sm->sm_flags.add_contact;
+  sr->sr_target_refresh = sm->sm_flags.target_refresh;
 
   sr->sr_owner = nh;
   sr->sr_initial = initial;
@@ -1171,12 +1183,12 @@
   }
 
   if (sr->sr_status < 300 && sm->sm_preprocess && sm->sm_preprocess(sr)) {
-    if (sr->sr_status < 200)    /* Preprocess may have set response status */
+    if (sr->sr_status < 200)    /* Set response status if preprocess did not */
       SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
   }
 
   if (sr->sr_status < 300) {
-    if (sm->sm_flags.target_refresh)
+    if (sr->sr_target_refresh)
       nua_dialog_uas_route(nh, nh->nh_ds, sip, 1); /* Set route and tags */
     nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
   }
@@ -1273,7 +1285,7 @@
  * content negotiation fails.
  *
  * When responding to an incoming INVITE request, the nua_respond() can be
- * called without NUTAG_WITH() (or NUTAG_WITH_CURRENT() or
+ * called without NUTAG_WITH() (or NUTAG_WITH_THIS() or
  * NUTAG_WITH_SAVED()). Otherwise, NUTAG_WITH() will contain an indication
  * of the request being responded.
  *
@@ -1302,7 +1314,7 @@
  *    nothing
  *
  * @par Related Tags:
- *    NUTAG_WITH(), NUTAG_WITH_CURRENT(), NUTAG_WITH_SAVED() \n
+ *    NUTAG_WITH(), NUTAG_WITH_THIS(), NUTAG_WITH_SAVED() \n
  *    NUTAG_EARLY_ANSWER() \n
  *    SOATAG_ADDRESS() \n
  *    SOATAG_AF() \n
@@ -1696,6 +1708,7 @@
   cr->cr_method = method;
   cr->cr_method_name = name;
   cr->cr_contactize = methods->crm_flags.target_refresh;
+  cr->cr_dialog = methods->crm_flags.create_dialog;
   cr->cr_auto = 1;
 
   if (su_msg_is_non_null(nh->nh_nua->nua_signal)) {
@@ -1927,6 +1940,10 @@
       has_contact = 1;
     else if (t->t_tag == nutag_url)
       url = (url_string_t const *)t->t_value;
+    else if (t->t_tag == nutag_dialog) {
+      cr->cr_dialog = t->t_value > 1;
+      cr->cr_contactize = t->t_value >= 1;
+    }
     else if (t->t_tag == nutag_auth && t->t_value) {
       /* XXX ignoring errors */
       if (nh->nh_auth)
@@ -1965,7 +1982,7 @@
 	sip_add_dup(msg, sip, (sip_header_t *)nua->nua_from) < 0)
       goto error;
 
-    if (cr->cr_methods->crm_flags.create_dialog) {
+    if (cr->cr_dialog) {
       ds->ds_leg = nta_leg_tcreate(nua->nua_nta,
 				   nua_stack_process_request, nh,
 				   SIPTAG_CALL_ID(sip->sip_call_id),
@@ -2030,7 +2047,6 @@
       if (sip_add_tagis(cr->cr_msg, NULL, &tags) < 0)
 	/* XXX */;
 
-    cr->cr_retry_count = 0;
     cr->cr_terminating = terminating;
 
     return nua_client_request_try(cr);
@@ -2125,6 +2141,8 @@
 
   assert(cr->cr_orq == NULL);
 
+  cr->cr_retry_count++;
+
   if (ds->ds_leg)
     leg = ds->ds_leg;
   else
@@ -2161,7 +2179,7 @@
    * are used: @Allow, @Supported, @Organization, and @UserAgent headers are
    * added to the request if they are not already set. 
    */
-  if (!sip->sip_allow && !ds->ds_route)
+  if (!sip->sip_allow)
     sip_add_dup(msg, sip, (sip_header_t*)NH_PGET(nh, allow));
   
   if (!sip->sip_supported && NH_PGET(nh, supported))
@@ -2337,7 +2355,7 @@
     }
     else {
       if (sip) {
-	if (cr->cr_methods->crm_flags.target_refresh)
+	if (cr->cr_contactize)
 	  nua_dialog_uac_route(nh, nh->nh_ds, sip, 1);
 	nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
       }
@@ -2392,7 +2410,7 @@
 
   assert(cr && status >= 200 && phrase && sip);
 
-  if (cr->cr_retry_count >= NH_PGET(nh, retry_count))
+  if (cr->cr_retry_count > NH_PGET(nh, retry_count))
     return 0;
 
   if (cr->cr_methods->crm_check_restart)
@@ -2482,7 +2500,6 @@
 
       orq = cr->cr_orq, cr->cr_orq = NULL;
       cr->cr_wait_for_cred = 1;
-      cr->cr_retry_count++;
       nua_client_report(cr, status, phrase, NULL, orq, NULL);
       nta_outgoing_destroy(orq);
 
@@ -2507,7 +2524,7 @@
   msg_t *msg;
   sip_t *sip;
 
-  if (++cr->cr_retry_count > NH_PGET(nh, retry_count))
+  if (cr->cr_retry_count > NH_PGET(nh, retry_count))
     return 0;
 
   orq = cr->cr_orq, cr->cr_orq = NULL;  assert(orq);
@@ -2641,22 +2658,23 @@
 
   if (cr->cr_terminated < 0) {
     /* XXX - dialog has been terminated */;
-    nua_dialog_deinit(nh, nh->nh_ds);
+    nua_dialog_deinit(nh, nh->nh_ds), cr->cr_usage = NULL;
   }
   else if (du) {
     if (cr->cr_terminated ||
 	(!du->du_ready && status >= 300 && nua_client_is_bound(cr))) {
       /* Usage has been destroyed */
-      nua_dialog_usage_remove(nh, nh->nh_ds, du);
+      nua_dialog_usage_remove(nh, nh->nh_ds, du), cr->cr_usage = NULL;
     }
     else if (cr->cr_graceful) {
       /* Terminate usage gracefully */
-      nua_dialog_usage_shutdown(nh, nh->nh_ds, du); 
+      if (nua_dialog_usage_shutdown(nh, nh->nh_ds, du) > 0)
+	cr->cr_usage = NULL;
     }
   }
   else if (cr->cr_terminated) {
     if (nh->nh_ds->ds_usage == NULL)
-      nua_dialog_remove(nh, nh->nh_ds, NULL);
+      nua_dialog_remove(nh, nh->nh_ds, NULL), cr->cr_usage = NULL;
   }
 
   cr->cr_reporting = 0, nh->nh_ds->ds_reporting = 0;

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h	Fri Apr 13 10:33:30 2007
@@ -336,8 +336,6 @@
 					sip_t const *sip,
 					int create_dialog);
 
-enum { create_dialog = 1 };
-
 int nua_stack_init_handle(nua_t *nua, nua_handle_t *nh, 
 			  tag_type_t tag, tag_value_t value, ...);
 

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c	Fri Apr 13 10:33:30 2007
@@ -61,6 +61,7 @@
   enum nua_substate eu_substate;	/**< Subscription state */
   sip_time_t eu_expires;	        /**< Proposed expiration time */
   unsigned eu_notified;		        /**< Number of NOTIFYs received */
+  unsigned eu_unsolicited:1;	        /**< Not SUBSCRIBEd or REFERed */
   unsigned eu_refer:1;		        /**< Implied subscription by refer */
   unsigned eu_final_wait:1;	        /**< Waiting for final NOTIFY */
   unsigned eu_no_id:1;		        /**< Do not use "id" (even if we have one) */
@@ -443,11 +444,12 @@
      */
   }
 
-  nua_stack_tevent(nh->nh_nua, nh, NULL,
-		   nua_i_notify, NUA_INTERNAL_ERROR,
-		   NUTAG_SUBSTATE(nua_substate_terminated),
-		   SIPTAG_EVENT(du->du_event),
-		   TAG_END());
+  if (!eu->eu_unsolicited)
+    nua_stack_tevent(nh->nh_nua, nh, NULL,
+		     nua_i_notify, NUA_INTERNAL_ERROR,
+		     NUTAG_SUBSTATE(nua_substate_terminated),
+		     SIPTAG_EVENT(du->du_event),
+		     TAG_END());
 
   nua_dialog_usage_remove(nh, ds, du);
 }
@@ -504,10 +506,10 @@
     SIP_METHOD_NOTIFY,
     nua_i_notify,		/* Event */
     { 
-      1,			/* Do create dialog */
-      0,			/* Not always in-dialog request */
-      1,			/* Target refresh request  */
-      1,			/* Add Contact to response */
+      /* create_dialog: */ 1,	/* Do create dialog */
+      /* in_dialog: */ 0,	/* Not always in-dialog request */
+      /* target_refresh: */ 1,	/* Target refresh request  */
+      /* add_contact: */ 1,	/* Add Contact to response */
     },
     nua_notify_server_init,
     nua_notify_server_preprocess,
@@ -557,17 +559,21 @@
   enum nua_substate substate = nua_substate_terminated;
   sip_subscription_state_t *subs = sip->sip_subscription_state;
   char const *what = "", *reason = NULL;
+  int solicited = 1;
 
   du = nua_dialog_usage_get(ds, nua_subscribe_usage, o);
-  sr->sr_usage = du;
 
   if (du == NULL) {
     if (!sip_is_allowed(NH_PGET(sr->sr_owner, appl_method), SIP_METHOD_NOTIFY))
       return SR_STATUS(sr, 481, "Subscription Does Not Exist");
-    /* Let application to handle unsolicited NOTIFY */
-    return 0;
+
+    solicited = 0;    /* Let application to handle unsolicited NOTIFY */
+    du = nua_dialog_usage_add(sr->sr_owner, ds, nua_subscribe_usage, o);
+    if (!du)
+      return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
   }
   
+  sr->sr_usage = du;
   eu = nua_dialog_usage_private(du); assert(eu);
   eu->eu_notified++;
   if (!o->o_id) 
@@ -602,12 +608,17 @@
   }
 
   eu->eu_substate = substate;
+  if (!solicited)
+    eu->eu_unsolicited = 1;
 
   SU_DEBUG_5(("nua(%p): %s: %s (%s)\n", 
 	      (void *)sr->sr_owner, "nua_notify_server_preprocess",
 	      what, reason ? reason : ""));
 
-  return SR_STATUS1(sr, SIP_200_OK);
+  if (solicited)
+    return SR_STATUS1(sr, SIP_200_OK);
+
+  return 0;
 }
 
 
@@ -656,10 +667,13 @@
 				   NUTAG_SUBSTATE(substate),
 				   TAG_NEXT(tags)); 
 
-  if (retval >= 2 || du == NULL)
+  if (retval != 1 || du == NULL)
     return retval;
 
-  if (retry >= 0) {		/* Try to subscribe again */
+  if (eu->eu_unsolicited) {
+    /* Xyzzy */;
+  }
+  else if (retry >= 0) {		/* Try to subscribe again */
     /* XXX - this needs through testing */
     nua_dialog_remove(nh, nh->nh_ds, du); /* tear down */
     nua_dialog_usage_refresh_range(du, retry, retry + 5);

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c	Fri Apr 13 10:33:30 2007
@@ -149,3 +149,4 @@
 tag_typedef_t nutag_detect_network_updates = UINTTAG_TYPEDEF(detect_network_updates);
 
 tag_typedef_t nutag_with = PTRTAG_TYPEDEF(with);
+tag_typedef_t nutag_dialog = UINTTAG_TYPEDEF(dialog);

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua.h
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua.h	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua.h	Fri Apr 13 10:33:30 2007
@@ -346,6 +346,9 @@
 			     tag_type_t, tag_value_t, 
 			     ...);
 
+/** Check if event can be responded with nua_respond() */
+SOFIAPUBFUN int nua_event_is_incoming_request(nua_event_t e);
+
 #define nua_handle_home(nh) ((su_home_t *)(nh))
 
 /** Generate an instance identifier */

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h	Fri Apr 13 10:33:30 2007
@@ -157,6 +157,9 @@
  */
 #define NUTAG_WITH_THIS(nua) nutag_with, tag_ptr_v(nua_current_request((nua)))
 
+#define NUTAG_WITH_CURRENT(nua) \
+   nutag_with, tag_ptr_v(nua_current_request((nua)))
+
 /**Specify request to respond to.
  *
  * @par Used with
@@ -174,6 +177,26 @@
  */
 #define NUTAG_WITH_SAVED(e) nutag_with, tag_ptr_v(nua_saved_event_request((e)))
 
+/**An (extension) method is used to create dialog or refresh target.
+ *
+ * @par Used with
+ *    nua_method()
+ *
+ * @par Parameter type
+ *    unsigned int (0, 1, 2) 
+ *
+ * @par Values
+ *   - 0 if dialog target is not refreshed
+ *   - 1 if dialog target is refreshed
+ *   - > 1 if dialog is to be created 
+ *
+ * @NEW_1_12_6.
+ *
+ * @sa nua_method(), #nua_i_method
+ */
+#define NUTAG_DIALOG(b) nutag_dialog, tag_uint_v((b))
+SOFIAPUBVAR tag_typedef_t nutag_dialog;
+
 /**Set request retry count.
  *
  * Retry count determines how many times stack will automatically retry
@@ -471,40 +494,48 @@
 
 /**Default session timer in seconds.
  *
- * Set default session timer in seconds when using session timer extension. 
- * The value given here is the proposed session expiration time in seconds.
- * Note that the session timer extension is ponly used 
+ * Set default value for session timer in seconds when the session timer
+ * extension is used. The tag value is the proposed session expiration time
+ * in seconds, the session is refreshed twice during the expiration time.
  *
  * @par Sending INVITE and UPDATE Requests 
  *
- * If NUTAG_SESSION_TIMER() is used with non-zero value, the value is
- * used in the @SessionExpires header included in the INVITE or UPDATE
- * requests. The intermediate proxies or the ultimate destination can lower
- * the interval in @SessionExpires header. If the value is too low, they can
+ * If NUTAG_SESSION_TIMER() is used with non-zero value, the value is used
+ * in the @SessionExpires header included in the INVITE or UPDATE requests. 
+ * The intermediate proxies or the ultimate destination can lower the
+ * interval in @SessionExpires header. If the value is too low, they can
  * reject the request with the status code <i>422 Session Timer Too
- * Small</i>. When Re-INVITE will be sent in given intervals. In that case,
- * @b nua retries the request automatically.
- * 
- * @par Returning Response to the INVITE and UPDATE Requests 
+ * Small</i>. In that case, @b nua increases the value of @SessionExpires
+ * header and retries the request automatically.
+ *
+ * @par Returning a Response to the INVITE and UPDATE Requests 
  *
  * The NUTAG_SESSION_TIMER() value is also used when sending the final
  * response to the INVITE or UPDATE requests. If the NUTAG_SESSION_TIMER()
- * value is 0 or the value in the @SessionExpires header of the requeast is
+ * value is 0 or the value in the @SessionExpires header of the request is
  * lower than the value in NUTAG_SESSION_TIMER(), the value from the
  * incoming @SessionExpires header is used. However, if the value in
  * @SessionExpires is lower than the minimal acceptable session expiration
  * interval specified with the tag NUTAG_MIN_SE() the request is
  * automatically rejected with <i>422 Session Timer Too Small</i>.
  *
+ * @par Refreshes
+ *
+ * After the initial INVITE request, the SIP session is refreshed at the
+ * intervals indicated by the @SessionExpires header returned in the 2XX
+ * response. The party indicated with the "refresher" parameter of the
+ * @SessionExpires header sends a re-INVITE requests (or an UPDATE
+ * request if NUTAG_UPDATE_REFRESH(1) parameter tag has been set).
+ * 
  * @par When to Use NUTAG_SESSION_TIMER()?
  *
  * The session time extension is enabled ("timer" feature tag is included in
  * @Supported header) but not activated by default (no @SessionExpires
  * header is included in the requests or responses by default). Using
- * non-zero value with NUTAG_SESSION_TIMER() activates it. When the
- * extension is activated, @nua refreshes the call state by sending periodic
- * re-INVITE or UPDATE requests unless the remote end indicated that it will
- * take care of refreshes.
+ * non-zero value with NUTAG_SESSION_TIMER() or NUTAG_SESSION_REFRESHER()
+ * activates it. When the extension is activated, @nua refreshes the call
+ * state by sending periodic re-INVITE or UPDATE requests unless the remote
+ * end indicated that it will take care of refreshes.
  *
  * The session timer extension is mainly useful for proxies or back-to-back
  * user agents that keep call state. The call state is "soft" meaning that
@@ -512,6 +543,10 @@
  * will be destroyed. An ordinary user-agent can also make use of session
  * timer if it cannot get any activity feedback from RTP or other media.
  *
+ * @note The session timer extension is used only if the feature
+ * tag "timer" is listed in the @Supported header, set by NUTAG_SUPPORTED(),
+ * SIPTAG_SUPPORTED(), or SIPTAG_SUPPORTED_STR() tags.
+ *
  * @par Used with
  *    nua_invite(), nua_update(), nua_respond() \n
  *    nua_set_params() or nua_set_hparams() \n
@@ -530,8 +565,8 @@
  * Corresponding tag taking reference parameter is NUTAG_SESSION_TIMER_REF()
  *
  * @sa NUTAG_SUPPORTED(), NUTAG_MIN_SE(), NUTAG_SESSION_REFRESHER(),
- * nua_invite(), #nua_r_invite, #nua_i_invite, nua_update(), #nua_r_update,
- * #nua_i_update, 
+ * nua_invite(), #nua_r_invite, #nua_i_invite, nua_respond(), 
+ * nua_update(), #nua_r_update, #nua_i_update, 
  * NUTAG_UPDATE_REFRESH(), @RFC4028, @SessionExpires, @MinSE
  */
 #define NUTAG_SESSION_TIMER(x)  nutag_session_timer, tag_uint_v((x))

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c	Fri Apr 13 10:33:30 2007
@@ -163,6 +163,7 @@
 
   nua_set_params(ctx->b.nua,
 		 NUTAG_EARLY_MEDIA(1),
+		 NUTAG_SESSION_TIMER(180),
 		 TAG_END());
   run_b_until(ctx, nua_r_set_params, until_final_response);
 
@@ -970,6 +971,8 @@
 
   TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_update);
   TEST(e->data->e_status, 200);
+  TEST_1(sip = sip_object(e->data->e_msg));
+  TEST_1(sip->sip_session_expires);
 
   TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
   TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
@@ -1197,14 +1200,14 @@
 
   nua_set_params(ctx->a.nua,
 		 NUTAG_EARLY_MEDIA(1),
-		 SIPTAG_SUPPORTED_STR("100rel, precondition"),
+		 SIPTAG_SUPPORTED_STR("100rel, precondition, timer"),
 		 TAG_END());
   run_a_until(ctx, nua_r_set_params, until_final_response);
 
   nua_set_params(ctx->b.nua,
 		 NUTAG_EARLY_MEDIA(1),
 		 NUTAG_ONLY183_100REL(1),
-		 SIPTAG_SUPPORTED_STR("100rel, precondition"),
+		 SIPTAG_SUPPORTED_STR("100rel, precondition, timer"),
 		 TAG_END());
   run_b_until(ctx, nua_r_set_params, until_final_response);
 

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_basic_call.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_basic_call.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_basic_call.c	Fri Apr 13 10:33:30 2007
@@ -205,9 +205,16 @@
   sip_replaces_t *repa, *repb;
   nua_handle_t *nh;
 
+  static int once = 0;
+  sip_time_t se, min_se;
+
   if (print_headings)
     printf("TEST NUA-3.1: Basic call\n");
 
+  /* Disable session timer from proxy */
+  test_proxy_get_session_timer(ctx->p, &se, &min_se); 
+  test_proxy_set_session_timer(ctx->p, 0, 0); 
+
   a_call->sdp = "m=audio 5008 RTP/AVP 8";
   b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
 
@@ -272,6 +279,10 @@
   TEST_1(sip->sip_contact);
   TEST_S(sip->sip_contact->m_display, "Bob");
   TEST_S(sip->sip_contact->m_url->url_user, "b+b");
+  if (!once) {
+    /* The session expiration is not used by default. */
+    TEST_1(sip->sip_session_expires == NULL);
+  }
   /* Test that B uses application-specific contact */
   if (ctx->proxy_tests)
     TEST_1(sip->sip_contact->m_url->url_user);
@@ -293,6 +304,10 @@
   TEST_1(sip->sip_contact);
   TEST_S(sip->sip_contact->m_display, "Alice");
   TEST_S(sip->sip_contact->m_url->url_user, "a+a");
+  if (!once++) {
+    /* The Session-Expires header is not used by default. */
+    TEST_1(sip->sip_session_expires == NULL);
+  }
   TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
   TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
   TEST_1(is_offer_recv(e->data->e_tags));
@@ -342,6 +357,8 @@
   nua_handle_destroy(a_call->nh), a_call->nh = NULL;
   nua_handle_destroy(b_call->nh), b_call->nh = NULL;
 
+  test_proxy_set_session_timer(ctx->p, se, min_se); 
+
   if (print_headings)
     printf("TEST NUA-3.1: PASSED\n");
 

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_call_reject.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_call_reject.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_call_reject.c	Fri Apr 13 10:33:30 2007
@@ -262,6 +262,7 @@
 /* ------------------------------------------------------------------------ */
 
 int reject_302(CONDITION_PARAMS), reject_305(CONDITION_PARAMS);
+int redirect_always(CONDITION_PARAMS);
 int reject_604(CONDITION_PARAMS);
 
 /*
@@ -336,6 +337,26 @@
   }
 }
 
+int redirect_always(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  if (event == nua_i_invite) {
+    char user[30];
+    sip_contact_t m[1];
+    *m = *ep->contact;
+    snprintf(user, sizeof user, "user-%u", ep->flags.n++);
+    m->m_url->url_user = user;
+    RESPOND(ep, call, nh, SIP_302_MOVED_TEMPORARILY,
+	    SIPTAG_CONTACT(m), TAG_END());
+    nua_handle_destroy(nh);
+    call->nh = NULL;
+    return 1;
+  }
+
+  return 0;
+}
 
 int reject_604(CONDITION_PARAMS)
 {
@@ -476,6 +497,25 @@
   if (print_headings)
     printf("TEST NUA-4.3: PASSED\n");
 
+  if (print_headings)
+    printf("TEST NUA-4.3.1: redirect until retry count is exceeded\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SIPTAG_SUBJECT_STR("redirect always"),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 TAG_END());
+  run_ab_until(ctx, -1, until_terminated, -1, redirect_always);
+
+  free_events_in_list(ctx, a->events);
+  nua_handle_destroy(a_call->nh), a_call->nh = NULL;
+  free_events_in_list(ctx, b->events);
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-4.3: PASSED\n");
+
   END();
 }
 
@@ -874,7 +914,7 @@
   }
 }
 
-int authenticate_once(CONDITION_PARAMS)
+int authenticate_bad(CONDITION_PARAMS)
 {
   if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
     return 0;
@@ -882,13 +922,8 @@
   save_event_in_list(ctx, event, ep, call);
 
   if (event == nua_r_invite && status == 401) {
-    if (ep->flags.bit0) {
-      nua_handle_destroy(nh); if (call) call->nh = NULL;
-      return 1;
-    }
-    ep->flags.bit0 = 1;
     AUTHENTICATE(ep, call, nh, NUTAG_AUTH("Digest:\"No hope\":jaska:secret"),
-		 SIPTAG_SUBJECT_STR("Got 401"),
+		 SIPTAG_SUBJECT_STR("Bad password"),
 		 TAG_END());
     return 0;
   }
@@ -925,7 +960,8 @@
 	 SOATAG_USER_SDP_STR(a_call->sdp),
 	 TAG_END());
 
-  run_ab_until(ctx, -1, authenticate_once, -1, reject_401_bad);
+
+  run_ab_until(ctx, -1, authenticate_bad, -1, reject_401_bad);
 
   /*
    Client transitions
@@ -941,7 +977,12 @@
   TEST_1(is_offer_sent(e->data->e_tags));
   TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
   TEST(sip_object(e->data->e_msg)->sip_status->st_status, 401);
-  TEST_1(!e->next);
+  /* nua_authenticate() fails and INVITE returns an internal error response */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
+  TEST(e->data->e_status, 904);
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
+  TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
+  TEST_1(!e->next); 
 
   free_events_in_list(ctx, a->events);
 

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c	Fri Apr 13 10:33:30 2007
@@ -871,13 +871,12 @@
   return len;
 }
 
-int test_early_bye(struct context *ctx)
+int test_bye_before_200(struct context *ctx)
 {
   BEGIN();
   struct endpoint *a = &ctx->a,  *b = &ctx->b;
   struct call *a_call = a->call, *b_call = b->call;
   struct event *e;
-  struct nat_filter *f = NULL;
 
   a_call->sdp = "m=audio 5008 RTP/AVP 8";
   b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
@@ -950,6 +949,41 @@
   if (print_headings)
     printf("TEST NUA-6.1: PASSED\n");
 
+  END();
+}
+
+
+int bye_when_completing(CONDITION_PARAMS)
+{
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  save_event_in_list(ctx, event, ep, call);
+
+  switch (callstate(tags)) {
+  case nua_callstate_completing:
+    ack_sent = 0;
+    BYE(ep, call, nh, TAG_END());
+    return 0;
+  case nua_callstate_terminated:
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+
+int test_bye_before_ack(struct context *ctx)
+{
+  BEGIN();
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+  struct nat_filter *f = NULL;
+
+  a_call->sdp = "m=audio 5008 RTP/AVP 8";
+  b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
 /* Early BYE 2
 
    A			B
@@ -1048,21 +1082,275 @@
   END();
 }
 
-int bye_when_completing(CONDITION_PARAMS)
+int reject_reinvite_401(CONDITION_PARAMS);
+
+int test_bye_after_receiving_401(struct context *ctx)
 {
-  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
-    return 0;
+  BEGIN();
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+
+  a_call->sdp = "m=audio 5008 RTP/AVP 8";
+  b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+/* BYE after receiving 401
+
+   A			B
+   |-------INVITE------>|
+   |<----100 Trying-----|
+   |			|
+   |<----180 Ringing----|
+   |<-------200---------|
+   |--------ACK-------->|
+   |			|
+   |<------INVITE-------|
+   |--------401-------->|
+   |<--------ACK--------|
+   |			|
+   |<--------BYE--------|
+   |------200 OK------->|
+   |			|
+*/
+  if (print_headings)
+    printf("TEST NUA-6.3: BYE after receiving 401\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SIPTAG_SUBJECT_STR("NUA-6.3"),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 NUTAG_AUTOANSWER(0),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, until_ready, -1, accept_call);
+
+  free_events_in_list(ctx, a->events);
+
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  free_events_in_list(ctx, b->events);
+
+  /* re-INVITE A. */
+  INVITE(b, b_call, b_call->nh, 
+	 SIPTAG_SUBJECT_STR("NUA-6.3 re-INVITE"),
+	 TAG_END());
+  run_ab_until(ctx, -1, reject_reinvite_401, -1, until_final_response);
+
+  TEST_1(nua_handle_has_active_call(a_call->nh));
+  TEST_1(nua_handle_has_active_call(b_call->nh));
+
+  free_events_in_list(ctx, a->events);
+  free_events_in_list(ctx, b->events);
+
+  BYE(b, b_call, b_call->nh, TAG_END());
+  
+  run_ab_until(ctx, -1, until_terminated, -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, b->events);
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-6.3: PASSED\n");
+
+  END();
+}
+
+int test_bye_after_sending_401(struct context *ctx)
+{
+  BEGIN();
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+
+  a_call->sdp = "m=audio 5008 RTP/AVP 8";
+  b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+/* BYE after sending 401
+
+   A			B
+   |-------INVITE------>|
+   |<----100 Trying-----|
+   |			|
+   |<----180 Ringing----|
+   |<-------200---------|
+   |--------ACK-------->|
+   |			|
+   |<------INVITE-------|
+   |--------401-------->|
+   |<--------ACK--------|
+   |			|
+   |--------BYE-------->|
+   |<------200 OK-------|
+   |			|
+*/
+  if (print_headings)
+    printf("TEST NUA-6.4: BYE after sending 401\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SIPTAG_SUBJECT_STR("NUA-6.4"),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 NUTAG_AUTOANSWER(0),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, until_ready, -1, accept_call);
+
+  free_events_in_list(ctx, a->events);
+
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  free_events_in_list(ctx, b->events);
+
+  /* re-INVITE A. */
+  INVITE(b, b_call, b_call->nh, 
+	 SIPTAG_SUBJECT_STR("NUA-6.4 re-INVITE"),
+	 TAG_END());
+  run_ab_until(ctx, -1, reject_reinvite_401, -1, until_final_response);
+
+  TEST_1(nua_handle_has_active_call(a_call->nh));
+  TEST_1(nua_handle_has_active_call(b_call->nh));
+
+  free_events_in_list(ctx, a->events);
+  free_events_in_list(ctx, b->events);
+
+  BYE(a, a_call, a_call->nh, TAG_END());
+  
+  run_ab_until(ctx, -1, until_terminated, -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, b->events);
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-6.4: PASSED\n");
+
+  END();
+}
+
+int test_bye_after_receiving_401_to_update(struct context *ctx)
+{
+  BEGIN();
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+
+  a_call->sdp = "m=audio 5008 RTP/AVP 8";
+  b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
+
+/* BYE after receiving 401
+
+   A			B
+   |-------INVITE------>|
+   |<----100 Trying-----|
+   |			|
+   |<----180 Ringing----|
+   |<-------200---------|
+   |--------ACK-------->|
+   |			|
+   |<------UPDATE-------|
+   |--------401-------->|
+   |			|
+   |<--------BYE--------|
+   |------200 OK------->|
+   |			|
+*/
+  if (print_headings)
+    printf("TEST NUA-6.5: BYE after receiving 401 to UPDATE\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  INVITE(a, a_call, a_call->nh,
+	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
+	 SIPTAG_SUBJECT_STR("NUA-6.5"),
+	 SOATAG_USER_SDP_STR(a_call->sdp),
+	 NUTAG_AUTOANSWER(0),
+	 NUTAG_APPL_METHOD("UPDATE"),
+	 TAG_END());
+
+  run_ab_until(ctx, -1, until_ready, -1, accept_call);
+
+  free_events_in_list(ctx, a->events);
+
+  TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
+  free_events_in_list(ctx, b->events);
+
+  /* UPDATE A. */
+  UPDATE(b, b_call, b_call->nh, 
+	 SIPTAG_SUBJECT_STR("NUA-6.4 UPDATE"),
+	 TAG_END());
+  BYE(b, b_call, b_call->nh, TAG_END()); /* Queued until nua_authenticate */
+  run_ab_until(ctx, -1, reject_reinvite_401, -1, until_final_response);
+
+  TEST_1(nua_handle_has_active_call(a_call->nh));
+  TEST_1(nua_handle_has_active_call(b_call->nh));
+
+  free_events_in_list(ctx, a->events);
+  free_events_in_list(ctx, b->events);
+
+  AUTHENTICATE(b, b_call, b_call->nh, TAG_END());
+  
+  run_ab_until(ctx, -1, until_terminated, -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, b->events);
+  nua_handle_destroy(b_call->nh), b_call->nh = NULL;
+
+  if (print_headings)
+    printf("TEST NUA-6.3: PASSED\n");
+
+  END();
+}
+
+int reject_reinvite_401(CONDITION_PARAMS)
+{
+  void *request = nua_current_request(nua);
 
   save_event_in_list(ctx, event, ep, call);
 
-  switch (callstate(tags)) {
-  case nua_callstate_completing:
-    ack_sent = 0;
-    BYE(ep, call, nh, TAG_END());
+  if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
+    return 0;
+
+  if (status < 200 && (event == nua_i_invite || event == nua_i_update)) {
+    RESPOND(ep, call, nh, SIP_401_UNAUTHORIZED,
+	    NUTAG_WITH(request),
+	    SIPTAG_WWW_AUTHENTICATE_STR("Digest realm=\"test_nua\", "
+					"nonce=\"nsdhfuds\", algorithm=MD5, "
+					"qop=\"auth\""),
+	    TAG_END());
     return 0;
+  }
+
+  if (event == nua_i_state) switch (callstate(tags)) {
+  case nua_callstate_ready:
+    return 1;
   case nua_callstate_terminated:
+    if (call)
+      nua_handle_destroy(call->nh), call->nh = NULL;
     return 1;
   default:
     return 0;
   }
+
+  return 0;
+}
+
+
+int test_early_bye(struct context *ctx)
+{
+  return 
+    test_bye_before_200(ctx) ||
+    test_bye_before_ack(ctx) ||
+    test_bye_after_receiving_401(ctx) ||
+    test_bye_after_sending_401(ctx) ||
+    test_bye_after_receiving_401_to_update(ctx) ||
+    0;
 }

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.c	Fri Apr 13 10:33:30 2007
@@ -248,8 +248,15 @@
   }
 #if HAVE_ALARM
   else if (o_alarm) {
-    alarm(o_expensive ? 60 : 120);
     signal(SIGALRM, sig_alarm);
+    if (o_expensive) {
+      printf("%s: extending timeout to %u because expensive tests\n",
+	     name, 240);
+      alarm(240);
+    }
+    else {
+      alarm(120);
+    }
   }
 #endif
 
@@ -316,8 +323,8 @@
       retval |= test_session_timer(ctx); SINGLE_FAILURE_CHECK();
       retval |= test_refer(ctx); SINGLE_FAILURE_CHECK();
       retval |= test_100rel(ctx); SINGLE_FAILURE_CHECK();
-      retval |= test_events(ctx); SINGLE_FAILURE_CHECK();
       retval |= test_simple(ctx); SINGLE_FAILURE_CHECK();
+      retval |= test_events(ctx); SINGLE_FAILURE_CHECK();
       retval |= test_extension(ctx); SINGLE_FAILURE_CHECK();
       if (!o_loop)
 	break;

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_offer_answer.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_offer_answer.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_offer_answer.c	Fri Apr 13 10:33:30 2007
@@ -86,7 +86,7 @@
   sip_t *sip;
 
   if (print_headings)
-    printf("TEST NUA-6.3: No SDP answer from callee\n");
+    printf("TEST NUA-6.5: No SDP answer from callee\n");
 
   a_call->sdp = "m=audio 5008 RTP/AVP 8";
   b_call->sdp = NULL;
@@ -184,7 +184,7 @@
   nua_handle_destroy(b_call->nh), b_call->nh = NULL;
 
   if (print_headings)
-    printf("TEST NUA-6.3: PASSED\n");
+    printf("TEST NUA-6.5: PASSED\n");
 
   END();
 }
@@ -229,7 +229,7 @@
   sip_t const *sip;
 
   if (print_headings)
-    printf("TEST NUA-6.4: No SDP offer from caller\n");
+    printf("TEST NUA-6.6: No SDP offer from caller\n");
 
   a_call->sdp = "v=0\r\n"
     "o=- 1 1 IN IP4 127.0.0.1\r\n"
@@ -330,7 +330,7 @@
   nua_handle_destroy(b_call->nh), b_call->nh = NULL;
 
   if (print_headings)
-    printf("TEST NUA-6.4: PASSED\n");
+    printf("TEST NUA-6.6: PASSED\n");
 
   END();
 }

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c	Fri Apr 13 10:33:30 2007
@@ -375,6 +375,27 @@
   }
 }
 
+void test_proxy_set_session_timer(struct proxy *p,
+				  sip_time_t session_expires, 
+				  sip_time_t min_se)
+{
+  if (p) {
+    p->prefs.session_expires = session_expires;
+    p->prefs.min_se = min_se;
+  }
+}
+
+void test_proxy_get_session_timer(struct proxy *p,
+				  sip_time_t *return_session_expires,
+				  sip_time_t *return_min_se)
+{
+  if (p) {
+    if (return_session_expires)
+      *return_session_expires = p->prefs.session_expires;
+    if (return_min_se) *return_min_se = p->prefs.min_se;
+  }
+}
+
 /* ---------------------------------------------------------------------- */
 
 static sip_contact_t *create_transport_contacts(struct proxy *p)
@@ -427,6 +448,7 @@
 
   sip_session_expires_t *x = NULL, x0[1];
   sip_min_se_t *min_se = NULL, min_se0[1];
+  char const *require = NULL;
 
   mf = sip->sip_max_forwards;
 
@@ -447,24 +469,33 @@
   }
 
   if (method == sip_method_invite) {
-    if (!sip->sip_min_se || 
-	sip->sip_min_se->min_delta < proxy->prefs.min_se) {
-      min_se = sip_min_se_init(min_se0);
-      min_se->min_delta = proxy->prefs.min_se;
-    }
-
-    if (!sip->sip_session_expires) {
-      x = sip_session_expires_init(x0);
-      x->x_delta = proxy->prefs.session_expires;
-    }
-    else if (sip->sip_session_expires->x_delta < proxy->prefs.min_se
-	     && sip_has_supported(sip->sip_supported, "timer")) {
-      if (min_se == NULL)
-	min_se = sip->sip_min_se; assert(min_se);
-      nta_incoming_treply(irq, SIP_422_SESSION_TIMER_TOO_SMALL,
-			  SIPTAG_MIN_SE(min_se),
-			  TAG_END());
-      return 422;
+    if (proxy->prefs.min_se) {
+      if (!sip->sip_min_se || 
+	  sip->sip_min_se->min_delta < proxy->prefs.min_se) {
+	min_se = sip_min_se_init(min_se0);
+	min_se->min_delta = proxy->prefs.min_se;
+      }
+
+      if (sip->sip_session_expires
+	  && sip->sip_session_expires->x_delta < proxy->prefs.min_se
+	  && sip_has_supported(sip->sip_supported, "timer")) {
+	if (min_se == NULL)
+	  min_se = sip->sip_min_se; assert(min_se);
+	nta_incoming_treply(irq, SIP_422_SESSION_TIMER_TOO_SMALL,
+			    SIPTAG_MIN_SE(min_se),
+			    TAG_END());
+	return 422;
+      }
+    }
+
+    if (proxy->prefs.session_expires) {
+      if (!sip->sip_session_expires ||
+	  sip->sip_session_expires->x_delta > proxy->prefs.session_expires) {
+	x = sip_session_expires_init(x0);
+	x->x_delta = proxy->prefs.session_expires;
+	if (!sip_has_supported(sip->sip_supported, "timer"))
+	  require = "timer";
+      }
     }
   }
 
@@ -528,6 +559,7 @@
 				   SIPTAG_REQUEST(rq),
 				   SIPTAG_SESSION_EXPIRES(x),
 				   SIPTAG_MIN_SE(min_se),
+				   SIPTAG_REQUIRE_STR(require),
 				   TAG_END());
   if (t->client == NULL) {
     proxy_transaction_destroy(t);

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.h
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.h	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.h	Fri Apr 13 10:33:30 2007
@@ -48,6 +48,14 @@
 			       sip_time_t *return_expires, 
 			       sip_time_t *return_max_expires);
 
+void test_proxy_set_session_timer(struct proxy *p,
+				  sip_time_t session_expires, 
+				  sip_time_t min_se);
+
+void test_proxy_get_session_timer(struct proxy *p,
+				  sip_time_t *return_session_expires,
+				  sip_time_t *return_min_se);
+
 SOFIA_END_DECLS
 
 #endif

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_register.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_register.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_register.c	Fri Apr 13 10:33:30 2007
@@ -685,6 +685,10 @@
     run_a_until(ctx, -1, save_until_final_response);
     TEST_1(e = a->events->head);
     TEST_E(e->data->e_event, nua_r_unregister);
+    if (e->data->e_status == 100) {
+      TEST_1(e = e->next);
+      TEST_E(e->data->e_event, nua_r_unregister);
+    }
     TEST(e->data->e_status, 200);
     TEST_1(sip = sip_object(e->data->e_msg));
     TEST_1(!sip->sip_contact);

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_session_timer.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_session_timer.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_session_timer.c	Fri Apr 13 10:33:30 2007
@@ -22,7 +22,7 @@
  *
  */
 
-/**@CFILE test_nua_re_invite.c
+/**@CFILE test_session_timer.c
  * @brief NUA-8 tests: Session timer, UPDATE
  *
  * @author Pekka Pessi <Pekka.Pessi at nokia.com>
@@ -40,11 +40,13 @@
 #elif HAVE_FUNCTION
 #define __func__ __FUNCTION__
 #else
-#define __func__ "test_call_hold"
+#define __func__ "test_session_timer"
 #endif
 
 /* ======================================================================== */
 
+static size_t remove_update(void *a, void *message, size_t len);
+
 int test_session_timer(struct context *ctx)
 {
   BEGIN();
@@ -69,22 +71,6 @@
    |--INVITE->| 	|
    |<--422----|		|
    |---ACK--->|		|
-   |			|
-   |-------INVITE------>|
-   |<-------422---------|
-   |--------ACK-------->|
-   |			|
-   |-------INVITE------>|
-   |<----100 Trying-----|
-   |			|
-   |<----180 Ringing----|
-   |			|
-   |<------200 OK-------|
-   |--------ACK-------->|
-   |			|
-   |<-------BYE---------|
-   |-------200 OK-------|
-   |			|
 
 */
 
@@ -94,8 +80,15 @@
   a_call->sdp = "m=audio 5008 RTP/AVP 8";
   b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
 
+  /* We negotiate session timer of 6 second */
+  /* Disable session timer from proxy */
+  test_proxy_set_session_timer(ctx->p, 0, 0); 
+
   nua_set_params(ctx->b.nua,
 		 NUTAG_SESSION_REFRESHER(nua_any_refresher),
+		 NUTAG_MIN_SE(1),
+		 NUTAG_SESSION_TIMER(6),
+		 NTATAG_SIP_T1X64(8000),
 		 TAG_END());
 
   run_b_until(ctx, nua_r_set_params, until_final_response);
@@ -159,23 +152,132 @@
   if (print_headings)
     printf("TEST NUA-8.1.1: PASSED\n");
 
+  if (ctx->expensive) {
+    nua_set_hparams(a_call->nh,
+		    NUTAG_SUPPORTED("timer"),
+		    NUTAG_MIN_SE(1),
+		    NUTAG_SESSION_TIMER(5),
+		    TAG_END());
+    run_a_until(ctx, nua_r_set_params, until_final_response);
+
+    if (print_headings)
+      printf("TEST NUA-8.1.2: Wait for refresh using INVITE\n");
+
+    run_ab_until(ctx, -1, until_ready, -1, until_ready);
+
+    free_events_in_list(ctx, a->events);
+    free_events_in_list(ctx, b->events);
+
+    if (print_headings)
+      printf("TEST NUA-8.1.2: PASSED\n");
+
+    nua_set_hparams(b_call->nh,
+		    NUTAG_UPDATE_REFRESH(1),
+		    TAG_END());
+    run_b_until(ctx, nua_r_set_params, until_final_response);
+
+    if (print_headings)
+      printf("TEST NUA-8.1.3: Wait for refresh using UPDATE\n");
+
+    run_ab_until(ctx, -1, until_ready, -1, until_ready);
+
+    TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_update);
+
+    free_events_in_list(ctx, a->events);
+    free_events_in_list(ctx, b->events);
+
+    if (print_headings)
+      printf("TEST NUA-8.1.3: PASSED\n");
+
+    if (ctx->nat) {
+      struct nat_filter *f;
+
+      if (print_headings)
+	printf("TEST NUA-8.1.4: filter UPDATE, wait until session expires\n");
+
+      f = test_nat_add_filter(ctx->nat, remove_update, NULL, nat_inbound);
+      TEST_1(f);
+
+      run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
+      
+      TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_bye);
+
+      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;
+
+      test_nat_remove_filter(ctx->nat, f);
+
+      if (print_headings)
+	printf("TEST NUA-8.1.4: PASSED\n");
+    }
+  }
+
+  if (b_call->nh) {
+    if (print_headings)
+      printf("TEST NUA-8.1.9: Terminate first session timer call\n");
+
+    BYE(b, b_call, b_call->nh, TAG_END());
+    run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
+    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-8.1.9: PASSED\n");
+  }
+
+  /*
+   |			|
+   |-------INVITE------>|
+   |<-------422---------|
+   |--------ACK-------->|
+   |			|
+   |-------INVITE------>|
+   |<----100 Trying-----|
+   |			|
+   |<----180 Ringing----|
+   |			|
+   |<------200 OK-------|
+   |--------ACK-------->|
+   |			|
+   |<-------BYE---------|
+   |-------200 OK-------|
+   |			|
+  */
+
   if (print_headings)
-    printf("TEST NUA-8.1.2: Session timers negotiation\n");
+    printf("TEST NUA-8.2: Session timers negotiation\n");
+
+  test_proxy_set_session_timer(ctx->p, 180, 90);
+
+  nua_set_params(a->nua,
+		 NUTAG_SUPPORTED("timer"),
+		 TAG_END());
+
+  run_a_until(ctx, nua_r_set_params, until_final_response);
 
-  nua_set_hparams(b_call->nh,
-		  NUTAG_AUTOANSWER(0),
-		  NUTAG_MIN_SE(120),
-		  TAG_END());
+  nua_set_params(b->nua,
+		 NUTAG_AUTOANSWER(0),
+		 NUTAG_MIN_SE(120),
+		 NTATAG_SIP_T1X64(2000),
+		 TAG_END());
 
   run_b_until(ctx, nua_r_set_params, until_final_response);
 
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to),
+				 TAG_END()));
 
   INVITE(a, a_call, a_call->nh,
 	 TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
 	 SOATAG_USER_SDP_STR(a_call->sdp),
 	 SIPTAG_SUPPORTED_STR("100rel, timer"),
-	 NUTAG_SESSION_TIMER(15),
-	 NUTAG_MIN_SE(5),
+	 NUTAG_SESSION_TIMER(4),
+	 NUTAG_MIN_SE(3),
 	 TAG_END());
 
   run_ab_until(ctx, -1, until_ready, -1, accept_call);
@@ -252,17 +354,17 @@
   free_events_in_list(ctx, b->events);
 
   if (print_headings)
-    printf("TEST NUA-8.1: PASSED\n");
+    printf("TEST NUA-8.2: PASSED\n");
 
   if (print_headings)
-    printf("TEST NUA-8.2: use UPDATE\n");
+    printf("TEST NUA-8.3: UPDATE with session timer headers\n");
 
   UPDATE(b, b_call, b_call->nh, TAG_END());
   run_ab_until(ctx, -1, until_ready, -1, until_ready);
 
   /* Events from B (who sent UPDATE) */
   TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_state);
-  TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
+  TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
   TEST_1(is_offer_sent(e->data->e_tags));
   if (!e->next)
     run_b_until(ctx, -1, until_ready);
@@ -313,7 +415,20 @@
   nua_handle_destroy(b_call->nh), b_call->nh = NULL;
 
   if (print_headings)
-    printf("TEST NUA-8.2: PASSED\n");
+    printf("TEST NUA-8.3: PASSED\n");
 
   END();
 }
+
+static
+size_t remove_update(void *a, void *message, size_t len)
+{
+  (void)a;
+
+  if (strncmp("UPDATE ", message, 7) == 0) {
+    return 0;
+  }
+
+  return len;
+}
+

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_simple.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_simple.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_simple.c	Fri Apr 13 10:33:30 2007
@@ -972,6 +972,7 @@
   return ep->flags.bit0 && ep->flags.bit1;
 }
 
+
 /* ---------------------------------------------------------------------- */
 /* Unsolicited NOTIFY */
 
@@ -1122,7 +1123,7 @@
   nua_handle_destroy(b_call->nh), b_call->nh = NULL;
 
   if (print_headings)
-    printf("TEST NUA-11.6: PASSED\n");
+    printf("TEST NUA-11.7: PASSED\n");
 
   END();
 }
@@ -1144,6 +1145,155 @@
 }
 
 /* ======================================================================== */
+
+int save_until_subscription_terminated(CONDITION_PARAMS);
+int accept_subscription_until_terminated(CONDITION_PARAMS);
+
+/* Timeout subscription */
+int test_subscription_timeout(struct context *ctx)
+{
+  BEGIN();
+
+  struct endpoint *a = &ctx->a,  *b = &ctx->b;
+  struct call *a_call = a->call, *b_call = b->call;
+  struct event *e;
+  sip_t const *sip;
+  tagi_t const *n_tags, *r_tags;
+
+  if (print_headings)
+    printf("TEST NUA-11.8: subscribe and wait until subscription times out\n");
+
+  TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
+
+  METHOD(a, a_call, a_call->nh,
+	 NUTAG_METHOD("SUBSCRIBE"),
+	 NUTAG_URL(b->contact->m_url),
+	 SIPTAG_EVENT_STR("presence"),
+	 SIPTAG_ACCEPT_STR("application/xpidf, application/pidf+xml"),
+	 SIPTAG_EXPIRES_STR("2"),
+	 NUTAG_APPL_METHOD("NOTIFY"),
+	 NUTAG_DIALOG(2),
+	 TAG_END());
+
+  run_ab_until(ctx,
+	       -1, save_until_subscription_terminated,
+	       -1, accept_subscription_until_terminated);
+
+  /* Client events:
+     nua_method(), nua_i_notify/nua_r_method, 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;
+  }
+  else {
+    TEST_E(e->data->e_event, nua_r_method);
+    TEST(e->data->e_status, 202);
+    r_tags = e->data->e_tags;
+    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;
+  }
+  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 = e->next); TEST_E(e->data->e_event, nua_i_notify);
+  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(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);
+  TEST_1(!e->next);
+
+  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_pending);
+
+  /* Notifier events: 2nd nua_r_notify */
+  TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
+  TEST_1(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);
+
+  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.8: PASSED\n");
+
+  END();
+}
+
+int save_until_subscription_terminated(CONDITION_PARAMS)
+{
+  void *with = nua_current_request(nua);
+
+  save_event_in_list(ctx, event, ep, call);
+
+  if (event == nua_i_notify) {
+    if (status < 200)
+      RESPOND(ep, call, nh, SIP_200_OK, NUTAG_WITH(with), TAG_END());
+
+    tags = tl_find(tags, nutag_substate);
+    return tags && tags->t_value == nua_substate_terminated;
+  }
+
+  return 0;
+}
+
+int accept_subscription_until_terminated(CONDITION_PARAMS)
+{
+  void *with = nua_current_request(nua);
+
+  save_event_in_list(ctx, event, ep, call);
+
+  if (event == nua_i_subscribe && status < 200) {
+    RESPOND(ep, call, nh, SIP_202_ACCEPTED,
+	    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());
+  }
+  else if (event == nua_r_notify) {
+    tags = tl_find(tags, nutag_substate);
+    return tags && tags->t_value == nua_substate_terminated;
+  }
+
+  return 0;
+}
+
+
+/* ======================================================================== */
 /* Test simple methods: MESSAGE, PUBLISH, SUBSCRIBE/NOTIFY */
 
 int test_simple(struct context *ctx)
@@ -1154,5 +1304,6 @@
     || test_subscribe_notify(ctx)
     || test_subscribe_notify_graceful(ctx)
     || test_newsub_notify(ctx)
+    || test_subscription_timeout(ctx)
     ;
 }

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/sdp/run_test_sdp
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/sdp/run_test_sdp	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/sdp/run_test_sdp	Fri Apr 13 10:33:30 2007
@@ -6,7 +6,8 @@
 #
 
 test_sdp="${1:-./test_sdp}"
-tests="${2:-${0%/*}/tests}"
+sdp_path=`dirname $0`
+tests="${2:-${sdp_path}/tests}"
 
 if test -r $tests/message-1.sdp ; then
 
@@ -20,4 +21,3 @@
     echo "sdp run-tests: no tests found in $tests, skipping."
     exit 77
 fi
-

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/sip/sip_feature.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/sip/sip_feature.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/sip/sip_feature.c	Fri Apr 13 10:33:30 2007
@@ -336,7 +336,7 @@
   return msg_list_e(b, bsiz, h, f);
 }
 
-/** Check if required feature is supported.
+/** Check if required feature is not supported.
  *
  * @retval NULL if all the required features are supported
  * @retval pointer to a @Unsupported header or
@@ -351,7 +351,7 @@
 }
 
 
-/** Check if required feature is supported.
+/** Check if required feature is not supported.
  *
  * @retval NULL if all the required features are supported
  * @retval pointer to a @Unsupported header or
@@ -370,7 +370,7 @@
 }
 
 
-/** Ensure that required features are supported.
+/** Check if required features are not supported.
  *
  * The supported features can be listed in @Supported, @Require or 
  * @ProxyRequire headers (in @a supported, @a by_require, or @a

Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c
==============================================================================
--- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c	(original)
+++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c	Fri Apr 13 10:33:30 2007
@@ -354,7 +354,7 @@
     su_home_t home[1] = { SU_HOME_INIT(home) };
     char const *display;
     url_t url[1];
-    char const * const *params;
+    msg_param_t const *params;
     char const *comment;
     char const na[] = "Raaka Arska <tel:+358501970>;param=1;humppa (test) ";
     char const na2[] = "tel:+358501970;param=1;humppa (test) ";
@@ -744,8 +744,6 @@
   }
 
   END();
-
-  return 0;
 }
 
 msg_t *read_message(int flags, char const buffer[])



More information about the Freeswitch-branches mailing list