Index: /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c
===================================================================
--- /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c	(revision 1560)
+++ /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c	(revision 1561)
@@ -118,4 +118,5 @@
     puts  ("");
     puts  ("SIP Account options:");
+    puts  ("  --use-ims           Enable 3GPP/IMS related settings on this account");
     puts  ("  --registrar=url     Set the URL of registrar server");
     puts  ("  --id=url            Set the URL of local ID (used in From header)");
@@ -129,5 +130,4 @@
     puts  ("  --publish           Send presence PUBLISH for this account");
     puts  ("  --use-100rel        Require reliable provisional response (100rel)");
-    puts  ("  --service-route     Enable Service-Route processing");
     puts  ("  --next-cred         Add another credentials");
     puts  ("");
@@ -373,5 +373,5 @@
 	   OPT_LOCAL_PORT, OPT_IP_ADDR, OPT_PROXY, OPT_OUTBOUND_PROXY, 
 	   OPT_REGISTRAR, OPT_REG_TIMEOUT, OPT_PUBLISH, OPT_ID, OPT_CONTACT,
-	   OPT_100REL, OPT_SERVICE_ROUTE, OPT_REALM, OPT_USERNAME, OPT_PASSWORD,
+	   OPT_100REL, OPT_USE_IMS, OPT_REALM, OPT_USERNAME, OPT_PASSWORD,
 	   OPT_NAMESERVER, OPT_STUN_DOMAIN, OPT_STUN_SRV,
 	   OPT_ADD_BUDDY, OPT_OFFER_X_MS_MSG, OPT_NO_PRESENCE,
@@ -410,5 +410,5 @@
 	{ "publish",    0, 0, OPT_PUBLISH},
 	{ "use-100rel", 0, 0, OPT_100REL},
-	{ "service-route", 0, 0, OPT_SERVICE_ROUTE},
+	{ "use-ims",    0, 0, OPT_USE_IMS},
 	{ "id",		1, 0, OPT_ID},
 	{ "contact",	1, 0, OPT_CONTACT},
@@ -637,6 +637,6 @@
 	    break;
 
-	case OPT_SERVICE_ROUTE: /* Service-Route processing */
-	    cur_acc->enable_service_route = PJ_TRUE;
+	case OPT_USE_IMS: /* Activate IMS settings */
+	    cur_acc->auth_pref.initial_auth = PJ_TRUE;
 	    break;
 
@@ -668,5 +668,5 @@
 	case OPT_USERNAME:   /* Default authentication user */
 	    cur_acc->cred_info[cur_acc->cred_count].username = pj_str(pj_optarg);
-	    cur_acc->cred_info[cur_acc->cred_count].scheme = pj_str("digest");
+	    cur_acc->cred_info[cur_acc->cred_count].scheme = pj_str("Digest");
 	    break;
 
@@ -993,7 +993,32 @@
 
     for (i=0; i<cfg->acc_cnt; ++i) {
-	if (cfg->acc_cfg[i].cred_info[cfg->acc_cfg[i].cred_count].username.slen)
+	pjsua_acc_config *acfg = &cfg->acc_cfg[i];
+
+	if (acfg->cred_info[acfg->cred_count].username.slen)
 	{
-	    cfg->acc_cfg[i].cred_count++;
+	    acfg->cred_count++;
+	}
+
+	/* When IMS mode is enabled for the account, verify that settings
+	 * are okay.
+	 */
+	/* For now we check if IMS mode is activated by looking if
+	 * initial_auth is set.
+	 */
+	if (acfg->auth_pref.initial_auth && acfg->cred_count) {
+	    /* Realm must point to the real domain */
+	    if (*acfg->cred_info[0].realm.ptr=='*') {
+		PJ_LOG(1,(THIS_FILE, 
+			  "Error: cannot use '*' as realm with IMS"));
+		return PJ_EINVAL;
+	    }
+
+	    /* Username for authentication must be in a@b format */
+	    if (strchr(acfg->cred_info[0].username.ptr, '@')==0) {
+		PJ_LOG(1,(THIS_FILE, 
+			  "Error: Username for authentication must "
+			  "be in user@domain format with IMS"));
+		return PJ_EINVAL;
+	    }
 	}
     }
