Index: /pjproject/trunk/pjsip/include/pjsip-simple/publish.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip-simple/publish.h	(revision 2660)
+++ /pjproject/trunk/pjsip/include/pjsip-simple/publish.h	(revision 2661)
@@ -79,5 +79,7 @@
     pj_str_t		 reason;    /**< SIP reason phrase received.	    */
     pjsip_rx_data	*rdata;	    /**< The complete received response.    */
-    int			 expiration;/**< Next expiration interval.	    */
+    int			 expiration;/**< Next expiration interval. If the
+					 value is -1, it means the session
+					 will not renew itself.		    */
 };
 
@@ -191,4 +193,23 @@
 
 /**
+ * Set list of headers to be added to each PUBLISH request generated by
+ * the client publication session. Note that application can also add
+ * the headers to the request after calling #pjsip_publishc_publish()
+ * or #pjsip_publishc_unpublish(), but the benefit of this function is
+ * the headers will also be added to requests generated internally by
+ * the session, such as during session renewal/refresh.
+ *
+ * Note that calling this function will clear the previously added list
+ * of headers.
+ *
+ * @param pubc	    The client publication structure.
+ * @param hdr_list  The list of headers.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_publishc_set_headers(pjsip_publishc *pubc,
+						const pjsip_hdr *hdr_list);
+
+/**
  * Create PUBLISH request for the specified client publication structure.
  * Application can use this function to both create initial publication
Index: /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 2660)
+++ /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 2661)
@@ -2038,5 +2038,5 @@
  */
 #ifndef PJSUA_PUBLISH_EXPIRATION
-#   define PJSUA_PUBLISH_EXPIRATION 600
+#   define PJSUA_PUBLISH_EXPIRATION PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED
 #endif
 
@@ -3494,5 +3494,6 @@
 /**
  * This specifies how long the library should retry resending SUBSCRIBE
- * if the previous SUBSCRIBE failed.
+ * if the previous SUBSCRIBE failed. This also controls the duration 
+ * before failed PUBLISH request will be retried.
  *
  * Default: 300 seconds
Index: /pjproject/trunk/pjsip/src/pjsip-simple/publishc.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip-simple/publishc.c	(revision 2660)
+++ /pjproject/trunk/pjsip/src/pjsip-simple/publishc.c	(revision 2661)
@@ -82,4 +82,5 @@
     pj_uint32_t			 expires;
     pjsip_route_hdr		 route_set;
+    pjsip_hdr			 usr_hdr;
 
     /* Authorization sessions. */
@@ -158,4 +159,5 @@
 
     pj_list_init(&pubc->route_set);
+    pj_list_init(&pubc->usr_hdr);
 
     /* Done */
