~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/src/sip/pres_sub_client.cpp

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Copyright (C) 2012, 2013 LOTES TM LLC
 
3
 *  Author : Andrey Loukhnov <aol.nnov@gmail.com>
 
4
 *
 
5
 *  This file is a part of pult5-voip
 
6
 *
 
7
 *  pult5-voip is free software; you can redistribute it and/or modify
 
8
 *  it under the terms of the GNU General Public License as published by
 
9
 *  the Free Software Foundation; either version 3 of the License, or
 
10
 *  (at your option) any later version.
 
11
 *
 
12
 *  pult5-voip is distributed in the hope that it will be useful,
 
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 *  GNU General Public License for more details.
 
16
 *
 
17
 *  You should have received a copy of the GNU General Public License
 
18
 *  along with this programm. If not, see <http://www.gnu.org/licenses/>.
 
19
 *
 
20
 *  Additional permission under GNU GPL version 3 section 7:
 
21
 *
 
22
 *  If you modify pult5-voip, or any covered work, by linking or
 
23
 *  combining it with the OpenSSL project's OpenSSL library (or a
 
24
 *  modified version of that library), containing parts covered by the
 
25
 *  terms of the OpenSSL or SSLeay licenses, LOTES-TM LLC
 
26
 *  grants you additional permission to convey the resulting work.
 
27
 *  Corresponding Source for a non-source form of such a combination
 
28
 *  shall include the source code for the parts of OpenSSL used as well
 
29
 *  as that of the covered work.
 
30
 */
 
31
 
 
32
#include <pj/log.h>
 
33
#include <pj/rand.h>
 
34
#include <pjsip/sip_module.h>
 
35
#include <pjsip/sip_types.h>
 
36
#include <pjsip/sip_event.h>
 
37
#include <pjsip/sip_transaction.h>
 
38
#include <pjsip/sip_dialog.h>
 
39
#include <pjsip/sip_endpoint.h>
 
40
#include <string>
 
41
#include <sstream>
 
42
#include <pj/pool.h>
 
43
#include <pjsip/sip_ua_layer.h>
 
44
#include <pjsip-simple/evsub.h>
 
45
#include <unistd.h>
 
46
 
 
47
#include "array_size.h"
 
48
#include "pres_sub_client.h"
 
49
#include "client/presencemanager.h"
 
50
#include "client/configurationmanager.h"
 
51
#include "sipaccount.h"
 
52
#include "sippresence.h"
 
53
#include "sipvoiplink.h"
 
54
#include "sip_utils.h"
 
55
#include "manager.h"
 
56
 
 
57
#include "logger.h"
 
58
 
 
59
#define PRES_TIMER 300 // 5min
 
60
 
 
61
int PresSubClient::modId_ = 0; // used to extract data structure from event_subscription
 
62
 
 
63
void
 
64
PresSubClient::pres_client_timer_cb(pj_timer_heap_t * /*th*/, pj_timer_entry *entry)
 
65
{
 
66
    PresSubClient *c = (PresSubClient *) entry->user_data;
 
67
    DEBUG("timeout for %s", c->getURI().c_str());
 
68
}
 
69
 
 
70
/* Callback called when *client* subscription state has changed. */
 
71
void
 
72
PresSubClient::pres_client_evsub_on_state(pjsip_evsub *sub, pjsip_event *event)
 
