📄 presence.c
字号:
pres->status.info_cnt = status->info_cnt;
return PJ_SUCCESS;
}
/*
* Create message body.
*/
static pj_status_t pres_create_msg_body( pjsip_pres *pres,
pjsip_tx_data *tdata)
{
pj_str_t entity;
/* Get publisher URI */
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 PJ_ENOMEM;
if (pres->content_type == CONTENT_TYPE_PIDF) {
return pjsip_pres_create_pidf(tdata->pool, &pres->status,
&entity, &tdata->msg->body);
} else if (pres->content_type == CONTENT_TYPE_XPIDF) {
return pjsip_pres_create_xpidf(tdata->pool, &pres->status,
&entity, &tdata->msg->body);
} else {
return PJSIP_SIMPLE_EBADCONTENT;
}
}
/*
* Create NOTIFY
*/
PJ_DEF(pj_status_t) pjsip_pres_notify( pjsip_evsub *sub,
pjsip_evsub_state state,
const pj_str_t *state_str,
const pj_str_t *reason,
pjsip_tx_data **p_tdata)
{
pjsip_pres *pres;
pjsip_tx_data *tdata;
pj_status_t status;
/* Check arguments. */
PJ_ASSERT_RETURN(sub, PJ_EINVAL);
/* Get the presence object. */
pres = pjsip_evsub_get_mod_data(sub, mod_presence.id);
PJ_ASSERT_RETURN(pres != NULL, PJSIP_SIMPLE_ENOPRESENCE);
/* Must have at least one presence info. */
PJ_ASSERT_RETURN(pres->status.info_cnt > 0, PJSIP_SIMPLE_ENOPRESENCEINFO);
/* Lock object. */
pjsip_dlg_inc_lock(pres->dlg);
/* Create the NOTIFY request. */
status = pjsip_evsub_notify( sub, state, state_str, reason, &tdata);
if (status != PJ_SUCCESS)
goto on_return;
/* Create message body to reflect the presence status. */
status = pres_create_msg_body( pres, tdata );
if (status != PJ_SUCCESS)
goto on_return;
/* Done. */
*p_tdata = tdata;
on_return:
pjsip_dlg_dec_lock(pres->dlg);
return status;
}
/*
* Create NOTIFY that reflect current state.
*/
PJ_DEF(pj_status_t) pjsip_pres_current_notify( pjsip_evsub *sub,
pjsip_tx_data **p_tdata )
{
pjsip_pres *pres;
pjsip_tx_data *tdata;
pj_status_t status;
/* Check arguments. */
PJ_ASSERT_RETURN(sub, PJ_EINVAL);
/* Get the presence object. */
pres = pjsip_evsub_get_mod_data(sub, mod_presence.id);
PJ_ASSERT_RETURN(pres != NULL, PJSIP_SIMPLE_ENOPRESENCE);
/* Must have at least one presence info. */
PJ_ASSERT_RETURN(pres->status.info_cnt > 0, PJSIP_SIMPLE_ENOPRESENCEINFO);
/* Lock object. */
pjsip_dlg_inc_lock(pres->dlg);
/* Create the NOTIFY request. */
status = pjsip_evsub_current_notify( sub, &tdata);
if (status != PJ_SUCCESS)
goto on_return;
/* Create message body to reflect the presence status. */
status = pres_create_msg_body( pres, tdata );
if (status != PJ_SUCCESS)
goto on_return;
/* Done. */
*p_tdata = tdata;
on_return:
pjsip_dlg_dec_lock(pres->dlg);
return status;
}
/*
* Send request.
*/
PJ_DEF(pj_status_t) pjsip_pres_send_request( pjsip_evsub *sub,
pjsip_tx_data *tdata )
{
return pjsip_evsub_send_request(sub, tdata);
}
/*
* This callback is called by event subscription when subscription
* state has changed.
*/
static void pres_on_evsub_state( pjsip_evsub *sub, pjsip_event *event)
{
pjsip_pres *pres;
pres = pjsip_evsub_get_mod_data(sub, mod_presence.id);
PJ_ASSERT_ON_FAIL(pres!=NULL, {return;});
if (pres->user_cb.on_evsub_state)
(*pres->user_cb.on_evsub_state)(sub, event);
}
/*
* Called when transaction state has changed.
*/
static void pres_on_evsub_tsx_state( pjsip_evsub *sub, pjsip_transaction *tsx,
pjsip_event *event)
{
pjsip_pres *pres;
pres = pjsip_evsub_get_mod_data(sub, mod_presence.id);
PJ_ASSERT_ON_FAIL(pres!=NULL, {return;});
if (pres->user_cb.on_tsx_state)
(*pres->user_cb.on_tsx_state)(sub, tsx, event);
}
/*
* Called when SUBSCRIBE is received.
*/
static void pres_on_evsub_rx_refresh( pjsip_evsub *sub,
pjsip_rx_data *rdata,
int *p_st_code,
pj_str_t **p_st_text,
pjsip_hdr *res_hdr,
pjsip_msg_body **p_body)
{
pjsip_pres *pres;
pres = pjsip_evsub_get_mod_data(sub, mod_presence.id);
PJ_ASSERT_ON_FAIL(pres!=NULL, {return;});
if (pres->user_cb.on_rx_refresh) {
(*pres->user_cb.on_rx_refresh)(sub, rdata, p_st_code, p_st_text,
res_hdr, p_body);
} else {
/* Implementors MUST send NOTIFY if it implements on_rx_refresh */
pjsip_tx_data *tdata;
pj_str_t timeout = { "timeout", 7};
pj_status_t status;
if (pjsip_evsub_get_state(sub)==PJSIP_EVSUB_STATE_TERMINATED) {
status = pjsip_pres_notify( sub, PJSIP_EVSUB_STATE_TERMINATED,
NULL, &timeout, &tdata);
} else {
status = pjsip_pres_current_notify(sub, &tdata);
}
if (status == PJ_SUCCESS)
pjsip_pres_send_request(sub, tdata);
}
}
/*
* Process the content of incoming NOTIFY request and update temporary
* status.
*
* return PJ_SUCCESS if incoming request is acceptable. If return value
* is not PJ_SUCCESS, res_hdr may be added with Warning header.
*/
static pj_status_t pres_process_rx_notify( pjsip_pres *pres,
pjsip_rx_data *rdata,
int *p_st_code,
pj_str_t **p_st_text,
pjsip_hdr *res_hdr)
{
pjsip_ctype_hdr *ctype_hdr;
pj_status_t status;
*p_st_text = NULL;
/* Check Content-Type and msg body are present. */
ctype_hdr = rdata->msg_info.ctype;
if (ctype_hdr==NULL || rdata->msg_info.msg->body==NULL) {
pjsip_warning_hdr *warn_hdr;
pj_str_t warn_text;
*p_st_code = PJSIP_SC_BAD_REQUEST;
warn_text = pj_str("Message body is not present");
warn_hdr = pjsip_warning_hdr_create(rdata->tp_info.pool, 399,
pjsip_endpt_name(pres->dlg->endpt),
&warn_text);
pj_list_push_back(res_hdr, warn_hdr);
return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_BAD_REQUEST);
}
/* Parse content. */
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,
&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,
&pres->tmp_status);
}
else
{
status = PJSIP_SIMPLE_EBADCONTENT;
}
if (status != PJ_SUCCESS) {
/* Unsupported or bad Content-Type */
pjsip_accept_hdr *accept_hdr;
pjsip_warning_hdr *warn_hdr;
*p_st_code = PJSIP_SC_NOT_ACCEPTABLE_HERE;
/* Add Accept header */
accept_hdr = pjsip_accept_hdr_create(rdata->tp_info.pool);
accept_hdr->values[accept_hdr->count++] = STR_APP_PIDF_XML;
accept_hdr->values[accept_hdr->count++] = STR_APP_XPIDF_XML;
pj_list_push_back(res_hdr, accept_hdr);
/* Add Warning header */
warn_hdr = pjsip_warning_hdr_create_from_status(
rdata->tp_info.pool,
pjsip_endpt_name(pres->dlg->endpt),
status);
pj_list_push_back(res_hdr, warn_hdr);
return status;
}
/* If application calls pres_get_status(), redirect the call to
* retrieve the temporary status.
*/
pres->tmp_status._is_valid = PJ_TRUE;
return PJ_SUCCESS;
}
/*
* Called when NOTIFY is received.
*/
static void pres_on_evsub_rx_notify( pjsip_evsub *sub,
pjsip_rx_data *rdata,
int *p_st_code,
pj_str_t **p_st_text,
pjsip_hdr *res_hdr,
pjsip_msg_body **p_body)
{
pjsip_pres *pres;
pj_status_t status;
pres = pjsip_evsub_get_mod_data(sub, mod_presence.id);
PJ_ASSERT_ON_FAIL(pres!=NULL, {return;});
if (rdata->msg_info.msg->body) {
status = pres_process_rx_notify( pres, rdata, p_st_code, p_st_text,
res_hdr );
if (status != PJ_SUCCESS)
return;
} else {
/* 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
unsigned i;
/* Subscription is terminated. Consider contact is offline */
pres->tmp_status._is_valid = PJ_TRUE;
for (i=0; i<pres->tmp_status.info_cnt; ++i)
pres->tmp_status.info[i].basic_open = PJ_FALSE;
#endif
}
/* Notify application. */
if (pres->user_cb.on_rx_notify) {
(*pres->user_cb.on_rx_notify)(sub, rdata, p_st_code, p_st_text,
res_hdr, p_body);
}
/* If application responded NOTIFY with 2xx, copy temporary status
* to main status, and mark the temporary status as invalid.
*/
if ((*p_st_code)/100 == 2) {
pj_memcpy(&pres->status, &pres->tmp_status, sizeof(pjsip_pres_status));
}
pres->tmp_status._is_valid = PJ_FALSE;
/* Done */
}
/*
* Called when it's time to send SUBSCRIBE.
*/
static void pres_on_evsub_client_refresh(pjsip_evsub *sub)
{
pjsip_pres *pres;
pres = pjsip_evsub_get_mod_data(sub, mod_presence.id);
PJ_ASSERT_ON_FAIL(pres!=NULL, {return;});
if (pres->user_cb.on_client_refresh) {
(*pres->user_cb.on_client_refresh)(sub);
} else {
pj_status_t status;
pjsip_tx_data *tdata;
status = pjsip_pres_initiate(sub, -1, &tdata);
if (status == PJ_SUCCESS)
pjsip_pres_send_request(sub, tdata);
}
}
/*
* Called when no refresh is received after the interval.
*/
static void pres_on_evsub_server_timeout(pjsip_evsub *sub)
{
pjsip_pres *pres;
pres = pjsip_evsub_get_mod_data(sub, mod_presence.id);
PJ_ASSERT_ON_FAIL(pres!=NULL, {return;});
if (pres->user_cb.on_server_timeout) {
(*pres->user_cb.on_server_timeout)(sub);
} else {
pj_status_t status;
pjsip_tx_data *tdata;
pj_str_t reason = { "timeout", 7 };
status = pjsip_pres_notify(sub, PJSIP_EVSUB_STATE_TERMINATED,
NULL, &reason, &tdata);
if (status == PJ_SUCCESS)
pjsip_pres_send_request(sub, tdata);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -