presence_subscription.cpp 10.4 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/*
 *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
 *
 *  Author: Patrick Keroulas  <patrick.keroulas@savoirfairelinux.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
 *
 *  Additional permission under GNU GPL version 3 section 7:
 *
 *  If you modify this program, or any covered work, by linking or
 *  combining it with the OpenSSL project's OpenSSL library (or a
 *  modified version of that library), containing parts covered by the
 *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
 *  grants you additional permission to convey the resulting work.
 *  Corresponding Source for a non-source form of such a combination
 *  shall include the source code for the parts of OpenSSL used as well
 *  as that of the covered work.
 */


#include "pjsip/sip_multipart.h"

#include "sipvoiplink.h"
#include "manager.h"
#include "sippresence.h"
#include "logger.h"
#include "presence_subscription.h"

/* Callback called when *server* subscription state has changed. */
void pres_evsub_on_srv_state(pjsip_evsub *sub, pjsip_event *event) {
    pjsip_rx_data *rdata = event->body.rx_msg.rdata;
    if(!rdata) {
45
        DEBUG("Presence server state has changed but no rdata.");
46
47
        return;
    }
48

49
50
    PJ_UNUSED_ARG(event);
    SIPPresence * pres = Manager::instance().getSipAccount("IP2IP")->getPresence();
51
    pres->lock();
52
    PresenceSubscription *presenceSub = (PresenceSubscription *) pjsip_evsub_get_mod_data(sub,pres->getModId());
53
    DEBUG("Presence server subscription to %s is %s", presenceSub->remote, pjsip_evsub_get_state_name(sub));
54
55
56
57
58
59
60
61
62
63

    if (presenceSub) {
        pjsip_evsub_state state;

        state = pjsip_evsub_get_state(sub);

        if (state == PJSIP_EVSUB_STATE_TERMINATED) {
            pjsip_evsub_set_mod_data(sub, pres->getModId(), NULL);
            pres->removeServerSubscription(presenceSub);
        }
64
        /* TODO check if other cases should be handled*/
65
    }
66
    pres->unlock();
67
68
69
70
71
72
73
}

pj_bool_t pres_on_rx_subscribe_request(pjsip_rx_data *rdata) {

    pjsip_method *method = &rdata->msg_info.msg->line.req.method;
    pj_str_t *str = &method->name;
    std::string request(str->ptr, str->slen);
74
//    pj_str_t contact;
75
76
77
78
79
80
81
82
83
84
85
    pj_status_t status;
    pjsip_dialog *dlg;
    pjsip_evsub *sub;
    pjsip_evsub_user pres_cb;
    pjsip_tx_data *tdata;
    pjsip_expires_hdr *expires_hdr;
    pjsip_status_code st_code;
    pj_str_t reason;
    pres_msg_data msg_data;
    pjsip_evsub_state ev_state;

86
87
88
89

    /* Only hande incoming subscribe messages should be processed here.
     * Otherwise we return FALSE to let other modules handle it */
    if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_subscribe_method()) != 0)
90
91
        return PJ_FALSE;

92
93
94
95
96
97
98
    /* debug msg */
    std::string name(rdata->msg_info.to->name.ptr, rdata->msg_info.to->name.slen);
    std::string server(rdata->msg_info.from->name.ptr, rdata->msg_info.from->name.slen);
    DEBUG("Incomming pres_on_rx_subscribe_request for %s, name:%s, server:%s."
            , request.c_str()
            , name.c_str()
            , server.c_str());
99

100
    /* get parents*/
101
    std::string accountId = "IP2IP"; /* this code is only used for IP2IP accounts */
102
103
104
    SIPAccount *acc = (SIPAccount *) Manager::instance().getSipAccount(accountId);
    pjsip_endpoint *endpt = ((SIPVoIPLink*) acc->getVoIPLink())->getEndpoint();
    SIPPresence * pres = acc->getPresence();
