Ignore:
Timestamp:
Feb 19, 2006 1:38:06 AM (18 years ago)
Author:
bennylp
Message:

Initial SIMPLE implementation

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip/src/pjsip-simple/presence.c

    • Property svn:keywords set to id
    r65 r197  
    1717 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
    1818 */ 
    19 #include <pjsip_simple/presence.h> 
    20 #include <pjsip/sip_transport.h> 
     19#include <pjsip-simple/presence.h> 
     20#include <pjsip-simple/errno.h> 
     21#include <pjsip-simple/evsub_msg.h> 
     22#include <pjsip/sip_module.h> 
     23#include <pjsip/sip_endpoint.h> 
     24#include <pjsip/sip_dialog.h> 
     25#include <pj/assert.h> 
     26#include <pj/guid.h> 
     27#include <pj/log.h> 
     28#include <pj/os.h> 
    2129#include <pj/pool.h> 
    2230#include <pj/string.h> 
    23 #include <pj/guid.h> 
    24 #include <pj/os.h> 
    25 #include <stdio.h> 
    26  
    27 /* Forward declarations. */ 
    28 static void on_query_subscribe(pjsip_rx_data *rdata, int *status); 
    29 static void on_subscribe(pjsip_event_sub *sub, pjsip_rx_data *rdata, 
    30                          pjsip_event_sub_cb **cb, int *expires); 
    31 static void on_sub_terminated(pjsip_event_sub *sub, const pj_str_t *reason); 
    32 static void on_sub_received_refresh(pjsip_event_sub *sub, pjsip_rx_data *rdata); 
    33 static void on_received_notify(pjsip_event_sub *sub, pjsip_rx_data *rdata); 
    34  
    35 /* Some string constants. */ 
    36 static pj_str_t PRESENCE_EVENT = { "presence", 8 }; 
    37  
    38 /* Accept types. */ 
    39 static pj_str_t accept_names[] = { 
    40     { "application/pidf+xml", 20 }, 
    41     { "application/xpidf+xml", 21 } 
     31 
     32 
     33#define THIS_FILE                   "presence.c" 
     34#define PRES_DEFAULT_EXPIRES        600 
     35 
     36/* 
     37 * Presence module (mod-presence) 
     38 */ 
     39static struct pjsip_module mod_presence =  
     40{ 
     41    NULL, NULL,                     /* prev, next.                      */ 
     42    { "mod-presence", 12 },         /* Name.                            */ 
     43    -1,                             /* Id                               */ 
     44    PJSIP_MOD_PRIORITY_APPLICATION-1,   /* Priority                     */ 
     45    NULL,                           /* User data.                       */ 
     46    NULL,                           /* load()                           */ 
     47    NULL,                           /* start()                          */ 
     48    NULL,                           /* stop()                           */ 
     49    NULL,                           /* unload()                         */ 
     50    NULL,                           /* on_rx_request()                  */ 
     51    NULL,                           /* on_rx_response()                 */ 
     52    NULL,                           /* on_tx_request.                   */ 
     53    NULL,                           /* on_tx_response()                 */ 
     54    NULL,                           /* on_tsx_state()                   */ 
    4255}; 
    43 static pjsip_media_type accept_types[] = { 
    44     { 
    45         { "application", 11 }, 
    46         { "pidf+xml", 8 } 
    47     }, 
    48     { 
    49         { "application", 11 }, 
    50         { "xpidf+xml", 9 } 
    51     } 
     56 
     57 
     58/* 
     59 * Presence message body type. 
     60 */ 
     61typedef enum content_type 
     62{ 
     63    CONTENT_TYPE_NONE, 
     64    CONTENT_TYPE_PIDF, 
     65    CONTENT_TYPE_XPIDF, 
     66} content_type; 
     67 
     68/* 
     69 * This structure describe a presentity, for both subscriber and notifier. 
     70 */ 
     71struct pjsip_pres 
     72{ 
     73    pjsip_evsub         *sub;           /**< Event subscribtion record.     */ 
     74    pjsip_dialog        *dlg;           /**< The dialog.                    */ 
     75    content_type         content_type;  /**< Content-Type.                  */ 
     76    pjsip_pres_status    status;        /**< Presence status.               */ 
     77    pjsip_pres_status    tmp_status;    /**< Temp, before NOTIFY is answred.*/ 
     78    pjsip_evsub_user     user_cb;       /**< The user callback.             */ 
    5279}; 
    5380 
    54 /* Callback that is registered by application. */ 
    55 static pjsip_presence_cb cb; 
    56  
    57 /* Package callback to be register to event_notify */ 
    58 static pjsip_event_sub_pkg_cb pkg_cb = { &on_query_subscribe, 
    59                                          &on_subscribe }; 
    60  
    61 /* Global/static callback to be registered to event_notify */ 
    62 static pjsip_event_sub_cb sub_cb = { &on_sub_terminated, 
    63                                      &on_sub_received_refresh, 
    64                                      NULL, 
    65                                      &on_received_notify, 
    66                                      NULL }; 
    67  
    68 /* 
    69  * Initialize presence module. 
    70  * This will register event package "presence" to event framework. 
    71  */ 
    72 PJ_DEF(void) pjsip_presence_init(const pjsip_presence_cb *pcb) 
    73 { 
    74     pj_memcpy(&cb, pcb, sizeof(*pcb)); 
    75     pjsip_event_sub_register_pkg( &PRESENCE_EVENT,  
    76                                   sizeof(accept_names)/sizeof(accept_names[0]), 
    77                                   accept_names, 
    78                                   &pkg_cb); 
    79 } 
    80  
    81 /* 
    82  * Create presence subscription. 
    83  */ 
    84 PJ_DEF(pjsip_presentity*) pjsip_presence_create( pjsip_endpoint *endpt, 
    85                                                  const pj_str_t *local_url, 
    86                                                  const pj_str_t *remote_url, 
    87                                                  int expires, 
    88                                                  void *user_data ) 
    89 { 
    90     pjsip_event_sub *sub; 
    91     pjsip_presentity *pres; 
    92  
    93     if (expires < 0) 
    94         expires = 300; 
     81 
     82typedef struct pjsip_pres pjsip_pres; 
     83 
     84 
     85/* 
     86 * Forward decl for evsub callback. 
     87 */ 
     88static void pres_on_evsub_state( pjsip_evsub *sub, pjsip_event *event); 
     89static void pres_on_evsub_tsx_state( pjsip_evsub *sub, pjsip_transaction *tsx, 
     90                                     pjsip_event *event); 
     91static void pres_on_evsub_rx_refresh( pjsip_evsub *sub,  
     92                                      pjsip_rx_data *rdata, 
     93                                      int *p_st_code, 
     94                                      pj_str_t **p_st_text, 
     95                                      pjsip_hdr *res_hdr, 
     96                                      pjsip_msg_body **p_body); 
     97static void pres_on_evsub_rx_notify( pjsip_evsub *sub,  
     98                                     pjsip_rx_data *rdata, 
     99                                     int *p_st_code, 
     100                                     pj_str_t **p_st_text, 
     101                                     pjsip_hdr *res_hdr, 
     102                                     pjsip_msg_body **p_body); 
     103static void pres_on_evsub_client_refresh(pjsip_evsub *sub); 
     104static void pres_on_evsub_server_timeout(pjsip_evsub *sub); 
     105 
     106 
     107/* 
     108 * Event subscription callback for presence. 
     109 */ 
     110static pjsip_evsub_user pres_user =  
     111{ 
     112    &pres_on_evsub_state, 
     113    &pres_on_evsub_tsx_state, 
     114    &pres_on_evsub_rx_refresh, 
     115    &pres_on_evsub_rx_notify, 
     116    &pres_on_evsub_client_refresh, 
     117    &pres_on_evsub_server_timeout, 
     118}; 
     119 
     120 
     121/* 
     122 * Some static constants. 
     123 */ 
     124const pj_str_t STR_EVENT            = { "Event", 5 }; 
     125const pj_str_t STR_PRESENCE         = { "presence", 8 }; 
     126const pj_str_t STR_APPLICATION      = { "application", 11 }; 
     127const pj_str_t STR_PIDF_XML         = { "pidf+xml", 8}; 
     128const pj_str_t STR_XPIDF_XML        = { "xpidf+xml", 9}; 
     129const pj_str_t STR_APP_PIDF_XML     = { "application/pidf+xml", 20 }; 
     130const pj_str_t STR_APP_XPIDF_XML    = { "application/xpidf+xml", 21 }; 
     131 
     132 
     133/* 
     134 * Init presence module. 
     135 */ 
     136PJ_DEF(pj_status_t) pjsip_pres_init_module( pjsip_endpoint *endpt, 
     137                                            pjsip_module *mod_evsub) 
     138{ 
     139    pj_status_t status; 
     140    pj_str_t accept[2]; 
     141 
     142    /* Check arguments. */ 
     143    PJ_ASSERT_RETURN(endpt && mod_evsub, PJ_EINVAL); 
     144 
     145    /* Must have not been registered */ 
     146    PJ_ASSERT_RETURN(mod_presence.id == -1, PJ_EINVALIDOP); 
     147 
     148    /* Register to endpoint */ 
     149    status = pjsip_endpt_register_module(endpt, &mod_presence); 
     150    if (status != PJ_SUCCESS) 
     151        return status; 
     152 
     153    accept[0] = STR_APP_PIDF_XML; 
     154    accept[1] = STR_APP_XPIDF_XML; 
     155 
     156    /* Register event package to event module. */ 
     157    status = pjsip_evsub_register_pkg( &mod_presence, &STR_PRESENCE,  
     158                                       PRES_DEFAULT_EXPIRES,  
     159                                       PJ_ARRAY_SIZE(accept), accept); 
     160    if (status != PJ_SUCCESS) { 
     161        pjsip_endpt_unregister_module(endpt, &mod_presence); 
     162        return status; 
     163    } 
     164 
     165    return PJ_SUCCESS; 
     166} 
     167 
     168 
     169/* 
     170 * Get presence module instance. 
     171 */ 
     172PJ_DEF(pjsip_module*) pjsip_pres_instance(void) 
     173{ 
     174    return &mod_presence; 
     175} 
     176 
     177 
     178/* 
     179 * Create client subscription. 
     180 */ 
     181PJ_DEF(pj_status_t) pjsip_pres_create_uac( pjsip_dialog *dlg, 
     182                                           const pjsip_evsub_user *user_cb, 
     183                                           pjsip_evsub **p_evsub ) 
     184{ 
     185    pj_status_t status; 
     186    pjsip_pres *pres; 
     187    pjsip_evsub *sub; 
     188 
     189    PJ_ASSERT_RETURN(dlg && p_evsub, PJ_EINVAL); 
     190 
     191    pjsip_dlg_inc_lock(dlg); 
    95192 
    96193    /* Create event subscription */ 
    97     sub = pjsip_event_sub_create(endpt, local_url, remote_url, &PRESENCE_EVENT,  
    98                                  expires,  
    99                                  sizeof(accept_names)/sizeof(accept_names[0]), 
    100                                  accept_names, 
    101                                  NULL, &sub_cb); 
    102     if (!sub) 
    103         return NULL; 
    104  
    105     /* Allocate presence descriptor. */ 
    106     pres = pj_pool_calloc(sub->pool, 1, sizeof(*pres)); 
    107     pres->sub = sub; 
    108     pres->user_data = user_data; 
    109     sub->user_data = pres; 
    110  
    111     return pres; 
    112 } 
    113  
    114 /* 
    115  * Send SUBSCRIBE. 
    116  */ 
    117 PJ_DEF(pj_status_t) pjsip_presence_subscribe( pjsip_presentity *pres ) 
    118 { 
    119     return pjsip_event_sub_subscribe( pres->sub ); 
    120 } 
    121  
    122 /* 
    123  * Set credentials to be used for outgoing requests. 
    124  */ 
    125 PJ_DEF(pj_status_t) pjsip_presence_set_credentials( pjsip_presentity *pres, 
    126                                                     int count, 
    127                                                     const pjsip_cred_info cred[]) 
    128 { 
    129     return pjsip_event_sub_set_credentials(pres->sub, count, cred); 
    130 } 
    131  
    132 /* 
    133  * Set route-set. 
    134  */ 
    135 PJ_DEF(pj_status_t) pjsip_presence_set_route_set( pjsip_presentity *pres, 
    136                                                   const pjsip_route_hdr *hdr ) 
    137 { 
    138     return pjsip_event_sub_set_route_set( pres->sub, hdr ); 
    139 } 
    140  
    141 /* 
    142  * Unsubscribe. 
    143  */ 
    144 PJ_DEF(pj_status_t) pjsip_presence_unsubscribe( pjsip_presentity *pres ) 
    145 { 
    146     return pjsip_event_sub_unsubscribe(pres->sub); 
    147 } 
    148  
    149 /* 
    150  * This is the pjsip_msg_body callback to print XML body. 
    151  */ 
    152 static int print_xml(pjsip_msg_body *body, char *buf, pj_size_t size) 
    153 { 
    154     return pj_xml_print( body->data, buf, size, PJ_TRUE ); 
    155 } 
    156  
    157 /* 
    158  * Create and initialize PIDF document and msg body (notifier only). 
    159  */ 
    160 static pj_status_t init_presence_info( pjsip_presentity *pres ) 
    161 { 
    162     pj_str_t uri; 
    163     pj_pool_t *pool = pres->sub->pool; 
    164     char tmp[PJSIP_MAX_URL_SIZE]; 
    165     pjpidf_tuple *tuple; 
    166     const pjsip_media_type *content_type = NULL; 
    167  
    168     pj_assert(pres->uas_body == NULL); 
    169  
    170     /* Make entity_id */ 
    171     uri.ptr = tmp; 
    172     uri.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, pres->sub->from->uri,  
    173                               tmp, sizeof(tmp)); 
    174     if (uri.slen < 0) 
    175         return -1; 
    176  
    177     if (pres->pres_type == PJSIP_PRES_TYPE_PIDF) { 
    178         pj_str_t s; 
    179  
    180         /* Create <presence>. */ 
    181         pres->uas_data.pidf = pjpidf_create(pool, &s); 
    182  
    183         /* Create <tuple> */ 
    184         pj_create_unique_string(pool, &s); 
    185         tuple = pjpidf_pres_add_tuple(pool, pres->uas_data.pidf, &s); 
    186  
    187         /* Set <contact> */ 
    188         s.ptr = tmp; 
    189         s.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, pres->sub->contact->uri, tmp, sizeof(tmp)); 
    190         if (s.slen < 0) 
    191             return -1; 
    192         pjpidf_tuple_set_contact(pool, tuple, &s); 
    193  
    194         /* Content-Type */ 
    195         content_type = &accept_types[PJSIP_PRES_TYPE_PIDF]; 
    196  
    197     } else if (pres->pres_type == PJSIP_PRES_TYPE_XPIDF) { 
    198  
    199         /* Create XPIDF */ 
    200         pres->uas_data.xpidf = pjxpidf_create(pool, &uri); 
    201  
    202         /* Content-Type. */ 
    203         content_type = &accept_types[PJSIP_PRES_TYPE_XPIDF]; 
    204     } 
    205  
    206     /* Create message body */ 
    207     pres->uas_body = pj_pool_alloc(pool, sizeof(pjsip_msg_body)); 
    208     pres->uas_body->content_type = *content_type; 
    209     pres->uas_body->data = pres->uas_data.pidf; 
    210     pres->uas_body->len = 0; 
    211     pres->uas_body->print_body = &print_xml; 
    212  
    213     return 0; 
    214 } 
    215  
    216 /* 
    217  * Send NOTIFY and set subscription state. 
    218  */ 
    219 PJ_DEF(pj_status_t) pjsip_presence_notify( pjsip_presentity *pres, 
    220                                            pjsip_event_sub_state state, 
    221                                            pj_bool_t is_online ) 
    222 { 
    223     pj_str_t reason = { "", 0 }; 
    224  
    225     if (pres->uas_data.pidf == NULL) { 
    226         if (init_presence_info(pres) != 0) 
    227             return -1; 
    228     } 
    229  
    230     /* Update basic status in PIDF/XPIDF document. */ 
    231     if (pres->pres_type == PJSIP_PRES_TYPE_PIDF) { 
    232         pjpidf_tuple *first; 
    233         pjpidf_status *status; 
    234         pj_time_val now; 
    235         pj_parsed_time pnow; 
    236  
    237         first = pjpidf_op.pres.get_first_tuple(pres->uas_data.pidf); 
    238         pj_assert(first); 
    239         status = pjpidf_op.tuple.get_status(first); 
    240         pj_assert(status); 
    241         pjpidf_op.status.set_basic_open(status, is_online); 
    242  
    243         /* Update timestamp. */ 
    244         if (pres->timestamp.ptr == 0) { 
    245             pres->timestamp.ptr = pj_pool_alloc(pres->sub->pool, 24); 
    246         } 
    247         pj_gettimeofday(&now); 
    248         pj_time_decode(&now, &pnow); 
    249         pres->timestamp.slen = sprintf(pres->timestamp.ptr, 
    250                                        "%04d-%02d-%02dT%02d:%02d:%02dZ", 
    251                                        pnow.year, pnow.mon, pnow.day, 
    252                                        pnow.hour, pnow.min, pnow.sec); 
    253         pjpidf_op.tuple.set_timestamp_np(pres->sub->pool, first, &pres->timestamp); 
    254  
    255     } else if (pres->pres_type == PJSIP_PRES_TYPE_XPIDF) { 
    256         pjxpidf_set_status( pres->uas_data.xpidf, is_online ); 
    257  
    258     } else { 
    259         pj_assert(0); 
    260     } 
    261  
    262     /* Send notify. */ 
    263     return pjsip_event_sub_notify( pres->sub, state, &reason, pres->uas_body); 
    264 } 
    265  
    266 /* 
    267  * Destroy subscription (can be called for both subscriber and notifier). 
    268  */ 
    269 PJ_DEF(pj_status_t) pjsip_presence_destroy( pjsip_presentity *pres ) 
    270 { 
    271     return pjsip_event_sub_destroy(pres->sub); 
    272 } 
    273  
    274 /* 
    275  * This callback is called by event framework to query whether we want to 
    276  * accept an incoming subscription. 
    277  */ 
    278 static void on_query_subscribe(pjsip_rx_data *rdata, int *status) 
    279 { 
    280     if (cb.accept_presence) { 
    281         (*cb.accept_presence)(rdata, status); 
    282     } 
    283 } 
    284  
    285 /* 
    286  * This callback is called by event framework after we accept the incoming 
    287  * subscription, to notify about the new subscription instance. 
    288  */ 
    289 static void on_subscribe(pjsip_event_sub *sub, pjsip_rx_data *rdata, 
    290                          pjsip_event_sub_cb **set_sub_cb, int *expires) 
    291 { 
    292     pjsip_presentity *pres; 
     194    status = pjsip_evsub_create_uac( dlg,  &pres_user, &STR_PRESENCE, &sub); 
     195    if (status != PJ_SUCCESS) 
     196        goto on_return; 
     197 
     198    /* Create presence */ 
     199    pres = pj_pool_zalloc(dlg->pool, sizeof(pjsip_pres)); 
     200    pres->dlg = dlg; 
     201    if (user_cb) 
     202        pj_memcpy(&pres->user_cb, user_cb, sizeof(pjsip_evsub_user)); 
     203 
     204    /* Attach to evsub */ 
     205    pjsip_evsub_set_mod_data(sub, mod_presence.id, pres); 
     206 
     207    *p_evsub = sub; 
     208 
     209on_return: 
     210    pjsip_dlg_dec_lock(dlg); 
     211    return status; 
     212} 
     213 
     214 
     215/* 
     216 * Create server subscription. 
     217 */ 
     218PJ_DEF(pj_status_t) pjsip_pres_create_uas( pjsip_dialog *dlg, 
     219                                           const pjsip_evsub_user *user_cb, 
     220                                           pjsip_rx_data *rdata, 
     221                                           pjsip_evsub **p_evsub ) 
     222{ 
    293223    pjsip_accept_hdr *accept; 
    294  
    295     pres = pj_pool_calloc(sub->pool, 1, sizeof(*pres)); 
    296     pres->sub = sub; 
    297     pres->pres_type = PJSIP_PRES_TYPE_PIDF; 
    298     sub->user_data = pres; 
    299     *set_sub_cb = &sub_cb; 
    300  
    301     accept = pjsip_msg_find_hdr(rdata->msg, PJSIP_H_ACCEPT, NULL); 
     224    pjsip_event_hdr *event; 
     225    pjsip_expires_hdr *expires_hdr; 
     226    unsigned expires; 
     227    content_type content_type = CONTENT_TYPE_NONE; 
     228    pjsip_evsub *sub; 
     229    pjsip_pres *pres; 
     230    pj_status_t status; 
     231 
     232    /* Check arguments */ 
     233    PJ_ASSERT_RETURN(dlg && rdata && p_evsub, PJ_EINVAL); 
     234 
     235    /* Must be request message */ 
     236    PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG, 
     237                     PJSIP_ENOTREQUESTMSG); 
     238 
     239    /* Check that request is SUBSCRIBE */ 
     240    PJ_ASSERT_RETURN(pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, 
     241                                      &pjsip_subscribe_method)==0, 
     242                     PJSIP_SIMPLE_ENOTSUBSCRIBE); 
     243 
     244    /* Check that Event header contains "presence" */ 
     245    event = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &STR_EVENT, NULL); 
     246    if (!event) { 
     247        return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_BAD_REQUEST); 
     248    } 
     249    if (pj_stricmp(&event->event_type, &STR_PRESENCE) != 0) { 
     250        return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_BAD_EVENT); 
     251    } 
     252 
     253    /* Check that request contains compatible Accept header. */ 
     254    accept = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, NULL); 
    302255    if (accept) { 
    303256        unsigned i; 
    304         int found = 0; 
    305         for (i=0; i<accept->count && !found; ++i) { 
    306             int j; 
    307             for (j=0; j<sizeof(accept_names)/sizeof(accept_names[0]); ++j) { 
    308                 if (!pj_stricmp(&accept->values[i], &accept_names[j])) { 
    309                     pres->pres_type = j; 
    310                     found = 1; 
    311                     break; 
    312                 } 
    313             } 
    314         } 
    315         pj_assert(found ); 
    316     } 
    317  
    318     (*cb.on_received_request)(pres, rdata, expires); 
    319 } 
    320  
    321 /* 
    322  * This callback is called by event framework when the subscription is 
    323  * terminated. 
    324  */ 
    325 static void on_sub_terminated(pjsip_event_sub *sub, const pj_str_t *reason) 
    326 { 
    327     pjsip_presentity *pres = sub->user_data; 
    328     if (cb.on_terminated) 
    329         (*cb.on_terminated)(pres, reason); 
    330 } 
    331  
    332 /* 
    333  * This callback is called by event framework when it receives incoming 
    334  * SUBSCRIBE request to refresh the subscription. 
    335  */ 
    336 static void on_sub_received_refresh(pjsip_event_sub *sub, pjsip_rx_data *rdata) 
    337 { 
    338     pjsip_presentity *pres = sub->user_data; 
    339     if (cb.on_received_refresh) 
    340         (*cb.on_received_refresh)(pres, rdata); 
    341 } 
    342  
    343 /* 
    344  * This callback is called by event framework when it receives incoming 
    345  * NOTIFY request. 
    346  */ 
    347 static void on_received_notify(pjsip_event_sub *sub, pjsip_rx_data *rdata) 
    348 { 
    349     pjsip_presentity *pres = sub->user_data; 
    350  
    351     if (cb.on_received_update) { 
    352         pj_status_t is_open; 
    353         pjsip_msg_body *body; 
    354         int i; 
    355  
    356         body = rdata->msg->body; 
    357         if (!body) 
    358             return; 
    359  
    360         for (i=0; i<sizeof(accept_types)/sizeof(accept_types[0]); ++i) { 
    361             if (!pj_stricmp(&body->content_type.type, &accept_types[i].type) && 
    362                 !pj_stricmp(&body->content_type.subtype, &accept_types[i].subtype)) 
    363             { 
     257        for (i=0; i<accept->count; ++i) { 
     258            if (pj_stricmp(&accept->values[i], &STR_APP_PIDF_XML)==0) { 
     259                content_type = CONTENT_TYPE_PIDF; 
     260                break; 
     261            } else 
     262            if (pj_stricmp(&accept->values[i], &STR_APP_XPIDF_XML)==0) { 
     263                content_type = CONTENT_TYPE_XPIDF; 
    364264                break; 
    365265            } 
    366266        } 
    367267 
    368         if (i==PJSIP_PRES_TYPE_PIDF) { 
    369             pjpidf_pres *pres; 
    370             pjpidf_tuple *tuple; 
    371             pjpidf_status *status; 
    372  
    373             pres = pjpidf_parse(rdata->pool, body->data, body->len); 
    374             if (!pres) 
    375                 return; 
    376             tuple = pjpidf_pres_get_first_tuple(pres); 
    377             if (!tuple) 
    378                 return; 
    379             status = pjpidf_tuple_get_status(tuple); 
    380             if (!status) 
    381                 return; 
    382             is_open = pjpidf_status_is_basic_open(status); 
    383  
    384         } else if (i==PJSIP_PRES_TYPE_XPIDF) { 
    385             pjxpidf_pres *pres; 
    386  
    387             pres = pjxpidf_parse(rdata->pool, body->data, body->len); 
    388             if (!pres) 
    389                 return; 
    390             is_open = pjxpidf_get_status(pres); 
    391  
     268        if (i==accept->count) { 
     269            /* Nothing is acceptable */ 
     270            return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE); 
     271        } 
     272 
     273    } else { 
     274        /* No Accept header. 
     275         * Treat as "application/pidf+xml" 
     276         */ 
     277        content_type = CONTENT_TYPE_PIDF; 
     278    } 
     279 
     280    /* Check that expires is not too short. */ 
     281    expires_hdr=pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL); 
     282    if (expires_hdr) { 
     283        if (expires_hdr->ivalue < 5) { 
     284            return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_INTERVAL_TOO_BRIEF); 
     285        } 
     286 
     287        expires = expires_hdr->ivalue; 
     288        if (expires > PRES_DEFAULT_EXPIRES) 
     289            expires = PRES_DEFAULT_EXPIRES; 
     290 
     291    } else { 
     292        expires = PRES_DEFAULT_EXPIRES; 
     293    } 
     294     
     295    /* Lock dialog */ 
     296    pjsip_dlg_inc_lock(dlg); 
     297 
     298 
     299    /* Create server subscription */ 
     300    status = pjsip_evsub_create_uas( dlg, &pres_user, rdata, &sub); 
     301    if (status != PJ_SUCCESS) 
     302        goto on_return; 
     303 
     304    /* Create server presence subscription */ 
     305    pres = pj_pool_zalloc(dlg->pool, sizeof(pjsip_pres)); 
     306    pres->dlg = dlg; 
     307    pres->sub = sub; 
     308    pres->content_type = content_type; 
     309    if (user_cb) 
     310        pj_memcpy(&pres->user_cb, user_cb, sizeof(pjsip_evsub_user)); 
     311 
     312    /* Attach to evsub */ 
     313    pjsip_evsub_set_mod_data(sub, mod_presence.id, pres); 
     314 
     315    /* Done: */ 
     316    *p_evsub = sub; 
     317 
     318on_return: 
     319    pjsip_dlg_dec_lock(dlg); 
     320    return status; 
     321} 
     322 
     323 
     324/* 
     325 * Create SUBSCRIBE 
     326 */ 
     327PJ_DEF(pj_status_t) pjsip_pres_initiate( pjsip_evsub *sub, 
     328                                         pj_int32_t expires, 
     329                                         pjsip_tx_data **p_tdata) 
     330{ 
     331    return pjsip_evsub_initiate(sub, &pjsip_subscribe_method, expires,  
     332                                p_tdata); 
     333} 
     334 
     335 
     336/* 
     337 * Accept incoming subscription. 
     338 */ 
     339PJ_DEF(pj_status_t) pjsip_pres_accept( pjsip_evsub *sub, 
     340                                       pjsip_rx_data *rdata, 
     341                                       int st_code, 
     342                                       const pjsip_hdr *hdr_list ) 
     343{ 
     344    return pjsip_evsub_accept( sub, rdata, st_code, hdr_list ); 
     345} 
     346 
     347 
     348/* 
     349 * Get presence status. 
     350 */ 
     351PJ_DEF(pj_status_t) pjsip_pres_get_status( pjsip_evsub *sub, 
     352                                           pjsip_pres_status *status ) 
     353{ 
     354    pjsip_pres *pres; 
     355 
     356    PJ_ASSERT_RETURN(sub && status, PJ_EINVAL); 
     357 
     358    pres = pjsip_evsub_get_mod_data(sub, mod_presence.id); 
     359    PJ_ASSERT_RETURN(pres!=NULL, PJSIP_SIMPLE_ENOPRESENCE); 
     360 
     361    if (pres->tmp_status._is_valid) 
     362        pj_memcpy(status, &pres->tmp_status, sizeof(pjsip_pres_status)); 
     363    else 
     364        pj_memcpy(status, &pres->status, sizeof(pjsip_pres_status)); 
     365 
     366    return PJ_SUCCESS; 
     367} 
     368 
     369 
     370/* 
     371 * Set presence status. 
     372 */ 
     373PJ_DEF(pj_status_t) pjsip_pres_set_status( pjsip_evsub *sub, 
     374                                           const pjsip_pres_status *status ) 
     375{ 
     376    unsigned i; 
     377    pjsip_pres *pres; 
     378 
     379    PJ_ASSERT_RETURN(sub && status, PJ_EINVAL); 
     380 
     381    pres = pjsip_evsub_get_mod_data(sub, mod_presence.id); 
     382    PJ_ASSERT_RETURN(pres!=NULL, PJSIP_SIMPLE_ENOPRESENCE); 
     383 
     384    for (i=0; i<status->info_cnt; ++i) { 
     385        pres->status.info[i].basic_open = status->info[i].basic_open; 
     386        if (status->info[i].id.slen == 0) { 
     387            pj_create_unique_string(pres->dlg->pool,  
     388                                    &pres->status.info[i].id); 
    392389        } else { 
    393             return; 
     390            pj_strdup(pres->dlg->pool,  
     391                      &pres->status.info[i].id, 
     392                      &status->info[i].id); 
    394393        } 
    395  
    396         (*cb.on_received_update)(pres, is_open); 
    397     } 
    398 } 
    399  
     394        pj_strdup(pres->dlg->pool,  
     395                  &pres->status.info[i].contact, 
     396                  &status->info[i].contact); 
     397    } 
     398 
     399    pres->status.info_cnt = status->info_cnt; 
     400 
     401    return PJ_SUCCESS; 
     402} 
     403 
     404 
     405/* 
     406 * Create PIDF document based on the presence info. 
     407 */ 
     408static pjpidf_pres* pres_create_pidf( pj_pool_t *pool, 
     409                                      pjsip_pres *pres ) 
     410{ 
     411    pjpidf_pres *pidf; 
     412    unsigned i; 
     413    pj_str_t entity; 
     414 
     415    /* Get publisher URI */ 
     416    entity.ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE); 
     417    entity.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, 
     418                                  pres->dlg->local.info->uri, 
     419                                  entity.ptr, PJSIP_MAX_URL_SIZE); 
     420    if (entity.slen < 1) 
     421        return NULL; 
     422 
     423    /* Create <presence>. */ 
     424    pidf = pjpidf_create(pool, &entity); 
     425 
     426    /* Create <tuple> */ 
     427    for (i=0; i<pres->status.info_cnt; ++i) { 
     428 
     429        pjpidf_tuple *pidf_tuple; 
     430        pjpidf_status *pidf_status; 
     431 
     432        /* Add tuple id. */ 
     433        pidf_tuple = pjpidf_pres_add_tuple(pool, pidf,  
     434                                           &pres->status.info[i].id); 
     435 
     436        /* Set <contact> */ 
     437        if (pres->status.info[i].contact.slen) 
     438            pjpidf_tuple_set_contact(pool, pidf_tuple,  
     439                                     &pres->status.info[i].contact); 
     440 
     441 
     442        /* Set basic status */ 
     443        pidf_status = pjpidf_tuple_get_status(pidf_tuple); 
     444        pjpidf_status_set_basic_open(pidf_status,  
     445                                     pres->status.info[i].basic_open); 
     446    } 
     447 
     448    return pidf; 
     449} 
     450 
     451 
     452/* 
     453 * Create XPIDF document based on the presence info. 
     454 */ 
     455static pjxpidf_pres* pres_create_xpidf( pj_pool_t *pool, 
     456                                        pjsip_pres *pres ) 
     457{ 
     458    /* Note: PJSIP implementation of XPIDF is not complete! 
     459     */ 
     460    pjxpidf_pres *xpidf; 
     461    pj_str_t publisher_uri; 
     462 
     463    PJ_LOG(4,(THIS_FILE, "Warning: XPIDF format is not fully supported " 
     464                         "by PJSIP")); 
     465 
     466    publisher_uri.ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE); 
     467    publisher_uri.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, 
     468                                         pres->dlg->local.info->uri, 
     469                                         publisher_uri.ptr, 
     470                                         PJSIP_MAX_URL_SIZE); 
     471    if (publisher_uri.slen < 1) 
     472        return NULL; 
     473 
     474    /* Create XPIDF document. */ 
     475    xpidf = pjxpidf_create(pool, &publisher_uri); 
     476 
     477    /* Set basic status. */ 
     478    if (pres->status.info_cnt > 0) 
     479        pjxpidf_set_status( xpidf, pres->status.info[0].basic_open); 
     480    else 
     481        pjxpidf_set_status( xpidf, PJ_FALSE); 
     482 
     483    return xpidf; 
     484} 
     485 
     486 
     487/* 
     488 * Function to print XML message body. 
     489 */ 
     490static int pres_print_body(struct pjsip_msg_body *msg_body,  
     491                           char *buf, pj_size_t size) 
     492{ 
     493    return pj_xml_print(msg_body->data, buf, size, PJ_TRUE); 
     494} 
     495 
     496 
     497/* 
     498 * Function to clone XML document. 
     499 */ 
     500static void* xml_clone_data(pj_pool_t *pool, const void *data, unsigned len) 
     501{ 
     502    PJ_UNUSED_ARG(len); 
     503    return pj_xml_clone( pool, data); 
     504} 
     505 
     506 
     507/* 
     508 * Create message body. 
     509 */ 
     510static pj_status_t pres_create_msg_body( pjsip_pres *pres,  
     511                                         pjsip_tx_data *tdata) 
     512{ 
     513    pjsip_msg_body *body; 
     514 
     515    body = pj_pool_zalloc(tdata->pool, sizeof(pjsip_msg_body)); 
     516     
     517    if (pres->content_type == CONTENT_TYPE_PIDF) { 
     518 
     519        body->data = pres_create_pidf(tdata->pool, pres); 
     520        body->content_type.type = pj_str("application"); 
     521        body->content_type.subtype = pj_str("pidf+xml"); 
     522 
     523    } else if (pres->content_type == CONTENT_TYPE_XPIDF) { 
     524 
     525        body->data = pres_create_xpidf(tdata->pool, pres); 
     526        body->content_type.type = pj_str("application"); 
     527        body->content_type.subtype = pj_str("xpidf+xml"); 
     528 
     529    } else { 
     530        return PJSIP_SIMPLE_EBADCONTENT; 
     531    } 
     532 
     533 
     534    body->print_body = &pres_print_body; 
     535    body->clone_data = &xml_clone_data; 
     536 
     537    tdata->msg->body = body; 
     538 
     539    return PJ_SUCCESS; 
     540} 
     541 
     542 
     543/* 
     544 * Create NOTIFY 
     545 */ 
     546PJ_DEF(pj_status_t) pjsip_pres_notify( pjsip_evsub *sub, 
     547                                       pjsip_evsub_state state, 
     548                                       const pj_str_t *state_str, 
     549                                       const pj_str_t *reason, 
     550                                       pjsip_tx_data **p_tdata) 
     551{ 
     552    pjsip_pres *pres; 
     553    pjsip_tx_data *tdata; 
     554    pj_status_t status; 
     555     
     556    /* Check arguments. */ 
     557    PJ_ASSERT_RETURN(sub, PJ_EINVAL); 
     558 
     559    /* Get the presence object. */ 
     560    pres = pjsip_evsub_get_mod_data(sub, mod_presence.id); 
     561    PJ_ASSERT_RETURN(pres != NULL, PJSIP_SIMPLE_ENOPRESENCE); 
     562 
     563    /* Must have at least one presence info. */ 
     564    PJ_ASSERT_RETURN(pres->status.info_cnt > 0, PJSIP_SIMPLE_ENOPRESENCEINFO); 
     565 
     566 
     567    /* Lock object. */ 
     568    pjsip_dlg_inc_lock(pres->dlg); 
     569 
     570    /* Create the NOTIFY request. */ 
     571    status = pjsip_evsub_notify( sub, state, state_str, reason, &tdata); 
     572    if (status != PJ_SUCCESS) 
     573        goto on_return; 
     574 
     575 
     576    /* Create message body to reflect the presence status. */ 
     577    status = pres_create_msg_body( pres, tdata ); 
     578    if (status != PJ_SUCCESS) 
     579        goto on_return; 
     580 
     581 
     582    /* Done. */ 
     583    *p_tdata = tdata; 
     584 
     585 
     586on_return: 
     587    pjsip_dlg_dec_lock(pres->dlg); 
     588    return status; 
     589} 
     590 
     591 
     592/* 
     593 * Create NOTIFY that reflect current state. 
     594 */ 
     595PJ_DEF(pj_status_t) pjsip_pres_current_notify( pjsip_evsub *sub, 
     596                                               pjsip_tx_data **p_tdata ) 
     597{ 
     598    pjsip_pres *pres; 
     599    pjsip_tx_data *tdata; 
     600    pj_status_t status; 
     601     
     602    /* Check arguments. */ 
     603    PJ_ASSERT_RETURN(sub, PJ_EINVAL); 
     604 
     605    /* Get the presence object. */ 
     606    pres = pjsip_evsub_get_mod_data(sub, mod_presence.id); 
     607    PJ_ASSERT_RETURN(pres != NULL, PJSIP_SIMPLE_ENOPRESENCE); 
     608 
     609    /* Must have at least one presence info. */ 
     610    PJ_ASSERT_RETURN(pres->status.info_cnt > 0, PJSIP_SIMPLE_ENOPRESENCEINFO); 
     611 
     612 
     613    /* Lock object. */ 
     614    pjsip_dlg_inc_lock(pres->dlg); 
     615 
     616    /* Create the NOTIFY request. */ 
     617    status = pjsip_evsub_current_notify( sub, &tdata); 
     618    if (status != PJ_SUCCESS) 
     619        goto on_return; 
     620 
     621 
     622    /* Create message body to reflect the presence status. */ 
     623    status = pres_create_msg_body( pres, tdata ); 
     624    if (status != PJ_SUCCESS) 
     625        goto on_return; 
     626 
     627 
     628    /* Done. */ 
     629    *p_tdata = tdata; 
     630 
     631 
     632on_return: 
     633    pjsip_dlg_dec_lock(pres->dlg); 
     634    return status; 
     635} 
     636 
     637 
     638/* 
     639 * Send request. 
     640 */ 
     641PJ_DEF(pj_status_t) pjsip_pres_send_request( pjsip_evsub *sub, 
     642                                             pjsip_tx_data *tdata ) 
     643{ 
     644    return pjsip_evsub_send_request(sub, tdata); 
     645} 
     646 
     647 
     648/* 
     649 * This callback is called by event subscription when subscription 
     650 * state has changed. 
     651 */ 
     652static void pres_on_evsub_state( pjsip_evsub *sub, pjsip_event *event) 
     653{ 
     654    pjsip_pres *pres; 
     655 
     656    pres = pjsip_evsub_get_mod_data(sub, mod_presence.id); 
     657    PJ_ASSERT_ON_FAIL(pres!=NULL, {return;}); 
     658 
     659    if (pres->user_cb.on_evsub_state) 
     660        (*pres->user_cb.on_evsub_state)(sub, event); 
     661} 
     662 
     663/* 
     664 * Called when transaction state has changed. 
     665 */ 
     666static void pres_on_evsub_tsx_state( pjsip_evsub *sub, pjsip_transaction *tsx, 
     667                                     pjsip_event *event) 
     668{ 
     669    pjsip_pres *pres; 
     670 
     671    pres = pjsip_evsub_get_mod_data(sub, mod_presence.id); 
     672    PJ_ASSERT_ON_FAIL(pres!=NULL, {return;}); 
     673 
     674    if (pres->user_cb.on_tsx_state) 
     675        (*pres->user_cb.on_tsx_state)(sub, tsx, event); 
     676} 
     677 
     678 
     679/* 
     680 * Called when SUBSCRIBE is received. 
     681 */ 
     682static void pres_on_evsub_rx_refresh( pjsip_evsub *sub,  
     683                                      pjsip_rx_data *rdata, 
     684                                      int *p_st_code, 
     685                                      pj_str_t **p_st_text, 
     686                                      pjsip_hdr *res_hdr, 
     687                                      pjsip_msg_body **p_body) 
     688{ 
     689    pjsip_pres *pres; 
     690 
     691    pres = pjsip_evsub_get_mod_data(sub, mod_presence.id); 
     692    PJ_ASSERT_ON_FAIL(pres!=NULL, {return;}); 
     693 
     694    if (pres->user_cb.on_rx_refresh) { 
     695        (*pres->user_cb.on_rx_refresh)(sub, rdata, p_st_code, p_st_text, 
     696                                       res_hdr, p_body); 
     697 
     698    } else { 
     699        /* Implementors MUST send NOTIFY if it implements on_rx_refresh */ 
     700        pjsip_tx_data *tdata; 
     701        pj_str_t timeout = { "timeout", 7}; 
     702        pj_status_t status; 
     703 
     704        if (pjsip_evsub_get_state(sub)==PJSIP_EVSUB_STATE_TERMINATED) { 
     705            status = pjsip_pres_notify( sub, PJSIP_EVSUB_STATE_TERMINATED, 
     706                                        NULL, &timeout, &tdata); 
     707        } else { 
     708            status = pjsip_pres_current_notify(sub, &tdata); 
     709        } 
     710 
     711        if (status == PJ_SUCCESS) 
     712            pjsip_pres_send_request(sub, tdata); 
     713    } 
     714} 
     715 
     716/* 
     717 * Parse PIDF to info. 
     718 */ 
     719static pj_status_t pres_parse_pidf( pjsip_pres *pres, 
     720                                    pjsip_rx_data *rdata, 
     721                                    pjsip_pres_status *pres_status) 
     722{ 
     723    pjpidf_pres *pidf; 
     724    pjpidf_tuple *pidf_tuple; 
     725 
     726    pidf = pjpidf_parse(rdata->tp_info.pool,  
     727                        rdata->msg_info.msg->body->data, 
     728                        rdata->msg_info.msg->body->len); 
     729    if (pidf == NULL) 
     730        return PJSIP_SIMPLE_EBADPIDF; 
     731 
     732    pres_status->info_cnt = 0; 
     733 
     734    pidf_tuple = pjpidf_pres_get_first_tuple(pidf); 
     735    while (pidf_tuple) { 
     736        pjpidf_status *pidf_status; 
     737 
     738        pj_strdup(pres->dlg->pool,  
     739                  &pres_status->info[pres_status->info_cnt].id, 
     740                  pjpidf_tuple_get_id(pidf_tuple)); 
     741 
     742        pj_strdup(pres->dlg->pool,  
     743                  &pres_status->info[pres_status->info_cnt].contact, 
     744                  pjpidf_tuple_get_contact(pidf_tuple)); 
     745 
     746        pidf_status = pjpidf_tuple_get_status(pidf_tuple); 
     747        if (pidf_status) { 
     748            pres_status->info[pres_status->info_cnt].basic_open =  
     749                pjpidf_status_is_basic_open(pidf_status); 
     750        } else { 
     751            pres_status->info[pres_status->info_cnt].basic_open = PJ_FALSE; 
     752        } 
     753 
     754        pidf_tuple = pjpidf_pres_get_next_tuple( pidf, pidf_tuple ); 
     755        pres_status->info_cnt++; 
     756    } 
     757 
     758    return PJ_SUCCESS; 
     759} 
     760 
     761/* 
     762 * Parse XPIDF info. 
     763 */ 
     764static pj_status_t pres_parse_xpidf( pjsip_pres *pres, 
     765                                     pjsip_rx_data *rdata, 
     766                                     pjsip_pres_status *pres_status) 
     767{ 
     768    pjxpidf_pres *xpidf; 
     769 
     770    xpidf = pjxpidf_parse(rdata->tp_info.pool,  
     771                          rdata->msg_info.msg->body->data, 
     772                          rdata->msg_info.msg->body->len); 
     773    if (xpidf == NULL) 
     774        return PJSIP_SIMPLE_EBADXPIDF; 
     775 
     776    pres_status->info_cnt = 1; 
     777     
     778    pj_strdup(pres->dlg->pool, 
     779              &pres_status->info[0].contact, 
     780              pjxpidf_get_uri(xpidf)); 
     781    pres_status->info[0].basic_open = pjxpidf_get_status(xpidf); 
     782    pres_status->info[0].id.slen = 0; 
     783 
     784    return PJ_SUCCESS; 
     785} 
     786 
     787 
     788/* 
     789 * Called when NOTIFY is received. 
     790 */ 
     791static void pres_on_evsub_rx_notify( pjsip_evsub *sub,  
     792                                     pjsip_rx_data *rdata, 
     793                                     int *p_st_code, 
     794                                     pj_str_t **p_st_text, 
     795                                     pjsip_hdr *res_hdr, 
     796                                     pjsip_msg_body **p_body) 
     797{ 
     798    pjsip_ctype_hdr *ctype_hdr; 
     799    pjsip_pres *pres; 
     800    pj_status_t status; 
     801 
     802    pres = pjsip_evsub_get_mod_data(sub, mod_presence.id); 
     803    PJ_ASSERT_ON_FAIL(pres!=NULL, {return;}); 
     804 
     805    /* Check Content-Type and msg body are present. */ 
     806    ctype_hdr = rdata->msg_info.ctype; 
     807 
     808    if (ctype_hdr==NULL || rdata->msg_info.msg->body==NULL) { 
     809         
     810        pjsip_warning_hdr *warn_hdr; 
     811        pj_str_t warn_text; 
     812 
     813        *p_st_code = PJSIP_SC_BAD_REQUEST; 
     814 
     815        warn_text = pj_str("Message body is not present"); 
     816        warn_hdr = pjsip_warning_hdr_create(rdata->tp_info.pool, 399, 
     817                                            pjsip_endpt_name(pres->dlg->endpt), 
     818                                            &warn_text); 
     819        pj_list_push_back(res_hdr, warn_hdr); 
     820 
     821        return; 
     822    } 
     823 
     824    /* Parse content. */ 
     825 
     826    if (pj_stricmp(&ctype_hdr->media.type, &STR_APPLICATION)==0 && 
     827        pj_stricmp(&ctype_hdr->media.subtype, &STR_PIDF_XML)==0) 
     828    { 
     829        status = pres_parse_pidf( pres, rdata, &pres->tmp_status); 
     830    } 
     831    else  
     832    if (pj_stricmp(&ctype_hdr->media.type, &STR_APPLICATION)==0 && 
     833        pj_stricmp(&ctype_hdr->media.subtype, &STR_XPIDF_XML)==0) 
     834    { 
     835        status = pres_parse_pidf( pres, rdata, &pres->tmp_status); 
     836    } 
     837    else 
     838    { 
     839        status = PJSIP_SIMPLE_EBADCONTENT; 
     840    } 
     841 
     842    if (status != PJ_SUCCESS) { 
     843        /* Unsupported or bad Content-Type */ 
     844        pjsip_accept_hdr *accept_hdr; 
     845        pjsip_warning_hdr *warn_hdr; 
     846 
     847        *p_st_code = PJSIP_SC_NOT_ACCEPTABLE_HERE; 
     848 
     849        /* Add Accept header */ 
     850        accept_hdr = pjsip_accept_hdr_create(rdata->tp_info.pool); 
     851        accept_hdr->values[accept_hdr->count++] = STR_APP_PIDF_XML; 
     852        accept_hdr->values[accept_hdr->count++] = STR_APP_XPIDF_XML; 
     853        pj_list_push_back(res_hdr, accept_hdr); 
     854 
     855        /* Add Warning header */ 
     856        warn_hdr = pjsip_warning_hdr_create_from_status( 
     857                                    rdata->tp_info.pool, 
     858                                    pjsip_endpt_name(pres->dlg->endpt), 
     859                                    status); 
     860        pj_list_push_back(res_hdr, warn_hdr); 
     861 
     862        return; 
     863    } 
     864 
     865    /* If application calls pres_get_status(), redirect the call to 
     866     * retrieve the temporary status. 
     867     */ 
     868    pres->tmp_status._is_valid = PJ_TRUE; 
     869 
     870    /* Notify application. */ 
     871    if (pres->user_cb.on_rx_notify) { 
     872        (*pres->user_cb.on_rx_notify)(sub, rdata, p_st_code, p_st_text,  
     873                                      res_hdr, p_body); 
     874    } 
     875 
     876     
     877    /* If application responded NOTIFY with 2xx, copy temporary status 
     878     * to main status, and mark the temporary status as invalid. 
     879     */ 
     880    if ((*p_st_code)/100 == 2) { 
     881        pj_memcpy(&pres->status, &pres->tmp_status, sizeof(pjsip_pres_status)); 
     882    } 
     883 
     884    pres->tmp_status._is_valid = PJ_FALSE; 
     885 
     886    /* Done */ 
     887} 
     888 
     889/* 
     890 * Called when it's time to send SUBSCRIBE. 
     891 */ 
     892static void pres_on_evsub_client_refresh(pjsip_evsub *sub) 
     893{ 
     894    pjsip_pres *pres; 
     895 
     896    pres = pjsip_evsub_get_mod_data(sub, mod_presence.id); 
     897    PJ_ASSERT_ON_FAIL(pres!=NULL, {return;}); 
     898 
     899    if (pres->user_cb.on_client_refresh) { 
     900        (*pres->user_cb.on_client_refresh)(sub); 
     901    } else { 
     902        pj_status_t status; 
     903        pjsip_tx_data *tdata; 
     904 
     905        status = pjsip_pres_initiate(sub, -1, &tdata); 
     906        if (status == PJ_SUCCESS) 
     907            pjsip_pres_send_request(sub, tdata); 
     908    } 
     909} 
     910 
     911/* 
     912 * Called when no refresh is received after the interval. 
     913 */ 
     914static void pres_on_evsub_server_timeout(pjsip_evsub *sub) 
     915{ 
     916    pjsip_pres *pres; 
     917 
     918    pres = pjsip_evsub_get_mod_data(sub, mod_presence.id); 
     919    PJ_ASSERT_ON_FAIL(pres!=NULL, {return;}); 
     920 
     921    if (pres->user_cb.on_server_timeout) { 
     922        (*pres->user_cb.on_server_timeout)(sub); 
     923    } else { 
     924        pj_status_t status; 
     925        pjsip_tx_data *tdata; 
     926        pj_str_t reason = { "timeout", 7 }; 
     927 
     928        status = pjsip_pres_notify(sub, PJSIP_EVSUB_STATE_TERMINATED, 
     929                                   NULL, &reason, &tdata); 
     930        if (status == PJ_SUCCESS) 
     931            pjsip_pres_send_request(sub, tdata); 
     932    } 
     933} 
     934 
Note: See TracChangeset for help on using the changeset viewer.