~noskcaj/ubuntu/saucy/sflphone/merge-1.2.3-2

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.0.1/pjsip/src/pjsip-ua/sip_xfer.c

  • Committer: Jackson Doak
  • Date: 2013-07-10 21:04:46 UTC
  • mfrom: (20.1.3 sid)
  • Revision ID: noskcaj@ubuntu.com-20130710210446-y8f587vza807icr9
Properly merged from upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: sip_xfer.c 3553 2011-05-05 06:14:19Z nanang $ */
 
2
/*
 
3
 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
 
4
 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; either version 2 of the License, or
 
9
 * (at your option) any later version.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program; if not, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
19
 */
 
20
#include <pjsip-ua/sip_xfer.h>
 
21
#include <pjsip-simple/evsub_msg.h>
 
22
#include <pjsip/sip_dialog.h>
 
23
#include <pjsip/sip_errno.h>
 
24
#include <pjsip/sip_endpoint.h>
 
25
#include <pjsip/sip_module.h>
 
26
#include <pjsip/sip_transport.h>
 
27
#include <pj/assert.h>
 
28
#include <pj/pool.h>
 
29
#include <pj/string.h>
 
30
 
 
31
/* Subscription expiration */
 
32
#ifndef PJSIP_XFER_EXPIRES
 
33
#   define PJSIP_XFER_EXPIRES       600
 
34
#endif
 
35
 
 
36
 
 
37
/*
 
38
 * Refer module (mod-refer)
 
39
 */
 
40
static struct pjsip_module mod_xfer =
 
41
{
 
42
    NULL, NULL,                         /* prev, next.                  */
 
43
    { "mod-refer", 9 },                 /* Name.                        */
 
44
    -1,                                 /* Id                           */
 
45
    PJSIP_MOD_PRIORITY_DIALOG_USAGE,    /* Priority                     */
 
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()               */
 
55
};
 
56
 
 
57
 
 
58
/* Declare PJSIP_REFER_METHOD, so that if somebody declares this in
 
59
 * sip_msg.h we can catch the error here.
 
60
 */
 
61
enum
 
62
{
 
63
    PJSIP_REFER_METHOD = PJSIP_OTHER_METHOD
 
64
};
 
65
 
 
66
PJ_DEF_DATA(const pjsip_method) pjsip_refer_method = {
 
67
    (pjsip_method_e) PJSIP_REFER_METHOD,
 
68
    { "REFER", 5}
 
69
};
 
70
 
 
71
PJ_DEF(const pjsip_method*) pjsip_get_refer_method()
 
72
{
 
73
    return &pjsip_refer_method;
 
74
}
 
75
 
 
76
/*
 
77
 * String constants
 
78
 */
 
79
const pj_str_t STR_REFER = { "refer", 5 };
 
80
const pj_str_t STR_MESSAGE = { "message", 7 };
 
81
const pj_str_t STR_SIPFRAG = { "sipfrag", 7 };
 
82
const pj_str_t STR_SIPFRAG_VERSION = {";version=2.0", 12 };
 
83
 
 
84
 
 
85
/*
 
86
 * Transfer struct.
 
87
 */
 
88
struct pjsip_xfer
 
89
{
 
90
    pjsip_evsub         *sub;           /**< Event subscribtion record.     */
 
91
    pjsip_dialog        *dlg;           /**< The dialog.                    */
 
92
    pjsip_evsub_user     user_cb;       /**< The user callback.             */
 
93
    pj_str_t             refer_to_uri;  /**< The full Refer-To URI.         */
 
94
    int                  last_st_code;  /**< st_code sent in last NOTIFY    */
 
95
    pj_str_t             last_st_text;  /**< st_text sent in last NOTIFY    */
 
96
};
 
97
 
 
98
 
 
99
typedef struct pjsip_xfer pjsip_xfer;
 
100
 
 
101
 
 
102
 
 
103
/*
 
104
 * Forward decl for evsub callback.
 
105
 */
 
106
static void xfer_on_evsub_state( pjsip_evsub *sub, pjsip_event *event);
 
107
static void xfer_on_evsub_tsx_state( pjsip_evsub *sub, pjsip_transaction *tsx,
 
108
                                     pjsip_event *event);
 
109
static void xfer_on_evsub_rx_refresh( pjsip_evsub *sub,
 
110
                                      pjsip_rx_data *rdata,
 
111
                                      int *p_st_code,
 
112
                                      pj_str_t **p_st_text,
 
113
                                      pjsip_hdr *res_hdr,
 
114
                                      pjsip_msg_body **p_body);
 
