Index: /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c
===================================================================
--- /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c	(revision 611)
+++ /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c	(revision 612)
@@ -138,5 +138,10 @@
 static void default_config(struct app_config *cfg)
 {
+    char tmp[80];
+
     pjsua_config_default(&cfg->cfg);
+    pj_ansi_sprintf(tmp, "PJSUA v%s/%s", PJ_VERSION, PJ_OS_NAME);
+    pj_strdup2_with_null(app_config.pool, &cfg->cfg.user_agent, tmp);
+
     pjsua_logging_config_default(&cfg->log_cfg);
     pjsua_media_config_default(&cfg->media_cfg);
@@ -473,5 +478,5 @@
 	case OPT_NEXT_ACCOUNT: /* Add more account. */
 	    cfg->acc_cnt++;
-	    cur_acc = &cfg->acc_cfg[cfg->acc_cnt - 1];
+	    cur_acc = &cfg->acc_cfg[cfg->acc_cnt];
 	    break;
 
@@ -665,6 +670,6 @@
     }
 
-    if (cfg->acc_cfg[0].id.slen && cfg->acc_cnt==0)
-	cfg->acc_cnt = 1;
+    if (cfg->acc_cfg[cfg->acc_cnt].id.slen)
+	cfg->acc_cnt++;
 
     for (i=0; i<cfg->acc_cnt; ++i) {
@@ -1307,5 +1312,5 @@
     puts("|                              | cc  Connect port         | dd  Dump detailed |");
     puts("|                              | cd  Disconnect port      | dc  Dump config   |");
-    puts("|                              |                          |  f  Save config   |");
+    puts("|  S  Send arbitrary REQUEST   |                          |  f  Save config   |");
     puts("+------------------------------+--------------------------+-------------------+");
     puts("|  q  QUIT                                                                    |");
@@ -1460,4 +1465,40 @@
     }
     puts("");
+}
+
+
+/*
+ * Send arbitrary request to remote host
+ */
+static void send_request(char *cstr_method, const pj_str_t *dst_uri)
+{
+    pj_str_t str_method;
+    pjsip_method method;
+    pjsip_tx_data *tdata;
+    pjsua_acc_info acc_info;
+    pjsip_endpoint *endpt;
+    pj_status_t status;
+
+    endpt = pjsua_get_pjsip_endpt();
+
+    str_method = pj_str(cstr_method);
+    pjsip_method_init_np(&method, &str_method);
+
+    pjsua_acc_get_info(current_acc, &acc_info);
+
+    status = pjsip_endpt_create_request(endpt, &method, dst_uri, 
+					&acc_info.acc_uri, dst_uri,
+					NULL, NULL, -1, NULL, &tdata);
+    if (status != PJ_SUCCESS) {
+	pjsua_perror(THIS_FILE, "Unable to create request", status);
+	return;
+    }
+
+    status = pjsip_endpt_send_request(endpt, tdata, -1, NULL, NULL);
+    if (status != PJ_SUCCESS) {
+	pjsua_perror(THIS_FILE, "Unable to send request", status);
+	pjsip_tx_data_dec_ref(tdata);
+	return;
+    }
 }
 
@@ -1892,4 +1933,42 @@
 		}
 	    }
+	    break;
+
+	case 'S':
+	    /*
+	     * Send arbitrary request
+	     */
+	    if (pjsua_acc_get_count() == 0) {
+		puts("Sorry, need at least one account configured");
+		break;
+	    }
+
+	    puts("Send arbitrary request to remote host");
+
+	    /* Input METHOD */
+	    if (!simple_input("Request method:",text,sizeof(text)))
+		break;
+
+	    /* Input destination URI */
+	    uri = NULL;
+	    ui_input_url("Destination URI", buf, sizeof(buf), &result);
+	    if (result.nb_result != NO_NB) {
+
+		if (result.nb_result == -1 || result.nb_result == 0) {
+		    puts("Sorry you can't do that!");
+		    continue;
+		} else {
+		    pjsua_buddy_info binfo;
+		    pjsua_buddy_get_info(result.nb_result-1, &binfo);
+		    uri = binfo.uri.ptr;
+		}
+
+	    } else if (result.uri_result) {
+		uri = result.uri_result;
+	    }
+	    
+	    tmp = pj_str(uri);
+
+	    send_request(text, &tmp);
 	    break;
 
Index: /pjproject/trunk/pjsip/include/pjsip-simple/evsub.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip-simple/evsub.h	(revision 611)
+++ /pjproject/trunk/pjsip/include/pjsip-simple/evsub.h	(revision 612)
@@ -253,4 +253,16 @@
 					       const pj_str_t accept[]);
 
+/**
+ * Get the Allow-Events header. This header is built based on the packages
+ * that are registered to the evsub module.
+ *
+ * @param m		Pointer to event subscription module instance, or
+ *			NULL to use default instance (equal to 
+ *			#pjsip_evsub_instance()).
+ *
+ * @return		The Allow-Events header.
+ */
+PJ_DECL(const pjsip_hdr*) pjsip_evsub_get_allow_events_hdr(pjsip_module *m);
+
 
 /**
Index: /pjproject/trunk/pjsip/include/pjsip-ua/sip_inv.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip-ua/sip_inv.h	(revision 611)
+++ /pjproject/trunk/pjsip/include/pjsip-ua/sip_inv.h	(revision 612)
@@ -616,4 +616,19 @@
 
 
+/**
+ * This is a utility function to create SIP body for SDP content.
+ *
+ * @param pool		Pool to allocate memory.
+ * @param sdp		SDP session to be put in the SIP message body.
+ * @param p_body	Pointer to receive SIP message body containing
+ *			the SDP session.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_create_sdp_body(pj_pool_t *pool,
+					   pjmedia_sdp_session *sdp,
+					   pjsip_msg_body **p_body);
+
+
 PJ_END_DECL
 
Index: /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 611)
+++ /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 612)
@@ -418,4 +418,9 @@
     pjsua_callback  cb;
 
+    /**
+     * User agent string (default empty)
+     */
+    pj_str_t	    user_agent;
+
 } pjsua_config;
 
@@ -469,4 +474,6 @@
 	pjsip_cred_dup(pool, &dst->cred_info[i], &src->cred_info[i]);
     }
+
+    pj_strdup_with_null(pool, &dst->user_agent, &src->user_agent);
 }
 
@@ -2081,5 +2088,5 @@
      * number.
      *
-     * Default: 3.
+     * Default: 5.
      */
     unsigned		quality;
@@ -2100,5 +2107,5 @@
     cfg->has_ioqueue = PJ_TRUE;
     cfg->thread_cnt = 1;
-    cfg->quality = 3;
+    cfg->quality = 5;
 }
 
Index: /pjproject/trunk/pjsip/src/pjsip-simple/evsub.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip-simple/evsub.c	(revision 611)
+++ /pjproject/trunk/pjsip/src/pjsip-simple/evsub.c	(revision 612)
@@ -421,4 +421,10 @@
     }
     
+    /* Add to endpoint's Accept header */
+    pjsip_endpt_add_capability(mod_evsub.endpt, &mod_evsub.mod,
+			       PJSIP_H_ACCEPT, NULL,
+			       pkg->pkg_accept->count,
+			       pkg->pkg_accept->values);
+
 
     /* Done */
@@ -431,4 +437,19 @@
 }
 
+
+/*
+ * Retrieve Allow-Events header
+ */
+PJ_DEF(const pjsip_hdr*) pjsip_evsub_get_allow_events_hdr(pjsip_module *m)
+{
+    struct mod_evsub *mod;
+
+    if (m == NULL)
+	m = pjsip_evsub_instance();
+
+    mod = (struct mod_evsub*)m;
+
+    return (pjsip_hdr*) mod->allow_events_hdr;
+}
 
 
Index: /pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c	(revision 611)
+++ /pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c	(revision 612)
@@ -113,8 +113,13 @@
 {
     pj_str_t allowed[] = {{"INVITE", 6}, {"ACK",3}, {"BYE",3}, {"CANCEL",6}};
+    pj_str_t accepted = { "application/sdp", 15 };
 
     /* Register supported methods: INVITE, ACK, BYE, CANCEL */
     pjsip_endpt_add_capability(endpt, &mod_inv.mod, PJSIP_H_ALLOW, NULL,
 			       PJ_ARRAY_SIZE(allowed), allowed);
+
+    /* Register "application/sdp" in Accept header */
+    pjsip_endpt_add_capability(endpt, &mod_inv.mod, PJSIP_H_ACCEPT, NULL,
+			       1, &accepted);
 
     return PJ_SUCCESS;
@@ -960,19 +965,40 @@
 }
 
