Index: pjproject/trunk/pjsip/src/pjsip-simple/publishc.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip-simple/publishc.c	(revision 683)
+++ pjproject/trunk/pjsip/src/pjsip-simple/publishc.c	(revision 685)
@@ -17,30 +17,39 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  */
-#include <pjsip-ua/sip_regc.h>
+#include <pjsip-simple/publish.h>
+#include <pjsip/sip_auth.h>
 #include <pjsip/sip_endpoint.h>
-#include <pjsip/sip_parser.h>
-#include <pjsip/sip_module.h>
+#include <pjsip/sip_errno.h>
+#include <pjsip/sip_event.h>
+#include <pjsip/sip_msg.h>
 #include <pjsip/sip_transaction.h>
-#include <pjsip/sip_event.h>
+#include <pjsip/sip_uri.h>
 #include <pjsip/sip_util.h>
-#include <pjsip/sip_auth_msg.h>
-#include <pjsip/sip_errno.h>
 #include <pj/assert.h>
 #include <pj/guid.h>
+#include <pj/log.h>
 #include <pj/os.h>
 #include <pj/pool.h>
-#include <pj/log.h>
 #include <pj/rand.h>
 #include <pj/string.h>
+#include <pj/timer.h>
 
 
 #define REFRESH_TIMER		1
 #define DELAY_BEFORE_REFRESH	5
-#define THIS_FILE		"sip_regc.c"
+#define THIS_FILE		"publishc.c"
+
+
+const pjsip_method pjsip_publish_method = 
+{
+    PJSIP_OTHER_METHOD,
+    { "PUBLISH", 7 }
+};
+
 
 /**
- * SIP client registration structure.
+ * SIP client publication structure.
  */
-struct pjsip_regc
+struct pjsip_publishc
 {
     pj_pool_t			*pool;
@@ -50,8 +59,9 @@
 
     void			*token;
-    pjsip_regc_cb		*cb;
-
-    pj_str_t			 str_srv_url;
-    pjsip_uri			*srv_url;
+    pjsip_publishc_cb		*cb;
+
+    pj_str_t			 event;
+    pj_str_t			 str_target_uri;
+    pjsip_uri			*target_uri;
     pjsip_cid_hdr		*cid_hdr;
     pjsip_cseq_hdr		*cseq_hdr;
@@ -59,9 +69,6 @@
     pjsip_from_hdr		*from_hdr;
     pjsip_to_hdr		*to_hdr;
-    char			*contact_buf;
-    pjsip_generic_string_hdr	*contact_hdr;
+    pj_str_t			 etag;
     pjsip_expires_hdr		*expires_hdr;
-    pjsip_contact_hdr		*unreg_contact_hdr;
-    pjsip_expires_hdr		*unreg_expires_hdr;
     pj_uint32_t			 expires;
     pjsip_route_hdr		 route_set;
@@ -70,8 +77,8 @@
     pjsip_auth_clt_sess		 auth_sess;
 
-    /* Auto refresh registration. */
-    pj_bool_t			 auto_reg;
-    pj_time_val			 last_reg;
-    pj_time_val			 next_reg;
+    /* Auto refresh publication. */
+    pj_bool_t			 auto_refresh;
+    pj_time_val			 last_refresh;
+    pj_time_val			 next_refresh;
     pj_timer_entry		 timer;
 };
