📄 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 + -