115
static void xfer_on_evsub_rx_notify( pjsip_evsub *sub,
 
116
                                     pjsip_rx_data *rdata,
 
117
                                     int *p_st_code,
 
118
                                     pj_str_t **p_st_text,
 
119
                                     pjsip_hdr *res_hdr,
 
120
                                     pjsip_msg_body **p_body);
 
121
static void xfer_on_evsub_client_refresh(pjsip_evsub *sub);
 
122
static void xfer_on_evsub_server_timeout(pjsip_evsub *sub);
 
123
 
 
124
 
 
125
/*
 
126
 * Event subscription callback for xference.
 
127
 */
 
128
static pjsip_evsub_user xfer_user =
 
129
{
 
130
    &xfer_on_evsub_state,
 
131
    &xfer_on_evsub_tsx_state,
 
132
    &xfer_on_evsub_rx_refresh,
 
133
    &xfer_on_evsub_rx_notify,
 
134
    &xfer_on_evsub_client_refresh,
 
135
    &xfer_on_evsub_server_timeout,
 
136
};
 
137
 
 
138
 
 
139
 
 
140
 
 
141
/*
 
142
 * Initialize the REFER subsystem.
 
143
 */
 
144
PJ_DEF(pj_status_t) pjsip_xfer_init_module(pjsip_endpoint *endpt)
 
145
{
 
146
    const pj_str_t accept = { "message/sipfrag;version=2.0", 27 };
 
147
    pj_status_t status;
 
148
 
 
149
    PJ_ASSERT_RETURN(endpt != NULL, PJ_EINVAL);
 
150
    PJ_ASSERT_RETURN(mod_xfer.id == -1, PJ_EINVALIDOP);
 
151
 
 
152
    status = pjsip_endpt_register_module(endpt, &mod_xfer);
 
153
    if (status != PJ_SUCCESS)
 
154
        return status;
 
155
 
 
156
    status = pjsip_endpt_add_capability( endpt, &mod_xfer, PJSIP_H_ALLOW,
 
157
                                         NULL, 1,
 
158
                                         &pjsip_get_refer_method()->name);
 
159
    if (status != PJ_SUCCESS)
 
160
        return status;
 
161
 
 
162
    status = pjsip_evsub_register_pkg(&mod_xfer, &STR_REFER,
 
163
                                      PJSIP_XFER_EXPIRES, 1, &accept);
 
164
    if (status != PJ_SUCCESS)
 
165
        return status;
 
166
 
 
167
    return PJ_SUCCESS;
 
168
}
 
169
 
 
170
 
 
171
/*
 
172
 * Create transferer (sender of REFER request).
 
173
 *
 
174
 */
 
175
PJ_DEF(pj_status_t) pjsip_xfer_create_uac( pjsip_dialog *dlg,
 
176
                                           const pjsip_evsub_user *user_cb,
 
177
                                           pjsip_evsub **p_evsub )
 
178
{
 
179
    pj_status_t status;
 
180
    pjsip_xfer *xfer;
 
181
    pjsip_evsub *sub;
 
182
 
 
183
    PJ_ASSERT_RETURN(dlg && p_evsub, PJ_EINVAL);
 
184
 
 
185
    pjsip_dlg_inc_lock(dlg);
 
186
 
 
187
    /* Create event subscription */
 
188
    status = pjsip_evsub_create_uac( dlg,  &xfer_user, &STR_REFER,
 
189
                                     PJSIP_EVSUB_NO_EVENT_ID, &sub);
 
190
    if (status != PJ_SUCCESS)
 
191
        goto on_return;
 
192
 
 
193
    /* Create xfer session */
 
194
    xfer = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_xfer);
 
195
    xfer->dlg = dlg;
 
196
    xfer->sub = sub;
 
197
    if (user_cb)
 
198
        pj_memcpy(&xfer->user_cb, user_cb, sizeof(pjsip_evsub_user));
 
199
 
 
200
    /* Attach to evsub */
 
201
    pjsip_evsub_set_mod_data(sub, mod_xfer.id, xfer);
 
202
 
 
203
    *p_evsub = sub;
 
204
 
 
205
on_return:
 
206
    pjsip_dlg_dec_lock(dlg);
 
207
    return status;
 
208
 
 
209
}
 
210
 
 
211
 
 
212
 
 
213
 
 
214
/*
 
215
 * Create transferee (receiver of REFER request).
 
216
 *
 
217
 */
 