-static pjsip_msg_body *create_sdp_body(pj_pool_t *pool,
-				       const pjmedia_sdp_session *c_sdp)
-{
+
+PJ_DEF(pj_status_t) pjsip_create_sdp_body( pj_pool_t *pool,
+					   pjmedia_sdp_session *sdp,
+					   pjsip_msg_body **p_body)
+{
+    const pj_str_t STR_APPLICATION = { "application", 11};
+    const pj_str_t STR_SDP = { "sdp", 3 };
     pjsip_msg_body *body;
 
-
     body = pj_pool_zalloc(pool, sizeof(pjsip_msg_body));
-    PJ_ASSERT_RETURN(body != NULL, NULL);
-
-    body->content_type.type = pj_str("application");
-    body->content_type.subtype = pj_str("sdp");
-    body->data = pjmedia_sdp_session_clone(pool, c_sdp);
+    PJ_ASSERT_RETURN(body != NULL, PJ_ENOMEM);
+
+    body->content_type.type = STR_APPLICATION;
+    body->content_type.subtype = STR_SDP;
+    body->data = sdp;
     body->len = 0;
     body->clone_data = &clone_sdp;
     body->print_body = &print_sdp;
+
+    *p_body = body;
+
+    return PJ_SUCCESS;
+}
+
+static pjsip_msg_body *create_sdp_body(pj_pool_t *pool,
+				       const pjmedia_sdp_session *c_sdp)
+{
+    pjsip_msg_body *body;
+    pj_status_t status;
+
+    status = pjsip_create_sdp_body(pool, 
+				   pjmedia_sdp_session_clone(pool, c_sdp),
+				   &body);
+
+    if (status != PJ_SUCCESS)
+	return NULL;
 
     return body;
Index: /pjproject/trunk/pjsip/src/pjsip/sip_dialog.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_dialog.c	(revision 611)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_dialog.c	(revision 612)
@@ -1345,6 +1345,7 @@
 	const pj_str_t reason = { "No session found", 16};
 
-	PJ_LOG(4,(tsx->obj_name, "Incoming request was unhandled by "
-				 "dialog usages, sending 500 response"));
+	PJ_LOG(4,(tsx->obj_name, "%s was unhandled by "
+				 "dialog usages, sending 500 response",
+				 pjsip_rx_data_get_info(rdata)));
 
 	status = pjsip_dlg_create_response(dlg, rdata, 500, &reason, &tdata);
@@ -1458,8 +1459,11 @@
     }
 
+    /* Unhandled response does not necessarily mean error because
+       dialog usages may choose to process the transaction state instead.
     if (i==dlg->usage_cnt) {
-	PJ_LOG(4,(dlg->obj_name, "%s is unhandled by dialog usages",
+	PJ_LOG(4,(dlg->obj_name, "%s was not claimed by any dialog usages",
 		  pjsip_rx_data_get_info(rdata)));
     }
+    */
 
     /* Unlock dialog and dec session, may destroy dialog. */
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_acc.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_acc.c	(revision 611)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_acc.c	(revision 612)
@@ -539,6 +539,8 @@
     }
 
