~ubuntu-branches/ubuntu/trusty/sflphone/trusty

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (4.3.4 sid)
  • Revision ID: package-import@ubuntu.com-20140128182336-jrsv0k9u6cawc068
Tags: 1.3.0-1
* 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 "pjsip/sip_multipart.h"
 
34
 
 
35
#include "sipvoiplink.h"
 
36
#include "manager.h"
 
37
#include "sippresence.h"
 
38
#include "client/presencemanager.h"
 
39
#include "logger.h"
 
40
#include "pres_sub_server.h"
 
41
 
 
42
/* Callback called when *server* subscription state has changed. */
 
43
void
 
44
PresSubServer::pres_evsub_on_srv_state(pjsip_evsub *sub, pjsip_event *event)
 
45
{
 
46
    pjsip_rx_data *rdata = event->body.rx_msg.rdata;
 
47
 
 
48
    if (!rdata) {
 
49
        DEBUG("Presence_subscription_server estate has changed but no rdata.");
 
50
        return;
 
51
    }
 
52
 
 
53
    PJ_UNUSED_ARG(event);
 
54
    SIPPresence * pres = Manager::instance().getSipAccount("IP2IP")->getPresence();
 
55
    pres->lock();
 
56
    PresSubServer *presSubServer = static_cast<PresSubServer *>(pjsip_evsub_get_mod_data(sub, pres->getModId()));
 
57
 
 
58
    if (presSubServer) {
 
59
        DEBUG("Presence_subscription_server to %s is %s",
 
60
              presSubServer->remote_, pjsip_evsub_get_state_name(sub));
 
61
        pjsip_evsub_state state;
 
62
 
 
63
        state = pjsip_evsub_get_state(sub);
 
64
 
 
65
        if (state == PJSIP_EVSUB_STATE_TERMINATED) {
 
66
            pjsip_evsub_set_mod_data(sub, pres->getModId(), NULL);
 
67
            pres->removePresSubServer(presSubServer);
 
68
        }
 
69
 
 
70
        /* TODO check if other cases should be handled*/
 
71
    }
 
72
 
 
73
    pres->unlock();
 
74
}
 
75
 
 
76
pj_bool_t
 
77
PresSubServer::pres_on_rx_subscribe_request(pjsip_rx_data *rdata)
 
78
{
 
79
 
 
80
    pjsip_method *method = &rdata->msg_info.msg->line.req.method;
 
81
    pj_str_t *str = &method->name;
 
82
    std::string request(str->ptr, str->slen);
 
83
//    pj_str_t contact;
 
84
    pj_status_t status;
 
85
    pjsip_dialog *dlg;
 
86
    pjsip_evsub *sub;
 
87
    pjsip_evsub_user pres_cb;
 
88
    pjsip_expires_hdr *expires_hdr;
 
89
    pjsip_status_code st_code;
 
90
    pj_str_t reason;
 
91
    pres_msg_data msg_data;
 
92
    pjsip_evsub_state ev_state;
 
93
 
 
94
 
 
95
    /* Only hande incoming subscribe messages should be processed here.
 
96
     * Otherwise we return FALSE to let other modules handle it */
 
97
    if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_subscribe_method()) != 0)
 
98
        return PJ_FALSE;
 
99
 
 
100
    /* debug msg */
 
101
    std::string name(rdata->msg_info.to->name.ptr, rdata->msg_info.to->name.slen);
 
102
    std::string server(rdata->msg_info.from->name.ptr, rdata->msg_info.from->name.slen);
 
103
    DEBUG("Incoming pres_on_rx_subscribe_request for %s, name:%s, server:%s."
 
104
          , request.c_str()
 
105
          , name.c_str()
 
106
          , server.c_str());
 
107
 
 
108
    /* get parents*/
 
109
    SIPAccount *acc = Manager::instance().getIP2IPAccount();
 
110
    assert(acc);
 
111
 
 
112
    pjsip_endpoint *endpt = ((SIPVoIPLink*) acc->getVoIPLink())->getEndpoint();
 
113
    SIPPresence * pres = acc->getPresence();
 
114
    pres->lock();
 
115
 
 
116
    /* Create UAS dialog: */
 
117
    const pj_str_t contact(acc->getContactHeader());
 
118
    status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, &contact, &dlg);
 
119
 
 
120
    if (status != PJ_SUCCESS) {
 
121
        char errmsg[PJ_ERR_MSG_SIZE];
 
122
        pj_strerror(status, errmsg, sizeof(errmsg));
 
123
        WARN("Unable to create UAS dialog for subscription: %s [status=%d]", errmsg, status);
 
124
        pres->unlock();
 
125
        pjsip_endpt_respond_stateless(endpt, rdata, 400, NULL, NULL, NULL);
 
126
        return PJ_TRUE;
 
127
    }
 