218
PJ_DEF(pj_status_t) pjsip_xfer_create_uas( pjsip_dialog *dlg,
 
219
                                           const pjsip_evsub_user *user_cb,
 
220
                                           pjsip_rx_data *rdata,
 
221
                                           pjsip_evsub **p_evsub )
 
222
{
 
223
    pjsip_evsub *sub;
 
224
    pjsip_xfer *xfer;
 
225
    const pj_str_t STR_EVENT = {"Event", 5 };
 
226
    pjsip_event_hdr *event_hdr;
 
227
    pj_status_t status;
 
228
 
 
229
    /* Check arguments */
 
230
    PJ_ASSERT_RETURN(dlg && rdata && p_evsub, PJ_EINVAL);
 
231
 
 
232
    /* Must be request message */
 
233
    PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG,
 
234
                     PJSIP_ENOTREQUESTMSG);
 
235
 
 
236
    /* Check that request is REFER */
 
237
    PJ_ASSERT_RETURN(pjsip_method_cmp(&rdata->msg_info.msg->line.req.method,
 
238
                                      pjsip_get_refer_method())==0,
 
239
                     PJSIP_ENOTREFER);
 
240
 
 
241
    /* Lock dialog */
 
242
    pjsip_dlg_inc_lock(dlg);
 
243
 
 
244
    /* The evsub framework expects an Event header in the request,
 
245
     * while a REFER request conveniently doesn't have one (pun intended!).
 
246
     * So create a dummy Event header.
 
247
     */
 
248
    if (pjsip_msg_find_hdr_by_name(rdata->msg_info.msg,
 
249
                                   &STR_EVENT, NULL)==NULL)
 
250
    {
 
251
        event_hdr = pjsip_event_hdr_create(rdata->tp_info.pool);
 
252
        event_hdr->event_type = STR_REFER;
 
253
        pjsip_msg_add_hdr(rdata->msg_info.msg, (pjsip_hdr*)event_hdr);
 
254
    }
 
255
 
 
256
    /* Create server subscription */
 
257
    status = pjsip_evsub_create_uas( dlg, &xfer_user, rdata,
 
258
                                     PJSIP_EVSUB_NO_EVENT_ID, &sub);
 
259
    if (status != PJ_SUCCESS)
 
260
        goto on_return;
 
261
 
 
262
    /* Create server xfer subscription */
 
263
    xfer = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_xfer);
 
264
    xfer->dlg = dlg;
 
265
    xfer->sub = sub;
 
266
    if (user_cb)
 
267
        pj_memcpy(&xfer->user_cb, user_cb, sizeof(pjsip_evsub_user));
 
268
 
 
269
    /* Attach to evsub */
 
270
    pjsip_evsub_set_mod_data(sub, mod_xfer.id, xfer);
 
271
 
 
272
    /* Done: */
 
273
    *p_evsub = sub;
 
274
 
 
275
on_return:
 
276
    pjsip_dlg_dec_lock(dlg);
 
277
    return status;
 
278
}
 
279
 
 
280
 
 
281
 
 
282
/*
 
283
 * Call this function to create request to initiate REFER subscription.
 
284
 *
 
285
 */
 
286
PJ_DEF(pj_status_t) pjsip_xfer_initiate( pjsip_evsub *sub,
 
287
                                         const pj_str_t *refer_to_uri,
 
288
                                         pjsip_tx_data **p_tdata)
 