-    if (status == PJ_SUCCESS)
+    if (status == PJ_SUCCESS) {
+	pjsua_process_msg_data(tdata, NULL);
 	status = pjsip_regc_send( pjsua_var.acc[acc_id].regc, tdata );
+    }
 
     if (status != PJ_SUCCESS) {
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 611)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 612)
@@ -130,4 +130,104 @@
 
 /*****************************************************************************
+ * Another simple module to handle incoming OPTIONS request
+ */
+
+/* Notification on incoming request */
+static pj_bool_t options_on_rx_request(pjsip_rx_data *rdata)
+{
+    pjsip_tx_data *tdata;
+    pjsip_response_addr res_addr;
+    pjmedia_sdp_session *sdp;
+    const pjsip_hdr *cap_hdr;
+    pj_status_t status;
+
+    /* Only want to handle OPTIONS requests */
+    if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method,
+			 &pjsip_options_method) != 0)
+    {
+	return PJ_FALSE;
+    }
+
+    /* Create basic response. */
+    status = pjsip_endpt_create_response(pjsua_var.endpt, rdata, 200, NULL, 
+					 &tdata);
+    if (status != PJ_SUCCESS) {
+	pjsua_perror(THIS_FILE, "Unable to create OPTIONS response", status);
+	return PJ_TRUE;
+    }
+
+    /* Add Allow header */
+    cap_hdr = pjsip_endpt_get_capability(pjsua_var.endpt, PJSIP_H_ALLOW, NULL);
+    if (cap_hdr) {
+	pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_clone(tdata->pool, cap_hdr));
+    }
+
+    /* Add Accept header */
+    cap_hdr = pjsip_endpt_get_capability(pjsua_var.endpt, PJSIP_H_ACCEPT, NULL);
+    if (cap_hdr) {
+	pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_clone(tdata->pool, cap_hdr));
+    }
+
+    /* Add Supported header */
+    cap_hdr = pjsip_endpt_get_capability(pjsua_var.endpt, PJSIP_H_SUPPORTED, NULL);
+    if (cap_hdr) {
+	pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_clone(tdata->pool, cap_hdr));
+    }
+
+    /* Add Allow-Events header from the evsub module */
+    cap_hdr = pjsip_evsub_get_allow_events_hdr(NULL);
+    if (cap_hdr) {
+	pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_clone(tdata->pool, cap_hdr));
+    }
+
+    /* Add User-Agent header */
+    if (pjsua_var.ua_cfg.user_agent.slen) {
+	const pj_str_t USER_AGENT = { "User-Agent", 10};
+	pjsip_hdr *h;
+
+	h = (pjsip_hdr*) pjsip_generic_string_hdr_create(tdata->pool,
+							 &USER_AGENT,
+							 &pjsua_var.ua_cfg.user_agent);
+	pjsip_msg_add_hdr(tdata->msg, h);
+    }
+
+    /* Add SDP body, using call0's RTP address */
+    status = pjmedia_endpt_create_sdp(pjsua_var.med_endpt, tdata->pool, 1,
+				      &pjsua_var.calls[0].skinfo, &sdp);
+    if (status == PJ_SUCCESS) {
+	pjsip_create_sdp_body(tdata->pool, sdp, &tdata->msg->body);
+    }
+
+    /* Send response statelessly */
+    pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
+    status = pjsip_endpt_send_response(pjsua_var.endpt, &res_addr, tdata, NULL, NULL);
+    if (status != PJ_SUCCESS)
+	pjsip_tx_data_dec_ref(tdata);
+
+    return PJ_TRUE;
+}
+
+
+/* The module instance. */
+static pjsip_module pjsua_options_handler = 
+{
+    NULL, NULL,				/* prev, next.		*/
+    { "mod-pjsua-options", 17 },	/* Name.		*/
+    -1,					/* Id			*/
+    PJSIP_MOD_PRIORITY_APPLICATION,	/* Priority	        */
+    NULL,				/* load()		*/
+    NULL,				/* start()		*/
+    NULL,				/* stop()		*/
+    NULL,				/* unload()		*/
+    &options_on_rx_request,		/* on_rx_request()	*/
+    NULL,				/* on_rx_response()	*/
+    NULL,				/* on_tx_request.	*/
+    NULL,				/* on_tx_response()	*/
+    NULL,				/* on_tsx_state()	*/
+
+};
+
+
+/*****************************************************************************
  * These two functions are the main callbacks registered to PJSIP stack
  * to receive SIP request and response messages that are outside any
@@ -235,4 +335,10 @@
     }
 
+    /* Unregister OPTIONS handler if it's previously registered */
+    if (pjsua_options_handler.id >= 0) {
+	pjsip_endpt_unregister_module(pjsua_var.endpt, &pjsua_options_handler);
+	pjsua_options_handler.id = -1;
+    }
+
     /* Unregister msg logging if it's previously registered */
     if (pjsua_msg_logger.id >= 0) {
@@ -245,4 +351,6 @@
 	pjsip_endpt_register_module(pjsua_var.endpt, &pjsua_msg_logger);
 
+    /* Register OPTIONS handler */
+    pjsip_endpt_register_module(pjsua_var.endpt, &pjsua_options_handler);
 
     return PJ_SUCCESS;
@@ -1025,4 +1133,16 @@
     const pjsip_hdr *hdr;
 
+    /* Always add User-Agent */
+    if (pjsua_var.ua_cfg.user_agent.slen && 
+	tdata->msg->type == PJSIP_REQUEST_MSG) 
+    {
+	const pj_str_t STR_USER_AGENT = { "User-Agent", 10 };
+	pjsip_hdr *h;
+	h = (pjsip_hdr*)pjsip_generic_string_hdr_create(tdata->pool, 
+							&STR_USER_AGENT, 
+							&pjsua_var.ua_cfg.user_agent);
+	pjsip_msg_add_hdr(tdata->msg, h);
+    }
+
     if (!msg_data)
 	return;
