SIMPLE test with FWD, and added more info in UI

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@201 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjsip/src/pjsip-simple/evsub.c b/pjsip/src/pjsip-simple/evsub.c
index c1b8db8..be27db3 100644
--- a/pjsip/src/pjsip-simple/evsub.c
+++ b/pjsip/src/pjsip-simple/evsub.c
@@ -127,6 +127,8 @@
      */
     TIMER_TYPE_UAC_WAIT_NOTIFY,
 
+    /* Max nb of timer types. */
+    TIMER_TYPE_MAX
 };
 
 static const char *timer_names[] = 
@@ -136,6 +138,7 @@
     "UAS_TIMEOUT"
     "UAC_TERMINATE",
     "UAC_WAIT_NOTIFY",
+    "INVALID_TIMER"
 };
 
 /*
@@ -249,6 +252,10 @@
 PJ_DEF(pj_status_t) pjsip_evsub_init_module(pjsip_endpoint *endpt)
 {
     pj_status_t status;
+    pj_str_t method_tags[] = {
+	{ "SUBSCRIBE", 9},
+	{ "NOTIFY", 6}
+    };
 
     PJ_ASSERT_RETURN(endpt != NULL, PJ_EINVAL);
     PJ_ASSERT_RETURN(mod_evsub.mod.id == -1, PJ_EINVALIDOP);
@@ -275,6 +282,11 @@
     /* Register SIP-event specific headers parser: */
     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;
 
 on_error:
@@ -436,6 +448,8 @@
 	pj_time_val timeout;
 
 	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;
 	timeout.msec = 0;
diff --git a/pjsip/src/pjsip-simple/xpidf.c b/pjsip/src/pjsip-simple/xpidf.c
index 1202482..1bd719c 100644
--- a/pjsip/src/pjsip-simple/xpidf.c
+++ b/pjsip/src/pjsip-simple/xpidf.c
@@ -29,6 +29,7 @@
 static pj_str_t URI = { "uri", 3 };
 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 };
 static pj_str_t PRESENTITY = { "presentity", 10 };
@@ -126,20 +127,23 @@
     /* Validate <presence> */
     if (pj_stricmp(&pres->name, &PRESENCE) != 0)
 	return NULL;
-    if (pj_xml_find_attr(pres, &URI, NULL) == NULL)
-	return NULL;
 
     /* Validate <presentity> */
     node = pj_xml_find_node(pres, &PRESENTITY);
     if (node == NULL)
 	return NULL;
+    if (pj_xml_find_attr(node, &URI, NULL) == NULL)
+	return NULL;
 
     /* Validate <atom> */
     node = pj_xml_find_node(pres, &ATOM);
     if (node == NULL)
 	return NULL;
-    if (pj_xml_find_attr(node, &ATOMID, NULL) == NULL)
+    if (pj_xml_find_attr(node, &ATOMID, NULL) == NULL && 
+	pj_xml_find_attr(node, &ID, NULL) == NULL)
+    {
 	return NULL;
+    }
 
     /* Address */
     node = pj_xml_find_node(node, &ADDRESS);
@@ -246,7 +250,7 @@
 	pj_assert(0);
 	return PJ_FALSE;
     }
-    status = pj_xml_find_node(atom, &STATUS);
+    status = pj_xml_find_node(addr, &STATUS);
     if (!status) {
 	pj_assert(0);
 	return PJ_FALSE;
@@ -257,7 +261,7 @@
 	return PJ_FALSE;
     }
 
-    return pj_stricmp(&attr->value, &OPEN) ? PJ_TRUE : PJ_FALSE;
+    return pj_stricmp(&attr->value, &OPEN)==0 ? PJ_TRUE : PJ_FALSE;
 }
 
 
diff --git a/pjsip/src/pjsip-ua/sip_reg.c b/pjsip/src/pjsip-ua/sip_reg.c
index c94aff2..6a614bc 100644
--- a/pjsip/src/pjsip-ua/sip_reg.c
+++ b/pjsip/src/pjsip-ua/sip_reg.c
@@ -25,11 +25,12 @@
 #include <pjsip/sip_util.h>
 #include <pjsip/sip_auth_msg.h>
 #include <pjsip/sip_errno.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <pj/guid.h>
-#include <pj/log.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>
 
 
 #define REFRESH_TIMER		1
@@ -53,6 +54,7 @@
     pjsip_uri			*srv_url;
     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;
     char			*contact_buf;
@@ -68,6 +70,8 @@
 
     /* Auto refresh registration. */
     pj_bool_t			 auto_reg;
+    pj_time_val			 last_reg;
+    pj_time_val			 next_reg;
     pj_timer_entry		 timer;
 };
 
@@ -110,6 +114,8 @@
 
 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;
 	regc->cb = NULL;