289
{
 
290
    pjsip_xfer *xfer;
 
291
    const pj_str_t refer_to = { "Refer-To", 8};
 
292
    pjsip_tx_data *tdata;
 
293
    pjsip_generic_string_hdr *hdr;
 
294
    pj_status_t status;
 
295
 
 
296
    /* sub and p_tdata argument must be valid.  */
 
297
    PJ_ASSERT_RETURN(sub && p_tdata, PJ_EINVAL);
 
298
 
 
299
 
 
300
    /* Get the xfer object. */
 
301
    xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
 
302
    PJ_ASSERT_RETURN(xfer != NULL, PJSIP_ENOREFERSESSION);
 
303
 
 
304
    /* refer_to_uri argument MAY be NULL for subsequent REFER requests,
 
305
     * but it MUST be specified in the first REFER.
 
306
     */
 
307
    PJ_ASSERT_RETURN((refer_to_uri || xfer->refer_to_uri.slen), PJ_EINVAL);
 
308
 
 
309
    /* Lock dialog. */
 
310
    pjsip_dlg_inc_lock(xfer->dlg);
 
311
 
 
312
    /* Create basic REFER request */
 
313
    status = pjsip_evsub_initiate(sub, pjsip_get_refer_method(), -1,
 
314
                                  &tdata);
 
315
    if (status != PJ_SUCCESS)
 
316
        goto on_return;
 
317
 
 
318
    /* Save Refer-To URI. */
 
319
    if (refer_to_uri == NULL) {
 
320
        refer_to_uri = &xfer->refer_to_uri;
 
321
    } else {
 
322
        pj_strdup(xfer->dlg->pool, &xfer->refer_to_uri, refer_to_uri);
 
323
    }
 
324
 
 
325
    /* Create and add Refer-To header. */
 
326
    hdr = pjsip_generic_string_hdr_create(tdata->pool, &refer_to,
 
327
                                          refer_to_uri);
 
328
    if (!hdr) {
 
329
        pjsip_tx_data_dec_ref(tdata);
 
330
        status = PJ_ENOMEM;
 
331
        goto on_return;
 
332
    }
 
333
 
 
334
    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
 
335
 
 
336
 
 
337
    /* Done. */
 
338
    *p_tdata = tdata;
 
339
 
 
340
    status = PJ_SUCCESS;
 
341
 
 
342
on_return:
 
343
    pjsip_dlg_dec_lock(xfer->dlg);
 
344
    return status;
 
345
}
 
346
 
 
347
 
 
348
/*
 
349
 * Accept the incoming REFER request by sending 2xx response.
 
350
 *
 
351
 */
 
352
PJ_DEF(pj_status_t) pjsip_xfer_accept( pjsip_evsub *sub,
 
353
                                       pjsip_rx_data *rdata,
 
354
                                       int st_code,
 
355
                                       const pjsip_hdr *hdr_list )
 
356
{
 
357
    /*
 
358
     * Don't need to add custom headers, so just call basic
 
359
     * evsub response.
 
360
     */
 
361
    return pjsip_evsub_accept( sub, rdata, st_code, hdr_list );
 
362
}
 
363
 
 
364
 
 
365
/*
 
366
 * For notifier, create NOTIFY request to subscriber, and set the state
 
367
 * of the subscription.
 
368
 */
 
369
PJ_DEF(pj_status_t) pjsip_xfer_notify( pjsip_evsub *sub,
 
370
                                       pjsip_evsub_state state,
 
371
                                       int xfer_st_code,
 
372
                                       const pj_str_t *xfer_st_text,
 
373
                                       pjsip_tx_data **p_tdata)
 
374
{
 
375
    pjsip_tx_data *tdata;
 
376
    pjsip_xfer *xfer;
 
377
    pjsip_param *param;
 
378
    const pj_str_t reason = { "noresource", 10 };
 
379
    char *body;
 
380
    int bodylen;
 
381
    pjsip_msg_body *msg_body;
 
382
    pj_status_t status;
 
383
 
 
384
 
 
385
    /* Check arguments. */
 
386
    PJ_ASSERT_RETURN(sub, PJ_EINVAL);
 
387
 
 
388
    /* Get the xfer object. */
 
389
    xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
 
390
    PJ_ASSERT_RETURN(xfer != NULL, PJSIP_ENOREFERSESSION);
 
391
 
 
392
 
 
393
    /* Lock object. */
 
394
    pjsip_dlg_inc_lock(xfer->dlg);
 
395
 
 
396
    /* Create the NOTIFY request.
 
397
     * Note that reason is only used when state is TERMINATED, and
 
398
     * the defined termination reason for REFER is "noresource".
 
399
     */
 
400
    status = pjsip_evsub_notify( sub, state, NULL, &reason, &tdata);
 
401
    if (status != PJ_SUCCESS)
 
402
        goto on_return;
 
403
 
 
404
 
 
405
    /* Check status text */
 
406
    if (xfer_st_text==NULL || xfer_st_text->slen==0)
 
407
        xfer_st_text = pjsip_get_status_text(xfer_st_code);
 
408
 
 
409
    /* Save st_code and st_text, for current_notify() */
 
410
    xfer->last_st_code = xfer_st_code;
 
411
    pj_strdup(xfer->dlg->pool, &xfer->last_st_text, xfer_st_text);
 
412
 
 
413
    /* Create sipfrag content. */
 
414
    body = (char*) pj_pool_alloc(tdata->pool, 128);
 
415
    bodylen = pj_ansi_snprintf(body, 128, "SIP/2.0 %u %.*s\r\n",
 
416
                               xfer_st_code,
 
417
                               (int)xfer_st_text->slen,
 
418
                               xfer_st_text->ptr);
 
419
    PJ_ASSERT_ON_FAIL(bodylen > 0 && bodylen < 128,
 
420
                        {status=PJ_EBUG; pjsip_tx_data_dec_ref(tdata);
 
421
                         goto on_return; });
 
422
 
 
423
 
 
424
    /* Create SIP message body. */
 
425
    msg_body = PJ_POOL_ZALLOC_T(tdata->pool, pjsip_msg_body);
 
426
    pjsip_media_type_init(&msg_body->content_type, (pj_str_t*)&STR_MESSAGE,
 
427
                          (pj_str_t*)&STR_SIPFRAG);
 
428
    msg_body->data = body;
 
429
    msg_body->len = bodylen;
 
430
    msg_body->print_body = &pjsip_print_text_body;
 
431
    msg_body->clone_data = &pjsip_clone_text_data;
 
432
 
 
433
    param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
 
434
    param->name = pj_str("version");
 
435
    param->value = pj_str("2.0");
 
436
    pj_list_push_back(&msg_body->content_type.param, param);
 
437
 
 
438
    /* Attach sipfrag body. */
 
439
    tdata->msg->body = msg_body;
 
440
 
 
441
 
 
442
    /* Done. */
 
443
    *p_tdata = tdata;
 
444
 
 
445
 
 
446
on_return:
 
447
    pjsip_dlg_dec_lock(xfer->dlg);
 
448
    return status;
 
449
 
 
450
}
 