105
    pres->lock();
106
107

    /* Create UAS dialog: */
108
109
    std::string c(acc->getContactHeader());
    const pj_str_t contact = pj_str((char*) c.c_str());
110
111
112
113
114
    status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, &contact, &dlg);
    if (status != PJ_SUCCESS) {
        char errmsg[PJ_ERR_MSG_SIZE];
        pj_strerror(status, errmsg, sizeof(errmsg));
        WARN("Unable to create UAS dialog for subscription: %s [status=%d]", errmsg, status);
115
        pres->unlock();
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
        pjsip_endpt_respond_stateless(endpt, rdata, 400, NULL, NULL, NULL);
        return PJ_TRUE;
    }

    /* Init callback: */
    pj_bzero(&pres_cb, sizeof(pres_cb));
    pres_cb.on_evsub_state = &pres_evsub_on_srv_state;

    /* Create server presence subscription: */
    status = pjsip_pres_create_uas(dlg, &pres_cb, rdata, &sub);
    if (status != PJ_SUCCESS) {
        int code = PJSIP_ERRNO_TO_SIP_STATUS(status);
        pjsip_tx_data *tdata;

        WARN("Unable to create server subscription %d", status);

        if (code == 599 || code > 699 || code < 300) {
            code = 400;
        }

        status = pjsip_dlg_create_response(dlg, rdata, code, NULL, &tdata);
        if (status == PJ_SUCCESS) {
            status = pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), tdata);
        }

141
        pres->unlock();
142
143
144
145
146
147
148
149
150
151
        return PJ_FALSE;
    }

    /* Attach our data to the subscription: */
    char* remote = (char*) pj_pool_alloc(dlg->pool, PJSIP_MAX_URL_SIZE);
    status = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, dlg->remote.info->uri, remote, PJSIP_MAX_URL_SIZE);
    if (status < 1)
        pj_ansi_strcpy(remote, "<-- url is too long-->");
    else
        remote[status] = '\0';
152
    //pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, dlg->local.info->uri, contact.ptr, PJSIP_MAX_URL_SIZE);
153

154
155
    /* Create a new PresenceSubription server and wait for client approve */
    PresenceSubscription *presenceSub = new PresenceSubscription(pres, sub, remote, dlg);
156
    pjsip_evsub_set_mod_data(sub, pres->getModId(), presenceSub);
157
    pres->reportNewServerSubscription(presenceSub); /* Notify the client.*/
158
159
    pres->addServerSubscription(presenceSub);

160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
    /* Capture the value of Expires header. */
    expires_hdr = (pjsip_expires_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
    if (expires_hdr)
        presenceSub->setExpires(expires_hdr->ivalue);
    else
        presenceSub->setExpires(-1);

    st_code = (pjsip_status_code) 200;
    reason = pj_str("OK");
    pj_bzero(&msg_data, sizeof(msg_data));
    pj_list_init(&msg_data.hdr_list);
    pjsip_media_type_init(&msg_data.multipart_ctype, NULL, NULL);
    pj_list_init(&msg_data.multipart_parts);

    /* Create and send 2xx response to the SUBSCRIBE request: */
    status = pjsip_pres_accept(sub, rdata, st_code, &msg_data.hdr_list);
    if (status != PJ_SUCCESS) {
        WARN("Unable to accept presence subscription %d", status);
        pjsip_pres_terminate(sub, PJ_FALSE);
179
        pres->unlock();
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
        return PJ_FALSE;
    }
//TODO: handle rejection case pjsua_pers.c:956


// -------------------------------------------------------------------------------V
// presenceSub->init();
//    return PJ_TRUE;
   /*Send notify immediatly*/

    pjsip_pres_set_status(sub, pres->getStatus());

    ev_state = PJSIP_EVSUB_STATE_ACTIVE;
    if (presenceSub->getExpires() == 0)
        ev_state = PJSIP_EVSUB_STATE_TERMINATED;

    /* Create and send the the first NOTIFY to active subscription: */
    pj_str_t stateStr = pj_str("");
    tdata = NULL;
    status = pjsip_pres_notify(sub, ev_state, &stateStr, &reason, &tdata);
    if (status == PJ_SUCCESS) {
201
        pres->fillDoc(tdata, &msg_data);
202
203
204
205
206
207
        status = pjsip_pres_send_request(sub, tdata);
    }

    if (status != PJ_SUCCESS) {
        WARN("Unable to create/send NOTIFY %d", status);
        pjsip_pres_terminate(sub, PJ_FALSE);
208
        pres->unlock();
209
210
        return status;
    }
211
    pres->unlock();
212
213
214
215
216
    return PJ_TRUE;
}



