summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2006-08-15 20:26:34 +0000
committerBenny Prijono <bennylp@teluu.com>2006-08-15 20:26:34 +0000
commit540278de72f88da8853d86dc3b655fe9bb3013b5 (patch)
treeda69840039428b7daa2f1806d9d72eae13d51157
parentab77e4d8b4ddc20d6018d67c739e3317e4746c49 (diff)
Support for PUBLISH (RFC 3903):
- API BREAK: pjsua_pres_create_uac() API CHANGED!! Added options in the function, to allow creating SUBSCRIBE without ";id=" parameter in the Event header. - the generic event publication in pjsip-simple/publish.[hc] - split PIDF and X-PIDF body generation and parsing into pjsip-simple/presence_body.c. - allow NULL in module parameter in pjsip_endpt_add_capability() - added "--publish" option in PJSUA. - by default, PJSUA-LIB will not add ";id=" parameter in Event header in the SUBSCRIBE request since lots of server and user agents don't support this correctly. - Set version to 0.5.7.6. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@685 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjlib/src/pj/config.c2
-rw-r--r--pjsip-apps/src/pjsua/pjsua_app.c8
-rw-r--r--pjsip/build/Makefile3
-rw-r--r--pjsip/build/pjsip_simple.dsp6
-rw-r--r--pjsip/include/pjsip-simple/presence.h74
-rw-r--r--pjsip/include/pjsip-simple/publish.h25
-rw-r--r--pjsip/include/pjsip_simple.h1
-rw-r--r--pjsip/include/pjsua-lib/pjsua.h13
-rw-r--r--pjsip/include/pjsua-lib/pjsua_internal.h12
-rw-r--r--pjsip/src/pjsip-simple/presence.c205
-rw-r--r--pjsip/src/pjsip-simple/presence_body.c228
-rw-r--r--pjsip/src/pjsip-simple/publishc.c512
-rw-r--r--pjsip/src/pjsip/sip_endpoint.c6
-rw-r--r--pjsip/src/pjsua-lib/pjsua_acc.c7
-rw-r--r--pjsip/src/pjsua-lib/pjsua_core.c2
-rw-r--r--pjsip/src/pjsua-lib/pjsua_pres.c181
16 files changed, 798 insertions, 487 deletions
diff --git a/pjlib/src/pj/config.c b/pjlib/src/pj/config.c
index 369a2872..8a372524 100644
--- a/pjlib/src/pj/config.c
+++ b/pjlib/src/pj/config.c
@@ -21,7 +21,7 @@
#include <pj/ioqueue.h>
static const char *id = "config.c";
-const char *PJ_VERSION = "0.5.7.1";
+const char *PJ_VERSION = "0.5.7.6";
PJ_DEF(void) pj_dump_config(void)
{
diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c
index 5692e7ca..1ed3fe8c 100644
--- a/pjsip-apps/src/pjsua/pjsua_app.c
+++ b/pjsip-apps/src/pjsua/pjsua_app.c
@@ -101,6 +101,7 @@ static void usage(void)
puts (" --realm=string Set realm");
puts (" --username=string Set authentication username");
puts (" --password=string Set authentication password");
+ puts (" --publish Send presence PUBLISH for this account");
puts (" --next-cred Add another credentials");
puts ("");
puts ("SIP Account Control:");
@@ -258,7 +259,7 @@ static pj_status_t parse_args(int argc, char *argv[],
enum { OPT_CONFIG_FILE, OPT_LOG_FILE, OPT_LOG_LEVEL, OPT_APP_LOG_LEVEL,
OPT_HELP, OPT_VERSION, OPT_NULL_AUDIO,
OPT_LOCAL_PORT, OPT_PROXY, OPT_OUTBOUND_PROXY, OPT_REGISTRAR,
- OPT_REG_TIMEOUT, OPT_ID, OPT_CONTACT,
+ OPT_REG_TIMEOUT, OPT_PUBLISH, OPT_ID, OPT_CONTACT,
OPT_REALM, OPT_USERNAME, OPT_PASSWORD,
OPT_USE_STUN1, OPT_USE_STUN2,
OPT_ADD_BUDDY, OPT_OFFER_X_MS_MSG, OPT_NO_PRESENCE,
@@ -286,6 +287,7 @@ static pj_status_t parse_args(int argc, char *argv[],
{ "outbound", 1, 0, OPT_OUTBOUND_PROXY},
{ "registrar", 1, 0, OPT_REGISTRAR},
{ "reg-timeout",1, 0, OPT_REG_TIMEOUT},
+ { "publish", 0, 0, OPT_PUBLISH},
{ "id", 1, 0, OPT_ID},
{ "contact", 1, 0, OPT_CONTACT},
{ "realm", 1, 0, OPT_REALM},
@@ -479,6 +481,10 @@ static pj_status_t parse_args(int argc, char *argv[],
}
break;
+ case OPT_PUBLISH: /* publish */
+ cur_acc->publish_enabled = PJ_TRUE;
+ break;
+
case OPT_ID: /* id */
if (pjsua_verify_sip_url(pj_optarg) != 0) {
PJ_LOG(1,(THIS_FILE,
diff --git a/pjsip/build/Makefile b/pjsip/build/Makefile
index 24755553..6bdec74d 100644
--- a/pjsip/build/Makefile
+++ b/pjsip/build/Makefile
@@ -66,7 +66,8 @@ export PJSIP_UA_CFLAGS += $(_CFLAGS)
#
export PJSIP_SIMPLE_SRCDIR = ../src/pjsip-simple
export PJSIP_SIMPLE_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
- errno.o evsub.o evsub_msg.o iscomposing.o pidf.o presence.o \
+ errno.o evsub.o evsub_msg.o iscomposing.o \
+ pidf.o presence.o presence_body.o publishc.o \
xpidf.o
export PJSIP_SIMPLE_CFLAGS += $(_CFLAGS)
diff --git a/pjsip/build/pjsip_simple.dsp b/pjsip/build/pjsip_simple.dsp
index 3df884ea..c5523fcc 100644
--- a/pjsip/build/pjsip_simple.dsp
+++ b/pjsip/build/pjsip_simple.dsp
@@ -109,14 +109,16 @@ SOURCE="..\src\pjsip-simple\presence.c"
# End Source File
# Begin Source File
+SOURCE="..\src\pjsip-simple\presence_body.c"
+# End Source File
+# Begin Source File
+
SOURCE="..\src\pjsip-simple\publishc.c"
!IF "$(CFG)" == "pjsip_simple - Win32 Release"
!ELSEIF "$(CFG)" == "pjsip_simple - Win32 Debug"
-# PROP Exclude_From_Build 1
-
!ENDIF
# End Source File
diff --git a/pjsip/include/pjsip-simple/presence.h b/pjsip/include/pjsip-simple/presence.h
index ee2805f4..668b723c 100644
--- a/pjsip/include/pjsip-simple/presence.h
+++ b/pjsip/include/pjsip-simple/presence.h
@@ -103,6 +103,8 @@ typedef struct pjsip_pres_status pjsip_pres_status;
* @param dlg The underlying dialog to use.
* @param user_cb Pointer to callbacks to receive presence subscription
* events.
+ * @param options Option flags. Currently only PJSIP_EVSUB_NO_EVENT_ID
+ * is recognized.
* @param p_evsub Pointer to receive the presence subscription
* session.
*
@@ -110,6 +112,7 @@ typedef struct pjsip_pres_status pjsip_pres_status;
*/
PJ_DECL(pj_status_t) pjsip_pres_create_uac( pjsip_dialog *dlg,
const pjsip_evsub_user *user_cb,
+ unsigned options,
pjsip_evsub **p_evsub );
@@ -265,6 +268,77 @@ PJ_DECL(pj_status_t) pjsip_pres_set_status( pjsip_evsub *sub,
/**
+ * This is a utility function to create PIDF message body from PJSIP
+ * presence status (pjsip_pres_status).
+ *
+ * @param pool The pool to allocate memory for the message body.
+ * @param status Presence status to be converted into PIDF message
+ * body.
+ * @param entity The entity ID, which normally is equal to the
+ * presentity ID publishing this presence info.
+ * @param p_body Pointer to receive the SIP message body.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_pres_create_pidf( pj_pool_t *pool,
+ const pjsip_pres_status *status,
+ const pj_str_t *entity,
+ pjsip_msg_body **p_body );
+
+
+/**
+ * This is a utility function to create X-PIDF message body from PJSIP
+ * presence status (pjsip_pres_status).
+ *
+ * @param pool The pool to allocate memory for the message body.
+ * @param status Presence status to be converted into X-PIDF message
+ * body.
+ * @param entity The entity ID, which normally is equal to the
+ * presentity ID publishing this presence info.
+ * @param p_body Pointer to receive the SIP message body.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_pres_create_xpidf(pj_pool_t *pool,
+ const pjsip_pres_status *status,
+ const pj_str_t *entity,
+ pjsip_msg_body **p_body );
+
+
+
+/**
+ * This is a utility function to parse PIDF body into PJSIP presence status.
+ *
+ * @param rdata The incoming SIP message containing the PIDF body.
+ * @param pool Pool to allocate memory to copy the strings into
+ * the presence status structure.
+ * @param status The presence status to be initialized.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_pres_parse_pidf(pjsip_rx_data *rdata,
+ pj_pool_t *pool,
+ pjsip_pres_status *status);
+
+
+
+/**
+ * This is a utility function to parse X-PIDF body into PJSIP presence status.
+ *
+ * @param rdata The incoming SIP message containing the X-PIDF body.
+ * @param pool Pool to allocate memory to copy the strings into
+ * the presence status structure.
+ * @param status The presence status to be initialized.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_pres_parse_xpidf(pjsip_rx_data *rdata,
+ pj_pool_t *pool,
+ pjsip_pres_status *status);
+
+
+
+/**
* @}
*/
diff --git a/pjsip/include/pjsip-simple/publish.h b/pjsip/include/pjsip-simple/publish.h
index 141bbf6a..bebc4d97 100644
--- a/pjsip/include/pjsip-simple/publish.h
+++ b/pjsip/include/pjsip-simple/publish.h
@@ -16,14 +16,16 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef __PJSIP_SIMPLE_PRESENCE_H__
-#define __PJSIP_SIMPLE_PRESENCE_H__
+#ifndef __PJSIP_SIMPLE_PUBLISH_H__
+#define __PJSIP_SIMPLE_PUBLISH_H__
/**
* @file publish.h
* @brief SIP Extension for Event State Publication (PUBLISH, RFC 3903)
*/
+#include <pjsip/sip_util.h>
+
PJ_BEGIN_DECL
@@ -38,6 +40,11 @@ PJ_BEGIN_DECL
Extension for Event State Publication (PUBLISH) as defined by RFC 3856.
*/
+/**
+ * The SIP PUBLISH method constant.
+ */
+extern const pjsip_method pjsip_publish_method;
+
/*****************************************************************************
* @defgroup PJSIP_SIMPLE_PUBLISH_CLIENT SIP Event State Publication Client
@@ -77,11 +84,22 @@ struct pjsip_publishc_cbparam
typedef void pjsip_publishc_cb(struct pjsip_publishc_cbparam *param);
+/**
+ * Initialize client publication module.
+ *
+ * @param endpt SIP endpoint.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_publishc_init_module(pjsip_endpoint *endpt);
+
+
/**
* Create client publication structure.
*
* @param endpt Endpoint, used to allocate pool from.
+ * @param options Option flags.
* @param token Opaque data to be associated with the client publication.
* @param cb Pointer to callback function to receive publication status.
* @param p_pubc Pointer to receive client publication structure.
@@ -89,6 +107,7 @@ typedef void pjsip_publishc_cb(struct pjsip_publishc_cbparam *param);
* @return PJ_SUCCESS on success.
*/
PJ_DECL(pj_status_t) pjsip_publishc_create( pjsip_endpoint *endpt,
+ unsigned options,
void *token,
pjsip_publishc_cb *cb,
pjsip_publishc **p_pubc);
@@ -248,5 +267,5 @@ PJ_DECL(pj_status_t) pjsip_publishc_send(pjsip_publishc *pubc,
PJ_END_DECL
-#endif /* __PJSIP_SIMPLE_PRESENCE_H__ */
+#endif /* __PJSIP_SIMPLE_PUBLISH_H__ */
diff --git a/pjsip/include/pjsip_simple.h b/pjsip/include/pjsip_simple.h
index 97af4bc4..0230426f 100644
--- a/pjsip/include/pjsip_simple.h
+++ b/pjsip/include/pjsip_simple.h
@@ -38,6 +38,7 @@
#include <pjsip-simple/iscomposing.h>
#include <pjsip-simple/presence.h>
#include <pjsip-simple/pidf.h>
+#include <pjsip-simple/publish.h>
#include <pjsip-simple/xpidf.h>
#endif /* __PJSIP_SIMPLE_H__ */
diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index 1ca2ad21..2ffea4cc 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -1003,6 +1003,14 @@ PJ_DECL(pj_status_t) pjsua_transport_close( pjsua_transport_id id,
/**
+ * Default PUBLISH expiration
+ */
+#ifndef PJSUA_PUBLISH_EXPIRATION
+# define PJSUA_PUBLISH_EXPIRATION 600
+#endif
+
+
+/**
* Account configuration.
*/
typedef struct pjsua_acc_config
@@ -1024,6 +1032,11 @@ typedef struct pjsua_acc_config
*/
pj_str_t reg_uri;
+ /**
+ * Publish presence?
+ */
+ pj_bool_t publish_enabled;
+
/**
* Optional URI to be put as Contact for this account. It is recommended
* that this field is left empty, so that the value will be calculated
diff --git a/pjsip/include/pjsua-lib/pjsua_internal.h b/pjsip/include/pjsua-lib/pjsua_internal.h
index c862219f..8b1002b4 100644
--- a/pjsip/include/pjsua-lib/pjsua_internal.h
+++ b/pjsip/include/pjsua-lib/pjsua_internal.h
@@ -97,6 +97,8 @@ typedef struct pjsua_acc
pj_bool_t online_status; /**< Our online status. */
pjsua_srv_pres pres_srv_list; /**< Server subscription list. */
+ pjsip_publishc *publish_sess; /**< Client publication session. */
+ pj_bool_t publish_state; /**< Last published online status */
} pjsua_acc;
@@ -255,8 +257,13 @@ PJ_INLINE(pjsua_im_data*) pjsua_im_data_dup(pj_pool_t *pool,
}
+#if 0
#define PJSUA_LOCK() pj_mutex_lock(pjsua_var.mutex);
#define PJSUA_UNLOCK() pj_mutex_unlock(pjsua_var.mutex);
+#else
+#define PJSUA_LOCK()
+#define PJSUA_UNLOCK()
+#endif
@@ -286,6 +293,11 @@ void pjsua_pres_refresh(void);
void pjsua_pres_shutdown(void);
/**
+ * Init presence for aoocunt.
+ */
+pj_status_t pjsua_pres_init_acc(int acc_id);
+
+/**
* Terminate server subscription for the account
*/
void pjsua_pres_delete_acc(int acc_id);
diff --git a/pjsip/src/pjsip-simple/presence.c b/pjsip/src/pjsip-simple/presence.c
index 9694c81c..5b919ebd 100644
--- a/pjsip/src/pjsip-simple/presence.c
+++ b/pjsip/src/pjsip-simple/presence.c
@@ -179,6 +179,7 @@ PJ_DEF(pjsip_module*) pjsip_pres_instance(void)
*/
PJ_DEF(pj_status_t) pjsip_pres_create_uac( pjsip_dialog *dlg,
const pjsip_evsub_user *user_cb,
+ unsigned options,
pjsip_evsub **p_evsub )
{
pj_status_t status;
@@ -190,7 +191,8 @@ PJ_DEF(pj_status_t) pjsip_pres_create_uac( pjsip_dialog *dlg,
pjsip_dlg_inc_lock(dlg);
/* Create event subscription */
- status = pjsip_evsub_create_uac( dlg, &pres_user, &STR_PRESENCE, 0, &sub);
+ status = pjsip_evsub_create_uac( dlg, &pres_user, &STR_PRESENCE,
+ options, &sub);
if (status != PJ_SUCCESS)
goto on_return;
@@ -412,140 +414,34 @@ PJ_DEF(pj_status_t) pjsip_pres_set_status( pjsip_evsub *sub,
/*
- * Create PIDF document based on the presence info.
+ * Create message body.
*/
-static pjpidf_pres* pres_create_pidf( pj_pool_t *pool,
- pjsip_pres *pres )
+static pj_status_t pres_create_msg_body( pjsip_pres *pres,
+ pjsip_tx_data *tdata)
{
- pjpidf_pres *pidf;
- unsigned i;
pj_str_t entity;
/* Get publisher URI */
- entity.ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
+ entity.ptr = pj_pool_alloc(tdata->pool, PJSIP_MAX_URL_SIZE);
entity.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI,
pres->dlg->local.info->uri,
entity.ptr, PJSIP_MAX_URL_SIZE);
if (entity.slen < 1)
- return NULL;
-
- /* Create <presence>. */
- pidf = pjpidf_create(pool, &entity);
-
- /* Create <tuple> */
- for (i=0; i<pres->status.info_cnt; ++i) {
-
- pjpidf_tuple *pidf_tuple;
- pjpidf_status *pidf_status;
-
- /* Add tuple id. */
- pidf_tuple = pjpidf_pres_add_tuple(pool, pidf,
- &pres->status.info[i].id);
-
- /* Set <contact> */
- if (pres->status.info[i].contact.slen)
- pjpidf_tuple_set_contact(pool, pidf_tuple,
- &pres->status.info[i].contact);
-
-
- /* Set basic status */
- pidf_status = pjpidf_tuple_get_status(pidf_tuple);
- pjpidf_status_set_basic_open(pidf_status,
- pres->status.info[i].basic_open);
- }
-
- return pidf;
-}
-
-
-/*
- * Create XPIDF document based on the presence info.
- */
-static pjxpidf_pres* pres_create_xpidf( pj_pool_t *pool,
- pjsip_pres *pres )
-{
- /* Note: PJSIP implementation of XPIDF is not complete!
- */
- pjxpidf_pres *xpidf;
- pj_str_t publisher_uri;
-
- PJ_LOG(4,(THIS_FILE, "Warning: XPIDF format is not fully supported "
- "by PJSIP"));
-
- publisher_uri.ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
- publisher_uri.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI,
- pres->dlg->local.info->uri,
- publisher_uri.ptr,
- PJSIP_MAX_URL_SIZE);
- if (publisher_uri.slen < 1)
- return NULL;
-
- /* Create XPIDF document. */
- xpidf = pjxpidf_create(pool, &publisher_uri);
-
- /* Set basic status. */
- if (pres->status.info_cnt > 0)
- pjxpidf_set_status( xpidf, pres->status.info[0].basic_open);
- else
- pjxpidf_set_status( xpidf, PJ_FALSE);
-
- return xpidf;
-}
-
-
-/*
- * Function to print XML message body.
- */
-static int pres_print_body(struct pjsip_msg_body *msg_body,
- char *buf, pj_size_t size)
-{
- return pj_xml_print(msg_body->data, buf, size, PJ_TRUE);
-}
-
+ return PJ_ENOMEM;
-/*
- * Function to clone XML document.
- */
-static void* xml_clone_data(pj_pool_t *pool, const void *data, unsigned len)
-{
- PJ_UNUSED_ARG(len);
- return pj_xml_clone( pool, data);
-}
-
-
-/*
- * Create message body.
- */
-static pj_status_t pres_create_msg_body( pjsip_pres *pres,
- pjsip_tx_data *tdata)
-{
- pjsip_msg_body *body;
-
- body = pj_pool_zalloc(tdata->pool, sizeof(pjsip_msg_body));
-
if (pres->content_type == CONTENT_TYPE_PIDF) {
- body->data = pres_create_pidf(tdata->pool, pres);
- body->content_type.type = pj_str("application");
- body->content_type.subtype = pj_str("pidf+xml");
+ return pjsip_pres_create_pidf(tdata->pool, &pres->status,
+ &entity, &tdata->msg->body);
} else if (pres->content_type == CONTENT_TYPE_XPIDF) {
- body->data = pres_create_xpidf(tdata->pool, pres);
- body->content_type.type = pj_str("application");
- body->content_type.subtype = pj_str("xpidf+xml");
+ return pjsip_pres_create_xpidf(tdata->pool, &pres->status,
+ &entity, &tdata->msg->body);
} else {
return PJSIP_SIMPLE_EBADCONTENT;
}
-
-
- body->print_body = &pres_print_body;
- body->clone_data = &xml_clone_data;
-
- tdata->msg->body = body;
-
- return PJ_SUCCESS;
}
@@ -722,77 +618,6 @@ static void pres_on_evsub_rx_refresh( pjsip_evsub *sub,
}
}
-/*
- * Parse PIDF to info.
- */
-static pj_status_t pres_parse_pidf( pjsip_pres *pres,
- pjsip_rx_data *rdata,
- pjsip_pres_status *pres_status)
-{
- pjpidf_pres *pidf;
- pjpidf_tuple *pidf_tuple;
-
- pidf = pjpidf_parse(rdata->tp_info.pool,
- rdata->msg_info.msg->body->data,
- rdata->msg_info.msg->body->len);
- if (pidf == NULL)
- return PJSIP_SIMPLE_EBADPIDF;
-
- pres_status->info_cnt = 0;
-
- pidf_tuple = pjpidf_pres_get_first_tuple(pidf);
- while (pidf_tuple) {
- pjpidf_status *pidf_status;
-
- pj_strdup(pres->dlg->pool,
- &pres_status->info[pres_status->info_cnt].id,
- pjpidf_tuple_get_id(pidf_tuple));
-
- pj_strdup(pres->dlg->pool,
- &pres_status->info[pres_status->info_cnt].contact,
- pjpidf_tuple_get_contact(pidf_tuple));
-
- pidf_status = pjpidf_tuple_get_status(pidf_tuple);
- if (pidf_status) {
- pres_status->info[pres_status->info_cnt].basic_open =
- pjpidf_status_is_basic_open(pidf_status);
- } else {
- pres_status->info[pres_status->info_cnt].basic_open = PJ_FALSE;
- }
-
- pidf_tuple = pjpidf_pres_get_next_tuple( pidf, pidf_tuple );
- pres_status->info_cnt++;
- }
-
- return PJ_SUCCESS;
-}
-
-/*
- * Parse XPIDF info.
- */
-static pj_status_t pres_parse_xpidf( pjsip_pres *pres,
- pjsip_rx_data *rdata,
- pjsip_pres_status *pres_status)
-{
- pjxpidf_pres *xpidf;
-
- xpidf = pjxpidf_parse(rdata->tp_info.pool,
- rdata->msg_info.msg->body->data,
- rdata->msg_info.msg->body->len);
- if (xpidf == NULL)
- return PJSIP_SIMPLE_EBADXPIDF;
-
- pres_status->info_cnt = 1;
-
- pj_strdup(pres->dlg->pool,
- &pres_status->info[0].contact,
- pjxpidf_get_uri(xpidf));
- pres_status->info[0].basic_open = pjxpidf_get_status(xpidf);
- pres_status->info[0].id.slen = 0;
-
- return PJ_SUCCESS;
-}
-
/*
* Process the content of incoming NOTIFY request and update temporary
@@ -836,13 +661,15 @@ static pj_status_t pres_process_rx_notify( pjsip_pres *pres,
if (pj_stricmp(&ctype_hdr->media.type, &STR_APPLICATION)==0 &&
pj_stricmp(&ctype_hdr->media.subtype, &STR_PIDF_XML)==0)
{
- status = pres_parse_pidf( pres, rdata, &pres->tmp_status);
+ status = pjsip_pres_parse_pidf( rdata, pres->dlg->pool,
+ &pres->tmp_status);
}
else
if (pj_stricmp(&ctype_hdr->media.type, &STR_APPLICATION)==0 &&
pj_stricmp(&ctype_hdr->media.subtype, &STR_XPIDF_XML)==0)
{
- status = pres_parse_xpidf( pres, rdata, &pres->tmp_status);
+ status = pjsip_pres_parse_xpidf( rdata, pres->dlg->pool,
+ &pres->tmp_status);
}
else
{
diff --git a/pjsip/src/pjsip-simple/presence_body.c b/pjsip/src/pjsip-simple/presence_body.c
new file mode 100644
index 00000000..c67890c1
--- /dev/null
+++ b/pjsip/src/pjsip-simple/presence_body.c
@@ -0,0 +1,228 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pjsip-simple/presence.h>
+#include <pjsip-simple/errno.h>
+#include <pjsip/sip_msg.h>
+#include <pjsip/sip_transport.h>
+#include <pj/guid.h>
+#include <pj/log.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+
+
+#define THIS_FILE "presence_body.c"
+
+
+static const pj_str_t STR_APPLICATION = { "application", 11 };
+static const pj_str_t STR_PIDF_XML = { "pidf+xml", 8 };
+static const pj_str_t STR_XPIDF_XML = { "xpidf+xml", 9 };
+
+
+
+
+/*
+ * Function to print XML message body.
+ */
+static int pres_print_body(struct pjsip_msg_body *msg_body,
+ char *buf, pj_size_t size)
+{
+ return pj_xml_print(msg_body->data, buf, size, PJ_TRUE);
+}
+
+
+/*
+ * Function to clone XML document.
+ */
+static void* xml_clone_data(pj_pool_t *pool, const void *data, unsigned len)
+{
+ PJ_UNUSED_ARG(len);
+ return pj_xml_clone( pool, data);
+}
+
+
+/*
+ * This is a utility function to create PIDF message body from PJSIP
+ * presence status (pjsip_pres_status).
+ */
+PJ_DEF(pj_status_t) pjsip_pres_create_pidf( pj_pool_t *pool,
+ const pjsip_pres_status *status,
+ const pj_str_t *entity,
+ pjsip_msg_body **p_body )
+{
+ pjpidf_pres *pidf;
+ pjsip_msg_body *body;
+ unsigned i;
+
+ /* Create <presence>. */
+ pidf = pjpidf_create(pool, entity);
+
+ /* Create <tuple> */
+ for (i=0; i<status->info_cnt; ++i) {
+
+ pjpidf_tuple *pidf_tuple;
+ pjpidf_status *pidf_status;
+ pj_str_t id;
+
+ /* Add tuple id. */
+ if (status->info[i].id.slen == 0) {
+ pj_create_unique_string(pool, &id);
+ } else {
+ id = status->info[i].id;
+ }
+
+ pidf_tuple = pjpidf_pres_add_tuple(pool, pidf, &id);
+
+ /* Set <contact> */
+ if (status->info[i].contact.slen)
+ pjpidf_tuple_set_contact(pool, pidf_tuple,
+ &status->info[i].contact);
+
+
+ /* Set basic status */
+ pidf_status = pjpidf_tuple_get_status(pidf_tuple);
+ pjpidf_status_set_basic_open(pidf_status,
+ status->info[i].basic_open);
+ }
+
+ body = pj_pool_zalloc(pool, sizeof(pjsip_msg_body));
+ body->data = pidf;
+ body->content_type.type = STR_APPLICATION;
+ body->content_type.subtype = STR_PIDF_XML;
+ body->print_body = &pres_print_body;
+ body->clone_data = &xml_clone_data;
+
+ *p_body = body;
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * This is a utility function to create X-PIDF message body from PJSIP
+ * presence status (pjsip_pres_status).
+ */
+PJ_DEF(pj_status_t) pjsip_pres_create_xpidf( pj_pool_t *pool,
+ const pjsip_pres_status *status,
+ const pj_str_t *entity,
+ pjsip_msg_body **p_body )
+{
+ /* Note: PJSIP implementation of XPIDF is not complete!
+ */
+ pjxpidf_pres *xpidf;
+ pjsip_msg_body *body;
+
+ PJ_LOG(4,(THIS_FILE, "Warning: XPIDF format is not fully supported "
+ "by PJSIP"));
+
+ /* Create XPIDF document. */
+ xpidf = pjxpidf_create(pool, entity);
+
+ /* Set basic status. */
+ if (status->info_cnt > 0)
+ pjxpidf_set_status( xpidf, status->info[0].basic_open);
+ else
+ pjxpidf_set_status( xpidf, PJ_FALSE);
+
+ body = pj_pool_zalloc(pool, sizeof(pjsip_msg_body));
+ body->data = xpidf;
+ body->content_type.type = STR_APPLICATION;
+ body->content_type.subtype = STR_XPIDF_XML;
+ body->print_body = &pres_print_body;
+ body->clone_data = &xml_clone_data;
+
+ *p_body = body;
+
+ return PJ_SUCCESS;
+}
+
+
+
+/*
+ * This is a utility function to parse PIDF body into PJSIP presence status.
+ */
+PJ_DEF(pj_status_t) pjsip_pres_parse_pidf( pjsip_rx_data *rdata,
+ pj_pool_t *pool,
+ pjsip_pres_status *pres_status)
+{
+ pjpidf_pres *pidf;
+ pjpidf_tuple *pidf_tuple;
+
+ pidf = pjpidf_parse(rdata->tp_info.pool,
+ rdata->msg_info.msg->body->data,
+ rdata->msg_info.msg->body->len);
+ if (pidf == NULL)
+ return PJSIP_SIMPLE_EBADPIDF;
+
+ pres_status->info_cnt = 0;
+
+ pidf_tuple = pjpidf_pres_get_first_tuple(pidf);
+ while (pidf_tuple) {
+ pjpidf_status *pidf_status;
+
+ pj_strdup(pool,
+ &pres_status->info[pres_status->info_cnt].id,
+ pjpidf_tuple_get_id(pidf_tuple));
+
+ pj_strdup(pool,
+ &pres_status->info[pres_status->info_cnt].contact,
+ pjpidf_tuple_get_contact(pidf_tuple));
+
+ pidf_status = pjpidf_tuple_get_status(pidf_tuple);
+ if (pidf_status) {
+ pres_status->info[pres_status->info_cnt].basic_open =
+ pjpidf_status_is_basic_open(pidf_status);
+ } else {
+ pres_status->info[pres_status->info_cnt].basic_open = PJ_FALSE;
+ }
+
+ pidf_tuple = pjpidf_pres_get_next_tuple( pidf, pidf_tuple );
+ pres_status->info_cnt++;
+ }
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * This is a utility function to parse X-PIDF body into PJSIP presence status.
+ */
+PJ_DEF(pj_status_t) pjsip_pres_parse_xpidf(pjsip_rx_data *rdata,
+ pj_pool_t *pool,
+ pjsip_pres_status *pres_status)
+{
+ pjxpidf_pres *xpidf;
+
+ xpidf = pjxpidf_parse(rdata->tp_info.pool,
+ rdata->msg_info.msg->body->data,
+ rdata->msg_info.msg->body->len);
+ if (xpidf == NULL)
+ return PJSIP_SIMPLE_EBADXPIDF;
+
+ pres_status->info_cnt = 1;
+
+ pj_strdup(pool,
+ &pres_status->info[0].contact,
+ pjxpidf_get_uri(xpidf));
+ pres_status->info[0].basic_open = pjxpidf_get_status(xpidf);
+ pres_status->info[0].id.slen = 0;
+
+ return PJ_SUCCESS;
+}
+
+
diff --git a/pjsip/src/pjsip-simple/publishc.c b/pjsip/src/pjsip-simple/publishc.c
index b61fa469..5a0df963 100644
--- a/pjsip/src/pjsip-simple/publishc.c
+++ b/pjsip/src/pjsip-simple/publishc.c
@@ -16,32 +16,41 @@
* along with this program; if not, write to the Free Software
* 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_transaction.h>
+#include <pjsip/sip_errno.h>
#include <pjsip/sip_event.h>
+#include <pjsip/sip_msg.h>
+#include <pjsip/sip_transaction.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;
pjsip_endpoint *endpt;
@@ -49,291 +58,228 @@ struct pjsip_regc
int pending_tsx;
void *token;
- pjsip_regc_cb *cb;
+ pjsip_publishc_cb *cb;
- pj_str_t str_srv_url;
- pjsip_uri *srv_url;
+ pj_str_t event;
+ pj_str_t str_target_uri;
+ pjsip_uri *target_uri;
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;
- 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;
/* Authorization sessions. */
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;
};
-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);
+ PJ_ASSERT_RETURN(endpt && cb && p_pubc, PJ_EINVAL);
+ PJ_ASSERT_RETURN(options == 0, PJ_EINVAL);
- pool = pjsip_endpt_create_pool(endpt, "regc%p", 1024, 1024);
+ 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));
+ pubc = pj_pool_zalloc(pool, sizeof(struct pjsip_publishc));
- 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;
+ pubc->pool = pool;
+ pubc->endpt = endpt;
+ pubc->token = token;
+ pubc->cb = cb;
+ pubc->expires = PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED;
- status = pjsip_auth_clt_init(&regc->auth_sess, endpt, regc->pool, 0);
+ 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;
+ *p_pubc = pubc;
return PJ_SUCCESS;
}
-PJ_DEF(pj_status_t) pjsip_regc_destroy(pjsip_regc *regc)
+PJ_DEF(pj_status_t) pjsip_publishc_destroy(pjsip_publishc *pubc)
{
- PJ_ASSERT_RETURN(regc, PJ_EINVAL);
+ PJ_ASSERT_RETURN(pubc, PJ_EINVAL);
- if (regc->pending_tsx) {
- regc->_delete_flag = 1;
- regc->cb = NULL;
+ 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;
+ pjsip_endpt_release_pool(pubc->endpt, pubc->pool);
}
return PJ_SUCCESS;
}
-PJ_DEF(pj_pool_t*) pjsip_regc_get_pool(pjsip_regc *regc)
+PJ_DEF(pj_pool_t*) pjsip_publishc_get_pool(pjsip_publishc *pubc)
{
- return regc->pool;
+ return pubc->pool;
}
-static void set_expires( pjsip_regc *regc, pj_uint32_t expires)
+static void set_expires( pjsip_publishc *pubc, pj_uint32_t expires)
{
- if (expires != regc->expires) {
- regc->expires_hdr = pjsip_expires_hdr_create(regc->pool, 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++ = ' ';
- }
+ pubc->expires_hdr = NULL;
}
-
- /* 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)
+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. */
return PJ_SUCCESS;
}
-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_ASSERT_RETURN(pubc && count && cred, PJ_EINVAL);
+ return pjsip_auth_clt_set_credentials(&pubc->auth_sess, count, cred);
}
-PJ_DEF(pj_status_t) pjsip_regc_set_route_set( pjsip_regc *regc,
+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_ASSERT_RETURN(pubc && route_set, PJ_EINVAL);
- pj_list_init(&regc->route_set);
+ 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;
}
return PJ_SUCCESS;
}
-static pj_status_t create_request(pjsip_regc *regc,
+static pj_status_t create_request(pjsip_publishc *pubc,
pjsip_tx_data **p_tdata)
{
+ 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);
if (status != PJ_SUCCESS)
return status;
/* 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;
@@ -341,8 +287,8 @@ static pj_status_t create_request(pjsip_regc *regc,
if (!route_pos)
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);
route_pos = new_hdr;
@@ -350,37 +296,59 @@ static pj_status_t create_request(pjsip_regc *regc,
}
}
+ /* 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;
return PJ_SUCCESS;
}
-PJ_DEF(pj_status_t) pjsip_regc_register(pjsip_regc *regc, pj_bool_t autoreg,
- pjsip_tx_data **p_tdata)
+PJ_DEF(pj_status_t) pjsip_publishc_publish(pjsip_publishc *pubc,
+ pj_bool_t auto_refresh,
+ pjsip_tx_data **p_tdata)
{
- pjsip_msg *msg;
pj_status_t status;
pjsip_tx_data *tdata;
- PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);
+ PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
- status = create_request(regc, &tdata);
+ 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);
+ /* Add Expires header */
+ if (pubc->expires_hdr) {
+ pjsip_hdr *dup;
- if (regc->timer.id != 0) {
- pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
- regc->timer.id = 0;
+ dup = pjsip_hdr_shallow_clone(tdata->pool, pubc->expires_hdr);
+ if (dup)
+ pjsip_msg_add_hdr(tdata->msg, dup);
}
- regc->auto_reg = autoreg;
+ /* 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 */
*p_tdata = tdata;
@@ -388,111 +356,99 @@ PJ_DEF(pj_status_t) pjsip_regc_register(pjsip_regc *regc, pj_bool_t autoreg,
}
-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;
+ pjsip_expires_hdr *expires;
pj_status_t status;
- PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);
+ PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
- if (regc->timer.id != 0) {
- pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
- regc->timer.id = 0;
+ if (pubc->timer.id != 0) {
+ pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer);
+ pubc->timer.id = 0;
}
- status = create_request(regc, &tdata);
+ 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;
return PJ_SUCCESS;
}
-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_DEF(pj_status_t) pjsip_publishc_update_expires( pjsip_publishc *pubc,
+ pj_uint32_t expires )
{
- PJ_ASSERT_RETURN(regc, PJ_EINVAL);
- set_expires( regc, expires );
+ PJ_ASSERT_RETURN(pubc, PJ_EINVAL);
+ set_expires( pubc, 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[])
+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_regc_cbparam cbparam;
+ struct pjsip_publishc_cbparam cbparam;
- cbparam.regc = regc;
- cbparam.token = regc->token;
+ 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);
+ (*pubc->cb)(&cbparam);
}
-static void regc_refresh_timer_cb( pj_timer_heap_t *timer_heap,
+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;
PJ_UNUSED_ARG(timer_heap);
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);
}
if (status != PJ_SUCCESS) {
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);
}
}
static void tsx_callback(void *token, pjsip_event *event)
{
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;
+ pj_assert(pubc->pending_tsx > 0);
+ --pubc->pending_tsx;
- /* If registration data has been deleted by user then remove registration
+ /* 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 */
;
@@ -503,75 +459,69 @@ static void tsx_callback(void *token, pjsip_event *event)
pjsip_rx_data *rdata = event->body.tsx_state.src.rdata;
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,
&tdata);
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);
}
return;
} 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);
if (expires)
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;
}
} else {
@@ -582,29 +532,30 @@ static void tsx_callback(void *token, pjsip_event *event)
/* 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);
+ rdata, expiration);
}
- /* Delete the record if user destroy regc during the callback. */
- if (regc->_delete_flag && regc->pending_tsx==0) {
- pjsip_regc_destroy(regc);
+ /* 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_regc_send(pjsip_regc *regc, pjsip_tx_data *tdata)
+
+PJ_DEF(pj_status_t) pjsip_publishc_send(pjsip_publishc *pubc,
+ pjsip_tx_data *tdata)
{
pj_status_t status;
pjsip_cseq_hdr *cseq_hdr;
pj_uint32_t cseq;
/* 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 );
return PJSIP_EBUSY;
@@ -614,17 +565,18 @@ PJ_DEF(pj_status_t) pjsip_regc_send(pjsip_regc *regc, pjsip_tx_data *tdata)
pjsip_tx_data_invalidate_msg(tdata);
/* 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;
/* Increment pending transaction first, since transaction callback
* 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));
}
diff --git a/pjsip/src/pjsip/sip_endpoint.c b/pjsip/src/pjsip/sip_endpoint.c
index aedab9d7..1fa39831 100644
--- a/pjsip/src/pjsip/sip_endpoint.c
+++ b/pjsip/src/pjsip/sip_endpoint.c
@@ -333,15 +333,15 @@ PJ_DEF(pj_status_t) pjsip_endpt_add_capability( pjsip_endpoint *endpt,
pjsip_generic_array_hdr *hdr;
unsigned i;
+ PJ_UNUSED_ARG(mod);
+
/* Check arguments. */
- PJ_ASSERT_RETURN(endpt!=NULL && mod!=NULL && count>0 && tags, PJ_EINVAL);
+ PJ_ASSERT_RETURN(endpt!=NULL && count>0 && tags, PJ_EINVAL);
PJ_ASSERT_RETURN(htype==PJSIP_H_ACCEPT ||
htype==PJSIP_H_ALLOW ||
htype==PJSIP_H_SUPPORTED,
PJ_EINVAL);
- PJ_UNUSED_ARG(mod);
-
/* Find the header. */
hdr = (pjsip_generic_array_hdr*) pjsip_endpt_get_capability(endpt,
htype, hname);
diff --git a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c
index 7860c33f..d545bdfb 100644
--- a/pjsip/src/pjsua-lib/pjsua_acc.c
+++ b/pjsip/src/pjsua-lib/pjsua_acc.c
@@ -98,6 +98,7 @@ static pj_status_t initialize_acc(unsigned acc_id)
pjsua_acc *acc = &pjsua_var.acc[acc_id];
pjsip_name_addr *name_addr;
pjsip_sip_uri *sip_uri, *sip_reg_uri;
+ pj_status_t status;
unsigned i;
/* Need to parse local_uri to get the elements: */
@@ -220,8 +221,10 @@ static pj_status_t initialize_acc(unsigned acc_id)
acc->cred[acc->cred_cnt++] = pjsua_var.ua_cfg.cred_info[i];
}
- /* Init presence subscription */
- pj_list_init(&acc->pres_srv_list);
+ status = pjsua_pres_init_acc(acc_id);
+ if (status != PJ_SUCCESS)
+ return status;
+
/* Mark account as valid */
pjsua_var.acc[acc_id].valid = PJ_TRUE;
diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
index 9c011b84..c9bd2482 100644
--- a/pjsip/src/pjsua-lib/pjsua_core.c
+++ b/pjsip/src/pjsua-lib/pjsua_core.c
@@ -524,6 +524,8 @@ PJ_DEF(pj_status_t) pjsua_init( const pjsua_config *ua_cfg,
status = pjsip_pres_init_module( pjsua_var.endpt, pjsip_evsub_instance());
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+ /* Init PUBLISH module */
+ pjsip_publishc_init_module(pjsua_var.endpt);
/* Init xfer/REFER module */
status = pjsip_xfer_init_module( pjsua_var.endpt );
diff --git a/pjsip/src/pjsua-lib/pjsua_pres.c b/pjsip/src/pjsua-lib/pjsua_pres.c
index ceb1b762..b3205cc5 100644
--- a/pjsip/src/pjsua-lib/pjsua_pres.c
+++ b/pjsip/src/pjsua-lib/pjsua_pres.c
@@ -566,14 +566,163 @@ static pj_bool_t pres_on_rx_request(pjsip_rx_data *rdata)
}
+/*
+ * Client presence publication callback.
+ */
+static void publish_cb(struct pjsip_publishc_cbparam *param)
+{
+ pjsua_acc *acc = param->token;
+
+ if (param->code/100 != 2 || param->status != PJ_SUCCESS) {
+ if (param->status != PJ_SUCCESS) {
+ char errmsg[PJ_ERR_MSG_SIZE];
+
+ pj_strerror(param->status, errmsg, sizeof(errmsg));
+ PJ_LOG(1,(THIS_FILE,
+ "Client publication (PUBLISH) failed, status=%d, msg=%s",
+ param->status, errmsg));
+ } else {
+ PJ_LOG(1,(THIS_FILE,
+ "Client publication (PUBLISH) failed (%d/%.*s)",
+ param->code, (int)param->reason.slen,
+ param->reason.ptr));
+ }
+
+ pjsip_publishc_destroy(param->pubc);
+ acc->publish_sess = NULL;
+ }
+}
+
+
+/*
+ * Send PUBLISH request.
+ */
+static pj_status_t send_publish(int acc_id, pj_bool_t active)
+{
+ pjsua_acc_config *acc_cfg = &pjsua_var.acc[acc_id].cfg;
+ pjsua_acc *acc = &pjsua_var.acc[acc_id];
+ pjsip_pres_status pres_status;
+ pjsip_tx_data *tdata;
+ pj_status_t status;
+
+
+ /* Create PUBLISH request */
+ if (active) {
+ status = pjsip_publishc_publish(acc->publish_sess, PJ_TRUE, &tdata);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Error creating PUBLISH request", status);
+ goto on_error;
+ }
+
+ /* Set our online status: */
+ pj_bzero(&pres_status, sizeof(pres_status));
+ pres_status.info_cnt = 1;
+ pres_status.info[0].basic_open = acc->online_status;
+
+ /* Create and add PIDF message body */
+ status = pjsip_pres_create_pidf(tdata->pool, &pres_status,
+ &acc_cfg->id, &tdata->msg->body);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Error creating PIDF for PUBLISH request",
+ status);
+ pjsip_tx_data_dec_ref(tdata);
+ goto on_error;
+ }
+ } else {
+ status = pjsip_publishc_unpublish(acc->publish_sess, &tdata);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Error creating PUBLISH request", status);
+ goto on_error;
+ }
+ }
+
+ /* Add headers etc */
+ pjsua_process_msg_data(tdata, NULL);
+
+ /* Send the PUBLISH request */
+ status = pjsip_publishc_send(acc->publish_sess, tdata);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE, "Error sending PUBLISH request", status);
+ goto on_error;
+ }
+
+ acc->publish_state = acc->online_status;
+ return PJ_SUCCESS;
+
+on_error:
+ pjsip_publishc_destroy(acc->publish_sess);
+ acc->publish_sess = NULL;
+ return status;
+}
+
+
+/* Create client publish session */
+static pj_status_t create_publish(int acc_id)
+{
+ const pj_str_t STR_PRESENCE = { "presence", 8 };
+ pjsua_acc_config *acc_cfg = &pjsua_var.acc[acc_id].cfg;
+ pjsua_acc *acc = &pjsua_var.acc[acc_id];
+ pj_status_t status;
+
+ /* Create and init client publication session */
+ if (acc_cfg->publish_enabled) {
+
+ /* Create client publication */
+ status = pjsip_publishc_create(pjsua_var.endpt, 0, acc, &publish_cb,
+ &acc->publish_sess);
+ if (status != PJ_SUCCESS) {
+ acc->publish_sess = NULL;
+ return status;
+ }
+
+ /* Initialize client publication */
+ status = pjsip_publishc_init(acc->publish_sess, &STR_PRESENCE,
+ &acc_cfg->id, &acc_cfg->id,
+ &acc_cfg->id,
+ PJSUA_PUBLISH_EXPIRATION);
+ if (status != PJ_SUCCESS) {
+ acc->publish_sess = NULL;
+ return status;
+ }
+
+ /* Send initial PUBLISH request */
+ if (acc->online_status != 0) {
+ status = send_publish(acc_id, PJ_TRUE);
+ if (status != PJ_SUCCESS)
+ return status;
+ }
+
+ } else {
+ acc->publish_sess = NULL;
+ }
+
+ return PJ_SUCCESS;
+}
+
+
+/* Init presence for account */
+pj_status_t pjsua_pres_init_acc(int acc_id)
+{
+ pjsua_acc *acc = &pjsua_var.acc[acc_id];
+
+ /* Init presence subscription */
+ pj_list_init(&acc->pres_srv_list);
+
+
+ return create_publish(acc_id);
+}
+
+
/* Terminate server subscription for the account */
void pjsua_pres_delete_acc(int acc_id)
{
+ pjsua_acc *acc = &pjsua_var.acc[acc_id];
+ pjsua_acc_config *acc_cfg = &pjsua_var.acc[acc_id].cfg;
pjsua_srv_pres *uapres;
uapres = pjsua_var.acc[acc_id].pres_srv_list.next;
- while (uapres != &pjsua_var.acc[acc_id].pres_srv_list) {
+ while (uapres != &acc->pres_srv_list) {
pjsip_pres_status pres_status;
pj_str_t reason = { "noresource", 10 };
@@ -593,24 +742,36 @@ void pjsua_pres_delete_acc(int acc_id)
uapres = uapres->next;
}
+
+ if (acc->publish_sess) {
+ acc->online_status = PJ_FALSE;
+ send_publish(acc_id, PJ_FALSE);
+ if (acc->publish_sess) {
+ pjsip_publishc_destroy(acc->publish_sess);
+ acc->publish_sess = NULL;
+ }
+ acc_cfg->publish_enabled = PJ_FALSE;
+ }
}
/* Refresh subscription (e.g. when our online status has changed) */
static void refresh_server_subscription(int acc_id)
{
+ pjsua_acc *acc = &pjsua_var.acc[acc_id];
+ pjsua_acc_config *acc_cfg = &pjsua_var.acc[acc_id].cfg;
pjsua_srv_pres *uapres;
uapres = pjsua_var.acc[acc_id].pres_srv_list.next;
- while (uapres != &pjsua_var.acc[acc_id].pres_srv_list) {
+ while (uapres != &acc->pres_srv_list) {
pjsip_pres_status pres_status;
pjsip_tx_data *tdata;
pjsip_pres_get_status(uapres->sub, &pres_status);
- if (pres_status.info[0].basic_open != pjsua_var.acc[acc_id].online_status) {
- pres_status.info[0].basic_open = pjsua_var.acc[acc_id].online_status;
+ if (pres_status.info[0].basic_open != acc->online_status) {
+ pres_status.info[0].basic_open = acc->online_status;
pjsip_pres_set_status(uapres->sub, &pres_status);
if (pjsip_pres_current_notify(uapres->sub, &tdata)==PJ_SUCCESS) {
@@ -621,6 +782,16 @@ static void refresh_server_subscription(int acc_id)
uapres = uapres->next;
}
+
+ /* Send PUBLISH if required */
+ if (acc_cfg->publish_enabled) {
+ if (acc->publish_sess == NULL)
+ create_publish(acc_id);
+
+ if (acc->publish_sess && acc->publish_state != acc->online_status) {
+ send_publish(acc_id, PJ_TRUE);
+ }
+ }
}
@@ -819,7 +990,7 @@ static void subscribe_buddy_presence(unsigned index)
}
status = pjsip_pres_create_uac( dlg, &pres_callback,
- &buddy->sub);
+ PJSIP_EVSUB_NO_EVENT_ID, &buddy->sub);
if (status != PJ_SUCCESS) {
pjsua_var.buddy[index].sub = NULL;
pjsua_perror(THIS_FILE, "Unable to create presence client",