@@ -121,6 +127,36 @@
 }
 
 
+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;
+    }
+
+    return PJ_SUCCESS;
+}
+
+
 PJ_DEF(pj_pool_t*) pjsip_regc_get_pool(pjsip_regc *regc)
 {
     return regc->pool;
@@ -194,7 +230,8 @@
     }
 
     /* 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, 
 					  PJSIP_PARSE_URI_AS_NAMEADDR);
@@ -325,6 +362,8 @@
     pj_status_t status;
     pjsip_tx_data *tdata;
 
+    PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);
+
     status = create_request(regc, &tdata);
     if (status != PJ_SUCCESS)
 	return status;
@@ -355,6 +394,8 @@
     pjsip_msg *msg;
     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);
 	regc->timer.id = 0;
@@ -377,6 +418,7 @@
 					        int contact_cnt,
 						const pj_str_t contact[] )
 {
+    PJ_ASSERT_RETURN(regc, PJ_EINVAL);
     return set_contact( regc, contact_cnt, contact );
 }
 
@@ -384,12 +426,14 @@
 PJ_DEF(pj_status_t) pjsip_regc_update_expires(  pjsip_regc *regc,
 					        pj_uint32_t expires )
 {
+    PJ_ASSERT_RETURN(regc, PJ_EINVAL);
     set_expires( regc, expires );
     return PJ_SUCCESS;
 }
 
 
-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[])
 {
@@ -398,7 +442,8 @@
 
     cbparam.regc = regc;
     cbparam.token = regc->token;
-    cbparam.code = status;
+    cbparam.status = status;
+    cbparam.code = st_code;
     cbparam.reason = *reason;
     cbparam.rdata = rdata;
     cbparam.contact_cnt = contact_cnt;
@@ -427,7 +472,7 @@
     } else {
 	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);
     }
 }
 
@@ -437,11 +482,16 @@
     pjsip_regc *regc = token;
     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 ||
 	       tsx->status_code == PJSIP_SC_UNAUTHORIZED)
@@ -455,13 +505,12 @@
 					    &tdata);
 
 	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 {
 	int contact_cnt = 0;
@@ -512,6 +561,9 @@
 		regc->timer.id = REFRESH_TIMER;
 		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;
 	    }
 
 	} else {
@@ -522,13 +574,12 @@
 
 	/* 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)),
 		      rdata, expiration, 
 		      contact_cnt, contact);
 
-	--regc->pending_tsx;
     }
 
     /* Delete the record if user destroy regc during the callback. */
@@ -543,10 +594,8 @@
 
     /* 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;
     }
 
     /* Invalidate message buffer. */
@@ -559,11 +608,6 @@
     status = pjsip_endpt_send_request(regc->endpt, tdata, -1, regc, &tsx_callback);
     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;
 }
diff --git a/pjsip/src/pjsua/main.c b/pjsip/src/pjsua/main.c
index 4a40d32..66d4de4 100644
--- a/pjsip/src/pjsua/main.c
+++ b/pjsip/src/pjsua/main.c
@@ -98,8 +98,31 @@
  */
 static void keystroke_help(void)
 {
+    char reg_status[128];
 
-    printf(">>>>\nOnline status: %s\n", 
+    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();
     
@@ -108,9 +131,9 @@
     puts("|       Call Commands:         |      IM & Presence:      |   Misc:           |");
     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("+-----------------------------------------------------------------------------+");
     puts("|  q  QUIT                                                                    |");
@@ -223,7 +246,7 @@
 	pj_status_t status;
 
 	if ((status=pjsua_verify_sip_url(buf)) != PJ_SUCCESS) {
-	    pjsua_perror("Invalid URL", status);
+	    pjsua_perror(THIS_FILE, "Invalid URL", status);
 	    return;
 	}
 
@@ -290,7 +313,8 @@
 		    status = pjsip_inv_send_msg(inv_session->inv, tdata, NULL);
 
 		if (status != PJ_SUCCESS)
-		    pjsua_perror("Unable to create/send response", status);
+		    pjsua_perror(THIS_FILE, "Unable to create/send response", 
+				 status);
 	    }
 
 	    break;
@@ -310,13 +334,17 @@
 		status = pjsip_inv_end_session(inv_session->inv, 
 					       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;
 		}
 
 		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;
 		}
 	    }
@@ -354,6 +382,14 @@
 
 	    break;
 
+	case 'R':
+	    pjsua_regc_update(PJ_TRUE);
+	    break;
+	    
+	case 'r':
+	    pjsua_regc_update(PJ_FALSE);
+	    break;
+
 	case 't':
 	    pjsua.online_status = !pjsua.online_status;
 	    pjsua_pres_refresh();
