Index: /pjproject/trunk/pjsip/include/pjsip-ua/sip_regc.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip-ua/sip_regc.h	(revision 200)
+++ /pjproject/trunk/pjsip/include/pjsip-ua/sip_regc.h	(revision 201)
@@ -60,4 +60,5 @@
     void		*token;
     int			 code;
+    pj_status_t		 status;
     pj_str_t		 reason;
     pjsip_rx_data	*rdata;
@@ -71,4 +72,22 @@
 typedef void pjsip_regc_cb(struct pjsip_regc_cbparam *param);
 
+/**
+ * Client registration information.
+ */
+struct pjsip_regc_info
+{
+    pj_str_t	server_uri; /**< Server URI,				    */
+    pj_str_t	client_uri; /**< Client URI (From header).		    */
+    pj_bool_t	is_busy;    /**< Have pending transaction?		    */
+    pj_bool_t	auto_reg;   /**< Will register automatically?		    */
+    int		interval;   /**< Registration interval (seconds).	    */
+    int		next_reg;   /**< Time until next registration (seconds).    */
+};
+
+/**
+ * @see pjsip_regc_info
+ */
+typedef struct pjsip_regc_info pjsip_regc_info;
+
 
 /**
@@ -105,4 +124,16 @@
  */
 PJ_DECL(pj_status_t) pjsip_regc_destroy(pjsip_regc *regc);
+
+/**
+ * Get registration info.
+ *
+ * @param regc	    The client registration structure.
+ * @param info	    Client registration info.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_regc_get_info( pjsip_regc *regc,
+					  pjsip_regc_info *info );
+
 
 /**
Index: /pjproject/trunk/pjsip/src/pjsip-simple/evsub.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip-simple/evsub.c	(revision 200)
+++ /pjproject/trunk/pjsip/src/pjsip-simple/evsub.c	(revision 201)
@@ -128,4 +128,6 @@
     TIMER_TYPE_UAC_WAIT_NOTIFY,
 
+    /* Max nb of timer types. */
+    TIMER_TYPE_MAX
 };
 
@@ -137,4 +139,5 @@
     "UAC_TERMINATE",
     "UAC_WAIT_NOTIFY",
+    "INVALID_TIMER"
 };
 
@@ -250,4 +253,8 @@
 {
     pj_status_t status;
+    pj_str_t method_tags[] = {
+	{ "SUBSCRIBE", 9},
+	{ "NOTIFY", 6}
+    };
 
     PJ_ASSERT_RETURN(endpt != NULL, PJ_EINVAL);
@@ -276,4 +283,9 @@
     pjsip_evsub_init_parser();
 
+    /* Register new methods SUBSCRIBE and NOTIFY in Allow-ed header */
+    pjsip_endpt_add_capability(endpt, &mod_evsub.mod, PJSIP_H_ALLOW, NULL,
+			       2, method_tags);
+
+    /* Done. */
     return PJ_SUCCESS;
 
@@ -437,4 +449,6 @@
 
 	PJ_ASSERT_ON_FAIL(seconds > 0, return);
+	PJ_ASSERT_ON_FAIL(timer_id>TIMER_TYPE_NONE && timer_id<TIMER_TYPE_MAX,
+			  return);
 
 	timeout.sec = seconds;
Index: /pjproject/trunk/pjsip/src/pjsip-simple/xpidf.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip-simple/xpidf.c	(revision 200)
+++ /pjproject/trunk/pjsip/src/pjsip-simple/xpidf.c	(revision 201)
@@ -30,4 +30,5 @@
 static pj_str_t ATOM = { "atom", 4 };
 static pj_str_t ATOMID = { "atomid", 6 };
+static pj_str_t ID = { "id", 2 };
 static pj_str_t ADDRESS = { "address", 7 };
 static pj_str_t SUBSCRIBE_PARAM = { ";method=SUBSCRIBE", 17 };
@@ -127,6 +128,4 @@
     if (pj_stricmp(&pres->name, &PRESENCE) != 0)
 	return NULL;
-    if (pj_xml_find_attr(pres, &URI, NULL) == NULL)
-	return NULL;
 
     /* Validate <presentity> */
@@ -134,4 +133,6 @@
     if (node == NULL)
 	return NULL;
+    if (pj_xml_find_attr(node, &URI, NULL) == NULL)
+	return NULL;
 
     /* Validate <atom> */
@@ -139,6 +140,9 @@
     if (node == NULL)
 	return NULL;
-    if (pj_xml_find_attr(node, &ATOMID, NULL) == NULL)
-	return NULL;
+    if (pj_xml_find_attr(node, &ATOMID, NULL) == NULL && 
+	pj_xml_find_attr(node, &ID, NULL) == NULL)
+    {
+	return NULL;
+    }
 
     /* Address */
@@ -247,5 +251,5 @@
 	return PJ_FALSE;
     }
