diff options
author | Benny Prijono <bennylp@teluu.com> | 2005-11-09 16:36:21 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2005-11-09 16:36:21 +0000 |
commit | febc030a59404ecbb3bfde1ceff6531588149ca9 (patch) | |
tree | aa5d796b4e81fd7ea3402c64f447546808bd6700 /pjsip/src/pjsip_simple | |
parent | 9f379fcbe89024353a25b3737d79ec7a82b6408f (diff) |
Organizing pjsip directory structure
git-svn-id: http://svn.pjsip.org/repos/pjproject/main@39 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip/src/pjsip_simple')
-rw-r--r-- | pjsip/src/pjsip_simple/event_notify.c | 1629 | ||||
-rw-r--r-- | pjsip/src/pjsip_simple/event_notify_msg.c | 307 | ||||
-rw-r--r-- | pjsip/src/pjsip_simple/messaging.c | 337 | ||||
-rw-r--r-- | pjsip/src/pjsip_simple/pidf.c | 335 | ||||
-rw-r--r-- | pjsip/src/pjsip_simple/presence.c | 384 | ||||
-rw-r--r-- | pjsip/src/pjsip_simple/xpidf.c | 279 |
6 files changed, 0 insertions, 3271 deletions
diff --git a/pjsip/src/pjsip_simple/event_notify.c b/pjsip/src/pjsip_simple/event_notify.c deleted file mode 100644 index 24aa68a0..00000000 --- a/pjsip/src/pjsip_simple/event_notify.c +++ /dev/null @@ -1,1629 +0,0 @@ -/* $Id$ - * - */ -#include <pjsip_simple/event_notify.h> -#include <pjsip/sip_msg.h> -#include <pjsip/sip_misc.h> -#include <pjsip/sip_endpoint.h> -#include <pjsip/sip_module.h> -#include <pjsip/sip_transaction.h> -#include <pjsip/sip_event.h> -#include <pj/pool.h> -#include <pj/timer.h> -#include <pj/string.h> -#include <pj/hash.h> -#include <pj/os.h> -#include <pj/except.h> -#include <pj/log.h> -#include <pj/guid.h> - -#define THIS_FILE "event_sub" - -/* String names for state. - * The names here should be compliant with sub_state names in RFC3265. - */ -static const pj_str_t state[] = { - { "null", 4 }, - { "active", 6 }, - { "pending", 7 }, - { "terminated", 10 }, - { "unknown", 7 } -}; - -/* Timer IDs */ -#define TIMER_ID_REFRESH 1 -#define TIMER_ID_UAS_EXPIRY 2 - -/* Static configuration. */ -#define SECONDS_BEFORE_EXPIRY 10 -#define MGR_POOL_SIZE 512 -#define MGR_POOL_INC 0 -#define SUB_POOL_SIZE 2048 -#define SUB_POOL_INC 0 -#define HASH_TABLE_SIZE 32 - -/* Static vars. */ -static int mod_id; -static const pjsip_method SUBSCRIBE = { PJSIP_OTHER_METHOD, {"SUBSCRIBE", 9}}; -static const pjsip_method NOTIFY = { PJSIP_OTHER_METHOD, { "NOTIFY", 6}}; - -typedef struct package -{ - PJ_DECL_LIST_MEMBER(struct package) - pj_str_t event; - int accept_cnt; - pj_str_t *accept; - pjsip_event_sub_pkg_cb cb; -} package; - -/* Event subscription manager singleton instance. */ -static struct pjsip_event_sub_mgr -{ - pj_pool_t *pool; - pj_hash_table_t *ht; - pjsip_endpoint *endpt; - pj_mutex_t *mutex; - pjsip_allow_events_hdr *allow_events; - package pkg_list; -} mgr; - -/* Fordward declarations for static functions. */ -static pj_status_t mod_init(pjsip_endpoint *, pjsip_module *, pj_uint32_t); -static pj_status_t mod_deinit(pjsip_module*); -static void tsx_handler(pjsip_module*, pjsip_event*); -static pjsip_event_sub *find_sub(pjsip_rx_data *); -static void on_subscribe_request(pjsip_transaction*, pjsip_rx_data*); -static void on_subscribe_response(void *, pjsip_event*); -static void on_notify_request(pjsip_transaction *, pjsip_rx_data*); -static void on_notify_response(void *, pjsip_event *); -static void refresh_timer_cb(pj_timer_heap_t*, pj_timer_entry*); -static void uas_expire_timer_cb(pj_timer_heap_t*, pj_timer_entry*); -static pj_status_t send_sub_refresh( pjsip_event_sub *sub ); - -/* Module descriptor. */ -static pjsip_module event_sub_module = -{ - {"EventSub", 8}, /* Name. */ - 0, /* Flag */ - 128, /* Priority */ - &mgr, /* User data. */ - 2, /* Number of methods supported . */ - { &SUBSCRIBE, &NOTIFY }, /* Array of methods */ - &mod_init, /* init_module() */ - NULL, /* start_module() */ - &mod_deinit, /* deinit_module() */ - &tsx_handler, /* tsx_handler() */ -}; - -/* - * Module initialization. - * This will be called by endpoint when it initializes all modules. - */ -static pj_status_t mod_init( pjsip_endpoint *endpt, - struct pjsip_module *mod, pj_uint32_t id ) -{ - pj_pool_t *pool; - - pool = pjsip_endpt_create_pool(endpt, "esubmgr", MGR_POOL_SIZE, MGR_POOL_INC); - if (!pool) - return -1; - - /* Manager initialization: create hash table and mutex. */ - mgr.pool = pool; - mgr.endpt = endpt; - mgr.ht = pj_hash_create(pool, HASH_TABLE_SIZE); - if (!mgr.ht) - return -1; - - mgr.mutex = pj_mutex_create(pool, "esubmgr", PJ_MUTEX_SIMPLE); - if (!mgr.mutex) - return -1; - - /* Attach manager to module. */ - mod->mod_data = &mgr; - - /* Init package list. */ - pj_list_init(&mgr.pkg_list); - - /* Init Allow-Events header. */ - mgr.allow_events = pjsip_allow_events_hdr_create(mgr.pool); - - /* Save the module ID. */ - mod_id = id; - - pjsip_event_notify_init_parser(); - return 0; -} - -/* - * Module deinitialization. - * Called by endpoint. - */ -static pj_status_t mod_deinit( struct pjsip_module *mod ) -{ - pj_mutex_lock(mgr.mutex); - pj_mutex_destroy(mgr.mutex); - pjsip_endpt_destroy_pool(mgr.endpt, mgr.pool); - return 0; -} - -/* - * This public function is called by application to register callback. - * In exchange, the instance of the module is returned. - */ -PJ_DEF(pjsip_module*) pjsip_event_sub_get_module(void) -{ - return &event_sub_module; -} - -/* - * Register event package. - */ -PJ_DEF(pj_status_t) pjsip_event_sub_register_pkg( const pj_str_t *event, - int accept_cnt, - const pj_str_t accept[], - const pjsip_event_sub_pkg_cb *cb ) -{ - package *pkg; - int i; - - pj_mutex_lock(mgr.mutex); - - /* Create and register new package. */ - pkg = pj_pool_alloc(mgr.pool, sizeof(*pkg)); - pj_strdup(mgr.pool, &pkg->event, event); - pj_list_insert_before(&mgr.pkg_list, pkg); - - /* Save Accept specification. */ - pkg->accept_cnt = accept_cnt; - pkg->accept = pj_pool_alloc(mgr.pool, accept_cnt*sizeof(pj_str_t)); - for (i=0; i<accept_cnt; ++i) { - pj_strdup(mgr.pool, &pkg->accept[i], &accept[i]); - } - - /* Copy callback. */ - pj_memcpy(&pkg->cb, cb, sizeof(*cb)); - - /* Update Allow-Events header. */ - pj_assert(mgr.allow_events->event_cnt < PJSIP_MAX_ALLOW_EVENTS); - mgr.allow_events->events[mgr.allow_events->event_cnt++] = pkg->event; - - pj_mutex_unlock(mgr.mutex); - return 0; -} - -/* - * Create subscription key (for hash table). - */ -static void create_subscriber_key( pj_str_t *key, pj_pool_t *pool, - pjsip_role_e role, - const pj_str_t *call_id, const pj_str_t *from_tag) -{ - char *p; - - p = key->ptr = pj_pool_alloc(pool, call_id->slen + from_tag->slen + 3); - *p++ = (role == PJSIP_ROLE_UAS ? 'S' : 'C'); - *p++ = '$'; - pj_memcpy(p, call_id->ptr, call_id->slen); - p += call_id->slen; - *p++ = '$'; - pj_memcpy(p, from_tag->ptr, from_tag->slen); - p += from_tag->slen; - - key->slen = p - key->ptr; -} - - -/* - * Create UAC subscription. - */ -PJ_DEF(pjsip_event_sub*) pjsip_event_sub_create( pjsip_endpoint *endpt, - const pj_str_t *from, - const pj_str_t *to, - const pj_str_t *event, - int expires, - int accept_cnt, - const pj_str_t accept[], - void *user_data, - const pjsip_event_sub_cb *cb) -{ - pjsip_tx_data *tdata; - pj_pool_t *pool; - const pjsip_hdr *hdr; - pjsip_event_sub *sub; - PJ_USE_EXCEPTION; - - PJ_LOG(5,(THIS_FILE, "Creating event subscription %.*s to %.*s", - event->slen, event->ptr, to->slen, to->ptr)); - - /* Create pool for the event subscription. */ - pool = pjsip_endpt_create_pool(endpt, "esub", SUB_POOL_SIZE, SUB_POOL_INC); - if (!pool) { - return NULL; - } - - /* Init subscription. */ - sub = pj_pool_calloc(pool, 1, sizeof(*sub)); - sub->pool = pool; - sub->endpt = endpt; - sub->role = PJSIP_ROLE_UAC; - sub->state = PJSIP_EVENT_SUB_STATE_PENDING; - sub->state_str = state[sub->state]; - sub->user_data = user_data; - sub->timer.id = 0; - sub->default_interval = expires; - pj_memcpy(&sub->cb, cb, sizeof(*cb)); - pj_list_init(&sub->auth_sess); - pj_list_init(&sub->route_set); - sub->mutex = pj_mutex_create(pool, "esub", PJ_MUTEX_RECURSE); - if (!sub->mutex) { - pjsip_endpt_destroy_pool(endpt, pool); - return NULL; - } - - /* The easiest way to parse the parameters is to create a dummy request! */ - tdata = pjsip_endpt_create_request( endpt, &SUBSCRIBE, to, from, to, from, - NULL, -1, NULL); - if (!tdata) { - pj_mutex_destroy(sub->mutex); - pjsip_endpt_destroy_pool(endpt, pool); - return NULL; - } - - /* - * Duplicate headers in the request to our structure. - */ - PJ_TRY { - int i; - - /* From */ - hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_FROM, NULL); - pj_assert(hdr != NULL); - sub->from = pjsip_hdr_clone(pool, hdr); - - /* To */ - hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_TO, NULL); - pj_assert(hdr != NULL); - sub->to = pjsip_hdr_clone(pool, hdr); - - /* Contact. */ - sub->contact = pjsip_contact_hdr_create(pool); - sub->contact->uri = sub->from->uri; - - /* Call-ID */ - hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CALL_ID, NULL); - pj_assert(hdr != NULL); - sub->call_id = pjsip_hdr_clone(pool, hdr); - - /* CSeq */ - sub->cseq = pj_rand() % 0xFFFF; - - /* Event. */ - sub->event = pjsip_event_hdr_create(sub->pool); - pj_strdup(pool, &sub->event->event_type, event); - - /* Expires. */ - sub->uac_expires = pjsip_expires_hdr_create(pool); - sub->uac_expires->ivalue = expires; - - /* Accept. */ - sub->local_accept = pjsip_accept_hdr_create(pool); - for (i=0; i<accept_cnt && i < PJSIP_MAX_ACCEPT_COUNT; ++i) { - sub->local_accept->count++; - pj_strdup(sub->pool, &sub->local_accept->values[i], &accept[i]); - } - - /* Register to hash table. */ - create_subscriber_key( &sub->key, pool, PJSIP_ROLE_UAC, - &sub->call_id->id, &sub->from->tag); - pj_mutex_lock( mgr.mutex ); - pj_hash_set( pool, mgr.ht, sub->key.ptr, sub->key.slen, sub); - pj_mutex_unlock( mgr.mutex ); - - } - PJ_DEFAULT { - PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): caught exception %d during init", - sub, state[sub->state].ptr, PJ_GET_EXCEPTION())); - - pjsip_tx_data_dec_ref(tdata); - pj_mutex_destroy(sub->mutex); - pjsip_endpt_destroy_pool(endpt, sub->pool); - return NULL; - } - PJ_END; - - /* All set, delete temporary transmit data as we don't need it. */ - pjsip_tx_data_dec_ref(tdata); - - PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): client created, target=%.*s, event=%.*s", - sub, state[sub->state].ptr, - to->slen, to->ptr, event->slen, event->ptr)); - - return sub; -} - -/* - * Set credentials. - */ -PJ_DEF(pj_status_t) pjsip_event_sub_set_credentials( pjsip_event_sub *sub, - int count, - const pjsip_cred_info cred[]) -{ - pj_mutex_lock(sub->mutex); - if (count > 0) { - sub->cred_info = pj_pool_alloc(sub->pool, count*sizeof(pjsip_cred_info)); - pj_memcpy( sub->cred_info, cred, count*sizeof(pjsip_cred_info)); - } - sub->cred_cnt = count; - pj_mutex_unlock(sub->mutex); - return 0; -} - -/* - * Set route-set. - */ -PJ_DEF(pj_status_t) pjsip_event_sub_set_route_set( pjsip_event_sub *sub, - const pjsip_route_hdr *route_set ) -{ - const pjsip_route_hdr *hdr; - - pj_mutex_lock(sub->mutex); - - /* Clear existing route set. */ - pj_list_init(&sub->route_set); - - /* Duplicate route headers. */ - hdr = route_set->next; - while (hdr != route_set) { - pjsip_route_hdr *new_hdr = pjsip_hdr_clone(sub->pool, hdr); - pj_list_insert_before(&sub->route_set, new_hdr); - hdr = hdr->next; - } - - pj_mutex_unlock(sub->mutex); - - return 0; -} - -/* - * Send subscribe request. - */ -PJ_DEF(pj_status_t) pjsip_event_sub_subscribe( pjsip_event_sub *sub ) -{ - pj_status_t status; - - pj_mutex_lock(sub->mutex); - status = send_sub_refresh(sub); - pj_mutex_unlock(sub->mutex); - - return status; -} - -/* - * Destroy subscription. - * If there are pending transactions, then this will just set the flag. - */ -PJ_DEF(pj_status_t) pjsip_event_sub_destroy(pjsip_event_sub *sub) -{ - pj_assert(sub != NULL); - if (sub == NULL) - return -1; - - /* Application must terminate the subscription first. */ - pj_assert(sub->state == PJSIP_EVENT_SUB_STATE_NULL || - sub->state == PJSIP_EVENT_SUB_STATE_TERMINATED); - - PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): about to be destroyed", - sub, state[sub->state].ptr)); - - pj_mutex_lock(mgr.mutex); - pj_mutex_lock(sub->mutex); - - /* Set delete flag. */ - sub->delete_flag = 1; - - /* Unregister timer, if any. */ - if (sub->timer.id != 0) { - pjsip_endpt_cancel_timer(sub->endpt, &sub->timer); - sub->timer.id = 0; - } - - if (sub->pending_tsx > 0) { - pj_mutex_unlock(sub->mutex); - pj_mutex_unlock(mgr.mutex); - PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): has %d pending, will destroy later", - sub, state[sub->state].ptr, - sub->pending_tsx)); - return 1; - } - - /* Unregister from hash table. */ - pj_hash_set(sub->pool, mgr.ht, sub->key.ptr, sub->key.slen, NULL); - - /* Destroy. */ - pj_mutex_destroy(sub->mutex); - pjsip_endpt_destroy_pool(sub->endpt, sub->pool); - - pj_mutex_unlock(mgr.mutex); - - PJ_LOG(4,(THIS_FILE, "event_sub%p: destroyed", sub)); - return 0; -} - -/* Change state. */ -static void sub_set_state( pjsip_event_sub *sub, int new_state) -{ - PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): changed state to %s", - sub, state[sub->state].ptr, state[new_state].ptr)); - sub->state = new_state; - sub->state_str = state[new_state]; -} - -/* - * Refresh subscription. - */ -static pj_status_t send_sub_refresh( pjsip_event_sub *sub ) -{ - pjsip_tx_data *tdata; - pj_status_t status; - const pjsip_route_hdr *route; - - pj_assert(sub->role == PJSIP_ROLE_UAC); - pj_assert(sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED); - if (sub->role != PJSIP_ROLE_UAC || - sub->state == PJSIP_EVENT_SUB_STATE_TERMINATED) - { - return -1; - } - - PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): refreshing subscription", - sub, state[sub->state].ptr)); - - /* Create request. */ - tdata = pjsip_endpt_create_request_from_hdr( sub->endpt, - &SUBSCRIBE, - sub->to->uri, - sub->from, sub->to, - sub->contact, sub->call_id, - sub->cseq++, - NULL); - - if (!tdata) { - PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): refresh: unable to create tx data!", - sub, state[sub->state].ptr)); - return -1; - } - - pjsip_msg_add_hdr( tdata->msg, - pjsip_hdr_shallow_clone(tdata->pool, sub->event)); - pjsip_msg_add_hdr( tdata->msg, - pjsip_hdr_shallow_clone(tdata->pool, sub->uac_expires)); - pjsip_msg_add_hdr( tdata->msg, - pjsip_hdr_shallow_clone(tdata->pool, sub->local_accept)); - pjsip_msg_add_hdr( tdata->msg, - pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events)); - - /* Authentication */ - pjsip_auth_init_req( sub->pool, tdata, &sub->auth_sess, - sub->cred_cnt, sub->cred_info); - - /* Route set. */ - route = sub->route_set.next; - while (route != &sub->route_set) { - pj_list_insert_before( &tdata->msg->hdr, - pjsip_hdr_shallow_clone(tdata->pool, route)); - route = route->next; - } - - /* Send */ - status = pjsip_endpt_send_request( sub->endpt, tdata, -1, sub, - &on_subscribe_response); - if (status == 0) { - sub->pending_tsx++; - } else { - PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): FAILED to refresh subscription!", - sub, state[sub->state].ptr)); - } - - return status; -} - -/* - * Stop subscription. - */ -PJ_DEF(pj_status_t) pjsip_event_sub_unsubscribe( pjsip_event_sub *sub ) -{ - pjsip_tx_data *tdata; - const pjsip_route_hdr *route; - pj_status_t status; - - PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): unsubscribing...", - sub, state[sub->state].ptr)); - - /* Lock subscription. */ - pj_mutex_lock(sub->mutex); - - pj_assert(sub->role == PJSIP_ROLE_UAC); - - /* Kill refresh timer, if any. */ - if (sub->timer.id != 0) { - sub->timer.id = 0; - pjsip_endpt_cancel_timer(sub->endpt, &sub->timer); - } - - /* Create request. */ - tdata = pjsip_endpt_create_request_from_hdr( sub->endpt, - &SUBSCRIBE, - sub->to->uri, - sub->from, sub->to, - sub->contact, sub->call_id, - sub->cseq++, - NULL); - - if (!tdata) { - pj_mutex_unlock(sub->mutex); - return -1; - } - - /* Add headers to request. */ - pjsip_msg_add_hdr( tdata->msg, pjsip_hdr_shallow_clone(tdata->pool, sub->event)); - sub->uac_expires->ivalue = 0; - pjsip_msg_add_hdr( tdata->msg, pjsip_hdr_shallow_clone(tdata->pool, sub->uac_expires)); - - /* Add authentication. */ - pjsip_auth_init_req( sub->pool, tdata, &sub->auth_sess, - sub->cred_cnt, sub->cred_info); - - - /* Route set. */ - route = sub->route_set.next; - while (route != &sub->route_set) { - pj_list_insert_before( &tdata->msg->hdr, - pjsip_hdr_shallow_clone(tdata->pool, route)); - route = route->next; - } - - /* Prevent timer from refreshing itself. */ - sub->default_interval = 0; - - /* Set state. */ - sub_set_state( sub, PJSIP_EVENT_SUB_STATE_TERMINATED ); - - /* Send the request. */ - status = pjsip_endpt_send_request( sub->endpt, tdata, -1, sub, - &on_subscribe_response); - if (status == 0) { - sub->pending_tsx++; - } - - pj_mutex_unlock(sub->mutex); - - if (status != 0) { - PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): FAILED to unsubscribe!", - sub, state[sub->state].ptr)); - } - - return status; -} - -/* - * Send notify. - */ -PJ_DEF(pj_status_t) pjsip_event_sub_notify(pjsip_event_sub *sub, - pjsip_event_sub_state new_state, - const pj_str_t *reason, - pjsip_msg_body *body) -{ - pjsip_tx_data *tdata; - pjsip_sub_state_hdr *ss_hdr; - const pjsip_route_hdr *route; - pj_time_val now; - pj_status_t status; - pjsip_event_sub_state old_state = sub->state; - - pj_gettimeofday(&now); - - pj_assert(sub->role == PJSIP_ROLE_UAS); - if (sub->role != PJSIP_ROLE_UAS) - return -1; - - PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): sending NOTIFY", - sub, state[new_state].ptr)); - - /* Lock subscription. */ - pj_mutex_lock(sub->mutex); - - /* Can not send NOTIFY if current state is NULL. We can accept TERMINATED. */ - if (sub->state==PJSIP_EVENT_SUB_STATE_NULL) { - pj_assert(0); - pj_mutex_unlock(sub->mutex); - return -1; - } - - /* Update state no matter what. */ - sub_set_state(sub, new_state); - - /* Create transmit data. */ - tdata = pjsip_endpt_create_request_from_hdr( sub->endpt, - &NOTIFY, - sub->to->uri, - sub->from, sub->to, - sub->contact, sub->call_id, - sub->cseq++, - NULL); - if (!tdata) { - pj_mutex_unlock(sub->mutex); - return -1; - } - - /* Add Event header. */ - pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_shallow_clone(tdata->pool, sub->event)); - - /* Add Subscription-State header. */ - ss_hdr = pjsip_sub_state_hdr_create(tdata->pool); - ss_hdr->sub_state = state[new_state]; - ss_hdr->expires_param = sub->expiry_time.sec - now.sec; - if (ss_hdr->expires_param < 0) - ss_hdr->expires_param = 0; - if (reason) - pj_strdup(tdata->pool, &ss_hdr->reason_param, reason); - pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)ss_hdr); - - /* Add Allow-Events header. */ - pjsip_msg_add_hdr( tdata->msg, - pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events)); - - /* Add authentication */ - pjsip_auth_init_req( sub->pool, tdata, &sub->auth_sess, - sub->cred_cnt, sub->cred_info); - - /* Route set. */ - route = sub->route_set.next; - while (route != &sub->route_set) { - pj_list_insert_before( &tdata->msg->hdr, - pjsip_hdr_shallow_clone(tdata->pool, route)); - route = route->next; - } - - /* Attach body. */ - tdata->msg->body = body; - - /* That's it, send! */ - status = pjsip_endpt_send_request( sub->endpt, tdata, -1, sub, &on_notify_response); - if (status == 0) - sub->pending_tsx++; - - /* If terminated notify application. */ - if (new_state!=old_state && new_state==PJSIP_EVENT_SUB_STATE_TERMINATED) { - if (sub->cb.on_sub_terminated) { - sub->pending_tsx++; - (*sub->cb.on_sub_terminated)(sub, reason); - sub->pending_tsx--; - } - } - - /* Unlock subscription. */ - pj_mutex_unlock(sub->mutex); - - if (status != 0) { - PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): failed to send NOTIFY", - sub, state[sub->state].ptr)); - } - - if (sub->delete_flag && sub->pending_tsx <= 0) { - pjsip_event_sub_destroy(sub); - } - return status; -} - - -/* If this timer callback is called, it means subscriber hasn't refreshed its - * subscription on-time. Set the state to terminated. This will also send - * NOTIFY with Subscription-State set to terminated. - */ -static void uas_expire_timer_cb( pj_timer_heap_t *timer_heap, pj_timer_entry *entry) -{ - pjsip_event_sub *sub = entry->user_data; - pj_str_t reason = { "timeout", 7 }; - - PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): UAS subscription expired!", - sub, state[sub->state].ptr)); - - pj_mutex_lock(sub->mutex); - sub->timer.id = 0; - - if (sub->cb.on_sub_terminated && sub->state!=PJSIP_EVENT_SUB_STATE_TERMINATED) { - /* Notify application, but prevent app from destroying the sub. */ - ++sub->pending_tsx; - (*sub->cb.on_sub_terminated)(sub, &reason); - --sub->pending_tsx; - } - //pjsip_event_sub_notify( sub, PJSIP_EVENT_SUB_STATE_TERMINATED, - // &reason, NULL); - pj_mutex_unlock(sub->mutex); - -} - -/* Schedule notifier expiration. */ -static void sub_schedule_uas_expire( pjsip_event_sub *sub, int sec_delay) -{ - pj_time_val delay = { 0, 0 }; - pj_parsed_time pt; - - if (sub->timer.id != 0) - pjsip_endpt_cancel_timer(sub->endpt, &sub->timer); - - pj_gettimeofday(&sub->expiry_time); - sub->expiry_time.sec += sec_delay; - - sub->timer.id = TIMER_ID_UAS_EXPIRY; - sub->timer.user_data = sub; - sub->timer.cb = &uas_expire_timer_cb; - delay.sec = sec_delay; - pjsip_endpt_schedule_timer( sub->endpt, &sub->timer, &delay); - - pj_time_decode(&sub->expiry_time, &pt); - PJ_LOG(4,(THIS_FILE, - "event_sub%p (%s)(UAS): will expire at %02d:%02d:%02d (in %d secs)", - sub, state[sub->state].ptr, pt.hour, pt.min, pt.sec, sec_delay)); -} - -/* This timer is called for UAC to refresh the subscription. */ -static void refresh_timer_cb( pj_timer_heap_t *timer_heap, pj_timer_entry *entry) -{ - pjsip_event_sub *sub = entry->user_data; - - PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): refresh subscription timer", - sub, state[sub->state].ptr)); - - pj_mutex_lock(sub->mutex); - sub->timer.id = 0; - send_sub_refresh(sub); - pj_mutex_unlock(sub->mutex); -} - - -/* This will update the UAC's refresh schedule. */ -static void update_next_refresh(pjsip_event_sub *sub, int interval) -{ - pj_time_val delay = {0, 0}; - pj_parsed_time pt; - - if (interval < SECONDS_BEFORE_EXPIRY) { - PJ_LOG(4,(THIS_FILE, - "event_sub%p (%s): expiration delay too short (%d sec)! updated.", - sub, state[sub->state].ptr, interval)); - interval = SECONDS_BEFORE_EXPIRY; - } - - if (sub->timer.id != 0) - pjsip_endpt_cancel_timer(sub->endpt, &sub->timer); - - sub->timer.id = TIMER_ID_REFRESH; - sub->timer.user_data = sub; - sub->timer.cb = &refresh_timer_cb; - pj_gettimeofday(&sub->expiry_time); - delay.sec = interval - SECONDS_BEFORE_EXPIRY; - sub->expiry_time.sec += delay.sec; - - pj_time_decode(&sub->expiry_time, &pt); - PJ_LOG(4,(THIS_FILE, - "event_sub%p (%s): will send SUBSCRIBE at %02d:%02d:%02d (in %d secs)", - sub, state[sub->state].ptr, - pt.hour, pt.min, pt.sec, - delay.sec)); - - pjsip_endpt_schedule_timer( sub->endpt, &sub->timer, &delay ); -} - - -/* Find subscription in the hash table. - * If found, lock the subscription before returning to caller. - */ -static pjsip_event_sub *find_sub(pjsip_rx_data *rdata) -{ - pj_str_t key; - pjsip_role_e role; - pjsip_event_sub *sub; - pjsip_method *method = &rdata->msg->line.req.method; - pj_str_t *tag; - - if (rdata->msg->type == PJSIP_REQUEST_MSG) { - if (pjsip_method_cmp(method, &SUBSCRIBE)==0) { - role = PJSIP_ROLE_UAS; - tag = &rdata->to_tag; - } else { - pj_assert(pjsip_method_cmp(method, &NOTIFY) == 0); - role = PJSIP_ROLE_UAC; - tag = &rdata->to_tag; - } - } else { - if (pjsip_method_cmp(&rdata->cseq->method, &SUBSCRIBE)==0) { - role = PJSIP_ROLE_UAC; - tag = &rdata->from_tag; - } else { - pj_assert(pjsip_method_cmp(method, &NOTIFY) == 0); - role = PJSIP_ROLE_UAS; - tag = &rdata->from_tag; - } - } - create_subscriber_key( &key, rdata->pool, role, &rdata->call_id, tag); - - pj_mutex_lock(mgr.mutex); - sub = pj_hash_get(mgr.ht, key.ptr, key.slen); - if (sub) - pj_mutex_lock(sub->mutex); - pj_mutex_unlock(mgr.mutex); - - return sub; -} - - -/* This function is called when we receive SUBSCRIBE request message - * to refresh existing subscription. - */ -static void on_received_sub_refresh( pjsip_event_sub *sub, - pjsip_transaction *tsx, pjsip_rx_data *rdata) -{ - pjsip_event_hdr *e; - pjsip_expires_hdr *expires; - pj_str_t hname; - int status = 200; - pj_str_t reason_phrase = { NULL, 0 }; - int new_state = sub->state; - int old_state = sub->state; - int new_interval = 0; - pjsip_tx_data *tdata; - - PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): received target refresh", - sub, state[sub->state].ptr)); - - /* Check that the event matches. */ - hname = pj_str("Event"); - e = pjsip_msg_find_hdr_by_name( rdata->msg, &hname, NULL); - if (!e) { - status = 400; - reason_phrase = pj_str("Missing Event header"); - goto send_response; - } - if (pj_stricmp(&e->event_type, &sub->event->event_type) != 0 || - pj_stricmp(&e->id_param, &sub->event->id_param) != 0) - { - status = 481; - reason_phrase = pj_str("Subscription does not exist"); - goto send_response; - } - - /* Check server state. */ - if (sub->state == PJSIP_EVENT_SUB_STATE_TERMINATED) { - status = 481; - reason_phrase = pj_str("Subscription does not exist"); - goto send_response; - } - - /* Check expires header. */ - expires = pjsip_msg_find_hdr(rdata->msg, PJSIP_H_EXPIRES, NULL); - if (!expires) { - /* - status = 400; - reason_phrase = pj_str("Missing Expires header"); - goto send_response; - */ - new_interval = sub->default_interval; - } else { - /* Check that interval is not too short. - * Note that expires time may be zero (for unsubscription). - */ - new_interval = expires->ivalue; - if (new_interval != 0 && new_interval < SECONDS_BEFORE_EXPIRY) { - status = PJSIP_SC_INTERVAL_TOO_BRIEF; - goto send_response; - } - } - - /* Update interval. */ - sub->default_interval = new_interval; - pj_gettimeofday(&sub->expiry_time); - sub->expiry_time.sec += new_interval; - - /* Update timer only if this is not unsubscription. */ - if (new_interval > 0) { - sub->default_interval = new_interval; - sub_schedule_uas_expire( sub, new_interval ); - - /* Call callback. */ - if (sub->cb.on_received_refresh) { - sub->pending_tsx++; - (*sub->cb.on_received_refresh)(sub, rdata); - sub->pending_tsx--; - } - } - -send_response: - tdata = pjsip_endpt_create_response( sub->endpt, rdata, status); - if (tdata) { - if (reason_phrase.slen) - tdata->msg->line.status.reason = reason_phrase; - - /* Add Expires header. */ - expires = pjsip_expires_hdr_create(tdata->pool); - expires->ivalue = sub->default_interval; - pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires); - - if (PJSIP_IS_STATUS_IN_CLASS(status,200)) { - pjsip_msg_add_hdr(tdata->msg, - pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events)); - } - /* Send down to transaction. */ - pjsip_tsx_on_tx_msg(tsx, tdata); - } - - if (sub->default_interval==0 || !PJSIP_IS_STATUS_IN_CLASS(status,200)) { - /* Notify application if sub is terminated. */ - new_state = PJSIP_EVENT_SUB_STATE_TERMINATED; - sub_set_state(sub, new_state); - if (new_state!=old_state && sub->cb.on_sub_terminated) { - pj_str_t reason = {"", 0}; - if (reason_phrase.slen) reason = reason_phrase; - else reason = *pjsip_get_status_text(status); - - sub->pending_tsx++; - (*sub->cb.on_sub_terminated)(sub, &reason); - sub->pending_tsx--; - } - } - - pj_mutex_unlock(sub->mutex); - - /* Prefer to call log when we're not holding the mutex. */ - PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): sent refresh response %s, status=%d", - sub, state[sub->state].ptr, - (tdata ? tdata->obj_name : "null"), status)); - - /* Check if application has requested deletion. */ - if (sub->delete_flag && sub->pending_tsx <= 0) { - pjsip_event_sub_destroy(sub); - } - -} - - -/* This function is called when we receive SUBSCRIBE request message for - * a new subscription. - */ -static void on_new_subscription( pjsip_transaction *tsx, pjsip_rx_data *rdata ) -{ - package *pkg; - pj_pool_t *pool; - pjsip_event_sub *sub = NULL; - pj_str_t hname; - int status = 200; - pj_str_t reason = { NULL, 0 }; - pjsip_tx_data *tdata; - pjsip_expires_hdr *expires; - pjsip_accept_hdr *accept; - pjsip_event_hdr *evhdr; - - /* Get the Event header. */ - hname = pj_str("Event"); - evhdr = pjsip_msg_find_hdr_by_name(rdata->msg, &hname, NULL); - if (!evhdr) { - status = 400; - reason = pj_str("No Event header in request"); - goto send_response; - } - - /* Find corresponding package. - * We don't lock the manager's mutex since we assume the package list - * won't change once the application is running! - */ - pkg = mgr.pkg_list.next; - while (pkg != &mgr.pkg_list) { - if (pj_stricmp(&pkg->event, &evhdr->event_type) == 0) - break; - pkg = pkg->next; - } - - if (pkg == &mgr.pkg_list) { - /* Event type is not supported by any packages! */ - status = 489; - reason = pj_str("Bad Event"); - goto send_response; - } - - /* First check that the Accept specification matches the - * package's Accept types. - */ - accept = pjsip_msg_find_hdr(rdata->msg, PJSIP_H_ACCEPT, NULL); - if (accept) { - unsigned i; - pj_str_t *content_type = NULL; - - for (i=0; i<accept->count && !content_type; ++i) { - int j; - for (j=0; j<pkg->accept_cnt; ++j) { - if (pj_stricmp(&accept->values[i], &pkg->accept[j])==0) { - content_type = &pkg->accept[j]; - break; - } - } - } - - if (!content_type) { - status = PJSIP_SC_NOT_ACCEPTABLE_HERE; - goto send_response; - } - } - - /* Check whether the package wants to accept the subscription. */ - pj_assert(pkg->cb.on_query_subscribe != NULL); - (*pkg->cb.on_query_subscribe)(rdata, &status); - if (!PJSIP_IS_STATUS_IN_CLASS(status,200)) - goto send_response; - - /* Create new subscription record. */ - pool = pjsip_endpt_create_pool(tsx->endpt, "esub", - SUB_POOL_SIZE, SUB_POOL_INC); - if (!pool) { - status = 500; - goto send_response; - } - sub = pj_pool_calloc(pool, 1, sizeof(*sub)); - sub->pool = pool; - sub->mutex = pj_mutex_create(pool, "esub", PJ_MUTEX_RECURSE); - if (!sub->mutex) { - status = 500; - goto send_response; - } - - PJ_LOG(4,(THIS_FILE, "event_sub%p: notifier is created.", sub)); - - /* Start locking mutex. */ - pj_mutex_lock(sub->mutex); - - /* Init UAS subscription */ - sub->endpt = tsx->endpt; - sub->role = PJSIP_ROLE_UAS; - sub->state = PJSIP_EVENT_SUB_STATE_PENDING; - sub->state_str = state[sub->state]; - pj_list_init(&sub->auth_sess); - pj_list_init(&sub->route_set); - sub->from = pjsip_hdr_clone(pool, rdata->to); - pjsip_fromto_set_from(sub->from); - if (sub->from->tag.slen == 0) { - pj_create_unique_string(pool, &sub->from->tag); - rdata->to->tag = sub->from->tag; - } - sub->to = pjsip_hdr_clone(pool, rdata->from); - pjsip_fromto_set_to(sub->to); - sub->contact = pjsip_contact_hdr_create(pool); - sub->contact->uri = sub->from->uri; - sub->call_id = pjsip_cid_hdr_create(pool); - pj_strdup(pool, &sub->call_id->id, &rdata->call_id); - sub->cseq = pj_rand() % 0xFFFF; - - expires = pjsip_msg_find_hdr( rdata->msg, PJSIP_H_EXPIRES, NULL); - if (expires) { - sub->default_interval = expires->ivalue; - if (sub->default_interval > 0 && - sub->default_interval < SECONDS_BEFORE_EXPIRY) - { - status = 423; /* Interval too short. */ - goto send_response; - } - } else { - sub->default_interval = 600; - } - - /* Clone Event header. */ - sub->event = pjsip_hdr_clone(pool, evhdr); - - /* Register to hash table. */ - create_subscriber_key(&sub->key, pool, PJSIP_ROLE_UAS, &sub->call_id->id, - &sub->from->tag); - pj_mutex_lock(mgr.mutex); - pj_hash_set(pool, mgr.ht, sub->key.ptr, sub->key.slen, sub); - pj_mutex_unlock(mgr.mutex); - - /* Set timer where subscription will expire only when expires<>0. - * Subscriber may send new subscription with expires==0. - */ - if (sub->default_interval != 0) { - sub_schedule_uas_expire( sub, sub->default_interval-SECONDS_BEFORE_EXPIRY); - } - - /* Notify application. */ - if (pkg->cb.on_subscribe) { - pjsip_event_sub_cb *cb = NULL; - sub->pending_tsx++; - (*pkg->cb.on_subscribe)(sub, rdata, &cb, &sub->default_interval); - sub->pending_tsx--; - if (cb == NULL) - pj_memset(&sub->cb, 0, sizeof(*cb)); - else - pj_memcpy(&sub->cb, cb, sizeof(*cb)); - } - - -send_response: - PJ_LOG(4,(THIS_FILE, "event_sub%p (%s)(UAS): status=%d", - sub, state[sub->state].ptr, status)); - - tdata = pjsip_endpt_create_response( tsx->endpt, rdata, status); - if (tdata) { - if (reason.slen) { - /* Customize reason text. */ - tdata->msg->line.status.reason = reason; - } - if (PJSIP_IS_STATUS_IN_CLASS(status,200)) { - /* Add Expires header. */ - pjsip_expires_hdr *hdr; - - hdr = pjsip_expires_hdr_create(tdata->pool); - hdr->ivalue = sub->default_interval; - pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)hdr ); - } - if (status == 423) { - /* Add Min-Expires header. */ - pjsip_min_expires_hdr *hdr; - - hdr = pjsip_min_expires_hdr_create(tdata->pool); - hdr->ivalue = SECONDS_BEFORE_EXPIRY; - pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)hdr); - } - if (status == 489 || - status==PJSIP_SC_NOT_ACCEPTABLE_HERE || - PJSIP_IS_STATUS_IN_CLASS(status,200)) - { - /* Add Allow-Events header. */ - pjsip_hdr *hdr; - hdr = pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events); - pjsip_msg_add_hdr(tdata->msg, hdr); - - /* Should add Accept header?. */ - } - - pjsip_tsx_on_tx_msg(tsx, tdata); - } - - /* If received new subscription with expires=0, terminate. */ - if (sub && sub->default_interval == 0) { - pj_assert(sub->state == PJSIP_EVENT_SUB_STATE_TERMINATED); - if (sub->cb.on_sub_terminated) { - pj_str_t reason = { "timeout", 7 }; - (*sub->cb.on_sub_terminated)(sub, &reason); - } - } - - if (!PJSIP_IS_STATUS_IN_CLASS(status,200) || (sub && sub->delete_flag)) { - if (sub && sub->mutex) { - pjsip_event_sub_destroy(sub); - } else if (sub) { - pjsip_endpt_destroy_pool(tsx->endpt, sub->pool); - } - } else { - pj_assert(status >= 200); - pj_mutex_unlock(sub->mutex); - } -} - -/* This is the main callback when SUBSCRIBE request is received. */ -static void on_subscribe_request(pjsip_transaction *tsx, pjsip_rx_data *rdata) -{ - pjsip_event_sub *sub = find_sub(rdata); - - if (sub) - on_received_sub_refresh(sub, tsx, rdata); - else - on_new_subscription(tsx, rdata); -} - - -/* This callback is called when response to SUBSCRIBE is received. */ -static void on_subscribe_response(void *token, pjsip_event *event) -{ - pjsip_event_sub *sub = token; - pjsip_transaction *tsx = event->obj.tsx; - int new_state, old_state = sub->state; - - pj_assert(tsx->status_code >= 200); - if (tsx->status_code < 200) - return; - - pj_assert(sub->role == PJSIP_ROLE_UAC); - - /* Lock mutex. */ - pj_mutex_lock(sub->mutex); - - /* If request failed with 401/407 error, silently retry the request. */ - if (tsx->status_code==401 || tsx->status_code==407) { - pjsip_tx_data *tdata; - tdata = pjsip_auth_reinit_req(sub->endpt, - sub->pool, &sub->auth_sess, - sub->cred_cnt, sub->cred_info, - tsx->last_tx, event->src.rdata ); - if (tdata) { - int status; - pjsip_cseq_hdr *cseq; - cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL); - cseq->cseq = sub->cseq++; - status = pjsip_endpt_send_request( sub->endpt, tdata, - -1, sub, - &on_subscribe_response); - if (status == 0) { - pj_mutex_unlock(sub->mutex); - return; - } - } - } - - if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code,200)) { - /* Update To tag. */ - if (sub->to->tag.slen == 0) - pj_strdup(sub->pool, &sub->to->tag, &event->src.rdata->to_tag); - - new_state = sub->state; - - } else if (tsx->status_code == 481) { - new_state = PJSIP_EVENT_SUB_STATE_TERMINATED; - - } else if (tsx->status_code >= 300) { - /* RFC 3265 Section 3.1.4.2: - * If a SUBSCRIBE request to refresh a subscription fails - * with a non-481 response, the original subscription is still - * considered valid for the duration of original exires. - * - * Note: - * Since we normally send SUBSCRIBE for refreshing the subscription, - * it means the subscription already expired anyway. So we terminate - * the subscription now. - */ - if (sub->state != PJSIP_EVENT_SUB_STATE_ACTIVE) { - new_state = PJSIP_EVENT_SUB_STATE_TERMINATED; - } else { - /* Use this to be compliant with Section 3.1.4.2 - new_state = sub->state; - */ - new_state = PJSIP_EVENT_SUB_STATE_TERMINATED; - } - } else { - pj_assert(0); - new_state = sub->state; - } - - if (new_state != sub->state && sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED) { - sub_set_state(sub, new_state); - } - - if (sub->state == PJSIP_EVENT_SUB_STATE_ACTIVE || - sub->state == PJSIP_EVENT_SUB_STATE_PENDING) - { - /* - * Register timer for next subscription refresh, but only when - * we're not unsubscribing. Also update default_interval and Expires - * header. - */ - if (sub->default_interval > 0 && !sub->delete_flag) { - pjsip_expires_hdr *exp = NULL; - - /* Could be transaction timeout. */ - if (event->src_type == PJSIP_EVENT_RX_MSG) { - exp = pjsip_msg_find_hdr(event->src.rdata->msg, - PJSIP_H_EXPIRES, NULL); - } - - if (exp) { - int delay = exp->ivalue; - if (delay > 0) { - pj_time_val new_expiry; - pj_gettimeofday(&new_expiry); - new_expiry.sec += delay; - if (sub->timer.id==0 || - new_expiry.sec < sub->expiry_time.sec-SECONDS_BEFORE_EXPIRY/2) - { - //if (delay > 0 && delay < sub->default_interval) { - sub->default_interval = delay; - sub->uac_expires->ivalue = delay; - update_next_refresh(sub, delay); - } - } - } - } - } - - /* Call callback. */ - if (!sub->delete_flag) { - if (sub->cb.on_received_sub_response) { - (*sub->cb.on_received_sub_response)(sub, event); - } - } - - /* Notify application if we're terminated. */ - if (new_state!=old_state && new_state==PJSIP_EVENT_SUB_STATE_TERMINATED) { - if (sub->cb.on_sub_terminated) { - pj_str_t reason; - if (event->src_type == PJSIP_EVENT_RX_MSG) - reason = event->src.rdata->msg->line.status.reason; - else - reason = *pjsip_get_status_text(tsx->status_code); - - (*sub->cb.on_sub_terminated)(sub, &reason); - } - } - - /* Decrement pending tsx count. */ - --sub->pending_tsx; - pj_assert(sub->pending_tsx >= 0); - - if (sub->delete_flag && sub->pending_tsx <= 0) { - pjsip_event_sub_destroy(sub); - } else { - pj_mutex_unlock(sub->mutex); - } - - /* DO NOT ACCESS sub FROM NOW ON! IT MIGHT HAVE BEEN DELETED */ -} - -/* - * This callback called when we receive incoming NOTIFY request. - */ -static void on_notify_request(pjsip_transaction *tsx, pjsip_rx_data *rdata) -{ - pjsip_event_sub *sub; - pjsip_tx_data *tdata; - int status = 200; - int old_state; - pj_str_t reason = { NULL, 0 }; - pj_str_t reason_phrase = { NULL, 0 }; - int new_state = PJSIP_EVENT_SUB_STATE_NULL; - - /* Find subscription based on Call-ID and From tag. - * This will also automatically lock the subscription, if it's found. - */ - sub = find_sub(rdata); - if (!sub) { - /* RFC 3265: Section 3.2 Description of NOTIFY Behavior: - * Answer with 481 Subscription does not exist. - */ - PJ_LOG(4,(THIS_FILE, "Unable to find subscription for incoming NOTIFY!")); - status = 481; - reason_phrase = pj_str("Subscription does not exist"); - - } else { - pj_assert(sub->role == PJSIP_ROLE_UAC); - PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): received NOTIFY", - sub, state[sub->state].ptr)); - - } - - new_state = old_state = sub->state; - - /* RFC 3265: Section 3.2.1 - * Check that the Event header match the subscription. - */ - if (status == 200) { - pjsip_event_hdr *hdr; - pj_str_t hname = { "Event", 5 }; - - hdr = pjsip_msg_find_hdr_by_name(rdata->msg, &hname, NULL); - if (!hdr) { - status = PJSIP_SC_BAD_REQUEST; - reason_phrase = pj_str("No Event header found"); - } else if (pj_stricmp(&hdr->event_type, &sub->event->event_type) != 0 || - pj_stricmp(&hdr->id_param, &sub->event->id_param) != 0) - { - status = 481; - reason_phrase = pj_str("Subscription does not exist"); - } - } - - /* Update subscription state and timer. */ - if (status == 200) { - pjsip_sub_state_hdr *hdr; - const pj_str_t hname = { "Subscription-State", 18 }; - const pj_str_t state_active = { "active", 6 }, - state_pending = { "pending", 7}, - state_terminated = { "terminated", 10 }; - - hdr = pjsip_msg_find_hdr_by_name( rdata->msg, &hname, NULL); - if (!hdr) { - status = PJSIP_SC_BAD_REQUEST; - reason_phrase = pj_str("No Subscription-State header found"); - goto process; - } - - /* - * Update subscription state. - */ - if (pj_stricmp(&hdr->sub_state, &state_active) == 0) { - if (sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED) - new_state = PJSIP_EVENT_SUB_STATE_ACTIVE; - } else if (pj_stricmp(&hdr->sub_state, &state_pending) == 0) { - if (sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED) - new_state = PJSIP_EVENT_SUB_STATE_PENDING; - } else if (pj_stricmp(&hdr->sub_state, &state_terminated) == 0) { - new_state = PJSIP_EVENT_SUB_STATE_TERMINATED; - } else { - new_state = PJSIP_EVENT_SUB_STATE_UNKNOWN; - } - - reason = hdr->reason_param; - - if (new_state != sub->state && new_state != PJSIP_EVENT_SUB_STATE_NULL && - sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED) - { - sub_set_state(sub, new_state); - if (new_state == PJSIP_EVENT_SUB_STATE_UNKNOWN) { - pj_strdup_with_null(sub->pool, &sub->state_str, &hdr->sub_state); - } else { - sub->state_str = state[new_state]; - } - } - - /* - * Update timeout timer in required, just in case notifier changed the - * expiration to shorter time. - * Section 3.2.2: the expires param can only shorten the interval. - */ - if ((sub->state==PJSIP_EVENT_SUB_STATE_ACTIVE || - sub->state==PJSIP_EVENT_SUB_STATE_PENDING) && hdr->expires_param > 0) - { - pj_time_val now, new_expiry; - - pj_gettimeofday(&now); - new_expiry.sec = now.sec + hdr->expires_param; - if (sub->timer.id==0 || - new_expiry.sec < sub->expiry_time.sec-SECONDS_BEFORE_EXPIRY/2) - { - update_next_refresh(sub, hdr->expires_param); - } - } - } - -process: - /* Note: here we sub MAY BE NULL! */ - - /* Send response to NOTIFY */ - tdata = pjsip_endpt_create_response( tsx->endpt, rdata, status ); - if (tdata) { - if (reason_phrase.slen) - tdata->msg->line.status.reason = reason_phrase; - - if (PJSIP_IS_STATUS_IN_CLASS(status,200)) { - pjsip_hdr *hdr; - hdr = pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events); - pjsip_msg_add_hdr( tdata->msg, hdr); - } - - pjsip_tsx_on_tx_msg(tsx, tdata); - } - - /* Call NOTIFY callback, if any. */ - if (sub && PJSIP_IS_STATUS_IN_CLASS(status,200) && sub->cb.on_received_notify) { - sub->pending_tsx++; - (*sub->cb.on_received_notify)(sub, rdata); - sub->pending_tsx--; - } - - /* Check if subscription is terminated and call callback. */ - if (sub && new_state!=old_state && new_state==PJSIP_EVENT_SUB_STATE_TERMINATED) { - if (sub->cb.on_sub_terminated) { - sub->pending_tsx++; - (*sub->cb.on_sub_terminated)(sub, &reason); - sub->pending_tsx--; - } - } - - /* Check if application has requested deletion. */ - if (sub && sub->delete_flag && sub->pending_tsx <= 0) { - pjsip_event_sub_destroy(sub); - } else if (sub) { - pj_mutex_unlock(sub->mutex); - } -} - -/* This callback is called when we received NOTIFY response. */ -static void on_notify_response(void *token, pjsip_event *event) -{ - pjsip_event_sub *sub = token; - pjsip_event_sub_state old_state = sub->state; - pjsip_transaction *tsx = event->obj.tsx; - - /* Lock the subscription. */ - pj_mutex_lock(sub->mutex); - - pj_assert(sub->role == PJSIP_ROLE_UAS); - - /* If request failed with authorization failure, silently retry. */ - if (tsx->status_code==401 || tsx->status_code==407) { - pjsip_tx_data *tdata; - tdata = pjsip_auth_reinit_req(sub->endpt, - sub->pool, &sub->auth_sess, - sub->cred_cnt, sub->cred_info, - tsx->last_tx, event->src.rdata ); - if (tdata) { - int status; - pjsip_cseq_hdr *cseq; - cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL); - cseq->cseq = sub->cseq++; - status = pjsip_endpt_send_request( sub->endpt, tdata, - -1, sub, - &on_notify_response); - if (status == 0) { - pj_mutex_unlock(sub->mutex); - return; - } - } - } - - /* Notify application. */ - if (sub->cb.on_received_notify_response) - (*sub->cb.on_received_notify_response)(sub, event); - - /* Check for response 481. */ - if (event->obj.tsx->status_code == 481) { - /* Remote says that the subscription does not exist! - * Terminate subscription! - */ - sub_set_state(sub, PJSIP_EVENT_SUB_STATE_TERMINATED); - if (sub->timer.id) { - pjsip_endpt_cancel_timer(sub->endpt, &sub->timer); - sub->timer.id = 0; - } - - PJ_LOG(4, (THIS_FILE, - "event_sub%p (%s): got 481 response to NOTIFY. Terminating...", - sub, state[sub->state].ptr)); - - /* Notify app. */ - if (sub->state!=old_state && sub->cb.on_sub_terminated) - (*sub->cb.on_sub_terminated)(sub, &event->src.rdata->msg->line.status.reason); - } - - /* Decrement pending transaction count. */ - --sub->pending_tsx; - pj_assert(sub->pending_tsx >= 0); - - /* Check that the subscription is marked for deletion. */ - if (sub->delete_flag && sub->pending_tsx <= 0) { - pjsip_event_sub_destroy(sub); - } else { - pj_mutex_unlock(sub->mutex); - } - - /* DO NOT ACCESS sub, IT MIGHT HAVE BEEN DESTROYED! */ -} - - -/* This is the transaction handler for incoming SUBSCRIBE and NOTIFY - * requests. - */ -static void tsx_handler( struct pjsip_module *mod, pjsip_event *event ) -{ - pjsip_msg *msg; - pjsip_rx_data *rdata; - - /* Only want incoming message events. */ - if (event->src_type != PJSIP_EVENT_RX_MSG) - return; - - rdata = event->src.rdata; - msg = rdata->msg; - - /* Only want to process request messages. */ - if (msg->type != PJSIP_REQUEST_MSG) - return; - - /* Only want the first notification. */ - if (event->obj.tsx && event->obj.tsx->status_code >= 100) - return; - - if (pjsip_method_cmp(&msg->line.req.method, &SUBSCRIBE)==0) { - /* Process incoming SUBSCRIBE request. */ - on_subscribe_request( event->obj.tsx, rdata ); - } else if (pjsip_method_cmp(&msg->line.req.method, &NOTIFY)==0) { - /* Process incoming NOTIFY request. */ - on_notify_request( event->obj.tsx, rdata ); - } -} - diff --git a/pjsip/src/pjsip_simple/event_notify_msg.c b/pjsip/src/pjsip_simple/event_notify_msg.c deleted file mode 100644 index 9d0f0cd7..00000000 --- a/pjsip/src/pjsip_simple/event_notify_msg.c +++ /dev/null @@ -1,307 +0,0 @@ -/* $Id$ - * - */ -#include <pjsip_simple/event_notify_msg.h> -#include <pjsip/print.h> -#include <pjsip/sip_parser.h> -#include <pj/pool.h> -#include <pj/string.h> -#include <pj/except.h> - -static int pjsip_event_hdr_print( pjsip_event_hdr *hdr, - char *buf, pj_size_t size); -static pjsip_event_hdr* pjsip_event_hdr_clone( pj_pool_t *pool, - const pjsip_event_hdr *hdr); -static pjsip_event_hdr* pjsip_event_hdr_shallow_clone( pj_pool_t *pool, - const pjsip_event_hdr*); - -static pjsip_hdr_vptr event_hdr_vptr = -{ - (pjsip_hdr_clone_fptr) &pjsip_event_hdr_clone, - (pjsip_hdr_clone_fptr) &pjsip_event_hdr_shallow_clone, - (pjsip_hdr_print_fptr) &pjsip_event_hdr_print, -}; - - -PJ_DEF(pjsip_event_hdr*) pjsip_event_hdr_create(pj_pool_t *pool) -{ - pj_str_t event = { "Event", 5 }; - pjsip_event_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr)); - hdr->type = PJSIP_H_OTHER; - hdr->name = hdr->sname = event; - hdr->vptr = &event_hdr_vptr; - pj_list_init(hdr); - return hdr; -} - -static int pjsip_event_hdr_print( pjsip_event_hdr *hdr, - char *buf, pj_size_t size) -{ - char *p = buf; - char *endbuf = buf+size; - int printed; - - copy_advance(p, hdr->name); - *p++ = ':'; - *p++ = ' '; - - copy_advance(p, hdr->event_type); - copy_advance_pair(p, ";id=", 4, hdr->id_param); - if (hdr->other_param.slen) - copy_advance(p, hdr->other_param); - return p - buf; -} - -static pjsip_event_hdr* pjsip_event_hdr_clone( pj_pool_t *pool, - const pjsip_event_hdr *rhs) -{ - pjsip_event_hdr *hdr = pjsip_event_hdr_create(pool); - pj_strdup(pool, &hdr->event_type, &rhs->event_type); - pj_strdup(pool, &hdr->id_param, &rhs->id_param); - pj_strdup(pool, &hdr->other_param, &rhs->other_param); - return hdr; -} - -static pjsip_event_hdr* pjsip_event_hdr_shallow_clone( pj_pool_t *pool, - const pjsip_event_hdr *rhs ) -{ - pjsip_event_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr)); - pj_memcpy(hdr, rhs, sizeof(*hdr)); - return hdr; -} - - -static int pjsip_allow_events_hdr_print(pjsip_allow_events_hdr *hdr, - char *buf, pj_size_t size); -static pjsip_allow_events_hdr* -pjsip_allow_events_hdr_clone(pj_pool_t *pool, - const pjsip_allow_events_hdr *hdr); -static pjsip_allow_events_hdr* -pjsip_allow_events_hdr_shallow_clone(pj_pool_t *pool, - const pjsip_allow_events_hdr*); - -static pjsip_hdr_vptr allow_event_hdr_vptr = -{ - (pjsip_hdr_clone_fptr) &pjsip_allow_events_hdr_clone, - (pjsip_hdr_clone_fptr) &pjsip_allow_events_hdr_shallow_clone, - (pjsip_hdr_print_fptr) &pjsip_allow_events_hdr_print, -}; - - -PJ_DEF(pjsip_allow_events_hdr*) pjsip_allow_events_hdr_create(pj_pool_t *pool) -{ - pj_str_t allow_events = { "Allow-Events", 12 }; - pjsip_allow_events_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr)); - hdr->type = PJSIP_H_OTHER; - hdr->name = hdr->sname = allow_events; - hdr->vptr = &allow_event_hdr_vptr; - pj_list_init(hdr); - return hdr; -} - -static int pjsip_allow_events_hdr_print(pjsip_allow_events_hdr *hdr, - char *buf, pj_size_t size) -{ - char *p = buf; - char *endbuf = buf+size; - int printed; - - copy_advance(p, hdr->name); - *p++ = ':'; - *p++ = ' '; - - if (hdr->event_cnt > 0) { - int i; - copy_advance(p, hdr->events[0]); - for (i=1; i<hdr->event_cnt; ++i) { - copy_advance_pair(p, ",", 1, hdr->events[i]); - } - } - - return p - buf; -} - -static pjsip_allow_events_hdr* -pjsip_allow_events_hdr_clone(pj_pool_t *pool, - const pjsip_allow_events_hdr *rhs) -{ - int i; - - pjsip_allow_events_hdr *hdr = pjsip_allow_events_hdr_create(pool); - hdr->event_cnt = rhs->event_cnt; - for (i=0; i<rhs->event_cnt; ++i) { - pj_strdup(pool, &hdr->events[i], &rhs->events[i]); - } - return hdr; -} - -static pjsip_allow_events_hdr* -pjsip_allow_events_hdr_shallow_clone(pj_pool_t *pool, - const pjsip_allow_events_hdr *rhs) -{ - pjsip_allow_events_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr)); - pj_memcpy(hdr, rhs, sizeof(*hdr)); - return hdr; -} - - -static int pjsip_sub_state_hdr_print(pjsip_sub_state_hdr *hdr, - char *buf, pj_size_t size); -static pjsip_sub_state_hdr* -pjsip_sub_state_hdr_clone(pj_pool_t *pool, - const pjsip_sub_state_hdr *hdr); -static pjsip_sub_state_hdr* -pjsip_sub_state_hdr_shallow_clone(pj_pool_t *pool, - const pjsip_sub_state_hdr*); - -static pjsip_hdr_vptr sub_state_hdr_vptr = -{ - (pjsip_hdr_clone_fptr) &pjsip_sub_state_hdr_clone, - (pjsip_hdr_clone_fptr) &pjsip_sub_state_hdr_shallow_clone, - (pjsip_hdr_print_fptr) &pjsip_sub_state_hdr_print, -}; - - -PJ_DEF(pjsip_sub_state_hdr*) pjsip_sub_state_hdr_create(pj_pool_t *pool) -{ - pj_str_t sub_state = { "Subscription-State", 18 }; - pjsip_sub_state_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr)); - hdr->type = PJSIP_H_OTHER; - hdr->name = hdr->sname = sub_state; - hdr->vptr = &sub_state_hdr_vptr; - hdr->expires_param = -1; - hdr->retry_after = -1; - pj_list_init(hdr); - return hdr; -} - -static int pjsip_sub_state_hdr_print(pjsip_sub_state_hdr *hdr, - char *buf, pj_size_t size) -{ - char *p = buf; - char *endbuf = buf+size; - int printed; - - copy_advance(p, hdr->name); - *p++ = ':'; - *p++ = ' '; - - copy_advance(p, hdr->sub_state); - copy_advance_pair(p, ";reason=", 8, hdr->reason_param); - if (hdr->expires_param >= 0) { - pj_memcpy(p, ";expires=", 9); - p += 9; - printed = pj_utoa(hdr->expires_param, p); - p += printed; - } - if (hdr->retry_after >= 0) { - pj_memcpy(p, ";retry-after=", 13); - p += 9; - printed = pj_utoa(hdr->retry_after, p); - p += printed; - } - if (hdr->other_param.slen) - copy_advance(p, hdr->other_param); - - return p - buf; -} - -static pjsip_sub_state_hdr* -pjsip_sub_state_hdr_clone(pj_pool_t *pool, - const pjsip_sub_state_hdr *rhs) -{ - pjsip_sub_state_hdr *hdr = pjsip_sub_state_hdr_create(pool); - pj_strdup(pool, &hdr->sub_state, &rhs->sub_state); - pj_strdup(pool, &hdr->reason_param, &rhs->reason_param); - hdr->retry_after = rhs->retry_after; - hdr->expires_param = rhs->expires_param; - pj_strdup(pool, &hdr->other_param, &rhs->other_param); - return hdr; -} - -static pjsip_sub_state_hdr* -pjsip_sub_state_hdr_shallow_clone(pj_pool_t *pool, - const pjsip_sub_state_hdr *rhs) -{ - pjsip_sub_state_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr)); - pj_memcpy(hdr, rhs, sizeof(*hdr)); - return hdr; -} - -static pjsip_event_hdr *parse_hdr_event(pj_scanner *scanner, - pj_pool_t *pool) -{ - pjsip_event_hdr *hdr = pjsip_event_hdr_create(pool); - const pj_str_t id_param = { "id", 2 }; - - pj_scan_get(scanner, pjsip_TOKEN_SPEC, &hdr->event_type); - - while (*scanner->current == ';') { - pj_str_t pname, pvalue; - pj_scan_get_char(scanner); - pjsip_parse_param_imp(scanner, &pname, &pvalue, 0); - if (pj_stricmp(&pname, &id_param)==0) { - hdr->id_param = pvalue; - } else { - pjsip_concat_param_imp(&hdr->other_param, pool, &pname, &pvalue, ';'); - } - } - pjsip_parse_end_hdr_imp( scanner ); - return hdr; -} - -static pjsip_allow_events_hdr *parse_hdr_allow_events(pj_scanner *scanner, - pj_pool_t *pool) -{ - pjsip_allow_events_hdr *hdr = pjsip_allow_events_hdr_create(pool); - - pj_scan_get(scanner, pjsip_TOKEN_SPEC, &hdr->events[0]); - hdr->event_cnt = 1; - - while (*scanner->current == ',') { - pj_scan_get_char(scanner); - pj_scan_get(scanner, pjsip_TOKEN_SPEC, &hdr->events[hdr->event_cnt++]); - if (hdr->event_cnt == PJSIP_MAX_ALLOW_EVENTS) { - PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); - } - } - - pjsip_parse_end_hdr_imp( scanner ); - return hdr; -} - -static pjsip_sub_state_hdr *parse_hdr_sub_state(pj_scanner *scanner, - pj_pool_t *pool) -{ - pjsip_sub_state_hdr *hdr = pjsip_sub_state_hdr_create(pool); - const pj_str_t reason = { "reason", 6 }, - expires = { "expires", 7 }, - retry_after = { "retry-after", 11 }; - pj_scan_get(scanner, pjsip_TOKEN_SPEC, &hdr->sub_state); - - while (*scanner->current == ';') { - pj_str_t pname, pvalue; - - pj_scan_get_char(scanner); - pjsip_parse_param_imp(scanner, &pname, &pvalue, 0); - if (pj_stricmp(&pname, &reason) == 0) { - hdr->reason_param = pvalue; - } else if (pj_stricmp(&pname, &expires) == 0) { - hdr->expires_param = pj_strtoul(&pvalue); - } else if (pj_stricmp(&pname, &retry_after) == 0) { - hdr->retry_after = pj_strtoul(&pvalue); - } else { - pjsip_concat_param_imp(&hdr->other_param, pool, &pname, &pvalue, ';'); - } - } - - pjsip_parse_end_hdr_imp( scanner ); - return hdr; -} - -PJ_DEF(void) pjsip_event_notify_init_parser(void) -{ - pjsip_register_hdr_parser( "Event", NULL, (pjsip_parse_hdr_func*) &parse_hdr_event); - pjsip_register_hdr_parser( "Allow-Events", NULL, (pjsip_parse_hdr_func*) &parse_hdr_allow_events); - pjsip_register_hdr_parser( "Subscription-State", NULL, (pjsip_parse_hdr_func*) &parse_hdr_sub_state); -} diff --git a/pjsip/src/pjsip_simple/messaging.c b/pjsip/src/pjsip_simple/messaging.c deleted file mode 100644 index c3992b4c..00000000 --- a/pjsip/src/pjsip_simple/messaging.c +++ /dev/null @@ -1,337 +0,0 @@ -/* $Id$ - * - */ -#include <pjsip_simple/messaging.h> -#include <pjsip/sip_endpoint.h> -#include <pjsip/sip_parser.h> -#include <pjsip/sip_transaction.h> -#include <pjsip/sip_event.h> -#include <pjsip/sip_module.h> -#include <pjsip/sip_misc.h> -#include <pj/string.h> -#include <pj/pool.h> -#include <pj/guid.h> -#include <pj/string.h> -#include <pj/log.h> -#include <stdio.h> -#include <stdlib.h> - -#define THIS_FILE "messaging" - -struct messaging_data -{ - void *token; - pjsip_messaging_cb cb; -}; - -struct pjsip_messaging_session -{ - pj_pool_t *pool; - pjsip_endpoint *endpt; - pjsip_from_hdr *from; - pjsip_to_hdr *to; - pjsip_cid_hdr *call_id; - pjsip_cseq_hdr *cseq; -}; - -static int module_id; -static pjsip_on_new_msg_cb incoming_cb; -static pjsip_method message_method; - - -/* - * Set global callback to receive incoming message. - */ -PJ_DEF(pjsip_on_new_msg_cb) -pjsip_messaging_set_incoming_callback(pjsip_on_new_msg_cb cb) -{ - pjsip_on_new_msg_cb prev_cb = incoming_cb; - incoming_cb = cb; - return prev_cb; -} - - -/* - * Create an independent message (ie. not associated with a session). - */ -PJ_DEF(pjsip_tx_data*) -pjsip_messaging_create_msg_from_hdr(pjsip_endpoint *endpt, - const pjsip_uri *target, - const pjsip_from_hdr *param_from, - const pjsip_to_hdr *param_to, - const pjsip_cid_hdr *param_call_id, - int param_cseq, - const pj_str_t *param_text) -{ - return pjsip_endpt_create_request_from_hdr( endpt, &message_method, - target, - param_from, param_to, - NULL, param_call_id, - param_cseq, param_text ); -} - -/* - * Create independent message from string (instead of from header). - */ -PJ_DEF(pjsip_tx_data*) -pjsip_messaging_create_msg( pjsip_endpoint *endpt, - const pj_str_t *target, - const pj_str_t *param_from, - const pj_str_t *param_to, - const pj_str_t *param_call_id, - int param_cseq, - const pj_str_t *param_text) -{ - return pjsip_endpt_create_request( endpt, &message_method, target, - param_from, param_to, NULL, param_call_id, - param_cseq, param_text); -} - -/* - * Initiate transaction to send outgoing message. - */ -PJ_DEF(pj_status_t) -pjsip_messaging_send_msg( pjsip_endpoint *endpt, pjsip_tx_data *tdata, - void *token, pjsip_messaging_cb cb ) -{ - pjsip_transaction *tsx; - struct messaging_data *msg_data; - - /* Create transaction. */ - tsx = pjsip_endpt_create_tsx(endpt); - if (!tsx) { - pjsip_tx_data_dec_ref(tdata); - return -1; - } - - /* Save parameters to messaging data and attach to tsx. */ - msg_data = pj_pool_calloc(tsx->pool, 1, sizeof(struct messaging_data)); - msg_data->cb = cb; - msg_data->token = token; - - /* Init transaction. */ - tsx->module_data[module_id] = msg_data; - if (pjsip_tsx_init_uac(tsx, tdata) != 0) { - pjsip_tx_data_dec_ref(tdata); - pjsip_endpt_destroy_tsx(endpt, tsx); - return -1; - } - - pjsip_endpt_register_tsx(endpt, tsx); - - /* - * Instruct transaction to send message. - * Further events will be received via transaction's event. - */ - pjsip_tsx_on_tx_msg(tsx, tdata); - - /* Decrement reference counter. */ - pjsip_tx_data_dec_ref(tdata); - return 0; -} - - -/* - * Create 'IM session'. - */ -PJ_DEF(pjsip_messaging_session*) -pjsip_messaging_create_session( pjsip_endpoint *endpt, const pj_str_t *param_from, - const pj_str_t *param_to ) -{ - pj_pool_t *pool; - pjsip_messaging_session *ses; - pj_str_t tmp, to; - - pool = pjsip_endpt_create_pool(endpt, "imsess", 1024, 1024); - if (!pool) - return NULL; - - ses = pj_pool_calloc(pool, 1, sizeof(pjsip_messaging_session)); - ses->pool = pool; - ses->endpt = endpt; - - ses->call_id = pjsip_cid_hdr_create(pool); - pj_create_unique_string(pool, &ses->call_id->id); - - ses->cseq = pjsip_cseq_hdr_create(pool); - ses->cseq->cseq = pj_rand(); - ses->cseq->method = message_method; - - ses->from = pjsip_from_hdr_create(pool); - pj_strdup_with_null(pool, &tmp, param_from); - ses->from->uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR); - if (ses->from->uri == NULL) { - pjsip_endpt_destroy_pool(endpt, pool); - return NULL; - } - pj_create_unique_string(pool, &ses->from->tag); - - ses->to = pjsip_to_hdr_create(pool); - pj_strdup_with_null(pool, &to, param_from); - ses->to->uri = pjsip_parse_uri(pool, to.ptr, to.slen, PJSIP_PARSE_URI_AS_NAMEADDR); - if (ses->to->uri == NULL) { - pjsip_endpt_destroy_pool(endpt, pool); - return NULL; - } - - PJ_LOG(4,(THIS_FILE, "IM session created: recipient=%s", to.ptr)); - return ses; -} - - -/* - * Send IM message using identification from 'IM session'. - */ -PJ_DEF(pjsip_tx_data*) -pjsip_messaging_session_create_msg( pjsip_messaging_session *ses, const pj_str_t *text ) -{ - return pjsip_endpt_create_request_from_hdr( ses->endpt, - &message_method, - ses->to->uri, - ses->from, - ses->to, - NULL, - ses->call_id, - ses->cseq->cseq++, - text); -} - - -/* - * Destroy 'IM session'. - */ -PJ_DEF(pj_status_t) -pjsip_messaging_destroy_session( pjsip_messaging_session *ses ) -{ - /* - * NOTE ABOUT POSSIBLE BUG HERE... - * - * We don't check number of pending transaction before destroying IM - * session. As the result, the headers in the txdata of pending transaction - * wil be INVALID once the IM session is deleted (because we only - * shallo_clone()-ed them). - * - * This normally should be okay, because once the message is - * submitted to transaction, the transaction (or rather the transport) - * will 'print' the message to a buffer, and once it is printed, it - * won't try to access the original message again. So even when the - * original message has a dangling pointer, we should be safe. - * - * However, it will cause a problem if: - * - resolving completes asynchronously and with a substantial delay, - * and before the resolver/transport finished its job the user - * destroy the IM session. - * - if the transmit data is invalidated after the IM session is - * destroyed. - */ - - pjsip_endpt_destroy_pool(ses->endpt, ses->pool); - return 0; -} - - -static pj_status_t messaging_init( pjsip_endpoint *endpt, - struct pjsip_module *mod, pj_uint32_t id ) -{ - PJ_UNUSED_ARG(endpt) - PJ_UNUSED_ARG(mod) - - module_id = id; - return 0; -} - -static pj_status_t messaging_start( struct pjsip_module *mod ) -{ - PJ_UNUSED_ARG(mod) - return 0; -} - -static pj_status_t messaging_deinit( struct pjsip_module *mod ) -{ - PJ_UNUSED_ARG(mod) - return 0; -} - -static void messaging_tsx_handler( struct pjsip_module *mod, pjsip_event *event ) -{ - pjsip_transaction *tsx = event->obj.tsx; - struct messaging_data *mod_data; - - PJ_UNUSED_ARG(mod) - - /* Ignore non transaction event */ - if (event->type != PJSIP_EVENT_TSX_STATE_CHANGED || tsx == NULL) - return; - - /* If this is an incoming message, inform application. */ - if (tsx->role == PJSIP_ROLE_UAS) { - int status = 100; - pjsip_tx_data *tdata; - - /* Check if we already answered this request. */ - if (tsx->status_code >= 200) - return; - - /* Only handle MESSAGE requests!. */ - if (pjsip_method_cmp(&tsx->method, &message_method) != 0) - return; - - /* Call application callback. */ - if (incoming_cb) - status = (*incoming_cb)(event->src.rdata); - - if (status < 200 || status >= 700) - status = PJSIP_SC_INTERNAL_SERVER_ERROR; - - /* Respond request. */ - tdata = pjsip_endpt_create_response(tsx->endpt, event->src.rdata, status ); - if (tdata) - pjsip_tsx_on_tx_msg(tsx, tdata); - - return; - } - - /* Ignore if it's not something that came from messaging module. */ - mod_data = tsx->module_data[ module_id ]; - if (mod_data == NULL) - return; - - /* Ignore non final response. */ - if (tsx->status_code < 200) - return; - - /* Don't want to call the callback more than once. */ - tsx->module_data[ module_id ] = NULL; - - /* Now call the callback. */ - if (mod_data->cb) { - (*mod_data->cb)(mod_data->token, tsx->status_code); - } -} - -static pjsip_module messaging_module = -{ - { "Messaging", 9}, /* Name. */ - 0, /* Flag */ - 128, /* Priority */ - NULL, /* User agent instance, initialized by APP. */ - 0, /* Number of methods supported (will be initialized later). */ - { 0 }, /* Array of methods (will be initialized later) */ - &messaging_init, /* init_module() */ - &messaging_start, /* start_module() */ - &messaging_deinit, /* deinit_module() */ - &messaging_tsx_handler, /* tsx_handler() */ -}; - -PJ_DEF(pjsip_module*) pjsip_messaging_get_module() -{ - static pj_str_t method_str = { "MESSAGE", 7 }; - - pjsip_method_init_np( &message_method, &method_str); - - messaging_module.method_cnt = 1; - messaging_module.methods[0] = &message_method; - - return &messaging_module; -} - diff --git a/pjsip/src/pjsip_simple/pidf.c b/pjsip/src/pjsip_simple/pidf.c deleted file mode 100644 index f1de9c9d..00000000 --- a/pjsip/src/pjsip_simple/pidf.c +++ /dev/null @@ -1,335 +0,0 @@ -/* $Id$ - * - */ -#include <pjsip_simple/pidf.h> -#include <pj/string.h> -#include <pj/pool.h> - -struct pjpidf_op_desc pjpidf_op = -{ - { - &pjpidf_pres_construct, - &pjpidf_pres_add_tuple, - &pjpidf_pres_get_first_tuple, - &pjpidf_pres_get_next_tuple, - &pjpidf_pres_find_tuple, - &pjpidf_pres_remove_tuple, - &pjpidf_pres_add_note, - &pjpidf_pres_get_first_note, - &pjpidf_pres_get_next_note - }, - { - &pjpidf_tuple_construct, - &pjpidf_tuple_get_id, - &pjpidf_tuple_set_id, - &pjpidf_tuple_get_status, - &pjpidf_tuple_get_contact, - &pjpidf_tuple_set_contact, - &pjpidf_tuple_set_contact_prio, - &pjpidf_tuple_get_contact_prio, - &pjpidf_tuple_add_note, - &pjpidf_tuple_get_first_note, - &pjpidf_tuple_get_next_note, - &pjpidf_tuple_get_timestamp, - &pjpidf_tuple_set_timestamp, - &pjpidf_tuple_set_timestamp_np - }, - { - &pjpidf_status_construct, - &pjpidf_status_is_basic_open, - &pjpidf_status_set_basic_open - } -}; - -static pj_str_t PRESENCE = { "presence", 8 }; -static pj_str_t ENTITY = { "entity", 6}; -static pj_str_t TUPLE = { "tuple", 5 }; -static pj_str_t ID = { "id", 2 }; -static pj_str_t NOTE = { "note", 4 }; -static pj_str_t STATUS = { "status", 6 }; -static pj_str_t CONTACT = { "contact", 7 }; -static pj_str_t PRIORITY = { "priority", 8 }; -static pj_str_t TIMESTAMP = { "timestamp", 9 }; -static pj_str_t BASIC = { "basic", 5 }; -static pj_str_t OPEN = { "open", 4 }; -static pj_str_t CLOSED = { "closed", 6 }; -static pj_str_t EMPTY_STRING = { NULL, 0 }; - -static void xml_init_node(pj_pool_t *pool, pj_xml_node *node, - pj_str_t *name, const pj_str_t *value) -{ - pj_list_init(&node->attr_head); - pj_list_init(&node->node_head); - node->name = *name; - if (value) pj_strdup(pool, &node->content, value); - else node->content.ptr=NULL, node->content.slen=0; -} - -static pj_xml_attr* xml_create_attr(pj_pool_t *pool, pj_str_t *name, - const pj_str_t *value) -{ - pj_xml_attr *attr = pj_pool_alloc(pool, sizeof(*attr)); - attr->name = *name; - pj_strdup(pool, &attr->value, value); - return attr; -} - -/* Presence */ -PJ_DEF(void) pjpidf_pres_construct(pj_pool_t *pool, pjpidf_pres *pres, - const pj_str_t *entity) -{ - pj_xml_attr *attr; - - xml_init_node(pool, pres, &PRESENCE, NULL); - attr = xml_create_attr(pool, &ENTITY, entity); - pj_xml_add_attr(pres, attr); -} - -PJ_DEF(pjpidf_tuple*) pjpidf_pres_add_tuple(pj_pool_t *pool, pjpidf_pres *pres, - const pj_str_t *id) -{ - pjpidf_tuple *t = pj_pool_alloc(pool, sizeof(*t)); - pjpidf_tuple_construct(pool, t, id); - pj_xml_add_node(pres, t); - return t; -} - -PJ_DEF(pjpidf_tuple*) pjpidf_pres_get_first_tuple(pjpidf_pres *pres) -{ - return pj_xml_find_node(pres, &TUPLE); -} - -PJ_DEF(pjpidf_tuple*) pjpidf_pres_get_next_tuple(pjpidf_pres *pres, - pjpidf_tuple *tuple) -{ - return pj_xml_find_next_node(pres, tuple, &TUPLE); -} - -static pj_bool_t find_tuple_by_id(pj_xml_node *node, const void *id) -{ - return pj_xml_find_attr(node, &ID, id) != NULL; -} - -PJ_DEF(pjpidf_tuple*) pjpidf_pres_find_tuple(pjpidf_pres *pres, const pj_str_t *id) -{ - return pj_xml_find(pres, &TUPLE, id, &find_tuple_by_id); -} - -PJ_DEF(void) pjpidf_pres_remove_tuple(pjpidf_pres *pres, pjpidf_tuple *t) -{ - PJ_UNUSED_ARG(pres) - pj_list_erase(t); -} - -PJ_DEF(pjpidf_note*) pjpidf_pres_add_note(pj_pool_t *pool, pjpidf_pres *pres, - const pj_str_t *text) -{ - pjpidf_note *note = pj_pool_alloc(pool, sizeof(*note)); - xml_init_node(pool, note, &NOTE, text); - pj_xml_add_node(pres, note); - return note; -} - -PJ_DEF(pjpidf_note*) pjpidf_pres_get_first_note(pjpidf_pres *pres) -{ - return pj_xml_find_node( pres, &NOTE); -} - -PJ_DEF(pjpidf_note*) pjpidf_pres_get_next_note(pjpidf_pres *t, pjpidf_note *note) -{ - return pj_xml_find_next_node(t, note, &NOTE); -} - - -/* Tuple */ -PJ_DEF(void) pjpidf_tuple_construct(pj_pool_t *pool, pjpidf_tuple *t, - const pj_str_t *id) -{ - pj_xml_attr *attr; - pjpidf_status *st; - - xml_init_node(pool, t, &TUPLE, NULL); - attr = xml_create_attr(pool, &ID, id); - pj_xml_add_attr(t, attr); - st = pj_pool_alloc(pool, sizeof(*st)); - pjpidf_status_construct(pool, st); - pj_xml_add_node(t, st); -} - -PJ_DEF(const pj_str_t*) pjpidf_tuple_get_id(const pjpidf_tuple *t) -{ - const pj_xml_attr *attr = pj_xml_find_attr((pj_xml_node*)t, &ID, NULL); - pj_assert(attr); - return &attr->value; -} - -PJ_DEF(void) pjpidf_tuple_set_id(pj_pool_t *pool, pjpidf_tuple *t, const pj_str_t *id) -{ - pj_xml_attr *attr = pj_xml_find_attr(t, &ID, NULL); - pj_assert(attr); - pj_strdup(pool, &attr->value, id); -} - - -PJ_DEF(pjpidf_status*) pjpidf_tuple_get_status(pjpidf_tuple *t) -{ - pjpidf_status *st = (pjpidf_status*)pj_xml_find_node(t, &STATUS); - pj_assert(st); - return st; -} - - -PJ_DEF(const pj_str_t*) pjpidf_tuple_get_contact(const pjpidf_tuple *t) -{ - pj_xml_node *node = pj_xml_find_node((pj_xml_node*)t, &CONTACT); - if (!node) - return &EMPTY_STRING; - return &node->content; -} - -PJ_DEF(void) pjpidf_tuple_set_contact(pj_pool_t *pool, pjpidf_tuple *t, - const pj_str_t *contact) -{ - pj_xml_node *node = pj_xml_find_node(t, &CONTACT); - if (!node) { - node = pj_pool_alloc(pool, sizeof(*node)); - xml_init_node(pool, node, &CONTACT, contact); - pj_xml_add_node(t, node); - } else { - pj_strdup(pool, &node->content, contact); - } -} - -PJ_DEF(void) pjpidf_tuple_set_contact_prio(pj_pool_t *pool, pjpidf_tuple *t, - const pj_str_t *prio) -{ - pj_xml_node *node = pj_xml_find_node(t, &CONTACT); - pj_xml_attr *attr; - - if (!node) { - node = pj_pool_alloc(pool, sizeof(*node)); - xml_init_node(pool, node, &CONTACT, NULL); - pj_xml_add_node(t, node); - } - attr = pj_xml_find_attr(node, &PRIORITY, NULL); - if (!attr) { - attr = xml_create_attr(pool, &PRIORITY, prio); - pj_xml_add_attr(node, attr); - } else { - pj_strdup(pool, &attr->value, prio); - } -} - -PJ_DEF(const pj_str_t*) pjpidf_tuple_get_contact_prio(const pjpidf_tuple *t) -{ - pj_xml_node *node = pj_xml_find_node((pj_xml_node*)t, &CONTACT); - pj_xml_attr *attr; - - if (!node) - return &EMPTY_STRING; - attr = pj_xml_find_attr(node, &PRIORITY, NULL); - if (!attr) - return &EMPTY_STRING; - return &attr->value; -} - - -PJ_DEF(pjpidf_note*) pjpidf_tuple_add_note(pj_pool_t *pool, pjpidf_tuple *t, - const pj_str_t *text) -{ - pjpidf_note *note = pj_pool_alloc(pool, sizeof(*note)); - xml_init_node(pool, note, &NOTE, text); - pj_xml_add_node(t, note); - return note; -} - -PJ_DEF(pjpidf_note*) pjpidf_tuple_get_first_note(pjpidf_tuple *t) -{ - return pj_xml_find_node(t, &NOTE); -} - -PJ_DEF(pjpidf_note*) pjpidf_tuple_get_next_note(pjpidf_tuple *t, pjpidf_note *n) -{ - return pj_xml_find_next_node(t, n, &NOTE); -} - - -PJ_DEF(const pj_str_t*) pjpidf_tuple_get_timestamp(const pjpidf_tuple *t) -{ - pj_xml_node *node = pj_xml_find_node((pj_xml_node*)t, &TIMESTAMP); - return node ? &node->content : &EMPTY_STRING; -} - -PJ_DEF(void) pjpidf_tuple_set_timestamp(pj_pool_t *pool, pjpidf_tuple *t, - const pj_str_t *ts) -{ - pj_xml_node *node = pj_xml_find_node(t, &TIMESTAMP); - if (!node) { - node = pj_pool_alloc(pool, sizeof(*node)); - xml_init_node(pool, node, &TIMESTAMP, ts); - } else { - pj_strdup(pool, &node->content, ts); - } -} - - -PJ_DEF(void) pjpidf_tuple_set_timestamp_np(pj_pool_t *pool, pjpidf_tuple *t, - pj_str_t *ts) -{ - pj_xml_node *node = pj_xml_find_node(t, &TIMESTAMP); - if (!node) { - node = pj_pool_alloc(pool, sizeof(*node)); - xml_init_node(pool, node, &TIMESTAMP, ts); - } else { - node->content = *ts; - } -} - - -/* Status */ -PJ_DEF(void) pjpidf_status_construct(pj_pool_t *pool, pjpidf_status *st) -{ - pj_xml_node *node; - - xml_init_node(pool, st, &STATUS, NULL); - node = pj_pool_alloc(pool, sizeof(*node)); - xml_init_node(pool, node, &BASIC, &CLOSED); - pj_xml_add_node(st, node); -} - -PJ_DEF(pj_bool_t) pjpidf_status_is_basic_open(const pjpidf_status *st) -{ - pj_xml_node *node = pj_xml_find_node((pj_xml_node*)st, &BASIC); - pj_assert(node != NULL); - return pj_stricmp(&node->content, &OPEN)==0; -} - -PJ_DEF(void) pjpidf_status_set_basic_open(pjpidf_status *st, pj_bool_t open) -{ - pj_xml_node *node = pj_xml_find_node(st, &BASIC); - pj_assert(node != NULL); - node->content = open ? OPEN : CLOSED; -} - -PJ_DEF(pjpidf_pres*) pjpidf_create(pj_pool_t *pool, const pj_str_t *entity) -{ - pjpidf_pres *pres = pj_pool_alloc(pool, sizeof(*pres)); - pjpidf_pres_construct(pool, pres, entity); - return pres; -} - -PJ_DEF(pjpidf_pres*) pjpidf_parse(pj_pool_t *pool, char *text, int len) -{ - pjpidf_pres *pres = pj_xml_parse(pool, text, len); - if (pres) { - if (pj_stricmp(&pres->name, &PRESENCE) != 0) - return NULL; - } - return pres; -} - -PJ_DEF(int) pjpidf_print(const pjpidf_pres* pres, char *buf, int len) -{ - return pj_xml_print(pres, buf, len, PJ_TRUE); -} - diff --git a/pjsip/src/pjsip_simple/presence.c b/pjsip/src/pjsip_simple/presence.c deleted file mode 100644 index 32ed8e3c..00000000 --- a/pjsip/src/pjsip_simple/presence.c +++ /dev/null @@ -1,384 +0,0 @@ -/* $Id$ - * - */ -#include <pjsip_simple/presence.h> -#include <pjsip/sip_transport.h> -#include <pj/pool.h> -#include <pj/string.h> -#include <pj/guid.h> -#include <pj/os.h> -#include <stdio.h> - -/* Forward declarations. */ -static void on_query_subscribe(pjsip_rx_data *rdata, int *status); -static void on_subscribe(pjsip_event_sub *sub, pjsip_rx_data *rdata, - pjsip_event_sub_cb **cb, int *expires); -static void on_sub_terminated(pjsip_event_sub *sub, const pj_str_t *reason); -static void on_sub_received_refresh(pjsip_event_sub *sub, pjsip_rx_data *rdata); -static void on_received_notify(pjsip_event_sub *sub, pjsip_rx_data *rdata); - -/* Some string constants. */ -static pj_str_t PRESENCE_EVENT = { "presence", 8 }; - -/* Accept types. */ -static pj_str_t accept_names[] = { - { "application/pidf+xml", 20 }, - { "application/xpidf+xml", 21 } -}; -static pjsip_media_type accept_types[] = { - { - { "application", 11 }, - { "pidf+xml", 8 } - }, - { - { "application", 11 }, - { "xpidf+xml", 9 } - } -}; - -/* Callback that is registered by application. */ -static pjsip_presence_cb cb; - -/* Package callback to be register to event_notify */ -static pjsip_event_sub_pkg_cb pkg_cb = { &on_query_subscribe, - &on_subscribe }; - -/* Global/static callback to be registered to event_notify */ -static pjsip_event_sub_cb sub_cb = { &on_sub_terminated, - &on_sub_received_refresh, - NULL, - &on_received_notify, - NULL }; - -/* - * Initialize presence module. - * This will register event package "presence" to event framework. - */ -PJ_DEF(void) pjsip_presence_init(const pjsip_presence_cb *pcb) -{ - pj_memcpy(&cb, pcb, sizeof(*pcb)); - pjsip_event_sub_register_pkg( &PRESENCE_EVENT, - sizeof(accept_names)/sizeof(accept_names[0]), - accept_names, - &pkg_cb); -} - -/* - * Create presence subscription. - */ -PJ_DEF(pjsip_presentity*) pjsip_presence_create( pjsip_endpoint *endpt, - const pj_str_t *local_url, - const pj_str_t *remote_url, - int expires, - void *user_data ) -{ - pjsip_event_sub *sub; - pjsip_presentity *pres; - - if (expires < 0) - expires = 300; - - /* Create event subscription */ - sub = pjsip_event_sub_create(endpt, local_url, remote_url, &PRESENCE_EVENT, - expires, - sizeof(accept_names)/sizeof(accept_names[0]), - accept_names, - NULL, &sub_cb); - if (!sub) - return NULL; - - /* Allocate presence descriptor. */ - pres = pj_pool_calloc(sub->pool, 1, sizeof(*pres)); - pres->sub = sub; - pres->user_data = user_data; - sub->user_data = pres; - - return pres; -} - -/* - * Send SUBSCRIBE. - */ -PJ_DEF(pj_status_t) pjsip_presence_subscribe( pjsip_presentity *pres ) -{ - return pjsip_event_sub_subscribe( pres->sub ); -} - -/* - * Set credentials to be used for outgoing requests. - */ -PJ_DEF(pj_status_t) pjsip_presence_set_credentials( pjsip_presentity *pres, - int count, - const pjsip_cred_info cred[]) -{ - return pjsip_event_sub_set_credentials(pres->sub, count, cred); -} - -/* - * Set route-set. - */ -PJ_DEF(pj_status_t) pjsip_presence_set_route_set( pjsip_presentity *pres, - const pjsip_route_hdr *hdr ) -{ - return pjsip_event_sub_set_route_set( pres->sub, hdr ); -} - -/* - * Unsubscribe. - */ -PJ_DEF(pj_status_t) pjsip_presence_unsubscribe( pjsip_presentity *pres ) -{ - return pjsip_event_sub_unsubscribe(pres->sub); -} - -/* - * This is the pjsip_msg_body callback to print XML body. - */ -static int print_xml(pjsip_msg_body *body, char *buf, pj_size_t size) -{ - return pj_xml_print( body->data, buf, size, PJ_TRUE ); -} - -/* - * Create and initialize PIDF document and msg body (notifier only). - */ -static pj_status_t init_presence_info( pjsip_presentity *pres ) -{ - pj_str_t uri; - pj_pool_t *pool = pres->sub->pool; - char tmp[PJSIP_MAX_URL_SIZE]; - pjpidf_tuple *tuple; - const pjsip_media_type *content_type = NULL; - - pj_assert(pres->uas_body == NULL); - - /* Make entity_id */ - uri.ptr = tmp; - uri.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, pres->sub->from->uri, - tmp, sizeof(tmp)); - if (uri.slen < 0) - return -1; - - if (pres->pres_type == PJSIP_PRES_TYPE_PIDF) { - pj_str_t s; - - /* Create <presence>. */ - pres->uas_data.pidf = pjpidf_create(pool, &s); - - /* Create <tuple> */ - pj_create_unique_string(pool, &s); - tuple = pjpidf_pres_add_tuple(pool, pres->uas_data.pidf, &s); - - /* Set <contact> */ - s.ptr = tmp; - s.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, pres->sub->contact->uri, tmp, sizeof(tmp)); - if (s.slen < 0) - return -1; - pjpidf_tuple_set_contact(pool, tuple, &s); - - /* Content-Type */ - content_type = &accept_types[PJSIP_PRES_TYPE_PIDF]; - - } else if (pres->pres_type == PJSIP_PRES_TYPE_XPIDF) { - - /* Create XPIDF */ - pres->uas_data.xpidf = pjxpidf_create(pool, &uri); - - /* Content-Type. */ - content_type = &accept_types[PJSIP_PRES_TYPE_XPIDF]; - } - - /* Create message body */ - pres->uas_body = pj_pool_alloc(pool, sizeof(pjsip_msg_body)); - pres->uas_body->content_type = *content_type; - pres->uas_body->data = pres->uas_data.pidf; - pres->uas_body->len = 0; - pres->uas_body->print_body = &print_xml; - - return 0; -} - -/* - * Send NOTIFY and set subscription state. - */ -PJ_DEF(pj_status_t) pjsip_presence_notify( pjsip_presentity *pres, - pjsip_event_sub_state state, - pj_bool_t is_online ) -{ - pj_str_t reason = { "", 0 }; - - if (pres->uas_data.pidf == NULL) { - if (init_presence_info(pres) != 0) - return -1; - } - - /* Update basic status in PIDF/XPIDF document. */ - if (pres->pres_type == PJSIP_PRES_TYPE_PIDF) { - pjpidf_tuple *first; - pjpidf_status *status; - pj_time_val now; - pj_parsed_time pnow; - - first = pjpidf_op.pres.get_first_tuple(pres->uas_data.pidf); - pj_assert(first); - status = pjpidf_op.tuple.get_status(first); - pj_assert(status); - pjpidf_op.status.set_basic_open(status, is_online); - - /* Update timestamp. */ - if (pres->timestamp.ptr == 0) { - pres->timestamp.ptr = pj_pool_alloc(pres->sub->pool, 24); - } - pj_gettimeofday(&now); - pj_time_decode(&now, &pnow); - pres->timestamp.slen = sprintf(pres->timestamp.ptr, - "%04d-%02d-%02dT%02d:%02d:%02dZ", - pnow.year, pnow.mon, pnow.day, - pnow.hour, pnow.min, pnow.sec); - pjpidf_op.tuple.set_timestamp_np(pres->sub->pool, first, &pres->timestamp); - - } else if (pres->pres_type == PJSIP_PRES_TYPE_XPIDF) { - pjxpidf_set_status( pres->uas_data.xpidf, is_online ); - - } else { - pj_assert(0); - } - - /* Send notify. */ - return pjsip_event_sub_notify( pres->sub, state, &reason, pres->uas_body); -} - -/* - * Destroy subscription (can be called for both subscriber and notifier). - */ -PJ_DEF(pj_status_t) pjsip_presence_destroy( pjsip_presentity *pres ) -{ - return pjsip_event_sub_destroy(pres->sub); -} - -/* - * This callback is called by event framework to query whether we want to - * accept an incoming subscription. - */ -static void on_query_subscribe(pjsip_rx_data *rdata, int *status) -{ - if (cb.accept_presence) { - (*cb.accept_presence)(rdata, status); - } -} - -/* - * This callback is called by event framework after we accept the incoming - * subscription, to notify about the new subscription instance. - */ -static void on_subscribe(pjsip_event_sub *sub, pjsip_rx_data *rdata, - pjsip_event_sub_cb **set_sub_cb, int *expires) -{ - pjsip_presentity *pres; - pjsip_accept_hdr *accept; - - pres = pj_pool_calloc(sub->pool, 1, sizeof(*pres)); - pres->sub = sub; - pres->pres_type = PJSIP_PRES_TYPE_PIDF; - sub->user_data = pres; - *set_sub_cb = &sub_cb; - - accept = pjsip_msg_find_hdr(rdata->msg, PJSIP_H_ACCEPT, NULL); - if (accept) { - unsigned i; - int found = 0; - for (i=0; i<accept->count && !found; ++i) { - int j; - for (j=0; j<sizeof(accept_names)/sizeof(accept_names[0]); ++j) { - if (!pj_stricmp(&accept->values[i], &accept_names[j])) { - pres->pres_type = j; - found = 1; - break; - } - } - } - pj_assert(found ); - } - - (*cb.on_received_request)(pres, rdata, expires); -} - -/* - * This callback is called by event framework when the subscription is - * terminated. - */ -static void on_sub_terminated(pjsip_event_sub *sub, const pj_str_t *reason) -{ - pjsip_presentity *pres = sub->user_data; - if (cb.on_terminated) - (*cb.on_terminated)(pres, reason); -} - -/* - * This callback is called by event framework when it receives incoming - * SUBSCRIBE request to refresh the subscription. - */ -static void on_sub_received_refresh(pjsip_event_sub *sub, pjsip_rx_data *rdata) -{ - pjsip_presentity *pres = sub->user_data; - if (cb.on_received_refresh) - (*cb.on_received_refresh)(pres, rdata); -} - -/* - * This callback is called by event framework when it receives incoming - * NOTIFY request. - */ -static void on_received_notify(pjsip_event_sub *sub, pjsip_rx_data *rdata) -{ - pjsip_presentity *pres = sub->user_data; - - if (cb.on_received_update) { - pj_status_t is_open; - pjsip_msg_body *body; - int i; - - body = rdata->msg->body; - if (!body) - return; - - for (i=0; i<sizeof(accept_types)/sizeof(accept_types[0]); ++i) { - if (!pj_stricmp(&body->content_type.type, &accept_types[i].type) && - !pj_stricmp(&body->content_type.subtype, &accept_types[i].subtype)) - { - break; - } - } - - if (i==PJSIP_PRES_TYPE_PIDF) { - pjpidf_pres *pres; - pjpidf_tuple *tuple; - pjpidf_status *status; - - pres = pjpidf_parse(rdata->pool, body->data, body->len); - if (!pres) - return; - tuple = pjpidf_pres_get_first_tuple(pres); - if (!tuple) - return; - status = pjpidf_tuple_get_status(tuple); - if (!status) - return; - is_open = pjpidf_status_is_basic_open(status); - - } else if (i==PJSIP_PRES_TYPE_XPIDF) { - pjxpidf_pres *pres; - - pres = pjxpidf_parse(rdata->pool, body->data, body->len); - if (!pres) - return; - is_open = pjxpidf_get_status(pres); - - } else { - return; - } - - (*cb.on_received_update)(pres, is_open); - } -} - diff --git a/pjsip/src/pjsip_simple/xpidf.c b/pjsip/src/pjsip_simple/xpidf.c deleted file mode 100644 index 5787f674..00000000 --- a/pjsip/src/pjsip_simple/xpidf.c +++ /dev/null @@ -1,279 +0,0 @@ -/* $Id$ - * - */ -#include <pjsip_simple/xpidf.h> -#include <pj/pool.h> -#include <pj/string.h> -#include <pj/guid.h> - -static pj_str_t PRESENCE = { "presence", 8 }; -static pj_str_t STATUS = { "status", 6 }; -static pj_str_t OPEN = { "open", 4 }; -static pj_str_t CLOSED = { "closed", 6 }; -static pj_str_t URI = { "uri", 3 }; -static pj_str_t ATOM = { "atom", 4 }; -static pj_str_t ATOMID = { "atomid", 6 }; -static pj_str_t ADDRESS = { "address", 7 }; -static pj_str_t SUBSCRIBE_PARAM = { ";method=SUBSCRIBE", 17 }; -static pj_str_t PRESENTITY = { "presentity", 10 }; -static pj_str_t EMPTY_STRING = { NULL, 0 }; - -static pj_xml_node* xml_create_node(pj_pool_t *pool, - pj_str_t *name, const pj_str_t *value) -{ - pj_xml_node *node; - - node = pj_pool_alloc(pool, sizeof(pj_xml_node)); - pj_list_init(&node->attr_head); - pj_list_init(&node->node_head); - node->name = *name; - if (value) pj_strdup(pool, &node->content, value); - else node->content.ptr=NULL, node->content.slen=0; - - return node; -} - -static pj_xml_attr* xml_create_attr(pj_pool_t *pool, pj_str_t *name, - const pj_str_t *value) -{ - pj_xml_attr *attr = pj_pool_alloc(pool, sizeof(*attr)); - attr->name = *name; - pj_strdup(pool, &attr->value, value); - return attr; -} - - -PJ_DEF(pjxpidf_pres*) pjxpidf_create(pj_pool_t *pool, const pj_str_t *uri_cstr) -{ - pjxpidf_pres *pres; - pj_xml_node *presentity; - pj_xml_node *atom; - pj_xml_node *addr; - pj_xml_node *status; - pj_xml_attr *attr; - pj_str_t uri; - pj_str_t tmp; - - /* <presence> */ - pres = xml_create_node(pool, &PRESENCE, NULL); - - /* <presentity> */ - presentity = xml_create_node(pool, &PRESENTITY, NULL); - pj_xml_add_node(pres, presentity); - - /* uri attribute */ - uri.ptr = pj_pool_alloc(pool, uri_cstr->slen + SUBSCRIBE_PARAM.slen); - pj_strcpy( &uri, uri_cstr); - pj_strcat( &uri, &SUBSCRIBE_PARAM); - attr = xml_create_attr(pool, &URI, &uri); - pj_xml_add_attr(presentity, attr); - - /* <atom> */ - atom = xml_create_node(pool, &ATOM, NULL); - pj_xml_add_node(pres, atom); - - /* atom id */ - pj_create_unique_string(pool, &tmp); - attr = xml_create_attr(pool, &ATOMID, &tmp); - pj_xml_add_attr(atom, attr); - - /* address */ - addr = xml_create_node(pool, &ADDRESS, NULL); - pj_xml_add_node(atom, addr); - - /* address'es uri */ - attr = xml_create_attr(pool, &URI, uri_cstr); - pj_xml_add_attr(addr, attr); - - /* status */ - status = xml_create_node(pool, &STATUS, NULL); - pj_xml_add_node(addr, status); - - /* status attr */ - attr = xml_create_attr(pool, &STATUS, &OPEN); - pj_xml_add_attr(status, attr); - - return pres; -} - - - -PJ_DEF(pjxpidf_pres*) pjxpidf_parse(pj_pool_t *pool, char *text, pj_size_t len) -{ - pjxpidf_pres *pres; - pj_xml_node *node; - - pres = pj_xml_parse(pool, text, len); - if (!pres) - return NULL; - - /* Validate <presence> */ - if (pj_stricmp(&pres->name, &PRESENCE) != 0) - return NULL; - if (pj_xml_find_attr(pres, &URI, NULL) == NULL) - return NULL; - - /* Validate <presentity> */ - node = pj_xml_find_node(pres, &PRESENTITY); - if (node == NULL) - return NULL; - - /* Validate <atom> */ - node = pj_xml_find_node(pres, &ATOM); - if (node == NULL) - return NULL; - if (pj_xml_find_attr(node, &ATOMID, NULL) == NULL) - return NULL; - - /* Address */ - node = pj_xml_find_node(node, &ADDRESS); - if (node == NULL) - return NULL; - if (pj_xml_find_attr(node, &URI, NULL) == NULL) - return NULL; - - - /* Status */ - node = pj_xml_find_node(node, &STATUS); - if (node == NULL) - return NULL; - if (pj_xml_find_attr(node, &STATUS, NULL) == NULL) - return NULL; - - return pres; -} - - -PJ_DEF(int) pjxpidf_print( pjxpidf_pres *pres, char *text, pj_size_t len) -{ - return pj_xml_print(pres, text, len, PJ_TRUE); -} - - -PJ_DEF(pj_str_t*) pjxpidf_get_uri(pjxpidf_pres *pres) -{ - pj_xml_node *presentity; - pj_xml_attr *attr; - - presentity = pj_xml_find_node(pres, &PRESENTITY); - if (!presentity) - return &EMPTY_STRING; - - attr = pj_xml_find_attr(presentity, &URI, NULL); - if (!attr) - return &EMPTY_STRING; - - return &attr->value; -} - - -PJ_DEF(pj_status_t) pjxpidf_set_uri(pj_pool_t *pool, pjxpidf_pres *pres, - const pj_str_t *uri) -{ - pj_xml_node *presentity; - pj_xml_node *atom; - pj_xml_node *addr; - pj_xml_attr *attr; - pj_str_t dup_uri; - - presentity = pj_xml_find_node(pres, &PRESENTITY); - if (!presentity) { - pj_assert(0); - return -1; - } - atom = pj_xml_find_node(pres, &ATOM); - if (!atom) { - pj_assert(0); - return -1; - } - addr = pj_xml_find_node(atom, &ADDRESS); - if (!addr) { - pj_assert(0); - return -1; - } - - /* Set uri in presentity */ - attr = pj_xml_find_attr(presentity, &URI, NULL); - if (!attr) { - pj_assert(0); - return -1; - } - pj_strdup(pool, &dup_uri, uri); - attr->value = dup_uri; - - /* Set uri in address. */ - attr = pj_xml_find_attr(addr, &URI, NULL); - if (!attr) { - pj_assert(0); - return -1; - } - attr->value = dup_uri; - - return 0; -} - - -PJ_DEF(pj_bool_t) pjxpidf_get_status(pjxpidf_pres *pres) -{ - pj_xml_node *atom; - pj_xml_node *addr; - pj_xml_node *status; - pj_xml_attr *attr; - - atom = pj_xml_find_node(pres, &ATOM); - if (!atom) { - pj_assert(0); - return PJ_FALSE; - } - addr = pj_xml_find_node(atom, &ADDRESS); - if (!addr) { - pj_assert(0); - return PJ_FALSE; - } - status = pj_xml_find_node(atom, &STATUS); - if (!status) { - pj_assert(0); - return PJ_FALSE; - } - attr = pj_xml_find_attr(status, &STATUS, NULL); - if (!attr) { - pj_assert(0); - return PJ_FALSE; - } - - return pj_stricmp(&attr->value, &OPEN) ? PJ_TRUE : PJ_FALSE; -} - - -PJ_DEF(pj_status_t) pjxpidf_set_status(pjxpidf_pres *pres, pj_bool_t online_status) -{ - pj_xml_node *atom; - pj_xml_node *addr; - pj_xml_node *status; - pj_xml_attr *attr; - - atom = pj_xml_find_node(pres, &ATOM); - if (!atom) { - pj_assert(0); - return -1; - } - addr = pj_xml_find_node(atom, &ADDRESS); - if (!addr) { - pj_assert(0); - return -1; - } - status = pj_xml_find_node(addr, &STATUS); - if (!status) { - pj_assert(0); - return -1; - } - attr = pj_xml_find_attr(status, &STATUS, NULL); - if (!attr) { - pj_assert(0); - return -1; - } - - attr->value = ( online_status ? OPEN : CLOSED ); - return 0; -} - |