Index: pjproject/trunk/pjsip-apps/src/py_pjsua/pjsua_app.py
===================================================================
--- pjproject/trunk/pjsip-apps/src/py_pjsua/pjsua_app.py	(revision 971)
+++ pjproject/trunk/pjsip-apps/src/py_pjsua/pjsua_app.py	(revision 972)
@@ -37,4 +37,21 @@
 g_rec_port = 0
 
+# Utility: display PJ error and exit
+#
+def err_exit(title, rc):
+    py_pjsua.perror(THIS_FILE, title, rc)
+    exit(1)
+
+
+# Logging function (also callback, called by pjsua-lib)
+#
+def log_cb(level, str, len):
+    if level <= C_LOG_LEVEL:
+        print str,
+
+def write_log(level, str):
+    log_cb(level, str + "\n", 0)
+
+
 # Utility to get call info
 #
@@ -85,8 +102,12 @@
 def on_reg_state(acc_id):
 	acc_info = py_pjsua.acc_get_info(acc_id)
+	if acc_info.has_registration != 0:
+		cmd = "registration"
+	else:
+		cmd = "unregistration"
 	if acc_info.status != 0 and acc_info.status != 200:
-		write_log(3, "Account (un)registration failed: rc=" + `acc_info.status` + " " + acc_info.status_text)
-	else:
-		write_log(3, "Account successfully (un)registered")
+		write_log(3, "Account " + cmd + " failed: rc=" + `acc_info.status` + " " + acc_info.status_text)
+	else:
+		write_log(3, "Account " + cmd + " success")
 
 
@@ -123,5 +144,5 @@
 	write_log(3, "IM indication: " + strfrom + " " + str_t)
 
-# on call transfer status
+# Received the status of previous call transfer request
 #
 def on_call_transfer_status(call_id,status_code,status_text,final,p_cont):
@@ -137,25 +158,8 @@
 		p_cont = 0
 
-# on call transfer request
+# Callback on incoming call transfer request
 #		
 def on_call_transfer_request(call_id, dst, code):
 	write_log(3, "Call transfer request from " + `call_id` + " to " + dst + " with code " + `code`)
-
-# Utility: display PJ error and exit
-#
-def err_exit(title, rc):
-    py_pjsua.perror(THIS_FILE, title, rc)
-    exit(1)
-
-
-# Logging function (also callback, called by pjsua-lib)
-#
-def log_cb(level, str, len):
-    if level <= C_LOG_LEVEL:
-        print str,
-
-def write_log(level, str):
-    log_cb(level, str + "\n", 0)
-
 
 #
@@ -330,11 +334,6 @@
 
 def conf_list():
-	
-	
 	ports = None
-
 	print "Conference ports : "
-
-	
 	ports = py_pjsua.enum_conf_ports()
 
@@ -401,5 +400,5 @@
 	else:
 		write_log(3, "No current call")
-		
+
 def xfer_call():
 	global g_current_call
@@ -507,7 +506,44 @@
 
 
+# Print account and buddy list
+def print_acc_buddy_list():
+	global g_acc_id
+	
+	acc_ids = py_pjsua.enum_accs()
+	print "Account list:"
+	for acc_id in acc_ids:
+		acc_info = py_pjsua.acc_get_info(acc_id)
+		if acc_info.has_registration == 0:
+			acc_status = acc_info.status_text
+		else:
+			acc_status = `acc_info.status` + "/" + acc_info.status_text + " (expires=" + `acc_info.expires` + ")"
+
+		if acc_id == g_acc_id:
+			print " *",
+		else:
+			print "  ",
+
+		print "[" + `acc_id` + "] " + acc_info.acc_uri + ": " + acc_status
+		print "       Presence status: ",
+		if acc_info.online_status != 0:
+			print "Online"
+		else:
+			print "Invisible"
+
+	if py_pjsua.get_buddy_count() > 0:
+		print ""
+		print "Buddy list:"
+		buddy_ids = py_pjsua.enum_buddies()
+		for buddy_id in buddy_ids:
+			bi = py_pjsua.buddy_get_info(buddy_id)
+			print "   [" + `buddy_id` + "] " + bi.status_text + " " + bi.uri
+	
+		
 # Print application menu
 #
 def print_menu():
+	print ""
+	print ">>>"
+	print_acc_buddy_list()
 	print """
 +============================================================================+
@@ -525,12 +561,12 @@
 |  X  Xfer with Replaces       |                          |                  |
 |                              | cl  List ports           |  d  Dump status  |
-|                              | cc  Connect port         |                  |
+|                              | cc  Connect port         | dd  Dump detail  |
 |                              | cd  Disconnect port      |                  |
 |                              | +p  Add file player      |                  |
 |------------------------------+ +r  Add file recorder    |                  |
 |  q  Quit application         |                          |                  |
-+============================================================================+
-	"""
-	print "Choice: ", 
++============================================================================+"""
+	print "You have " + `py_pjsua.call_get_count()` + " active call(s)"
+	print ">>>", 
 
 # Menu
@@ -592,4 +628,5 @@
 				continue
             
+			bc.uri = bc.uri.replace("\n", "")
 			bc.subscribe = 1
 			status, buddy_id = py_pjsua.buddy_add(bc)
@@ -714,17 +751,5 @@
 				py_pjsua.acc_set_registration(g_acc_id, 0)
 		elif choice[0] == "d":
-			
-			write_log(3, "Start dumping application states : ")
-			write_log(3, "Dumping invite sessions : ")
-
-			if py_pjsua.call_get_count() == 0:
-				write_log(3, "  - no sessions -")
-			else:
-				for i in range(0, g_ua_cfg.max_calls):
-					if py_pjsua.call_is_active(i):
-						buf = py_pjsua.call_dump(i, 1, 1024, "  ")
-						write_log(3, buf)	
-			py_pjsua.pres_dump(1)
-			write_log(3, "Dump complete")
+			py_pjsua.dump(choice[1] == "d")
 		elif choice[0] == "a":
 			if g_current_call != py_pjsua.PJSUA_INVALID_ID:				
Index: pjproject/trunk/pjsip-apps/src/py_pjsua/py_pjsua.c
===================================================================
--- pjproject/trunk/pjsip-apps/src/py_pjsua/py_pjsua.c	(revision 971)
+++ pjproject/trunk/pjsip-apps/src/py_pjsua/py_pjsua.c	(revision 972)
@@ -28,31 +28,17 @@
 /* LIB BASE */
 
-static PyObject* obj_reconfigure_logging;
-static PyObject* obj_logging_init;
+static PyObject* obj_log_cb;
 static long thread_id;
 
-/*
- * cb_reconfigure_logging
+#define ENTER_PYTHON()	    PyGILState_STATE state = PyGILState_Ensure()
+#define LEAVE_PYTHON()	    PyGILState_Release(state)
+
+/*
+ * cb_log_cb
  * declares method for reconfiguring logging process for callback struct
  */
-static void cb_reconfigure_logging(int level, const char *data, pj_size_t len)
+static void cb_log_cb(int level, const char *data, pj_size_t len)
 {
 	
-    if (PyCallable_Check(obj_reconfigure_logging))
-    {
-        PyObject_CallFunctionObjArgs(
-            obj_reconfigure_logging, Py_BuildValue("i",level),
-            PyString_FromString(data), Py_BuildValue("i",len), NULL
-        );
-    }
-}
-
-
-/*
- * cb_logging_init
- * declares method logging_init for callback struct
- */
-static void cb_logging_init(int level, const char *data, pj_size_t len)
-{
     /* Ignore if this callback is called from alien thread context,
      * or otherwise it will crash Python.
@@ -61,11 +47,14 @@
 	return;
 
-    if (PyCallable_Check(obj_logging_init))
-    {
-        
+    if (PyCallable_Check(obj_log_cb))
+    {
+	ENTER_PYTHON();
+
         PyObject_CallFunctionObjArgs(
-            obj_logging_init, Py_BuildValue("i",level),
+            obj_log_cb, Py_BuildValue("i",level),
             PyString_FromString(data), Py_BuildValue("i",len), NULL
         );
+
+	LEAVE_PYTHON();
     }
 }
@@ -196,8 +185,9 @@
     {	
         pjsip_event_Object * obj;
-		
-	obj =
-	        (pjsip_event_Object *)PyType_GenericNew(&pjsip_event_Type, 
-						    NULL, NULL);
+
+	ENTER_PYTHON();
+
+	obj = (pjsip_event_Object *)PyType_GenericNew(&pjsip_event_Type,
+						      NULL, NULL);
 		
 	obj->event = e;
@@ -206,5 +196,6 @@
             g_obj_callback->on_call_state,Py_BuildValue("i",call_id),obj,NULL
         );
-		
+
+	LEAVE_PYTHON();
     }
 }
@@ -220,6 +211,9 @@
     if (PyCallable_Check(g_obj_callback->on_incoming_call))
     {
-	pjsip_rx_data_Object * obj = (pjsip_rx_data_Object *)
-				      PyType_GenericNew(&pjsip_rx_data_Type, 
+	pjsip_rx_data_Object * obj;
+
+	ENTER_PYTHON();
+
+	obj = (pjsip_rx_data_Object *)PyType_GenericNew(&pjsip_rx_data_Type, 
 							NULL, NULL);
 	obj->rdata = rdata;
@@ -232,4 +226,6 @@
 		NULL
         );
+
+	LEAVE_PYTHON();
     }
 }
@@ -244,5 +240,9 @@
     if (PyCallable_Check(g_obj_callback->on_call_media_state))
     {
+	ENTER_PYTHON();
+
         PyObject_CallFunction(g_obj_callback->on_call_media_state,"i",call_id);
+
+	LEAVE_PYTHON();
     }
 }
@@ -257,8 +257,11 @@
 				        pjsip_status_code *code)
 {
-    PyObject * ret;
-    int cd;
     if (PyCallable_Check(g_obj_callback->on_call_transfer_request))
     {
+	PyObject * ret;
+	int cd;
+
+	ENTER_PYTHON();
+
         ret = PyObject_CallFunctionObjArgs(
             g_obj_callback->on_call_transfer_request,
@@ -275,4 +278,6 @@
 	    }
 	}
+
+	LEAVE_PYTHON();
     }
 }
@@ -292,8 +297,11 @@
 					pj_bool_t *p_cont)
 {
-    PyObject * ret;
-    int cnt;
     if (PyCallable_Check(g_obj_callback->on_call_transfer_status))
     {
+	PyObject * ret;
+	int cnt;
+
+	ENTER_PYTHON();
+
         ret = PyObject_CallFunctionObjArgs(
             g_obj_callback->on_call_transfer_status,
@@ -312,4 +320,6 @@
 	    }
 	}
+
+	LEAVE_PYTHON();
     }
 }
@@ -326,11 +336,14 @@
 					pj_str_t *st_text)
 {
-    PyObject * ret;
-    PyObject * txt;
-    int cd;
     if (PyCallable_Check(g_obj_callback->on_call_replace_request))
     {
-        pjsip_rx_data_Object * obj = (pjsip_rx_data_Object *)
-				      PyType_GenericNew(&pjsip_rx_data_Type,
+	PyObject * ret;
+	PyObject * txt;
+	int cd;
+        pjsip_rx_data_Object * obj;
+
+	ENTER_PYTHON();
+
+	obj = (pjsip_rx_data_Object *)PyType_GenericNew(&pjsip_rx_data_Type,
 							NULL, NULL);
         obj->rdata = rdata;
@@ -353,4 +366,6 @@
 	    }
 	}
+
+	LEAVE_PYTHON();
     }
 }
@@ -367,4 +382,6 @@
     if (PyCallable_Check(g_obj_callback->on_call_replaced))
     {
+	ENTER_PYTHON();
+
         PyObject_CallFunctionObjArgs(
             g_obj_callback->on_call_replaced,
@@ -373,4 +390,6 @@
 	    NULL
         );
+
+	LEAVE_PYTHON();
     }
 }
@@ -385,5 +404,9 @@
     if (PyCallable_Check(g_obj_callback->on_reg_state))
     {
+	ENTER_PYTHON();
+
         PyObject_CallFunction(g_obj_callback->on_reg_state,"i",acc_id);
+
+	LEAVE_PYTHON();
     }
 }
@@ -398,5 +421,9 @@
     if (PyCallable_Check(g_obj_callback->on_buddy_state))
     {
+	ENTER_PYTHON();
+
         PyObject_CallFunction(g_obj_callback->on_buddy_state,"i",buddy_id);
+
+	LEAVE_PYTHON();
     }
 }
@@ -412,4 +439,6 @@
     if (PyCallable_Check(g_obj_callback->on_pager))
     {
+	ENTER_PYTHON();
+
         PyObject_CallFunctionObjArgs(
             g_obj_callback->on_pager,Py_BuildValue("i",call_id),
@@ -420,4 +449,6 @@
             PyString_FromStringAndSize(body->ptr, body->slen), NULL
         );
+
+	LEAVE_PYTHON();
     }
 }
@@ -433,15 +464,24 @@
                                 const pj_str_t *reason)
 {
-	
-    PyObject * obj = PyType_GenericNew(user_data, NULL, NULL);
     if (PyCallable_Check(g_obj_callback->on_pager))
     {
+	PyObject * obj_user_data;
+
+	ENTER_PYTHON();
+
+	obj_user_data = Py_BuildValue("i", user_data);
+
         PyObject_CallFunctionObjArgs(
-            g_obj_callback->on_pager,Py_BuildValue("i",call_id),
+            g_obj_callback->on_pager_status,
+	    Py_BuildValue("i",call_id),
             PyString_FromStringAndSize(to->ptr, to->slen),
-            PyString_FromStringAndSize(body->ptr, body->slen),obj,
-            Py_BuildValue("i",status),PyString_FromStringAndSize(reason->ptr,
-            reason->slen),NULL
+            PyString_FromStringAndSize(body->ptr, body->slen), 
+	    obj_user_data,
+            Py_BuildValue("i",status),
+	    PyString_FromStringAndSize(reason->ptr,reason->slen),
+	    NULL
         );
+
+	LEAVE_PYTHON();
     }
 }
@@ -458,4 +498,6 @@
     if (PyCallable_Check(g_obj_callback->on_typing))
     {
+	ENTER_PYTHON();
+
         PyObject_CallFunctionObjArgs(
             g_obj_callback->on_typing,Py_BuildValue("i",call_id),
@@ -465,4 +507,6 @@
             Py_BuildValue("i",is_typing),NULL
         );
+
+	LEAVE_PYTHON();
     }
 }
@@ -1300,8 +1344,8 @@
 void translate_hdr(pj_pool_t *pool, pjsip_hdr *hdr, PyObject *py_hdr_list)
 {
-    int i;
+    pj_list_init(hdr);
 
     if (PyList_Check(py_hdr_list)) {
-        pj_list_init(hdr);
+	int i;
 
         for (i = 0; i < PyList_Size(py_hdr_list); i++) 
@@ -1867,8 +1911,8 @@
         cfg.log_filename.ptr = PyString_AsString(log->log_filename);
         cfg.log_filename.slen = strlen(cfg.log_filename.ptr);
-        Py_XDECREF(obj_reconfigure_logging);
-        obj_reconfigure_logging = log->cb;
-        Py_INCREF(obj_reconfigure_logging);
-        cfg.cb = &cb_reconfigure_logging;
+        Py_XDECREF(obj_log_cb);
+        obj_log_cb = log->cb;
+        Py_INCREF(obj_log_cb);
+        cfg.cb = &cb_log_cb;
         status = pjsua_reconfigure_logging(&cfg);
     } else {
@@ -2087,8 +2131,8 @@
         cfg_log.log_filename.ptr = PyString_AsString(log_cfg->log_filename);
         cfg_log.log_filename.slen = strlen(cfg_log.log_filename.ptr);
-        Py_XDECREF(obj_logging_init);
-        obj_logging_init = log_cfg->cb;
-        Py_INCREF(obj_logging_init);
-        cfg_log.cb = &cb_logging_init;
+        Py_XDECREF(obj_log_cb);
+        obj_log_cb = log_cfg->cb;
+        Py_INCREF(obj_log_cb);
+        cfg_log.cb = &cb_log_cb;
         p_cfg_log = &cfg_log;
     } else {
@@ -7863,4 +7907,64 @@
 }
 
+
+/*
+ * py_pjsua_dump
+ * Dump application states.
+ */
+static PyObject *py_pjsua_dump(PyObject *pSelf, PyObject *pArgs)
+{
+    unsigned old_decor;
+    char buf[1024];
+    int detail;
+
+    if (!PyArg_ParseTuple(pArgs, "i", &detail))
+    {
+        return NULL;
+    }	
+
+    PJ_LOG(3,(THIS_FILE, "Start dumping application states:"));
+
+    old_decor = pj_log_get_decor();
+    pj_log_set_decor(old_decor & (PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_CR));
+
+    if (detail)
+	pj_dump_config();
+
+    pjsip_endpt_dump(pjsua_get_pjsip_endpt(), detail);
+    pjmedia_endpt_dump(pjsua_get_pjmedia_endpt());
+    pjsip_tsx_layer_dump(detail);
+    pjsip_ua_dump(detail);
+
+
+    /* Dump all invite sessions: */
+    PJ_LOG(3,(THIS_FILE, "Dumping invite sessions:"));
+
+    if (pjsua_call_get_count() == 0) {
+
+	PJ_LOG(3,(THIS_FILE, "  - no sessions -"));
+
+    } else {
+	unsigned i, max;
+
+	max = pjsua_call_get_max_count();
+	for (i=0; i<max; ++i) {
+	    if (pjsua_call_is_active(i)) {
+		pjsua_call_dump(i, detail, buf, sizeof(buf), "  ");
+		PJ_LOG(3,(THIS_FILE, "%s", buf));
+	    }
+	}
+    }
+
+    /* Dump presence status */
+    pjsua_pres_dump(detail);
+
+    pj_log_set_decor(old_decor);
+    PJ_LOG(3,(THIS_FILE, "Dump complete"));
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+
 static char pjsua_call_get_max_count_doc[] =
     "int py_pjsua.call_get_max_count () "
@@ -8356,5 +8460,7 @@
         pjsua_call_dump_doc
     },
-
+    {
+	"dump", py_pjsua_dump, METH_VARARGS, "Dump application state"
+    },
 
     
@@ -8374,4 +8480,6 @@
 
     
+    PyEval_InitThreads();
+
     if (PyType_Ready(&callback_Type) < 0)
         return;