@@ -2686,5 +2711,5 @@
 		acc_cfg.reg_uri = pj_str(registrar);
 		acc_cfg.cred_count = 1;
-		acc_cfg.cred_info[0].scheme = pj_str("digest");
+		acc_cfg.cred_info[0].scheme = pj_str("Digest");
 		acc_cfg.cred_info[0].realm = pj_str(realm);
 		acc_cfg.cred_info[0].username = pj_str(uname);
Index: /pjproject/trunk/pjsip/include/pjsip-ua/sip_regc.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip-ua/sip_regc.h	(revision 1560)
+++ /pjproject/trunk/pjsip/include/pjsip-ua/sip_regc.h	(revision 1561)
@@ -190,4 +190,15 @@
 
 /**
+ * Set authentication preference.
+ *
+ * @param regc	    The registration structure.
+ * @param pref	    Authentication preference.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_regc_set_prefs( pjsip_regc *regc,
+					   const pjsip_auth_clt_pref *pref);
+
+/**
  * Set route set to be used for outgoing requests.
  *
Index: /pjproject/trunk/pjsip/include/pjsip/sip_auth.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/sip_auth.h	(revision 1560)
+++ /pjproject/trunk/pjsip/include/pjsip/sip_auth.h	(revision 1561)
@@ -184,4 +184,26 @@
 
 /**
+ * This structure describes client authentication session preference.
+ * The preference can be set by calling #pjsip_auth_clt_set_prefs().
+ */
+typedef struct pjsip_auth_clt_pref
+{
+    /**
+     * If this flag is set, the authentication client framework will
+     * send an empty Authorization header in each initial request.
+     * Default is no.
+     */
+    pj_bool_t	initial_auth;
+
+    /**
+     * Specify the algorithm to use when empty Authorization header 
+     * is to be sent for each initial request (see above)
+     */
+    pj_str_t	algorithm;
+
+} pjsip_auth_clt_pref;
+
+
+/**
  * This structure describes client authentication sessions. It keeps
  * all the information needed to authorize the client against all downstream 
@@ -192,4 +214,5 @@
     pj_pool_t		*pool;		/**< Pool to use.		    */
     pjsip_endpoint	*endpt;		/**< Endpoint where this belongs.   */
+    pjsip_auth_clt_pref  pref;		/**< Preference/options.	    */
     unsigned		 cred_cnt;	/**< Number of credentials.	    */
     pjsip_cred_info	*cred_info;	/**< Array of credential information*/
@@ -288,4 +311,27 @@
 						     const pjsip_cred_info *c);
 
+
+/**
+ * Set the preference for the client authentication session.
+ *
+ * @param sess		The client authentication session.
+ * @param p		Preference.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_auth_clt_set_prefs(pjsip_auth_clt_sess *sess,
+					      const pjsip_auth_clt_pref *p);
+
+
+/**
+ * Get the preference for the client authentication session.
+ *
+ * @param sess		The client authentication session.
+ * @param p		Pointer to receive the preference.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_auth_clt_get_prefs(pjsip_auth_clt_sess *sess,
+					      pjsip_auth_clt_pref *p);
 
 /**
Index: /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 1560)
+++ /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 1561)
@@ -1841,6 +1841,13 @@
      * If this flag is set, the presence information of this account will
      * be PUBLISH-ed to the server where the account belongs.
+     *
+     * Default: PJ_FALSE
      */
     pj_bool_t	    publish_enabled;