@@ -187,5 +189,7 @@
 static void set_expires( pjsip_publishc *pubc, pj_uint32_t expires)
 {
-    if (expires != pubc->expires) {
+    if (expires != pubc->expires && 
+	expires != PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED) 
+    {
 	pubc->expires_hdr = pjsip_expires_hdr_create(pubc->pool, expires);
     } else {
@@ -277,4 +281,21 @@
 	pj_list_push_back(&pubc->route_set, pjsip_hdr_clone(pubc->pool, chdr));
 	chdr = chdr->next;
+    }
+
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pjsip_publishc_set_headers( pjsip_publishc *pubc,
+						const pjsip_hdr *hdr_list)
+{
+    const pjsip_hdr *h;
+
+    PJ_ASSERT_RETURN(pubc && hdr_list, PJ_EINVAL);
+
+    pj_list_init(&pubc->usr_hdr);
+    h = hdr_list->next;
+    while (h != hdr_list) {
+	pj_list_push_back(&pubc->usr_hdr, pjsip_hdr_clone(pubc->pool, h));
+	h = h->next;
     }
 
@@ -346,4 +367,17 @@
     }
 
+    /* Add user headers */
+    if (!pj_list_empty(&pubc->usr_hdr)) {
+	const pjsip_hdr *hdr;
+
+	hdr = pubc->usr_hdr.next;
+	while (hdr != &pubc->usr_hdr) {
+	    pjsip_hdr *new_hdr = (pjsip_hdr*)
+	    			 pjsip_hdr_shallow_clone(tdata->pool, hdr);
+	    pjsip_msg_add_hdr(tdata->msg, new_hdr);
+	    hdr = hdr->next;
+	}
+    }
+
 
     /* Done. */
@@ -531,5 +565,5 @@
 	    	      pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
 
-	    if (expires)
+	    if (pubc->auto_refresh && expires)
 		expiration = expires->ivalue;
 	    
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_pres.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_pres.c	(revision 2660)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_pres.c	(revision 2661)
@@ -962,4 +962,8 @@
 
     if (param->code/100 != 2 || param->status != PJ_SUCCESS) {
+
+	pjsip_publishc_destroy(param->pubc);
+	acc->publish_sess = NULL;
+
 	if (param->status != PJ_SUCCESS) {
 	    char errmsg[PJ_ERR_MSG_SIZE];
@@ -969,4 +973,10 @@
 		      "Client publication (PUBLISH) failed, status=%d, msg=%s",
 		       param->status, errmsg));
+	} else if (param->code == 412) {
+	    /* 412 (Conditional Request Failed)
+	     * The PUBLISH refresh has failed, retry with new one.
+	     */
+	    pjsua_pres_init_publish_acc(acc->index);
+	    
 	} else {
 	    PJ_LOG(1,(THIS_FILE, 
@@ -976,6 +986,12 @@
 	}
 
-	pjsip_publishc_destroy(param->pubc);
-	acc->publish_sess = NULL;
+    } else {
+	if (param->expiration == -1) {
+	    /* Could happen if server "forgot" to include Expires header
+	     * in the response. We will not renew, so destroy the pubc.
+	     */
+	    pjsip_publishc_destroy(param->pubc);
+	    acc->publish_sess = NULL;
+	}
     }
 }
@@ -1092,5 +1108,5 @@
 				     &acc_cfg->id, &acc_cfg->id,
 				     &acc_cfg->id, 
-				     PJSUA_PRES_TIMER);
+				     PJSUA_PUBLISH_EXPIRATION);
 	if (status != PJ_SUCCESS) {
 	    acc->publish_sess = NULL;
@@ -1607,5 +1623,13 @@
 			  pj_timer_entry *entry)
 {
+    unsigned i;
     pj_time_val delay = { PJSUA_PRES_TIMER, 0 };
+
+    /* Retry failed PUBLISH requests */
+    for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
+	pjsua_acc *acc = &pjsua_var.acc[i];
+	if (acc->cfg.publish_enabled && acc->publish_sess==NULL)
+	    pjsua_pres_init_publish_acc(acc->index);
+    }
 
     entry->id = PJ_FALSE;
Index: /pjproject/trunk/tests/pjsua/scripts-recvfrom/240_publish_scenarios.py
===================================================================
--- /pjproject/trunk/tests/pjsua/scripts-recvfrom/240_publish_scenarios.py	(revision 2661)
+++ /pjproject/trunk/tests/pjsua/scripts-recvfrom/240_publish_scenarios.py	(revision 2661)
@@ -0,0 +1,51 @@
+# $Id$
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Several PUBLISH failure scenarios that should be handled automatically
+
+
+pjsua = "--null-audio --id=sip:127.0.0.1:$PORT --registrar sip:127.0.0.1:$PORT " + \
+	"--realm=python --user=username --password=password " + \
+	"--auto-update-nat=0 --publish"
+#pjsua = "--null-audio --local-port 0 --rtp-port 0"
+
+# Handle REGISTER first
+req1 = sip.RecvfromTransaction("Initial REGISTER", 200,
+				include=["REGISTER sip"], 
+				exclude=[],
+				resp_hdr=["Expires: 1800"]
+			  	)
+
+# First PUBLISH, reply with 412
+req2 = sip.RecvfromTransaction("Initial PUBLISH, will be replied with 412", 412,
+				include=["PUBLISH sip"], 
+				exclude=["Expires:"]
+			  	)
+
+# Second PUBLISH
+req3 = sip.RecvfromTransaction("Second PUBLISH, will be replied with 200", 200,
+				include=["PUBLISH sip"], 
+				exclude=["Expires:"],
+				resp_hdr=["Expires: 60", "SIP-ETag: dx200xyz"]
+			  	)
+
+# PUBLISH refresh, respond with 408
+req4 = sip.RecvfromTransaction("PUBLISH refresh, will be replied with 408", 408,
+				include=["PUBLISH sip", "SIP-If-Match: dx200xyz"], 
+				exclude=["Expires:"],
+				resp_hdr=["Expires: 60", "SIP-ETag: dx200xyz"]
+			  	)
+
+# After 5 minutes, pjsua should retry again
+req5 = sip.RecvfromTransaction("PUBLISH retry", 200,
+				include=["PUBLISH sip"], 
+				exclude=["Expires:", "SIP-If-Match:"],
+				resp_hdr=["Expires: 60", "SIP-ETag: abc"]
+			  	)
+
+
+
+recvfrom_cfg = sip.RecvfromCfg("PUBLISH scenarios",
+			       pjsua, [req1, req2, req3])
+
