From f44d17658e64639499d53b2c524718546bb2bd5e Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Mon, 15 Jun 2009 16:03:40 +0000 Subject: Ticket #873: Include the parsed XML tuple in the pjsip_pres_status, and include it in the pjsua_buddy_info in PJSUA-LIB, in case the PIDF document contains other info that is needed by application (thanks Johan Lantz for the suggestion) git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@2762 74dad513-b988-da41-8d7b-12977e46ad98 --- pjsip/include/pjsip-simple/presence.h | 8 ++++ pjsip/include/pjsip/sip_config.h | 11 +++++ pjsip/include/pjsua-lib/pjsua.h | 5 +++ pjsip/src/pjsip-simple/presence.c | 79 ++++++++++++++++++++++++++++++---- pjsip/src/pjsip-simple/presence_body.c | 29 ++++++++++++- pjsip/src/pjsua-lib/pjsua_pres.c | 3 ++ 6 files changed, 125 insertions(+), 10 deletions(-) (limited to 'pjsip') diff --git a/pjsip/include/pjsip-simple/presence.h b/pjsip/include/pjsip-simple/presence.h index efebeb2c..7c996123 100644 --- a/pjsip/include/pjsip-simple/presence.h +++ b/pjsip/include/pjsip-simple/presence.h @@ -90,6 +90,14 @@ struct pjsip_pres_status pj_str_t id; /**< Tuple id. */ pj_str_t contact; /**< Optional contact address. */ + pj_xml_node *tuple_node; /**< Pointer to tuple XML node of + parsed PIDF body received from + remote agent. Only valid for + client subscription. If the + last received NOTIFY request + does not contain any PIDF body, + this valud will be set to NULL */ + } info[PJSIP_PRES_STATUS_MAX_INFO]; /**< Array of info. */ pj_bool_t _is_valid; /**< Internal flag. */ diff --git a/pjsip/include/pjsip/sip_config.h b/pjsip/include/pjsip/sip_config.h index fe4fbe24..293c3c14 100644 --- a/pjsip/include/pjsip/sip_config.h +++ b/pjsip/include/pjsip/sip_config.h @@ -872,6 +872,17 @@ PJ_INLINE(pjsip_cfg_t*) pjsip_cfg(void) #endif +/** + * Add "timestamp" information in generated PIDF document for both server + * subscription and presence publication. + * + * Default: 1 (yes) + */ +#ifndef PJSIP_PRES_PIDF_ADD_TIMESTAMP +# define PJSIP_PRES_PIDF_ADD_TIMESTAMP 1 +#endif + + PJ_END_DECL /** diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h index 44980caa..8744e9a8 100644 --- a/pjsip/include/pjsua-lib/pjsua.h +++ b/pjsip/include/pjsua-lib/pjsua.h @@ -2906,6 +2906,11 @@ typedef struct pjsua_buddy_info */ pjrpid_element rpid; + /** + * Extended presence info. + */ + pjsip_pres_status pres_status; + /** * Internal buffer. */ diff --git a/pjsip/src/pjsip-simple/presence.c b/pjsip/src/pjsip-simple/presence.c index 31c83fc1..24049359 100644 --- a/pjsip/src/pjsip-simple/presence.c +++ b/pjsip/src/pjsip-simple/presence.c @@ -73,7 +73,9 @@ struct pjsip_pres pjsip_evsub *sub; /**< Event subscribtion record. */ pjsip_dialog *dlg; /**< The dialog. */ content_type_e content_type; /**< Content-Type. */ + pj_pool_t *status_pool; /**< Pool for pres_status */ pjsip_pres_status status; /**< Presence status. */ + pj_pool_t *tmp_pool; /**< Pool for tmp_status */ pjsip_pres_status tmp_status; /**< Temp, before NOTIFY is answred.*/ pjsip_evsub_user user_cb; /**< The user callback. */ }; @@ -185,6 +187,7 @@ PJ_DEF(pj_status_t) pjsip_pres_create_uac( pjsip_dialog *dlg, { pj_status_t status; pjsip_pres *pres; + char obj_name[PJ_MAX_OBJ_NAME]; pjsip_evsub *sub; PJ_ASSERT_RETURN(dlg && p_evsub, PJ_EINVAL); @@ -204,6 +207,13 @@ PJ_DEF(pj_status_t) pjsip_pres_create_uac( pjsip_dialog *dlg, if (user_cb) pj_memcpy(&pres->user_cb, user_cb, sizeof(pjsip_evsub_user)); + pj_ansi_snprintf(obj_name, PJ_MAX_OBJ_NAME, "pres%p", dlg->pool); + pres->status_pool = pj_pool_create(dlg->pool->factory, obj_name, + 512, 512, NULL); + pj_ansi_snprintf(obj_name, PJ_MAX_OBJ_NAME, "tmpres%p", dlg->pool); + pres->tmp_pool = pj_pool_create(dlg->pool->factory, obj_name, + 512, 512, NULL); + /* Attach to evsub */ pjsip_evsub_set_mod_data(sub, mod_presence.id, pres); @@ -228,6 +238,7 @@ PJ_DEF(pj_status_t) pjsip_pres_create_uas( pjsip_dialog *dlg, content_type_e content_type = CONTENT_TYPE_NONE; pjsip_evsub *sub; pjsip_pres *pres; + char obj_name[PJ_MAX_OBJ_NAME]; pj_status_t status; /* Check arguments */ @@ -297,6 +308,13 @@ PJ_DEF(pj_status_t) pjsip_pres_create_uas( pjsip_dialog *dlg, if (user_cb) pj_memcpy(&pres->user_cb, user_cb, sizeof(pjsip_evsub_user)); + pj_ansi_snprintf(obj_name, PJ_MAX_OBJ_NAME, "pres%p", dlg->pool); + pres->status_pool = pj_pool_create(dlg->pool->factory, obj_name, + 512, 512, NULL); + pj_ansi_snprintf(obj_name, PJ_MAX_OBJ_NAME, "tmpres%p", dlg->pool); + pres->tmp_pool = pj_pool_create(dlg->pool->factory, obj_name, + 512, 512, NULL); + /* Attach to evsub */ pjsip_evsub_set_mod_data(sub, mod_presence.id, pres); @@ -355,10 +373,13 @@ PJ_DEF(pj_status_t) pjsip_pres_get_status( pjsip_evsub *sub, pres = (pjsip_pres*) pjsip_evsub_get_mod_data(sub, mod_presence.id); PJ_ASSERT_RETURN(pres!=NULL, PJSIP_SIMPLE_ENOPRESENCE); - if (pres->tmp_status._is_valid) + if (pres->tmp_status._is_valid) { + PJ_ASSERT_RETURN(pres->tmp_pool!=NULL, PJSIP_SIMPLE_ENOPRESENCE); pj_memcpy(status, &pres->tmp_status, sizeof(pjsip_pres_status)); - else + } else { + PJ_ASSERT_RETURN(pres->status_pool!=NULL, PJSIP_SIMPLE_ENOPRESENCE); pj_memcpy(status, &pres->status, sizeof(pjsip_pres_status)); + } return PJ_SUCCESS; } @@ -371,6 +392,7 @@ PJ_DEF(pj_status_t) pjsip_pres_set_status( pjsip_evsub *sub, const pjsip_pres_status *status ) { unsigned i; + pj_pool_t *tmp; pjsip_pres *pres; PJ_ASSERT_RETURN(sub && status, PJ_EINVAL); @@ -380,7 +402,9 @@ PJ_DEF(pj_status_t) pjsip_pres_set_status( pjsip_evsub *sub, for (i=0; iinfo_cnt; ++i) { pres->status.info[i].basic_open = status->info[i].basic_open; - if (status->info[i].id.slen == 0) { + if (pres->status.info[i].id.slen) { + /* Id already set */ + } else if (status->info[i].id.slen == 0) { pj_create_unique_string(pres->dlg->pool, &pres->status.info[i].id); } else { @@ -388,17 +412,17 @@ PJ_DEF(pj_status_t) pjsip_pres_set_status( pjsip_evsub *sub, &pres->status.info[i].id, &status->info[i].id); } - pj_strdup(pres->dlg->pool, + pj_strdup(pres->tmp_pool, &pres->status.info[i].contact, &status->info[i].contact); /* Duplicate */ pres->status.info[i].rpid.activity = status->info[i].rpid.activity; - pj_strdup(pres->dlg->pool, + pj_strdup(pres->tmp_pool, &pres->status.info[i].rpid.id, &status->info[i].rpid.id); - pj_strdup(pres->dlg->pool, + pj_strdup(pres->tmp_pool, &pres->status.info[i].rpid.note, &status->info[i].rpid.note); @@ -406,6 +430,12 @@ PJ_DEF(pj_status_t) pjsip_pres_set_status( pjsip_evsub *sub, pres->status.info_cnt = status->info_cnt; + /* Swap pools */ + tmp = pres->tmp_pool; + pres->tmp_pool = pres->status_pool; + pres->status_pool = tmp; + pj_pool_reset(pres->tmp_pool); + return PJ_SUCCESS; } @@ -572,6 +602,17 @@ static void pres_on_evsub_state( pjsip_evsub *sub, pjsip_event *event) if (pres->user_cb.on_evsub_state) (*pres->user_cb.on_evsub_state)(sub, event); + + if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) { + if (pres->status_pool) { + pj_pool_release(pres->status_pool); + pres->status_pool = NULL; + } + if (pres->tmp_pool) { + pj_pool_release(pres->tmp_pool); + pres->tmp_pool = NULL; + } + } } /* @@ -670,14 +711,14 @@ 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 = pjsip_pres_parse_pidf( rdata, pres->dlg->pool, + status = pjsip_pres_parse_pidf( rdata, pres->tmp_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 = pjsip_pres_parse_xpidf( rdata, pres->dlg->pool, + status = pjsip_pres_parse_xpidf( rdata, pres->tmp_pool, &pres->tmp_status); } else @@ -740,11 +781,23 @@ static void pres_on_evsub_rx_notify( pjsip_evsub *sub, return; } else { +#if 1 + /* This is the newest change, http://trac.pjsip.org/repos/ticket/873 + * Some app want to be notified about the empty NOTIFY, e.g. to + * decide whether it should consider the buddy as offline. + * In this case, leave the buddy state unchanged, but set the + * "tuple_node" in pjsip_pres_status to NULL. + */ + unsigned i; + for (i=0; istatus.info_cnt; ++i) { + pres->status.info[i].tuple_node = NULL; + } + +#elif 0 /* This has just been changed. Previously, we treat incoming NOTIFY * with no message body as having the presence subscription closed. * Now we treat it as no change in presence status (ref: EyeBeam). */ -#if 1 *p_st_code = 200; return; #else @@ -767,10 +820,18 @@ static void pres_on_evsub_rx_notify( pjsip_evsub *sub, * to main status, and mark the temporary status as invalid. */ if ((*p_st_code)/100 == 2) { + pj_pool_t *tmp; + pj_memcpy(&pres->status, &pres->tmp_status, sizeof(pjsip_pres_status)); + + /* Swap the pool */ + tmp = pres->tmp_pool; + pres->tmp_pool = pres->status_pool; + pres->status_pool = tmp; } pres->tmp_status._is_valid = PJ_FALSE; + pj_pool_reset(pres->tmp_pool); /* Done */ } diff --git a/pjsip/src/pjsip-simple/presence_body.c b/pjsip/src/pjsip-simple/presence_body.c index 6b215b47..30b6318f 100644 --- a/pjsip/src/pjsip-simple/presence_body.c +++ b/pjsip/src/pjsip-simple/presence_body.c @@ -100,6 +100,29 @@ PJ_DEF(pj_status_t) pjsip_pres_create_pidf( pj_pool_t *pool, pidf_status = pjpidf_tuple_get_status(pidf_tuple); pjpidf_status_set_basic_open(pidf_status, status->info[i].basic_open); + + /* Add if configured */ +#if defined(PJSIP_PRES_PIDF_ADD_TIMESTAMP) && PJSIP_PRES_PIDF_ADD_TIMESTAMP + if (PJSIP_PRES_PIDF_ADD_TIMESTAMP) { + char buf[50]; + int tslen = 0; + pj_time_val tv; + pj_parsed_time pt; + + pj_gettimeofday(&tv); + /* TODO: convert time to GMT! (unsupported by pjlib) */ + pj_time_decode( &tv, &pt); + + tslen = pj_ansi_snprintf(buf, sizeof(buf), + "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", + pt.year, pt.mon, pt.day, + pt.hour, pt.min, pt.sec, pt.msec); + if (tslen > 0 && tslen < sizeof(buf)) { + pj_str_t time = pj_str(buf); + pjpidf_tuple_set_timestamp(pool, pidf_tuple, &time); + } + } +#endif } /* Create (RPID) */ @@ -179,9 +202,12 @@ PJ_DEF(pj_status_t) pjsip_pres_parse_pidf( pjsip_rx_data *rdata, pres_status->info_cnt = 0; pidf_tuple = pjpidf_pres_get_first_tuple(pidf); - while (pidf_tuple) { + while (pidf_tuple && pres_status->info_cnt < PJSIP_PRES_STATUS_MAX_INFO) { pjpidf_status *pidf_status; + pres_status->info[pres_status->info_cnt].tuple_node = + pj_xml_clone(pool, pidf_tuple); + pj_strdup(pool, &pres_status->info[pres_status->info_cnt].id, pjpidf_tuple_get_id(pidf_tuple)); @@ -231,6 +257,7 @@ PJ_DEF(pj_status_t) pjsip_pres_parse_xpidf(pjsip_rx_data *rdata, pjxpidf_get_uri(xpidf)); pres_status->info[0].basic_open = pjxpidf_get_status(xpidf); pres_status->info[0].id.slen = 0; + pres_status->info[0].tuple_node = NULL; return PJ_SUCCESS; } diff --git a/pjsip/src/pjsua-lib/pjsua_pres.c b/pjsip/src/pjsua-lib/pjsua_pres.c index d980e617..797fb84c 100644 --- a/pjsip/src/pjsua-lib/pjsua_pres.c +++ b/pjsip/src/pjsua-lib/pjsua_pres.c @@ -166,6 +166,9 @@ PJ_DEF(pj_status_t) pjsua_buddy_get_info( pjsua_buddy_id buddy_id, pj_strncpy(&info->contact, &buddy->contact, sizeof(info->buf_)-total); total += info->contact.slen; + /* Presence status */ + pj_memcpy(&info->pres_status, &buddy->status, sizeof(pjsip_pres_status)); + /* status and status text */ if (buddy->sub == NULL || buddy->status.info_cnt==0) { info->status = PJSUA_BUDDY_STATUS_UNKNOWN; -- cgit v1.2.3