Ticket #930:
 - Updated semantic of contact param in functions pjsip_dlg_create_uac(), pjsip_dlg_create_uas(), pjsip_endpt_create_request() and also variable pjsua_acc.contact to be Contact header value (was Contact URI).
 - Updated docs related to above modifications.
 - Fixed pjsua_im_send() in generating contact header, it should use pjsua_acc.contact instead, if it is set.




git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@2855 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjsip/include/pjsip-ua/sip_regc.h b/pjsip/include/pjsip-ua/sip_regc.h
index 91adaa4..eb8b33c 100644
--- a/pjsip/include/pjsip-ua/sip_regc.h
+++ b/pjsip/include/pjsip-ua/sip_regc.h
@@ -166,7 +166,15 @@
  * @param to_url    The address of record for which the registration is targetd, must
  *		    be a SIP/SIPS URL.
  * @param ccnt	    Number of contacts in the array.
- * @param contact   Array of contacts.
+ * @param contact   Array of contacts, each contact item must be formatted
+ *		    as described in RFC 3261 Section 20.10:
+ *		    When the header field value contains a display 
+ *		    name, the URI including all URI parameters is 
+ *		    enclosed in "<" and ">".  If no "<" and ">" are 
+ *		    present, all parameters after the URI are header
+ *		    parameters, not URI parameters.  The display name 
+ *		    can be tokens, or a quoted string, if a larger 
+ *		    character set is desired.
  * @param expires   Default expiration interval (in seconds) to be applied for
  *		    contact URL that doesn't have expiration settings. If the
  *		    value PJSIP_REGC_EXPIRATION_NOT_SPECIFIED is given, then 
@@ -303,8 +311,8 @@
 
 /**
  * Update Contact details in the client registration structure. For each
- * contact URI, if the uri is not found in existing contact, it will be
- * added to the Contact list. If the URI matches existing contact, nothing
+ * contact, if the contact is not found in existing contact, it will be
+ * added to the Contact list. If it matches existing contact, nothing
  * will be added. This function will also mark existing contacts which
  * are not specified in the new contact list as to be removed, by adding
  * "expires=0" parameter to these contacts.
@@ -317,7 +325,15 @@
  *
  * @param regc	    The client registration structure.
  * @param ccnt	    Number of contacts.
- * @param contact   Array of contact URIs.
+ * @param contact   Array of contacts, each contact item must be formatted
+ *		    as described in RFC 3261 Section 20.10:
+ *		    When the header field value contains a display 
+ *		    name, the URI including all URI parameters is 
+ *		    enclosed in "<" and ">".  If no "<" and ">" are 
+ *		    present, all parameters after the URI are header
+ *		    parameters, not URI parameters.  The display name 
+ *		    can be tokens, or a quoted string, if a larger 
+ *		    character set is desired.
  * @return	    PJ_SUCCESS if sucessfull.
  */
 PJ_DECL(pj_status_t) pjsip_regc_update_contact( pjsip_regc *regc,
diff --git a/pjsip/include/pjsip/sip_dialog.h b/pjsip/include/pjsip/sip_dialog.h
index 03098df..6b748b3 100644
--- a/pjsip/include/pjsip/sip_dialog.h
+++ b/pjsip/include/pjsip/sip_dialog.h
@@ -183,9 +183,18 @@
  *
  * @param ua		    The user agent module instance.
  * @param local_uri	    Dialog local URI (i.e. From header).
- * @param local_contact_uri Optional dialog local Contact URI. 
- *			    If this argument is NULL, the Contact will be
- *			    taken from the local URI.
+ * @param local_contact	    Optional dialog local Contact to be put as Contact
+ *			    header value, hence the format must follow
+ *			    RFC 3261 Section 20.10:
+ *			    When the header field value contains a display 
+ *			    name, the URI including all URI parameters is 
+ *			    enclosed in "<" and ">".  If no "<" and ">" are 
+ *			    present, all parameters after the URI are header
+ *			    parameters, not URI parameters.  The display name 
+ *			    can be tokens, or a quoted string, if a larger 
+ *			    character set is desired.
+ *			    If this argument is NULL, the Contact will be taken
+ *			    from the local URI.
  * @param remote_uri	    Dialog remote URI (i.e. To header).
  * @param target	    Optional initial remote target. If this argument
  *			    is NULL, the initial target will be set to
@@ -196,7 +205,7 @@
  */
 PJ_DECL(pj_status_t) pjsip_dlg_create_uac( pjsip_user_agent *ua,
 					   const pj_str_t *local_uri,
-					   const pj_str_t *local_contact_uri,
+					   const pj_str_t *local_contact,
 					   const pj_str_t *remote_uri,
 					   const pj_str_t *target,
 					   pjsip_dialog **p_dlg);
@@ -220,8 +229,17 @@
  * @param ua		    The user agent module instance.
  * @param rdata		    The incoming request that creates the dialog,
  *			    such as INVITE, SUBSCRIBE, or REFER.
- * @param contact	    Optional URI to be used as local Contact. If
- *			    this argument is NULL, the local contact will be
+ * @param contact	    Optional dialog local Contact to be put as Contact
+ *			    header value, hence the format must follow
+ *			    RFC 3261 Section 20.10:
+ *			    When the header field value contains a display 
+ *			    name, the URI including all URI parameters is 
+ *			    enclosed in "<" and ">".  If no "<" and ">" are 
+ *			    present, all parameters after the URI are header
+ *			    parameters, not URI parameters.  The display name 
+ *			    can be tokens, or a quoted string, if a larger 
+ *			    character set is desired.
+ *			    If this argument is NULL, the local contact will be
  *			    initialized from the value of To header in the
  *			    request.
  * @param p_dlg		    Pointer to receive the dialog.
diff --git a/pjsip/include/pjsip/sip_util.h b/pjsip/include/pjsip/sip_util.h
index b7b0078..57a4821 100644
--- a/pjsip/include/pjsip/sip_util.h
+++ b/pjsip/include/pjsip/sip_util.h
@@ -243,7 +243,15 @@
  * @param target    Target URI.
  * @param from	    URL to put in From header.
  * @param to	    URL to put in To header.
- * @param contact   URL to put in Contact header.
+ * @param contact   Contact to be put as Contact header value, hence
+ *		    the format must follow RFC 3261 Section 20.10:
+ *		    When the header field value contains a display 
+ *		    name, the URI including all URI parameters is 
+ *		    enclosed in "<" and ">".  If no "<" and ">" are 
+ *		    present, all parameters after the URI are header
+ *		    parameters, not URI parameters.  The display name 
+ *		    can be tokens, or a quoted string, if a larger 
+ *		    character set is desired.
  * @param call_id   Optional Call-ID (put NULL to generate unique Call-ID).
  * @param cseq	    Optional CSeq (put -1 to generate random CSeq).
  * @param text	    Optional text body (put NULL to omit body).
@@ -280,9 +288,9 @@
  * @param endpt	    Endpoint instance.
  * @param method    SIP Method.
  * @param target    Target URI.
- * @param from	    URL to put in From header.
- * @param to	    URL to put in To header.
- * @param contact   URL to put in Contact header.
+ * @param from	    From header.
+ * @param to	    To header.
+ * @param contact   Contact header.
  * @param call_id   Optional Call-ID (put NULL to generate unique Call-ID).
  * @param cseq	    Optional CSeq (put -1 to generate random CSeq).
  * @param text	    Optional text body (put NULL to omit body).
diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index 023acb6..e06019d 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -2163,11 +2163,11 @@
 
 
 /**
- * Create a suitable URI to be put as Contact based on the specified
- * target URI for the specified account.
+ * Create a suitable Contact header value, based on the specified target URI 
+ * for the specified account.
  *
  * @param pool		Pool to allocate memory for the string.
- * @param contact	The string where the Contact URI will be stored.
+ * @param contact	The string where the Contact will be stored.
  * @param acc_id	Account ID.
  * @param uri		Destination URI of the request.
  *
@@ -2181,11 +2181,11 @@
 
 
 /**
- * Create a suitable URI to be put as Contact based on the information
- * in the incoming request.
+ * Create a suitable Contact header value, based on the information in the 
+ * incoming request.
  *
  * @param pool		Pool to allocate memory for the string.
- * @param contact	The string where the Contact URI will be stored.
+ * @param contact	The string where the Contact will be stored.
  * @param acc_id	Account ID.
  * @param rdata		Incoming request.
  *
diff --git a/pjsip/include/pjsua-lib/pjsua_internal.h b/pjsip/include/pjsua-lib/pjsua_internal.h
index a144c97..d80f5d1 100644
--- a/pjsip/include/pjsua-lib/pjsua_internal.h
+++ b/pjsip/include/pjsua-lib/pjsua_internal.h
@@ -118,7 +118,7 @@
     int		     index;	    /**< Index in accounts array.	*/
     pj_str_t	     display;	    /**< Display name, if any.		*/
     pj_str_t	     user_part;	    /**< User part of local URI.	*/
-    pj_str_t	     contact;	    /**< Our Contact URI for REGISTER	*/
+    pj_str_t	     contact;	    /**< Our Contact header.		*/
 
     pj_str_t	     srv_domain;    /**< Host part of reg server.	*/
     int		     srv_port;	    /**< Port number of reg server.	*/
diff --git a/pjsip/src/pjsip-ua/sip_reg.c b/pjsip/src/pjsip-ua/sip_reg.c
index 5278ae4..ecba264 100644
--- a/pjsip/src/pjsip-ua/sip_reg.c
+++ b/pjsip/src/pjsip-ua/sip_reg.c
@@ -272,7 +272,7 @@
 	hdr = (pjsip_contact_hdr*)
               pjsip_parse_hdr(regc->pool, &CONTACT, tmp.ptr, tmp.slen, NULL);
 	if (hdr == NULL) {
-	    PJ_LOG(4,(THIS_FILE, "Invalid Contact URI: \"%.*s\"", 
+	    PJ_LOG(4,(THIS_FILE, "Invalid Contact: \"%.*s\"", 
 		     (int)tmp.slen, tmp.ptr));
 	    return PJSIP_EINVALIDURI;
 	}
diff --git a/pjsip/src/pjsip/sip_dialog.c b/pjsip/src/pjsip/sip_dialog.c
index caa7286..5fcd7e8 100644
--- a/pjsip/src/pjsip/sip_dialog.c
+++ b/pjsip/src/pjsip/sip_dialog.c
@@ -43,6 +43,8 @@
 /* Config */
 pj_bool_t pjsip_include_allow_hdr_in_dlg = PJSIP_INCLUDE_ALLOW_HDR_IN_DLG;
 
+/* Contact header string */
+static const pj_str_t HCONTACT = { "Contact", 7 };
 
 PJ_DEF(pj_bool_t) pjsip_method_creates_dialog(const pjsip_method *m)
 {
@@ -210,12 +212,11 @@
     dlg->local.cseq = dlg->local.first_cseq;
 
     /* Init local contact. */
-    dlg->local.contact = pjsip_contact_hdr_create(dlg->pool);
     pj_strdup_with_null(dlg->pool, &tmp, 
 			local_contact ? local_contact : local_uri);
-    dlg->local.contact->uri = pjsip_parse_uri(dlg->pool, tmp.ptr, tmp.slen,
-					      PJSIP_PARSE_URI_AS_NAMEADDR);
-    if (!dlg->local.contact->uri) {
+    dlg->local.contact = pjsip_parse_hdr(dlg->pool, &HCONTACT, tmp.ptr, 
+					 tmp.slen, NULL);
+    if (!dlg->local.contact) {
 	status = PJSIP_EINVALIDURI;
 	goto on_error;
     }
@@ -390,11 +391,10 @@
     if (contact) {
 	pj_str_t tmp;
 
-	dlg->local.contact = pjsip_contact_hdr_create(dlg->pool);
 	pj_strdup_with_null(dlg->pool, &tmp, contact);
-	dlg->local.contact->uri = pjsip_parse_uri(dlg->pool, tmp.ptr, tmp.slen,
-						  PJSIP_PARSE_URI_AS_NAMEADDR);
-	if (!dlg->local.contact->uri) {
+	dlg->local.contact = pjsip_parse_hdr(dlg->pool, &HCONTACT, tmp.ptr, 
+					     tmp.slen, NULL);
+	if (!dlg->local.contact) {
 	    status = PJSIP_EINVALIDURI;
 	    goto on_error;
 	}
@@ -1225,11 +1225,9 @@
 	if (st_class==2 || st_class==3 || (st_class==1 && st_code != 100) ||
 	    st_code==485) 
 	{
-	    pj_str_t hcontact = { "Contact", 7 };
-
 	    /* Add contact header only if one is not present. */
 	    if (pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL) == 0 &&
-		pjsip_msg_find_hdr_by_name(tdata->msg, &hcontact, NULL) == 0) 
+		pjsip_msg_find_hdr_by_name(tdata->msg, &HCONTACT, NULL) == 0) 
 	    {
 		hdr = (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, 
 						   dlg->local.contact);
diff --git a/pjsip/src/pjsip/sip_util.c b/pjsip/src/pjsip/sip_util.c
index 01948a5..cc5d71d 100644
--- a/pjsip/src/pjsip/sip_util.c
+++ b/pjsip/src/pjsip/sip_util.c
@@ -307,6 +307,7 @@
     pjsip_cid_hdr *call_id;
     pj_str_t tmp;
     pj_status_t status;
+    const pj_str_t STR_CONTACT = { "Contact", 7 };
     PJ_USE_EXCEPTION;
 
     status = pjsip_endpt_create_tdata(endpt, &tdata);
@@ -348,11 +349,11 @@
 
 	/* Contact. */
 	if (param_contact) {
-	    contact = pjsip_contact_hdr_create(tdata->pool);
 	    pj_strdup_with_null(tdata->pool, &tmp, param_contact);
-	    contact->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen,
-					    PJSIP_PARSE_URI_AS_NAMEADDR);
-	    if (contact->uri == NULL) {
+	    contact = (pjsip_contact_hdr*)
+		      pjsip_parse_hdr(tdata->pool, &STR_CONTACT, tmp.ptr, 
+				      tmp.slen, NULL);
+	    if (contact == NULL) {
 		status = PJSIP_EINVALIDHDR;
 		goto on_error;
 	    }
diff --git a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c
index 05cedf4..4bfe98c 100644
--- a/pjsip/src/pjsua-lib/pjsua_acc.c
+++ b/pjsip/src/pjsua-lib/pjsua_acc.c
@@ -573,6 +573,8 @@
     pj_status_t status;
     pj_bool_t matched;
     pj_str_t srv_ip;
+    pjsip_contact_hdr *contact_hdr;
+    const pj_str_t STR_CONTACT = { "Contact", 7 };
 
     tp = param->rdata->tp_info.transport;
 
@@ -619,8 +621,11 @@
 
     /* Compare received and rport with the URI in our registration */
     pool = pjsua_pool_create("tmp", 512, 512);
-    uri = (pjsip_sip_uri*)
-	  pjsip_parse_uri(pool, acc->contact.ptr, acc->contact.slen, 0);
+    contact_hdr = (pjsip_contact_hdr*)
+		  pjsip_parse_hdr(pool, &STR_CONTACT, acc->contact.ptr, 
+				  acc->contact.slen, NULL);
+    pj_assert(contact_hdr != NULL);
+    uri = (pjsip_sip_uri*) contact_hdr->uri;
     pj_assert(uri != NULL);
     uri = (pjsip_sip_uri*) pjsip_uri_get_uri(uri);
 
diff --git a/pjsip/src/pjsua-lib/pjsua_im.c b/pjsip/src/pjsua-lib/pjsua_im.c
index a727d5d..121e01f 100644
--- a/pjsip/src/pjsua-lib/pjsua_im.c
+++ b/pjsip/src/pjsua-lib/pjsua_im.c
@@ -509,16 +509,19 @@
     const pj_str_t STR_CONTACT = { "Contact", 7 };
     pjsip_media_type media_type;
     pjsua_im_data *im_data;
+    pjsua_acc *acc;
     pj_str_t contact;
     pj_status_t status;
 
     /* To and message body must be specified. */
     PJ_ASSERT_RETURN(to && content, PJ_EINVAL);
 
+    acc = &pjsua_var.acc[acc_id];
+
     /* Create request. */
     status = pjsip_endpt_create_request(pjsua_var.endpt, 
 					&pjsip_message_method, to, 
-					&pjsua_var.acc[acc_id].cfg.id,
+					&acc->cfg.id,
 					to, NULL, NULL, -1, NULL, &tdata);
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "Unable to create request", status);
@@ -528,10 +531,10 @@
     /* If account is locked to specific transport, then set transport to
      * the request.
      */
-    if (pjsua_var.acc[acc_id].cfg.transport_id != PJSUA_INVALID_ID) {
+    if (acc->cfg.transport_id != PJSUA_INVALID_ID) {
 	pjsip_tpselector tp_sel;
 
-	pjsua_init_tpselector(pjsua_var.acc[acc_id].cfg.transport_id, &tp_sel);
+	pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel);
 	pjsip_tx_data_set_transport(tdata, &tp_sel);
     }
 
@@ -539,12 +542,18 @@
     pjsip_msg_add_hdr( tdata->msg, 
 		       (pjsip_hdr*)pjsua_im_create_accept(tdata->pool));
 
-    /* Add contact. */
-    status = pjsua_acc_create_uac_contact(tdata->pool, &contact, acc_id, to);
-    if (status != PJ_SUCCESS) {
-	pjsua_perror(THIS_FILE, "Unable to generate Contact header", status);
-	pjsip_tx_data_dec_ref(tdata);
-	return status;
+    /* Create suitable Contact header unless a Contact header has been
+     * set in the account.
+     */
+    if (acc->contact.slen) {
+	contact = acc->contact;
+    } else {
+	status = pjsua_acc_create_uac_contact(tdata->pool, &contact, acc_id, to);
+	if (status != PJ_SUCCESS) {
+	    pjsua_perror(THIS_FILE, "Unable to generate Contact header", status);
+	    pjsip_tx_data_dec_ref(tdata);
+	    return status;
+	}
     }
 
     pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)
@@ -584,7 +593,7 @@
     pjsua_process_msg_data(tdata, msg_data);
 
     /* Add route set */
-    pjsua_set_msg_route_set(tdata, &pjsua_var.acc[acc_id].route_set);
+    pjsua_set_msg_route_set(tdata, &acc->route_set);
 
     /* Send request (statefully) */
     status = pjsip_endpt_send_request( pjsua_var.endpt, tdata, -1, 
@@ -609,12 +618,15 @@
     const pj_str_t STR_CONTACT = { "Contact", 7 };
     pjsua_im_data *im_data;
     pjsip_tx_data *tdata;
+    pjsua_acc *acc;
     pj_str_t contact;
     pj_status_t status;
 
+    acc = &pjsua_var.acc[acc_id];
+
     /* Create request. */
     status = pjsip_endpt_create_request( pjsua_var.endpt, &pjsip_message_method,
-					 to, &pjsua_var.acc[acc_id].cfg.id,
+					 to, &acc->cfg.id,
 					 to, NULL, NULL, -1, NULL, &tdata);
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "Unable to create request", status);
@@ -625,10 +637,10 @@
     /* If account is locked to specific transport, then set transport to
      * the request.
      */
-    if (pjsua_var.acc[acc_id].cfg.transport_id != PJSUA_INVALID_ID) {
+    if (acc->cfg.transport_id != PJSUA_INVALID_ID) {
 	pjsip_tpselector tp_sel;
 
-	pjsua_init_tpselector(pjsua_var.acc[acc_id].cfg.transport_id, &tp_sel);
+	pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel);
 	pjsip_tx_data_set_transport(tdata, &tp_sel);
     }
 
@@ -637,12 +649,18 @@
 		       (pjsip_hdr*)pjsua_im_create_accept(tdata->pool));
 
 
-    /* Add contact. */
-    status = pjsua_acc_create_uac_contact(tdata->pool, &contact, acc_id, to);
-    if (status != PJ_SUCCESS) {
-	pjsua_perror(THIS_FILE, "Unable to generate Contact header", status);
-	pjsip_tx_data_dec_ref(tdata);
-	return status;
+    /* Create suitable Contact header unless a Contact header has been
+     * set in the account.
+     */
+    if (acc->contact.slen) {
+	contact = acc->contact;
+    } else {
+	status = pjsua_acc_create_uac_contact(tdata->pool, &contact, acc_id, to);
+	if (status != PJ_SUCCESS) {
+	    pjsua_perror(THIS_FILE, "Unable to generate Contact header", status);
+	    pjsip_tx_data_dec_ref(tdata);
+	    return status;
+	}
     }
 
     pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)
@@ -658,7 +676,7 @@
     pjsua_process_msg_data(tdata, msg_data);
 
     /* Add route set */
-    pjsua_set_msg_route_set(tdata, &pjsua_var.acc[acc_id].route_set);
+    pjsua_set_msg_route_set(tdata, &acc->route_set);
 
     /* Create data to reauthenticate */
     im_data = PJ_POOL_ZALLOC_T(tdata->pool, pjsua_im_data);