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

« back to all changes in this revision

Viewing changes to daemon/src/sip/sippresence.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) 2004-2013 Savoir-Faire Linux Inc.
 
3
 *
 
4
 *  Author: Patrick Keroulas  <patrick.keroulas@savoirfairelinux.com>
 
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 3 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
 
19
 *
 
20
 *  Additional permission under GNU GPL version 3 section 7:
 
21
 *
 
22
 *  If you modify this program, 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, Savoir-Faire Linux Inc.
 
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
 
 
33
#include "sippresence.h"
 
34
 
 
35
#include <sstream>
 
36
#include "logger.h"
 
37
#include "manager.h"
 
38
#include "client/client.h"
 
39
#include "client/presencemanager.h"
 
40
#include "client/configurationmanager.h"
 
41
#include "sipaccount.h"
 
42
#include "sip_utils.h"
 
43
#include "pres_sub_server.h"
 
44
#include "pres_sub_client.h"
 
45
#include "sipvoiplink.h"
 
46
 
 
47
#define MAX_N_SUB_SERVER 50
 
48
#define MAX_N_SUB_CLIENT 50
 
49
 
 
50
SIPPresence::SIPPresence(SIPAccount *acc)
 
51
    : publish_sess_()
 
52
    , status_data_()
 
53
    , enabled_(false)
 
54
    , publish_supported_(false)
 
55
    , subscribe_supported_(false)
 
56
    , status_(false)
 
57
    , note_(" ")
 
58
    , acc_(acc)
 
59
    , sub_server_list_()  //IP2IP context
 
60
    , sub_client_list_()
 
61
    , mutex_()
 
62
    , mutex_nesting_level_()
 
63
    , mutex_owner_()
 
64
    , cp_()
 
65
    , pool_()
 
66
{
 
67
    /* init pool */
 
68
    pj_caching_pool_init(&cp_, &pj_pool_factory_default_policy, 0);
 
69
    pool_ = pj_pool_create(&cp_.factory, "pres", 1000, 1000, NULL);
 
70
    if (!pool_)
 
71
        throw std::runtime_error("Could not allocate pool for presence");
 
72
 
 
73
    /* Create mutex */
 
74
    if (pj_mutex_create_recursive(pool_, "pres", &mutex_) != PJ_SUCCESS) {
 
75
        pj_pool_release(pool_);
 
76
        pj_caching_pool_destroy(&cp_);
 
77
        throw std::runtime_error("Unable to create mutex");
 
78
    }
 
79
 
 
80
    /* init default status */
 
81
    updateStatus(false, " ");
 
82
}
 
83
 
 
84
 
 
85
SIPPresence::~SIPPresence()
 
86
{
 
87
    /* Flush the lists */
 
88
    // FIXME: Can't destroy/unsubscribe buddies properly.
 
89
    // Is the transport usable when the account is being destroyed?
 
90
    //for (const auto & c : sub_client_list_)
 
91
    //    delete(c);
 
92
    sub_client_list_.clear();
 
93
    sub_server_list_.clear();
 
94
 
 
95
    if (mutex_ and pj_mutex_destroy(mutex_) != PJ_SUCCESS)
 
96
        ERROR("Error destroying mutex");
 
97
 
 
98
    pj_pool_release(pool_);
 
99
    pj_caching_pool_destroy(&cp_);
 
100
}
 
101
 
 
102
SIPAccount * SIPPresence::getAccount() const
 
103
{
 
104
    return acc_;
 
105
}
 
106
 
 
107
pjsip_pres_status * SIPPresence::getStatus()
 
108
{
 
109
    return &status_data_;
 
110
}
 
111
 
 
112
int SIPPresence::getModId() const
 
113
{
 
114
    return ((SIPVoIPLink*)(acc_->getVoIPLink()))->getModId();
 
115
}
 
116
 
 
117
pj_pool_t*  SIPPresence::getPool() const
 
118
{
 
119
    return pool_;
 
120
}
 
121
 
 
122
void SIPPresence::enable(bool enabled)
 
123
{
 
124
    enabled_ = enabled;
 
125
}
 
126
 
 
127
void SIPPresence::support(int function, bool supported)
 
128
{
 
129
    if(function == PRESENCE_FUNCTION_PUBLISH)
 
130
        publish_supported_ = supported;
 
131
    else if(function == PRESENCE_FUNCTION_SUBSCRIBE)
 
132
        subscribe_supported_ = supported;
 
133
}
 
134
 
 
135
bool SIPPresence::isSupported(int function)
 
136
{
 
137
    if(function == PRESENCE_FUNCTION_PUBLISH)
 
138
        return publish_supported_;
 
139
    else if(function == PRESENCE_FUNCTION_SUBSCRIBE)
 
140
        return subscribe_supported_;
 
141
 
 
142
    return false;
 
143
}
 
144
 
 
145
void SIPPresence::updateStatus(bool status, const std::string &note)
 
146
{
 
147
    //char* pj_note  = (char*) pj_pool_alloc(pool_, "50");
 
148
 
 
149
    pjrpid_element rpid = {
 
150
        PJRPID_ELEMENT_TYPE_PERSON,
 
151
        CONST_PJ_STR("0"),
 
152
        PJRPID_ACTIVITY_UNKNOWN,
 
153
        pj_str((char *) note.c_str())
 
154
    };
 
155
 
 
156
    /* fill activity if user not available. */
 
157
    if (note == "away")
 
158
        rpid.activity = PJRPID_ACTIVITY_AWAY;
 
159
    else if (note == "busy")
 
160
        rpid.activity = PJRPID_ACTIVITY_BUSY;
 
161
    /*
 
162
    else // TODO: is there any other possibilities
 
163
        DEBUG("Presence : no activity");
 
164
    */
 
165
 
 
166
    pj_bzero(&status_data_, sizeof(status_data_));
 
167
    status_data_.info_cnt = 1;
 
168
    status_data_.info[0].basic_open = status;
 
169
 
 
170
    // at most we will have 3 digits + NULL termination
 
171
    char buf[4];
 
172
    pj_utoa(rand() % 1000, buf);
 
173
    status_data_.info[0].id = pj_strdup3(pool_, buf);
 
174
 
 
175
    pj_memcpy(&status_data_.info[0].rpid, &rpid, sizeof(pjrpid_element));
 
176
    /* "contact" field is optionnal */
 
177
}
 
178
 
 
179
void SIPPresence::sendPresence(bool status, const std::string &note)
 
180
{
 
181
    updateStatus(status, note);
 
182
 
 
183
    //if ((not publish_supported_) or (not enabled_))
 
184
    //    return;
 
185
 
 
186
    if (acc_->isIP2IP())
 
187
        notifyPresSubServer(); // to each subscribers
 
188
    else
 
189
        publish(this); // to the PBX server
 
190
}
 
191
 
 
192
 
 
193
void SIPPresence::reportPresSubClientNotification(const std::string& uri, pjsip_pres_status * status)
 
194
{
 
195
    /* Update our info. See pjsua_buddy_get_info() for additionnal ideas*/
 
196
    const std::string acc_ID = acc_->getAccountID();
 
197
    const std::string basic(status->info[0].basic_open ? "open" : "closed");
 
198
    const std::string note(status->info[0].rpid.note.ptr, status->info[0].rpid.note.slen);
 
199
    DEBUG(" Received status of PresSubClient  %s(acc:%s): status=%s note=%s", uri.c_str(), acc_ID.c_str(), basic.c_str(), note.c_str());
 
200
 
 
201
    if(uri == acc_->getFromUri())
 
202
    {
 
203
        // save the status of our own account
 
204
        status_ = status->info[0].basic_open;
 
205
        note_ = note;
 
206
    }
 
207
    // report status to client signal
 
208
    Manager::instance().getClient()->getPresenceManager()->newBuddyNotification(acc_ID, uri, status->info[0].basic_open, note);
 
209
}
 
210
 
 
211
void SIPPresence::subscribeClient(const std::string& uri, bool flag)
 
212
{
 
213
    /* if an account has a server that doesn't support SUBSCRIBE, it's still possible
 
214
     * to subscribe to someone on another server */
 
215
    /*
 
216
    std::string account_host = std::string(pj_gethostname()->ptr, pj_gethostname()->slen);
 
217
    std::string sub_host = sip_utils::getHostFromUri(uri);
 
218
    if (((not subscribe_supported_) && (account_host == sub_host))
 
219
            or (not enabled_))
 
220
        return;
 
221
    */
 
222
 
 
223
    /* Check if the buddy was already subscribed */
 
224
    for (const auto & c : sub_client_list_) {
 
225
        if (c->getURI() == uri) {
 
226
            //DEBUG("-PresSubClient:%s exists in the list. Replace it.", uri.c_str());
 
227
            if(flag)
 
228
                c->subscribe();
 
229
            else
 
230
                c->unsubscribe();
 
231
            return;
 
232
        }
 
233
    }
 
234
 
 
235
    if (sub_client_list_.size() >= MAX_N_SUB_CLIENT) {
 
236
        WARN("Can't add PresSubClient, max number reached.");
 
237
        return;
 
238
    }
 
239
 
 
240
    if (flag) {
 
241
        PresSubClient *c = new PresSubClient(uri, this);
 
242
        if (!(c->subscribe())) {
 
243
            WARN("Failed send subscribe.");
 
244
            delete c;
 
245
        }
 
246
        // the buddy has to be accepted before being added in the list
 
247
    }
 
248
}
 
249
 
 
250
void SIPPresence::addPresSubClient(PresSubClient *c)
 
251
{
 
252
    if (sub_client_list_.size() < MAX_N_SUB_CLIENT) {
 
253
        sub_client_list_.push_back(c);
 
254
        DEBUG("New Presence_subscription_client added (list[%i]).", sub_client_list_.size());
 
255
    } else {
 
256
        WARN("Max Presence_subscription_client is reach.");
 
257
        // let the client alive //delete c;
 
258
    }
 
259
}
 
260
 
 
261
void SIPPresence::removePresSubClient(PresSubClient *c)
 
262
{
 
263
    DEBUG("Remove Presence_subscription_client from the buddy list.");
 
264
    sub_client_list_.remove(c);
 
265
}
 
266
 
 
267
void SIPPresence::approvePresSubServer(const std::string& uri, bool flag)
 
268
{
 
269
    for (const auto & s : sub_server_list_) {
 
270
        if (s->matches((char *) uri.c_str())) {
 
271
            s->approve(flag);
 
272
            // return; // 'return' would prevent multiple-time subscribers from spam
 
273
        }
 
274
    }
 
275
}
 
276
 
 
277
 
 
278
void SIPPresence::addPresSubServer(PresSubServer *s)
 
279
{
 
280
    if (sub_server_list_.size() < MAX_N_SUB_SERVER) {
 
281
        sub_server_list_.push_back(s);
 
282
    } else {
 
283
        WARN("Max Presence_subscription_server is reach.");
 
284
        // let de server alive // delete s;
 
285
    }
 
286
}
 
287
 
 
288
void SIPPresence::removePresSubServer(PresSubServer *s)
 
289
{
 
290
    sub_server_list_.remove(s);
 
291
    DEBUG("Presence_subscription_server removed");
 
292
}
 
293
 
 
294
void SIPPresence::notifyPresSubServer()
 
295
{
 
296
    DEBUG("Iterating through IP2IP Presence_subscription_server:");
 
297
 
 
298
    for (const auto & s : sub_server_list_)
 
299
        s->notify();
 
300
}
 
301
 
 
302
void SIPPresence::lock()
 
303
{
 
304
    pj_mutex_lock(mutex_);
 
305
    mutex_owner_ = pj_thread_this();
 
306
    ++mutex_nesting_level_;
 
307
}
 
308
 
 
309
bool SIPPresence::tryLock()
 
310
{
 
311
    pj_status_t status;
 
312
    status = pj_mutex_trylock(mutex_);
 
313
    if (status == PJ_SUCCESS) {
 
314
        mutex_owner_ = pj_thread_this();
 
315
        ++mutex_nesting_level_;
 
316
    }
 
317
    return status==PJ_SUCCESS;
 
318
}
 
319
 
 
320
void SIPPresence::unlock()
 
321
{
 
322
    if (--mutex_nesting_level_ == 0)
 
323
        mutex_owner_ = NULL;
 
324
 
 
325
    pj_mutex_unlock(mutex_);
 
326
}
 
327
 
 
328
void SIPPresence::fillDoc(pjsip_tx_data *tdata, const pres_msg_data *msg_data)
 
329
{
 
330
 
 
331
    if (tdata->msg->type == PJSIP_REQUEST_MSG) {
 
332
        const pj_str_t STR_USER_AGENT = CONST_PJ_STR("User-Agent");
 
333
        std::string useragent(acc_->getUserAgentName());
 
334
        pj_str_t pJuseragent = pj_str((char*) useragent.c_str());
 
335
        pjsip_hdr *h = (pjsip_hdr*) pjsip_generic_string_hdr_create(tdata->pool, &STR_USER_AGENT, &pJuseragent);
 
336
        pjsip_msg_add_hdr(tdata->msg, h);
 
337
    }
 
338
 
 
339
    if (msg_data == NULL)
 
340
        return;
 
341
 
 
342
    const pjsip_hdr *hdr;
 
343
    hdr = msg_data->hdr_list.next;
 
344
 
 
345
    while (hdr && hdr != &msg_data->hdr_list) {
 
346
        pjsip_hdr *new_hdr;
 
347
        new_hdr = (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, hdr);
 
348
        DEBUG("adding header", new_hdr->name.ptr);
 
349
        pjsip_msg_add_hdr(tdata->msg, new_hdr);
 
350
        hdr = hdr->next;
 
351
    }
 
352
 
 
353
    if (msg_data->content_type.slen && msg_data->msg_body.slen) {
 
354
        pjsip_msg_body *body;
 
355
        const pj_str_t type = CONST_PJ_STR("application");
 
356
        const pj_str_t subtype = CONST_PJ_STR("pidf+xml");
 
357
        body = pjsip_msg_body_create(tdata->pool, &type, &subtype, &msg_data->msg_body);
 
358
        tdata->msg->body = body;
 
359
    }
 
360
}
 
361
 
 
362
static const pjsip_publishc_opt my_publish_opt = {true}; // this is queue_request
 
363
 
 
364
/*
 
365
 * Client presence publication callback.
 
366
 */
 
367
void
 
368
SIPPresence::publish_cb(struct pjsip_publishc_cbparam *param)
 