@@ -79,202 +86,139 @@
 
 
-PJ_DEF(pj_status_t) pjsip_regc_create( pjsip_endpoint *endpt, void *token,
-				       pjsip_regc_cb *cb,
-				       pjsip_regc **p_regc)
+/*
+ * Initialize client publication module.
+ */
+PJ_DEF(pj_status_t) pjsip_publishc_init_module(pjsip_endpoint *endpt)
+{
+    return pjsip_endpt_add_capability( endpt, NULL, PJSIP_H_ALLOW, NULL,
+				       1, &pjsip_publish_method.name);
+}
+
+
+PJ_DEF(pj_status_t) pjsip_publishc_create( pjsip_endpoint *endpt, 
+					   unsigned options,
+					   void *token,
+					   pjsip_publishc_cb *cb,	
+					   pjsip_publishc **p_pubc)
 {
     pj_pool_t *pool;
-    pjsip_regc *regc;
+    pjsip_publishc *pubc;
     pj_status_t status;
 
     /* Verify arguments. */
-    PJ_ASSERT_RETURN(endpt && cb && p_regc, PJ_EINVAL);
-
-    pool = pjsip_endpt_create_pool(endpt, "regc%p", 1024, 1024);
+    PJ_ASSERT_RETURN(endpt && cb && p_pubc, PJ_EINVAL);
+    PJ_ASSERT_RETURN(options == 0, PJ_EINVAL);
+
+    PJ_UNUSED_ARG(options);
+
+    pool = pjsip_endpt_create_pool(endpt, "pubc%p", 1024, 1024);
     PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
 
-    regc = pj_pool_zalloc(pool, sizeof(struct pjsip_regc));
-
-    regc->pool = pool;
-    regc->endpt = endpt;
-    regc->token = token;
-    regc->cb = cb;
-    regc->contact_buf = pj_pool_alloc(pool, PJSIP_REGC_CONTACT_BUF_SIZE);
-    regc->expires = PJSIP_REGC_EXPIRATION_NOT_SPECIFIED;
-
-    status = pjsip_auth_clt_init(&regc->auth_sess, endpt, regc->pool, 0);
+    pubc = pj_pool_zalloc(pool, sizeof(struct pjsip_publishc));
+
+    pubc->pool = pool;
+    pubc->endpt = endpt;
+    pubc->token = token;
+    pubc->cb = cb;
+    pubc->expires = PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED;
+
+    status = pjsip_auth_clt_init(&pubc->auth_sess, endpt, pubc->pool, 0);
     if (status != PJ_SUCCESS)
 	return status;
 
-    pj_list_init(&regc->route_set);
+    pj_list_init(&pubc->route_set);
 
     /* Done */
-    *p_regc = regc;
-    return PJ_SUCCESS;
-}
-
-
-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;
+    *p_pubc = pubc;
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pjsip_publishc_destroy(pjsip_publishc *pubc)
+{
+    PJ_ASSERT_RETURN(pubc, PJ_EINVAL);
+
+    if (pubc->pending_tsx) {
+	pubc->_delete_flag = 1;
+	pubc->cb = NULL;
     } 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;
-    }
-
-    return PJ_SUCCESS;
-}
-
-
-PJ_DEF(pj_pool_t*) pjsip_regc_get_pool(pjsip_regc *regc)
-{
-    return regc->pool;
-}
-
-static void set_expires( pjsip_regc *regc, pj_uint32_t expires)
-{
-    if (expires != regc->expires) {
-	regc->expires_hdr = pjsip_expires_hdr_create(regc->pool, expires);
+	pjsip_endpt_release_pool(pubc->endpt, pubc->pool);
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_pool_t*) pjsip_publishc_get_pool(pjsip_publishc *pubc)
+{
+    return pubc->pool;
+}
+
+static void set_expires( pjsip_publishc *pubc, pj_uint32_t expires)
+{
+    if (expires != pubc->expires) {
+	pubc->expires_hdr = pjsip_expires_hdr_create(pubc->pool, expires);
     } else {
-	regc->expires_hdr = NULL;
-    }
-}
-
-
-static pj_status_t set_contact( pjsip_regc *regc,
-			        int contact_cnt,
-				const pj_str_t contact[] )
-{
-    int i;
-    char *s;
-    const pj_str_t contact_STR = { "Contact", 7};
-
-    /* Concatenate contacts. */
-    for (i=0, s=regc->contact_buf; i<contact_cnt; ++i) {
-	if ((s-regc->contact_buf) + contact[i].slen + 2 > PJSIP_REGC_CONTACT_BUF_SIZE) {
-	    return PJSIP_EURITOOLONG;
-	}
-	pj_memcpy(s, contact[i].ptr, contact[i].slen);
-	s += contact[i].slen;
-
-	if (i != contact_cnt - 1) {
-	    *s++ = ',';
-	    *s++ = ' ';
-	}
-    }
-
-    /* Set "Contact" header. */
-    regc->contact_hdr = pjsip_generic_string_hdr_create(regc->pool, 
-							&contact_STR,
-							NULL);
-    regc->contact_hdr->hvalue.ptr = regc->contact_buf;
-    regc->contact_hdr->hvalue.slen = (s - regc->contact_buf);
-
-    return PJ_SUCCESS;
-}
-
-
-PJ_DEF(pj_status_t) pjsip_regc_init( pjsip_regc *regc,
-				     const pj_str_t *srv_url,
-				     const pj_str_t *from_url,
-				     const pj_str_t *to_url,
-				     int contact_cnt,
-				     const pj_str_t contact[],
-				     pj_uint32_t expires)
+	pubc->expires_hdr = NULL;
+    }
+}
+
+
+PJ_DEF(pj_status_t) pjsip_publishc_init(pjsip_publishc *pubc,
+					const pj_str_t *event,
+					const pj_str_t *target_uri,
+					const pj_str_t *from_uri,
+					const pj_str_t *to_uri,
+					pj_uint32_t expires)
 {
     pj_str_t tmp;
-    pj_status_t status;
-
-    PJ_ASSERT_RETURN(regc && srv_url && from_url && to_url && 
-		     contact_cnt && contact && expires, PJ_EINVAL);
+
+    PJ_ASSERT_RETURN(pubc && event && target_uri && from_uri && to_uri && 
+		     expires, PJ_EINVAL);
+
+    /* Copy event type */
+    pj_strdup_with_null(pubc->pool, &pubc->event, event);
 
     /* Copy server URL. */
-    pj_strdup_with_null(regc->pool, &regc->str_srv_url, srv_url);
+    pj_strdup_with_null(pubc->pool, &pubc->str_target_uri, target_uri);
 
     /* Set server URL. */
-    tmp = regc->str_srv_url;
-    regc->srv_url = pjsip_parse_uri( regc->pool, tmp.ptr, tmp.slen, 0);
-    if (regc->srv_url == NULL) {
+    tmp = pubc->str_target_uri;
+    pubc->target_uri = pjsip_parse_uri( pubc->pool, tmp.ptr, tmp.slen, 0);
+    if (pubc->target_uri == NULL) {
 	return PJSIP_EINVALIDURI;
     }
 
     /* Set "From" header. */
-    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, 
+    pj_strdup_with_null(pubc->pool, &pubc->from_uri, from_uri);
+    tmp = pubc->from_uri;
+    pubc->from_hdr = pjsip_from_hdr_create(pubc->pool);
+    pubc->from_hdr->uri = pjsip_parse_uri(pubc->pool, tmp.ptr, tmp.slen, 
 					  PJSIP_PARSE_URI_AS_NAMEADDR);
-    if (!regc->from_hdr->uri) {
-	PJ_LOG(4,(THIS_FILE, "regc: invalid source URI %.*s", 
-		  from_url->slen, from_url->ptr));
+    if (!pubc->from_hdr->uri) {
 	return PJSIP_EINVALIDURI;
     }
 
     /* Set "To" header. */
-    pj_strdup_with_null(regc->pool, &tmp, to_url);
-    regc->to_hdr = pjsip_to_hdr_create(regc->pool);
-    regc->to_hdr->uri = pjsip_parse_uri(regc->pool, tmp.ptr, tmp.slen, 
+    pj_strdup_with_null(pubc->pool, &tmp, to_uri);
+    pubc->to_hdr = pjsip_to_hdr_create(pubc->pool);
+    pubc->to_hdr->uri = pjsip_parse_uri(pubc->pool, tmp.ptr, tmp.slen, 
 					PJSIP_PARSE_URI_AS_NAMEADDR);
-    if (!regc->to_hdr->uri) {
-	PJ_LOG(4,(THIS_FILE, "regc: invalid target URI %.*s", to_url->slen, to_url->ptr));
+    if (!pubc->to_hdr->uri) {
 	return PJSIP_EINVALIDURI;
     }
 
 
-    /* Set "Contact" header. */
-    status = set_contact( regc, contact_cnt, contact);
-    if (status != PJ_SUCCESS)
-	return status;
-
     /* Set "Expires" header, if required. */
-    set_expires( regc, expires);
+    set_expires( pubc, expires);
 
     /* Set "Call-ID" header. */
-    regc->cid_hdr = pjsip_cid_hdr_create(regc->pool);
-    pj_create_unique_string(regc->pool, &regc->cid_hdr->id);
+    pubc->cid_hdr = pjsip_cid_hdr_create(pubc->pool);
+    pj_create_unique_string(pubc->pool, &pubc->cid_hdr->id);
 
     /* Set "CSeq" header. */
-    regc->cseq_hdr = pjsip_cseq_hdr_create(regc->pool);
-    regc->cseq_hdr->cseq = pj_rand() % 0xFFFF;
-    pjsip_method_set( &regc->cseq_hdr->method, PJSIP_REGISTER_METHOD);
-
-    /* Create "Contact" header used in unregistration. */
-    regc->unreg_contact_hdr = pjsip_contact_hdr_create(regc->pool);
-    regc->unreg_contact_hdr->star = 1;
-
-    /* Create "Expires" header used in unregistration. */
-    regc->unreg_expires_hdr = pjsip_expires_hdr_create( regc->pool, 0);
+    pubc->cseq_hdr = pjsip_cseq_hdr_create(pubc->pool);
+    pubc->cseq_hdr->cseq = pj_rand() % 0xFFFF;
+    pjsip_method_set( &pubc->cseq_hdr->method, PJSIP_REGISTER_METHOD);
 
     /* Done. */
@@ -282,24 +226,24 @@
 }
 
-PJ_DEF(pj_status_t) pjsip_regc_set_credentials( pjsip_regc *regc,
+PJ_DEF(pj_status_t) pjsip_publishc_set_credentials( pjsip_publishc *pubc,
 						int count,
 						const pjsip_cred_info cred[] )
 {
-    PJ_ASSERT_RETURN(regc && count && cred, PJ_EINVAL);
-    return pjsip_auth_clt_set_credentials(&regc->auth_sess, count, cred);
-}
-
-PJ_DEF(pj_status_t) pjsip_regc_set_route_set( pjsip_regc *regc,
+    PJ_ASSERT_RETURN(pubc && count && cred, PJ_EINVAL);
+    return pjsip_auth_clt_set_credentials(&pubc->auth_sess, count, cred);
+}
+
+PJ_DEF(pj_status_t) pjsip_publishc_set_route_set( pjsip_publishc *pubc,
 					      const pjsip_route_hdr *route_set)
 {
     const pjsip_route_hdr *chdr;
 
-    PJ_ASSERT_RETURN(regc && route_set, PJ_EINVAL);
-
-    pj_list_init(&regc->route_set);
+    PJ_ASSERT_RETURN(pubc && route_set, PJ_EINVAL);
+
+    pj_list_init(&pubc->route_set);
 
     chdr = route_set->next;
     while (chdr != route_set) {
-	pj_list_push_back(&regc->route_set, pjsip_hdr_clone(regc->pool, chdr));
+	pj_list_push_back(&pubc->route_set, pjsip_hdr_clone(pubc->pool, chdr));
 	chdr = chdr->next;
     }
@@ -308,21 +252,23 @@
 }
 
-static pj_status_t create_request(pjsip_regc *regc, 
+static pj_status_t create_request(pjsip_publishc *pubc, 
 				  pjsip_tx_data **p_tdata)
 {
-    pj_status_t status;
+    const pj_str_t STR_EVENT = { "Event", 5 };
+    pj_status_t status;
+    pjsip_generic_string_hdr *hdr;
     pjsip_tx_data *tdata;
 
-    PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);
+    PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
 
     /* Create the request. */
-    status = pjsip_endpt_create_request_from_hdr( regc->endpt, 
-						  &pjsip_register_method,
-						  regc->srv_url,
-						  regc->from_hdr,
-						  regc->to_hdr,
+    status = pjsip_endpt_create_request_from_hdr( pubc->endpt, 
+						  &pjsip_publish_method,
+						  pubc->target_uri,
+						  pubc->from_hdr,
+						  pubc->to_hdr,
 						  NULL,
-						  regc->cid_hdr,
-						  regc->cseq_hdr->cseq,
+						  pubc->cid_hdr,
+						  pubc->cseq_hdr->cseq,
 						  NULL,
 						  &tdata);
@@ -331,8 +277,8 @@
 
     /* Add cached authorization headers. */
-    pjsip_auth_clt_init_req( &regc->auth_sess, tdata );
+    pjsip_auth_clt_init_req( &pubc->auth_sess, tdata );
 
     /* Add Route headers from route set, ideally after Via header */
-    if (!pj_list_empty(&regc->route_set)) {
+    if (!pj_list_empty(&pubc->route_set)) {
 	pjsip_hdr *route_pos;
 	const pjsip_route_hdr *route;
@@ -342,6 +288,6 @@
 	    route_pos = &tdata->msg->hdr;
 
-	route = regc->route_set.next;
-	while (route != &regc->route_set) {
+	route = pubc->route_set.next;
+	while (route != &pubc->route_set) {
 	    pjsip_hdr *new_hdr = pjsip_hdr_shallow_clone(tdata->pool, route);
 	    pj_list_insert_after(route_pos, new_hdr);
@@ -351,4 +297,22 @@
     }
 
+    /* Add Event header */
+    hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_EVENT,
+					  &pubc->event);
+    if (hdr)
+	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
+
+
+    /* Add SIP-If-Match if we have etag */
+    if (pubc->etag.slen) {
+	const pj_str_t STR_HNAME = { "SIP-If-Match", 12 };
+
+	hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_HNAME,
+					      &pubc->etag);
+	if (hdr)
+	    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
+    }
+
+
     /* Done. */
     *p_tdata = tdata;
@@ -357,29 +321,33 @@
 
 
-PJ_DEF(pj_status_t) pjsip_regc_register(pjsip_regc *regc, pj_bool_t autoreg,
-					pjsip_tx_data **p_tdata)
-{
-    pjsip_msg *msg;
+PJ_DEF(pj_status_t) pjsip_publishc_publish(pjsip_publishc *pubc, 
+					   pj_bool_t auto_refresh,
+					   pjsip_tx_data **p_tdata)
+{
     pj_status_t status;
     pjsip_tx_data *tdata;
 
-    PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);
-
-    status = create_request(regc, &tdata);
+    PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
+
+    status = create_request(pubc, &tdata);
     if (status != PJ_SUCCESS)
 	return status;
 
-    /* Add Contact header. */
-    msg = tdata->msg;
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*) regc->contact_hdr);
-    if (regc->expires_hdr)
-	pjsip_msg_add_hdr(msg, (pjsip_hdr*) regc->expires_hdr);
-
-    if (regc->timer.id != 0) {
-	pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
-	regc->timer.id = 0;
-    }
-
-    regc->auto_reg = autoreg;
+    /* Add Expires header */
+    if (pubc->expires_hdr) {
+	pjsip_hdr *dup;
+
+	dup = pjsip_hdr_shallow_clone(tdata->pool, pubc->expires_hdr);
+	if (dup)
+	    pjsip_msg_add_hdr(tdata->msg, dup);
+    }
+
+    /* Cancel existing timer */
+    if (pubc->timer.id != 0) {
+	pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer);
+	pubc->timer.id = 0;
+    }
+
+    pubc->auto_refresh = auto_refresh;
 
     /* Done */
@@ -389,25 +357,28 @@
 
 
-PJ_DEF(pj_status_t) pjsip_regc_unregister(pjsip_regc *regc,
-					  pjsip_tx_data **p_tdata)
+PJ_DEF(pj_status_t) pjsip_publishc_unpublish(pjsip_publishc *pubc,
+					     pjsip_tx_data **p_tdata)
 {
     pjsip_tx_data *tdata;
     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;
-    }
-
-    status = create_request(regc, &tdata);
+    pjsip_expires_hdr *expires;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
+
+    if (pubc->timer.id != 0) {
+	pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer);
+	pubc->timer.id = 0;
+    }
+
+    status = create_request(pubc, &tdata);
     if (status != PJ_SUCCESS)
 	return status;
 
     msg = tdata->msg;
-    pjsip_msg_add_hdr( msg, (pjsip_hdr*)regc->unreg_contact_hdr);
-    pjsip_msg_add_hdr( msg, (pjsip_hdr*)regc->unreg_expires_hdr);
+
+    /* Add Expires:0 header */
+    expires = pjsip_expires_hdr_create(tdata->pool, 0);
+    pjsip_msg_add_hdr( msg, (pjsip_hdr*)expires);
 
     *p_tdata = tdata;
@@ -416,50 +387,35 @@
 
 
-PJ_DEF(pj_status_t) pjsip_regc_update_contact(  pjsip_regc *regc,
-					        int contact_cnt,
-						const pj_str_t contact[] )
-{
-    PJ_ASSERT_RETURN(regc, PJ_EINVAL);
-    return set_contact( regc, contact_cnt, contact );
-}
-
-
-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, 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[])
-{
-    struct pjsip_regc_cbparam cbparam;
-
-
-    cbparam.regc = regc;
-    cbparam.token = regc->token;
+PJ_DEF(pj_status_t) pjsip_publishc_update_expires( pjsip_publishc *pubc,
+					           pj_uint32_t expires )
+{
+    PJ_ASSERT_RETURN(pubc, PJ_EINVAL);
+    set_expires( pubc, expires );
+    return PJ_SUCCESS;
+}
+
+
+static void call_callback(pjsip_publishc *pubc, pj_status_t status, 
+			  int st_code, const pj_str_t *reason,
+			  pjsip_rx_data *rdata, pj_int32_t expiration)
+{
+    struct pjsip_publishc_cbparam cbparam;
+
+
+    cbparam.pubc = pubc;
+    cbparam.token = pubc->token;
     cbparam.status = status;
     cbparam.code = st_code;
     cbparam.reason = *reason;
     cbparam.rdata = rdata;
-    cbparam.contact_cnt = contact_cnt;
     cbparam.expiration = expiration;
-    if (contact_cnt) {
-	pj_memcpy( cbparam.contact, contact, 
-		   contact_cnt*sizeof(pjsip_contact_hdr*));
-    }
-
-    (*regc->cb)(&cbparam);
-}
-
-static void regc_refresh_timer_cb( pj_timer_heap_t *timer_heap,
+
+    (*pubc->cb)(&cbparam);
+}
+
+static void pubc_refresh_timer_cb( pj_timer_heap_t *timer_heap,
 				   struct pj_timer_entry *entry)
 {
-    pjsip_regc *regc = entry->user_data;
+    pjsip_publishc *pubc = entry->user_data;
     pjsip_tx_data *tdata;
     pj_status_t status;
@@ -468,7 +424,7 @@
 
     entry->id = 0;
-    status = pjsip_regc_register(regc, 1, &tdata);
+    status = pjsip_publishc_publish(pubc, 1, &tdata);
     if (status == PJ_SUCCESS) {
-	status = pjsip_regc_send(regc, tdata);
+	status = pjsip_publishc_send(pubc, tdata);
     } 
     
@@ -476,5 +432,5 @@
 	char errmsg[PJ_ERR_MSG_SIZE];
 	pj_str_t reason = pj_strerror(status, errmsg, sizeof(errmsg));
-	call_callback(regc, status, 400, &reason, NULL, -1, 0, NULL);
+	call_callback(pubc, status, 400, &reason, NULL, -1);
     }
 }
@@ -483,15 +439,15 @@
 {
     pj_status_t status;
-    pjsip_regc *regc = token;
+    pjsip_publishc *pubc = token;
     pjsip_transaction *tsx = event->body.tsx_state.tsx;
     
     /* Decrement pending transaction counter. */
-    pj_assert(regc->pending_tsx > 0);
-    --regc->pending_tsx;
-
-    /* If registration data has been deleted by user then remove registration 
+    pj_assert(pubc->pending_tsx > 0);
+    --pubc->pending_tsx;
+
+    /* If publication data has been deleted by user then remove publication 
      * data from transaction's callback, and don't call callback.
      */
-    if (regc->_delete_flag) {
+    if (pubc->_delete_flag) {
 
 	/* Nothing to do */
@@ -504,5 +460,5 @@
 	pjsip_tx_data *tdata;
 
-	status = pjsip_auth_clt_reinit_req( &regc->auth_sess,
+	status = pjsip_auth_clt_reinit_req( &pubc->auth_sess,
 					    rdata, 
 					    tsx->last_tx,  
@@ -510,11 +466,11 @@
 
 	if (status == PJ_SUCCESS) {
-	    status = pjsip_regc_send(regc, tdata);
+	    status = pjsip_publishc_send(pubc, tdata);
 	} 
 	
 	if (status != PJ_SUCCESS) {
-	    call_callback(regc, status, tsx->status_code, 
+	    call_callback(pubc, status, tsx->status_code, 
 			  &rdata->msg_info.msg->line.status.reason,
-			  rdata, -1, 0, NULL);
+			  rdata, -1);
 	}
 
@@ -522,26 +478,26 @@
 
     } else {
-	int contact_cnt = 0;
-	pjsip_contact_hdr *contact[PJSIP_REGC_MAX_CONTACT];
 	pjsip_rx_data *rdata;
 	pj_int32_t expiration = 0xFFFF;
 
 	if (tsx->status_code/100 == 2) {
-	    int i;
-	    pjsip_contact_hdr *hdr;
 	    pjsip_msg *msg;
 	    pjsip_expires_hdr *expires;
+	    pjsip_generic_string_hdr *etag_hdr;
+	    const pj_str_t STR_ETAG = { "SIP-ETag", 8 };
 
 	    rdata = event->body.tsx_state.src.rdata;
 	    msg = rdata->msg_info.msg;
-	    hdr = pjsip_msg_find_hdr( msg, PJSIP_H_CONTACT, NULL);
-	    while (hdr) {
-		contact[contact_cnt++] = hdr;
-		hdr = hdr->next;
-		if (hdr == (void*)&msg->hdr)
-		    break;
-		hdr = pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, hdr);
+
+	    /* Save ETag value */
+	    etag_hdr = (pjsip_generic_string_hdr*)
+		       pjsip_msg_find_hdr_by_name(msg, &STR_ETAG, NULL);
+	    if (etag_hdr) {
+		pj_strdup(pubc->pool, &pubc->etag, &etag_hdr->hvalue);
+	    } else {
+		pubc->etag.slen = 0;
 	    }
 
+	    /* Update expires value */
 	    expires = pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
 
@@ -549,28 +505,22 @@
 		expiration = expires->ivalue;
 	    
-	    for (i=0; i<contact_cnt; ++i) {
-		hdr = contact[i];
-		if (hdr->expires >= 0 && hdr->expires < expiration)
-		    expiration = contact[i]->expires;
-	    }
-
-	    if (regc->auto_reg && expiration != 0 && expiration != 0xFFFF) {
+	    if (pubc->auto_refresh && expiration!=0 && expiration!=0xFFFF) {
 		pj_time_val delay = { 0, 0};
 
 		delay.sec = expiration - DELAY_BEFORE_REFRESH;
-		if (regc->expires != PJSIP_REGC_EXPIRATION_NOT_SPECIFIED && 
-		    delay.sec > (pj_int32_t)regc->expires) 
+		if (pubc->expires != PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED && 
+		    delay.sec > (pj_int32_t)pubc->expires) 
 		{
-		    delay.sec = regc->expires;
+		    delay.sec = pubc->expires;
 		}
 		if (delay.sec < DELAY_BEFORE_REFRESH) 
 		    delay.sec = DELAY_BEFORE_REFRESH;
-		regc->timer.cb = &regc_refresh_timer_cb;
-		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;
+		pubc->timer.cb = &pubc_refresh_timer_cb;
+		pubc->timer.id = REFRESH_TIMER;
+		pubc->timer.user_data = pubc;
+		pjsip_endpt_schedule_timer( pubc->endpt, &pubc->timer, &delay);
+		pj_gettimeofday(&pubc->last_refresh);
+		pubc->next_refresh = pubc->last_refresh;
+		pubc->next_refresh.sec += delay.sec;
 	    }
 
@@ -583,19 +533,20 @@
 	/* Call callback. */
 	if (expiration == 0xFFFF) expiration = -1;
-	call_callback(regc, PJ_SUCCESS, tsx->status_code, 
+	call_callback(pubc, 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);
-
-    }
-
-    /* Delete the record if user destroy regc during the callback. */
-    if (regc->_delete_flag && regc->pending_tsx==0) {
-	pjsip_regc_destroy(regc);
-    }
-}
-
-PJ_DEF(pj_status_t) pjsip_regc_send(pjsip_regc *regc, pjsip_tx_data *tdata)
+		      rdata, expiration);
+
+    }
+
+    /* Delete the record if user destroy pubc during the callback. */
+    if (pubc->_delete_flag && pubc->pending_tsx==0) {
+	pjsip_publishc_destroy(pubc);
+    }
+}
+
+
+PJ_DEF(pj_status_t) pjsip_publishc_send(pjsip_publishc *pubc, 
+					pjsip_tx_data *tdata)
 {
     pj_status_t status;
@@ -604,6 +555,6 @@
 
     /* Make sure we don't have pending transaction. */
-    if (regc->pending_tsx) {
-	PJ_LOG(4,(THIS_FILE, "Unable to send request, regc has another "
+    if (pubc->pending_tsx) {
+	PJ_LOG(4,(THIS_FILE, "Unable to send request, pubc has another "
 			     "transaction pending"));
 	pjsip_tx_data_dec_ref( tdata );
@@ -615,5 +566,5 @@
 
     /* Increment CSeq */
-    cseq = ++regc->cseq_hdr->cseq;
+    cseq = ++pubc->cseq_hdr->cseq;
     cseq_hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
     cseq_hdr->cseq = cseq;
@@ -622,8 +573,9 @@
      * may be called even before send_request() returns!
      */
-    ++regc->pending_tsx;
-    status = pjsip_endpt_send_request(regc->endpt, tdata, -1, regc, &tsx_callback);
+    ++pubc->pending_tsx;
+    status = pjsip_endpt_send_request(pubc->endpt, tdata, -1, pubc, 
+				      &tsx_callback);
     if (status!=PJ_SUCCESS) {
-	--regc->pending_tsx;
+	--pubc->pending_tsx;
 	PJ_LOG(4,(THIS_FILE, "Error sending request, status=%d", status));
     }