+
+    /**
+     * Authentication preference.
+     */
+    pjsip_auth_clt_pref auth_pref;
 
     /**
@@ -1890,9 +1897,4 @@
      */
     pj_str_t	    proxy[PJSUA_ACC_MAX_PROXIES];
-
-    /**
-     * Enable Service-Route processing for this account.
-     */
-    pj_bool_t	    enable_service_route;
 
     /** 
Index: /pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c	(revision 1560)
+++ /pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c	(revision 1561)
@@ -1564,7 +1564,17 @@
     /* Include SDP when it's available for 2xx and 18x (but not 180) response.
      * Subsequent response will include this SDP.
+     *
+     * Note note:
+     *	- When offer/answer has been completed in reliable 183, we MUST NOT
+     *	  send SDP in 2xx response. So if we don't have SDP to send, clear
+     *	  the SDP in the message body ONLY if 100rel is active in this 
+     *    session.
      */
     if (sdp) {
 	tdata->msg->body = create_sdp_body(tdata->pool, sdp);
+    } else {
+	if (inv->options & PJSIP_INV_REQUIRE_100REL) {
+	    tdata->msg->body = NULL;
+	}
     }
 
@@ -2227,6 +2237,30 @@
     pj_status_t status = -1;
 
+    /* Handle 401/407 challenge. */
+    if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
+	(tsx->status_code == 401 || tsx->status_code == 407)) {
+
+	pjsip_tx_data *tdata;
+	
+	status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess, 
+					    e->body.tsx_state.src.rdata,
+					    tsx->last_tx,
+					    &tdata);
+	
+	if (status != PJ_SUCCESS) {
+	    
+	    /* Does not have proper credentials. 
+	     * End the session anyway.
+	     */
+	    inv_set_cause(inv, PJSIP_SC_OK, NULL);
+	    inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
+	    
+	} else {
+	    /* Re-send BYE. */
+	    status = pjsip_inv_send_msg(inv, tdata);
+	}
+
     /* Process 2xx response */
-    if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
+    } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
 	tsx->status_code/100 == 2 &&
 	e->body.tsx_state.src.rdata->msg_info.msg->body)
Index: /pjproject/trunk/pjsip/src/pjsip-ua/sip_reg.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip-ua/sip_reg.c	(revision 1560)
+++ /pjproject/trunk/pjsip/src/pjsip-ua/sip_reg.c	(revision 1561)
@@ -308,4 +308,11 @@
 }
 
+PJ_DEF(pj_status_t) pjsip_regc_set_prefs( pjsip_regc *regc,
+					  const pjsip_auth_clt_pref *pref)
+{
+    PJ_ASSERT_RETURN(regc && pref, PJ_EINVAL);
+    return pjsip_auth_clt_set_prefs(&regc->auth_sess, pref);
+}
+
 PJ_DEF(pj_status_t) pjsip_regc_set_route_set( pjsip_regc *regc,
 					      const pjsip_route_hdr *route_set)
Index: /pjproject/trunk/pjsip/src/pjsip/sip_auth_client.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_auth_client.c	(revision 1560)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_auth_client.c	(revision 1561)
@@ -533,4 +533,34 @@
 
 
+/*
+ * Set the preference for the client authentication session.
+ */
+PJ_DEF(pj_status_t) pjsip_auth_clt_set_prefs(pjsip_auth_clt_sess *sess,
+					     const pjsip_auth_clt_pref *p)
+{
+    PJ_ASSERT_RETURN(sess && p, PJ_EINVAL);
+
+    pj_memcpy(&sess->pref, p, sizeof(*p));
+    pj_strdup(sess->pool, &sess->pref.algorithm, &p->algorithm);
+    //if (sess->pref.algorithm.slen == 0)
+    //	sess->pref.algorithm = pj_str("md5");
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Get the preference for the client authentication session.
+ */
+PJ_DEF(pj_status_t) pjsip_auth_clt_get_prefs(pjsip_auth_clt_sess *sess,
+					     pjsip_auth_clt_pref *p)
+{
+    PJ_ASSERT_RETURN(sess && p, PJ_EINVAL);
+
+    pj_memcpy(p, &sess->pref, sizeof(pjsip_auth_clt_pref));
+    return PJ_SUCCESS;
+}
+
+
 /* 
  * Create Authorization/Proxy-Authorization response header based on the challege
@@ -699,4 +729,20 @@
 
 
+/* Find credential in list of (Proxy-)Authorization headers */
+static pjsip_authorization_hdr* get_header_for_realm(const pjsip_hdr *hdr_list,
+						     const pj_str_t *realm)
+{
+    pjsip_authorization_hdr *h;
+
+    h = (pjsip_authorization_hdr*)hdr_list->next;
+    while (h != (pjsip_authorization_hdr*)hdr_list) {
+	if (pj_stricmp(&h->credential.digest.realm, realm)==0)
+	    return h;
+	h = h->next;
+    }
+
+    return NULL;
+}
+
 
 /* Initialize outgoing request. */
@@ -706,4 +752,5 @@
     const pjsip_method *method;
     pjsip_cached_auth *auth;
+    pjsip_hdr added;
 
     PJ_ASSERT_RETURN(sess && tdata, PJ_EINVAL);
@@ -711,4 +758,7 @@
     PJ_ASSERT_RETURN(tdata->msg->type==PJSIP_REQUEST_MSG,
 		     PJSIP_ENOTREQUESTMSG);
+
+    /* Init list */
+    pj_list_init(&added);
 
     /* Get the method. */
@@ -729,5 +779,6 @@
 			pjsip_authorization_hdr *hauth;
 			hauth = pjsip_hdr_shallow_clone(tdata->pool, entry->hdr);
-			pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hauth);
+			//pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hauth);
+			pj_list_push_back(&added, hauth);
 			break;
 		    }
@@ -777,9 +828,76 @@
 		return status;
 	    
-	    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hauth);
+	    //pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hauth);
+	    pj_list_push_back(&added, hauth);
 	}
 #	endif	/* PJSIP_AUTH_QOP_SUPPORT && PJSIP_AUTH_AUTO_SEND_NEXT */
 
 	auth = auth->next;
+    }
+
+    if (sess->pref.initial_auth == PJ_FALSE) {
+	pjsip_hdr *h;
+
+	/* Don't want to send initial empty Authorization header, so
+	 * just send whatever available in the list (maybe empty).
+	 */
+
+	h = added.next;
+	while (h != &added) {
+	    pjsip_hdr *next = h->next;
+	    pjsip_msg_add_hdr(tdata->msg, h);
+	    h = next;
+	}
+    } else {
+	/* For each realm, add either the cached authorization header
+	 * or add an empty authorization header.
+	 */
+	unsigned i;
+	char *uri_str;
+	int len;
+
+	uri_str = pj_pool_alloc(tdata->pool, PJSIP_MAX_URL_SIZE);
+	len = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, tdata->msg->line.req.uri,
+			      uri_str, PJSIP_MAX_URL_SIZE);
+	if (len < 1 || len >= PJSIP_MAX_URL_SIZE)
+	    return PJSIP_EURITOOLONG;
+
+	for (i=0; i<sess->cred_cnt; ++i) {
+	    pjsip_cred_info *c = &sess->cred_info[i];
+	    pjsip_authorization_hdr *h;
+
+	    h = get_header_for_realm(&added, &c->realm);
+	    if (h) {
+		pj_list_erase(h);
+		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)h);
+	    } else {
+		enum { HDRLEN = 256 };
+		const pj_str_t hname = pj_str("Authorization");
+		pj_str_t hval;
+		pjsip_generic_string_hdr *hs;
+		char *hdr;
+
+		hdr = pj_pool_alloc(tdata->pool, HDRLEN);
+		len = pj_ansi_snprintf(
+		    hdr, HDRLEN,
+		    "%.*s username=\"%.*s\", realm=\"%.*s\","
+		    " nonce=\"\", uri=\"%s\",%s%.*s%s response=\"\"",
+		    (int)c->scheme.slen, c->scheme.ptr,
+		    (int)c->username.slen, c->username.ptr,
+		    (int)c->realm.slen, c->realm.ptr,
+		    uri_str,
+		    (sess->pref.algorithm.slen ? " algorithm=" : ""),
+		    (int)sess->pref.algorithm.slen, sess->pref.algorithm.ptr,
+		    (sess->pref.algorithm.slen ? "," : ""));
+
+		PJ_ASSERT_RETURN(len>0 && len<HDRLEN, PJ_ETOOBIG);
+
+		hval.ptr = hdr;
+		hval.slen = len;
+		hs = pjsip_generic_string_hdr_create(tdata->pool, &hname, 
+						     &hval);
+		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hs);
+	    }
+	}
     }
 
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_acc.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_acc.c	(revision 1560)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_acc.c	(revision 1561)
@@ -545,8 +545,4 @@
     unsigned i, uri_cnt = 0, rcnt;
 