-    status = pj_xml_find_node(atom, &STATUS);
+    status = pj_xml_find_node(addr, &STATUS);
     if (!status) {
 	pj_assert(0);
@@ -258,5 +262,5 @@
     }
 
-    return pj_stricmp(&attr->value, &OPEN) ? PJ_TRUE : PJ_FALSE;
+    return pj_stricmp(&attr->value, &OPEN)==0 ? PJ_TRUE : PJ_FALSE;
 }
 
Index: /pjproject/trunk/pjsip/src/pjsip-ua/sip_reg.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip-ua/sip_reg.c	(revision 200)
+++ /pjproject/trunk/pjsip/src/pjsip-ua/sip_reg.c	(revision 201)
@@ -26,9 +26,10 @@
 #include <pjsip/sip_auth_msg.h>
 #include <pjsip/sip_errno.h>
+#include <pj/assert.h>
+#include <pj/guid.h>
+#include <pj/os.h>
 #include <pj/pool.h>
+#include <pj/log.h>
 #include <pj/string.h>
-#include <pj/guid.h>
-#include <pj/log.h>
-#include <pj/assert.h>
 
 
@@ -54,4 +55,5 @@
     pjsip_cid_hdr		*cid_hdr;
     pjsip_cseq_hdr		*cseq_hdr;
+    pj_str_t			 from_uri;
     pjsip_from_hdr		*from_hdr;
     pjsip_to_hdr		*to_hdr;
@@ -69,4 +71,6 @@
     /* Auto refresh registration. */
     pj_bool_t			 auto_reg;
+    pj_time_val			 last_reg;
+    pj_time_val			 next_reg;
     pj_timer_entry		 timer;
 };