369
{
 
370
    SIPPresence *pres = (SIPPresence*) param->token;
 
371
 
 
372
    if (param->code / 100 != 2 || param->status != PJ_SUCCESS) {
 
373
 
 
374
        pjsip_publishc_destroy(param->pubc);
 
375
        pres->publish_sess_ = NULL;
 
376
        std::ostringstream os;
 
377
        os << param->code;
 
378
        const std::string error = os.str() + " / "+ std::string(param->reason.ptr, param->reason.slen);
 
379
 
 
380
        if (param->status != PJ_SUCCESS) {
 
381
            char errmsg[PJ_ERR_MSG_SIZE];
 
382
            pj_strerror(param->status, errmsg, sizeof(errmsg));
 
383
            ERROR("Client (PUBLISH) failed, status=%d, msg=%s", param->status, errmsg);
 
384
            Manager::instance().getClient()->getPresenceManager()->serverError(
 
385
                    pres->getAccount()->getAccountID(),
 
386
                    error,
 
387
                    errmsg);
 
388
 
 
389
        } else if (param->code == 412) {
 
390
            /* 412 (Conditional Request Failed)
 
391
             * The PUBLISH refresh has failed, retry with new one.
 
392
             */
 
393
            WARN("Publish retry.");
 
394
            publish(pres);
 
395
        } else if ((param->code == PJSIP_SC_BAD_EVENT) || (param->code == PJSIP_SC_NOT_IMPLEMENTED)){ //489 or 501
 
396
            WARN("Client (PUBLISH) failed (%s)",error.c_str());
 
397
 
 
398
            Manager::instance().getClient()->getPresenceManager()->serverError(
 
399
                    pres->getAccount()->getAccountID(),
 
400
                    error,
 
401
                    "Publish not supported.");
 
402
 
 
403
            pres->getAccount()->supportPresence(PRESENCE_FUNCTION_PUBLISH, false);
 
404
        }
 
405
 
 
406
    } else {
 
407
        if (param->expiration < 1) {
 
408
            /* Could happen if server "forgot" to include Expires header
 
409
             * in the response. We will not renew, so destroy the pubc.
 
410
             */
 
411
            pjsip_publishc_destroy(param->pubc);
 
412
            pres->publish_sess_ = NULL;
 
413
        }
 
414
 
 
415
        pres->getAccount()->supportPresence(PRESENCE_FUNCTION_PUBLISH, true);
 
416
    }
 
417
}
 
418
 
 
419
/*
 
420
 * Send PUBLISH request.
 
421
 */
 
422
pj_status_t
 
423
SIPPresence::send_publish(SIPPresence * pres)
 
424
{
 
425
    pjsip_tx_data *tdata;
 
426
    pj_status_t status;
 
427
 
 
428
    DEBUG("Send PUBLISH (%s).", pres->getAccount()->getAccountID().c_str());
 
429
 
 
430
    SIPAccount * acc = pres->getAccount();
 
431
    std::string contactWithAngles =  acc->getFromUri();
 
432
    contactWithAngles.erase(contactWithAngles.find('>'));
 
433
    int semicolon = contactWithAngles.find_first_of(":");
 
434
    std::string contactWithoutAngles = contactWithAngles.substr(semicolon + 1);
 
435
//    pj_str_t contact = pj_str(strdup(contactWithoutAngles.c_str()));
 
436
//    pj_memcpy(&status_data.info[0].contact, &contt, sizeof(pj_str_t));;
 
437
 
 
438
    /* Create PUBLISH request */
 
439
    char *bpos;
 
440
    pj_str_t entity;
 
441
 
 
442
    status = pjsip_publishc_publish(pres->publish_sess_, PJ_TRUE, &tdata);
 
443
    pj_str_t from = pj_strdup3(pres->pool_, acc->getFromUri().c_str());
 
444
 
 
445
    if (status != PJ_SUCCESS) {
 
446
        ERROR("Error creating PUBLISH request", status);
 
447
        goto on_error;
 
448
    }
 
449
 
 
450
    if ((bpos = pj_strchr(&from, '<')) != NULL) {
 
451
        char *epos = pj_strchr(&from, '>');
 
452
 
 
453
        if (epos - bpos < 2) {
 
454
            pj_assert(!"Unexpected invalid URI");
 
455
            status = PJSIP_EINVALIDURI;
 
456
            goto on_error;
 
457
        }
 
458
 
 
459
        entity.ptr = bpos + 1;
 
460
        entity.slen = epos - bpos - 1;
 
461
    } else {
 
462
        entity = from;
 
463
    }
 
464
 
 
465
    /* Create and add PIDF message body */
 
466
    status = pjsip_pres_create_pidf(tdata->pool, pres->getStatus(),
 
467
                                    &entity, &tdata->msg->body);
 
468
 
 
469
    pres_msg_data msg_data;
 
470
 
 
471
    if (status != PJ_SUCCESS) {
 
472
        ERROR("Error creating PIDF for PUBLISH request");
 
473
        pjsip_tx_data_dec_ref(tdata);
 
474
        goto on_error;
 
475
    }
 
476
 
 
477
    pj_bzero(&msg_data, sizeof(msg_data));
 
478
    pj_list_init(&msg_data.hdr_list);
 
479
    pjsip_media_type_init(&msg_data.multipart_ctype, NULL, NULL);
 
480
    pj_list_init(&msg_data.multipart_parts);
 
481
 
 
482
    pres->fillDoc(tdata, &msg_data);
 
483
 
 
484
    /* Send the PUBLISH request */
 
485
    status = pjsip_publishc_send(pres->publish_sess_, tdata);
 
486
 
 
487
    if (status == PJ_EPENDING) {
 
488
        WARN("Previous request is in progress, ");
 
489
    } else if (status != PJ_SUCCESS) {
 
490
        ERROR("Error sending PUBLISH request");
 
491
        goto on_error;
 
492
    }
 
493
 
 
494
    return PJ_SUCCESS;
 
495
 
 
496
on_error:
 
497
 
 
498
    if (pres->publish_sess_) {
 
499
        pjsip_publishc_destroy(pres->publish_sess_);
 
500
        pres->publish_sess_ = NULL;
 
501
    }
 
502
 
 
503
    return status;
 
504
}
 
