2
* Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
4
* Author: Patrick Keroulas <patrick.keroulas@savoirfairelinux.com>
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.
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.
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.
20
* Additional permission under GNU GPL version 3 section 7:
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.
33
#include "pjsip/sip_multipart.h"
35
#include "sipvoiplink.h"
37
#include "sippresence.h"
38
#include "client/presencemanager.h"
40
#include "pres_sub_server.h"
42
/* Callback called when *server* subscription state has changed. */
44
PresSubServer::pres_evsub_on_srv_state(pjsip_evsub *sub, pjsip_event *event)
46
pjsip_rx_data *rdata = event->body.rx_msg.rdata;
49
DEBUG("Presence_subscription_server estate has changed but no rdata.");
54
SIPPresence * pres = Manager::instance().getSipAccount("IP2IP")->getPresence();
56
PresSubServer *presSubServer = static_cast<PresSubServer *>(pjsip_evsub_get_mod_data(sub, pres->getModId()));
59
DEBUG("Presence_subscription_server to %s is %s",
60
presSubServer->remote_, pjsip_evsub_get_state_name(sub));
61
pjsip_evsub_state state;
63
state = pjsip_evsub_get_state(sub);
65
if (state == PJSIP_EVSUB_STATE_TERMINATED) {
66
pjsip_evsub_set_mod_data(sub, pres->getModId(), NULL);
67
pres->removePresSubServer(presSubServer);
70
/* TODO check if other cases should be handled*/
77
PresSubServer::pres_on_rx_subscribe_request(pjsip_rx_data *rdata)
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);
87
pjsip_evsub_user pres_cb;
88
pjsip_expires_hdr *expires_hdr;
89
pjsip_status_code st_code;
91
pres_msg_data msg_data;
92
pjsip_evsub_state ev_state;
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)
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."
109
SIPAccount *acc = Manager::instance().getIP2IPAccount();
112
pjsip_endpoint *endpt = ((SIPVoIPLink*) acc->getVoIPLink())->getEndpoint();
113
SIPPresence * pres = acc->getPresence();
116
/* Create UAS dialog: */
117
const pj_str_t contact(acc->getContactHeader());
118
status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, &contact, &dlg);
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);
125
pjsip_endpt_respond_stateless(endpt, rdata, 400, NULL, NULL, NULL);
130
pj_bzero(&pres_cb, sizeof(pres_cb));
131
pres_cb.on_evsub_state = &pres_evsub_on_srv_state;
133
/* Create server presence subscription: */
134
status = pjsip_pres_create_uas(dlg, &pres_cb, rdata, &sub);
136
if (status != PJ_SUCCESS) {
137
int code = PJSIP_ERRNO_TO_SIP_STATUS(status);
138
pjsip_tx_data *tdata;
140
WARN("Unable to create server subscription %d", status);
142
if (code == 599 || code > 699 || code < 300) {
146
status = pjsip_dlg_create_response(dlg, rdata, code, NULL, &tdata);
148
if (status == PJ_SUCCESS) {
149
status = pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), tdata);
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);
161
pj_ansi_strcpy(remote, "<-- url is too long-->");
163
remote[status] = '\0';
165
//pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, dlg->local.info->uri, contact.ptr, PJSIP_MAX_URL_SIZE);
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_);
173
pres->addPresSubServer(presSubServer);
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);
179
presSubServer->setExpires(expires_hdr->ivalue);
181
presSubServer->setExpires(-1);
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);
190
/* Create and send 2xx response to the SUBSCRIBE request: */
191
status = pjsip_pres_accept(sub, rdata, st_code, &msg_data.hdr_list);
193
if (status != PJ_SUCCESS) {
194
WARN("Unable to accept presence subscription %d", status);
195
pjsip_pres_terminate(sub, PJ_FALSE);
201
ev_state = PJSIP_EVSUB_STATE_ACTIVE;
203
if (presSubServer->getExpires() == 0) {
204
ev_state = PJSIP_EVSUB_STATE_TERMINATED;
209
/*Send notify immediatly. Replace real status with fake.*/
211
// pjsip_pres_set_status(sub, pres->getStatus()); // real status
213
// fake temporary status
214
pjrpid_element rpid = {
215
PJRPID_ELEMENT_TYPE_PERSON,
217
PJRPID_ACTIVITY_UNKNOWN,
218
CONST_PJ_STR("") // empty note by default
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);
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);
233
if (status == PJ_SUCCESS) {
234
pres->fillDoc(tdata, &msg_data);
235
status = pjsip_pres_send_request(sub, tdata);
238
if (status != PJ_SUCCESS) {
239
WARN("Unable to create/send NOTIFY %d", status);
240
pjsip_pres_terminate(sub, PJ_FALSE);
249
pjsip_module PresSubServer::mod_presence_server = {
250
NULL, NULL, /* prev, next. */
251
CONST_PJ_STR("mod-presence-server"), /* Name. */
253
PJSIP_MOD_PRIORITY_DIALOG_USAGE,
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() */
268
PresSubServer::PresSubServer(SIPPresence * pres, pjsip_evsub *evsub, const char *remote, pjsip_dialog *d)
277
PresSubServer::~PresSubServer()
279
//TODO: check if evsub needs to be forced TERMINATED.
282
void PresSubServer::setExpires(int ms)
287
int PresSubServer::getExpires() const
292
bool PresSubServer::matches(const char *s) const
294
// servers match if they have the same remote uri and the account ID.
295
return (!(strcmp(remote_, s))) ;
298
void PresSubServer::approve(bool 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());
307
void PresSubServer::notify()
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.
315
if ((pjsip_evsub_get_state(sub_) == PJSIP_EVSUB_STATE_ACTIVE) && (approved_)) {
316
DEBUG("Notifying %s.", remote_);
318
pjsip_tx_data *tdata;
319
pjsip_pres_set_status(sub_, pres_->getStatus());
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);
326
WARN("Unable to create/send NOTIFY");
327
pjsip_pres_terminate(sub_, PJ_FALSE);