@@ -111,4 +115,6 @@
 PJ_DEF(pj_status_t) pjsip_regc_destroy(pjsip_regc *regc)
 {
+    PJ_ASSERT_RETURN(regc, PJ_EINVAL);
+
     if (regc->pending_tsx) {
 	regc->_delete_flag = 1;
@@ -116,4 +122,34 @@
     } else {
 	pjsip_endpt_release_pool(regc->endpt, regc->pool);
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pjsip_regc_get_info( pjsip_regc *regc,
+					 pjsip_regc_info *info )
+{
+    PJ_ASSERT_RETURN(regc && info, PJ_EINVAL);
+
+    info->server_uri = regc->str_srv_url;
+    info->client_uri = regc->from_uri;
+    info->is_busy = (regc->pending_tsx != 0);
+    info->auto_reg = regc->auto_reg;
+    info->interval = regc->expires;
+    
+    if (regc->pending_tsx)
+	info->next_reg = 0;
+    else if (regc->auto_reg == 0)
+	info->next_reg = 0;
+    else if (regc->expires < 0)
+	info->next_reg = regc->expires;
+    else {
+	pj_time_val now, next_reg;
+
+	next_reg = regc->next_reg;
+	pj_gettimeofday(&now);
+	PJ_TIME_VAL_SUB(next_reg, now);
+	info->next_reg = next_reg.sec;
     }
 
@@ -195,5 +231,6 @@
 
     /* Set "From" header. */
-    pj_strdup_with_null(regc->pool, &tmp, from_url);
+    pj_strdup_with_null(regc->pool, &regc->from_uri, from_url);
+    tmp = regc->from_uri;
     regc->from_hdr = pjsip_from_hdr_create(regc->pool);
     regc->from_hdr->uri = pjsip_parse_uri(regc->pool, tmp.ptr, tmp.slen, 
@@ -326,4 +363,6 @@
     pjsip_tx_data *tdata;
 
+    PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);
+
     status = create_request(regc, &tdata);
     if (status != PJ_SUCCESS)
@@ -356,4 +395,6 @@
     pj_status_t status;
 
+    PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);
+
     if (regc->timer.id != 0) {
 	pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
@@ -378,4 +419,5 @@
 						const pj_str_t contact[] )
 {
+    PJ_ASSERT_RETURN(regc, PJ_EINVAL);
     return set_contact( regc, contact_cnt, contact );
 }
@@ -385,4 +427,5 @@
 					        pj_uint32_t expires )
 {
+    PJ_ASSERT_RETURN(regc, PJ_EINVAL);
     set_expires( regc, expires );
     return PJ_SUCCESS;
@@ -390,5 +433,6 @@
 
 
-static void call_callback(pjsip_regc *regc, int status, const pj_str_t *reason,
+static void call_callback(pjsip_regc *regc, pj_status_t status, int st_code, 
+			  const pj_str_t *reason,
 			  pjsip_rx_data *rdata, pj_int32_t expiration,
 			  int contact_cnt, pjsip_contact_hdr *contact[])
@@ -399,5 +443,6 @@
     cbparam.regc = regc;
     cbparam.token = regc->token;
-    cbparam.code = status;
+    cbparam.status = status;
+    cbparam.code = st_code;
     cbparam.reason = *reason;
     cbparam.rdata = rdata;
@@ -428,5 +473,5 @@
 	char errmsg[PJ_ERR_MSG_SIZE];
 	pj_str_t reason = pj_strerror(status, errmsg, sizeof(errmsg));
-	call_callback(regc, -1, &reason, NULL, -1, 0, NULL);
+	call_callback(regc, status, 400, &reason, NULL, -1, 0, NULL);
     }
 }
@@ -438,9 +483,14 @@
     pjsip_transaction *tsx = event->body.tsx_state.tsx;
     
+    /* Decrement pending transaction counter. */
+    --regc->pending_tsx;
+
     /* If registration data has been deleted by user then remove registration 
      * data from transaction's callback, and don't call callback.
      */
     if (regc->_delete_flag) {
-	--regc->pending_tsx;
+
+	/* Nothing to do */
+	;
 
     } else if (tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED ||
@@ -456,11 +506,10 @@
 
 	if (status == PJ_SUCCESS) {
-	    --regc->pending_tsx;
 	    pjsip_regc_send(regc, tdata);
 	    return;
 	} else {
-	    call_callback(regc, tsx->status_code, &rdata->msg_info.msg->line.status.reason,
+	    call_callback(regc, status, tsx->status_code, 
+			  &rdata->msg_info.msg->line.status.reason,
 			  rdata, -1, 0, NULL);
-	    --regc->pending_tsx;
 	}
     } else {
@@ -513,4 +562,7 @@
 		regc->timer.user_data = regc;
 		pjsip_endpt_schedule_timer( regc->endpt, &regc->timer, &delay);
+		pj_gettimeofday(&regc->last_reg);
+		regc->next_reg = regc->last_reg;
+		regc->next_reg.sec += delay.sec;
 	    }
 
@@ -523,5 +575,5 @@
 	/* Call callback. */
 	if (expiration == 0xFFFF) expiration = -1;
-	call_callback(regc, tsx->status_code, 
+	call_callback(regc, PJ_SUCCESS, tsx->status_code, 
 		      (rdata ? &rdata->msg_info.msg->line.status.reason 
 			: pjsip_get_status_text(tsx->status_code)),
@@ -529,5 +581,4 @@
 		      contact_cnt, contact);
 
-	--regc->pending_tsx;
     }
 
@@ -544,8 +595,6 @@
     /* Make sure we don't have pending transaction. */
     if (regc->pending_tsx) {
-	pj_str_t reason = pj_str("Transaction in progress");
-	call_callback(regc, -1, &reason, NULL, -1, 0, NULL);
 	pjsip_tx_data_dec_ref( tdata );
-	return PJ_EINVALIDOP;
+	return PJSIP_EBUSY;
     }
 
@@ -560,9 +609,4 @@
     if (status==PJ_SUCCESS)
 	++regc->pending_tsx;
-    else {
-	char errmsg[PJ_ERR_MSG_SIZE];
-	pj_str_t reason = pj_strerror(status, errmsg, sizeof(errmsg));
-	call_callback(regc, status, &reason, NULL, -1, 0, NULL);
-    }
 
     return status;
Index: /pjproject/trunk/pjsip/src/pjsua/main.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua/main.c	(revision 200)
+++ /pjproject/trunk/pjsip/src/pjsua/main.c	(revision 201)
@@ -99,6 +99,29 @@
 static void keystroke_help(void)
 {
-
-    printf(">>>>\nOnline status: %s\n", 
+    char reg_status[128];
+
+    if (pjsua.regc == NULL) {
+	pj_ansi_strcpy(reg_status, " -not registered to server-");
+    } else if (pjsua.regc_last_err != PJ_SUCCESS) {
+	pj_strerror(pjsua.regc_last_err, reg_status, sizeof(reg_status));
+    } else if (pjsua.regc_last_code>=200 && pjsua.regc_last_code<=699) {
+
+	pjsip_regc_info info;
+
+	pjsip_regc_get_info(pjsua.regc, &info);
+
+	pj_snprintf(reg_status, sizeof(reg_status),
+		    "%s (%.*s;expires=%d)",
+		    pjsip_get_status_text(pjsua.regc_last_code)->ptr,
+		    (int)info.server_uri.slen,
+		    info.server_uri.ptr,
+		    info.next_reg);
+
+    } else {
+	pj_sprintf(reg_status, "in progress (%d)", pjsua.regc_last_code);
+    }
+
+    printf(">>>>\nRegistration status: %s\n", reg_status);
+    printf("Online status: %s\n", 
 	   (pjsua.online_status ? "Online" : "Invisible"));
     print_buddy_list();
@@ -109,7 +132,7 @@
     puts("|                              |                          |                   |");
     puts("|  m  Make new call            |  i  Send IM              |  o  Send OPTIONS  |");
-    puts("|  a  Answer call              |  s  Subscribe presence   |  d  Dump status   |");
-    puts("|  h  Hangup call              |  u  Unsubscribe presence |  d1 Dump detailed |");
-    puts("|  ]  Select next dialog       |  t  Toggle Online status |                   |");
+    puts("|  a  Answer call              |  s  Subscribe presence   |  R  (Re-)register |");
+    puts("|  h  Hangup call              |  u  Unsubscribe presence |  r  Unregister    |");
+    puts("|  ]  Select next dialog       |  t  Toggle Online status |  d  Dump status   |");
     puts("|  [  Select previous dialog   |                          |                   |");
     puts("+-----------------------------------------------------------------------------+");
@@ -224,5 +247,5 @@
 
 	if ((status=pjsua_verify_sip_url(buf)) != PJ_SUCCESS) {
-	    pjsua_perror("Invalid URL", status);
+	    pjsua_perror(THIS_FILE, "Invalid URL", status);
 	    return;
 	}
@@ -291,5 +314,6 @@
 
 		if (status != PJ_SUCCESS)
-		    pjsua_perror("Unable to create/send response", status);
+		    pjsua_perror(THIS_FILE, "Unable to create/send response", 
+				 status);
 	    }
 
@@ -311,5 +335,7 @@
 					       PJSIP_SC_DECLINE, NULL, &tdata);
 		if (status != PJ_SUCCESS) {
-		    pjsua_perror("Failed to create end session message", status);
+		    pjsua_perror(THIS_FILE, 
+				 "Failed to create end session message", 
+				 status);
 		    continue;
 		}
@@ -317,5 +343,7 @@
 		status = pjsip_inv_send_msg(inv_session->inv, tdata, NULL);
 		if (status != PJ_SUCCESS) {
-		    pjsua_perror("Failed to send end session message", status);
+		    pjsua_perror(THIS_FILE, 
+				 "Failed to send end session message", 
+				 status);
 		    continue;
 		}
@@ -353,4 +381,12 @@
 	    }
 
+	    break;
+
+	case 'R':
+	    pjsua_regc_update(PJ_TRUE);
+	    break;
+	    
+	case 'r':
+	    pjsua_regc_update(PJ_FALSE);
 	    break;
 
@@ -501,5 +537,6 @@
  * Display error message for the specified error code.
  */
-void pjsua_perror(const char *title, pj_status_t status)
+void pjsua_perror(const char *sender, const char *title, 
+		  pj_status_t status)
 {
     char errmsg[PJ_ERR_MSG_SIZE];
@@ -507,5 +544,5 @@
     pj_strerror(status, errmsg, sizeof(errmsg));
 
-    PJ_LOG(1,(THIS_FILE, "%s: %s [code=%d]", title, errmsg, status));
+    PJ_LOG(1,(sender, "%s: %s [code=%d]", title, errmsg, status));
 }
 
Index: /pjproject/trunk/pjsip/src/pjsua/pjsua.h
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua/pjsua.h	(revision 200)
+++ /pjproject/trunk/pjsip/src/pjsua/pjsua.h	(revision 201)
@@ -128,4 +128,5 @@
     pj_int32_t	     reg_timeout;
     pj_timer_entry   regc_timer;
+    pj_status_t	     regc_last_err; /**< Last registration error.	*/
     int		     regc_last_code;/**< Last status last register.	*/
 
@@ -200,5 +201,6 @@
  * Display error message for the specified error code.
  */
-void pjsua_perror(const char *title, pj_status_t status);
+void pjsua_perror(const char *sender, const char *title, 
+		  pj_status_t status);
 
 
Index: /pjproject/trunk/pjsip/src/pjsua/pjsua_core.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua/pjsua_core.c	(revision 200)
+++ /pjproject/trunk/pjsip/src/pjsua/pjsua_core.c	(revision 201)
@@ -73,4 +73,8 @@
     pjsua.local_uri = pj_str(PJSUA_LOCAL_URI);
 
+    /* Default registration timeout: */
+
+    pjsua.reg_timeout = 55;
+
     /* Init route set list: */
 
@@ -156,5 +160,5 @@
     status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[SIP_SOCK]);
     if (status != PJ_SUCCESS) {
-	pjsua_perror("socket() error", status);
+	pjsua_perror(THIS_FILE, "socket() error", status);
 	goto on_error;
     }
