Changeset 685


Ignore:
Timestamp:
Aug 15, 2006 8:26:34 PM (16 years ago)
Author:
bennylp
Message:

Support for PUBLISH (RFC 3903):

  • API BREAK: pjsua_pres_create_uac() API CHANGED!! Added options in the function, to allow creating SUBSCRIBE without ";id=" parameter in the Event header.
  • the generic event publication in pjsip-simple/publish.[hc]
  • split PIDF and X-PIDF body generation and parsing into pjsip-simple/presence_body.c.
  • allow NULL in module parameter in pjsip_endpt_add_capability()
  • added "--publish" option in PJSUA.
  • by default, PJSUA-LIB will not add ";id=" parameter in Event header in the SUBSCRIBE request since lots of server and user agents don't support this correctly.
  • Set version to 0.5.7.6.
Location:
pjproject/trunk
Files:
1 added
15 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjlib/src/pj/config.c

    r659 r685  
    2222 
    2323static const char *id = "config.c"; 
    24 const char *PJ_VERSION = "0.5.7.1"; 
     24const char *PJ_VERSION = "0.5.7.6"; 
    2525 
    2626PJ_DEF(void) pj_dump_config(void) 
  • pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c

    r683 r685  
    102102    puts  ("  --username=string   Set authentication username"); 
    103103    puts  ("  --password=string   Set authentication password"); 
     104    puts  ("  --publish           Send presence PUBLISH for this account"); 
    104105    puts  ("  --next-cred         Add another credentials"); 
    105106    puts  (""); 
     
    259260           OPT_HELP, OPT_VERSION, OPT_NULL_AUDIO,  
    260261           OPT_LOCAL_PORT, OPT_PROXY, OPT_OUTBOUND_PROXY, OPT_REGISTRAR, 
    261            OPT_REG_TIMEOUT, OPT_ID, OPT_CONTACT,  
     262           OPT_REG_TIMEOUT, OPT_PUBLISH, OPT_ID, OPT_CONTACT,  
    262263           OPT_REALM, OPT_USERNAME, OPT_PASSWORD, 
    263264           OPT_USE_STUN1, OPT_USE_STUN2,  
     
    287288        { "registrar",  1, 0, OPT_REGISTRAR}, 
    288289        { "reg-timeout",1, 0, OPT_REG_TIMEOUT}, 
     290        { "publish",    0, 0, OPT_PUBLISH}, 
    289291        { "id",         1, 0, OPT_ID}, 
    290292        { "contact",    1, 0, OPT_CONTACT}, 
     
    480482            break; 
    481483 
     484        case OPT_PUBLISH:   /* publish */ 
     485            cur_acc->publish_enabled = PJ_TRUE; 
     486            break; 
     487 
    482488        case OPT_ID:   /* id */ 
    483489            if (pjsua_verify_sip_url(pj_optarg) != 0) { 
  • pjproject/trunk/pjsip/build/Makefile

    r604 r685  
    6767export PJSIP_SIMPLE_SRCDIR = ../src/pjsip-simple 
    6868export PJSIP_SIMPLE_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \ 
    69                         errno.o evsub.o evsub_msg.o iscomposing.o pidf.o presence.o \ 
     69                        errno.o evsub.o evsub_msg.o iscomposing.o \ 
     70                        pidf.o presence.o presence_body.o publishc.o \ 
    7071                        xpidf.o 
    7172export PJSIP_SIMPLE_CFLAGS += $(_CFLAGS) 
  • pjproject/trunk/pjsip/build/pjsip_simple.dsp

    r683 r685  
    110110# Begin Source File 
    111111 
     112SOURCE="..\src\pjsip-simple\presence_body.c" 
     113# End Source File 
     114# Begin Source File 
     115 
    112116SOURCE="..\src\pjsip-simple\publishc.c" 
    113117 
     
    115119 
    116120!ELSEIF  "$(CFG)" == "pjsip_simple - Win32 Debug" 
    117  
    118 # PROP Exclude_From_Build 1 
    119121 
    120122!ENDIF  
  • pjproject/trunk/pjsip/include/pjsip-simple/presence.h

    r515 r685  
    104104 * @param user_cb       Pointer to callbacks to receive presence subscription 
    105105 *                      events. 
     106 * @param options       Option flags. Currently only PJSIP_EVSUB_NO_EVENT_ID 
     107 *                      is recognized. 
    106108 * @param p_evsub       Pointer to receive the presence subscription 
    107109 *                      session. 
     
    111113PJ_DECL(pj_status_t) pjsip_pres_create_uac( pjsip_dialog *dlg, 
    112114                                            const pjsip_evsub_user *user_cb, 
     115                                            unsigned options, 
    113116                                            pjsip_evsub **p_evsub ); 
    114117 
     
    266269 
    267270/** 
     271 * This is a utility function to create PIDF message body from PJSIP 
     272 * presence status (pjsip_pres_status). 
     273 * 
     274 * @param pool          The pool to allocate memory for the message body. 
     275 * @param status        Presence status to be converted into PIDF message 
     276 *                      body. 
     277 * @param entity        The entity ID, which normally is equal to the  
     278 *                      presentity ID publishing this presence info. 
     279 * @param p_body        Pointer to receive the SIP message body. 
     280 * 
     281 * @return              PJ_SUCCESS on success. 
     282 */ 
     283PJ_DECL(pj_status_t) pjsip_pres_create_pidf( pj_pool_t *pool, 
     284                                             const pjsip_pres_status *status, 
     285                                             const pj_str_t *entity, 
     286                                             pjsip_msg_body **p_body ); 
     287 
     288 
     289/** 
     290 * This is a utility function to create X-PIDF message body from PJSIP 
     291 * presence status (pjsip_pres_status). 
     292 * 
     293 * @param pool          The pool to allocate memory for the message body. 
     294 * @param status        Presence status to be converted into X-PIDF message 
     295 *                      body. 
     296 * @param entity        The entity ID, which normally is equal to the  
     297 *                      presentity ID publishing this presence info. 
     298 * @param p_body        Pointer to receive the SIP message body. 
     299 * 
     300 * @return              PJ_SUCCESS on success. 
     301 */ 
     302PJ_DECL(pj_status_t) pjsip_pres_create_xpidf(pj_pool_t *pool, 
     303                                             const pjsip_pres_status *status, 
     304                                             const pj_str_t *entity, 
     305                                             pjsip_msg_body **p_body ); 
     306 
     307 
     308 
     309/** 
     310 * This is a utility function to parse PIDF body into PJSIP presence status. 
     311 * 
     312 * @param rdata         The incoming SIP message containing the PIDF body. 
     313 * @param pool          Pool to allocate memory to copy the strings into 
     314 *                      the presence status structure. 
     315 * @param status        The presence status to be initialized. 
     316 * 
     317 * @return              PJ_SUCCESS on success. 
     318 */ 
     319PJ_DECL(pj_status_t) pjsip_pres_parse_pidf(pjsip_rx_data *rdata, 
     320                                           pj_pool_t *pool, 
     321                                           pjsip_pres_status *status); 
     322 
     323 
     324 
     325/** 
     326 * This is a utility function to parse X-PIDF body into PJSIP presence status. 
     327 * 
     328 * @param rdata         The incoming SIP message containing the X-PIDF body. 
     329 * @param pool          Pool to allocate memory to copy the strings into 
     330 *                      the presence status structure. 
     331 * @param status        The presence status to be initialized. 
     332 * 
     333 * @return              PJ_SUCCESS on success. 
     334 */ 
     335PJ_DECL(pj_status_t) pjsip_pres_parse_xpidf(pjsip_rx_data *rdata, 
     336                                           pj_pool_t *pool, 
     337                                           pjsip_pres_status *status); 
     338 
     339 
     340 
     341/** 
    268342 * @} 
    269343 */ 
  • pjproject/trunk/pjsip/include/pjsip-simple/publish.h

    r683 r685  
    1717 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
    1818 */ 
    19 #ifndef __PJSIP_SIMPLE_PRESENCE_H__ 
    20 #define __PJSIP_SIMPLE_PRESENCE_H__ 
     19#ifndef __PJSIP_SIMPLE_PUBLISH_H__ 
     20#define __PJSIP_SIMPLE_PUBLISH_H__ 
    2121 
    2222/** 
     
    2424 * @brief SIP Extension for Event State Publication (PUBLISH, RFC 3903) 
    2525 */ 
     26 
     27#include <pjsip/sip_util.h> 
    2628 
    2729 
     
    3840 Extension for Event State Publication (PUBLISH) as defined by RFC 3856. 
    3941 */ 
     42 
     43/** 
     44 * The SIP PUBLISH method constant. 
     45 */ 
     46extern const pjsip_method pjsip_publish_method; 
    4047 
    4148 
     
    7885 
    7986 
     87/** 
     88 * Initialize client publication module. 
     89 * 
     90 * @param endpt     SIP endpoint. 
     91 * 
     92 * @return          PJ_SUCCESS on success. 
     93 */ 
     94PJ_DECL(pj_status_t) pjsip_publishc_init_module(pjsip_endpoint *endpt); 
     95 
     96 
    8097 
    8198/** 
     
    83100 * 
    84101 * @param endpt     Endpoint, used to allocate pool from. 
     102 * @param options   Option flags. 
    85103 * @param token     Opaque data to be associated with the client publication. 
    86104 * @param cb        Pointer to callback function to receive publication status. 
     
    90108 */ 
    91109PJ_DECL(pj_status_t) pjsip_publishc_create( pjsip_endpoint *endpt,  
     110                                            unsigned options, 
    92111                                            void *token, 
    93112                                            pjsip_publishc_cb *cb,  
     
    249268 
    250269 
    251 #endif  /* __PJSIP_SIMPLE_PRESENCE_H__ */ 
    252  
     270#endif  /* __PJSIP_SIMPLE_PUBLISH_H__ */ 
     271 
  • pjproject/trunk/pjsip/include/pjsip_simple.h

    r515 r685  
    3939#include <pjsip-simple/presence.h> 
    4040#include <pjsip-simple/pidf.h> 
     41#include <pjsip-simple/publish.h> 
    4142#include <pjsip-simple/xpidf.h> 
    4243 
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h

    r683 r685  
    10041004 
    10051005/** 
     1006 * Default PUBLISH expiration 
     1007 */ 
     1008#ifndef PJSUA_PUBLISH_EXPIRATION 
     1009#   define PJSUA_PUBLISH_EXPIRATION 600 
     1010#endif 
     1011 
     1012 
     1013/** 
    10061014 * Account configuration. 
    10071015 */ 
     
    10241032     */ 
    10251033    pj_str_t        reg_uri; 
     1034 
     1035    /** 
     1036     * Publish presence? 
     1037     */ 
     1038    pj_bool_t       publish_enabled; 
    10261039 
    10271040    /**  
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h

    r648 r685  
    9898    pj_bool_t        online_status; /**< Our online status.             */ 
    9999    pjsua_srv_pres   pres_srv_list; /**< Server subscription list.      */ 
     100    pjsip_publishc  *publish_sess;  /**< Client publication session.    */ 
     101    pj_bool_t        publish_state; /**< Last published online status   */ 
    100102 
    101103} pjsua_acc; 
     
    256258 
    257259 
     260#if 0 
    258261#define PJSUA_LOCK()        pj_mutex_lock(pjsua_var.mutex); 
    259262#define PJSUA_UNLOCK()      pj_mutex_unlock(pjsua_var.mutex); 
     263#else 
     264#define PJSUA_LOCK() 
     265#define PJSUA_UNLOCK() 
     266#endif 
    260267 
    261268 
     
    285292 */ 
    286293void pjsua_pres_shutdown(void); 
     294 
     295/** 
     296 * Init presence for aoocunt. 
     297 */ 
     298pj_status_t pjsua_pres_init_acc(int acc_id); 
    287299 
    288300/** 
  • pjproject/trunk/pjsip/src/pjsip-simple/presence.c

    r519 r685  
    180180PJ_DEF(pj_status_t) pjsip_pres_create_uac( pjsip_dialog *dlg, 
    181181                                           const pjsip_evsub_user *user_cb, 
     182                                           unsigned options, 
    182183                                           pjsip_evsub **p_evsub ) 
    183184{ 
     
    191192 
    192193    /* Create event subscription */ 
    193     status = pjsip_evsub_create_uac( dlg,  &pres_user, &STR_PRESENCE, 0, &sub); 
     194    status = pjsip_evsub_create_uac( dlg,  &pres_user, &STR_PRESENCE,  
     195                                     options, &sub); 
    194196    if (status != PJ_SUCCESS) 
    195197        goto on_return; 
     
    413415 
    414416/* 
    415  * Create PIDF document based on the presence info. 
    416  */ 
    417 static pjpidf_pres* pres_create_pidf( pj_pool_t *pool, 
    418                                       pjsip_pres *pres ) 
    419 { 
    420     pjpidf_pres *pidf; 
    421     unsigned i; 
     417 * Create message body. 
     418 */ 
     419static pj_status_t pres_create_msg_body( pjsip_pres *pres,  
     420                                         pjsip_tx_data *tdata) 
     421{ 
    422422    pj_str_t entity; 
    423423 
    424424    /* Get publisher URI */ 
    425     entity.ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE); 
     425    entity.ptr = pj_pool_alloc(tdata->pool, PJSIP_MAX_URL_SIZE); 
    426426    entity.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, 
    427427                                  pres->dlg->local.info->uri, 
    428428                                  entity.ptr, PJSIP_MAX_URL_SIZE); 
    429429    if (entity.slen < 1) 
    430         return NULL; 
    431  
    432     /* Create <presence>. */ 
    433     pidf = pjpidf_create(pool, &entity); 
    434  
    435     /* Create <tuple> */ 
    436     for (i=0; i<pres->status.info_cnt; ++i) { 
    437  
    438         pjpidf_tuple *pidf_tuple; 
    439         pjpidf_status *pidf_status; 
    440  
    441         /* Add tuple id. */ 
    442         pidf_tuple = pjpidf_pres_add_tuple(pool, pidf,  
    443                                            &pres->status.info[i].id); 
    444  
    445         /* Set <contact> */ 
    446         if (pres->status.info[i].contact.slen) 
    447             pjpidf_tuple_set_contact(pool, pidf_tuple,  
    448                                      &pres->status.info[i].contact); 
    449  
    450  
    451         /* Set basic status */ 
    452         pidf_status = pjpidf_tuple_get_status(pidf_tuple); 
    453         pjpidf_status_set_basic_open(pidf_status,  
    454                                      pres->status.info[i].basic_open); 
    455     } 
    456  
    457     return pidf; 
    458 } 
    459  
    460  
    461 /* 
    462  * Create XPIDF document based on the presence info. 
    463  */ 
    464 static pjxpidf_pres* pres_create_xpidf( pj_pool_t *pool, 
    465                                         pjsip_pres *pres ) 
    466 { 
    467     /* Note: PJSIP implementation of XPIDF is not complete! 
    468      */ 
    469     pjxpidf_pres *xpidf; 
    470     pj_str_t publisher_uri; 
    471  
    472     PJ_LOG(4,(THIS_FILE, "Warning: XPIDF format is not fully supported " 
    473                          "by PJSIP")); 
    474  
    475     publisher_uri.ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE); 
    476     publisher_uri.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, 
    477                                          pres->dlg->local.info->uri, 
    478                                          publisher_uri.ptr, 
    479                                          PJSIP_MAX_URL_SIZE); 
    480     if (publisher_uri.slen < 1) 
    481         return NULL; 
    482  
    483     /* Create XPIDF document. */ 
    484     xpidf = pjxpidf_create(pool, &publisher_uri); 
    485  
    486     /* Set basic status. */ 
    487     if (pres->status.info_cnt > 0) 
    488         pjxpidf_set_status( xpidf, pres->status.info[0].basic_open); 
    489     else 
    490         pjxpidf_set_status( xpidf, PJ_FALSE); 
    491  
    492     return xpidf; 
    493 } 
    494  
    495  
    496 /* 
    497  * Function to print XML message body. 
    498  */ 
    499 static int pres_print_body(struct pjsip_msg_body *msg_body,  
    500                            char *buf, pj_size_t size) 
    501 { 
    502     return pj_xml_print(msg_body->data, buf, size, PJ_TRUE); 
    503 } 
    504  
    505  
    506 /* 
    507  * Function to clone XML document. 
    508  */ 
    509 static void* xml_clone_data(pj_pool_t *pool, const void *data, unsigned len) 
    510 { 
    511     PJ_UNUSED_ARG(len); 
    512     return pj_xml_clone( pool, data); 
    513 } 
    514  
    515  
    516 /* 
    517  * Create message body. 
    518  */ 
    519 static pj_status_t pres_create_msg_body( pjsip_pres *pres,  
    520                                          pjsip_tx_data *tdata) 
    521 { 
    522     pjsip_msg_body *body; 
    523  
    524     body = pj_pool_zalloc(tdata->pool, sizeof(pjsip_msg_body)); 
    525      
     430        return PJ_ENOMEM; 
     431 
    526432    if (pres->content_type == CONTENT_TYPE_PIDF) { 
    527433 
    528         body->data = pres_create_pidf(tdata->pool, pres); 
    529         body->content_type.type = pj_str("application"); 
    530         body->content_type.subtype = pj_str("pidf+xml"); 
     434        return pjsip_pres_create_pidf(tdata->pool, &pres->status, 
     435                                      &entity, &tdata->msg->body); 
    531436 
    532437    } else if (pres->content_type == CONTENT_TYPE_XPIDF) { 
    533438 
    534         body->data = pres_create_xpidf(tdata->pool, pres); 
    535         body->content_type.type = pj_str("application"); 
    536         body->content_type.subtype = pj_str("xpidf+xml"); 
     439        return pjsip_pres_create_xpidf(tdata->pool, &pres->status, 
     440                                       &entity, &tdata->msg->body); 
    537441 
    538442    } else { 
    539443        return PJSIP_SIMPLE_EBADCONTENT; 
    540444    } 
    541  
    542  
    543     body->print_body = &pres_print_body; 
    544     body->clone_data = &xml_clone_data; 
    545  
    546     tdata->msg->body = body; 
    547  
    548     return PJ_SUCCESS; 
    549445} 
    550446 
     
    723619} 
    724620 
    725 /* 
    726  * Parse PIDF to info. 
    727  */ 
    728 static pj_status_t pres_parse_pidf( pjsip_pres *pres, 
    729                                     pjsip_rx_data *rdata, 
    730                                     pjsip_pres_status *pres_status) 
    731 { 
    732     pjpidf_pres *pidf; 
    733     pjpidf_tuple *pidf_tuple; 
    734  
    735     pidf = pjpidf_parse(rdata->tp_info.pool,  
    736                         rdata->msg_info.msg->body->data, 
    737                         rdata->msg_info.msg->body->len); 
    738     if (pidf == NULL) 
    739         return PJSIP_SIMPLE_EBADPIDF; 
    740  
    741     pres_status->info_cnt = 0; 
    742  
    743     pidf_tuple = pjpidf_pres_get_first_tuple(pidf); 
    744     while (pidf_tuple) { 
    745         pjpidf_status *pidf_status; 
    746  
    747         pj_strdup(pres->dlg->pool,  
    748                   &pres_status->info[pres_status->info_cnt].id, 
    749                   pjpidf_tuple_get_id(pidf_tuple)); 
    750  
    751         pj_strdup(pres->dlg->pool,  
    752                   &pres_status->info[pres_status->info_cnt].contact, 
    753                   pjpidf_tuple_get_contact(pidf_tuple)); 
    754  
    755         pidf_status = pjpidf_tuple_get_status(pidf_tuple); 
    756         if (pidf_status) { 
    757             pres_status->info[pres_status->info_cnt].basic_open =  
    758                 pjpidf_status_is_basic_open(pidf_status); 
    759         } else { 
    760             pres_status->info[pres_status->info_cnt].basic_open = PJ_FALSE; 
    761         } 
    762  
    763         pidf_tuple = pjpidf_pres_get_next_tuple( pidf, pidf_tuple ); 
    764         pres_status->info_cnt++; 
    765     } 
    766  
    767     return PJ_SUCCESS; 
    768 } 
    769  
    770 /* 
    771  * Parse XPIDF info. 
    772  */ 
    773 static pj_status_t pres_parse_xpidf( pjsip_pres *pres, 
    774                                      pjsip_rx_data *rdata, 
    775                                      pjsip_pres_status *pres_status) 
    776 { 
    777     pjxpidf_pres *xpidf; 
    778  
    779     xpidf = pjxpidf_parse(rdata->tp_info.pool,  
    780                           rdata->msg_info.msg->body->data, 
    781                           rdata->msg_info.msg->body->len); 
    782     if (xpidf == NULL) 
    783         return PJSIP_SIMPLE_EBADXPIDF; 
    784  
    785     pres_status->info_cnt = 1; 
    786      
    787     pj_strdup(pres->dlg->pool, 
    788               &pres_status->info[0].contact, 
    789               pjxpidf_get_uri(xpidf)); 
    790     pres_status->info[0].basic_open = pjxpidf_get_status(xpidf); 
    791     pres_status->info[0].id.slen = 0; 
    792  
    793     return PJ_SUCCESS; 
    794 } 
    795  
    796621 
    797622/* 
     
    837662        pj_stricmp(&ctype_hdr->media.subtype, &STR_PIDF_XML)==0) 
    838663    { 
    839         status = pres_parse_pidf( pres, rdata, &pres->tmp_status); 
     664        status = pjsip_pres_parse_pidf( rdata, pres->dlg->pool, 
     665                                        &pres->tmp_status); 
    840666    } 
    841667    else  
     
    843669        pj_stricmp(&ctype_hdr->media.subtype, &STR_XPIDF_XML)==0) 
    844670    { 
    845         status = pres_parse_xpidf( pres, rdata, &pres->tmp_status); 
     671        status = pjsip_pres_parse_xpidf( rdata, pres->dlg->pool, 
     672                                         &pres->tmp_status); 
    846673    } 
    847674    else 
  • pjproject/trunk/pjsip/src/pjsip-simple/publishc.c

    r683 r685  
    1717 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
    1818 */ 
    19 #include <pjsip-ua/sip_regc.h> 
     19#include <pjsip-simple/publish.h> 
     20#include <pjsip/sip_auth.h> 
    2021#include <pjsip/sip_endpoint.h> 
    21 #include <pjsip/sip_parser.h> 
    22 #include <pjsip/sip_module.h> 
     22#include <pjsip/sip_errno.h> 
     23#include <pjsip/sip_event.h> 
     24#include <pjsip/sip_msg.h> 
    2325#include <pjsip/sip_transaction.h> 
    24 #include <pjsip/sip_event.h> 
     26#include <pjsip/sip_uri.h> 
    2527#include <pjsip/sip_util.h> 
    26 #include <pjsip/sip_auth_msg.h> 
    27 #include <pjsip/sip_errno.h> 
    2828#include <pj/assert.h> 
    2929#include <pj/guid.h> 
     30#include <pj/log.h> 
    3031#include <pj/os.h> 
    3132#include <pj/pool.h> 
    32 #include <pj/log.h> 
    3333#include <pj/rand.h> 
    3434#include <pj/string.h> 
     35#include <pj/timer.h> 
    3536 
    3637 
    3738#define REFRESH_TIMER           1 
    3839#define DELAY_BEFORE_REFRESH    5 
    39 #define THIS_FILE               "sip_regc.c" 
     40#define THIS_FILE               "publishc.c" 
     41 
     42 
     43const pjsip_method pjsip_publish_method =  
     44{ 
     45    PJSIP_OTHER_METHOD, 
     46    { "PUBLISH", 7 } 
     47}; 
     48 
    4049 
    4150/** 
    42  * SIP client registration structure. 
     51 * SIP client publication structure. 
    4352 */ 
    44 struct pjsip_regc 
     53struct pjsip_publishc 
    4554{ 
    4655    pj_pool_t                   *pool; 
     
    5059 
    5160    void                        *token; 
    52     pjsip_regc_cb               *cb; 
    53  
    54     pj_str_t                     str_srv_url; 
    55     pjsip_uri                   *srv_url; 
     61    pjsip_publishc_cb           *cb; 
     62 
     63    pj_str_t                     event; 
     64    pj_str_t                     str_target_uri; 
     65    pjsip_uri                   *target_uri; 
    5666    pjsip_cid_hdr               *cid_hdr; 
    5767    pjsip_cseq_hdr              *cseq_hdr; 
     
    5969    pjsip_from_hdr              *from_hdr; 
    6070    pjsip_to_hdr                *to_hdr; 
    61     char                        *contact_buf; 
    62     pjsip_generic_string_hdr    *contact_hdr; 
     71    pj_str_t                     etag; 
    6372    pjsip_expires_hdr           *expires_hdr; 
    64     pjsip_contact_hdr           *unreg_contact_hdr; 
    65     pjsip_expires_hdr           *unreg_expires_hdr; 
    6673    pj_uint32_t                  expires; 
    6774    pjsip_route_hdr              route_set; 
     
    7077    pjsip_auth_clt_sess          auth_sess; 
    7178 
    72     /* Auto refresh registration. */ 
    73     pj_bool_t                    auto_reg; 
    74     pj_time_val                  last_reg; 
    75     pj_time_val                  next_reg; 
     79    /* Auto refresh publication. */ 
     80    pj_bool_t                    auto_refresh; 
     81    pj_time_val                  last_refresh; 
     82    pj_time_val                  next_refresh; 
    7683    pj_timer_entry               timer; 
    7784}; 
     
    7986 
    8087 
    81 PJ_DEF(pj_status_t) pjsip_regc_create( pjsip_endpoint *endpt, void *token, 
    82                                        pjsip_regc_cb *cb, 
    83                                        pjsip_regc **p_regc) 
     88/* 
     89 * Initialize client publication module. 
     90 */ 
     91PJ_DEF(pj_status_t) pjsip_publishc_init_module(pjsip_endpoint *endpt) 
     92{ 
     93    return pjsip_endpt_add_capability( endpt, NULL, PJSIP_H_ALLOW, NULL, 
     94                                       1, &pjsip_publish_method.name); 
     95} 
     96 
     97 
     98PJ_DEF(pj_status_t) pjsip_publishc_create( pjsip_endpoint *endpt,  
     99                                           unsigned options, 
     100                                           void *token, 
     101                                           pjsip_publishc_cb *cb,        
     102                                           pjsip_publishc **p_pubc) 
    84103{ 
    85104    pj_pool_t *pool; 
    86     pjsip_regc *regc; 
     105    pjsip_publishc *pubc; 
    87106    pj_status_t status; 
    88107 
    89108    /* Verify arguments. */ 
    90     PJ_ASSERT_RETURN(endpt && cb && p_regc, PJ_EINVAL); 
    91  
    92     pool = pjsip_endpt_create_pool(endpt, "regc%p", 1024, 1024); 
     109    PJ_ASSERT_RETURN(endpt && cb && p_pubc, PJ_EINVAL); 
     110    PJ_ASSERT_RETURN(options == 0, PJ_EINVAL); 
     111 
     112    PJ_UNUSED_ARG(options); 
     113 
     114    pool = pjsip_endpt_create_pool(endpt, "pubc%p", 1024, 1024); 
    93115    PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM); 
    94116 
    95     regc = pj_pool_zalloc(pool, sizeof(struct pjsip_regc)); 
    96  
    97     regc->pool = pool; 
    98     regc->endpt = endpt; 
    99     regc->token = token; 
    100     regc->cb = cb; 
    101     regc->contact_buf = pj_pool_alloc(pool, PJSIP_REGC_CONTACT_BUF_SIZE); 
    102     regc->expires = PJSIP_REGC_EXPIRATION_NOT_SPECIFIED; 
    103  
    104     status = pjsip_auth_clt_init(&regc->auth_sess, endpt, regc->pool, 0); 
     117    pubc = pj_pool_zalloc(pool, sizeof(struct pjsip_publishc)); 
     118 
     119    pubc->pool = pool; 
     120    pubc->endpt = endpt; 
     121    pubc->token = token; 
     122    pubc->cb = cb; 
     123    pubc->expires = PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED; 
     124 
     125    status = pjsip_auth_clt_init(&pubc->auth_sess, endpt, pubc->pool, 0); 
    105126    if (status != PJ_SUCCESS) 
    106127        return status; 
    107128 
    108     pj_list_init(&regc->route_set); 
     129    pj_list_init(&pubc->route_set); 
    109130 
    110131    /* Done */ 
    111     *p_regc = regc; 
    112     return PJ_SUCCESS; 
    113 } 
    114  
    115  
    116 PJ_DEF(pj_status_t) pjsip_regc_destroy(pjsip_regc *regc) 
    117 { 
    118     PJ_ASSERT_RETURN(regc, PJ_EINVAL); 
    119  
    120     if (regc->pending_tsx) { 
    121         regc->_delete_flag = 1; 
    122         regc->cb = NULL; 
     132    *p_pubc = pubc; 
     133    return PJ_SUCCESS; 
     134} 
     135 
     136 
     137PJ_DEF(pj_status_t) pjsip_publishc_destroy(pjsip_publishc *pubc) 
     138{ 
     139    PJ_ASSERT_RETURN(pubc, PJ_EINVAL); 
     140 
     141    if (pubc->pending_tsx) { 
     142        pubc->_delete_flag = 1; 
     143        pubc->cb = NULL; 
    123144    } else { 
    124         pjsip_endpt_release_pool(regc->endpt, regc->pool); 
    125     } 
    126  
    127     return PJ_SUCCESS; 
    128 } 
    129  
    130  
    131 PJ_DEF(pj_status_t) pjsip_regc_get_info( pjsip_regc *regc, 
    132                                          pjsip_regc_info *info ) 
    133 { 
    134     PJ_ASSERT_RETURN(regc && info, PJ_EINVAL); 
    135  
    136     info->server_uri = regc->str_srv_url; 
    137     info->client_uri = regc->from_uri; 
    138     info->is_busy = (regc->pending_tsx != 0); 
    139     info->auto_reg = regc->auto_reg; 
    140     info->interval = regc->expires; 
    141      
    142     if (regc->pending_tsx) 
    143         info->next_reg = 0; 
    144     else if (regc->auto_reg == 0) 
    145         info->next_reg = 0; 
    146     else if (regc->expires < 0) 
    147         info->next_reg = regc->expires; 
    148     else { 
    149         pj_time_val now, next_reg; 
    150  
    151         next_reg = regc->next_reg; 
    152         pj_gettimeofday(&now); 
    153         PJ_TIME_VAL_SUB(next_reg, now); 
    154         info->next_reg = next_reg.sec; 
    155     } 
    156  
    157     return PJ_SUCCESS; 
    158 } 
    159  
    160  
    161 PJ_DEF(pj_pool_t*) pjsip_regc_get_pool(pjsip_regc *regc) 
    162 { 
    163     return regc->pool; 
    164 } 
    165  
    166 static void set_expires( pjsip_regc *regc, pj_uint32_t expires) 
    167 { 
    168     if (expires != regc->expires) { 
    169         regc->expires_hdr = pjsip_expires_hdr_create(regc->pool, expires); 
     145        pjsip_endpt_release_pool(pubc->endpt, pubc->pool); 
     146    } 
     147 
     148    return PJ_SUCCESS; 
     149} 
     150 
     151 
     152PJ_DEF(pj_pool_t*) pjsip_publishc_get_pool(pjsip_publishc *pubc) 
     153{ 
     154    return pubc->pool; 
     155} 
     156 
     157static void set_expires( pjsip_publishc *pubc, pj_uint32_t expires) 
     158{ 
     159    if (expires != pubc->expires) { 
     160        pubc->expires_hdr = pjsip_expires_hdr_create(pubc->pool, expires); 
    170161    } else { 
    171         regc->expires_hdr = NULL; 
    172     } 
    173 } 
    174  
    175  
    176 static pj_status_t set_contact( pjsip_regc *regc, 
    177                                 int contact_cnt, 
    178                                 const pj_str_t contact[] ) 
    179 { 
    180     int i; 
    181     char *s; 
    182     const pj_str_t contact_STR = { "Contact", 7}; 
    183  
    184     /* Concatenate contacts. */ 
    185     for (i=0, s=regc->contact_buf; i<contact_cnt; ++i) { 
    186         if ((s-regc->contact_buf) + contact[i].slen + 2 > PJSIP_REGC_CONTACT_BUF_SIZE) { 
    187             return PJSIP_EURITOOLONG; 
    188         } 
    189         pj_memcpy(s, contact[i].ptr, contact[i].slen); 
    190         s += contact[i].slen; 
    191  
    192         if (i != contact_cnt - 1) { 
    193             *s++ = ','; 
    194             *s++ = ' '; 
    195         } 
    196     } 
    197  
    198     /* Set "Contact" header. */ 
    199     regc->contact_hdr = pjsip_generic_string_hdr_create(regc->pool,  
    200                                                         &contact_STR, 
    201                                                         NULL); 
    202     regc->contact_hdr->hvalue.ptr = regc->contact_buf; 
    203     regc->contact_hdr->hvalue.slen = (s - regc->contact_buf); 
    204  
    205     return PJ_SUCCESS; 
    206 } 
    207  
    208  
    209 PJ_DEF(pj_status_t) pjsip_regc_init( pjsip_regc *regc, 
    210                                      const pj_str_t *srv_url, 
    211                                      const pj_str_t *from_url, 
    212                                      const pj_str_t *to_url, 
    213                                      int contact_cnt, 
    214                                      const pj_str_t contact[], 
    215                                      pj_uint32_t expires) 
     162        pubc->expires_hdr = NULL; 
     163    } 
     164} 
     165 
     166 
     167PJ_DEF(pj_status_t) pjsip_publishc_init(pjsip_publishc *pubc, 
     168                                        const pj_str_t *event, 
     169                                        const pj_str_t *target_uri, 
     170                                        const pj_str_t *from_uri, 
     171                                        const pj_str_t *to_uri, 
     172                                        pj_uint32_t expires) 
    216173{ 
    217174    pj_str_t tmp; 
    218     pj_status_t status; 
    219  
    220     PJ_ASSERT_RETURN(regc && srv_url && from_url && to_url &&  
    221                      contact_cnt && contact && expires, PJ_EINVAL); 
     175 
     176    PJ_ASSERT_RETURN(pubc && event && target_uri && from_uri && to_uri &&  
     177                     expires, PJ_EINVAL); 
     178 
     179    /* Copy event type */ 
     180    pj_strdup_with_null(pubc->pool, &pubc->event, event); 
    222181 
    223182    /* Copy server URL. */ 
    224     pj_strdup_with_null(regc->pool, &regc->str_srv_url, srv_url); 
     183    pj_strdup_with_null(pubc->pool, &pubc->str_target_uri, target_uri); 
    225184 
    226185    /* Set server URL. */ 
    227     tmp = regc->str_srv_url; 
    228     regc->srv_url = pjsip_parse_uri( regc->pool, tmp.ptr, tmp.slen, 0); 
    229     if (regc->srv_url == NULL) { 
     186    tmp = pubc->str_target_uri; 
     187    pubc->target_uri = pjsip_parse_uri( pubc->pool, tmp.ptr, tmp.slen, 0); 
     188    if (pubc->target_uri == NULL) { 
    230189        return PJSIP_EINVALIDURI; 
    231190    } 
    232191 
    233192    /* Set "From" header. */ 
    234     pj_strdup_with_null(regc->pool, &regc->from_uri, from_url); 
    235     tmp = regc->from_uri; 
    236     regc->from_hdr = pjsip_from_hdr_create(regc->pool); 
    237     regc->from_hdr->uri = pjsip_parse_uri(regc->pool, tmp.ptr, tmp.slen,  
     193    pj_strdup_with_null(pubc->pool, &pubc->from_uri, from_uri); 
     194    tmp = pubc->from_uri; 
     195    pubc->from_hdr = pjsip_from_hdr_create(pubc->pool); 
     196    pubc->from_hdr->uri = pjsip_parse_uri(pubc->pool, tmp.ptr, tmp.slen,  
    238197                                          PJSIP_PARSE_URI_AS_NAMEADDR); 
    239     if (!regc->from_hdr->uri) { 
    240         PJ_LOG(4,(THIS_FILE, "regc: invalid source URI %.*s",  
    241                   from_url->slen, from_url->ptr)); 
     198    if (!pubc->from_hdr->uri) { 
    242199        return PJSIP_EINVALIDURI; 
    243200    } 
    244201 
    245202    /* Set "To" header. */ 
    246     pj_strdup_with_null(regc->pool, &tmp, to_url); 
    247     regc->to_hdr = pjsip_to_hdr_create(regc->pool); 
    248     regc->to_hdr->uri = pjsip_parse_uri(regc->pool, tmp.ptr, tmp.slen,  
     203    pj_strdup_with_null(pubc->pool, &tmp, to_uri); 
     204    pubc->to_hdr = pjsip_to_hdr_create(pubc->pool); 
     205    pubc->to_hdr->uri = pjsip_parse_uri(pubc->pool, tmp.ptr, tmp.slen,  
    249206                                        PJSIP_PARSE_URI_AS_NAMEADDR); 
    250     if (!regc->to_hdr->uri) { 
    251         PJ_LOG(4,(THIS_FILE, "regc: invalid target URI %.*s", to_url->slen, to_url->ptr)); 
     207    if (!pubc->to_hdr->uri) { 
    252208        return PJSIP_EINVALIDURI; 
    253209    } 
    254210 
    255211 
    256     /* Set "Contact" header. */ 
    257     status = set_contact( regc, contact_cnt, contact); 
    258     if (status != PJ_SUCCESS) 
    259         return status; 
    260  
    261212    /* Set "Expires" header, if required. */ 
    262     set_expires( regc, expires); 
     213    set_expires( pubc, expires); 
    263214 
    264215    /* Set "Call-ID" header. */ 
    265     regc->cid_hdr = pjsip_cid_hdr_create(regc->pool); 
    266     pj_create_unique_string(regc->pool, &regc->cid_hdr->id); 
     216    pubc->cid_hdr = pjsip_cid_hdr_create(pubc->pool); 
     217    pj_create_unique_string(pubc->pool, &pubc->cid_hdr->id); 
    267218 
    268219    /* Set "CSeq" header. */ 
    269     regc->cseq_hdr = pjsip_cseq_hdr_create(regc->pool); 
    270     regc->cseq_hdr->cseq = pj_rand() % 0xFFFF; 
    271     pjsip_method_set( &regc->cseq_hdr->method, PJSIP_REGISTER_METHOD); 
    272  
    273     /* Create "Contact" header used in unregistration. */ 
    274     regc->unreg_contact_hdr = pjsip_contact_hdr_create(regc->pool); 
    275     regc->unreg_contact_hdr->star = 1; 
    276  
    277     /* Create "Expires" header used in unregistration. */ 
    278     regc->unreg_expires_hdr = pjsip_expires_hdr_create( regc->pool, 0); 
     220    pubc->cseq_hdr = pjsip_cseq_hdr_create(pubc->pool); 
     221    pubc->cseq_hdr->cseq = pj_rand() % 0xFFFF; 
     222    pjsip_method_set( &pubc->cseq_hdr->method, PJSIP_REGISTER_METHOD); 
    279223 
    280224    /* Done. */ 
     
    282226} 
    283227 
    284 PJ_DEF(pj_status_t) pjsip_regc_set_credentials( pjsip_regc *regc, 
     228PJ_DEF(pj_status_t) pjsip_publishc_set_credentials( pjsip_publishc *pubc, 
    285229                                                int count, 
    286230                                                const pjsip_cred_info cred[] ) 
    287231{ 
    288     PJ_ASSERT_RETURN(regc && count && cred, PJ_EINVAL); 
    289     return pjsip_auth_clt_set_credentials(&regc->auth_sess, count, cred); 
    290 } 
    291  
    292 PJ_DEF(pj_status_t) pjsip_regc_set_route_set( pjsip_regc *regc, 
     232    PJ_ASSERT_RETURN(pubc && count && cred, PJ_EINVAL); 
     233    return pjsip_auth_clt_set_credentials(&pubc->auth_sess, count, cred); 
     234} 
     235 
     236PJ_DEF(pj_status_t) pjsip_publishc_set_route_set( pjsip_publishc *pubc, 
    293237                                              const pjsip_route_hdr *route_set) 
    294238{ 
    295239    const pjsip_route_hdr *chdr; 
    296240 
    297     PJ_ASSERT_RETURN(regc && route_set, PJ_EINVAL); 
    298  
    299     pj_list_init(&regc->route_set); 
     241    PJ_ASSERT_RETURN(pubc && route_set, PJ_EINVAL); 
     242 
     243    pj_list_init(&pubc->route_set); 
    300244 
    301245    chdr = route_set->next; 
    302246    while (chdr != route_set) { 
    303         pj_list_push_back(&regc->route_set, pjsip_hdr_clone(regc->pool, chdr)); 
     247        pj_list_push_back(&pubc->route_set, pjsip_hdr_clone(pubc->pool, chdr)); 
    304248        chdr = chdr->next; 
    305249    } 
     
    308252} 
    309253 
    310 static pj_status_t create_request(pjsip_regc *regc,  
     254static pj_status_t create_request(pjsip_publishc *pubc,  
    311255                                  pjsip_tx_data **p_tdata) 
    312256{ 
    313     pj_status_t status; 
     257    const pj_str_t STR_EVENT = { "Event", 5 }; 
     258    pj_status_t status; 
     259    pjsip_generic_string_hdr *hdr; 
    314260    pjsip_tx_data *tdata; 
    315261 
    316     PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL); 
     262    PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL); 
    317263 
    318264    /* Create the request. */ 
    319     status = pjsip_endpt_create_request_from_hdr( regc->endpt,  
    320                                                   &pjsip_register_method, 
    321                                                   regc->srv_url, 
    322                                                   regc->from_hdr, 
    323                                                   regc->to_hdr, 
     265    status = pjsip_endpt_create_request_from_hdr( pubc->endpt,  
     266                                                  &pjsip_publish_method, 
     267                                                  pubc->target_uri, 
     268                                                  pubc->from_hdr, 
     269                                                  pubc->to_hdr, 
    324270                                                  NULL, 
    325                                                   regc->cid_hdr, 
    326                                                   regc->cseq_hdr->cseq, 
     271                                                  pubc->cid_hdr, 
     272                                                  pubc->cseq_hdr->cseq, 
    327273                                                  NULL, 
    328274                                                  &tdata); 
     
    331277 
    332278    /* Add cached authorization headers. */ 
    333     pjsip_auth_clt_init_req( &regc->auth_sess, tdata ); 
     279    pjsip_auth_clt_init_req( &pubc->auth_sess, tdata ); 
    334280 
    335281    /* Add Route headers from route set, ideally after Via header */ 
    336     if (!pj_list_empty(&regc->route_set)) { 
     282    if (!pj_list_empty(&pubc->route_set)) { 
    337283        pjsip_hdr *route_pos; 
    338284        const pjsip_route_hdr *route; 
     
    342288            route_pos = &tdata->msg->hdr; 
    343289 
    344         route = regc->route_set.next; 
    345         while (route != &regc->route_set) { 
     290        route = pubc->route_set.next; 
     291        while (route != &pubc->route_set) { 
    346292            pjsip_hdr *new_hdr = pjsip_hdr_shallow_clone(tdata->pool, route); 
    347293            pj_list_insert_after(route_pos, new_hdr); 
     
    351297    } 
    352298 
     299    /* Add Event header */ 
     300    hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_EVENT, 
     301                                          &pubc->event); 
     302    if (hdr) 
     303        pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr); 
     304 
     305 
     306    /* Add SIP-If-Match if we have etag */ 
     307    if (pubc->etag.slen) { 
     308        const pj_str_t STR_HNAME = { "SIP-If-Match", 12 }; 
     309 
     310        hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_HNAME, 
     311                                              &pubc->etag); 
     312        if (hdr) 
     313            pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr); 
     314    } 
     315 
     316 
    353317    /* Done. */ 
    354318    *p_tdata = tdata; 
     
    357321 
    358322 
    359 PJ_DEF(pj_status_t) pjsip_regc_register(pjsip_regc *regc, pj_bool_t autoreg, 
    360                                         pjsip_tx_data **p_tdata) 
    361 { 
    362     pjsip_msg *msg; 
     323PJ_DEF(pj_status_t) pjsip_publishc_publish(pjsip_publishc *pubc,  
     324                                           pj_bool_t auto_refresh, 
     325                                           pjsip_tx_data **p_tdata) 
     326{ 
    363327    pj_status_t status; 
    364328    pjsip_tx_data *tdata; 
    365329 
    366     PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL); 
    367  
    368     status = create_request(regc, &tdata); 
     330    PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL); 
     331 
     332    status = create_request(pubc, &tdata); 
    369333    if (status != PJ_SUCCESS) 
    370334        return status; 
    371335 
    372     /* Add Contact header. */ 
    373     msg = tdata->msg; 
    374     pjsip_msg_add_hdr(msg, (pjsip_hdr*) regc->contact_hdr); 
    375     if (regc->expires_hdr) 
    376         pjsip_msg_add_hdr(msg, (pjsip_hdr*) regc->expires_hdr); 
    377  
    378     if (regc->timer.id != 0) { 
    379         pjsip_endpt_cancel_timer(regc->endpt, &regc->timer); 
    380         regc->timer.id = 0; 
    381     } 
    382  
    383     regc->auto_reg = autoreg; 
     336    /* Add Expires header */ 
     337    if (pubc->expires_hdr) { 
     338        pjsip_hdr *dup; 
     339 
     340        dup = pjsip_hdr_shallow_clone(tdata->pool, pubc->expires_hdr); 
     341        if (dup) 
     342            pjsip_msg_add_hdr(tdata->msg, dup); 
     343    } 
     344 
     345    /* Cancel existing timer */ 
     346    if (pubc->timer.id != 0) { 
     347        pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer); 
     348        pubc->timer.id = 0; 
     349    } 
     350 
     351    pubc->auto_refresh = auto_refresh; 
    384352 
    385353    /* Done */ 
     
    389357 
    390358 
    391 PJ_DEF(pj_status_t) pjsip_regc_unregister(pjsip_regc *regc, 
    392                                           pjsip_tx_data **p_tdata) 
     359PJ_DEF(pj_status_t) pjsip_publishc_unpublish(pjsip_publishc *pubc, 
     360                                             pjsip_tx_data **p_tdata) 
    393361{ 
    394362    pjsip_tx_data *tdata; 
    395363    pjsip_msg *msg; 
    396     pj_status_t status; 
    397  
    398     PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL); 
    399  
    400     if (regc->timer.id != 0) { 
    401         pjsip_endpt_cancel_timer(regc->endpt, &regc->timer); 
    402         regc->timer.id = 0; 
    403     } 
    404  
    405     status = create_request(regc, &tdata); 
     364    pjsip_expires_hdr *expires; 
     365    pj_status_t status; 
     366 
     367    PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL); 
     368 
     369    if (pubc->timer.id != 0) { 
     370        pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer); 
     371        pubc->timer.id = 0; 
     372    } 
     373 
     374    status = create_request(pubc, &tdata); 
    406375    if (status != PJ_SUCCESS) 
    407376        return status; 
    408377 
    409378    msg = tdata->msg; 
    410     pjsip_msg_add_hdr( msg, (pjsip_hdr*)regc->unreg_contact_hdr); 
    411     pjsip_msg_add_hdr( msg, (pjsip_hdr*)regc->unreg_expires_hdr); 
     379 
     380    /* Add Expires:0 header */ 
     381    expires = pjsip_expires_hdr_create(tdata->pool, 0); 
     382    pjsip_msg_add_hdr( msg, (pjsip_hdr*)expires); 
    412383 
    413384    *p_tdata = tdata; 
     
    416387 
    417388 
    418 PJ_DEF(pj_status_t) pjsip_regc_update_contact(  pjsip_regc *regc, 
    419                                                 int contact_cnt, 
    420                                                 const pj_str_t contact[] ) 
    421 { 
    422     PJ_ASSERT_RETURN(regc, PJ_EINVAL); 
    423     return set_contact( regc, contact_cnt, contact ); 
    424 } 
    425  
    426  
    427 PJ_DEF(pj_status_t) pjsip_regc_update_expires(  pjsip_regc *regc, 
    428                                                 pj_uint32_t expires ) 
    429 { 
    430     PJ_ASSERT_RETURN(regc, PJ_EINVAL); 
    431     set_expires( regc, expires ); 
    432     return PJ_SUCCESS; 
    433 } 
    434  
    435  
    436 static void call_callback(pjsip_regc *regc, pj_status_t status, int st_code,  
    437                           const pj_str_t *reason, 
    438                           pjsip_rx_data *rdata, pj_int32_t expiration, 
    439                           int contact_cnt, pjsip_contact_hdr *contact[]) 
    440 { 
    441     struct pjsip_regc_cbparam cbparam; 
    442  
    443  
    444     cbparam.regc = regc; 
    445     cbparam.token = regc->token; 
     389PJ_DEF(pj_status_t) pjsip_publishc_update_expires( pjsip_publishc *pubc, 
     390                                                   pj_uint32_t expires ) 
     391{ 
     392    PJ_ASSERT_RETURN(pubc, PJ_EINVAL); 
     393    set_expires( pubc, expires ); 
     394    return PJ_SUCCESS; 
     395} 
     396 
     397 
     398static void call_callback(pjsip_publishc *pubc, pj_status_t status,  
     399                          int st_code, const pj_str_t *reason, 
     400                          pjsip_rx_data *rdata, pj_int32_t expiration) 
     401{ 
     402    struct pjsip_publishc_cbparam cbparam; 
     403 
     404 
     405    cbparam.pubc = pubc; 
     406    cbparam.token = pubc->token; 
    446407    cbparam.status = status; 
    447408    cbparam.code = st_code; 
    448409    cbparam.reason = *reason; 
    449410    cbparam.rdata = rdata; 
    450     cbparam.contact_cnt = contact_cnt; 
    451411    cbparam.expiration = expiration; 
    452     if (contact_cnt) { 
    453         pj_memcpy( cbparam.contact, contact,  
    454                    contact_cnt*sizeof(pjsip_contact_hdr*)); 
    455     } 
    456  
    457     (*regc->cb)(&cbparam); 
    458 } 
    459  
    460 static void regc_refresh_timer_cb( pj_timer_heap_t *timer_heap, 
     412 
     413    (*pubc->cb)(&cbparam); 
     414} 
     415 
     416static void pubc_refresh_timer_cb( pj_timer_heap_t *timer_heap, 
    461417                                   struct pj_timer_entry *entry) 
    462418{ 
    463     pjsip_regc *regc = entry->user_data; 
     419    pjsip_publishc *pubc = entry->user_data; 
    464420    pjsip_tx_data *tdata; 
    465421    pj_status_t status; 
     
    468424 
    469425    entry->id = 0; 
    470     status = pjsip_regc_register(regc, 1, &tdata); 
     426    status = pjsip_publishc_publish(pubc, 1, &tdata); 
    471427    if (status == PJ_SUCCESS) { 
    472         status = pjsip_regc_send(regc, tdata); 
     428        status = pjsip_publishc_send(pubc, tdata); 
    473429    }  
    474430     
     
    476432        char errmsg[PJ_ERR_MSG_SIZE]; 
    477433        pj_str_t reason = pj_strerror(status, errmsg, sizeof(errmsg)); 
    478         call_callback(regc, status, 400, &reason, NULL, -1, 0, NULL); 
     434        call_callback(pubc, status, 400, &reason, NULL, -1); 
    479435    } 
    480436} 
     
    483439{ 
    484440    pj_status_t status; 
    485     pjsip_regc *regc = token; 
     441    pjsip_publishc *pubc = token; 
    486442    pjsip_transaction *tsx = event->body.tsx_state.tsx; 
    487443     
    488444    /* Decrement pending transaction counter. */ 
    489     pj_assert(regc->pending_tsx > 0); 
    490     --regc->pending_tsx; 
    491  
    492     /* If registration data has been deleted by user then remove registration  
     445    pj_assert(pubc->pending_tsx > 0); 
     446    --pubc->pending_tsx; 
     447 
     448    /* If publication data has been deleted by user then remove publication  
    493449     * data from transaction's callback, and don't call callback. 
    494450     */ 
    495     if (regc->_delete_flag) { 
     451    if (pubc->_delete_flag) { 
    496452 
    497453        /* Nothing to do */ 
     
    504460        pjsip_tx_data *tdata; 
    505461 
    506         status = pjsip_auth_clt_reinit_req( &regc->auth_sess, 
     462        status = pjsip_auth_clt_reinit_req( &pubc->auth_sess, 
    507463                                            rdata,  
    508464                                            tsx->last_tx,   
     
    510466 
    511467        if (status == PJ_SUCCESS) { 
    512             status = pjsip_regc_send(regc, tdata); 
     468            status = pjsip_publishc_send(pubc, tdata); 
    513469        }  
    514470         
    515471        if (status != PJ_SUCCESS) { 
    516             call_callback(regc, status, tsx->status_code,  
     472            call_callback(pubc, status, tsx->status_code,  
    517473                          &rdata->msg_info.msg->line.status.reason, 
    518                           rdata, -1, 0, NULL); 
     474                          rdata, -1); 
    519475        } 
    520476 
     
    522478 
    523479    } else { 
    524         int contact_cnt = 0; 
    525         pjsip_contact_hdr *contact[PJSIP_REGC_MAX_CONTACT]; 
    526480        pjsip_rx_data *rdata; 
    527481        pj_int32_t expiration = 0xFFFF; 
    528482 
    529483        if (tsx->status_code/100 == 2) { 
    530             int i; 
    531             pjsip_contact_hdr *hdr; 
    532484            pjsip_msg *msg; 
    533485            pjsip_expires_hdr *expires; 
     486            pjsip_generic_string_hdr *etag_hdr; 
     487            const pj_str_t STR_ETAG = { "SIP-ETag", 8 }; 
    534488 
    535489            rdata = event->body.tsx_state.src.rdata; 
    536490            msg = rdata->msg_info.msg; 
    537             hdr = pjsip_msg_find_hdr( msg, PJSIP_H_CONTACT, NULL); 
    538             while (hdr) { 
    539                 contact[contact_cnt++] = hdr; 
    540                 hdr = hdr->next; 
    541                 if (hdr == (void*)&msg->hdr) 
    542                     break; 
    543                 hdr = pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, hdr); 
     491 
     492            /* Save ETag value */ 
     493            etag_hdr = (pjsip_generic_string_hdr*) 
     494                       pjsip_msg_find_hdr_by_name(msg, &STR_ETAG, NULL); 
     495            if (etag_hdr) { 
     496                pj_strdup(pubc->pool, &pubc->etag, &etag_hdr->hvalue); 
     497            } else { 
     498                pubc->etag.slen = 0; 
    544499            } 
    545500 
     501            /* Update expires value */ 
    546502            expires = pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL); 
    547503 
     
    549505                expiration = expires->ivalue; 
    550506             
    551             for (i=0; i<contact_cnt; ++i) { 
    552                 hdr = contact[i]; 
    553                 if (hdr->expires >= 0 && hdr->expires < expiration) 
    554                     expiration = contact[i]->expires; 
    555             } 
    556  
    557             if (regc->auto_reg && expiration != 0 && expiration != 0xFFFF) { 
     507            if (pubc->auto_refresh && expiration!=0 && expiration!=0xFFFF) { 
    558508                pj_time_val delay = { 0, 0}; 
    559509 
    560510                delay.sec = expiration - DELAY_BEFORE_REFRESH; 
    561                 if (regc->expires != PJSIP_REGC_EXPIRATION_NOT_SPECIFIED &&  
    562                     delay.sec > (pj_int32_t)regc->expires)  
     511                if (pubc->expires != PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED &&  
     512                    delay.sec > (pj_int32_t)pubc->expires)  
    563513                { 
    564                     delay.sec = regc->expires; 
     514                    delay.sec = pubc->expires; 
    565515                } 
    566516                if (delay.sec < DELAY_BEFORE_REFRESH)  
    567517                    delay.sec = DELAY_BEFORE_REFRESH; 
    568                 regc->timer.cb = &regc_refresh_timer_cb; 
    569                 regc->timer.id = REFRESH_TIMER; 
    570                 regc->timer.user_data = regc; 
    571                 pjsip_endpt_schedule_timer( regc->endpt, &regc->timer, &delay); 
    572                 pj_gettimeofday(&regc->last_reg); 
    573                 regc->next_reg = regc->last_reg; 
    574                 regc->next_reg.sec += delay.sec; 
     518                pubc->timer.cb = &pubc_refresh_timer_cb; 
     519                pubc->timer.id = REFRESH_TIMER; 
     520                pubc->timer.user_data = pubc; 
     521                pjsip_endpt_schedule_timer( pubc->endpt, &pubc->timer, &delay); 
     522                pj_gettimeofday(&pubc->last_refresh); 
     523                pubc->next_refresh = pubc->last_refresh; 
     524                pubc->next_refresh.sec += delay.sec; 
    575525            } 
    576526 
     
    583533        /* Call callback. */ 
    584534        if (expiration == 0xFFFF) expiration = -1; 
    585         call_callback(regc, PJ_SUCCESS, tsx->status_code,  
     535        call_callback(pubc, PJ_SUCCESS, tsx->status_code,  
    586536                      (rdata ? &rdata->msg_info.msg->line.status.reason  
    587537                        : pjsip_get_status_text(tsx->status_code)), 
    588                       rdata, expiration,  
    589                       contact_cnt, contact); 
    590  
    591     } 
    592  
    593     /* Delete the record if user destroy regc during the callback. */ 
    594     if (regc->_delete_flag && regc->pending_tsx==0) { 
    595         pjsip_regc_destroy(regc); 
    596     } 
    597 } 
    598  
    599 PJ_DEF(pj_status_t) pjsip_regc_send(pjsip_regc *regc, pjsip_tx_data *tdata) 
     538                      rdata, expiration); 
     539 
     540    } 
     541 
     542    /* Delete the record if user destroy pubc during the callback. */ 
     543    if (pubc->_delete_flag && pubc->pending_tsx==0) { 
     544        pjsip_publishc_destroy(pubc); 
     545    } 
     546} 
     547 
     548 
     549PJ_DEF(pj_status_t) pjsip_publishc_send(pjsip_publishc *pubc,  
     550                                        pjsip_tx_data *tdata) 
    600551{ 
    601552    pj_status_t status; 
     
    604555 
    605556    /* Make sure we don't have pending transaction. */ 
    606     if (regc->pending_tsx) { 
    607         PJ_LOG(4,(THIS_FILE, "Unable to send request, regc has another " 
     557    if (pubc->pending_tsx) { 
     558        PJ_LOG(4,(THIS_FILE, "Unable to send request, pubc has another " 
    608559                             "transaction pending")); 
    609560        pjsip_tx_data_dec_ref( tdata ); 
     
    615566 
    616567    /* Increment CSeq */ 
    617     cseq = ++regc->cseq_hdr->cseq; 
     568    cseq = ++pubc->cseq_hdr->cseq; 
    618569    cseq_hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL); 
    619570    cseq_hdr->cseq = cseq; 
     
    622573     * may be called even before send_request() returns! 
    623574     */ 
    624     ++regc->pending_tsx; 
    625     status = pjsip_endpt_send_request(regc->endpt, tdata, -1, regc, &tsx_callback); 
     575    ++pubc->pending_tsx; 
     576    status = pjsip_endpt_send_request(pubc->endpt, tdata, -1, pubc,  
     577                                      &tsx_callback); 
    626578    if (status!=PJ_SUCCESS) { 
    627         --regc->pending_tsx; 
     579        --pubc->pending_tsx; 
    628580        PJ_LOG(4,(THIS_FILE, "Error sending request, status=%d", status)); 
    629581    } 
  • pjproject/trunk/pjsip/src/pjsip/sip_endpoint.c

    r610 r685  
    334334    unsigned i; 
    335335 
     336    PJ_UNUSED_ARG(mod); 
     337 
    336338    /* Check arguments. */ 
    337     PJ_ASSERT_RETURN(endpt!=NULL && mod!=NULL && count>0 && tags, PJ_EINVAL); 
     339    PJ_ASSERT_RETURN(endpt!=NULL && count>0 && tags, PJ_EINVAL); 
    338340    PJ_ASSERT_RETURN(htype==PJSIP_H_ACCEPT ||  
    339341                     htype==PJSIP_H_ALLOW || 
    340342                     htype==PJSIP_H_SUPPORTED, 
    341343                     PJ_EINVAL); 
    342  
    343     PJ_UNUSED_ARG(mod); 
    344344 
    345345    /* Find the header. */ 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_acc.c

    r683 r685  
    9999    pjsip_name_addr *name_addr; 
    100100    pjsip_sip_uri *sip_uri, *sip_reg_uri; 
     101    pj_status_t status; 
    101102    unsigned i; 
    102103 
     
    221222    } 
    222223 
    223     /* Init presence subscription */ 
    224     pj_list_init(&acc->pres_srv_list); 
     224    status = pjsua_pres_init_acc(acc_id); 
     225    if (status != PJ_SUCCESS) 
     226        return status; 
     227 
    225228 
    226229    /* Mark account as valid */ 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c

    r657 r685  
    525525    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 
    526526 
     527    /* Init PUBLISH module */ 
     528    pjsip_publishc_init_module(pjsua_var.endpt); 
    527529 
    528530    /* Init xfer/REFER module */ 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_pres.c

    r683 r685  
    567567 
    568568 
     569/* 
     570 * Client presence publication callback. 
     571 */ 
     572static void publish_cb(struct pjsip_publishc_cbparam *param) 
     573{ 
     574    pjsua_acc *acc = param->token; 
     575 
     576    if (param->code/100 != 2 || param->status != PJ_SUCCESS) { 
     577        if (param->status != PJ_SUCCESS) { 
     578            char errmsg[PJ_ERR_MSG_SIZE]; 
     579 
     580            pj_strerror(param->status, errmsg, sizeof(errmsg)); 
     581            PJ_LOG(1,(THIS_FILE,  
     582                      "Client publication (PUBLISH) failed, status=%d, msg=%s", 
     583                       param->status, errmsg)); 
     584        } else { 
     585            PJ_LOG(1,(THIS_FILE,  
     586                      "Client publication (PUBLISH) failed (%d/%.*s)", 
     587                       param->code, (int)param->reason.slen, 
     588                       param->reason.ptr)); 
     589        } 
     590 
     591        pjsip_publishc_destroy(param->pubc); 
     592        acc->publish_sess = NULL; 
     593    } 
     594} 
     595 
     596 
     597/* 
     598 * Send PUBLISH request. 
     599 */ 
     600static pj_status_t send_publish(int acc_id, pj_bool_t active) 
     601{ 
     602    pjsua_acc_config *acc_cfg = &pjsua_var.acc[acc_id].cfg; 
     603    pjsua_acc *acc = &pjsua_var.acc[acc_id]; 
     604    pjsip_pres_status pres_status; 
     605    pjsip_tx_data *tdata; 
     606    pj_status_t status; 
     607 
     608 
     609    /* Create PUBLISH request */ 
     610    if (active) { 
     611        status = pjsip_publishc_publish(acc->publish_sess, PJ_TRUE, &tdata); 
     612        if (status != PJ_SUCCESS) { 
     613            pjsua_perror(THIS_FILE, "Error creating PUBLISH request", status); 
     614            goto on_error; 
     615        } 
     616 
     617        /* Set our online status: */ 
     618        pj_bzero(&pres_status, sizeof(pres_status)); 
     619        pres_status.info_cnt = 1; 
     620        pres_status.info[0].basic_open = acc->online_status; 
     621 
     622        /* Create and add PIDF message body */ 
     623        status = pjsip_pres_create_pidf(tdata->pool, &pres_status, 
     624                                        &acc_cfg->id, &tdata->msg->body); 
     625        if (status != PJ_SUCCESS) { 
     626            pjsua_perror(THIS_FILE, "Error creating PIDF for PUBLISH request", 
     627                         status); 
     628            pjsip_tx_data_dec_ref(tdata); 
     629            goto on_error; 
     630        } 
     631    } else { 
     632        status = pjsip_publishc_unpublish(acc->publish_sess, &tdata); 
     633        if (status != PJ_SUCCESS) { 
     634            pjsua_perror(THIS_FILE, "Error creating PUBLISH request", status); 
     635            goto on_error; 
     636        } 
     637    } 
     638 
     639    /* Add headers etc */ 
     640    pjsua_process_msg_data(tdata, NULL); 
     641 
     642    /* Send the PUBLISH request */ 
     643    status = pjsip_publishc_send(acc->publish_sess, tdata); 
     644    if (status != PJ_SUCCESS) { 
     645        pjsua_perror(THIS_FILE, "Error sending PUBLISH request", status); 
     646        goto on_error; 
     647    } 
     648 
     649    acc->publish_state = acc->online_status; 
     650    return PJ_SUCCESS; 
     651 
     652on_error: 
     653    pjsip_publishc_destroy(acc->publish_sess); 
     654    acc->publish_sess = NULL; 
     655    return status; 
     656} 
     657 
     658 
     659/* Create client publish session */ 
     660static pj_status_t create_publish(int acc_id) 
     661{ 
     662    const pj_str_t STR_PRESENCE = { "presence", 8 }; 
     663    pjsua_acc_config *acc_cfg = &pjsua_var.acc[acc_id].cfg; 
     664    pjsua_acc *acc = &pjsua_var.acc[acc_id]; 
     665    pj_status_t status; 
     666 
     667    /* Create and init client publication session */ 
     668    if (acc_cfg->publish_enabled) { 
     669 
     670        /* Create client publication */ 
     671        status = pjsip_publishc_create(pjsua_var.endpt, 0, acc, &publish_cb, 
     672                                       &acc->publish_sess); 
     673        if (status != PJ_SUCCESS) { 
     674            acc->publish_sess = NULL; 
     675            return status; 
     676        } 
     677 
     678        /* Initialize client publication */ 
     679        status = pjsip_publishc_init(acc->publish_sess, &STR_PRESENCE, 
     680                                     &acc_cfg->id, &acc_cfg->id, 
     681                                     &acc_cfg->id,  
     682                                     PJSUA_PUBLISH_EXPIRATION); 
     683        if (status != PJ_SUCCESS) { 
     684            acc->publish_sess = NULL; 
     685            return status; 
     686        } 
     687 
     688        /* Send initial PUBLISH request */ 
     689        if (acc->online_status != 0) { 
     690            status = send_publish(acc_id, PJ_TRUE); 
     691            if (status != PJ_SUCCESS) 
     692                return status; 
     693        } 
     694 
     695    } else { 
     696        acc->publish_sess = NULL; 
     697    } 
     698 
     699    return PJ_SUCCESS; 
     700} 
     701 
     702 
     703/* Init presence for account */ 
     704pj_status_t pjsua_pres_init_acc(int acc_id) 
     705{ 
     706    pjsua_acc *acc = &pjsua_var.acc[acc_id]; 
     707 
     708    /* Init presence subscription */ 
     709    pj_list_init(&acc->pres_srv_list); 
     710 
     711 
     712    return create_publish(acc_id); 
     713} 
     714 
     715 
    569716/* Terminate server subscription for the account */ 
    570717void pjsua_pres_delete_acc(int acc_id) 
    571718{ 
     719    pjsua_acc *acc = &pjsua_var.acc[acc_id]; 
     720    pjsua_acc_config *acc_cfg = &pjsua_var.acc[acc_id].cfg; 
    572721    pjsua_srv_pres *uapres; 
    573722 
    574723    uapres = pjsua_var.acc[acc_id].pres_srv_list.next; 
    575724 
    576     while (uapres != &pjsua_var.acc[acc_id].pres_srv_list) { 
     725    while (uapres != &acc->pres_srv_list) { 
    577726         
    578727        pjsip_pres_status pres_status; 
     
    594743        uapres = uapres->next; 
    595744    } 
     745 
     746    if (acc->publish_sess) { 
     747        acc->online_status = PJ_FALSE; 
     748        send_publish(acc_id, PJ_FALSE); 
     749        if (acc->publish_sess) { 
     750            pjsip_publishc_destroy(acc->publish_sess); 
     751            acc->publish_sess = NULL; 
     752        } 
     753        acc_cfg->publish_enabled = PJ_FALSE; 
     754    } 
    596755} 
    597756 
     
    600759static void refresh_server_subscription(int acc_id) 
    601760{ 
     761    pjsua_acc *acc = &pjsua_var.acc[acc_id]; 
     762    pjsua_acc_config *acc_cfg = &pjsua_var.acc[acc_id].cfg; 
    602763    pjsua_srv_pres *uapres; 
    603764 
    604765    uapres = pjsua_var.acc[acc_id].pres_srv_list.next; 
    605766 
    606     while (uapres != &pjsua_var.acc[acc_id].pres_srv_list) { 
     767    while (uapres != &acc->pres_srv_list) { 
    607768         
    608769        pjsip_pres_status pres_status; 
     
    610771 
    611772        pjsip_pres_get_status(uapres->sub, &pres_status); 
    612         if (pres_status.info[0].basic_open != pjsua_var.acc[acc_id].online_status) { 
    613             pres_status.info[0].basic_open = pjsua_var.acc[acc_id].online_status; 
     773        if (pres_status.info[0].basic_open != acc->online_status) { 
     774            pres_status.info[0].basic_open = acc->online_status; 
    614775            pjsip_pres_set_status(uapres->sub, &pres_status); 
    615776 
     
    621782 
    622783        uapres = uapres->next; 
     784    } 
     785 
     786    /* Send PUBLISH if required */ 
     787    if (acc_cfg->publish_enabled) { 
     788        if (acc->publish_sess == NULL) 
     789            create_publish(acc_id); 
     790 
     791        if (acc->publish_sess && acc->publish_state != acc->online_status) { 
     792            send_publish(acc_id, PJ_TRUE); 
     793        } 
    623794    } 
    624795} 
     
    820991 
    821992    status = pjsip_pres_create_uac( dlg, &pres_callback,  
    822                                     &buddy->sub); 
     993                                    PJSIP_EVSUB_NO_EVENT_ID, &buddy->sub); 
    823994    if (status != PJ_SUCCESS) { 
    824995        pjsua_var.buddy[index].sub = NULL; 
Note: See TracChangeset for help on using the changeset viewer.