73
{
 
74
    PJ_UNUSED_ARG(event);
 
75
 
 
76
    PresSubClient *pres_client = (PresSubClient *) pjsip_evsub_get_mod_data(sub, modId_);
 
77
    /* No need to pres->lock() here since the client has a locked dialog*/
 
78
 
 
79
    if (!pres_client) {
 
80
        WARN("pres_client not found");
 
81
        return;
 
82
    }
 
83
 
 
84
    DEBUG("Subscription for pres_client '%s' is '%s'", pres_client->getURI().c_str(),
 
85
            pjsip_evsub_get_state_name(sub) ? pjsip_evsub_get_state_name(sub) : "null");
 
86
 
 
87
    pjsip_evsub_state state = pjsip_evsub_get_state(sub);
 
88
 
 
89
    SIPPresence * pres = pres_client->getPresence();
 
90
 
 
91
    if (state == PJSIP_EVSUB_STATE_ACCEPTED) {
 
92
        pres_client->enable(true);
 
93
        Manager::instance().getClient()->getPresenceManager()->subscriptionStateChanged(
 
94
                pres->getAccount()->getAccountID(),
 
95
                pres_client->getURI().c_str(),
 
96
                PJ_TRUE);
 
97
 
 
98
        pres->getAccount()->supportPresence(PRESENCE_FUNCTION_SUBSCRIBE, true);
 
99
 
 
100
    } else if (state == PJSIP_EVSUB_STATE_TERMINATED) {
 
101
        int resub_delay = -1;
 
102
        pj_strdup_with_null(pres_client->pool_, &pres_client->term_reason_, pjsip_evsub_get_termination_reason(sub));
 
103
 
 
104
        Manager::instance().getClient()->getPresenceManager()->subscriptionStateChanged(
 
105
                pres->getAccount()->getAccountID(),
 
106
                pres_client->getURI().c_str(),
 
107
                PJ_FALSE);
 
108
 
 
109
        pres_client->term_code_ = 200;
 
110
 
 
111
        /* Determine whether to resubscribe automatically */
 
112
        if (event && event->type == PJSIP_EVENT_TSX_STATE) {
 
113
            const pjsip_transaction *tsx = event->body.tsx_state.tsx;
 
114
 
 
115
            if (pjsip_method_cmp(&tsx->method, &pjsip_subscribe_method) == 0) {
 
116
                pres_client->term_code_ = tsx->status_code;
 
117
                std::ostringstream os;
 
118
                os << pres_client->term_code_;
 
119
                const std::string error = os.str() + "/" +
 
120
                    std::string(pres_client->term_reason_.ptr,
 
121
                            pres_client->term_reason_.slen);
 
122
 
 
123
                std::string msg;
 
124
                bool subscribe_allowed = PJ_FALSE;
 
125
 
 
126
                switch (tsx->status_code) {
 
127
                    case PJSIP_SC_CALL_TSX_DOES_NOT_EXIST:
 
128
                        /* 481: we refreshed too late? resubscribe
 
129
                         * immediately.
 
130
                         */
 
131
                        /* But this must only happen when the 481 is received
 
132
                         * on subscription refresh request. We MUST NOT try to
 
133
                         * resubscribe automatically if the 481 is received
 
134
                         * on the initial SUBSCRIBE (if server returns this
 
135
                         * response for some reason).
 
136
                         */
 
137
                        if (pres_client->dlg_->remote.contact)
 
138
                            resub_delay = 500;
 
139
                        msg = "Bad subscribe refresh.";
 
140
                        subscribe_allowed = PJ_TRUE;
 
141
                        break;
 
142
 
 
143
                    case PJSIP_SC_NOT_FOUND:
 
144
                        msg = "Subscribe context not set for this buddy.";
 
145
                        subscribe_allowed = PJ_TRUE;
 
146
                        break;
 
147
 
 
148
                    case PJSIP_SC_FORBIDDEN:
 
149
                        msg = "Subscribe not allowed for this buddy.";
 
150
                        subscribe_allowed = PJ_TRUE;
 
151
                        break;
 
152
 
 
153
                    case PJSIP_SC_PRECONDITION_FAILURE:
 
154
                        msg = "Wrong server.";
 
155
                        break;
 
156
                }
 
157
 
 
158
                /*  report error:
 
159
                 *  1) send a signal through DBus
 
160
                 *  2) change the support field in the account schema if the pres_sub's server
 
161
                 *  is the same as the account's server
 
162
                 */
 
163
                Manager::instance().getClient()->getPresenceManager()->serverError(
 
164
                        pres_client->getPresence()->getAccount()->getAccountID(),
 
165
                        error,
 
166
                        msg);
 
167
 
 
168
                std::string account_host = std::string(pj_gethostname()->ptr, pj_gethostname()->slen);
 
169
                std::string sub_host = sip_utils::getHostFromUri(pres_client->getURI());
 
170
 
 
171
                if((!subscribe_allowed) && (account_host == sub_host))
 
172
                    pres_client->getPresence()->getAccount()->supportPresence(PRESENCE_FUNCTION_SUBSCRIBE, false);
 
173
 
 
174
            } else if (pjsip_method_cmp(&tsx->method, &pjsip_notify_method) == 0) {
 
175
                if (pres_client->isTermReason("deactivated") || pres_client->isTermReason("timeout")) {
 
176
                    /* deactivated: The subscription has been terminated,
 
177
                     * but the subscriber SHOULD retry immediately with
 
178
                     * a new subscription.
 
179
                     */
 
180
                    /* timeout: The subscription has been terminated
 
181
                     * because it was not refreshed before it expired.
 
182
                     * Clients MAY re-subscribe immediately. The
 
183
                     * "retry-after" parameter has no semantics for
 
184
                     * "timeout".
 
185
                     */
 
186
                    resub_delay = 500;
 
187
                } else if (pres_client->isTermReason("probation") || pres_client->isTermReason("giveup")) {
 
188
                    /* probation: The subscription has been terminated,
 
189
                     * but the client SHOULD retry at some later time.
 
190
                     * If a "retry-after" parameter is also present, the
 
191
                     * client SHOULD wait at least the number of seconds
 
192
                     * specified by that parameter before attempting to re-
 
193
                     * subscribe.
 
194
                     */
 
195
                    /* giveup: The subscription has been terminated because
 
196
                     * the notifier could not obtain authorization in a
 
197
                     * timely fashion.  If a "retry-after" parameter is
 
198
                     * also present, the client SHOULD wait at least the
 
199
                     * number of seconds specified by that parameter before
 
200
                     * attempting to re-subscribe; otherwise, the client
 
201
                     * MAY retry immediately, but will likely get put back
 
202
                     * into pending state.
 
203
                     */
 
204
                    const pjsip_sub_state_hdr *sub_hdr;
 
205
                    pj_str_t sub_state = CONST_PJ_STR("Subscription-State");
 
206
                    const pjsip_msg *msg;
 
207
 
 
208
                    msg = event->body.tsx_state.src.rdata->msg_info.msg;
 
209
                    sub_hdr = (const pjsip_sub_state_hdr*) pjsip_msg_find_hdr_by_name(msg, &sub_state, NULL);
 
210
 
 
211
                    if (sub_hdr && sub_hdr->retry_after > 0)
 
212
                        resub_delay = sub_hdr->retry_after * 1000;
 
213
                }
 
214
 
 
215
            }
 
216
        }
 
217
 
 
218
        /* For other cases of subscription termination, if resubscribe
 
219
         * timer is not set, schedule with default expiration (plus minus
 
220
         * some random value, to avoid sending SUBSCRIBEs all at once)
 
221
         */
 
222
        if (resub_delay == -1) {
 
223
            resub_delay = PRES_TIMER * 1000;
 
224
        }
 
225
 
 
226
        pres_client->sub_ = sub;
 
227
        pres_client->rescheduleTimer(PJ_TRUE, resub_delay);
 
228
 
 
229
    } else { //state==ACTIVE ......
 
230
        //This will clear the last termination code/reason
 
231
        pres_client->term_code_ = 0;
 
232
        pres_client->term_reason_.ptr = NULL;
 
233
    }
 
234
 
 
235
    /* Clear subscription */
 
236
    if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
 
237
        pjsip_evsub_terminate(pres_client->sub_, PJ_FALSE); // = NULL;
 
238
        pres_client->status_.info_cnt = 0;
 
239
        pres_client->dlg_ = NULL;
 
240
        pres_client->rescheduleTimer(PJ_FALSE, 0);
 
241
        pjsip_evsub_set_mod_data(sub, modId_, NULL);
 
242
 
 
243
        pres_client->enable(false);
 
244
    }
 