@@ -162,5 +166,5 @@
     status = pj_sock_bind_in(sock[SIP_SOCK], 0, pjsua.sip_port);
     if (status != PJ_SUCCESS) {
-	pjsua_perror("bind() error", status);
+	pjsua_perror(THIS_FILE, "bind() error", status);
 	goto on_error;
     }
@@ -175,5 +179,5 @@
 	status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[RTP_SOCK]);
 	if (status != PJ_SUCCESS) {
-	    pjsua_perror("socket() error", status);
+	    pjsua_perror(THIS_FILE, "socket() error", status);
 	    goto on_error;
 	}
@@ -189,5 +193,5 @@
 	status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[RTCP_SOCK]);
 	if (status != PJ_SUCCESS) {
-	    pjsua_perror("socket() error", status);
+	    pjsua_perror(THIS_FILE, "socket() error", status);
 	    goto on_error;
 	}
@@ -218,5 +222,6 @@
 	    status = pj_sockaddr_in_set_str_addr( &addr, hostname);
 	    if (status != PJ_SUCCESS) {
-		pjsua_perror("Unresolvable local hostname", status);
+		pjsua_perror(THIS_FILE, "Unresolvable local hostname", 
+			     status);
 		goto on_error;
 	    }
@@ -235,5 +240,5 @@
 					      mapped_addr);
 	    if (status != PJ_SUCCESS) {
-		pjsua_perror("STUN error", status);
+		pjsua_perror(THIS_FILE, "STUN error", status);
 		goto on_error;
 	    }