@@ -500,13 +536,14 @@
 /*
  * 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];
 
     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));
 }
 
 
diff --git a/pjsip/src/pjsua/pjsua.h b/pjsip/src/pjsua/pjsua.h
index 202c284..6bd19d5 100644
--- a/pjsip/src/pjsua/pjsua.h
+++ b/pjsip/src/pjsua/pjsua.h
@@ -127,6 +127,7 @@
     pjsip_regc	    *regc;
     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.	*/
 
 
@@ -199,7 +200,8 @@
 /**
  * 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);
 
 
 /**
diff --git a/pjsip/src/pjsua/pjsua_core.c b/pjsip/src/pjsua/pjsua_core.c
index 2d059d9..7556020 100644
--- a/pjsip/src/pjsua/pjsua_core.c
+++ b/pjsip/src/pjsua/pjsua_core.c
@@ -72,6 +72,10 @@
 
     pjsua.local_uri = pj_str(PJSUA_LOCAL_URI);
 
+    /* Default registration timeout: */
+
+    pjsua.reg_timeout = 55;
+
     /* Init route set list: */
 
     pj_list_init(&pjsua.route_set);
@@ -155,13 +159,13 @@
     /* Create and bind SIP UDP socket. */
     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;
     }
     
     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;
     }
 
@@ -174,7 +178,7 @@
 	/* Create and bind RTP socket. */
 	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;
 	}
 
@@ -188,7 +192,7 @@
 	/* Create and bind RTCP socket. */
 	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;
 	}
 
@@ -217,7 +221,8 @@
 	    addr.sin_family = PJ_AF_INET;
 	    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;
 	    }
 
@@ -234,7 +239,7 @@
 					      &pjsua.stun_srv2, pjsua.stun_port2,
 					      mapped_addr);
 	    if (status != PJ_SUCCESS) {
-		pjsua_perror("STUN error", status);
+		pjsua_perror(THIS_FILE, "STUN error", status);
 		goto on_error;
 	    }
 
@@ -310,7 +315,7 @@
 	status = pjsip_endpt_create(&pjsua.cp.factory, endpt_name, 
 				    &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;
 	}
     }
@@ -320,7 +325,8 @@
 
     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;
     }
 
@@ -328,7 +334,7 @@
 
     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;
     }
 
@@ -357,7 +363,8 @@
 
 	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;
 	}
     }
@@ -377,7 +384,8 @@
 	/* Initialize invite session module: */
 	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;
 	}
 
@@ -427,7 +435,7 @@
 
     status = pj_init();
     if (status != PJ_SUCCESS) {
-	pjsua_perror("pj_init() error", status);
+	pjsua_perror(THIS_FILE, "pj_init() error", status);
 	return status;
     }
 
@@ -445,7 +453,8 @@
     status = init_stack();
     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;
     }
 
@@ -469,7 +478,9 @@
     status = pjmedia_endpt_create(&pjsua.cp.factory, &pjsua.med_endpt);
     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;
     }
 
@@ -478,7 +489,9 @@
     status = pjmedia_codec_init(pjsua.med_endpt);
     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;
     }
 
@@ -503,7 +516,8 @@
 
     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;
     }
 
@@ -527,7 +541,8 @@
 					     &addr_name, 1, 
 					     &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;
 	}
     }
@@ -552,7 +567,8 @@
 	uri = pjsip_parse_uri(pjsua.pool, pjsua.local_uri.ptr, 
 			      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;
 	}
 
@@ -560,7 +576,8 @@
 	/* Local URI MUST be a SIP or SIPS: */
 
 	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;
 	}
 
@@ -594,7 +611,7 @@
 	}
 
 	if (len < 1 || len >= sizeof(contact)) {
-	    pjsua_perror("Invalid Contact", PJSIP_EURITOOLONG);
+	    pjsua_perror(THIS_FILE, "Invalid Contact", PJSIP_EURITOOLONG);
 	    return PJSIP_EURITOOLONG;
 	}
 
@@ -617,7 +634,8 @@
 				 pjsua.outbound_proxy.slen,
 				   &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;
 	}
 
diff --git a/pjsip/src/pjsua/pjsua_inv.c b/pjsip/src/pjsua/pjsua_inv.c
index 6f9607b..bfd714b 100644
--- a/pjsip/src/pjsua/pjsua_inv.c
+++ b/pjsip/src/pjsua/pjsua_inv.c
@@ -53,7 +53,7 @@
 				   &pjsua.contact_uri, &dest_uri, &dest_uri,
 				   &dlg);
     if (status != PJ_SUCCESS) {
-	pjsua_perror("Dialog creation failed", status);
+	pjsua_perror(THIS_FILE, "Dialog creation failed", status);
 	return status;
     }
 