245
}
 
246
 
 
247
/* Callback when transaction state has changed. */
 
248
    void
 
249
PresSubClient::pres_client_evsub_on_tsx_state(pjsip_evsub *sub, pjsip_transaction *tsx, pjsip_event *event)
 
250
{
 
251
 
 
252
    PresSubClient *pres_client;
 
253
    pjsip_contact_hdr *contact_hdr;
 
254
 
 
255
    pres_client = (PresSubClient *) pjsip_evsub_get_mod_data(sub, modId_);
 
256
    /* No need to pres->lock() here since the client has a locked dialog*/
 
257
 
 
258
    if (!pres_client) {
 
259
        WARN("Couldn't find pres_client.");
 
260
        return;
 
261
    }
 
262
 
 
263
    /* We only use this to update pres_client's Contact, when it's not
 
264
     * set.
 
265
     */
 
266
    if (pres_client->contact_.slen != 0) {
 
267
        /* Contact already set */
 
268
        return;
 
269
    }
 
270
 
 
271
    /* Only care about 2xx response to outgoing SUBSCRIBE */
 
272
    if (tsx->status_code / 100 != 2 || tsx->role != PJSIP_UAC_ROLE || event->type != PJSIP_EVENT_RX_MSG
 
273
            || pjsip_method_cmp(&tsx->method, pjsip_get_subscribe_method()) != 0) {
 
274
        return;
 
275
    }
 
276
 
 
277
    /* Find contact header. */
 
278
    contact_hdr = (pjsip_contact_hdr*) pjsip_msg_find_hdr(event->body.rx_msg.rdata->msg_info.msg, PJSIP_H_CONTACT,
 
279
                  NULL);
 
280
 
 
281
    if (!contact_hdr || !contact_hdr->uri) {
 
282
        return;
 
283
    }
 
284
 
 
285
    pres_client->contact_.ptr = (char*) pj_pool_alloc(pres_client->pool_, PJSIP_MAX_URL_SIZE);
 
286
    pres_client->contact_.slen = pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, contact_hdr->uri, pres_client->contact_.ptr,
 
287
                                PJSIP_MAX_URL_SIZE);
 
