LCOV - code coverage report
Current view: top level - src/sip - pres_sub_server.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 7 45 15.6 %
Date: 2024-12-21 08:56:24 Functions: 1 9 11.1 %

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

Generated by: LCOV version 1.14