Index: pjproject/trunk/pjsip/include/pjsip-simple/evsub.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsip-simple/evsub.h	(revision 2148)
+++ pjproject/trunk/pjsip/include/pjsip-simple/evsub.h	(revision 2149)
@@ -347,4 +347,15 @@
 
 /**
+ * Get subscription termination reason, if any. If remote did not
+ * send termination reason, this function will return empty string.
+ *
+ * @param sub		Event subscription instance.
+ *
+ * @return		NULL terminated string.
+ */
+PJ_DECL(const pj_str_t*) pjsip_evsub_get_termination_reason(pjsip_evsub *sub);
+
+
+/**
  * Call this function to create request to initiate subscription, to 
  * refresh subcription, or to request subscription termination.
Index: pjproject/trunk/pjsip/src/pjsip-simple/evsub.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip-simple/evsub.c	(revision 2148)
+++ pjproject/trunk/pjsip/src/pjsip-simple/evsub.c	(revision 2149)
@@ -222,4 +222,5 @@
     pjsip_evsub_state	  dst_state;	/**< Pending state to be set.	    */
     pj_str_t		  dst_state_str;/**< Pending state to be set.	    */
+    pj_str_t		  term_reason;	/**< Termination reason.	    */
     pjsip_method	  method;	/**< Method that established subscr.*/
     pjsip_event_hdr	 *event;	/**< Event description.		    */
@@ -551,5 +552,6 @@
  */
 static void set_state( pjsip_evsub *sub, pjsip_evsub_state state,
-		       const pj_str_t *state_str, pjsip_event *event)
+		       const pj_str_t *state_str, pjsip_event *event,
+		       const pj_str_t *reason)
 {
     pjsip_evsub_state prev_state = sub->state;
@@ -562,4 +564,7 @@
     else
 	sub->state_str = evsub_state_names[state];
+
+    if (reason && sub->term_reason.slen==0)
+	pj_strdup(sub->pool, &sub->term_reason, reason);
 
     PJ_LOG(4,(sub->obj_name, 
@@ -639,7 +644,10 @@
     case TIMER_TYPE_UAC_TERMINATE:
 	{
+	    pj_str_t timeout = {"timeout", 7};
+
 	    PJ_LOG(5,(sub->obj_name, "Timeout waiting for final NOTIFY. "
 				     "Terminating.."));
-	    set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL);
+	    set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL, 
+		      &timeout);
 	}
 	break;
@@ -913,5 +921,5 @@
 
     sub->call_cb = notify;
-    set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL);
+    set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL, NULL);
 
     pjsip_dlg_dec_lock(sub->dlg);
@@ -935,4 +943,11 @@
 }
 
+/*
+ * Get termination reason.
+ */
+PJ_DEF(const pj_str_t*) pjsip_evsub_get_termination_reason(pjsip_evsub *sub)
+{
+    return &sub->term_reason;
+}
 
 /*
@@ -1086,8 +1101,8 @@
     case PJSIP_EVSUB_STATE_NULL:
     case PJSIP_EVSUB_STATE_SENT:
-    case PJSIP_EVSUB_STATE_ACCEPTED:
 	pj_assert(!"Invalid state!");
 	/* Treat as pending */
 
+    case PJSIP_EVSUB_STATE_ACCEPTED:
     case PJSIP_EVSUB_STATE_PENDING:
 	sub_state->sub_state = STR_PENDING;
@@ -1156,5 +1171,7 @@
     pjsip_auth_clt_init_req( &sub->dlg->auth_sess, tdata );
 
-    
+    /* Update reason */
+    if (reason)
+	pj_strdup(sub->dlg->pool, &sub->term_reason, reason);
 
     /* Save destination state. */
@@ -1219,5 +1236,5 @@
 	set_state(sub, sub->dst_state, 
 		  (sub->dst_state_str.slen ? &sub->dst_state_str : NULL), 
-		  NULL);
+		  NULL, NULL);
 
 	sub->dst_state = PJSIP_EVSUB_STATE_NULL;
@@ -1547,5 +1564,5 @@
 	    tsx->state == PJSIP_TSX_STATE_CALLING)
 	{
-	    set_state(sub, PJSIP_EVSUB_STATE_SENT, NULL, event);
+	    set_state(sub, PJSIP_EVSUB_STATE_SENT, NULL, event, NULL);
 	    return;
 	}
@@ -1588,6 +1605,5 @@
 		/* Authentication failed! */
 		set_state(sub, PJSIP_EVSUB_STATE_TERMINATED,
-			       NULL,
-			       event);
+			  NULL, event, &tsx->status_text);
 		return;
 	    }
@@ -1647,5 +1663,5 @@
 	    pj_assert(sub->state != PJSIP_EVSUB_STATE_NULL);
 	    if (sub->state == PJSIP_EVSUB_STATE_SENT) {
-		set_state(sub, PJSIP_EVSUB_STATE_ACCEPTED, NULL, event);
+		set_state(sub, PJSIP_EVSUB_STATE_ACCEPTED, NULL, event, NULL);
 	    }
 
@@ -1686,5 +1702,5 @@
 	    /* Set state to TERMINATED */
 	    set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, 
-		      NULL, event);
+		      NULL, event, &tsx->status_text);
 
 	}
@@ -1772,5 +1788,10 @@
 		set_timer(sub, TIMER_TYPE_UAC_WAIT_NOTIFY, timeout);
 	    } else {
-		set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL);
+		char errmsg[PJ_ERR_MSG_SIZE];
+		pj_str_t reason;
+
+		reason = pj_strerror(status, errmsg, sizeof(errmsg));
+		set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL, 
+			  &reason);
 	    }
 