128
 
 
129
    /* Init callback: */
 
130
    pj_bzero(&pres_cb, sizeof(pres_cb));
 
131
    pres_cb.on_evsub_state = &pres_evsub_on_srv_state;
 
132
 
 
133
    /* Create server presence subscription: */
 
134
    status = pjsip_pres_create_uas(dlg, &pres_cb, rdata, &sub);
 
135
 
 
136
    if (status != PJ_SUCCESS) {
 
137
        int code = PJSIP_ERRNO_TO_SIP_STATUS(status);
 
138
        pjsip_tx_data *tdata;
 
139
 
 
140
        WARN("Unable to create server subscription %d", status);
 
141
 
 
142
        if (code == 599 || code > 699 || code < 300) {
 
143
            code = 400;
 
144
        }
 
145
 
 
146
        status = pjsip_dlg_create_response(dlg, rdata, code, NULL, &tdata);
 
147
 
 
148
        if (status == PJ_SUCCESS) {
 
149
            status = pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), tdata);
 
150
        }
 
151
 
 
152
        pres->unlock();
 
153
        return PJ_FALSE;
 
154
    }
 
155
 
 
156
    /* Attach our data to the subscription: */
 
157
    char* remote = (char*) pj_pool_alloc(dlg->pool, PJSIP_MAX_URL_SIZE);
 
158
    status = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, dlg->remote.info->uri, remote, PJSIP_MAX_URL_SIZE);
 
159
 
 
160
    if (status < 1)
 
161
        pj_ansi_strcpy(remote, "<-- url is too long-->");
 
162
    else
 
163
        remote[status] = '\0';
 
164
 
 
165
    //pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, dlg->local.info->uri, contact.ptr, PJSIP_MAX_URL_SIZE);
 
166
 
 
167
    /* Create a new PresSubServer server and wait for client approve */
 
168
    PresSubServer *presSubServer = new PresSubServer(pres, sub, remote, dlg);
 
169
    pjsip_evsub_set_mod_data(sub, pres->getModId(), presSubServer);
 
170
    // Notify the client.
 
171
    Manager::instance().getClient()->getPresenceManager()->newServerSubscriptionRequest(presSubServer->remote_);
 
172
 
 
173
    pres->addPresSubServer(presSubServer);
 
174
 
 
175
    /* Capture the value of Expires header. */
 
176
    expires_hdr = (pjsip_expires_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
 
177
 
 
178
    if (expires_hdr)
 
179
        presSubServer->setExpires(expires_hdr->ivalue);
 
180
    else
 
181
        presSubServer->setExpires(-1);
 
182
 
 
183
    st_code = (pjsip_status_code) 200;
 
184
    reason = CONST_PJ_STR("OK");
 
185
    pj_bzero(&msg_data, sizeof(msg_data));
 
186
    pj_list_init(&msg_data.hdr_list);
 
187
    pjsip_media_type_init(&msg_data.multipart_ctype, NULL, NULL);
 
188
    pj_list_init(&msg_data.multipart_parts);
 
189
 
 
190
    /* Create and send 2xx response to the SUBSCRIBE request: */
 
191
    status = pjsip_pres_accept(sub, rdata, st_code, &msg_data.hdr_list);
 
192
 
 
193
    if (status != PJ_SUCCESS) {
 
194
        WARN("Unable to accept presence subscription %d", status);
 
195
        pjsip_pres_terminate(sub, PJ_FALSE);
 
196
        pres->unlock();
 
197
        return PJ_FALSE;
 
198
    }
 
199
 
 
200
    // Unsubscribe case
 
201
    ev_state = PJSIP_EVSUB_STATE_ACTIVE;
 
202
 
 
203
    if (presSubServer->getExpires() == 0) {
 
204
        ev_state = PJSIP_EVSUB_STATE_TERMINATED;
 
205
        pres->unlock();
 
206
        return PJ_TRUE;
 
207
    }
 
208
 
 
209
    /*Send notify immediatly. Replace real status with fake.*/
 
210
 
 
211
    // pjsip_pres_set_status(sub, pres->getStatus()); // real status
 
212
 
 
213
    // fake temporary status
 
214
    pjrpid_element rpid = {
 
215
        PJRPID_ELEMENT_TYPE_PERSON,
 
216
        CONST_PJ_STR("20"),
 
217
        PJRPID_ACTIVITY_UNKNOWN,
 
218
        CONST_PJ_STR("") // empty note by default
 
219
    };
 
220
    pjsip_pres_status fake_status_data;
 
221
    pj_bzero(&fake_status_data, sizeof(pjsip_pres_status));
 
222
    fake_status_data.info_cnt = 1;
 
223
    fake_status_data.info[0].basic_open = false;
 
224
    fake_status_data.info[0].id = CONST_PJ_STR("0"); /* todo: tuplie_id*/
 
225
    pj_memcpy(&fake_status_data.info[0].rpid, &rpid, sizeof(pjrpid_element));
 
226
    pjsip_pres_set_status(sub, &fake_status_data);
 
227
 
 
228
    /* Create and send the the first NOTIFY to active subscription: */
 
229
    pj_str_t stateStr = CONST_PJ_STR("");
 
230
    pjsip_tx_data *tdata = NULL;
 
231
    status = pjsip_pres_notify(sub, ev_state, &stateStr, &reason, &tdata);
 
232
 
 
233
    if (status == PJ_SUCCESS) {
 
234
        pres->fillDoc(tdata, &msg_data);
 
235
        status = pjsip_pres_send_request(sub, tdata);
 
236
    }
 
237
 
 
238
    if (status != PJ_SUCCESS) {
 
239
        WARN("Unable to create/send NOTIFY %d", status);
 
240
        pjsip_pres_terminate(sub, PJ_FALSE);
 
241
        pres->unlock();
 
242
        return status;
 
243
    }
 
244
 
 
245
    pres->unlock();
 
246
    return PJ_TRUE;
 
247
}
 
248
 
 
249
pjsip_module PresSubServer::mod_presence_server = {
 
250
    NULL, NULL, /* prev, next.        */
 
251
    CONST_PJ_STR("mod-presence-server"), /* Name.        */
 
252
    -1, /* Id            */
 
253
    PJSIP_MOD_PRIORITY_DIALOG_USAGE,
 
254
    NULL, /* load()        */
 
255
    NULL, /* start()        */
 
256
    NULL, /* stop()        */
 
257
    NULL, /* unload()        */
 
258
    &pres_on_rx_subscribe_request, /* on_rx_request()    */
 
259
    NULL, /* on_rx_response()    */
 
260
    NULL, /* on_tx_request.    */
 
261
    NULL, /* on_tx_response()    */
 
262
    NULL, /* on_tsx_state()    */
 
263
 
 
264
};
 
265
 
 
266
 
 
267
 
 
268
PresSubServer::PresSubServer(SIPPresence * pres, pjsip_evsub *evsub, const char *remote, pjsip_dialog *d)
 
269
    : remote_(remote)
 
270
    , pres_(pres)
 
271
    , sub_(evsub)
 
272
    , dlg_(d)
 
273
    , expires_(-1)
 
274
    , approved_(false)
 
275
{}
 
276
 
 
277
PresSubServer::~PresSubServer()
 
278
{
 
279
    //TODO: check if evsub needs to be forced TERMINATED.
 
280
}
 
281
 
 
282
void PresSubServer::setExpires(int ms)
 
283
{
 
284
    expires_ = ms;
 
285
}
 
286
 
 
287
int PresSubServer::getExpires() const
 
288
{
 
289
    return expires_;
 
290
}
 
291
 
 
292
bool PresSubServer::matches(const char *s) const
 
293
{
 
294
    // servers match if they have the same remote uri and the account ID.
 
295
    return (!(strcmp(remote_, s))) ;
 
296
}
 
297
 
 
298
void PresSubServer::approve(bool flag)
 
299
{
 
300
    approved_ = flag;
 
301
    DEBUG("Approve Presence_subscription_server for %s: %s.", remote_, flag ? "true" : "false");
 
302
    // attach the real status data
 
303
    pjsip_pres_set_status(sub_, pres_->getStatus());
 
304
}
 
305
 
 
306
 
 
307
void PresSubServer::notify()
 
308
{
 
309
    /* Only send NOTIFY once subscription is active. Some subscriptions
 
310
    * may still be in NULL (when app is adding a new buddy while in the
 
311
    * on_incoming_subscribe() callback) or PENDING (when user approval is
 
312
    * being requested) state and we don't send NOTIFY to these subs until
 
313
    * the user accepted the request.
 
314
    */
 
315
    if ((pjsip_evsub_get_state(sub_) == PJSIP_EVSUB_STATE_ACTIVE) && (approved_)) {
 
316
        DEBUG("Notifying %s.", remote_);
 
317
 
 
318
        pjsip_tx_data *tdata;
 
319
        pjsip_pres_set_status(sub_, pres_->getStatus());
 
320
 
 
321
        if (pjsip_pres_current_notify(sub_, &tdata) == PJ_SUCCESS) {
 
322
            // add msg header and send
 
323
            pres_->fillDoc(tdata, NULL);
 
324
            pjsip_pres_send_request(sub_, tdata);
 
325
        } else {
 
326
            WARN("Unable to create/send NOTIFY");
 
327
            pjsip_pres_terminate(sub_, PJ_FALSE);
 
328
        }
 
329
    }
 
330
}