@@ -311,5 +316,5 @@
 				    &pjsua.endpt);
 	if (status != PJ_SUCCESS) {
-	    pjsua_perror("Unable to create SIP endpoint", status);
+	    pjsua_perror(THIS_FILE, "Unable to create SIP endpoint", status);
 	    return status;
 	}
@@ -321,5 +326,6 @@
     status = pjsip_tsx_layer_init(pjsua.endpt);
     if (status != PJ_SUCCESS) {
-	pjsua_perror("Transaction layer initialization error", status);
+	pjsua_perror(THIS_FILE, "Transaction layer initialization error", 
+		     status);
 	goto on_error;
     }
@@ -329,5 +335,5 @@
     status = pjsip_ua_init( pjsua.endpt, NULL );
     if (status != PJ_SUCCESS) {
-	pjsua_perror("UA layer initialization error", status);
+	pjsua_perror(THIS_FILE, "UA layer initialization error", status);
 	goto on_error;
     }
@@ -358,5 +364,6 @@
 	status = pjsip_endpt_register_module(pjsua.endpt, &pjsua.mod);
 	if (status != PJ_SUCCESS) {
-	    pjsua_perror("Unable to register pjsua module", status);
+	    pjsua_perror(THIS_FILE, "Unable to register pjsua module", 
+			 status);
 	    goto on_error;
 	}
@@ -378,5 +385,6 @@
 	status = pjsip_inv_usage_init(pjsua.endpt, &pjsua.mod, &inv_cb);
 	if (status != PJ_SUCCESS) {
-	    pjsua_perror("Invite usage initialization error", status);
+	    pjsua_perror(THIS_FILE, "Invite usage initialization error", 
+			 status);
 	    goto on_error;
 	}