288
 
 
289
    if (pres_client->contact_.slen < 0)
 
290
        pres_client->contact_.slen = 0;
 
291
 
 
292
}
 
293
 
 
294
/* Callback called when we receive NOTIFY */
 
295
void
 
296
PresSubClient::pres_client_evsub_on_rx_notify(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
 
297
{
 
298
 
 
299
    PresSubClient *pres_client = (PresSubClient *) pjsip_evsub_get_mod_data(sub, modId_);
 
300
 
 
301
    if (!pres_client) {
 
302
        WARN("Couldn't find pres_client from ev_sub.");
 
303
        return;
 
304
    }
 
305
    /* No need to pres->lock() here since the client has a locked dialog*/
 
306
 
 
307
    pjsip_pres_get_status(sub, &pres_client->status_);
 
308
    pres_client->reportPresence();
 
309
 
 
310
    /* The default is to send 200 response to NOTIFY.
 
311
     * Just leave it there..
 
312
     */
 
313
    PJ_UNUSED_ARG(rdata);
 
314
    PJ_UNUSED_ARG(p_st_code);
 
315
    PJ_UNUSED_ARG(p_st_text);
 
316
    PJ_UNUSED_ARG(res_hdr);
 
317
    PJ_UNUSED_ARG(p_body);
 
318
}
 
319
 
 
320
PresSubClient::PresSubClient(const std::string& uri, SIPPresence *pres) :
 
321
    pres_(pres),
 
322
    uri_{0, 0},
 
323
    contact_{0, 0},
 
324
    display_(),
 
325
    dlg_(NULL),
 
326
    monitored_(false),
 
327
    name_(),
 
328
    cp_(),
 
329
    pool_(0),
 
330
    status_(),
 
331
    sub_(NULL),
 
332
    term_code_(0),
 
333
    term_reason_(),
 
334
    timer_(),
 
335
    user_data_(NULL),
 
336
    lock_count_(0),
 
337
    lock_flag_(0)
 
338
{
 
339
    pj_caching_pool_init(&cp_, &pj_pool_factory_default_policy, 0);
 
340
    pool_ = pj_pool_create(&cp_.factory, "Pres_sub_client", 512, 512, NULL);
 
341
    uri_ = pj_strdup3(pool_, uri.c_str());
 
342
    contact_ = pj_strdup3(pool_, pres_->getAccount()->getFromUri().c_str());
 
343
}
 
344
 
 
345
PresSubClient::~PresSubClient()
 
346
{
 
347
    DEBUG("Destroying pres_client object with uri %.*s", uri_.slen, uri_.ptr);
 
348
    rescheduleTimer(PJ_FALSE, 0);
 
349
    unsubscribe();
 
350
    pj_pool_release(pool_);
 
351
}
 
352
 
 
353
bool PresSubClient::isSubscribed()
 
354
{
 
355
    return monitored_;
 
356
}
 
357
 
 
358
std::string PresSubClient::getURI()
 
359
{
 
360
    std::string res(uri_.ptr, uri_.slen);
 
361
    return res;
 
362
}
 
363
 
 
364
SIPPresence * PresSubClient::getPresence()
 
365
{
 
366
    return pres_;
 
367
}
 
368
 
 
369
bool PresSubClient::isPresent()
 
370
{
 
371
    return status_.info[0].basic_open;
 
372
}
 
373
 
 
374
std::string PresSubClient::getLineStatus()
 
375
{
 
376
    return std::string(status_.info[0].rpid.note.ptr, status_.info[0].rpid.note.slen);
 
377
}
 
378
 
 
379
bool PresSubClient::isTermReason(const std::string &reason)
 
380
{
 
381
    const std::string myReason(term_reason_.ptr, term_reason_.slen);
 
382
    return not myReason.compare(reason);
 
383
}
 
384
 
 
385
void PresSubClient::rescheduleTimer(bool reschedule, unsigned msec)
 
386
{
 
387
    SIPAccount * acc = pres_->getAccount();
 
388
 
 
389
    if (timer_.id) {
 
390
        pjsip_endpt_cancel_timer(((SIPVoIPLink*) acc->getVoIPLink())->getEndpoint(), &timer_);
 
391
        timer_.id = PJ_FALSE;
 
392
    }
 
393
 
 
394
    if (reschedule) {
 
395
        pj_time_val delay;
 
396
 
 
397
        WARN("pres_client  %.*s will resubscribe in %u ms (reason: %.*s)",
 
398
             uri_.slen, uri_.ptr, msec, (int) term_reason_.slen, term_reason_.ptr);
 
399
        pj_timer_entry_init(&timer_, 0, this, &pres_client_timer_cb);
 
400
        delay.sec = 0;
 
401
        delay.msec = msec;
 
402
        pj_time_val_normalize(&delay);
 
403
 
 
404
        if (pjsip_endpt_schedule_timer(((SIPVoIPLink*) acc->getVoIPLink())->getEndpoint(), &timer_, &delay) == PJ_SUCCESS) {
 
405
            timer_.id = PJ_TRUE;
 
406
        }
 
407
    }
 
408
}
 
409
 
 
410
void PresSubClient::enable(bool flag)
 
411
{
 
412
    DEBUG("pres_client %s is %s monitored.",getURI().c_str(), flag? "":"NOT");
 
413
    if(flag && !monitored_)
 
414
        pres_->addPresSubClient(this);
 
415
    monitored_ = flag;
 
416
}
 
417
 
 
418
void PresSubClient::reportPresence()
 
419
{
 
420
    /* callback*/
 
421
    pres_->reportPresSubClientNotification(getURI(), &status_);
 
422
}
 
423
 
 
424
bool PresSubClient::lock()
 
425
{
 
426
    unsigned i;
 
427
 
 
428
    for(i=0; i<50; i++)
 
429
    {
 
430
        if(!(pres_->tryLock())){
 
431
            pj_thread_sleep(i/10);
 
432
            continue;
 
433
        }
 
434
        lock_flag_ = PRESENCE_LOCK_FLAG;
 
435
 
 
436
        if (dlg_ == NULL)
 
437
            return true;
 
438
 
 
439
        if (pjsip_dlg_try_inc_lock(dlg_) != PJ_SUCCESS) {
 
440
            lock_flag_ = 0;
 
441
            pres_->unlock();
 
442
            pj_thread_sleep(i/10);
 
443
            continue;
 
444
        }
 
445
 
 
446
        lock_flag_ = PRESENCE_CLIENT_LOCK_FLAG;
 
447
        pres_->unlock();
 
448
    }
 
449
 
 
450
    if(lock_flag_ == 0)
 
451
    {
 
452
        DEBUG("pres_client failed to lock : timeout");
 
453
        return false;
 
454
    }
 
455
    return true;
 
456
}
 
457
 
 
458
void PresSubClient::unlock()
 
459
{
 
460
    if (lock_flag_ & PRESENCE_CLIENT_LOCK_FLAG)
 
461
        pjsip_dlg_dec_lock(dlg_);
 
462
 
 
463
    if (lock_flag_ & PRESENCE_LOCK_FLAG)
 
464
        pres_->unlock();
 
465
}
 
466
 
 
467
bool PresSubClient::unsubscribe()
 
468
{
 
469
    if(!lock())
 
470
        return false;
 
471
 
 
472
    monitored_ = false;
 
473
 
 
474
    pjsip_tx_data *tdata;
 
475
    pj_status_t retStatus;
 
476
 
 
477
    if (sub_ == NULL or dlg_ == NULL) {
 
478
        WARN("PresSubClient already unsubscribed.");
 
479
        unlock();
 
480
        return false;
 
481
    }
 
482
 
 
483
    if (pjsip_evsub_get_state(sub_) == PJSIP_EVSUB_STATE_TERMINATED) {
 
484
        WARN("pres_client already unsubscribed sub=TERMINATED.");
 
485
        sub_ = NULL;
 
486
        unlock();
 
487
        return false;
 
488
    }
 
489
 
 
490
    /* Unsubscribe means send a subscribe with timeout=0s*/
 
491
    WARN("pres_client %.*s: unsubscribing..", uri_.slen, uri_.ptr);
 
492
    retStatus = pjsip_pres_initiate(sub_, 0, &tdata);
 
493
 
 
494
    if (retStatus == PJ_SUCCESS) {
 
495
        pres_->fillDoc(tdata, NULL);
 
496
        retStatus = pjsip_pres_send_request(sub_, tdata);
 
497
    }
 
498
 
 
499
    if (retStatus != PJ_SUCCESS and sub_) {
 
500
        pjsip_pres_terminate(sub_, PJ_FALSE);
 
501
        sub_ = NULL;
 
502
        WARN("Unable to unsubscribe presence", retStatus);
 
503
        unlock();
 
504
        return false;
 
505
    }
 
506
 
 
507
    //pjsip_evsub_set_mod_data(sub_, modId_, NULL);   // Not interested with further events
 
508
 
 
509
    unlock();
 
510
    return true;
 
511
}
 
512
 
 
513
 
 
514
bool PresSubClient::subscribe()
 
515
{
 
516
 
 
517
    if (sub_ and dlg_) { //do not bother if already subscribed
 
518
        pjsip_evsub_terminate(sub_, PJ_FALSE);
 
519
        DEBUG("PreseSubClient %.*s: already subscribed. Refresh it.", uri_.slen, uri_.ptr);
 
520
    }
 
521
 
 
522
    //subscribe
 
523
    pjsip_evsub_user pres_callback;
 
524
    pjsip_tx_data *tdata;
 
525
    pj_status_t status;
 
526
 
 
527
    /* Event subscription callback. */
 
528
    pj_bzero(&pres_callback, sizeof(pres_callback));
 
529
    pres_callback.on_evsub_state = &pres_client_evsub_on_state;
 
530
    pres_callback.on_tsx_state = &pres_client_evsub_on_tsx_state;
 
531
    pres_callback.on_rx_notify = &pres_client_evsub_on_rx_notify;
 
532
 
 
533
    SIPAccount * acc = pres_->getAccount();
 
534
    DEBUG("PresSubClient %.*s: subscribing ", uri_.slen, uri_.ptr);
 
535
 
 
536
 
 
537
    /* Create UAC dialog */
 
538
    pj_str_t from = pj_strdup3(pool_, acc->getFromUri().c_str());
 
539
    status = pjsip_dlg_create_uac(pjsip_ua_instance(), &from, &contact_, &uri_, NULL, &dlg_);
 
540
 
 
541
    if (status != PJ_SUCCESS) {
 
542
        ERROR("Unable to create dialog \n");
 
543
        return false;
 
544
    }
 
545
 
 
546
    /* Add credential for auth. */
 
547
    if (acc->hasCredentials() and pjsip_auth_clt_set_credentials(&dlg_->auth_sess, acc->getCredentialCount(), acc->getCredInfo()) != PJ_SUCCESS) {
 
548
        ERROR("Could not initialize credentials for subscribe session authentication");
 
549
    }
 
550
 
 
551
    /* Increment the dialog's lock otherwise when presence session creation
 
552
     * fails the dialog will be destroyed prematurely.
 
553
     */
 
554
    pjsip_dlg_inc_lock(dlg_);
 
555
 
 
556
    status = pjsip_pres_create_uac(dlg_, &pres_callback, PJSIP_EVSUB_NO_EVENT_ID, &sub_);
 
557
 
 
558
    if (status != PJ_SUCCESS) {
 
559
        sub_ = NULL;
 
560
        WARN("Unable to create presence client", status);
 
561
 
 
562
        /* This should destroy the dialog since there's no session
 
563
         * referencing it
 
564
         */
 
565
        if (dlg_) {
 
566
            pjsip_dlg_dec_lock(dlg_);
 
567
        }
 
568
 
 
569
        return false;
 
570
    }
 
571
 
 
572
    /* Add credential for authentication */
 
573
    if (acc->hasCredentials() and pjsip_auth_clt_set_credentials(&dlg_->auth_sess, acc->getCredentialCount(), acc->getCredInfo()) != PJ_SUCCESS) {
 
574
        ERROR("Could not initialize credentials for invite session authentication");
 
575
        return false;
 
576
    }
 
577
 
 
578
    /* Set route-set */
 
579
    pjsip_regc *regc = acc->getRegistrationInfo();
 
580
    if (regc and acc->hasServiceRoute())
 
581
        pjsip_regc_set_route_set(regc, sip_utils::createRouteSet(acc->getServiceRoute(), pres_->getPool()));
 
582
 
 
583
    // attach the client data to the sub
 
584
    pjsip_evsub_set_mod_data(sub_, modId_, this);
 
585
 
 
586
    status = pjsip_pres_initiate(sub_, -1, &tdata);
 
587
    if (status != PJ_SUCCESS) {
 
588
        if (dlg_)
 
589
            pjsip_dlg_dec_lock(dlg_);
 
590
        if (sub_)
 
591
            pjsip_pres_terminate(sub_, PJ_FALSE);
 
592
        sub_ = NULL;
 
593
        WARN("Unable to create initial SUBSCRIBE", status);
 
594
        return false;
 
595
    }
 
596
 
 
597
//    pjsua_process_msg_data(tdata, NULL);
 
598
 
 
599
    status = pjsip_pres_send_request(sub_, tdata);
 
600
 
 
601
    if (status != PJ_SUCCESS) {
 
602
        if (dlg_)
 
603
            pjsip_dlg_dec_lock(dlg_);
 
604
        if (sub_)
 
605
            pjsip_pres_terminate(sub_, PJ_FALSE);
 
606
        sub_ = NULL;
 
607
        WARN("Unable to send initial SUBSCRIBE", status);
 
608
        return false;
 
609
    }
 
610
 
 
611
    pjsip_dlg_dec_lock(dlg_);
 
612
    return true;
 
613
}
 
614
 
 
615
bool PresSubClient::match(PresSubClient *b)
 
616
{
 
617
    return (b->getURI() == getURI());
 
618
}