@@ -62,7 +62,7 @@
     status = pjmedia_endpt_create_sdp( pjsua.med_endpt, dlg->pool,
 				       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;
     }
 
@@ -70,7 +70,7 @@
 
     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;
     }
 
@@ -99,7 +99,8 @@
 
     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;
     }
 
@@ -108,7 +109,8 @@
 
     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;
     }
 
@@ -301,7 +303,7 @@
 
     if (status != PJ_SUCCESS) {
 
-	pjsua_perror("SDP negotiation has failed", status);
+	pjsua_perror(THIS_FILE, "SDP negotiation has failed", status);
 	return;
 
     }
@@ -318,14 +320,18 @@
 
     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;
     }
 
 
     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;
     }
 
@@ -340,7 +346,8 @@
 					 local_sdp, remote_sdp, 
 					 &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;
 	}
 
diff --git a/pjsip/src/pjsua/pjsua_pres.c b/pjsip/src/pjsua/pjsua_pres.c
index db009ee..8129a82 100644
--- a/pjsip/src/pjsua/pjsua_pres.c
+++ b/pjsip/src/pjsua/pjsua_pres.c
@@ -98,7 +98,9 @@
     status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata, 
 				   &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;
     }
 
@@ -110,7 +112,8 @@
     status = pjsip_pres_create_uas( dlg, &pres_cb, rdata, &sub);
     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;
     }
 
@@ -134,7 +137,8 @@
     /* Create and send 200 (OK) to the SUBSCRIBE request: */
     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;
     }
@@ -157,7 +161,8 @@
 	status = pjsip_pres_send_request( sub, tdata);
 
     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;
     }
@@ -304,7 +309,8 @@
 				   &pjsua.buddies[index].uri,
 				   NULL, &dlg);
     if (status != PJ_SUCCESS) {
-	pjsua_perror("Unable to create dialog", status);
+	pjsua_perror(THIS_FILE, "Unable to create dialog", 
+		     status);
 	return;
     }
 
@@ -312,7 +318,8 @@
 				    &pjsua.buddies[index].sub);
     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;
     }
 
@@ -322,14 +329,16 @@
     status = pjsip_pres_initiate(pjsua.buddies[index].sub, 60, &tdata);
     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;
     }
 
     status = pjsip_pres_send_request(pjsua.buddies[index].sub, tdata);
     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;
     }
 
@@ -364,7 +373,8 @@
 	//pjsua.buddies[index].sub = NULL;
 
     } else {
-	pjsua_perror("Unable to unsubscribe presence", status);
+	pjsua_perror(THIS_FILE, "Unable to unsubscribe presence", 
+		     status);
     }
 }
 
@@ -396,7 +406,8 @@
 
     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);
     }
 
     return status;
diff --git a/pjsip/src/pjsua/pjsua_reg.c b/pjsip/src/pjsua/pjsua_reg.c
index 972791b..f11ff3f 100644
--- a/pjsip/src/pjsua/pjsua_reg.c
+++ b/pjsip/src/pjsua/pjsua_reg.c
@@ -37,9 +37,15 @@
     /*
      * 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;
 
     } else if (PJSIP_IS_STATUS_IN_CLASS(param->code, 200)) {
@@ -53,6 +59,7 @@
 	PJ_LOG(4, (THIS_FILE, "SIP registration updated status=%d", param->code));
     }
 
+    pjsua.regc_last_err = param->status;
     pjsua.regc_last_code = param->code;
 
     pjsua_ui_regc_on_state_changed(pjsua.regc_last_code);
@@ -68,19 +75,33 @@
     pjsip_tx_data *tdata;
 
     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) {
-	pjsua_perror("Unable to create REGISTER request", status);
-	return;
-    }
+    if (status == PJ_SUCCESS)
+	status = pjsip_regc_send( pjsua.regc, tdata );
 
-    pjsip_regc_send( pjsua.regc, tdata );
+    if (status != PJ_SUCCESS) {
+	pjsua_perror(THIS_FILE, "Unable to create/send REGISTER", 
+		     status);
+    } else {
+	PJ_LOG(3,(THIS_FILE, "%s sent",
+	         (renew? "Registration" : "Unregistration")));
+    }
 }
 
 /*
@@ -96,7 +117,8 @@
 	status = pjsip_regc_create( pjsua.endpt, NULL, &regc_cb, &pjsua.regc);
 
 	if (status != PJ_SUCCESS) {
-	    pjsua_perror("Unable to create client registration", status);
+	    pjsua_perror(THIS_FILE, "Unable to create client registration", 
+			 status);
 	    return status;
 	}
 
@@ -107,7 +129,9 @@
 				  1, &pjsua.contact_uri, 
 				  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;
 	}