@@ -428,5 +436,5 @@
     status = pj_init();
     if (status != PJ_SUCCESS) {
-	pjsua_perror("pj_init() error", status);
+	pjsua_perror(THIS_FILE, "pj_init() error", status);
 	return status;
     }
@@ -446,5 +454,6 @@
     if (status != PJ_SUCCESS) {
 	pj_caching_pool_destroy(&pjsua.cp);
-	pjsua_perror("Stack initialization has returned error", status);
+	pjsua_perror(THIS_FILE, "Stack initialization has returned error", 
+		     status);
 	return status;
     }
@@ -470,5 +479,7 @@
     if (status != PJ_SUCCESS) {
 	pj_caching_pool_destroy(&pjsua.cp);
-	pjsua_perror("Media stack initialization has returned error", status);
+	pjsua_perror(THIS_FILE, 
+		     "Media stack initialization has returned error", 
+		     status);
 	return status;
     }
@@ -479,5 +490,7 @@
     if (status != PJ_SUCCESS) {
 	pj_caching_pool_destroy(&pjsua.cp);
-	pjsua_perror("Media codec initialization has returned error", status);
+	pjsua_perror(THIS_FILE, 
+		     "Media codec initialization has returned error", 
+		     status);
 	return status;
     }
@@ -504,5 +517,6 @@
     status = init_sockets();
     if (status != PJ_SUCCESS) {
-	pjsua_perror("init_sockets() has returned error", status);
+	pjsua_perror(THIS_FILE, "init_sockets() has returned error", 
+		     status);
 	return status;
     }
@@ -528,5 +542,6 @@
 					     &udp_transport);
 	if (status != PJ_SUCCESS) {
-	    pjsua_perror("Unable to start UDP transport", status);
+	    pjsua_perror(THIS_FILE, "Unable to start UDP transport", 
+			 status);
 	    return status;
 	}
@@ -553,5 +568,6 @@
 			      pjsua.local_uri.slen, 0);
 	if (uri == NULL) {
-	    pjsua_perror("Invalid local URI", PJSIP_EINVALIDURI);
+	    pjsua_perror(THIS_FILE, "Invalid local URI", 
+			 PJSIP_EINVALIDURI);
 	    return PJSIP_EINVALIDURI;
 	}
@@ -561,5 +577,6 @@
 
 	if (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri)) {
-	    pjsua_perror("Invalid local URI", PJSIP_EINVALIDSCHEME);
+	    pjsua_perror(THIS_FILE, "Invalid local URI", 
+			 PJSIP_EINVALIDSCHEME);
 	    return PJSIP_EINVALIDSCHEME;
 	}
@@ -595,5 +612,5 @@
 
 	if (len < 1 || len >= sizeof(contact)) {
-	    pjsua_perror("Invalid Contact", PJSIP_EURITOOLONG);
+	    pjsua_perror(THIS_FILE, "Invalid Contact", PJSIP_EURITOOLONG);
 	    return PJSIP_EURITOOLONG;
 	}
@@ -618,5 +635,6 @@
 				   &parsed_len);
 	if (route == NULL) {
-	    pjsua_perror("Invalid outbound proxy URL", PJSIP_EINVALIDURI);
+	    pjsua_perror(THIS_FILE, "Invalid outbound proxy URL", 
+			 PJSIP_EINVALIDURI);
 	    return PJSIP_EINVALIDURI;
 	}
Index: /pjproject/trunk/pjsip/src/pjsua/pjsua_inv.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua/pjsua_inv.c	(revision 200)
+++ /pjproject/trunk/pjsip/src/pjsua/pjsua_inv.c	(revision 201)
@@ -54,5 +54,5 @@
 				   &dlg);
     if (status != PJ_SUCCESS) {
-	pjsua_perror("Dialog creation failed", status);
+	pjsua_perror(THIS_FILE, "Dialog creation failed", status);
 	return status;
     }
@@ -63,5 +63,5 @@
 				       1, &pjsua.med_skinfo, &offer);
     if (status != PJ_SUCCESS) {
-	pjsua_perror("pjmedia unable to create SDP", status);
+	pjsua_perror(THIS_FILE, "pjmedia unable to create SDP", status);
 	goto on_error;
     }
