📄 presence.c
字号:
/* $Id: presence.c 974 2007-02-19 01:13:53Z bennylp $ *//* * Copyright (C) 2003-2007 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-simple/evsub_msg.h>#include <pjsip/sip_module.h>#include <pjsip/sip_endpoint.h>#include <pjsip/sip_dialog.h>#include <pj/assert.h>#include <pj/guid.h>#include <pj/log.h>#include <pj/os.h>#include <pj/pool.h>#include <pj/string.h>#define THIS_FILE "presence.c"#define PRES_DEFAULT_EXPIRES 600/* * Presence module (mod-presence) */static struct pjsip_module mod_presence = { NULL, NULL, /* prev, next. */ { "mod-presence", 12 }, /* Name. */ -1, /* Id */ PJSIP_MOD_PRIORITY_DIALOG_USAGE,/* Priority */ NULL, /* load() */ NULL, /* start() */ NULL, /* stop() */ NULL, /* unload() */ NULL, /* on_rx_request() */ NULL, /* on_rx_response() */ NULL, /* on_tx_request. */ NULL, /* on_tx_response() */ NULL, /* on_tsx_state() */};/* * Presence message body type. */typedef enum content_type{ CONTENT_TYPE_NONE, CONTENT_TYPE_PIDF, CONTENT_TYPE_XPIDF,} content_type;/* * This structure describe a presentity, for both subscriber and notifier. */struct pjsip_pres{ pjsip_evsub *sub; /**< Event subscribtion record. */ pjsip_dialog *dlg; /**< The dialog. */ content_type content_type; /**< Content-Type. */ pjsip_pres_status status; /**< Presence status. */ pjsip_pres_status tmp_status; /**< Temp, before NOTIFY is answred.*/ pjsip_evsub_user user_cb; /**< The user callback. */};typedef struct pjsip_pres pjsip_pres;/* * Forward decl for evsub callback. */static void pres_on_evsub_state( pjsip_evsub *sub, pjsip_event *event);static void pres_on_evsub_tsx_state( pjsip_evsub *sub, pjsip_transaction *tsx, pjsip_event *event);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);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);static void pres_on_evsub_client_refresh(pjsip_evsub *sub);static void pres_on_evsub_server_timeout(pjsip_evsub *sub);/* * Event subscription callback for presence. */static pjsip_evsub_user pres_user = { &pres_on_evsub_state, &pres_on_evsub_tsx_state, &pres_on_evsub_rx_refresh, &pres_on_evsub_rx_notify, &pres_on_evsub_client_refresh, &pres_on_evsub_server_timeout,};/* * Some static constants. */const pj_str_t STR_EVENT = { "Event", 5 };const pj_str_t STR_PRESENCE = { "presence", 8 };const pj_str_t STR_APPLICATION = { "application", 11 };const pj_str_t STR_PIDF_XML = { "pidf+xml", 8};const pj_str_t STR_XPIDF_XML = { "xpidf+xml", 9};const pj_str_t STR_APP_PIDF_XML = { "application/pidf+xml", 20 };const pj_str_t STR_APP_XPIDF_XML = { "application/xpidf+xml", 21 };/* * Init presence module. */PJ_DEF(pj_status_t) pjsip_pres_init_module( pjsip_endpoint *endpt, pjsip_module *mod_evsub){ pj_status_t status; pj_str_t accept[2]; /* Check arguments. */ PJ_ASSERT_RETURN(endpt && mod_evsub, PJ_EINVAL); /* Must have not been registered */ PJ_ASSERT_RETURN(mod_presence.id == -1, PJ_EINVALIDOP); /* Register to endpoint */ status = pjsip_endpt_register_module(endpt, &mod_presence); if (status != PJ_SUCCESS) return status; accept[0] = STR_APP_PIDF_XML; accept[1] = STR_APP_XPIDF_XML; /* Register event package to event module. */ status = pjsip_evsub_register_pkg( &mod_presence, &STR_PRESENCE, PRES_DEFAULT_EXPIRES, PJ_ARRAY_SIZE(accept), accept); if (status != PJ_SUCCESS) { pjsip_endpt_unregister_module(endpt, &mod_presence); return status; } return PJ_SUCCESS;}/* * Get presence module instance. */PJ_DEF(pjsip_module*) pjsip_pres_instance(void){ return &mod_presence;}/* * Create client subscription. */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; pjsip_pres *pres; pjsip_evsub *sub; PJ_ASSERT_RETURN(dlg && p_evsub, PJ_EINVAL); pjsip_dlg_inc_lock(dlg); /* Create event subscription */ status = pjsip_evsub_create_uac( dlg, &pres_user, &STR_PRESENCE, options, &sub); if (status != PJ_SUCCESS) goto on_return; /* Create presence */ pres = pj_pool_zalloc(dlg->pool, sizeof(pjsip_pres)); pres->dlg = dlg; pres->sub = sub; if (user_cb) pj_memcpy(&pres->user_cb, user_cb, sizeof(pjsip_evsub_user)); /* Attach to evsub */ pjsip_evsub_set_mod_data(sub, mod_presence.id, pres); *p_evsub = sub;on_return: pjsip_dlg_dec_lock(dlg); return status;}/* * Create server subscription. */PJ_DEF(pj_status_t) pjsip_pres_create_uas( pjsip_dialog *dlg, const pjsip_evsub_user *user_cb, pjsip_rx_data *rdata, pjsip_evsub **p_evsub ){ pjsip_accept_hdr *accept; pjsip_event_hdr *event; pjsip_expires_hdr *expires_hdr; unsigned expires; content_type content_type = CONTENT_TYPE_NONE; pjsip_evsub *sub; pjsip_pres *pres; pj_status_t status; /* Check arguments */ PJ_ASSERT_RETURN(dlg && rdata && p_evsub, PJ_EINVAL); /* Must be request message */ PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG, PJSIP_ENOTREQUESTMSG); /* Check that request is SUBSCRIBE */ PJ_ASSERT_RETURN(pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_subscribe_method)==0, PJSIP_SIMPLE_ENOTSUBSCRIBE); /* Check that Event header contains "presence" */ event = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &STR_EVENT, NULL); if (!event) { return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_BAD_REQUEST); } if (pj_stricmp(&event->event_type, &STR_PRESENCE) != 0) { return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_BAD_EVENT); } /* Check that request contains compatible Accept header. */ accept = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, NULL); if (accept) { unsigned i; for (i=0; i<accept->count; ++i) { if (pj_stricmp(&accept->values[i], &STR_APP_PIDF_XML)==0) { content_type = CONTENT_TYPE_PIDF; break; } else if (pj_stricmp(&accept->values[i], &STR_APP_XPIDF_XML)==0) { content_type = CONTENT_TYPE_XPIDF; break; } } if (i==accept->count) { /* Nothing is acceptable */ return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE); } } else { /* No Accept header. * Treat as "application/pidf+xml" */ content_type = CONTENT_TYPE_PIDF; } /* Check that expires is not too short. */ expires_hdr=pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL); if (expires_hdr) { if (expires_hdr->ivalue < 5) { return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_INTERVAL_TOO_BRIEF); } expires = expires_hdr->ivalue; if (expires > PRES_DEFAULT_EXPIRES) expires = PRES_DEFAULT_EXPIRES; } else { expires = PRES_DEFAULT_EXPIRES; } /* Lock dialog */ pjsip_dlg_inc_lock(dlg); /* Create server subscription */ status = pjsip_evsub_create_uas( dlg, &pres_user, rdata, 0, &sub); if (status != PJ_SUCCESS) goto on_return; /* Create server presence subscription */ pres = pj_pool_zalloc(dlg->pool, sizeof(pjsip_pres)); pres->dlg = dlg; pres->sub = sub; pres->content_type = content_type; if (user_cb) pj_memcpy(&pres->user_cb, user_cb, sizeof(pjsip_evsub_user)); /* Attach to evsub */ pjsip_evsub_set_mod_data(sub, mod_presence.id, pres); /* Done: */ *p_evsub = sub;on_return: pjsip_dlg_dec_lock(dlg); return status;}/* * Forcefully terminate presence. */PJ_DEF(pj_status_t) pjsip_pres_terminate( pjsip_evsub *sub, pj_bool_t notify ){ return pjsip_evsub_terminate(sub, notify);}/* * Create SUBSCRIBE */PJ_DEF(pj_status_t) pjsip_pres_initiate( pjsip_evsub *sub, pj_int32_t expires, pjsip_tx_data **p_tdata){ return pjsip_evsub_initiate(sub, &pjsip_subscribe_method, expires, p_tdata);}/* * Accept incoming subscription. */PJ_DEF(pj_status_t) pjsip_pres_accept( pjsip_evsub *sub, pjsip_rx_data *rdata, int st_code, const pjsip_hdr *hdr_list ){ return pjsip_evsub_accept( sub, rdata, st_code, hdr_list );}/* * Get presence status. */PJ_DEF(pj_status_t) pjsip_pres_get_status( pjsip_evsub *sub, pjsip_pres_status *status ){ pjsip_pres *pres; PJ_ASSERT_RETURN(sub && status, PJ_EINVAL); pres = pjsip_evsub_get_mod_data(sub, mod_presence.id); PJ_ASSERT_RETURN(pres!=NULL, PJSIP_SIMPLE_ENOPRESENCE); if (pres->tmp_status._is_valid) pj_memcpy(status, &pres->tmp_status, sizeof(pjsip_pres_status)); else pj_memcpy(status, &pres->status, sizeof(pjsip_pres_status)); return PJ_SUCCESS;}/* * Set presence status. */PJ_DEF(pj_status_t) pjsip_pres_set_status( pjsip_evsub *sub, const pjsip_pres_status *status ){ unsigned i; pjsip_pres *pres; PJ_ASSERT_RETURN(sub && status, PJ_EINVAL); pres = pjsip_evsub_get_mod_data(sub, mod_presence.id); PJ_ASSERT_RETURN(pres!=NULL, PJSIP_SIMPLE_ENOPRESENCE); for (i=0; i<status->info_cnt; ++i) { pres->status.info[i].basic_open = status->info[i].basic_open; if (status->info[i].id.slen == 0) { pj_create_unique_string(pres->dlg->pool, &pres->status.info[i].id); } else { pj_strdup(pres->dlg->pool, &pres->status.info[i].id, &status->info[i].id); } pj_strdup(pres->dlg->pool, &pres->status.info[i].contact, &status->info[i].contact); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -