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-04-19 08:05:40 Functions: 1 9 11.1 %

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

Generated by: LCOV version 1.14