@@ -71,5 +71,5 @@
     status = pjsip_inv_create_uac( dlg, offer, 0, &inv);
     if (status != PJ_SUCCESS) {
-	pjsua_perror("Invite session creation failed", status);
+	pjsua_perror(THIS_FILE, "Invite session creation failed", status);
 	goto on_error;
     }
@@ -100,5 +100,6 @@
     status = pjsip_inv_invite(inv, &tdata);
     if (status != PJ_SUCCESS) {
-	pjsua_perror("Unable to create initial INVITE request", status);
+	pjsua_perror(THIS_FILE, "Unable to create initial INVITE request", 
+		     status);
 	goto on_error;
     }
@@ -109,5 +110,6 @@
     status = pjsip_inv_send_msg(inv, tdata, NULL);
     if (status != PJ_SUCCESS) {
-	pjsua_perror("Unable to send initial INVITE request", status);
+	pjsua_perror(THIS_FILE, "Unable to send initial INVITE request", 
+		     status);
 	goto on_error;
     }
@@ -302,5 +304,5 @@
     if (status != PJ_SUCCESS) {
 
-	pjsua_perror("SDP negotiation has failed", status);
+	pjsua_perror(THIS_FILE, "SDP negotiation has failed", status);
 	return;
 
@@ -319,5 +321,7 @@
     status = pjmedia_sdp_neg_get_active_local(inv->neg, &local_sdp);
     if (status != PJ_SUCCESS) {
-	pjsua_perror("Unable to retrieve currently active local SDP", status);
+	pjsua_perror(THIS_FILE, 
+		     "Unable to retrieve currently active local SDP", 
+		     status);
 	return;
     }
@@ -326,5 +330,7 @@
     status = pjmedia_sdp_neg_get_active_remote(inv->neg, &remote_sdp);
     if (status != PJ_SUCCESS) {
-	pjsua_perror("Unable to retrieve currently active remote SDP", status);
+	pjsua_perror(THIS_FILE, 
+		     "Unable to retrieve currently active remote SDP", 
+		     status);
 	return;
     }
@@ -341,5 +347,6 @@
 					 &inv_data->session );
 	if (status != PJ_SUCCESS) {
-	    pjsua_perror("Unable to create media session", status);
+	    pjsua_perror(THIS_FILE, "Unable to create media session", 
+			 status);
 	    return;
 	}
Index: /pjproject/trunk/pjsip/src/pjsua/pjsua_pres.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua/pjsua_pres.c	(revision 200)
+++ /pjproject/trunk/pjsip/src/pjsua/pjsua_pres.c	(revision 201)
@@ -99,5 +99,7 @@
 				   &pjsua.contact_uri, &dlg);
     if (status != PJ_SUCCESS) {
-	pjsua_perror("Unable to create UAS dialog for subscription", status);
+	pjsua_perror(THIS_FILE, 
+		     "Unable to create UAS dialog for subscription", 
+		     status);
 	return PJ_FALSE;
     }
@@ -111,5 +113,6 @@
     if (status != PJ_SUCCESS) {
 	PJ_TODO(DESTROY_DIALOG);
-	pjsua_perror("Unable to create server subscription", status);
+	pjsua_perror(THIS_FILE, "Unable to create server subscription", 
+		     status);
 	return PJ_FALSE;
     }
@@ -135,5 +138,6 @@
     status = pjsip_pres_accept(sub, rdata, 200, NULL);
     if (status != PJ_SUCCESS) {
-	pjsua_perror("Unable to accept presence subscription", status);
+	pjsua_perror(THIS_FILE, "Unable to accept presence subscription", 
+		     status);
 	pj_list_erase(uapres);
 	return PJ_FALSE;
@@ -158,5 +162,6 @@
 
     if (status != PJ_SUCCESS) {
-	pjsua_perror("Unable to create/send NOTIFY", status);
+	pjsua_perror(THIS_FILE, "Unable to create/send NOTIFY", 
+		     status);
 	pj_list_erase(uapres);
 	return PJ_FALSE;
@@ -305,5 +310,6 @@
 				   NULL, &dlg);
     if (status != PJ_SUCCESS) {
-	pjsua_perror("Unable to create dialog", status);
+	pjsua_perror(THIS_FILE, "Unable to create dialog", 
+		     status);
 	return;
     }
@@ -313,5 +319,6 @@
     if (status != PJ_SUCCESS) {
 	pjsua.buddies[index].sub = NULL;
-	pjsua_perror("Unable to create presence client", status);
+	pjsua_perror(THIS_FILE, "Unable to create presence client", 
+		     status);
 	return;
     }
@@ -323,5 +330,6 @@
     if (status != PJ_SUCCESS) {
 	pjsua.buddies[index].sub = NULL;
-	pjsua_perror("Unable to create initial SUBSCRIBE", status);
+	pjsua_perror(THIS_FILE, "Unable to create initial SUBSCRIBE", 
+		     status);
 	return;
     }
@@ -330,5 +338,6 @@
     if (status != PJ_SUCCESS) {
 	pjsua.buddies[index].sub = NULL;
-	pjsua_perror("Unable to send initial SUBSCRIBE", status);
+	pjsua_perror(THIS_FILE, "Unable to send initial SUBSCRIBE", 
+		     status);
 	return;
     }
@@ -365,5 +374,6 @@
 
     } else {
-	pjsua_perror("Unable to unsubscribe presence", status);
+	pjsua_perror(THIS_FILE, "Unable to unsubscribe presence", 
+		     status);
     }
 }
