Line data Source code
1 : /*
2 : * Copyright (C) 2004-2026 Savoir-faire Linux Inc.
3 : *
4 : * This program is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 3 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * This program is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 : */
17 :
18 : #include "sip/sipaccount.h"
19 : #include "sip/sippresence.h"
20 : #include "logger.h"
21 : #include "pres_sub_server.h"
22 : #include "connectivity/sip_utils.h"
23 : #include "compiler_intrinsics.h"
24 :
25 : namespace jami {
26 :
27 : using sip_utils::CONST_PJ_STR;
28 :
29 : /* Callback called when *server* subscription state has changed. */
30 : void
31 0 : PresSubServer::pres_evsub_on_srv_state(UNUSED pjsip_evsub* sub, UNUSED pjsip_event* event)
32 : {
33 0 : JAMI_ERR("PresSubServer::pres_evsub_on_srv_state() is deprecated and does nothing");
34 0 : return;
35 :
36 : #if 0 // DISABLED: removed IP2IP support, tuleap: #448
37 : pjsip_rx_data *rdata = event->body.rx_msg.rdata;
38 :
39 : if (!rdata) {
40 : JAMI_DBG("Presence_subscription_server estate has changed but no rdata.");
41 : return;
42 : }
43 :
44 : auto account = Manager::instance().getIP2IPAccount();
45 : auto sipaccount = static_cast<SIPAccount *>(account.get());
46 : if (!sipaccount) {
47 : JAMI_ERR("Unable to find account IP2IP");
48 : return;
49 : }
50 :
51 : auto pres = sipaccount->getPresence();
52 :
53 : if (!pres) {
54 : JAMI_ERR("Presence not initialized");
55 : return;
56 : }
57 :
58 : pres->lock();
59 : PresSubServer *presSubServer = static_cast<PresSubServer *>(pjsip_evsub_get_mod_data(sub, pres->getModId()));
60 :
61 : if (presSubServer) {
62 : JAMI_DBG("Presence_subscription_server to %s is %s",
63 : presSubServer->remote_, pjsip_evsub_get_state_name(sub));
64 : pjsip_evsub_state state;
65 :
66 : state = pjsip_evsub_get_state(sub);
67 :
68 : if (state == PJSIP_EVSUB_STATE_TERMINATED) {
69 : pjsip_evsub_set_mod_data(sub, pres->getModId(), NULL);
70 : pres->removePresSubServer(presSubServer);
71 : }
72 :
73 : /* TODO check if other cases should be handled*/
74 : }
75 :
76 : pres->unlock();
77 : #endif
78 : }
79 :
80 : pj_bool_t
81 105 : PresSubServer::pres_on_rx_subscribe_request(pjsip_rx_data* rdata)
82 : {
83 : /* Only hande incoming subscribe messages should be processed here.
84 : * Otherwise we return FALSE to let other modules handle it */
85 105 : if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_subscribe_method()) != 0)
86 105 : return PJ_FALSE;
87 :
88 0 : JAMI_ERR("PresSubServer::pres_evsub_on_srv_state() is deprecated and does nothing");
89 0 : return PJ_FALSE;
90 : }
91 :
92 : pjsip_module PresSubServer::mod_presence_server = {
93 : NULL,
94 : NULL, /* prev, next. */
95 : CONST_PJ_STR("mod-presence-server"), /* Name. */
96 : -1, /* Id */
97 : PJSIP_MOD_PRIORITY_DIALOG_USAGE,
98 : NULL, /* load() */
99 : NULL, /* start() */
100 : NULL, /* stop() */
101 : NULL, /* unload() */
102 : &pres_on_rx_subscribe_request, /* on_rx_request() */
103 : NULL, /* on_rx_response() */
104 : NULL, /* on_tx_request. */
105 : NULL, /* on_tx_response() */
106 : NULL, /* on_tsx_state() */
107 :
108 : };
109 :
110 0 : PresSubServer::PresSubServer(SIPPresence* pres, pjsip_evsub* evsub, const char* remote, pjsip_dialog* d)
111 0 : : remote_(remote)
112 0 : , pres_(pres)
113 0 : , sub_(evsub)
114 0 : , dlg_(d)
115 0 : , expires_(-1)
116 0 : , approved_(false)
117 0 : {}
118 :
119 0 : PresSubServer::~PresSubServer()
120 : {
121 : // TODO: check if evsub needs to be forced TERMINATED.
122 0 : }
123 :
124 : void
125 0 : PresSubServer::setExpires(int ms)
126 : {
127 0 : expires_ = ms;
128 0 : }
129 :
130 : int
131 0 : PresSubServer::getExpires() const
132 : {
133 0 : return expires_;
134 : }
135 :
136 : bool
137 0 : PresSubServer::matches(const char* s) const
138 : {
139 : // servers match if they have the same remote uri and the account ID.
140 0 : return (!(strcmp(remote_, s)));
141 : }
142 :
143 : void
144 0 : PresSubServer::approve(bool flag)
145 : {
146 0 : approved_ = flag;
147 0 : JAMI_DBG("Approve Presence_subscription_server for %s: %s.", remote_, flag ? "true" : "false");
148 : // attach the real status data
149 0 : pjsip_pres_set_status(sub_, pres_->getStatus());
150 0 : }
151 :
152 : void
153 0 : PresSubServer::notify()
154 : {
155 : /* Only send NOTIFY once subscription is active. Some subscriptions
156 : * may still be in NULL (when app is adding a new buddy while in the
157 : * on_incoming_subscribe() callback) or PENDING (when user approval is
158 : * being requested) state and we don't send NOTIFY to these subs until
159 : * the user accepted the request.
160 : */
161 0 : if ((pjsip_evsub_get_state(sub_) == PJSIP_EVSUB_STATE_ACTIVE) && (approved_)) {
162 0 : JAMI_DBG("Notifying %s.", remote_);
163 :
164 : pjsip_tx_data* tdata;
165 0 : pjsip_pres_set_status(sub_, pres_->getStatus());
166 :
167 0 : if (pjsip_pres_current_notify(sub_, &tdata) == PJ_SUCCESS) {
168 : // add msg header and send
169 0 : pres_->fillDoc(tdata, NULL);
170 0 : pjsip_pres_send_request(sub_, tdata);
171 : } else {
172 0 : JAMI_WARN("Unable to create/send NOTIFY");
173 0 : pjsip_pres_terminate(sub_, PJ_FALSE);
174 : }
175 : }
176 0 : }
177 :
178 : } // namespace jami
|