@@ -1816,7 +1837,13 @@
 	/* Set the state */
 	if (status == PJ_SUCCESS) {
-	    set_state(sub, new_state, new_state_str, event);
+	    set_state(sub, new_state, new_state_str, event, 
+		      &sub_state->reason_param);
 	} else {
-	    set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, event);
+	    char errmsg[PJ_ERR_MSG_SIZE];
+	    pj_str_t reason;
+
+	    reason = pj_strerror(status, errmsg, sizeof(errmsg));
+	    set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, event, 
+		      &reason);
 	}
 
@@ -1859,4 +1886,5 @@
 	pjsip_evsub_state old_state;
 	pj_str_t old_state_str;
+	pj_str_t reason = { NULL, 0 };
 	pj_status_t status;
 
@@ -1945,7 +1973,7 @@
 	    
 	    if (sub->expires->ivalue == 0) {
-		set_state(sub, sub->state, NULL, event);
+		set_state(sub, sub->state, NULL, event, &reason);
 	    } else  if (sub->state == PJSIP_EVSUB_STATE_NULL) {
-		set_state(sub, sub->state, NULL, event);
+		set_state(sub, sub->state, NULL, event, &reason);
 	    }
 
@@ -1981,5 +2009,6 @@
 	    if (status != PJ_SUCCESS) {
 		/* Can't authenticate. Terminate session (?) */
-		set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL);
+		set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL, 
+			  &tsx->status_text);
 		return;
 	    }
@@ -1994,5 +2023,6 @@
 	     tsx->status_code/100 == 7))
 	{
-	    set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, event);
+	    set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, event,
+		      &tsx->status_text);
 	    return;
 	}
Index: pjproject/trunk/pjsip/src/pjsip-simple/evsub_msg.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip-simple/evsub_msg.c	(revision 2148)
+++ pjproject/trunk/pjsip/src/pjsip-simple/evsub_msg.c	(revision 2149)
@@ -20,4 +20,5 @@
 #include <pjsip/print_util.h>
 #include <pjsip/sip_parser.h>
+#include <pjlib-util/string.h>
 #include <pj/pool.h>
 #include <pj/string.h>
@@ -167,6 +168,7 @@
     *p++ = ' ';
 
-    copy_advance(p, hdr->sub_state);
-    copy_advance_pair(p, ";reason=", 8, hdr->reason_param);
+    copy_advance_escape(p, hdr->sub_state, pc->pjsip_TOKEN_SPEC);
+    copy_advance_pair_escape(p, ";reason=", 8, hdr->reason_param,
+			     pc->pjsip_TOKEN_SPEC);
     if (hdr->expires_param >= 0) {
 	pj_memcpy(p, ";expires=", 9);
Index: pjproject/trunk/pjsip/src/pjsip-simple/presence.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip-simple/presence.c	(revision 2148)
+++ pjproject/trunk/pjsip/src/pjsip-simple/presence.c	(revision 2149)
@@ -462,6 +462,11 @@
     PJ_ASSERT_RETURN(pres != NULL, PJSIP_SIMPLE_ENOPRESENCE);
 
-    /* Must have at least one presence info. */
-    PJ_ASSERT_RETURN(pres->status.info_cnt > 0, PJSIP_SIMPLE_ENOPRESENCEINFO);
+    /* Must have at least one presence info, unless state is 
+     * PJSIP_EVSUB_STATE_TERMINATED. This could happen if subscription
+     * has not been active (e.g. we're waiting for user authorization)
+     * and remote cancels the subscription.
+     */
+    PJ_ASSERT_RETURN(state==PJSIP_EVSUB_STATE_TERMINATED ||
+		     pres->status.info_cnt > 0, PJSIP_SIMPLE_ENOPRESENCEINFO);
 
 
@@ -475,9 +480,12 @@
 
 
-    /* Create message body to reflect the presence status. */
-    status = pres_create_msg_body( pres, tdata );
-    if (status != PJ_SUCCESS)
-	goto on_return;
-
+    /* Create message body to reflect the presence status. 
+     * Only do this if we have presence status info to send (see above).
+     */
+    if (pres->status.info_cnt > 0) {
+	status = pres_create_msg_body( pres, tdata );
+	if (status != PJ_SUCCESS)
+	    goto on_return;
+    }
 
     /* Done. */
@@ -508,6 +516,9 @@
     PJ_ASSERT_RETURN(pres != NULL, PJSIP_SIMPLE_ENOPRESENCE);
 
-    /* Must have at least one presence info. */
-    PJ_ASSERT_RETURN(pres->status.info_cnt > 0, PJSIP_SIMPLE_ENOPRESENCEINFO);
+    /* We may not have a presence info yet, e.g. when we receive SUBSCRIBE
+     * to refresh subscription while we're waiting for user authorization.
+     */
+    //PJ_ASSERT_RETURN(pres->status.info_cnt > 0, 
+    //		       PJSIP_SIMPLE_ENOPRESENCEINFO);
 
 
@@ -522,8 +533,9 @@
 
     /* Create message body to reflect the presence status. */
-    status = pres_create_msg_body( pres, tdata );
-    if (status != PJ_SUCCESS)
-	goto on_return;
-
+    if (pres->status.info_cnt > 0) {
+	status = pres_create_msg_body( pres, tdata );
+	if (status != PJ_SUCCESS)
+	    goto on_return;
+    }
 
     /* Done. */