@@ -397,5 +407,6 @@
     status = pjsip_endpt_register_module( pjsua.endpt, &mod_pjsua_pres);
     if (status != PJ_SUCCESS) {
-	pjsua_perror("Unable to register pjsua presence module", status);
+	pjsua_perror(THIS_FILE, "Unable to register pjsua presence module", 
+		     status);
     }
 
Index: /pjproject/trunk/pjsip/src/pjsua/pjsua_reg.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua/pjsua_reg.c	(revision 200)
+++ /pjproject/trunk/pjsip/src/pjsua/pjsua_reg.c	(revision 201)
@@ -38,7 +38,13 @@
      * Print registration status.
      */
-    if (param->code < 0 || param->code >= 300) {
+    if (param->status!=PJ_SUCCESS) {
+	pjsua_perror(THIS_FILE, "SIP registration error", 
+		     param->status);
+	pjsua.regc = NULL;
+	
+    } else if (param->code < 0 || param->code >= 300) {
 	PJ_LOG(2, (THIS_FILE, "SIP registration failed, status=%d (%s)", 
-		   param->code, pjsip_get_status_text(param->code)->ptr));
+		   param->code, 
+		   pjsip_get_status_text(param->code)->ptr));
 	pjsua.regc = NULL;
 
@@ -54,4 +60,5 @@
     }
 
+    pjsua.regc_last_err = param->status;
     pjsua.regc_last_code = param->code;
 
@@ -69,17 +76,31 @@
 
     if (renew) {
-	PJ_LOG(3,(THIS_FILE, "Performing SIP registration..."));
+	if (pjsua.regc == NULL) {
+	    status = pjsua_regc_init();
+	    if (status != PJ_SUCCESS) {
+		pjsua_perror(THIS_FILE, "Unable to create registration", 
+			     status);
+		return;
+	    }
+	}
 	status = pjsip_regc_register(pjsua.regc, 1, &tdata);
     } else {
-	PJ_LOG(3,(THIS_FILE, "Performing SIP unregistration..."));
+	if (pjsua.regc == NULL) {
+	    PJ_LOG(3,(THIS_FILE, "Currently not registered"));
+	    return;
+	}
 	status = pjsip_regc_unregister(pjsua.regc, &tdata);
     }
 
+    if (status == PJ_SUCCESS)
+	status = pjsip_regc_send( pjsua.regc, tdata );
+
     if (status != PJ_SUCCESS) {
-	pjsua_perror("Unable to create REGISTER request", status);
-	return;
+	pjsua_perror(THIS_FILE, "Unable to create/send REGISTER", 
+		     status);
+    } else {
+	PJ_LOG(3,(THIS_FILE, "%s sent",
+	         (renew? "Registration" : "Unregistration")));
     }
-
-    pjsip_regc_send( pjsua.regc, tdata );
 }
 
@@ -97,5 +118,6 @@
 
 	if (status != PJ_SUCCESS) {
-	    pjsua_perror("Unable to create client registration", status);
+	    pjsua_perror(THIS_FILE, "Unable to create client registration", 
+			 status);
 	    return status;
 	}
@@ -108,5 +130,7 @@
 				  pjsua.reg_timeout);
 	if (status != PJ_SUCCESS) {
-	    pjsua_perror("Client registration initialization error", status);
+	    pjsua_perror(THIS_FILE, 
+			 "Client registration initialization error", 
+			 status);
 	    return status;
 	}