451
 
 
452
 
 
453
/*
 
454
 * Send current state and the last sipfrag body.
 
455
 */
 
456
PJ_DEF(pj_status_t) pjsip_xfer_current_notify( pjsip_evsub *sub,
 
457
                                               pjsip_tx_data **p_tdata )
 
458
{
 
459
    pjsip_xfer *xfer;
 
460
    pj_status_t status;
 
461
 
 
462
 
 
463
    /* Check arguments. */
 
464
    PJ_ASSERT_RETURN(sub, PJ_EINVAL);
 
465
 
 
466
    /* Get the xfer object. */
 
467
    xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
 
468
    PJ_ASSERT_RETURN(xfer != NULL, PJSIP_ENOREFERSESSION);
 
469
 
 
470
    pjsip_dlg_inc_lock(xfer->dlg);
 
471
 
 
472
    status = pjsip_xfer_notify(sub, pjsip_evsub_get_state(sub),
 
473
                               xfer->last_st_code, &xfer->last_st_text,
 
474
                               p_tdata);
 
475
 
 
476
    pjsip_dlg_dec_lock(xfer->dlg);
 
477
 
 
478
    return status;
 
479
}
 
480
 
 
481
 
 
482
/*
 
483
 * Send request message.
 
484
 */
 
485
PJ_DEF(pj_status_t) pjsip_xfer_send_request( pjsip_evsub *sub,
 
486
                                             pjsip_tx_data *tdata)
 
487
{
 
488
    return pjsip_evsub_send_request(sub, tdata);
 
489
}
 
490
 
 
491
 
 
492
/*
 
493
 * This callback is called by event subscription when subscription
 
494
 * state has changed.
 
495
 */
 
496
static void xfer_on_evsub_state( pjsip_evsub *sub, pjsip_event *event)
 
497
{
 
498
    pjsip_xfer *xfer;
 
499
 
 
500
    xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
 
501
    PJ_ASSERT_ON_FAIL(xfer!=NULL, {return;});
 
502
 
 
503
    if (xfer->user_cb.on_evsub_state)
 
504
        (*xfer->user_cb.on_evsub_state)(sub, event);
 
505
 
 
506
}
 
507
 
 
508
/*
 
509
 * Called when transaction state has changed.
 
510
 */
 
511
static void xfer_on_evsub_tsx_state( pjsip_evsub *sub, pjsip_transaction *tsx,
 
512
                                     pjsip_event *event)
 
513
{
 
514
    pjsip_xfer *xfer;
 
515
 
 
516
    xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
 
517
    PJ_ASSERT_ON_FAIL(xfer!=NULL, {return;});
 
518
 
 
519
    if (xfer->user_cb.on_tsx_state)
 
520
        (*xfer->user_cb.on_tsx_state)(sub, tsx, event);
 
521
}
 
522
 
 
523
/*
 
524
 * Called when REFER is received to refresh subscription.
 
525
 */
 
