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_ERROR("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_LOG("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_ERROR("Unable to find account IP2IP");
48 : return;
49 : }
50 :
51 : auto pres = sipaccount->getPresence();
52 :
53 : if (!pres) {
54 : JAMI_ERROR("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_LOG("Presence_subscription_server to {} is {}", presSubServer->remote_, pjsip_evsub_get_state_name(sub));
63 : pjsip_evsub_state state;
64 :
65 : state = pjsip_evsub_get_state(sub);
66 :
67 : if (state == PJSIP_EVSUB_STATE_TERMINATED) {
68 : pjsip_evsub_set_mod_data(sub, pres->getModId(), NULL);
69 : pres->removePresSubServer(presSubServer);
70 : }
71 :
72 : /* TODO check if other cases should be handled*/
73 : }
74 :
75 : pres->unlock();
76 : #endif
77 : }
78 :
79 : pj_bool_t
80 106 : PresSubServer::pres_on_rx_subscribe_request(pjsip_rx_data* rdata)
81 : {
82 : /* Only hande incoming subscribe messages should be processed here.
83 : * Otherwise we return FALSE to let other modules handle it */
84 106 : if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_subscribe_method()) != 0)
85 106 : return PJ_FALSE;
86 :
87 0 : JAMI_ERROR("PresSubServer::pres_evsub_on_srv_state() is deprecated and does nothing");
88 0 : return PJ_FALSE;
89 : }
90 :
91 : pjsip_module PresSubServer::mod_presence_server = {
92 : NULL,
93 : NULL, /* prev, next. */
94 : CONST_PJ_STR("mod-presence-server"), /* Name. */
95 : -1, /* Id */
96 : PJSIP_MOD_PRIORITY_DIALOG_USAGE,
97 : NULL, /* load() */
98 : NULL, /* start() */
99 : NULL, /* stop() */
100 : NULL, /* unload() */
101 : &pres_on_rx_subscribe_request, /* on_rx_request() */
102 : NULL, /* on_rx_response() */
103 : NULL, /* on_tx_request. */
104 : NULL, /* on_tx_response() */
105 : NULL, /* on_tsx_state() */
106 :
107 : };
108 :
109 0 : PresSubServer::PresSubServer(SIPPresence* pres, pjsip_evsub* evsub, const char* remote, pjsip_dialog* d)
110 0 : : remote_(remote)
111 0 : , pres_(pres)
112 0 : , sub_(evsub)
113 0 : , dlg_(d)
114 0 : , expires_(-1)
115 0 : , approved_(false)
116 0 : {}
117 :
118 0 : PresSubServer::~PresSubServer()
119 : {
120 : // TODO: check if evsub needs to be forced TERMINATED.
121 0 : }
122 :
123 : void
124 0 : PresSubServer::setExpires(int ms)
125 : {
126 0 : expires_ = ms;
127 0 : }
128 :
129 : int
130 0 : PresSubServer::getExpires() const
131 : {
132 0 : return expires_;
133 : }
134 :
135 : bool
136 0 : PresSubServer::matches(const char* s) const
137 : {
138 : // servers match if they have the same remote uri and the account ID.
139 0 : return (!(strcmp(remote_, s)));
140 : }
141 :
142 : void
143 0 : PresSubServer::approve(bool flag)
144 : {
145 0 : approved_ = flag;
146 0 : JAMI_LOG("Approve Presence_subscription_server for {}: {}.", remote_, flag ? "true" : "false");
147 : // attach the real status data
148 0 : pjsip_pres_set_status(sub_, pres_->getStatus());
149 0 : }
150 :
151 : void
152 0 : PresSubServer::notify()
153 : {
154 : /* Only send NOTIFY once subscription is active. Some subscriptions
155 : * may still be in NULL (when app is adding a new buddy while in the
156 : * on_incoming_subscribe() callback) or PENDING (when user approval is
157 : * being requested) state and we don't send NOTIFY to these subs until
158 : * the user accepted the request.
159 : */
160 0 : if ((pjsip_evsub_get_state(sub_) == PJSIP_EVSUB_STATE_ACTIVE) && (approved_)) {
161 0 : JAMI_LOG("Notifying {}.", remote_);
162 :
163 : pjsip_tx_data* tdata;
164 0 : pjsip_pres_set_status(sub_, pres_->getStatus());
165 :
166 0 : if (pjsip_pres_current_notify(sub_, &tdata) == PJ_SUCCESS) {
167 : // add msg header and send
168 0 : pres_->fillDoc(tdata, NULL);
169 0 : pjsip_pres_send_request(sub_, tdata);
170 : } else {
171 0 : JAMI_WARNING("Unable to create/send NOTIFY");
172 0 : pjsip_pres_terminate(sub_, PJ_FALSE);
173 : }
174 : }
175 0 : }
176 :
177 : } // namespace jami
|