217
218
219
PresenceSubscription::PresenceSubscription(SIPPresence * pres, pjsip_evsub *evsub, char *r, pjsip_dialog *d)
    : pres_(pres)
    , sub(evsub)
220
221
    , remote(r)
    , dlg(d)
222
223
    , expires(-1)
    , approved(false)
224
{}
225
226
227
228
229
230
231
232
233
234
235
236
237
238


void PresenceSubscription::setExpires(int ms) {
    expires = ms;
}

int PresenceSubscription::getExpires(){
    return expires;
}

/*SIPPresence *  PresenceSubscription::getPresence(){
    return pres_;
}*/

239
bool PresenceSubscription::matches(char *s){
240
    // servers match if they have the same remote uri and the account ID.
241
  return (!(strcmp(remote,s))) ;
242
243
}

244
245
void PresenceSubscription::approve(const bool& flag){
    approved = flag;
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
}

/**
 * Send the tirst notification.
 * FIXME : pjsip_pres_notify crash because the header can't be cloned
 * So far, the first notify is sent in sipvoip_pres.c instead.
 */
void PresenceSubscription::init(){
    pjsip_tx_data *tdata = NULL;
    pres_msg_data msg_data;
    pj_str_t reason = pj_str("OK");
    pjsip_evsub_state ev_state = PJSIP_EVSUB_STATE_ACTIVE;

    pjsip_pres_set_status(sub, pres_->getStatus());
    if (expires == 0)
        ev_state = PJSIP_EVSUB_STATE_TERMINATED;

    /* Create and send the the first NOTIFY to active subscription: */
    pj_str_t stateStr = pj_str("");
    pj_status_t status = pjsip_pres_notify(sub, ev_state, &stateStr, &reason, &tdata);
    if (status == PJ_SUCCESS) {
267
        pres_->fillDoc(tdata, &msg_data);
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
        status = pjsip_pres_send_request(sub, tdata);
    }

    if (status != PJ_SUCCESS) {
        WARN("Unable to create/send NOTIFY %d", status);
        pjsip_pres_terminate(sub, PJ_FALSE);
    }
}

void PresenceSubscription::notify() {
     /* Only send NOTIFY once subscription is active. Some subscriptions
     * may still be in NULL (when app is adding a new buddy while in the
     * on_incoming_subscribe() callback) or PENDING (when user approval is
     * being requested) state and we don't send NOTIFY to these subs until
     * the user accepted the request.
     */
284
    if ((pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACTIVE) && (approved)) {
285
286
287
288
289
290
291
        DEBUG("Notifying %s.", remote);

        pjsip_tx_data *tdata;
        pjsip_pres_set_status(sub, pres_->getStatus());

        if (pjsip_pres_current_notify(sub, &tdata) == PJ_SUCCESS) {
            // add msg header and send
292
            pres_->fillDoc(tdata, NULL);
293
294
295
296
297
298
299
300
            pjsip_pres_send_request(sub, tdata);
        }
        else{
            WARN("Unable to create/send NOTIFY");
            pjsip_pres_terminate(sub, PJ_FALSE);
        }
    }
}