526
static void xfer_on_evsub_rx_refresh( pjsip_evsub *sub,
 
527
                                      pjsip_rx_data *rdata,
 
528
                                      int *p_st_code,
 
529
                                      pj_str_t **p_st_text,
 
530
                                      pjsip_hdr *res_hdr,
 
531
                                      pjsip_msg_body **p_body)
 
532
{
 
533
    pjsip_xfer *xfer;
 
534
 
 
535
    xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
 
536
    PJ_ASSERT_ON_FAIL(xfer!=NULL, {return;});
 
537
 
 
538
    if (xfer->user_cb.on_rx_refresh) {
 
539
        (*xfer->user_cb.on_rx_refresh)(sub, rdata, p_st_code, p_st_text,
 
540
                                       res_hdr, p_body);
 
541
 
 
542
    } else {
 
543
        /* Implementors MUST send NOTIFY if it implements on_rx_refresh
 
544
         * (implementor == "us" from evsub point of view.
 
545
         */
 
546
        pjsip_tx_data *tdata;
 
547
        pj_status_t status;
 
548
 
 
549
        if (pjsip_evsub_get_state(sub)==PJSIP_EVSUB_STATE_TERMINATED) {
 
550
            status = pjsip_xfer_notify( sub, PJSIP_EVSUB_STATE_TERMINATED,
 
551
                                        xfer->last_st_code,
 
552
                                        &xfer->last_st_text,
 
553
                                        &tdata);
 
554
        } else {
 
555
            status = pjsip_xfer_current_notify(sub, &tdata);
 
556
        }
 
557
 
 
558
        if (status == PJ_SUCCESS)
 
559
            pjsip_xfer_send_request(sub, tdata);
 
560
    }
 
561
}
 
562
 
 
563
 
 
564
/*
 
565
 * Called when NOTIFY is received.
 
566
 */
 
567
static void xfer_on_evsub_rx_notify( pjsip_evsub *sub,
 
568
                                     pjsip_rx_data *rdata,
 
569
                                     int *p_st_code,
 
570
                                     pj_str_t **p_st_text,
 
571
                                     pjsip_hdr *res_hdr,
 
572
                                     pjsip_msg_body **p_body)
 
573
{
 
574
    pjsip_xfer *xfer;
 
575
 
 
576
    xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
 
577
    PJ_ASSERT_ON_FAIL(xfer!=NULL, {return;});
 
578
 
 
579
    if (xfer->user_cb.on_rx_notify)
 
580
        (*xfer->user_cb.on_rx_notify)(sub, rdata, p_st_code, p_st_text,
 
581
                                      res_hdr, p_body);
 
582
}
 
583
 
 
584
/*
 
585
 * Called when it's time to send SUBSCRIBE.
 
586
 */
 
587
static void xfer_on_evsub_client_refresh(pjsip_evsub *sub)
 
588
{
 
589
    pjsip_xfer *xfer;
 
590
 
 
591
    xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
 
592
    PJ_ASSERT_ON_FAIL(xfer!=NULL, {return;});
 
593
 
 
594
    if (xfer->user_cb.on_client_refresh) {
 
595
        (*xfer->user_cb.on_client_refresh)(sub);
 
596
    } else {
 
597
        pj_status_t status;
 
598
        pjsip_tx_data *tdata;
 
599
 
 
600
        status = pjsip_evsub_initiate(sub, NULL, PJSIP_XFER_EXPIRES, &tdata);
 
601
        if (status == PJ_SUCCESS)
 
602
            pjsip_xfer_send_request(sub, tdata);
 
603
    }
 
604
}
 
605
 
 
606
 
 
607
/*
 
608
 * Called when no refresh is received after the interval.
 
609
 */
 
610
static void xfer_on_evsub_server_timeout(pjsip_evsub *sub)
 
611
{
 
612
    pjsip_xfer *xfer;
 
613
 
 
614
    xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
 
615
    PJ_ASSERT_ON_FAIL(xfer!=NULL, {return;});
 
616
 
 
617
    if (xfer->user_cb.on_server_timeout) {
 
618
        (*xfer->user_cb.on_server_timeout)(sub);
 
619
    } else {
 
620
        pj_status_t status;
 
621
        pjsip_tx_data *tdata;
 
622
 
 
623
        status = pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_TERMINATED,
 
624
                                   xfer->last_st_code,
 
625
                                   &xfer->last_st_text, &tdata);
 
626
        if (status == PJ_SUCCESS)
 
627
            pjsip_xfer_send_request(sub, tdata);
 
628
    }
 
629
}