505
 
 
506
 
 
507
/* Create client publish session */
 
508
pj_status_t
 
509
SIPPresence::publish(SIPPresence *pres)
 
510
{
 
511
    pj_status_t status;
 
512
    const pj_str_t STR_PRESENCE = CONST_PJ_STR("presence");
 
513
    SIPAccount * acc = pres->getAccount();
 
514
    pjsip_endpoint *endpt = ((SIPVoIPLink*) acc->getVoIPLink())->getEndpoint();
 
515
 
 
516
    /* Create and init client publication session */
 
517
 
 
518
    /* Create client publication */
 
519
    status = pjsip_publishc_create(endpt, &my_publish_opt,
 
520
                                   pres, &publish_cb,
 
521
                                   &pres->publish_sess_);
 
522
 
 
523
    if (status != PJ_SUCCESS) {
 
524
        pres->publish_sess_ = NULL;
 
525
        ERROR("Failed to create a publish seesion.");
 
526
        return status;
 
527
    }
 
528
 
 
529
    /* Initialize client publication */
 
530
    pj_str_t from = pj_strdup3(pres->pool_, acc->getFromUri().c_str());
 
531
    status = pjsip_publishc_init(pres->publish_sess_, &STR_PRESENCE, &from, &from, &from, 0xFFFF);
 
532
 
 
533
    if (status != PJ_SUCCESS) {
 
534
        ERROR("Failed to init a publish session");
 
535
        pres->publish_sess_ = NULL;
 
536
        return status;
 
537
    }
 
538
 
 
539
    /* Add credential for authentication */
 
540
    if (acc->hasCredentials() and pjsip_publishc_set_credentials(pres->publish_sess_, acc->getCredentialCount(), acc->getCredInfo()) != PJ_SUCCESS) {
 
541
        ERROR("Could not initialize credentials for invite session authentication");
 
542
        return status;
 
543
    }
 
544
 
 
545
    /* Set route-set */
 
546
    // FIXME: is this really necessary?
 
547
    pjsip_regc *regc = acc->getRegistrationInfo();
 
548
    if (regc and acc->hasServiceRoute())
 
549
        pjsip_regc_set_route_set(regc, sip_utils::createRouteSet(acc->getServiceRoute(), pres->getPool()));
 
550
 
 
551
    /* Send initial PUBLISH request */
 
552
    status = send_publish(pres);
 
553
 
 
554
    if (status != PJ_SUCCESS)
 
555
        return status;
 
556
 
 
557
    return PJ_SUCCESS;
 
558
}