-    /* Skip processing is enable_service_route is not set */
-    if (!acc->cfg.enable_service_route)
-	return;
-
     /* Find and parse Service-Route headers */
     for (;;) {
@@ -916,4 +912,7 @@
 	pjsip_regc_set_credentials( acc->regc, acc->cred_cnt, acc->cred);
     }
+
+    /* Set authentication preference */
+    pjsip_regc_set_prefs(acc->regc, &acc->cfg.auth_pref);
 
     /* Set route-set
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c	(revision 1560)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c	(revision 1561)
@@ -384,4 +384,6 @@
     }
 
+    /* Set authentication preference */
+    pjsip_auth_clt_set_prefs(&dlg->auth_sess, &acc->cfg.auth_pref);
 
     /* Create initial INVITE: */
@@ -666,4 +668,8 @@
 				       pjsua_var.acc[acc_id].cred);
     }
+
+    /* Set preference */
+    pjsip_auth_clt_set_prefs(&dlg->auth_sess, 
+			     &pjsua_var.acc[acc_id].cfg.auth_pref);
 
     /* Create invite session: */
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_im.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_im.c	(revision 1560)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_im.c	(revision 1561)
@@ -322,4 +322,7 @@
 		pjsua_var.acc[im_data->acc_id].cred);
 
+	    pjsip_auth_clt_set_prefs(&auth, 
+				     &pjsua_var.acc[im_data->acc_id].cfg.auth_pref);
+
 	    status = pjsip_auth_clt_reinit_req(&auth, rdata, tsx->last_tx,
 					       &tdata);
@@ -418,4 +421,7 @@
 		pjsua_var.acc[im_data->acc_id].cred);
 
+	    pjsip_auth_clt_set_prefs(&auth, 
+				     &pjsua_var.acc[im_data->acc_id].cfg.auth_pref);
+
 	    status = pjsip_auth_clt_reinit_req(&auth, rdata, tsx->last_tx,
 					       &tdata);
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_pres.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_pres.c	(revision 1560)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_pres.c	(revision 1561)
@@ -572,6 +572,7 @@
     }
 
-    /* Set credentials. */
+    /* Set credentials and preference. */
     pjsip_auth_clt_set_credentials(&dlg->auth_sess, acc->cred_cnt, acc->cred);
+    pjsip_auth_clt_set_prefs(&dlg->auth_sess, &acc->cfg.auth_pref);
 
     /* Init callback: */
@@ -1174,4 +1175,7 @@
     }
 
+    /* Set authentication preference */
+    pjsip_auth_clt_set_prefs(&buddy->dlg->auth_sess, &acc->cfg.auth_pref);
+
     pjsip_evsub_set_mod_data(buddy->sub, pjsua_var.mod.id, buddy);
 
